99 "fmt"
1010
1111 "github.com/gardener/gardener/extensions/pkg/controller/worker"
12+ gardencorev1beta1 "github.com/gardener/gardener/pkg/apis/core/v1beta1"
1213 v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants"
13- "k8s.io/utils/ptr "
14+ gardencorev1beta1helper "github.com/gardener/gardener/pkg/apis/core/v1beta1/helper "
1415 k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
1516
1617 api "github.com/gardener/gardener-extension-provider-openstack/pkg/apis/openstack"
@@ -38,10 +39,33 @@ func (w *workerDelegate) UpdateMachineImagesStatus(ctx context.Context) error {
3839 return nil
3940}
4041
41- func (w * workerDelegate ) findMachineImage (name , version , architecture string ) (* api.MachineImage , error ) {
42- image , err := helper .FindImageFromCloudProfile (w .cloudProfileConfig , name , version , w .cluster .Shoot .Spec .Region , architecture )
43- if err == nil {
44- return image , nil
42+ func (w * workerDelegate ) selectMachineImageForWorkerPool (name , version string , region string , arch * string , machineCapabilities gardencorev1beta1.Capabilities ) (* api.MachineImage , error ) {
43+ selectedMachineImage := & api.MachineImage {
44+ Name : name ,
45+ Version : version ,
46+ }
47+
48+ if capabilitySet , err := helper .FindImageInCloudProfile (w .cloudProfileConfig , name , version , region , arch , machineCapabilities , w .cluster .CloudProfile .Spec .MachineCapabilities ); err == nil {
49+ selectedMachineImage .Capabilities = capabilitySet .Capabilities
50+ // ID takes precedence over Image attribute. Reminder: Image is global name while ID is region specific.
51+ if capabilitySet .Regions [0 ].ID == "" {
52+ selectedMachineImage .Image = capabilitySet .Image
53+ } else {
54+ selectedMachineImage .ID = capabilitySet .Regions [0 ].ID
55+ }
56+
57+ if len (selectedMachineImage .Capabilities [v1beta1constants .ArchitectureName ]) > 0 {
58+ var selectedArch * string
59+ selectedArch = & selectedMachineImage .Capabilities [v1beta1constants .ArchitectureName ][0 ]
60+ // Verify that selectedMachineImage has correct architecture
61+ if selectedArch == nil || arch != nil && * selectedArch != * arch {
62+ return nil , fmt .Errorf ("architecture does not match for machine image" )
63+ }
64+ } else {
65+ selectedMachineImage .Architecture = capabilitySet .Regions [0 ].Architecture
66+ }
67+
68+ return selectedMachineImage , nil
4569 }
4670
4771 // Try to look up machine image in worker provider status as it was not found in componentconfig.
@@ -51,27 +75,46 @@ func (w *workerDelegate) findMachineImage(name, version, architecture string) (*
5175 return nil , fmt .Errorf ("could not decode worker status of worker '%s': %w" , k8sclient .ObjectKeyFromObject (w .worker ), err )
5276 }
5377
54- machineImage , err := helper .FindMachineImage (workerStatus .MachineImages , name , version , architecture )
55- if err != nil {
56- return nil , worker .ErrorMachineImageNotFound (name , version )
57- }
78+ return helper .FindImageInWorkerStatus (workerStatus .MachineImages , name , version , arch , machineCapabilities , w .cluster .CloudProfile .Spec .MachineCapabilities )
79+ }
5880
59- // The architecture field might not be present in the WorkerStatus if the Shoot has been created before introduction
60- // of the field. Hence, initialize it if it's empty.
61- machineImage = machineImage .DeepCopy ()
62- if machineImage .Architecture == nil {
63- machineImage .Architecture = & architecture
64- }
81+ return nil , worker .ErrorMachineImageNotFound (name , version , * arch , region )
82+ }
6583
66- return machineImage , nil
84+ func appendMachineImage (machineImages []api.MachineImage , machineImage api.MachineImage , capabilityDefinitions []gardencorev1beta1.CapabilityDefinition ) []api.MachineImage {
85+ // support for cloudprofile machine images without capabilities
86+ if len (capabilityDefinitions ) == 0 {
87+ for _ , image := range machineImages {
88+ if image .Name == machineImage .Name && image .Version == machineImage .Version && machineImage .Architecture == image .Architecture {
89+ // If the image already exists without capabilities, we can just return the existing list.
90+ return machineImages
91+ }
92+ }
93+ return append (machineImages , api.MachineImage {
94+ Name : machineImage .Name ,
95+ Version : machineImage .Version ,
96+ ID : machineImage .ID ,
97+ Architecture : machineImage .Architecture ,
98+ })
6799 }
68100
69- return nil , worker .ErrorMachineImageNotFound (name , version )
70- }
101+ defaultedCapabilities := gardencorev1beta1 .GetCapabilitiesWithAppliedDefaults (machineImage .Capabilities , capabilityDefinitions )
71102
72- func appendMachineImage (machineImages []api.MachineImage , machineImage api.MachineImage ) []api.MachineImage {
73- if _ , err := helper .FindMachineImage (machineImages , machineImage .Name , machineImage .Version , ptr .Deref (machineImage .Architecture , v1beta1constants .ArchitectureAMD64 )); err != nil {
74- return append (machineImages , machineImage )
103+ for _ , existingMachineImage := range machineImages {
104+ existingDefaultedCapabilities := gardencorev1beta1 .GetCapabilitiesWithAppliedDefaults (existingMachineImage .Capabilities , capabilityDefinitions )
105+ if existingMachineImage .Name == machineImage .Name && existingMachineImage .Version == machineImage .Version && gardencorev1beta1helper .AreCapabilitiesEqual (defaultedCapabilities , existingDefaultedCapabilities ) {
106+ // If the image already exists with the same capabilities return the existing list.
107+ return machineImages
108+ }
75109 }
110+
111+ // If the image does not exist, we create a new machine image entry with the capabilities.
112+ machineImages = append (machineImages , api.MachineImage {
113+ Name : machineImage .Name ,
114+ Version : machineImage .Version ,
115+ ID : machineImage .ID ,
116+ Capabilities : machineImage .Capabilities ,
117+ })
118+
76119 return machineImages
77120}
0 commit comments