@@ -23,6 +23,7 @@ import (
2323 "reflect"
2424 "sort"
2525 "strconv"
26+ "strings"
2627
2728 "github.com/go-logr/logr"
2829 infrastructurev1beta1 "github.com/oracle/cluster-api-provider-oci/api/v1beta1"
@@ -43,7 +44,9 @@ import (
4344 "sigs.k8s.io/controller-runtime/pkg/client"
4445)
4546
46- const OCIManagedMachinePoolKind = "OCIManagedMachinePool"
47+ const (
48+ OCIManagedMachinePoolKind = "OCIManagedMachinePool"
49+ )
4750
4851// ManagedMachinePoolScopeParams defines the params need to create a new ManagedMachinePoolScope
4952type ManagedMachinePoolScopeParams struct {
@@ -267,11 +270,14 @@ func (m *ManagedMachinePoolScope) CreateNodePool(ctx context.Context) (*oke.Node
267270 nodeShapeConfig .MemoryInGBs = common .Float32 (float32 (memoryInGBs ))
268271 }
269272 }
273+ err = m .setNodepoolImageId (ctx )
274+ if err != nil {
275+ return nil , err
276+ }
270277 sourceDetails := oke.NodeSourceViaImageDetails {
271- ImageId : m . OCIManagedMachinePool .Spec .NodeSourceViaImage .ImageId ,
278+ ImageId : machinePool .Spec .NodeSourceViaImage .ImageId ,
272279 BootVolumeSizeInGBs : machinePool .Spec .NodeSourceViaImage .BootVolumeSizeInGBs ,
273280 }
274-
275281 podNetworkOptions := machinePool .Spec .NodePoolNodeConfig .NodePoolPodNetworkOptionDetails
276282 if podNetworkOptions != nil {
277283 if podNetworkOptions .CniType == expinfra1 .VCNNativeCNI {
@@ -343,6 +349,80 @@ func (m *ManagedMachinePoolScope) CreateNodePool(ctx context.Context) (*oke.Node
343349 return m .getOKENodePoolFromOCID (ctx , nodePoolId )
344350}
345351
352+ func (m * ManagedMachinePoolScope ) setNodepoolImageId (ctx context.Context ) error {
353+ imageId := m .OCIManagedMachinePool .Spec .NodeSourceViaImage .ImageId
354+ if imageId != nil && * imageId != "" {
355+ return nil
356+ }
357+ response , err := m .ContainerEngineClient .GetNodePoolOptions (ctx , oke.GetNodePoolOptionsRequest {
358+ NodePoolOptionId : common .String ("all" ),
359+ CompartmentId : common .String (m .OCIManagedCluster .Spec .CompartmentId ),
360+ })
361+ if err != nil {
362+ m .Logger .Error (err , "Could not lookup node pool options" )
363+ return err
364+ }
365+ // version in the capoci spec starts with v, wheres as in the node pool options API in OKE
366+ // the image name does not contain . For example
367+ // {
368+ // "image-id": "ocid1.image.oc1.iad.aaaaaaaafp7ysdbfl2bg67s4jzbpewxo3k772baixa3vwzecwogl474qecza",
369+ // "source-name": "Oracle-Linux-8.6-aarch64-2022.12.15-0-OKE-1.25.4-543",
370+ // "source-type": "IMAGE"
371+ // },
372+ // {
373+ // "image-id": "ocid1.image.oc1.iad.aaaaaaaauwwokidwf5nfi34ucbvgnjsni3klnfmu6pz73ctdohb2byiw6ztq",
374+ // "source-name": "Oracle-Linux-8.6-2022.12.15-0-OKE-1.23.4-543",
375+ // "source-type": "IMAGE"
376+ // },
377+ // we will only default to non gpu image
378+
379+ // proper validation exists in webhook, this is to be fail-safe
380+ specVersion := m .OCIManagedMachinePool .Spec .Version
381+ if specVersion == nil || len (* specVersion ) < 1 {
382+ return errors .New (fmt .Sprintf ("invalid/nil kubernetes version is set in OCIManagedMachinePool Spec" ))
383+ }
384+ k8sVersion := (* specVersion )[1 :]
385+ shape := m .OCIManagedMachinePool .Spec .NodeShape
386+ isArmShape := strings .Contains (shape , "A1" )
387+ for _ , source := range response .Sources {
388+ image , ok := source .(oke.NodeSourceViaImageOption )
389+ if ok {
390+ sourceName := * image .SourceName
391+ if isValidImage (sourceName ) {
392+ // if source is an arm source and expectation is not an arm image, ignore
393+ if strings .Contains (sourceName , "aarch64" ) && ! isArmShape {
394+ continue
395+ }
396+ if strings .Contains (sourceName , k8sVersion ) {
397+ m .Info ("Image being used" , "Name" , sourceName , "OCID" , * image .ImageId )
398+ m .OCIManagedMachinePool .Spec .NodeSourceViaImage .ImageId = image .ImageId
399+ return nil
400+ }
401+ }
402+ }
403+ }
404+ sourceJson , err := json .Marshal (response .Sources )
405+ if err != nil {
406+ return err
407+ }
408+ err = errors .New (fmt .Sprintf ("could not lookup nodepool image id from nodepool options" ))
409+ m .Logger .Error (err , "Could not lookup an image corresponding to the kubernetes version from OKE nodepool options" ,
410+ "oke-node-pool-image-sources" , sourceJson )
411+ return err
412+ }
413+
414+ func isValidImage (sourceName string ) bool {
415+ // invalidImageSources is the array of names of source images that should be ignored to be considered as defaults
416+ // for node pool images
417+ invalidImageSources := []string {"GPU" }
418+ for _ , invalidImageSource := range invalidImageSources {
419+ if strings .Contains (sourceName , invalidImageSource ) {
420+ return false
421+ }
422+ }
423+ return true
424+ }
425+
346426func (m * ManagedMachinePoolScope ) getOKENodePoolFromOCID (ctx context.Context , nodePoolId * string ) (* oke.NodePool , error ) {
347427 req := oke.GetNodePoolRequest {NodePoolId : nodePoolId }
348428
@@ -558,6 +638,10 @@ func (m *ManagedMachinePoolScope) UpdateNodePool(ctx context.Context, pool *oke.
558638 nodeShapeConfig .MemoryInGBs = common .Float32 (float32 (memoryInGBs ))
559639 }
560640 }
641+ err = m .setNodepoolImageId (ctx )
642+ if err != nil {
643+ return false , err
644+ }
561645 sourceDetails := oke.NodeSourceViaImageDetails {
562646 ImageId : spec .NodeSourceViaImage .ImageId ,
563647 BootVolumeSizeInGBs : spec .NodeSourceViaImage .BootVolumeSizeInGBs ,
0 commit comments