diff --git a/cloud/scope/managedmachinepool.go b/cloud/scope/managedmachinepool.go index b10f521fc..a8bf74a87 100644 --- a/cloud/scope/managedmachinepool.go +++ b/cloud/scope/managedmachinepool.go @@ -213,6 +213,9 @@ func ConvertToSdkNodePool(nodePool infrav1exp.GCPManagedMachinePool, machinePool if nodePool.Spec.Scaling != nil { sdkNodePool.Autoscaling = infrav1exp.ConvertToSdkAutoscaling(nodePool.Spec.Scaling) } + if nodePool.Spec.LinuxNodeConfig != nil { + sdkNodePool.Config.LinuxNodeConfig = infrav1exp.ConvertToSdkLinuxNodeConfig(nodePool.Spec.LinuxNodeConfig) + } if nodePool.Spec.Management != nil { sdkNodePool.Management = &containerpb.NodeManagement{ AutoRepair: nodePool.Spec.Management.AutoRepair, diff --git a/cloud/services/container/nodepools/reconcile.go b/cloud/services/container/nodepools/reconcile.go index b02e1cbd9..8216c83fb 100644 --- a/cloud/services/container/nodepools/reconcile.go +++ b/cloud/services/container/nodepools/reconcile.go @@ -30,6 +30,7 @@ import ( "cloud.google.com/go/container/apiv1/containerpb" "github.com/go-logr/logr" "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/googleapis/gax-go/v2/apierror" "github.com/pkg/errors" "sigs.k8s.io/cluster-api-provider-gcp/cloud/providerid" @@ -148,7 +149,7 @@ func (s *Service) Reconcile(ctx context.Context) (ctrl.Result, error) { log.Info("Node pool config update required", "request", nodePoolUpdateConfigRequest) err = s.updateNodePoolConfig(ctx, nodePoolUpdateConfigRequest) if err != nil { - return ctrl.Result{}, fmt.Errorf("node pool config update (either version/labels/taints/locations/image type/network tag or all) failed: %s", err) + return ctrl.Result{}, fmt.Errorf("node pool config update (either version/labels/taints/locations/image type/network tag/linux node config or all) failed: %s", err) } log.Info("Node pool config updating in progress") s.scope.GCPManagedMachinePool.Status.Ready = true @@ -399,6 +400,12 @@ func (s *Service) checkDiffAndPrepareUpdateConfig(existingNodePool *containerpb. Tags: desiredNetworkTags, } } + // LinuxNodeConfig + desiredLinuxNodeConfig := infrav1exp.ConvertToSdkLinuxNodeConfig(s.scope.GCPManagedMachinePool.Spec.LinuxNodeConfig) + if !cmp.Equal(desiredLinuxNodeConfig, existingNodePool.Config.LinuxNodeConfig, cmpopts.IgnoreUnexported(containerpb.LinuxNodeConfig{})) { + needUpdate = true + updateNodePoolRequest.LinuxNodeConfig = desiredLinuxNodeConfig + } return needUpdate, &updateNodePoolRequest } 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 d3d715076..93db4d622 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_gcpmanagedmachinepools.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_gcpmanagedmachinepools.yaml @@ -109,6 +109,31 @@ spec: - value type: object type: array + linuxNodeConfig: + description: LinuxNodeConfig specifies the settings for Linux agent + nodes. + properties: + cgroupMode: + description: CgroupMode specifies the cgroup mode for this node + pool. + format: int32 + type: integer + sysctls: + description: Sysctls specifies the sysctl settings for this node + pool. + items: + description: SysctlConfig specifies the sysctl settings for + Linux nodes. + properties: + parameter: + description: Parameter specifies sysctl parameter name. + type: string + value: + description: Value specifies sysctl parameter value. + type: string + type: object + type: array + type: object localSsdCount: description: LocalSsdCount is the number of local SSD disks to be attached to the node. diff --git a/exp/api/v1beta1/gcpmanagedmachinepool_types.go b/exp/api/v1beta1/gcpmanagedmachinepool_types.go index b943ff6c6..1d24a77d3 100644 --- a/exp/api/v1beta1/gcpmanagedmachinepool_types.go +++ b/exp/api/v1beta1/gcpmanagedmachinepool_types.go @@ -106,6 +106,9 @@ type GCPManagedMachinePoolSpec struct { // Management specifies the node pool management options. // +optional Management *NodePoolManagement `json:"management,omitempty"` + // LinuxNodeConfig specifies the settings for Linux agent nodes. + // +optional + LinuxNodeConfig *LinuxNodeConfig `json:"linuxNodeConfig,omitempty"` // ProviderIDList are the provider IDs of instances in the // managed instance group corresponding to the nodegroup represented by this // machine pool @@ -234,6 +237,29 @@ type NodePoolManagement struct { // ManagedNodePoolLocationPolicy specifies the location policy of the node pool when autoscaling is enabled. type ManagedNodePoolLocationPolicy string +// LinuxNodeConfig specifies the settings for Linux agent nodes. +type LinuxNodeConfig struct { + // Sysctls specifies the sysctl settings for this node pool. + // +optional + Sysctls []SysctlConfig `json:"sysctls,omitempty"` + // CgroupMode specifies the cgroup mode for this node pool. + // +optional + CgroupMode *ManagedNodePoolCgroupMode `json:"cgroupMode,omitempty"` +} + +// SysctlConfig specifies the sysctl settings for Linux nodes. +type SysctlConfig struct { + // Parameter specifies sysctl parameter name. + // +optional + Parameter string `json:"parameter,omitempty"` + // Value specifies sysctl parameter value. + // +optional + Value string `json:"value,omitempty"` +} + +// ManagedNodePoolCgroupMode specifies the cgroup mode of the node pool when autoscaling is enabled. +type ManagedNodePoolCgroupMode int32 + const ( // ManagedNodePoolLocationPolicyBalanced aims to balance the sizes of different zones. ManagedNodePoolLocationPolicyBalanced ManagedNodePoolLocationPolicy = "balanced" diff --git a/exp/api/v1beta1/types.go b/exp/api/v1beta1/types.go index 6f4baf0a2..3e9245da7 100644 --- a/exp/api/v1beta1/types.go +++ b/exp/api/v1beta1/types.go @@ -112,3 +112,32 @@ func ConvertFromSdkNodeVersion(sdkNodeVersion string) string { // For example, the node version returned from GCP SDK can be 1.27.2-gke.2100, we want to convert it to 1.27.2 return strings.Split(sdkNodeVersion, "-")[0] } + +// ConvertToSdkCgroupMode converts GCP SDK node version to k8s version. +func ConvertToSdkCgroupMode(cgroupMode ManagedNodePoolCgroupMode) containerpb.LinuxNodeConfig_CgroupMode { + switch cgroupMode { + case 1: + return containerpb.LinuxNodeConfig_CGROUP_MODE_V1 + case 2: + return containerpb.LinuxNodeConfig_CGROUP_MODE_V2 + } + return containerpb.LinuxNodeConfig_CGROUP_MODE_UNSPECIFIED +} + +// ConvertToSdkLinuxNodeConfig converts GCP SDK node version to k8s version. +func ConvertToSdkLinuxNodeConfig(linuxNodeConfig *LinuxNodeConfig) *containerpb.LinuxNodeConfig { + sdkLinuxNodeConfig := containerpb.LinuxNodeConfig{} + if linuxNodeConfig != nil { + if linuxNodeConfig.Sysctls != nil { + sdkSysctl := make(map[string]string) + for _, sysctl := range linuxNodeConfig.Sysctls { + sdkSysctl[sysctl.Parameter] = sysctl.Value + } + sdkLinuxNodeConfig.Sysctls = sdkSysctl + } + if linuxNodeConfig.CgroupMode != nil { + sdkLinuxNodeConfig.CgroupMode = ConvertToSdkCgroupMode(*linuxNodeConfig.CgroupMode) + } + } + return &sdkLinuxNodeConfig +} diff --git a/exp/api/v1beta1/zz_generated.deepcopy.go b/exp/api/v1beta1/zz_generated.deepcopy.go index 6ae3297ff..201879f2a 100644 --- a/exp/api/v1beta1/zz_generated.deepcopy.go +++ b/exp/api/v1beta1/zz_generated.deepcopy.go @@ -400,6 +400,11 @@ func (in *GCPManagedMachinePoolSpec) DeepCopyInto(out *GCPManagedMachinePoolSpec *out = new(NodePoolManagement) **out = **in } + if in.LinuxNodeConfig != nil { + in, out := &in.LinuxNodeConfig, &out.LinuxNodeConfig + *out = new(LinuxNodeConfig) + (*in).DeepCopyInto(*out) + } if in.ProviderIDList != nil { in, out := &in.ProviderIDList, &out.ProviderIDList *out = make([]string, len(*in)) @@ -439,6 +444,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 *LinuxNodeConfig) DeepCopyInto(out *LinuxNodeConfig) { + *out = *in + if in.Sysctls != nil { + in, out := &in.Sysctls, &out.Sysctls + *out = make([]SysctlConfig, len(*in)) + copy(*out, *in) + } + if in.CgroupMode != nil { + in, out := &in.CgroupMode, &out.CgroupMode + *out = new(ManagedNodePoolCgroupMode) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LinuxNodeConfig. +func (in *LinuxNodeConfig) DeepCopy() *LinuxNodeConfig { + if in == nil { + return nil + } + out := new(LinuxNodeConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MasterAuthorizedNetworksConfig) DeepCopyInto(out *MasterAuthorizedNetworksConfig) { *out = *in @@ -626,6 +656,21 @@ func (in *ServiceAccountConfig) DeepCopy() *ServiceAccountConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SysctlConfig) DeepCopyInto(out *SysctlConfig) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SysctlConfig. +func (in *SysctlConfig) DeepCopy() *SysctlConfig { + if in == nil { + return nil + } + out := new(SysctlConfig) + 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