From 4ff82a2156009f630b7e29152d6c9d97098006e7 Mon Sep 17 00:00:00 2001 From: vishal Date: Wed, 7 Jul 2021 23:22:54 -0400 Subject: [PATCH 1/4] Make --print-config display yaml that is consumable by cortex configure command --- cli/cmd/cluster.go | 45 +++-- cli/cmd/lib_cluster_config.go | 4 +- pkg/config/config.go | 19 +- pkg/consts/consts.go | 3 + pkg/operator/operator/cron.go | 1 - .../resources/realtimeapi/k8s_specs.go | 3 +- pkg/types/clusterconfig/cluster_config.go | 184 ++++++------------ 7 files changed, 103 insertions(+), 156 deletions(-) diff --git a/cli/cmd/cluster.go b/cli/cmd/cluster.go index 375f1ca0d8..77bba2e4fe 100644 --- a/cli/cmd/cluster.go +++ b/cli/cmd/cluster.go @@ -421,8 +421,10 @@ var _clusterInfoCmd = &cobra.Command{ if _flagClusterInfoDebug { cmdDebug(awsClient, accessConfig) + } else if _flagClusterInfoPrintConfig { + cmdPrintConfig(awsClient, accessConfig, _flagOutput) } else { - cmdInfo(awsClient, accessConfig, stacks, _flagClusterInfoPrintConfig, _flagOutput, _flagClusterDisallowPrompt) + cmdInfo(awsClient, accessConfig, stacks, _flagOutput, _flagClusterDisallowPrompt) } }, } @@ -743,7 +745,27 @@ var _clusterExportCmd = &cobra.Command{ }, } -func cmdInfo(awsClient *aws.Client, accessConfig *clusterconfig.AccessConfig, stacks clusterstate.ClusterStacks, printConfig bool, outputType flags.OutputType, disallowPrompt bool) { +func cmdPrintConfig(awsClient *aws.Client, accessConfig *clusterconfig.AccessConfig, outputType flags.OutputType) { + clusterConfig := refreshCachedClusterConfig(awsClient, accessConfig, outputType == flags.PrettyOutputType) + + infoInterface := clusterConfig.CoreConfig + + if outputType == flags.JSONOutputType { + outputBytes, err := libjson.Marshal(infoInterface) + if err != nil { + exit.Error(err) + } + fmt.Println(string(outputBytes)) + } else { + outputBytes, err := yaml.Marshal(infoInterface) + if err != nil { + exit.Error(err) + } + fmt.Println(string(outputBytes)) + } +} + +func cmdInfo(awsClient *aws.Client, accessConfig *clusterconfig.AccessConfig, stacks clusterstate.ClusterStacks, outputType flags.OutputType, disallowPrompt bool) { clusterConfig := refreshCachedClusterConfig(awsClient, accessConfig, outputType == flags.PrettyOutputType) operatorLoadBalancer, err := getLoadBalancer(accessConfig.ClusterName, OperatorLoadBalancer, awsClient) @@ -765,18 +787,13 @@ func cmdInfo(awsClient *aws.Client, accessConfig *clusterconfig.AccessConfig, st } infoResponse.ClusterConfig.Config = clusterConfig - var infoInterface interface{} - if printConfig { - infoInterface = infoResponse.ClusterConfig.Config - } else { - infoInterface = map[string]interface{}{ - "cluster_config": infoResponse.ClusterConfig.Config, - "cluster_metadata": infoResponse.ClusterConfig.OperatorMetadata, - "worker_node_infos": infoResponse.WorkerNodeInfos, - "operator_node_infos": infoResponse.OperatorNodeInfos, - "endpoint_operator": operatorEndpoint, - "endpoint_api": apiEndpoint, - } + infoInterface := map[string]interface{}{ + "cluster_config": infoResponse.ClusterConfig.Config, + "cluster_metadata": infoResponse.ClusterConfig.OperatorMetadata, + "worker_node_infos": infoResponse.WorkerNodeInfos, + "operator_node_infos": infoResponse.OperatorNodeInfos, + "endpoint_operator": operatorEndpoint, + "endpoint_api": apiEndpoint, } var outputBytes []byte diff --git a/cli/cmd/lib_cluster_config.go b/cli/cmd/lib_cluster_config.go index 1da6de2f7a..1f67d9ace3 100644 --- a/cli/cmd/lib_cluster_config.go +++ b/cli/cmd/lib_cluster_config.go @@ -60,7 +60,7 @@ func existingCachedClusterConfigPaths() []string { } func readCachedClusterConfigFile(clusterConfig *clusterconfig.Config, filePath string) error { - errs := cr.ParseYAMLFile(clusterConfig, clusterconfig.FullManagedValidation, filePath) + errs := cr.ParseYAMLFile(clusterConfig, clusterconfig.FullConfigValidation, filePath) if errors.HasError(errs) { return errors.FirstError(errs...) } @@ -69,7 +69,7 @@ func readCachedClusterConfigFile(clusterConfig *clusterconfig.Config, filePath s } func readUserClusterConfigFile(clusterConfig *clusterconfig.Config, filePath string) error { - errs := cr.ParseYAMLFile(clusterConfig, clusterconfig.FullManagedValidation, filePath) + errs := cr.ParseYAMLFile(clusterConfig, clusterconfig.FullConfigValidation, filePath) if errors.HasError(errs) { return errors.Append(errors.FirstError(errs...), fmt.Sprintf("\n\ncluster configuration schema can be found at https://docs.cortex.dev/v/%s/", consts.CortexVersionMinor)) } diff --git a/pkg/config/config.go b/pkg/config/config.go index c2f46c101a..5f73dbf6e0 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -78,8 +78,6 @@ func getClusterConfigFromConfigMap() (clusterconfig.Config, error) { func Init() error { var err error - var clusterNamespace string - var istioNamespace string clusterConfigPath := os.Getenv("CORTEX_CLUSTER_CONFIG_PATH") if clusterConfigPath == "" { @@ -112,14 +110,11 @@ func Init() error { IsOperatorInCluster: strings.ToLower(os.Getenv("CORTEX_OPERATOR_IN_CLUSTER")) != "false", } - clusterNamespace = clusterConfig.Namespace - istioNamespace = clusterConfig.IstioNamespace - - if K8s, err = k8s.New(clusterNamespace, OperatorMetadata.IsOperatorInCluster, nil, scheme); err != nil { + if K8s, err = k8s.New(consts.DefaultNamespace, OperatorMetadata.IsOperatorInCluster, nil, scheme); err != nil { return err } - if K8sIstio, err = k8s.New(istioNamespace, OperatorMetadata.IsOperatorInCluster, nil, scheme); err != nil { + if K8sIstio, err = k8s.New(consts.IstioNamespace, OperatorMetadata.IsOperatorInCluster, nil, scheme); err != nil { return err } @@ -157,7 +152,7 @@ func Init() error { prometheusURL := os.Getenv("CORTEX_PROMETHEUS_URL") if len(prometheusURL) == 0 { - prometheusURL = fmt.Sprintf("http://prometheus.%s:9090", clusterNamespace) + prometheusURL = fmt.Sprintf("http://prometheus.%s:9090", consts.DefaultNamespace) } promClient, err := promapi.NewClient(promapi.Config{ @@ -172,9 +167,11 @@ func Init() error { return err } - MetricsClient, err = statsd.New("prometheus-statsd-exporter.default:9125") - if err != nil { - return errors.Wrap(errors.WithStack(err), "unable to initialize metrics client") + if OperatorMetadata.IsOperatorInCluster { + MetricsClient, err = statsd.New(fmt.Sprintf("prometheus-statsd-exporter.%s:9125", consts.DefaultNamespace)) + if err != nil { + return errors.Wrap(errors.WithStack(err), "unable to initialize metrics client") + } } return nil diff --git a/pkg/consts/consts.go b/pkg/consts/consts.go index 4dddd258ad..67a9c7e4d0 100644 --- a/pkg/consts/consts.go +++ b/pkg/consts/consts.go @@ -27,6 +27,9 @@ var ( CortexVersion = "master" // CORTEX_VERSION CortexVersionMinor = "master" // CORTEX_VERSION_MINOR + DefaultNamespace = "default" + IstioNamespace = "istio-system" + DefaultMaxQueueLength = int64(100) DefaultMaxConcurrency = int64(1) diff --git a/pkg/operator/operator/cron.go b/pkg/operator/operator/cron.go index a234f31240..276c0595a5 100644 --- a/pkg/operator/operator/cron.go +++ b/pkg/operator/operator/cron.go @@ -84,7 +84,6 @@ func ClusterTelemetry() error { } telemetry.Event("operator.cron", properties, config.ClusterConfig.CoreConfig.TelemetryEvent(), - config.ClusterConfig.ManagedConfig.TelemetryEvent(), ) return nil diff --git a/pkg/operator/resources/realtimeapi/k8s_specs.go b/pkg/operator/resources/realtimeapi/k8s_specs.go index a5dc01f995..7a6824d14d 100644 --- a/pkg/operator/resources/realtimeapi/k8s_specs.go +++ b/pkg/operator/resources/realtimeapi/k8s_specs.go @@ -19,7 +19,6 @@ package realtimeapi import ( "fmt" - "github.com/cortexlabs/cortex/pkg/config" "github.com/cortexlabs/cortex/pkg/consts" "github.com/cortexlabs/cortex/pkg/lib/k8s" "github.com/cortexlabs/cortex/pkg/lib/pointer" @@ -135,7 +134,7 @@ func virtualServiceSpec(api *spec.API) *istioclientnetworking.VirtualService { consts.CortexTargetServiceHeader: fmt.Sprintf( "http://%s.%s:%d", workloads.K8sName(api.Name), - config.ClusterConfig.Namespace, + consts.DefaultNamespace, consts.ProxyPortInt32, ), }, diff --git a/pkg/types/clusterconfig/cluster_config.go b/pkg/types/clusterconfig/cluster_config.go index be098efcc8..0326ab2478 100644 --- a/pkg/types/clusterconfig/cluster_config.go +++ b/pkg/types/clusterconfig/cluster_config.go @@ -78,19 +78,10 @@ var ( ) type CoreConfig struct { - // Non-user-specifiable fields - ClusterUID string `json:"cluster_uid" yaml:"cluster_uid"` - Bucket string `json:"bucket" yaml:"bucket"` - Telemetry bool `json:"telemetry" yaml:"telemetry"` - Namespace string `json:"namespace" yaml:"namespace"` - IstioNamespace string `json:"istio_namespace" yaml:"istio_namespace"` - - // User-specifiable fields ClusterName string `json:"cluster_name" yaml:"cluster_name"` Region string `json:"region" yaml:"region"` PrometheusInstanceType string `json:"prometheus_instance_type" yaml:"prometheus_instance_type"` - // User-specifiable fields ImageOperator string `json:"image_operator" yaml:"image_operator"` ImageControllerManager string `json:"image_controller_manager" yaml:"image_controller_manager"` ImageManager string `json:"image_manager" yaml:"image_manager"` @@ -119,9 +110,7 @@ type CoreConfig struct { ImageKubeRBACProxy string `json:"image_kube_rbac_proxy" yaml:"image_kube_rbac_proxy"` ImageGrafana string `json:"image_grafana" yaml:"image_grafana"` ImageEventExporter string `json:"image_event_exporter" yaml:"image_event_exporter"` -} -type ManagedConfig struct { NodeGroups []*NodeGroup `json:"node_groups" yaml:"node_groups"` Tags map[string]string `json:"tags" yaml:"tags"` AvailabilityZones []string `json:"availability_zones" yaml:"availability_zones"` @@ -135,8 +124,15 @@ type ManagedConfig struct { APILoadBalancerCIDRWhiteList []string `json:"api_load_balancer_cidr_white_list,omitempty" yaml:"api_load_balancer_cidr_white_list,omitempty"` OperatorLoadBalancerCIDRWhiteList []string `json:"operator_load_balancer_cidr_white_list,omitempty" yaml:"operator_load_balancer_cidr_white_list,omitempty"` VPCCIDR *string `json:"vpc_cidr,omitempty" yaml:"vpc_cidr,omitempty"` - CortexPolicyARN string `json:"cortex_policy_arn" yaml:"cortex_policy_arn"` // this field is not user facing - AccountID string `json:"account_id" yaml:"account_id"` // this field is not user facing + Telemetry bool `json:"telemetry" yaml:"telemetry"` +} + +type ManagedConfig struct { + // fields that must be set by Cortex + CortexPolicyARN string `json:"cortex_policy_arn" yaml:"cortex_policy_arn"` + AccountID string `json:"account_id" yaml:"account_id"` + ClusterUID string `json:"cluster_uid" yaml:"cluster_uid"` + Bucket string `json:"bucket" yaml:"bucket"` } type NodeGroup struct { @@ -222,22 +218,13 @@ func (c *ConfigureChanges) GetGhostEKSNodeGroups() []string { // NewForFile initializes and validates the cluster config from the YAML config file func NewForFile(clusterConfigPath string) (*Config, error) { - coreConfig := CoreConfig{} - errs := cr.ParseYAMLFile(&coreConfig, CoreConfigValidations(true), clusterConfigPath) + config := Config{} + errs := cr.ParseYAMLFile(&config, FullConfigValidation, clusterConfigPath) if errors.HasError(errs) { return nil, errors.FirstError(errs...) } - managedConfig := ManagedConfig{} - errs = cr.ParseYAMLFile(&managedConfig, ManagedConfigValidations(true), clusterConfigPath) - if errors.HasError(errs) { - return nil, errors.FirstError(errs...) - } - - return &Config{ - CoreConfig: coreConfig, - ManagedConfig: managedConfig, - }, nil + return &config, nil } func ValidateRegion(region string) error { @@ -276,51 +263,6 @@ func (cc *Config) Hash() (string, error) { } var CoreConfigStructFieldValidations = []*cr.StructFieldValidation{ - { - Key: "provider", - StringValidation: &cr.StringValidation{ - AllowEmpty: true, - Validator: func(provider string) (string, error) { - if provider == "" || provider == "aws" { - return "", nil - } - if provider == "gcp" || provider == "local" { - return "", ErrorInvalidLegacyProvider(provider) - } - return "", ErrorInvalidProvider(provider) - }, - }, - }, - { - StructField: "ClusterUID", - StringValidation: &cr.StringValidation{ - Default: "", - AllowEmpty: true, - TreatNullAsEmpty: true, - }, - }, - { - StructField: "Bucket", - StringValidation: &cr.StringValidation{ - Default: "", - AllowEmpty: true, - TreatNullAsEmpty: true, - }, - }, - { - StructField: "Namespace", - StringValidation: &cr.StringValidation{ - Default: "default", - AllowedValues: []string{"default"}, - }, - }, - { - StructField: "IstioNamespace", - StringValidation: &cr.StringValidation{ - Default: "istio-system", - AllowedValues: []string{"istio-system"}, - }, - }, { StructField: "ClusterName", StringValidation: &cr.StringValidation{ @@ -548,9 +490,6 @@ var CoreConfigStructFieldValidations = []*cr.StructFieldValidation{ Validator: validateImageVersion, }, }, -} - -var ManagedConfigStructFieldValidations = []*cr.StructFieldValidation{ { StructField: "NodeGroups", StructListValidation: &cr.StructListValidation{ @@ -711,6 +650,25 @@ var ManagedConfigStructFieldValidations = []*cr.StructFieldValidation{ Validator: validateCIDR, }, }, +} + +var ManagedConfigStructFieldValidations = []*cr.StructFieldValidation{ + { + StructField: "ClusterUID", + StringValidation: &cr.StringValidation{ + Default: "", + AllowEmpty: true, + TreatNullAsEmpty: true, + }, + }, + { + StructField: "Bucket", + StringValidation: &cr.StringValidation{ + Default: "", + AllowEmpty: true, + TreatNullAsEmpty: true, + }, + }, { StructField: "CortexPolicyARN", StringValidation: &cr.StringValidation{ @@ -857,25 +815,10 @@ var nodeGroupsFieldValidation *cr.StructValidation = &cr.StructValidation{ }, } -func CoreConfigValidations(allowExtraFields bool) *cr.StructValidation { - return &cr.StructValidation{ - Required: true, - StructFieldValidations: CoreConfigStructFieldValidations, - AllowExtraFields: allowExtraFields, - } -} - -func ManagedConfigValidations(allowExtraFields bool) *cr.StructValidation { - return &cr.StructValidation{ - Required: true, - StructFieldValidations: ManagedConfigStructFieldValidations, - AllowExtraFields: allowExtraFields, - } -} - -var FullManagedValidation = &cr.StructValidation{ +var FullConfigValidation = &cr.StructValidation{ Required: true, StructFieldValidations: append([]*cr.StructFieldValidation{}, append(CoreConfigStructFieldValidations, ManagedConfigStructFieldValidations...)...), + AllowExtraFields: false, } var AccessValidation = &cr.StructValidation{ @@ -1688,13 +1631,6 @@ func (cc *CoreConfig) TelemetryEvent() map[string]interface{} { event["cluster_name._is_custom"] = true } - if cc.Namespace != "default" { - event["namespace._is_custom"] = true - } - if cc.IstioNamespace != "istio-system" { - event["istio_namespace._is_custom"] = true - } - event["region"] = cc.Region event["prometheus_instance_type"] = cc.PrometheusInstanceType @@ -1783,40 +1719,35 @@ func (cc *CoreConfig) TelemetryEvent() map[string]interface{} { event["image_event_exporter._is_custom"] = true } - return event -} - -func (mc *ManagedConfig) TelemetryEvent() map[string]interface{} { - event := map[string]interface{}{} - if len(mc.Tags) > 0 { + if len(cc.Tags) > 0 { event["tags._is_defined"] = true - event["tags._len"] = len(mc.Tags) + event["tags._len"] = len(cc.Tags) } - if len(mc.AvailabilityZones) > 0 { + if len(cc.AvailabilityZones) > 0 { event["availability_zones._is_defined"] = true - event["availability_zones._len"] = len(mc.AvailabilityZones) - event["availability_zones"] = mc.AvailabilityZones + event["availability_zones._len"] = len(cc.AvailabilityZones) + event["availability_zones"] = cc.AvailabilityZones } - if len(mc.Subnets) > 0 { + if len(cc.Subnets) > 0 { event["subnets._is_defined"] = true - event["subnets._len"] = len(mc.Subnets) - event["subnets"] = mc.Subnets + event["subnets._len"] = len(cc.Subnets) + event["subnets"] = cc.Subnets } - if mc.SSLCertificateARN != nil { + if cc.SSLCertificateARN != nil { event["ssl_certificate_arn._is_defined"] = true } // CortexPolicyARN should be managed by cortex - if !strset.New(_defaultIAMPolicies...).IsEqual(strset.New(mc.IAMPolicyARNs...)) { + if !strset.New(_defaultIAMPolicies...).IsEqual(strset.New(cc.IAMPolicyARNs...)) { event["iam_policy_arns._is_custom"] = true } - event["iam_policy_arns._len"] = len(mc.IAMPolicyARNs) + event["iam_policy_arns._len"] = len(cc.IAMPolicyARNs) - event["subnet_visibility"] = mc.SubnetVisibility - event["nat_gateway"] = mc.NATGateway - event["api_load_balancer_scheme"] = mc.APILoadBalancerScheme - event["operator_load_balancer_scheme"] = mc.OperatorLoadBalancerScheme - if mc.VPCCIDR != nil { + event["subnet_visibility"] = cc.SubnetVisibility + event["nat_gateway"] = cc.NATGateway + event["api_load_balancer_scheme"] = cc.APILoadBalancerScheme + event["operator_load_balancer_scheme"] = cc.OperatorLoadBalancerScheme + if cc.VPCCIDR != nil { event["vpc_cidr._is_defined"] = true } @@ -1824,11 +1755,12 @@ func (mc *ManagedConfig) TelemetryEvent() map[string]interface{} { spotInstanceTypes := strset.New() var totalMinSize, totalMaxSize int - event["node_groups._len"] = len(mc.NodeGroups) - for i, ng := range mc.NodeGroups { + event["node_groups._len"] = len(cc.NodeGroups) + for i, ng := range cc.NodeGroups { nodeGroupKey := func(field string) string { return fmt.Sprintf("node_groups.%d.%s", i, field) } + event[nodeGroupKey("_is_defined")] = true event[nodeGroupKey("name")] = ng.Name event[nodeGroupKey("instance_type")] = ng.InstanceType @@ -1891,8 +1823,8 @@ func (mc *ManagedConfig) TelemetryEvent() map[string]interface{} { return event } -func (mc *ManagedConfig) GetNodeGroupByName(name string) *NodeGroup { - for _, ng := range mc.NodeGroups { +func (cc *CoreConfig) GetNodeGroupByName(name string) *NodeGroup { + for _, ng := range cc.NodeGroups { if ng.Name == name { matchedNodeGroup := *ng return &matchedNodeGroup @@ -1902,10 +1834,10 @@ func (mc *ManagedConfig) GetNodeGroupByName(name string) *NodeGroup { return nil } -func (mc *ManagedConfig) GetNodeGroupNames() []string { - allNodeGroupNames := make([]string, len(mc.NodeGroups)) - for i := range mc.NodeGroups { - allNodeGroupNames[i] = mc.NodeGroups[i].Name +func (cc *CoreConfig) GetNodeGroupNames() []string { + allNodeGroupNames := make([]string, len(cc.NodeGroups)) + for i := range cc.NodeGroups { + allNodeGroupNames[i] = cc.NodeGroups[i].Name } return allNodeGroupNames From 776391ff0601921a374d5f20cdf0676d6cd8c5fd Mon Sep 17 00:00:00 2001 From: vishal Date: Wed, 7 Jul 2021 23:37:48 -0400 Subject: [PATCH 2/4] Fix typo --- pkg/config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index 5f73dbf6e0..304ee1dcf3 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -68,7 +68,7 @@ func getClusterConfigFromConfigMap() (clusterconfig.Config, error) { return clusterconfig.Config{}, err } clusterConfig := clusterconfig.Config{} - err = cr.ParseYAMLBytes(&clusterConfig, clusterconfig.FullManagedValidation, []byte(configMapData["cluster.yaml"])) + err = cr.ParseYAMLBytes(&clusterConfig, clusterconfig.FullConfigValidation, []byte(configMapData["cluster.yaml"])) if err != nil { return clusterconfig.Config{}, err } From d4f0a1a0779154b9af7c152fe9596f544ab86528 Mon Sep 17 00:00:00 2001 From: vishal Date: Wed, 7 Jul 2021 23:51:11 -0400 Subject: [PATCH 3/4] Fix typos --- pkg/crds/controllers/batch/batchjob_controller_helpers.go | 2 +- pkg/crds/main.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/crds/controllers/batch/batchjob_controller_helpers.go b/pkg/crds/controllers/batch/batchjob_controller_helpers.go index b48c4b2460..e04d98524d 100644 --- a/pkg/crds/controllers/batch/batchjob_controller_helpers.go +++ b/pkg/crds/controllers/batch/batchjob_controller_helpers.go @@ -529,7 +529,7 @@ func (r *BatchJobReconciler) updateStatus(ctx context.Context, batchJob *batch.B func (r *BatchJobReconciler) checkWorkersOOM(ctx context.Context, batchJob *batch.BatchJob) (bool, error) { workerJobPods := kcore.PodList{} if err := r.List(ctx, &workerJobPods, - client.InNamespace(r.ClusterConfig.Namespace), + client.InNamespace(consts.DefaultNamespace), client.MatchingLabels{ "jobID": batchJob.Name, "apiName": batchJob.Spec.APIName, diff --git a/pkg/crds/main.go b/pkg/crds/main.go index c4f1182995..62b552a426 100644 --- a/pkg/crds/main.go +++ b/pkg/crds/main.go @@ -102,7 +102,7 @@ func main() { } if prometheusURL == "" { - prometheusURL = fmt.Sprintf("http://prometheus.%s:9090", clusterConfig.Namespace) + prometheusURL = fmt.Sprintf("http://prometheus.%s:9090", consts.DefaultNamespace) } mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ From 94f29665e906302c4d752bd4fc39b08c2daebe86 Mon Sep 17 00:00:00 2001 From: vishal Date: Mon, 12 Jul 2021 18:28:29 -0400 Subject: [PATCH 4/4] Respond to PR comments --- pkg/types/clusterconfig/cluster_config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/types/clusterconfig/cluster_config.go b/pkg/types/clusterconfig/cluster_config.go index 77f88cfa6a..aa7c80dbd1 100644 --- a/pkg/types/clusterconfig/cluster_config.go +++ b/pkg/types/clusterconfig/cluster_config.go @@ -823,7 +823,7 @@ var nodeGroupsFieldValidation *cr.StructValidation = &cr.StructValidation{ var FullConfigValidation = &cr.StructValidation{ Required: true, - StructFieldValidations: append([]*cr.StructFieldValidation{}, append(CoreConfigStructFieldValidations, ManagedConfigStructFieldValidations...)...), + StructFieldValidations: append(CoreConfigStructFieldValidations, ManagedConfigStructFieldValidations...), AllowExtraFields: false, }