@@ -5,7 +5,10 @@ package controller
55
66import (
77 "context"
8+ "encoding/json"
89 "fmt"
10+ "github.com/containerd/containerd/remotes/docker"
11+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
912 "strings"
1013
1114 corev1 "k8s.io/api/core/v1"
@@ -25,6 +28,10 @@ import (
2528 metalv1alpha1 "github.com/ironcore-dev/metal-operator/api/v1alpha1"
2629)
2730
31+ const (
32+ MediaTypeUKI = "application/vnd.ironcore.image.uki"
33+ )
34+
2835type ServerBootConfigurationHTTPReconciler struct {
2936 client.Client
3037 Scheme * runtime.Scheme
@@ -75,7 +82,10 @@ func (r *ServerBootConfigurationHTTPReconciler) reconcile(ctx context.Context, l
7582 }
7683 log .V (1 ).Info ("Got system IPs from Server" , "systemIPs" , systemIPs )
7784
78- ukiURL := r .constructUKIURL (config .Spec .Image )
85+ ukiURL , err := r .constructUKIURL (ctx , config .Spec .Image )
86+ if err != nil {
87+ return ctrl.Result {}, fmt .Errorf ("failed to construct UKI URL: %w" , err )
88+ }
7989 log .V (1 ).Info ("Extracted UKI URL for boot" )
8090
8191 httpBootConfig := & bootv1alpha1.HTTPBootConfig {
@@ -166,16 +176,46 @@ func (r *ServerBootConfigurationHTTPReconciler) getSystemIPFromServer(ctx contex
166176 return systemIPs , nil
167177}
168178
169- func (r * ServerBootConfigurationHTTPReconciler ) constructUKIURL (image string ) string {
170- sanitizedImage := strings .ReplaceAll (image , "/" , "-" )
171- sanitizedImage = strings .ReplaceAll (sanitizedImage , ":" , "-" )
172- sanitizedImage = strings .ReplaceAll (sanitizedImage , "https://" , "" )
173- sanitizedImage = strings .ReplaceAll (sanitizedImage , "http://" , "" )
179+ func (r * ServerBootConfigurationHTTPReconciler ) constructUKIURL (ctx context.Context , image string ) (string , error ) {
180+ imageDetails := strings .Split (image , ":" )
181+ if len (imageDetails ) != 2 {
182+ return "" , fmt .Errorf ("invalid image format" )
183+ }
184+
185+ ukiDigest , err := r .getUKIDigestFromNestedManifest (ctx , imageDetails [0 ], imageDetails [1 ])
186+ if err != nil {
187+ return "" , fmt .Errorf ("failed to fetch UKI layer digest: %w" , err )
188+ }
189+
190+ ukiURL := fmt .Sprintf ("%s/image?imageName=%s&version=%s&layerDigest=%s" , r .ImageServerURL , imageDetails [0 ], imageDetails [1 ], ukiDigest )
191+ return ukiURL , nil
192+ }
193+
194+ func (r * ServerBootConfigurationHTTPReconciler ) getUKIDigestFromNestedManifest (ctx context.Context , imageName , imageVersion string ) (string , error ) {
195+ resolver := docker .NewResolver (docker.ResolverOptions {})
196+ imageRef := fmt .Sprintf ("%s:%s" , imageName , imageVersion )
197+ name , desc , err := resolver .Resolve (ctx , imageRef )
198+ if err != nil {
199+ return "" , fmt .Errorf ("failed to resolve image reference: %w" , err )
200+ }
201+
202+ manifestData , err := fetchContent (ctx , resolver , name , desc )
203+ if err != nil {
204+ return "" , fmt .Errorf ("failed to fetch manifest data: %w" , err )
205+ }
206+
207+ var manifest ocispec.Manifest
208+ if err := json .Unmarshal (manifestData , & manifest ); err != nil {
209+ return "" , fmt .Errorf ("failed to unmarshal manifest: %w" , err )
210+ }
174211
175- filename := fmt .Sprintf ("%s-uki.efi" , sanitizedImage )
212+ for _ , layer := range manifest .Layers {
213+ if layer .MediaType == MediaTypeUKI {
214+ return layer .Digest .String (), nil
215+ }
216+ }
176217
177- ukiURL := fmt .Sprintf ("%s/%s" , r .ImageServerURL , filename )
178- return ukiURL
218+ return "" , fmt .Errorf ("UKI layer digest not found" )
179219}
180220
181221// SetupWithManager sets up the controller with the Manager.
0 commit comments