Skip to content

Commit e5676d6

Browse files
Add node pool recycling (#285)
* Add OKE node pool recycling option
1 parent 40c3141 commit e5676d6

24 files changed

+573
-51
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ generate-e2e-templates: $(KUSTOMIZE)
289289
$(KUSTOMIZE) build $(OCI_TEMPLATES)/v1beta2/cluster-template-externally-managed-vcn --load-restrictor LoadRestrictionsNone > $(OCI_TEMPLATES)/v1beta2/cluster-template-externally-managed-vcn.yaml
290290
$(KUSTOMIZE) build $(OCI_TEMPLATES)/v1beta2/cluster-template-machine-pool --load-restrictor LoadRestrictionsNone > $(OCI_TEMPLATES)/v1beta2/cluster-template-machine-pool.yaml
291291
$(KUSTOMIZE) build $(OCI_TEMPLATES)/v1beta2/cluster-template-managed --load-restrictor LoadRestrictionsNone > $(OCI_TEMPLATES)/v1beta2/cluster-template-managed.yaml
292+
$(KUSTOMIZE) build $(OCI_TEMPLATES)/v1beta2/cluster-template-managed-node-recycling --load-restrictor LoadRestrictionsNone > $(OCI_TEMPLATES)/v1beta2/cluster-template-managed-node-recycling.yaml
292293
$(KUSTOMIZE) build $(OCI_TEMPLATES)/v1beta2/cluster-template-managed-cluster-identity --load-restrictor LoadRestrictionsNone > $(OCI_TEMPLATES)/v1beta2/cluster-template-managed-cluster-identity.yaml
293294
$(KUSTOMIZE) build $(OCI_TEMPLATES)/v1beta2/cluster-template-cluster-identity --load-restrictor LoadRestrictionsNone > $(OCI_TEMPLATES)/v1beta2/cluster-template-cluster-identity.yaml
294295
$(KUSTOMIZE) build $(OCI_TEMPLATES)/v1beta2/cluster-template-windows-calico --load-restrictor LoadRestrictionsNone > $(OCI_TEMPLATES)/v1beta2/cluster-template-windows-calico.yaml

cloud/scope/managed_control_plane.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,9 @@ func (s *ManagedControlPlaneScope) UpdateControlPlane(ctx context.Context, okeCl
588588
// there is a chance user will edit the cluster
589589
func setControlPlaneSpecDefaults(spec *infrav2exp.OCIManagedControlPlaneSpec) {
590590
spec.ControlPlaneEndpoint = clusterv1.APIEndpoint{}
591+
if spec.ClusterType == "" {
592+
spec.ClusterType = infrav2exp.BasicClusterType
593+
}
591594
if spec.ImagePolicyConfig == nil {
592595
spec.ImagePolicyConfig = &infrav2exp.ImagePolicyConfig{
593596
IsPolicyEnabled: common.Bool(false),
@@ -663,6 +666,7 @@ func (s *ManagedControlPlaneScope) getSpecFromActual(cluster *oke.Cluster) *infr
663666
spec.ClusterType = infrav2exp.EnhancedClusterType
664667
break
665668
default:
669+
spec.ClusterType = infrav2exp.BasicClusterType
666670
break
667671
}
668672
}

cloud/scope/managed_control_plane_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,7 @@ func TestControlPlaneUpdation(t *testing.T) {
473473
CompartmentId: common.String("test-compartment"),
474474
VcnId: common.String("vcn-id"),
475475
KubernetesVersion: common.String("v1.24.5"),
476+
Type: oke.ClusterTypeBasicCluster,
476477
FreeformTags: tags,
477478
DefinedTags: definedTagsInterface,
478479
EndpointConfig: &oke.ClusterEndpointConfig{

cloud/scope/managed_machine_pool.go

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,14 @@ func (m *ManagedMachinePoolScope) CreateNodePool(ctx context.Context) (*oke.Node
313313
IsForceDeleteAfterGraceDuration: m.OCIManagedMachinePool.Spec.NodeEvictionNodePoolSettings.IsForceDeleteAfterGraceDuration,
314314
}
315315
}
316+
recycleConfig := m.OCIManagedMachinePool.Spec.NodePoolCyclingDetails
317+
if recycleConfig != nil {
318+
nodePoolDetails.NodePoolCyclingDetails = &oke.NodePoolCyclingDetails{
319+
IsNodeCyclingEnabled: recycleConfig.IsNodeCyclingEnabled,
320+
MaximumSurge: recycleConfig.MaximumSurge,
321+
MaximumUnavailable: recycleConfig.MaximumUnavailable,
322+
}
323+
}
316324
nodePoolDetails.InitialNodeLabels = m.getInitialNodeKeyValuePairs()
317325

318326
req := oke.CreateNodePoolRequest{
@@ -603,16 +611,22 @@ func (m *ManagedMachinePoolScope) UpdateNodePool(ctx context.Context, pool *oke.
603611
return false, err
604612
}
605613
m.Logger.Info("Node pool", "spec", jsonSpec, "actual", jsonActual)
606-
placementConfig, err := m.buildPlacementConfig(spec.NodePoolNodeConfig.PlacementConfigs)
607-
if err != nil {
608-
return false, err
609-
}
614+
610615
nodeConfigDetails := oke.UpdateNodePoolNodeConfigDetails{
611616
NsgIds: m.getWorkerMachineNSGs(),
612-
PlacementConfigs: placementConfig,
613617
IsPvEncryptionInTransitEnabled: spec.NodePoolNodeConfig.IsPvEncryptionInTransitEnabled,
614618
KmsKeyId: spec.NodePoolNodeConfig.KmsKeyId,
615619
}
620+
// send placement config only if there is an actual change in placement
621+
// placement config and recycle config cannot be sent at the same time, and most use cases will
622+
// be to update kubernetes version in which case, placement config is not required to be sent
623+
if !reflect.DeepEqual(spec.NodePoolNodeConfig.PlacementConfigs, actual.NodePoolNodeConfig.PlacementConfigs) {
624+
placementConfig, err := m.buildPlacementConfig(spec.NodePoolNodeConfig.PlacementConfigs)
625+
if err != nil {
626+
return false, err
627+
}
628+
nodeConfigDetails.PlacementConfigs = placementConfig
629+
}
616630
if nodePoolSizeUpdateRequired {
617631
nodeConfigDetails.Size = common.Int(int(*m.MachinePool.Spec.Replicas))
618632
}
@@ -643,7 +657,9 @@ func (m *ManagedMachinePoolScope) UpdateNodePool(ctx context.Context, pool *oke.
643657
return false, err
644658
}
645659
sourceDetails := oke.NodeSourceViaImageDetails{
646-
ImageId: spec.NodeSourceViaImage.ImageId,
660+
// use image id from machinepool spec itself as the copy will not have the image set in the
661+
// setNodepoolImageId method above
662+
ImageId: m.OCIManagedMachinePool.Spec.NodeSourceViaImage.ImageId,
647663
BootVolumeSizeInGBs: spec.NodeSourceViaImage.BootVolumeSizeInGBs,
648664
}
649665

@@ -672,6 +688,19 @@ func (m *ManagedMachinePoolScope) UpdateNodePool(ctx context.Context, pool *oke.
672688
NodeConfigDetails: &nodeConfigDetails,
673689
NodeMetadata: spec.NodeMetadata,
674690
}
691+
recycleConfig := spec.NodePoolCyclingDetails
692+
// cannot send recycle config and placement config together
693+
if recycleConfig != nil && len(nodeConfigDetails.PlacementConfigs) == 0 {
694+
nodePoolDetails.NodePoolCyclingDetails = &oke.NodePoolCyclingDetails{
695+
IsNodeCyclingEnabled: recycleConfig.IsNodeCyclingEnabled,
696+
MaximumSurge: recycleConfig.MaximumSurge,
697+
MaximumUnavailable: recycleConfig.MaximumUnavailable,
698+
}
699+
}
700+
if recycleConfig != nil && len(nodeConfigDetails.PlacementConfigs) != 0 {
701+
m.Logger.V(LogLevelWarn).Info("Placement configuration has been changed in the update, " +
702+
"hence node pool recycling configuration will not be sent with the update request")
703+
}
675704
if spec.NodeEvictionNodePoolSettings != nil {
676705
nodePoolDetails.NodeEvictionNodePoolSettings = &oke.NodeEvictionNodePoolSettings{
677706
EvictionGraceDuration: spec.NodeEvictionNodePoolSettings.EvictionGraceDuration,
@@ -701,6 +730,7 @@ func (m *ManagedMachinePoolScope) UpdateNodePool(ctx context.Context, pool *oke.
701730
func setMachinePoolSpecDefaults(spec *infrav2exp.OCIManagedMachinePoolSpec) {
702731
spec.ProviderIDList = nil
703732
spec.ProviderID = nil
733+
704734
if spec.NodePoolNodeConfig != nil {
705735
if spec.NodePoolNodeConfig.PlacementConfigs != nil {
706736
configs := spec.NodePoolNodeConfig.PlacementConfigs
@@ -782,6 +812,14 @@ func (m *ManagedMachinePoolScope) getSpecFromAPIObject(pool *oke.NodePool) *expi
782812
}
783813
spec.NodeShapeConfig = &nodeShapeConfig
784814
}
815+
if pool.NodePoolCyclingDetails != nil {
816+
cyclingDetails := pool.NodePoolCyclingDetails
817+
spec.NodePoolCyclingDetails = &expinfra1.NodePoolCyclingDetails{
818+
IsNodeCyclingEnabled: cyclingDetails.IsNodeCyclingEnabled,
819+
MaximumSurge: cyclingDetails.MaximumSurge,
820+
MaximumUnavailable: cyclingDetails.MaximumUnavailable,
821+
}
822+
}
785823
return &spec
786824
}
787825

cloud/scope/managed_machine_pool_test.go

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,15 +1129,7 @@ func TestManagedMachinePoolUpdate(t *testing.T) {
11291129
},
11301130
SshPublicKey: common.String("test-ssh-public-key"),
11311131
NodeConfigDetails: &oke.UpdateNodePoolNodeConfigDetails{
1132-
Size: common.Int(4),
1133-
PlacementConfigs: []oke.NodePoolPlacementConfigDetails{
1134-
{
1135-
AvailabilityDomain: common.String("test-ad"),
1136-
CapacityReservationId: common.String("cap-id"),
1137-
SubnetId: common.String("subnet-id"),
1138-
FaultDomains: []string{"fd-1", "fd-2"},
1139-
},
1140-
},
1132+
Size: common.Int(4),
11411133
NsgIds: []string{"nsg-id"},
11421134
KmsKeyId: common.String("kms-key-id"),
11431135
IsPvEncryptionInTransitEnabled: common.Bool(true),
@@ -1376,14 +1368,6 @@ func TestManagedMachinePoolUpdate(t *testing.T) {
13761368
},
13771369
SshPublicKey: common.String("test-ssh-public-key"),
13781370
NodeConfigDetails: &oke.UpdateNodePoolNodeConfigDetails{
1379-
PlacementConfigs: []oke.NodePoolPlacementConfigDetails{
1380-
{
1381-
AvailabilityDomain: common.String("test-ad"),
1382-
CapacityReservationId: common.String("cap-id"),
1383-
SubnetId: common.String("subnet-id"),
1384-
FaultDomains: []string{"fd-1", "fd-2"},
1385-
},
1386-
},
13871371
NsgIds: []string{"nsg-id"},
13881372
KmsKeyId: common.String("kms-key-id"),
13891373
IsPvEncryptionInTransitEnabled: common.Bool(true),
@@ -1618,6 +1602,11 @@ func TestManagedMachinePoolUpdate(t *testing.T) {
16181602
NodeSourceViaImage: &infrav2exp.NodeSourceViaImage{
16191603
ImageId: common.String("test-image-id"),
16201604
},
1605+
NodePoolCyclingDetails: &infrav2exp.NodePoolCyclingDetails{
1606+
IsNodeCyclingEnabled: common.Bool(true),
1607+
MaximumSurge: common.String("20%"),
1608+
MaximumUnavailable: common.String("10%"),
1609+
},
16211610
SshPublicKey: "test-ssh-public-key",
16221611
NodePoolNodeConfig: &infrav2exp.NodePoolNodeConfig{
16231612
PlacementConfigs: []infrav2exp.PlacementConfig{
@@ -1663,16 +1652,13 @@ func TestManagedMachinePoolUpdate(t *testing.T) {
16631652
NodeSourceDetails: &oke.NodeSourceViaImageDetails{
16641653
ImageId: common.String("test-image-id"),
16651654
},
1655+
NodePoolCyclingDetails: &oke.NodePoolCyclingDetails{
1656+
IsNodeCyclingEnabled: common.Bool(true),
1657+
MaximumSurge: common.String("20%"),
1658+
MaximumUnavailable: common.String("10%"),
1659+
},
16661660
SshPublicKey: common.String("test-ssh-public-key"),
16671661
NodeConfigDetails: &oke.UpdateNodePoolNodeConfigDetails{
1668-
PlacementConfigs: []oke.NodePoolPlacementConfigDetails{
1669-
{
1670-
AvailabilityDomain: common.String("test-ad"),
1671-
CapacityReservationId: common.String("cap-id"),
1672-
SubnetId: common.String("subnet-id"),
1673-
FaultDomains: []string{"fd-1", "fd-2"},
1674-
},
1675-
},
16761662
NsgIds: []string{"nsg-id"},
16771663
KmsKeyId: common.String("kms-key-id"),
16781664
IsPvEncryptionInTransitEnabled: common.Bool(true),

cloud/scope/util.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ import (
2020
infrastructurev1beta2 "github.com/oracle/cluster-api-provider-oci/api/v1beta2"
2121
)
2222

23+
const (
24+
LogLevelWarn = 3
25+
)
26+
2327
// GetNsgNamesFromId returns the names of the NSGs with the provided IDs
2428
func GetNsgNamesFromId(ids []string, nsgs []*infrastructurev1beta2.NSG) []string {
2529
names := make([]string, 0)

config/crd/bases/infrastructure.cluster.x-k8s.io_ocimanagedmachinepools.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,28 @@ spec:
339339
description: NodeMetadata defines a list of key/value pairs to add
340340
to each underlying OCI instance in the node pool on launch.
341341
type: object
342+
nodePoolCyclingDetails:
343+
description: NodePoolCyclingDetails defines the node pool recycling
344+
options.
345+
properties:
346+
isNodeCyclingEnabled:
347+
description: IsNodeCyclingEnabled refers if nodes in the nodepool
348+
will be cycled to have new changes.
349+
type: boolean
350+
maximumSurge:
351+
description: MaximumSurge refers to the maximum additional new
352+
compute instances that would be temporarily created and added
353+
to nodepool during the cycling nodepool process. OKE supports
354+
both integer and percentage input. Defaults to 1, Ranges from
355+
0 to Nodepool size or 0% to 100%
356+
type: string
357+
maximumUnavailable:
358+
description: Maximum active nodes that would be terminated from
359+
nodepool during the cycling nodepool process. OKE supports both
360+
integer and percentage input. Defaults to 0, Ranges from 0 to
361+
Nodepool size or 0% to 100%
362+
type: string
363+
type: object
342364
nodePoolNodeConfig:
343365
description: NodePoolNodeConfig defines the configuration of nodes
344366
in the node pool.

config/crd/bases/infrastructure.cluster.x-k8s.io_ocimanagedmachinepooltemplates.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,28 @@ spec:
308308
to add to each underlying OCI instance in the node pool
309309
on launch.
310310
type: object
311+
nodePoolCyclingDetails:
312+
description: NodePoolCyclingDetails defines the node pool
313+
recycling options.
314+
properties:
315+
isNodeCyclingEnabled:
316+
description: IsNodeCyclingEnabled refers if nodes in the
317+
nodepool will be cycled to have new changes.
318+
type: boolean
319+
maximumSurge:
320+
description: MaximumSurge refers to the maximum additional
321+
new compute instances that would be temporarily created
322+
and added to nodepool during the cycling nodepool process.
323+
OKE supports both integer and percentage input. Defaults
324+
to 1, Ranges from 0 to Nodepool size or 0% to 100%
325+
type: string
326+
maximumUnavailable:
327+
description: Maximum active nodes that would be terminated
328+
from nodepool during the cycling nodepool process. OKE
329+
supports both integer and percentage input. Defaults
330+
to 0, Ranges from 0 to Nodepool size or 0% to 100%
331+
type: string
332+
type: object
311333
nodePoolNodeConfig:
312334
description: NodePoolNodeConfig defines the configuration
313335
of nodes in the node pool.

exp/api/v1beta1/conversion.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,7 @@ func Convert_v1beta2_NetworkDetails_To_v1beta1_NetworkDetails(in *infrastructure
5151
func Convert_v1beta2_OCIManagedControlPlaneSpec_To_v1beta1_OCIManagedControlPlaneSpec(in *v1beta2.OCIManagedControlPlaneSpec, out *OCIManagedControlPlaneSpec, s conversion.Scope) error {
5252
return autoConvert_v1beta2_OCIManagedControlPlaneSpec_To_v1beta1_OCIManagedControlPlaneSpec(in, out, s)
5353
}
54+
55+
func Convert_v1beta2_OCIManagedMachinePoolSpec_To_v1beta1_OCIManagedMachinePoolSpec(in *v1beta2.OCIManagedMachinePoolSpec, out *OCIManagedMachinePoolSpec, s conversion.Scope) error {
56+
return autoConvert_v1beta2_OCIManagedMachinePoolSpec_To_v1beta1_OCIManagedMachinePoolSpec(in, out, s)
57+
}

exp/api/v1beta1/ocimanagedmachinepool_conversion.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ func (src *OCIManagedMachinePool) ConvertTo(dstRaw conversion.Hub) error {
3434
if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok {
3535
return err
3636
}
37+
dst.Spec.NodePoolCyclingDetails = restored.Spec.NodePoolCyclingDetails
3738

3839
return nil
3940
}

0 commit comments

Comments
 (0)