@@ -55,19 +55,6 @@ public Map<String, Object> adaptImageResponse(Map<String, Object> response) {
5555
5656 Map <String , Object > adapted = new HashMap <>(response );
5757
58- // v1.48+ includes ImageManifestDescriptor for multi-platform images
59- if (adapted .containsKey ("ImageManifestDescriptor" )) {
60- LOG .fine (
61- "Image response includes ImageManifestDescriptor (multi-platform support in API v"
62- + apiVersion
63- + ")" );
64- }
65-
66- // v1.48+ includes Descriptor field (OCI descriptor)
67- if (adapted .containsKey ("Descriptor" )) {
68- LOG .fine ("Image response includes OCI Descriptor field (API v" + apiVersion + ")" );
69- }
70-
7158 // Ensure VirtualSize is not present (removed in v1.44)
7259 if (adapted .containsKey ("VirtualSize" )) {
7360 LOG .warning (
@@ -77,6 +64,46 @@ public Map<String, Object> adaptImageResponse(Map<String, Object> response) {
7764 adapted .remove ("VirtualSize" );
7865 }
7966
67+ // Ensure Size field is present (required in v1.44+)
68+ if (!adapted .containsKey ("Size" )) {
69+ LOG .warning ("Size field missing from image response in API v" + apiVersion );
70+ }
71+
72+ // v1.48+ includes ImageManifestDescriptor for multi-platform images
73+ // Extract platform information for better observability
74+ if (adapted .containsKey ("ImageManifestDescriptor" )) {
75+ @ SuppressWarnings ("unchecked" )
76+ Map <String , Object > descriptor = (Map <String , Object >) adapted .get ("ImageManifestDescriptor" );
77+ if (descriptor != null && descriptor .containsKey ("platform" )) {
78+ Object platformObj = descriptor .get ("platform" );
79+ if (platformObj instanceof Map ) {
80+ @ SuppressWarnings ("unchecked" )
81+ Map <String , Object > platform = (Map <String , Object >) platformObj ;
82+ String arch = (String ) platform .get ("architecture" );
83+ String os = (String ) platform .get ("os" );
84+ if (arch != null && os != null ) {
85+ LOG .fine (
86+ String .format (
87+ "Image is platform-specific: %s/%s (API v%s multi-platform support)" ,
88+ os , arch , apiVersion ));
89+ }
90+ }
91+ }
92+ }
93+
94+ // v1.48+ includes Descriptor field (OCI descriptor)
95+ // Validate OCI descriptor structure
96+ if (adapted .containsKey ("Descriptor" )) {
97+ @ SuppressWarnings ("unchecked" )
98+ Map <String , Object > descriptor = (Map <String , Object >) adapted .get ("Descriptor" );
99+ if (descriptor != null ) {
100+ String mediaType = (String ) descriptor .get ("mediaType" );
101+ if (mediaType != null ) {
102+ LOG .fine ("Image includes OCI descriptor with mediaType: " + mediaType );
103+ }
104+ }
105+ }
106+
80107 return adapted ;
81108 }
82109
@@ -89,6 +116,7 @@ public Map<String, Object> adaptContainerCreateRequest(Map<String, Object> reque
89116 Map <String , Object > adapted = new HashMap <>(request );
90117
91118 // v1.48+ supports Mount type "image" for mounting images inside containers
119+ // Validate image mount configurations
92120 @ SuppressWarnings ("unchecked" )
93121 Map <String , Object > hostConfig = (Map <String , Object >) adapted .get ("HostConfig" );
94122
@@ -104,17 +132,31 @@ public Map<String, Object> adaptContainerCreateRequest(Map<String, Object> reque
104132 String type = (String ) mountMap .get ("Type" );
105133
106134 if ("image" .equals (type )) {
107- LOG .fine (
108- "Container creation includes image mount type (supported in API v"
109- + apiVersion
110- + "+)" );
135+ // Validate required fields for image mounts
136+ String source = (String ) mountMap .get ("Source" );
137+ String target = (String ) mountMap .get ("Target" );
138+
139+ if (source == null || source .isEmpty ()) {
140+ LOG .warning ("Image mount missing required 'Source' field" );
141+ }
142+ if (target == null || target .isEmpty ()) {
143+ LOG .warning ("Image mount missing required 'Target' field" );
144+ }
145+
146+ if (source != null && target != null ) {
147+ LOG .fine (
148+ String .format (
149+ "Mounting image '%s' at '%s' (API v%s+ image mount support)" ,
150+ source , target , apiVersion ));
151+ }
111152 }
112153 }
113154 }
114155 }
115156 }
116157
117158 // v1.48+ supports GwPriority in NetworkingConfig for gateway priority
159+ // Validate and log gateway priority configuration
118160 @ SuppressWarnings ("unchecked" )
119161 Map <String , Object > networkingConfig = (Map <String , Object >) adapted .get ("NetworkingConfig" );
120162
@@ -123,22 +165,39 @@ public Map<String, Object> adaptContainerCreateRequest(Map<String, Object> reque
123165 Map <String , Object > endpointsConfig =
124166 (Map <String , Object >) networkingConfig .get ("EndpointsConfig" );
125167
126- if (endpointsConfig != null ) {
168+ if (endpointsConfig != null && endpointsConfig .size () > 1 ) {
169+ // Track gateway priorities for multi-network containers
170+ int highestPriority = Integer .MIN_VALUE ;
171+ String defaultGatewayNetwork = null ;
172+
127173 for (Map .Entry <String , Object > entry : endpointsConfig .entrySet ()) {
128174 if (entry .getValue () instanceof Map ) {
129175 @ SuppressWarnings ("unchecked" )
130176 Map <String , Object > endpointConfig = (Map <String , Object >) entry .getValue ();
131177
132178 if (endpointConfig .containsKey ("GwPriority" )) {
133- LOG .fine (
134- "Network endpoint '"
135- + entry .getKey ()
136- + "' includes GwPriority (supported in API v"
137- + apiVersion
138- + "+)" );
179+ Object priorityObj = endpointConfig .get ("GwPriority" );
180+ int priority = priorityObj instanceof Number ? ((Number ) priorityObj ).intValue () : 0 ;
181+
182+ if (priority > highestPriority ) {
183+ highestPriority = priority ;
184+ defaultGatewayNetwork = entry .getKey ();
185+ }
139186 }
140187 }
141188 }
189+
190+ if (defaultGatewayNetwork != null ) {
191+ LOG .fine (
192+ String .format (
193+ "Container will use '%s' as default gateway (priority: %d, API v%s+)" ,
194+ defaultGatewayNetwork , highestPriority , apiVersion ));
195+ } else {
196+ LOG .fine (
197+ String .format (
198+ "Creating container with %d networks, no explicit gateway priority set" ,
199+ endpointsConfig .size ()));
200+ }
142201 }
143202 }
144203
@@ -153,34 +212,74 @@ public Map<String, Object> adaptContainerInspectResponse(Map<String, Object> res
153212
154213 Map <String , Object > adapted = new HashMap <>(response );
155214
156- // v1.48+ includes ImageManifestDescriptor
215+ // v1.48+ includes ImageManifestDescriptor with platform information
216+ // Extract and expose platform details for better observability
157217 if (adapted .containsKey ("ImageManifestDescriptor" )) {
158- LOG .fine (
159- "Container inspect includes ImageManifestDescriptor (multi-platform support in API v"
160- + apiVersion
161- + ")" );
218+ @ SuppressWarnings ("unchecked" )
219+ Map <String , Object > descriptor = (Map <String , Object >) adapted .get ("ImageManifestDescriptor" );
220+ if (descriptor != null && descriptor .containsKey ("platform" )) {
221+ Object platformObj = descriptor .get ("platform" );
222+ if (platformObj instanceof Map ) {
223+ @ SuppressWarnings ("unchecked" )
224+ Map <String , Object > platform = (Map <String , Object >) platformObj ;
225+ String arch = (String ) platform .get ("architecture" );
226+ String os = (String ) platform .get ("os" );
227+ String digest = (String ) descriptor .get ("digest" );
228+
229+ if (arch != null && os != null ) {
230+ LOG .fine (
231+ String .format (
232+ "Container running on %s/%s platform (digest: %s, API v%s+)" ,
233+ os ,
234+ arch ,
235+ digest != null ? digest .substring (0 , Math .min (12 , digest .length ())) : "unknown" ,
236+ apiVersion ));
237+ }
238+ }
239+ }
162240 }
163241
164242 // v1.48+ includes GwPriority in NetworkSettings
243+ // Identify which network is providing the default gateway
165244 @ SuppressWarnings ("unchecked" )
166- Map <String , Object > networkSettings = (Map <String , Object >) adapted .get ("NetworkSettings" );
245+ Map <String , Object > originalNetworkSettings =
246+ (Map <String , Object >) adapted .get ("NetworkSettings" );
247+
248+ if (originalNetworkSettings != null ) {
249+ // Create defensive copy to avoid mutating the original response
250+ Map <String , Object > networkSettings = new HashMap <>(originalNetworkSettings );
251+ adapted .put ("NetworkSettings" , networkSettings );
167252
168- if (networkSettings != null ) {
169253 @ SuppressWarnings ("unchecked" )
170254 Map <String , Object > networks = (Map <String , Object >) networkSettings .get ("Networks" );
171255
172- if (networks != null ) {
256+ if (networks != null && networks .size () > 1 ) {
257+ int highestPriority = Integer .MIN_VALUE ;
258+ String defaultGatewayNetwork = null ;
259+
173260 for (Map .Entry <String , Object > entry : networks .entrySet ()) {
174261 if (entry .getValue () instanceof Map ) {
175262 @ SuppressWarnings ("unchecked" )
176263 Map <String , Object > network = (Map <String , Object >) entry .getValue ();
177264
178265 if (network .containsKey ("GwPriority" )) {
179- LOG .fine (
180- "Network '" + entry .getKey () + "' includes GwPriority (API v" + apiVersion + ")" );
266+ Object priorityObj = network .get ("GwPriority" );
267+ int priority = priorityObj instanceof Number ? ((Number ) priorityObj ).intValue () : 0 ;
268+
269+ if (priority > highestPriority ) {
270+ highestPriority = priority ;
271+ defaultGatewayNetwork = entry .getKey ();
272+ }
181273 }
182274 }
183275 }
276+
277+ if (defaultGatewayNetwork != null ) {
278+ LOG .fine (
279+ String .format (
280+ "Container using '%s' as default gateway (priority: %d)" ,
281+ defaultGatewayNetwork , highestPriority ));
282+ }
184283 }
185284
186285 // Remove deprecated fields (should not be present in v1.48+)
0 commit comments