@@ -95,14 +95,24 @@ func (m *manager) createInstance(
9595 imageCtx , imageSpanEnd := m .startLifecycleStep (ctx , "resolve_image" ,
9696 attribute .String ("operation" , "resolve_image" ),
9797 )
98+ waitNameForDigest := func (digest string ) string {
99+ if strings .TrimSpace (digest ) == "" {
100+ return req .Image
101+ }
102+ normalizedRef , parseErr := images .ParseNormalizedRef (req .Image )
103+ if parseErr != nil {
104+ return req .Image
105+ }
106+ return normalizedRef .Repository () + "@" + digest
107+ }
98108 imageInfo , err := m .imageManager .GetImage (imageCtx , req .Image )
99109 if err != nil {
100110 if err == images .ErrNotFound {
101111 // Auto-pull: image not found locally, kick off the pull in the
102112 // background and wait up to 5 seconds for it to complete. Thread the
103113 // requested platform so boot-by-tag pulls the right architecture.
104114 log .InfoContext (ctx , "image not found locally, auto-pulling" , "image" , req .Image , "platform" , req .Platform )
105- _ , pullErr := m .imageManager .CreateImage (imageCtx , images.CreateImageRequest {Name : req .Image , Platform : req .Platform })
115+ pulledImage , pullErr := m .imageManager .CreateImage (imageCtx , images.CreateImageRequest {Name : req .Image , Platform : req .Platform })
106116 if pullErr != nil {
107117 imageSpanEnd (pullErr )
108118 log .ErrorContext (ctx , "failed to auto-pull image" , "image" , req .Image , "error" , pullErr )
@@ -112,7 +122,11 @@ func (m *manager) createInstance(
112122 // we return an error but let it continue in the background.
113123 pullCtx , pullCancel := context .WithTimeout (imageCtx , 5 * time .Second )
114124 defer pullCancel ()
115- if waitErr := m .imageManager .WaitForReady (pullCtx , req .Image ); waitErr != nil {
125+ waitName := req .Image
126+ if pulledImage != nil {
127+ waitName = waitNameForDigest (pulledImage .Digest )
128+ }
129+ if waitErr := m .imageManager .WaitForReady (pullCtx , waitName ); waitErr != nil {
116130 imageSpanEnd (waitErr )
117131 log .InfoContext (ctx , "image pull not ready within timeout, pull continues in background" , "image" , req .Image , "error" , waitErr )
118132 return nil , fmt .Errorf ("%w: image %s is being pulled, please try again shortly" , ErrImageNotReady , req .Image )
@@ -130,6 +144,52 @@ func (m *manager) createInstance(
130144 return nil , fmt .Errorf ("get image: %w" , err )
131145 }
132146 }
147+ if strings .TrimSpace (req .Platform ) != "" {
148+ requestedPlatform , parseErr := images .ParsePlatform (req .Platform )
149+ if parseErr != nil {
150+ imageSpanEnd (parseErr )
151+ log .ErrorContext (ctx , "invalid requested image platform" , "image" , req .Image , "platform" , req .Platform , "error" , parseErr )
152+ return nil , parseErr
153+ }
154+ resolvedPlatform , parseErr := images .ParsePlatform (imageInfo .Platform )
155+ platformMismatch := parseErr != nil || resolvedPlatform .String () != requestedPlatform .String ()
156+ if platformMismatch {
157+ log .InfoContext (ctx ,
158+ "resolved image platform differs from request, reconciling" ,
159+ "image" , req .Image ,
160+ "requested_platform" , requestedPlatform .String (),
161+ "resolved_platform" , imageInfo .Platform ,
162+ )
163+ pulledImage , pullErr := m .imageManager .CreateImage (imageCtx , images.CreateImageRequest {Name : req .Image , Platform : requestedPlatform .String ()})
164+ if pullErr != nil {
165+ imageSpanEnd (pullErr )
166+ log .ErrorContext (ctx , "failed to resolve requested image platform" , "image" , req .Image , "platform" , requestedPlatform .String (), "error" , pullErr )
167+ return nil , fmt .Errorf ("resolve image for platform %s: %w" , requestedPlatform , pullErr )
168+ }
169+ pullCtx , pullCancel := context .WithTimeout (imageCtx , 5 * time .Second )
170+ defer pullCancel ()
171+ waitName := req .Image
172+ if pulledImage != nil {
173+ waitName = waitNameForDigest (pulledImage .Digest )
174+ }
175+ if waitErr := m .imageManager .WaitForReady (pullCtx , waitName ); waitErr != nil {
176+ imageSpanEnd (waitErr )
177+ log .InfoContext (ctx ,
178+ "platform-specific image pull not ready within timeout, pull continues in background" ,
179+ "image" , req .Image ,
180+ "platform" , requestedPlatform .String (),
181+ "error" , waitErr ,
182+ )
183+ return nil , fmt .Errorf ("%w: image %s for platform %s is being pulled, please try again shortly" , ErrImageNotReady , req .Image , requestedPlatform )
184+ }
185+ imageInfo , err = m .imageManager .GetImage (imageCtx , req .Image )
186+ if err != nil {
187+ imageSpanEnd (err )
188+ log .ErrorContext (ctx , "failed to get image after platform reconciliation" , "image" , req .Image , "platform" , requestedPlatform .String (), "error" , err )
189+ return nil , fmt .Errorf ("get image after platform reconciliation: %w" , err )
190+ }
191+ }
192+ }
133193 imageSpanEnd (nil )
134194
135195 if imageInfo .Status != images .StatusReady {
0 commit comments