diff --git a/cloud/scope/managedmachinepool.go b/cloud/scope/managedmachinepool.go index 553062b16b..b2b37b7e92 100644 --- a/cloud/scope/managedmachinepool.go +++ b/cloud/scope/managedmachinepool.go @@ -173,13 +173,20 @@ func ConvertToSdkNodePool(nodePool infrav1exp.GCPManagedMachinePool, machinePool } sdkNodePool := containerpb.NodePool{ Name: nodePoolName, - InitialNodeCount: nodePool.Spec.NodeCount, + InitialNodeCount: nodePool.Spec.InitialNodeCount, Config: &containerpb.NodeConfig{ Labels: nodePool.Spec.KubernetesLabels, Taints: infrav1exp.ConvertToSdkTaint(nodePool.Spec.KubernetesTaints), Metadata: nodePool.Spec.AdditionalLabels, }, } + if nodePool.Spec.Scaling != nil { + sdkNodePool.Autoscaling = &containerpb.NodePoolAutoscaling{ + Enabled: true, + MinNodeCount: *nodePool.Spec.Scaling.MinCount, + MaxNodeCount: *nodePool.Spec.Scaling.MaxCount, + } + } if machinePool.Spec.Template.Spec.Version != nil { sdkNodePool.Version = *machinePool.Spec.Template.Spec.Version } diff --git a/cloud/services/container/nodepools/reconcile.go b/cloud/services/container/nodepools/reconcile.go index d39f4624eb..679106e803 100644 --- a/cloud/services/container/nodepools/reconcile.go +++ b/cloud/services/container/nodepools/reconcile.go @@ -127,6 +127,19 @@ func (s *Service) Reconcile(ctx context.Context) (ctrl.Result, error) { return ctrl.Result{RequeueAfter: reconciler.DefaultRetryTime}, nil } + needUpdateAutoscaling, setNodePoolAutoscalingRequest := s.checkDiffAndPrepareUpdateAutoscaling(nodePool) + if needUpdateAutoscaling { + log.Info("Auto scaling update required") + err = s.updateNodePoolAutoscaling(ctx, setNodePoolAutoscalingRequest) + if err != nil { + return ctrl.Result{}, err + } + log.Info("Node pool auto scaling updating in progress") + s.scope.GCPManagedMachinePool.Status.Ready = true + conditions.MarkTrue(s.scope.ConditionSetter(), infrav1exp.GKEMachinePoolUpdatingCondition) + return ctrl.Result{RequeueAfter: reconciler.DefaultRetryTime}, nil + } + needUpdateSize, setNodePoolSizeRequest := s.checkDiffAndPrepareUpdateSize(nodePool) if needUpdateSize { log.Info("Size update required") @@ -268,6 +281,15 @@ func (s *Service) updateNodePoolVersionOrImage(ctx context.Context, updateNodePo return nil } +func (s *Service) updateNodePoolAutoscaling(ctx context.Context, setNodePoolAutoscalingRequest *containerpb.SetNodePoolAutoscalingRequest) error { + _, err := s.scope.ManagedMachinePoolClient().SetNodePoolAutoscaling(ctx, setNodePoolAutoscalingRequest) + if err != nil { + return err + } + + return nil +} + func (s *Service) updateNodePoolSize(ctx context.Context, setNodePoolSizeRequest *containerpb.SetNodePoolSizeRequest) error { _, err := s.scope.ManagedMachinePoolClient().SetNodePoolSize(ctx, setNodePoolSizeRequest) if err != nil { @@ -317,14 +339,27 @@ func (s *Service) checkDiffAndPrepareUpdateVersionOrImage(existingNodePool *cont return needUpdate, &updateNodePoolRequest } +func (s *Service) checkDiffAndPrepareUpdateAutoscaling(existingNodePool *containerpb.NodePool) (bool, *containerpb.SetNodePoolAutoscalingRequest) { + needUpdate := false + desiredNodePool := scope.ConvertToSdkNodePool(*s.scope.GCPManagedMachinePool, *s.scope.MachinePool) + setNodePoolAutoscalingRequest := containerpb.SetNodePoolAutoscalingRequest{ + Name: s.scope.NodePoolFullName(), + } + if !reflect.DeepEqual(desiredNodePool.Autoscaling, existingNodePool.Autoscaling) { + needUpdate = true + setNodePoolAutoscalingRequest.Autoscaling = desiredNodePool.Autoscaling + } + return needUpdate, &setNodePoolAutoscalingRequest +} + func (s *Service) checkDiffAndPrepareUpdateSize(existingNodePool *containerpb.NodePool) (bool, *containerpb.SetNodePoolSizeRequest) { needUpdate := false setNodePoolSizeRequest := containerpb.SetNodePoolSizeRequest{ Name: s.scope.NodePoolFullName(), } - if s.scope.GCPManagedMachinePool.Spec.NodeCount != existingNodePool.InitialNodeCount { + if s.scope.GCPManagedMachinePool.Spec.InitialNodeCount != existingNodePool.InitialNodeCount { needUpdate = true - setNodePoolSizeRequest.NodeCount = s.scope.GCPManagedMachinePool.Spec.NodeCount + setNodePoolSizeRequest.NodeCount = s.scope.GCPManagedMachinePool.Spec.InitialNodeCount } return needUpdate, &setNodePoolSizeRequest } diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_gcpmanagedmachinepools.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_gcpmanagedmachinepools.yaml index a3a4747031..5581257cbe 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_gcpmanagedmachinepools.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_gcpmanagedmachinepools.yaml @@ -51,6 +51,12 @@ spec: GCP resources managed by the GCP provider, in addition to the ones added by default. type: object + initialNodeCount: + description: InitialNodeCount represents the initial number of nodes + for the pool. In regional or multi-zonal clusters, this is the number + of nodes per zone. + format: int32 + type: integer kubernetesLabels: additionalProperties: type: string @@ -82,12 +88,6 @@ spec: - value type: object type: array - nodeCount: - description: NodeCount represents the initial number of nodes for - the pool. In regional or multi-zonal clusters, this is the number - of nodes per zone. - format: int32 - type: integer nodePoolName: description: NodePoolName specifies the name of the GKE node pool corresponding to this MachinePool. If you don't specify a name then @@ -101,8 +101,18 @@ spec: items: type: string type: array + scaling: + description: Scaling specifies scaling for the node pool + properties: + maxCount: + format: int32 + type: integer + minCount: + format: int32 + type: integer + type: object required: - - nodeCount + - initialNodeCount type: object status: description: GCPManagedMachinePoolStatus defines the observed state of diff --git a/exp/api/v1beta1/gcpmanagedmachinepool_types.go b/exp/api/v1beta1/gcpmanagedmachinepool_types.go index ce7b5c2a4f..81e5037a34 100644 --- a/exp/api/v1beta1/gcpmanagedmachinepool_types.go +++ b/exp/api/v1beta1/gcpmanagedmachinepool_types.go @@ -34,9 +34,12 @@ type GCPManagedMachinePoolSpec struct { // then a default name will be created based on the namespace and name of the managed machine pool. // +optional NodePoolName string `json:"nodePoolName,omitempty"` - // NodeCount represents the initial number of nodes for the pool. + // InitialNodeCount represents the initial number of nodes for the pool. // In regional or multi-zonal clusters, this is the number of nodes per zone. - NodeCount int32 `json:"nodeCount"` + InitialNodeCount int32 `json:"initialNodeCount"` + // Scaling specifies scaling for the node pool + // +optional + Scaling *NodePoolAutoScaling `json:"scaling,omitempty"` // KubernetesLabels specifies the labels to apply to the nodes of the node pool. // +optional KubernetesLabels infrav1.Labels `json:"kubernetesLabels,omitempty"` @@ -88,6 +91,12 @@ type GCPManagedMachinePoolList struct { Items []GCPManagedMachinePool `json:"items"` } +// NodePoolAutoScaling specifies scaling options. +type NodePoolAutoScaling struct { + MinCount *int32 `json:"minCount,omitempty"` + MaxCount *int32 `json:"maxCount,omitempty"` +} + // GetConditions returns the machine pool conditions. func (r *GCPManagedMachinePool) GetConditions() clusterv1.Conditions { return r.Status.Conditions diff --git a/exp/api/v1beta1/zz_generated.deepcopy.go b/exp/api/v1beta1/zz_generated.deepcopy.go index 502f060b3f..1e0e020beb 100644 --- a/exp/api/v1beta1/zz_generated.deepcopy.go +++ b/exp/api/v1beta1/zz_generated.deepcopy.go @@ -314,6 +314,11 @@ func (in *GCPManagedMachinePoolList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GCPManagedMachinePoolSpec) DeepCopyInto(out *GCPManagedMachinePoolSpec) { *out = *in + if in.Scaling != nil { + in, out := &in.Scaling, &out.Scaling + *out = new(NodePoolAutoScaling) + (*in).DeepCopyInto(*out) + } if in.KubernetesLabels != nil { in, out := &in.KubernetesLabels, &out.KubernetesLabels *out = make(apiv1beta1.Labels, len(*in)) @@ -372,6 +377,31 @@ func (in *GCPManagedMachinePoolStatus) DeepCopy() *GCPManagedMachinePoolStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodePoolAutoScaling) DeepCopyInto(out *NodePoolAutoScaling) { + *out = *in + if in.MinCount != nil { + in, out := &in.MinCount, &out.MinCount + *out = new(int32) + **out = **in + } + if in.MaxCount != nil { + in, out := &in.MaxCount, &out.MaxCount + *out = new(int32) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodePoolAutoScaling. +func (in *NodePoolAutoScaling) DeepCopy() *NodePoolAutoScaling { + if in == nil { + return nil + } + out := new(NodePoolAutoScaling) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Taint) DeepCopyInto(out *Taint) { *out = *in