| 1 | /*++ |
| 2 | |
| 3 | Copyright (c) Microsoft. All rights reserved. |
| 4 | |
| 5 | Module Name: |
| 6 | |
| 7 | docker_schema.h |
| 8 | |
| 9 | Abstract: |
| 10 | |
| 11 | JSON schema for the docker API. |
| 12 | Targets the daemon API version bundled with WSLC's dockerd (currently v25.0.3, API v1.44). |
| 13 | The documentation for the API can be found at: https://docs.docker.com/reference/api/engine/version/v1.44/#tag/Container |
| 14 | |
| 15 | --*/ |
| 16 | |
| 17 | #pragma once |
| 18 | |
| 19 | #include "JsonUtils.h" |
| 20 | |
| 21 | namespace wsl::windows::common::docker_schema { |
| 22 | |
| 23 | using wsl::shared::EmptyObject; |
| 24 | |
| 25 | // The daemon formats timestamps that were never set as the zero value of Go's time.Time rather than |
| 26 | // omitting them, so this value means "unset" instead of an actual point in time. |
| 27 | inline constexpr std::string_view c_unsetTimestamp = "0001-01-01T00:00:00Z"; |
| 28 | |
| 29 | // Reads a value, treating both a missing key and an explicit null as absent. The daemon reports some |
| 30 | // empty maps and objects as null, which the default deserializer rejects. |
| 31 | template <typename T> |
| 32 | T ValueOrNull(const nlohmann::json& json, const char* key, T defaultValue = T{}) |
| 33 | { |
| 34 | const auto entry = json.find(key); |
| 35 | if (entry == json.end() || entry->is_null()) |
| 36 | { |
| 37 | return defaultValue; |
| 38 | } |
| 39 | |
| 40 | return entry->get<T>(); |
| 41 | } |
| 42 | |
| 43 | struct CreatedContainer |
| 44 | { |
| 45 | std::string Id; |
| 46 | std::vector<std::string> Warnings; |
| 47 | |
| 48 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(CreatedContainer, Id, Warnings); |
| 49 | }; |
| 50 | |
| 51 | struct ErrorResponse |
| 52 | { |
| 53 | std::string message; |
| 54 | |
| 55 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ErrorResponse, message); |
| 56 | }; |
| 57 | |
| 58 | struct ImageLoadResult |
| 59 | { |
| 60 | std::optional<std::string> stream; |
| 61 | std::optional<std::string> status; |
| 62 | std::optional<ErrorResponse> errorDetail; |
| 63 | |
| 64 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ImageLoadResult, stream, status, errorDetail); |
| 65 | }; |
| 66 | |
| 67 | struct EmptyRequest |
| 68 | { |
| 69 | using TResponse = void; |
| 70 | }; |
| 71 | |
| 72 | struct AuthRequest |
| 73 | { |
| 74 | using TResponse = struct AuthResponse; |
| 75 | |
| 76 | std::string username; |
| 77 | std::string password; |
| 78 | std::string serveraddress; |
| 79 | |
| 80 | NLOHMANN_DEFINE_TYPE_INTRUSIVE(AuthRequest, username, password, serveraddress); |
| 81 | }; |
| 82 | |
| 83 | struct AuthResponse |
| 84 | { |
| 85 | std::string Status; |
| 86 | std::optional<std::string> IdentityToken; |
| 87 | |
| 88 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(AuthResponse, Status, IdentityToken); |
| 89 | }; |
| 90 | |
| 91 | struct VolumeUsageData |
| 92 | { |
| 93 | int64_t Size{-1}; |
| 94 | int64_t RefCount{-1}; |
| 95 | |
| 96 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(VolumeUsageData, Size, RefCount); |
| 97 | }; |
| 98 | |
| 99 | struct Volume |
| 100 | { |
| 101 | std::string Name; |
| 102 | std::string Driver; |
| 103 | std::string Mountpoint; |
| 104 | std::string CreatedAt; |
| 105 | std::optional<std::map<std::string, std::string>> Options; |
| 106 | std::optional<std::map<std::string, std::string>> Labels; |
| 107 | // Docker's wire schema for Status is map[string]any: third-party volume |
| 108 | // drivers may set arbitrary JSON values (numbers, bools, objects), not |
| 109 | // just strings. Use nlohmann::json so deserialization never throws. |
| 110 | std::optional<std::map<std::string, nlohmann::json>> Status; |
| 111 | std::optional<VolumeUsageData> UsageData; |
| 112 | |
| 113 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Volume, Name, Driver, Mountpoint, CreatedAt, Options, Labels, Status, UsageData); |
| 114 | }; |
| 115 | |
| 116 | struct CreateVolume |
| 117 | { |
| 118 | using TResponse = Volume; |
| 119 | |
| 120 | std::string Name; |
| 121 | std::string Driver; |
| 122 | std::map<std::string, std::string> DriverOpts; |
| 123 | std::map<std::string, std::string> Labels; |
| 124 | |
| 125 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(CreateVolume, Name, Driver, DriverOpts, Labels); |
| 126 | }; |
| 127 | |
| 128 | struct ListVolumesResponse |
| 129 | { |
| 130 | std::vector<Volume> Volumes; |
| 131 | |
| 132 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ListVolumesResponse, Volumes); |
| 133 | }; |
| 134 | |
| 135 | struct IPAMConfig |
| 136 | { |
| 137 | std::string Subnet; |
| 138 | std::string Gateway; |
| 139 | std::string IPRange; |
| 140 | |
| 141 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(IPAMConfig, Subnet, Gateway, IPRange); |
| 142 | }; |
| 143 | |
| 144 | struct IPAM |
| 145 | { |
| 146 | std::string Driver; |
| 147 | std::optional<std::vector<IPAMConfig>> Config; |
| 148 | std::map<std::string, std::string> Options; |
| 149 | }; |
| 150 | |
| 151 | inline void to_json(nlohmann::json& j, const IPAM& ipam) |
| 152 | { |
| 153 | j = nlohmann::json{{"Driver", ipam.Driver}, {"Config", ipam.Config}, {"Options", ipam.Options}}; |
| 154 | } |
| 155 | |
| 156 | inline void from_json(const nlohmann::json& j, IPAM& ipam) |
| 157 | { |
| 158 | ipam.Driver = ValueOrNull<std::string>(j, "Driver"); |
| 159 | ipam.Config = ValueOrNull<std::optional<std::vector<IPAMConfig>>>(j, "Config"); |
| 160 | ipam.Options = ValueOrNull<std::map<std::string, std::string>>(j, "Options"); |
| 161 | } |
| 162 | |
| 163 | struct NetworkConfigFrom |
| 164 | { |
| 165 | std::string Network; |
| 166 | |
| 167 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(NetworkConfigFrom, Network); |
| 168 | }; |
| 169 | |
| 170 | struct NetworkContainer |
| 171 | { |
| 172 | std::string Name; |
| 173 | std::string EndpointID; |
| 174 | std::string MacAddress; |
| 175 | std::string IPv4Address; |
| 176 | std::string IPv6Address; |
| 177 | |
| 178 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(NetworkContainer, Name, EndpointID, MacAddress, IPv4Address, IPv6Address); |
| 179 | }; |
| 180 | |
| 181 | struct CreateNetworkResponse |
| 182 | { |
| 183 | std::string Id; |
| 184 | std::string Warning; |
| 185 | |
| 186 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(CreateNetworkResponse, Id, Warning); |
| 187 | }; |
| 188 | |
| 189 | struct CreateNetwork |
| 190 | { |
| 191 | using TResponse = CreateNetworkResponse; |
| 192 | |
| 193 | std::string Name; |
| 194 | std::string Driver; |
| 195 | bool Internal{}; |
| 196 | std::optional<IPAM> IPAM; |
| 197 | std::optional<std::map<std::string, std::string>> Options; |
| 198 | std::map<std::string, std::string> Labels; |
| 199 | |
| 200 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(CreateNetwork, Name, Driver, Internal, IPAM, Options, Labels); |
| 201 | }; |
| 202 | |
| 203 | struct Network |
| 204 | { |
| 205 | std::string Id; |
| 206 | std::string Name; |
| 207 | std::string Created; |
| 208 | std::string Driver; |
| 209 | std::string Scope; |
| 210 | bool EnableIPv4{true}; |
| 211 | bool EnableIPv6{}; |
| 212 | bool Internal{}; |
| 213 | bool Attachable{}; |
| 214 | bool Ingress{}; |
| 215 | bool ConfigOnly{}; |
| 216 | NetworkConfigFrom ConfigFrom; |
| 217 | IPAM IPAM; |
| 218 | std::map<std::string, std::string> Options; |
| 219 | std::map<std::string, std::string> Labels; |
| 220 | std::map<std::string, NetworkContainer> Containers; |
| 221 | nlohmann::json Status = nlohmann::json::object(); |
| 222 | }; |
| 223 | |
| 224 | inline void from_json(const nlohmann::json& j, Network& network) |
| 225 | { |
| 226 | const Network defaults{}; |
| 227 | |
| 228 | network.Id = ValueOrNull<std::string>(j, "Id"); |
| 229 | network.Name = ValueOrNull<std::string>(j, "Name"); |
| 230 | network.Created = ValueOrNull<std::string>(j, "Created"); |
| 231 | network.Driver = ValueOrNull<std::string>(j, "Driver"); |
| 232 | network.Scope = ValueOrNull<std::string>(j, "Scope"); |
| 233 | network.EnableIPv4 = ValueOrNull<bool>(j, "EnableIPv4", defaults.EnableIPv4); |
| 234 | network.EnableIPv6 = ValueOrNull<bool>(j, "EnableIPv6"); |
| 235 | network.Internal = ValueOrNull<bool>(j, "Internal"); |
| 236 | network.Attachable = ValueOrNull<bool>(j, "Attachable"); |
| 237 | network.Ingress = ValueOrNull<bool>(j, "Ingress"); |
| 238 | network.ConfigOnly = ValueOrNull<bool>(j, "ConfigOnly"); |
| 239 | network.ConfigFrom = ValueOrNull<NetworkConfigFrom>(j, "ConfigFrom"); |
| 240 | network.IPAM = ValueOrNull<docker_schema::IPAM>(j, "IPAM"); |
| 241 | network.Options = ValueOrNull<std::map<std::string, std::string>>(j, "Options"); |
| 242 | network.Labels = ValueOrNull<std::map<std::string, std::string>>(j, "Labels"); |
| 243 | network.Containers = ValueOrNull<std::map<std::string, NetworkContainer>>(j, "Containers"); |
| 244 | network.Status = ValueOrNull<nlohmann::json>(j, "Status", defaults.Status); |
| 245 | } |
| 246 | |
| 247 | struct EndpointIPAMConfig |
| 248 | { |
| 249 | std::string IPv4Address; |
| 250 | std::optional<std::vector<std::string>> LinkLocalIPs; |
| 251 | }; |
| 252 | |
| 253 | inline void to_json(nlohmann::json& j, const EndpointIPAMConfig& v) |
| 254 | { |
| 255 | j = nlohmann::json::object(); |
| 256 | if (!v.IPv4Address.empty()) |
| 257 | { |
| 258 | j["IPv4Address"] = v.IPv4Address; |
| 259 | } |
| 260 | if (v.LinkLocalIPs.has_value() && !v.LinkLocalIPs->empty()) |
| 261 | { |
| 262 | j["LinkLocalIPs"] = *v.LinkLocalIPs; |
| 263 | } |
| 264 | } |
| 265 | |
| 266 | struct EndpointConfig |
| 267 | { |
| 268 | std::optional<std::vector<std::string>> Aliases; |
| 269 | std::optional<EndpointIPAMConfig> IPAMConfig; |
| 270 | std::optional<std::vector<std::string>> Links; |
| 271 | std::optional<std::map<std::string, std::string>> DriverOpts; |
| 272 | }; |
| 273 | |
| 274 | inline void to_json(nlohmann::json& j, const EndpointConfig& v) |
| 275 | { |
| 276 | j = nlohmann::json::object(); |
| 277 | if (v.Aliases.has_value() && !v.Aliases->empty()) |
| 278 | { |
| 279 | j["Aliases"] = *v.Aliases; |
| 280 | } |
| 281 | if (v.IPAMConfig.has_value()) |
| 282 | { |
| 283 | auto ipam = nlohmann::json(*v.IPAMConfig); |
| 284 | if (!ipam.empty()) |
| 285 | { |
| 286 | j["IPAMConfig"] = std::move(ipam); |
| 287 | } |
| 288 | } |
| 289 | if (v.Links.has_value() && !v.Links->empty()) |
| 290 | { |
| 291 | j["Links"] = *v.Links; |
| 292 | } |
| 293 | if (v.DriverOpts.has_value() && !v.DriverOpts->empty()) |
| 294 | { |
| 295 | j["DriverOpts"] = *v.DriverOpts; |
| 296 | } |
| 297 | } |
| 298 | |
| 299 | struct ContainerNetworkRequest |
| 300 | { |
| 301 | using TResponse = void; |
| 302 | std::string Container; |
| 303 | std::optional<EndpointConfig> EndpointConfig; |
| 304 | }; |
| 305 | |
| 306 | inline void to_json(nlohmann::json& j, const ContainerNetworkRequest& v) |
| 307 | { |
| 308 | j = nlohmann::json{{"Container", v.Container}}; |
| 309 | if (v.EndpointConfig.has_value()) |
| 310 | { |
| 311 | auto endpoint = nlohmann::json(*v.EndpointConfig); |
| 312 | if (!endpoint.empty()) |
| 313 | { |
| 314 | j["EndpointConfig"] = std::move(endpoint); |
| 315 | } |
| 316 | } |
| 317 | } |
| 318 | |
| 319 | struct MountTmpfsOptions |
| 320 | { |
| 321 | std::int64_t SizeBytes{}; |
| 322 | std::uint32_t Mode{}; |
| 323 | |
| 324 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(MountTmpfsOptions, SizeBytes, Mode); |
| 325 | }; |
| 326 | |
| 327 | struct Mount |
| 328 | { |
| 329 | std::string Name; |
| 330 | std::string Source; |
| 331 | std::string Target; |
| 332 | std::string Type; |
| 333 | bool ReadOnly{}; |
| 334 | std::optional<MountTmpfsOptions> TmpfsOptions; |
| 335 | |
| 336 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Mount, Name, Target, Source, Type, ReadOnly, TmpfsOptions); |
| 337 | }; |
| 338 | |
| 339 | struct DeviceMapping |
| 340 | { |
| 341 | std::string PathOnHost; |
| 342 | std::string PathInContainer; |
| 343 | std::string CgroupPermissions; |
| 344 | |
| 345 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(DeviceMapping, PathOnHost, PathInContainer, CgroupPermissions); |
| 346 | }; |
| 347 | |
| 348 | struct PortMapping |
| 349 | { |
| 350 | std::string HostIp; |
| 351 | std::string HostPort; |
| 352 | |
| 353 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(PortMapping, HostIp, HostPort); |
| 354 | }; |
| 355 | |
| 356 | struct Ulimit |
| 357 | { |
| 358 | std::string Name; |
| 359 | std::int64_t Soft{}; |
| 360 | std::int64_t Hard{}; |
| 361 | |
| 362 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Ulimit, Name, Soft, Hard); |
| 363 | }; |
| 364 | |
| 365 | struct DeviceRequest |
| 366 | { |
| 367 | std::string Driver; |
| 368 | std::vector<std::string> DeviceIDs; |
| 369 | |
| 370 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(DeviceRequest, Driver, DeviceIDs); |
| 371 | }; |
| 372 | |
| 373 | struct HostConfig |
| 374 | { |
| 375 | std::vector<Mount> Mounts; |
| 376 | std::map<std::string, std::vector<PortMapping>> PortBindings; |
| 377 | std::string NetworkMode; |
| 378 | bool Init{}; |
| 379 | std::optional<std::vector<std::string>> Dns; |
| 380 | std::optional<std::vector<std::string>> DnsSearch; |
| 381 | std::optional<std::vector<std::string>> DnsOptions; |
| 382 | std::optional<std::vector<std::string>> Binds; |
| 383 | std::map<std::string, std::string> Tmpfs; |
| 384 | // Docker wire type is int64. 0 means "use daemon default" — same as omitting |
| 385 | // the field — so we don't bother with std::optional here. |
| 386 | std::int64_t ShmSize{}; |
| 387 | std::optional<std::vector<DeviceMapping>> Devices; |
| 388 | std::optional<std::vector<DeviceRequest>> DeviceRequests; |
| 389 | |
| 390 | // Per-container resource limits. 0 means "no limit" (Docker default). |
| 391 | std::int64_t Memory{}; |
| 392 | std::int64_t NanoCpus{}; |
| 393 | std::optional<std::vector<Ulimit>> Ulimits; |
| 394 | |
| 395 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT( |
| 396 | HostConfig, Mounts, PortBindings, NetworkMode, Init, Dns, DnsSearch, DnsOptions, Binds, Tmpfs, Devices, DeviceRequests, ShmSize, Memory, NanoCpus, Ulimits); |
| 397 | }; |
| 398 | |
| 399 | struct InspectEndpointIPAMConfig |
| 400 | { |
| 401 | std::string IPv4Address; |
| 402 | std::optional<std::vector<std::string>> LinkLocalIPs; |
| 403 | |
| 404 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(InspectEndpointIPAMConfig, IPv4Address, LinkLocalIPs); |
| 405 | }; |
| 406 | |
| 407 | struct EndpointSettings |
| 408 | { |
| 409 | std::string IPAddress; |
| 410 | std::string Gateway; |
| 411 | std::string MacAddress; |
| 412 | int IPPrefixLen{}; |
| 413 | std::optional<std::vector<std::string>> Aliases; |
| 414 | std::optional<std::vector<std::string>> Links; |
| 415 | std::optional<std::map<std::string, std::string>> DriverOpts; |
| 416 | std::optional<InspectEndpointIPAMConfig> IPAMConfig; |
| 417 | |
| 418 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(EndpointSettings, IPAddress, Gateway, MacAddress, IPPrefixLen, Aliases, Links, DriverOpts, IPAMConfig); |
| 419 | }; |
| 420 | |
| 421 | struct NetworkingConfig |
| 422 | { |
| 423 | std::map<std::string, EndpointConfig> EndpointsConfig; |
| 424 | |
| 425 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(NetworkingConfig, EndpointsConfig); |
| 426 | }; |
| 427 | |
| 428 | struct NetworkSettings |
| 429 | { |
| 430 | std::map<std::string, EndpointSettings> Networks; |
| 431 | |
| 432 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(NetworkSettings, Networks); |
| 433 | }; |
| 434 | |
| 435 | struct HealthConfig |
| 436 | { |
| 437 | std::optional<std::vector<std::string>> Test; |
| 438 | std::optional<std::int64_t> Interval; |
| 439 | std::optional<std::int64_t> Timeout; |
| 440 | std::optional<std::int64_t> StartPeriod; |
| 441 | std::optional<int> Retries; |
| 442 | |
| 443 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(HealthConfig, Test, Interval, Timeout, StartPeriod, Retries); |
| 444 | }; |
| 445 | |
| 446 | struct CreateContainer |
| 447 | { |
| 448 | using TResponse = CreatedContainer; |
| 449 | |
| 450 | std::string Image; |
| 451 | bool Tty{}; |
| 452 | bool OpenStdin{}; |
| 453 | bool StdinOnce{}; |
| 454 | bool AttachStdin{}; |
| 455 | bool AttachStdout{}; |
| 456 | bool AttachStderr{}; |
| 457 | std::optional<std::string> User; |
| 458 | std::string Hostname; |
| 459 | std::string Domainname; |
| 460 | std::optional<std::string> StopSignal; |
| 461 | std::optional<long> StopTimeout; |
| 462 | std::optional<std::string> WorkingDir; |
| 463 | std::optional<std::vector<std::string>> Cmd; |
| 464 | std::optional<std::vector<std::string>> Entrypoint; |
| 465 | std::vector<std::string> Env; |
| 466 | std::map<std::string, EmptyObject> ExposedPorts; |
| 467 | std::map<std::string, std::string> Labels; |
| 468 | std::optional<HealthConfig> Healthcheck; |
| 469 | HostConfig HostConfig; |
| 470 | NetworkingConfig NetworkingConfig; |
| 471 | |
| 472 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE( |
| 473 | CreateContainer, Image, Cmd, Tty, OpenStdin, StdinOnce, Entrypoint, Env, ExposedPorts, HostConfig, StopSignal, StopTimeout, WorkingDir, User, Hostname, Domainname, Labels, Healthcheck, NetworkingConfig); |
| 474 | }; |
| 475 | |
| 476 | struct HealthcheckResult |
| 477 | { |
| 478 | std::string Start; |
| 479 | std::string End; |
| 480 | int ExitCode{}; |
| 481 | std::string Output; |
| 482 | |
| 483 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(HealthcheckResult, Start, End, ExitCode, Output); |
| 484 | }; |
| 485 | |
| 486 | struct Health |
| 487 | { |
| 488 | std::string Status; |
| 489 | int FailingStreak{}; |
| 490 | std::vector<HealthcheckResult> Log; |
| 491 | |
| 492 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Health, Status, FailingStreak, Log); |
| 493 | }; |
| 494 | |
| 495 | struct ContainerInspectState |
| 496 | { |
| 497 | std::string Status; |
| 498 | bool Running{}; |
| 499 | int ExitCode{}; |
| 500 | std::string StartedAt; |
| 501 | std::string FinishedAt; |
| 502 | std::optional<Health> Health; |
| 503 | |
| 504 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ContainerInspectState, Status, Running, ExitCode, StartedAt, FinishedAt, Health); |
| 505 | }; |
| 506 | |
| 507 | struct ContainerConfig |
| 508 | { |
| 509 | std::string Image; |
| 510 | std::string User; |
| 511 | std::string WorkingDir; |
| 512 | std::optional<std::vector<std::string>> Env; |
| 513 | std::optional<std::vector<std::string>> Cmd; |
| 514 | std::optional<std::vector<std::string>> Entrypoint; |
| 515 | std::optional<std::string> StopSignal; |
| 516 | std::optional<int> StopTimeout; |
| 517 | std::optional<HealthConfig> Healthcheck; |
| 518 | // Optional because dockerd may emit `"Labels": null` for containers with no merged labels. |
| 519 | std::optional<std::map<std::string, std::string>> Labels; |
| 520 | |
| 521 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ContainerConfig, Image, User, WorkingDir, Env, Cmd, Entrypoint, StopSignal, StopTimeout, Healthcheck, Labels); |
| 522 | }; |
| 523 | |
| 524 | struct InspectMount |
| 525 | { |
| 526 | std::string Type; |
| 527 | std::string Name; |
| 528 | std::string Source; |
| 529 | std::string Destination; |
| 530 | bool RW{}; |
| 531 | |
| 532 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(InspectMount, Type, Name, Source, Destination, RW); |
| 533 | }; |
| 534 | |
| 535 | struct InspectContainer |
| 536 | { |
| 537 | std::string Id; |
| 538 | std::string Name; |
| 539 | std::string Created; |
| 540 | std::string Image; |
| 541 | ContainerInspectState State; |
| 542 | ContainerConfig Config; |
| 543 | HostConfig HostConfig; |
| 544 | std::vector<InspectMount> Mounts; |
| 545 | NetworkSettings NetworkSettings; |
| 546 | std::optional<int64_t> SizeRw; |
| 547 | std::optional<int64_t> SizeRootFs; |
| 548 | |
| 549 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT( |
| 550 | InspectContainer, Id, Name, Created, Image, State, Config, HostConfig, Mounts, NetworkSettings, SizeRw, SizeRootFs); |
| 551 | }; |
| 552 | |
| 553 | struct InspectExec |
| 554 | { |
| 555 | // N.B. Pid is a non-nullable int in moby's schema; it is 0 until runc forks the user process. ExitCode is a *int and |
| 556 | // is null until the exec exits. |
| 557 | int Pid{}; |
| 558 | std::optional<int> ExitCode{}; |
| 559 | bool Running{}; |
| 560 | |
| 561 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(InspectExec, Pid, ExitCode, Running); |
| 562 | }; |
| 563 | |
| 564 | struct PruneContainerResult |
| 565 | { |
| 566 | std::optional<std::vector<std::string>> ContainersDeleted; // Null if no containers were deleted. |
| 567 | uint64_t SpaceReclaimed{}; |
| 568 | |
| 569 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(PruneContainerResult, ContainersDeleted, SpaceReclaimed); |
| 570 | }; |
| 571 | |
| 572 | struct Image |
| 573 | { |
| 574 | std::string Id; |
| 575 | std::vector<std::string> RepoTags; |
| 576 | std::vector<std::string> RepoDigests; |
| 577 | int64_t Size{}; |
| 578 | int64_t Created{}; |
| 579 | std::string ParentId; |
| 580 | |
| 581 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Image, Id, RepoTags, RepoDigests, Size, Created, ParentId); |
| 582 | }; |
| 583 | |
| 584 | struct DeletedImage |
| 585 | { |
| 586 | std::string Untagged; |
| 587 | std::string Deleted; |
| 588 | |
| 589 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(DeletedImage, Untagged, Deleted); |
| 590 | }; |
| 591 | |
| 592 | struct PruneImageResult |
| 593 | { |
| 594 | std::optional<std::vector<DeletedImage>> ImagesDeleted; |
| 595 | uint64_t SpaceReclaimed{}; |
| 596 | |
| 597 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(PruneImageResult, ImagesDeleted, SpaceReclaimed); |
| 598 | }; |
| 599 | |
| 600 | struct PruneVolumeResult |
| 601 | { |
| 602 | std::optional<std::vector<std::string>> VolumesDeleted; |
| 603 | uint64_t SpaceReclaimed{}; |
| 604 | |
| 605 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(PruneVolumeResult, VolumesDeleted, SpaceReclaimed); |
| 606 | }; |
| 607 | |
| 608 | struct PruneNetworkResult |
| 609 | { |
| 610 | std::optional<std::vector<std::string>> NetworksDeleted; |
| 611 | |
| 612 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(PruneNetworkResult, NetworksDeleted); |
| 613 | }; |
| 614 | |
| 615 | struct ImportStatus |
| 616 | { |
| 617 | std::string status; |
| 618 | |
| 619 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ImportStatus, status); |
| 620 | }; |
| 621 | |
| 622 | struct ImageConfig |
| 623 | { |
| 624 | std::string User; |
| 625 | std::optional<std::map<std::string, EmptyObject>> ExposedPorts; |
| 626 | std::optional<std::vector<std::string>> Env; |
| 627 | std::optional<std::vector<std::string>> Cmd; |
| 628 | std::optional<std::vector<std::string>> Entrypoint; |
| 629 | std::optional<std::map<std::string, EmptyObject>> Volumes; |
| 630 | std::string WorkingDir; |
| 631 | std::optional<std::map<std::string, std::string>> Labels; |
| 632 | std::string StopSignal; |
| 633 | std::optional<std::vector<std::string>> Shell; |
| 634 | |
| 635 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ImageConfig, User, ExposedPorts, Env, Cmd, Entrypoint, Volumes, WorkingDir, Labels, StopSignal, Shell); |
| 636 | }; |
| 637 | |
| 638 | struct RootFS |
| 639 | { |
| 640 | std::string Type; |
| 641 | std::optional<std::vector<std::string>> Layers; |
| 642 | |
| 643 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(RootFS, Type, Layers); |
| 644 | }; |
| 645 | |
| 646 | struct GraphDriverData |
| 647 | { |
| 648 | std::string Name; |
| 649 | std::optional<std::map<std::string, std::string>> Data; |
| 650 | |
| 651 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GraphDriverData, Name, Data); |
| 652 | }; |
| 653 | |
| 654 | struct InspectImage |
| 655 | { |
| 656 | std::string Id; |
| 657 | std::optional<std::vector<std::string>> RepoTags; |
| 658 | std::optional<std::vector<std::string>> RepoDigests; |
| 659 | std::string Parent; |
| 660 | std::string Comment; |
| 661 | std::string Created; |
| 662 | std::optional<ImageConfig> Config; |
| 663 | std::string Author; |
| 664 | std::string Architecture; |
| 665 | std::string Variant; |
| 666 | std::string Os; |
| 667 | std::string OsVersion; |
| 668 | int64_t Size{}; |
| 669 | std::optional<GraphDriverData> GraphDriver; |
| 670 | std::optional<RootFS> RootFS; |
| 671 | std::optional<std::map<std::string, std::string>> Metadata; |
| 672 | |
| 673 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT( |
| 674 | InspectImage, Id, RepoTags, RepoDigests, Parent, Comment, Created, Config, Author, Architecture, Variant, Os, OsVersion, Size, GraphDriver, RootFS, Metadata); |
| 675 | }; |
| 676 | |
| 677 | struct CreateExecResponse |
| 678 | { |
| 679 | std::string Id; |
| 680 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(CreateExecResponse, Id); |
| 681 | }; |
| 682 | |
| 683 | struct CreateExec |
| 684 | { |
| 685 | using TResponse = CreateExecResponse; |
| 686 | |
| 687 | bool AttachStdin{}; |
| 688 | bool AttachStdout{}; |
| 689 | bool AttachStderr{}; |
| 690 | bool Tty{}; |
| 691 | // Docker wire type is *[2]uint64. Sending an empty array on a TTY exec yields |
| 692 | // a 0x0 console; the field must be omitted entirely when the caller didn't set it. |
| 693 | std::vector<ULONG> ConsoleSize; |
| 694 | std::vector<std::string> Cmd; |
| 695 | std::vector<std::string> Env; |
| 696 | std::optional<std::string> User; |
| 697 | std::string WorkingDir; |
| 698 | std::optional<std::string> DetachKeys; |
| 699 | }; |
| 700 | |
| 701 | inline void to_json(nlohmann::json& j, const CreateExec& v) |
| 702 | { |
| 703 | j = nlohmann::json{ |
| 704 | {"AttachStdin", v.AttachStdin}, |
| 705 | {"AttachStdout", v.AttachStdout}, |
| 706 | {"AttachStderr", v.AttachStderr}, |
| 707 | {"Tty", v.Tty}, |
| 708 | {"Cmd", v.Cmd}, |
| 709 | {"Env", v.Env}, |
| 710 | {"WorkingDir", v.WorkingDir}, |
| 711 | {"User", v.User}, |
| 712 | {"DetachKeys", v.DetachKeys}, |
| 713 | }; |
| 714 | |
| 715 | if (!v.ConsoleSize.empty()) |
| 716 | { |
| 717 | j["ConsoleSize"] = v.ConsoleSize; |
| 718 | } |
| 719 | } |
| 720 | |
| 721 | struct StartExec |
| 722 | { |
| 723 | using TResponse = void; |
| 724 | bool Tty{}; |
| 725 | bool Detach{}; |
| 726 | // See CreateExec::ConsoleSize. |
| 727 | std::vector<ULONG> ConsoleSize; |
| 728 | }; |
| 729 | |
| 730 | inline void to_json(nlohmann::json& j, const StartExec& v) |
| 731 | { |
| 732 | j = nlohmann::json{{"Tty", v.Tty}, {"Detach", v.Detach}}; |
| 733 | |
| 734 | if (!v.ConsoleSize.empty()) |
| 735 | { |
| 736 | j["ConsoleSize"] = v.ConsoleSize; |
| 737 | } |
| 738 | } |
| 739 | |
| 740 | enum class ContainerState |
| 741 | { |
| 742 | Unknown, |
| 743 | Created, |
| 744 | Running, |
| 745 | Paused, |
| 746 | Restarting, |
| 747 | Exited, |
| 748 | Removing, |
| 749 | Dead |
| 750 | }; |
| 751 | |
| 752 | NLOHMANN_JSON_SERIALIZE_ENUM( |
| 753 | ContainerState, |
| 754 | { |
| 755 | // Unknown is first so unrecognized strings (or missing field) deserialize to Unknown, |
| 756 | // not to whatever the next entry happens to be. |
| 757 | {ContainerState::Unknown, nullptr}, |
| 758 | {ContainerState::Created, "created"}, |
| 759 | {ContainerState::Running, "running"}, |
| 760 | {ContainerState::Paused, "paused"}, |
| 761 | {ContainerState::Restarting, "restarting"}, |
| 762 | {ContainerState::Exited, "exited"}, |
| 763 | {ContainerState::Removing, "removing"}, |
| 764 | {ContainerState::Dead, "dead"}, |
| 765 | }); |
| 766 | |
| 767 | struct Port |
| 768 | { |
| 769 | uint16_t PrivatePort{}; |
| 770 | uint16_t PublicPort{}; |
| 771 | |
| 772 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Port, PrivatePort, PublicPort); |
| 773 | }; |
| 774 | |
| 775 | struct ContainerInfo |
| 776 | { |
| 777 | std::string Id; |
| 778 | std::vector<std::string> Names; |
| 779 | std::string Image; |
| 780 | std::string ImageID; |
| 781 | std::string Command; |
| 782 | std::string Status; |
| 783 | std::map<std::string, std::string> Labels; |
| 784 | std::vector<Port> Ports; |
| 785 | std::vector<Mount> Mounts; |
| 786 | ContainerState State{ContainerState::Unknown}; |
| 787 | int64_t Created{}; |
| 788 | HostConfig HostConfig; |
| 789 | NetworkSettings NetworkSettings; |
| 790 | |
| 791 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT( |
| 792 | ContainerInfo, Id, Names, Image, ImageID, Command, Status, Labels, Ports, Mounts, State, Created, HostConfig, NetworkSettings); |
| 793 | }; |
| 794 | |
| 795 | struct BuildKitVertex |
| 796 | { |
| 797 | std::string digest; |
| 798 | std::string name; |
| 799 | std::string started; |
| 800 | std::string completed; |
| 801 | std::string error; |
| 802 | bool cached{}; |
| 803 | |
| 804 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(BuildKitVertex, digest, name, started, completed, error, cached); |
| 805 | }; |
| 806 | |
| 807 | struct BuildKitStatus |
| 808 | { |
| 809 | std::string id; |
| 810 | std::string vertex; |
| 811 | int64_t current{}; |
| 812 | int64_t total{}; |
| 813 | |
| 814 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(BuildKitStatus, id, vertex, current, total); |
| 815 | }; |
| 816 | |
| 817 | struct BuildKitLog |
| 818 | { |
| 819 | std::string vertex; |
| 820 | std::string data; // base64-encoded output |
| 821 | int stream{}; // 1 = stdout, 2 = stderr |
| 822 | |
| 823 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(BuildKitLog, vertex, data, stream); |
| 824 | }; |
| 825 | |
| 826 | struct BuildKitSolveStatus |
| 827 | { |
| 828 | std::vector<BuildKitVertex> vertexes; |
| 829 | std::vector<BuildKitStatus> statuses; |
| 830 | std::vector<BuildKitLog> logs; |
| 831 | |
| 832 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(BuildKitSolveStatus, vertexes, statuses, logs); |
| 833 | }; |
| 834 | |
| 835 | struct CreateImageProgressDetails |
| 836 | { |
| 837 | uint64_t current{}; |
| 838 | uint64_t total{}; |
| 839 | std::string unit; |
| 840 | |
| 841 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(CreateImageProgressDetails, current, total, unit); |
| 842 | }; |
| 843 | |
| 844 | struct CreateImageProgress |
| 845 | { |
| 846 | std::string status; |
| 847 | std::string id; |
| 848 | std::optional<ErrorResponse> errorDetail; |
| 849 | |
| 850 | CreateImageProgressDetails progressDetail; |
| 851 | |
| 852 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(CreateImageProgress, status, id, progressDetail, errorDetail); |
| 853 | }; |
| 854 | |
| 855 | // Container stats (GET /containers/{id}/stats?stream=false) |
| 856 | // See: https://docs.docker.com/reference/api/engine/version/v1.44/#tag/Container/operation/ContainerStats |
| 857 | |
| 858 | struct ContainerStatsCpuUsage |
| 859 | { |
| 860 | uint64_t total_usage{}; |
| 861 | std::optional<std::vector<uint64_t>> percpu_usage; |
| 862 | uint64_t usage_in_kernelmode{}; |
| 863 | uint64_t usage_in_usermode{}; |
| 864 | |
| 865 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ContainerStatsCpuUsage, total_usage, percpu_usage, usage_in_kernelmode, usage_in_usermode); |
| 866 | }; |
| 867 | |
| 868 | struct ContainerStatsCpuStats |
| 869 | { |
| 870 | ContainerStatsCpuUsage cpu_usage; |
| 871 | uint64_t system_cpu_usage{}; |
| 872 | uint32_t online_cpus{}; |
| 873 | |
| 874 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ContainerStatsCpuStats, cpu_usage, system_cpu_usage, online_cpus); |
| 875 | }; |
| 876 | |
| 877 | struct ContainerStatsMemoryStats |
| 878 | { |
| 879 | uint64_t usage{}; |
| 880 | uint64_t limit{}; |
| 881 | |
| 882 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ContainerStatsMemoryStats, usage, limit); |
| 883 | }; |
| 884 | |
| 885 | struct ContainerStatsNetworkEntry |
| 886 | { |
| 887 | uint64_t rx_bytes{}; |
| 888 | uint64_t rx_packets{}; |
| 889 | uint64_t tx_bytes{}; |
| 890 | uint64_t tx_packets{}; |
| 891 | |
| 892 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ContainerStatsNetworkEntry, rx_bytes, rx_packets, tx_bytes, tx_packets); |
| 893 | }; |
| 894 | |
| 895 | struct ContainerStatsBlkioEntry |
| 896 | { |
| 897 | std::string op; |
| 898 | uint64_t value{}; |
| 899 | |
| 900 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ContainerStatsBlkioEntry, op, value); |
| 901 | }; |
| 902 | |
| 903 | struct ContainerStatsBlkioStats |
| 904 | { |
| 905 | std::optional<std::vector<ContainerStatsBlkioEntry>> io_service_bytes_recursive; |
| 906 | |
| 907 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ContainerStatsBlkioStats, io_service_bytes_recursive); |
| 908 | }; |
| 909 | |
| 910 | struct ContainerStatsPidsStats |
| 911 | { |
| 912 | uint64_t current{}; |
| 913 | |
| 914 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ContainerStatsPidsStats, current); |
| 915 | }; |
| 916 | |
| 917 | struct ContainerStats |
| 918 | { |
| 919 | std::string id; |
| 920 | std::string name; |
| 921 | ContainerStatsCpuStats cpu_stats; |
| 922 | ContainerStatsCpuStats precpu_stats; |
| 923 | ContainerStatsMemoryStats memory_stats; |
| 924 | std::optional<std::map<std::string, ContainerStatsNetworkEntry>> networks; |
| 925 | ContainerStatsBlkioStats blkio_stats; |
| 926 | ContainerStatsPidsStats pids_stats; |
| 927 | |
| 928 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ContainerStats, id, name, cpu_stats, precpu_stats, memory_stats, networks, blkio_stats, pids_stats); |
| 929 | }; |
| 930 | |
| 931 | } // namespace wsl::windows::common::docker_schema |