@@ -5,9 +5,13 @@ package controller
55
66import (
77 "context"
8+ "encoding/json"
89 "fmt"
910 "strings"
1011
12+ "github.com/containerd/containerd/remotes/docker"
13+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
14+
1115 corev1 "k8s.io/api/core/v1"
1216 "k8s.io/apimachinery/pkg/types"
1317 "sigs.k8s.io/controller-runtime/pkg/handler"
@@ -25,6 +29,10 @@ import (
2529 metalv1alpha1 "github.com/ironcore-dev/metal-operator/api/v1alpha1"
2630)
2731
32+ const (
33+ MediaTypeUKI = "application/vnd.ironcore.image.uki"
34+ )
35+
2836type ServerBootConfigurationHTTPReconciler struct {
2937 client.Client
3038 Scheme * runtime.Scheme
@@ -75,7 +83,10 @@ func (r *ServerBootConfigurationHTTPReconciler) reconcile(ctx context.Context, l
7583 }
7684 log .V (1 ).Info ("Got system IPs from Server" , "systemIPs" , systemIPs )
7785
78- ukiURL := r .constructUKIURL (config .Spec .Image )
86+ ukiURL , err := r .constructUKIURL (ctx , config .Spec .Image )
87+ if err != nil {
88+ return ctrl.Result {}, fmt .Errorf ("failed to construct UKI URL: %w" , err )
89+ }
7990 log .V (1 ).Info ("Extracted UKI URL for boot" )
8091
8192 httpBootConfig := & bootv1alpha1.HTTPBootConfig {
@@ -166,16 +177,46 @@ func (r *ServerBootConfigurationHTTPReconciler) getSystemIPFromServer(ctx contex
166177 return systemIPs , nil
167178}
168179
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://" , "" )
180+ func (r * ServerBootConfigurationHTTPReconciler ) constructUKIURL (ctx context.Context , image string ) (string , error ) {
181+ imageDetails := strings .Split (image , ":" )
182+ if len (imageDetails ) != 2 {
183+ return "" , fmt .Errorf ("invalid image format" )
184+ }
185+
186+ ukiDigest , err := r .getUKIDigestFromNestedManifest (ctx , imageDetails [0 ], imageDetails [1 ])
187+ if err != nil {
188+ return "" , fmt .Errorf ("failed to fetch UKI layer digest: %w" , err )
189+ }
190+
191+ ukiURL := fmt .Sprintf ("%s/image?imageName=%s&version=%s&layerDigest=%s" , r .ImageServerURL , imageDetails [0 ], imageDetails [1 ], ukiDigest )
192+ return ukiURL , nil
193+ }
174194
175- filename := fmt .Sprintf ("%s-uki.efi" , sanitizedImage )
195+ func (r * ServerBootConfigurationHTTPReconciler ) getUKIDigestFromNestedManifest (ctx context.Context , imageName , imageVersion string ) (string , error ) {
196+ resolver := docker .NewResolver (docker.ResolverOptions {})
197+ imageRef := fmt .Sprintf ("%s:%s" , imageName , imageVersion )
198+ name , desc , err := resolver .Resolve (ctx , imageRef )
199+ if err != nil {
200+ return "" , fmt .Errorf ("failed to resolve image reference: %w" , err )
201+ }
202+
203+ manifestData , err := fetchContent (ctx , resolver , name , desc )
204+ if err != nil {
205+ return "" , fmt .Errorf ("failed to fetch manifest data: %w" , err )
206+ }
207+
208+ var manifest ocispec.Manifest
209+ if err := json .Unmarshal (manifestData , & manifest ); err != nil {
210+ return "" , fmt .Errorf ("failed to unmarshal manifest: %w" , err )
211+ }
212+
213+ for _ , layer := range manifest .Layers {
214+ if layer .MediaType == MediaTypeUKI {
215+ return layer .Digest .String (), nil
216+ }
217+ }
176218
177- ukiURL := fmt .Sprintf ("%s/%s" , r .ImageServerURL , filename )
178- return ukiURL
219+ return "" , fmt .Errorf ("UKI layer digest not found" )
179220}
180221
181222// SetupWithManager sets up the controller with the Manager.
0 commit comments