master
h 931 lines 25.6 KB
Raw
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