From 3e1996f63d001cd5a0d1aa21f429a2a7bfceea10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20BUISSON?= Date: Mon, 22 Jul 2024 10:08:24 +0200 Subject: [PATCH] feat: support setting loggingService and monitoringService --- .../services/container/clusters/reconcile.go | 20 ++++++++ ...ster.x-k8s.io_gcpmanagedcontrolplanes.yaml | 12 +++++ .../v1beta1/gcpmanagedcontrolplane_types.go | 50 +++++++++++++++++++ .../v1beta1/gcpmanagedcontrolplane_webhook.go | 37 +++++++++++++- exp/api/v1beta1/zz_generated.deepcopy.go | 10 ++++ 5 files changed, 128 insertions(+), 1 deletion(-) diff --git a/cloud/services/container/clusters/reconcile.go b/cloud/services/container/clusters/reconcile.go index cb0074d98..82954b6d5 100644 --- a/cloud/services/container/clusters/reconcile.go +++ b/cloud/services/container/clusters/reconcile.go @@ -297,6 +297,12 @@ func (s *Service) createCluster(ctx context.Context, log *logr.Logger) error { } if !s.scope.IsAutopilotCluster() { cluster.NodePools = scope.ConvertToSdkNodePools(nodePools, machinePools, isRegional, cluster.GetName()) + if s.scope.GCPManagedControlPlane.Spec.LoggingService != nil { + cluster.LoggingService = s.scope.GCPManagedControlPlane.Spec.LoggingService.String() + } + if s.scope.GCPManagedControlPlane.Spec.MonitoringService != nil { + cluster.MonitoringService = s.scope.GCPManagedControlPlane.Spec.MonitoringService.String() + } } createClusterRequest := &containerpb.CreateClusterRequest{ @@ -431,6 +437,20 @@ func (s *Service) checkDiffAndPrepareUpdate(existingCluster *containerpb.Cluster } } + // LoggingService + if existingCluster.GetLoggingService() != s.scope.GCPManagedControlPlane.Spec.LoggingService.String() { + needUpdate = true + clusterUpdate.DesiredLoggingService = s.scope.GCPManagedControlPlane.Spec.LoggingService.String() + log.V(2).Info("LoggingService config update required", "current", existingCluster.GetLoggingService(), "desired", s.scope.GCPManagedControlPlane.Spec.LoggingService.String()) + } + + // MonitoringService + if existingCluster.GetMonitoringService() != s.scope.GCPManagedControlPlane.Spec.MonitoringService.String() { + needUpdate = true + clusterUpdate.DesiredLoggingService = s.scope.GCPManagedControlPlane.Spec.MonitoringService.String() + log.V(2).Info("MonitoringService config update required", "current", existingCluster.GetMonitoringService(), "desired", s.scope.GCPManagedControlPlane.Spec.MonitoringService.String()) + } + // DesiredMasterAuthorizedNetworksConfig // When desiredMasterAuthorizedNetworksConfig is nil, it means that the user wants to disable the feature. desiredMasterAuthorizedNetworksConfig := convertToSdkMasterAuthorizedNetworksConfig(s.scope.GCPManagedControlPlane.Spec.MasterAuthorizedNetworksConfig) diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_gcpmanagedcontrolplanes.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_gcpmanagedcontrolplanes.yaml index 39a580c90..01b052e98 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_gcpmanagedcontrolplanes.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_gcpmanagedcontrolplanes.yaml @@ -161,6 +161,12 @@ spec: Location represents the location (region or zone) in which the GKE cluster will be created. type: string + loggingService: + description: |- + LoggingService represents configuration of logging service feature of the GKE cluster. + Possible values: none, logging.googleapis.com/kubernetes (default). + Value is ignored when enableAutopilot = true. + type: string master_authorized_networks_config: description: |- MasterAuthorizedNetworksConfig represents configuration options for master authorized networks feature of the GKE cluster. @@ -189,6 +195,12 @@ spec: Public IP addresses. type: boolean type: object + monitoringService: + description: |- + MonitoringService represents configuration of monitoring service feature of the GKE cluster. + Possible values: none, monitoring.googleapis.com/kubernetes (default). + Value is ignored when enableAutopilot = true. + type: string project: description: Project is the name of the project to deploy the cluster to. diff --git a/exp/api/v1beta1/gcpmanagedcontrolplane_types.go b/exp/api/v1beta1/gcpmanagedcontrolplane_types.go index b7b1699cf..ab9591f1b 100644 --- a/exp/api/v1beta1/gcpmanagedcontrolplane_types.go +++ b/exp/api/v1beta1/gcpmanagedcontrolplane_types.go @@ -17,7 +17,11 @@ limitations under the License. package v1beta1 import ( + "fmt" + "strings" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/strings/slices" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" ) @@ -148,6 +152,16 @@ type GCPManagedControlPlaneSpec struct { // This feature is disabled if this field is not specified. // +optional MasterAuthorizedNetworksConfig *MasterAuthorizedNetworksConfig `json:"master_authorized_networks_config,omitempty"` + // LoggingService represents configuration of logging service feature of the GKE cluster. + // Possible values: none, logging.googleapis.com/kubernetes (default). + // Value is ignored when enableAutopilot = true. + // +optional + LoggingService *LoggingService `json:"loggingService,omitempty"` + // MonitoringService represents configuration of monitoring service feature of the GKE cluster. + // Possible values: none, monitoring.googleapis.com/kubernetes (default). + // Value is ignored when enableAutopilot = true. + // +optional + MonitoringService *MonitoringService `json:"monitoringService,omitempty"` } // GCPManagedControlPlaneStatus defines the observed state of GCPManagedControlPlane. @@ -233,6 +247,42 @@ type MasterAuthorizedNetworksConfigCidrBlock struct { CidrBlock string `json:"cidr_block,omitempty"` } +// LoggingService is GKE logging service configuration. +type LoggingService string + +// Validate validates LoggingService value. +func (l LoggingService) Validate() error { + validValues := []string{"none", "logging.googleapis.com/kubernetes"} + if !slices.Contains(validValues, l.String()) { + return fmt.Errorf("invalid value; expect one of : %s", strings.Join(validValues, ",")) + } + + return nil +} + +// String returns a string from LoggingService. +func (l LoggingService) String() string { + return string(l) +} + +// MonitoringService is GKE logging service configuration. +type MonitoringService string + +// Validate validates MonitoringService value. +func (m MonitoringService) Validate() error { + validValues := []string{"none", "monitoring.googleapis.com/kubernetes"} + if !slices.Contains(validValues, m.String()) { + return fmt.Errorf("invalid value; expect one of : %s", strings.Join(validValues, ",")) + } + + return nil +} + +// String returns a string from MonitoringService. +func (m MonitoringService) String() string { + return string(m) +} + // GetConditions returns the control planes conditions. func (r *GCPManagedControlPlane) GetConditions() clusterv1.Conditions { return r.Status.Conditions diff --git a/exp/api/v1beta1/gcpmanagedcontrolplane_webhook.go b/exp/api/v1beta1/gcpmanagedcontrolplane_webhook.go index 402ebc3bd..7835b4143 100644 --- a/exp/api/v1beta1/gcpmanagedcontrolplane_webhook.go +++ b/exp/api/v1beta1/gcpmanagedcontrolplane_webhook.go @@ -21,7 +21,6 @@ import ( "strings" "github.com/google/go-cmp/cmp" - apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/util/validation/field" @@ -89,6 +88,16 @@ func (r *GCPManagedControlPlane) ValidateCreate() (admission.Warnings, error) { allErrs = append(allErrs, field.Required(field.NewPath("spec", "ReleaseChannel"), "Release channel is required for an autopilot enabled cluster")) } + if r.Spec.EnableAutopilot && r.Spec.LoggingService != nil { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "LoggingService"), + r.Spec.LoggingService, "can't be set when autopilot is enabled")) + } + + if r.Spec.EnableAutopilot && r.Spec.MonitoringService != nil { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "MonitoringService"), + r.Spec.LoggingService, "can't be set when autopilot is enabled")) + } + if len(allErrs) == 0 { return nil, nil } @@ -130,6 +139,32 @@ func (r *GCPManagedControlPlane) ValidateUpdate(oldRaw runtime.Object) (admissio ) } + if old.Spec.EnableAutopilot && r.Spec.LoggingService != nil { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "LoggingService"), + r.Spec.LoggingService, "can't be set when autopilot is enabled")) + } + + if old.Spec.EnableAutopilot && r.Spec.MonitoringService != nil { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "MonitoringService"), + r.Spec.LoggingService, "can't be set when autopilot is enabled")) + } + + if r.Spec.LoggingService != nil { + err := r.Spec.LoggingService.Validate() + if err != nil { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "LoggingService"), + r.Spec.LoggingService, err.Error())) + } + } + + if r.Spec.MonitoringService != nil { + err := r.Spec.MonitoringService.Validate() + if err != nil { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "MonitoringService"), + r.Spec.MonitoringService, err.Error())) + } + } + if len(allErrs) == 0 { return nil, nil } diff --git a/exp/api/v1beta1/zz_generated.deepcopy.go b/exp/api/v1beta1/zz_generated.deepcopy.go index f70cde996..521cd4510 100644 --- a/exp/api/v1beta1/zz_generated.deepcopy.go +++ b/exp/api/v1beta1/zz_generated.deepcopy.go @@ -308,6 +308,16 @@ func (in *GCPManagedControlPlaneSpec) DeepCopyInto(out *GCPManagedControlPlaneSp *out = new(MasterAuthorizedNetworksConfig) (*in).DeepCopyInto(*out) } + if in.LoggingService != nil { + in, out := &in.LoggingService, &out.LoggingService + *out = new(LoggingService) + **out = **in + } + if in.MonitoringService != nil { + in, out := &in.MonitoringService, &out.MonitoringService + *out = new(MonitoringService) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GCPManagedControlPlaneSpec.