From 557f64f32942da3e80050b8c8cd23dcd8d2bd40a Mon Sep 17 00:00:00 2001 From: David Eliahu Date: Mon, 21 Jun 2021 15:37:11 -0700 Subject: [PATCH 1/3] Support clusters with no node groups --- pkg/lib/configreader/reader.go | 2 +- pkg/operator/resources/errors.go | 10 +++++ pkg/operator/resources/validations.go | 4 ++ pkg/types/clusterconfig/availability_zones.go | 42 +++++++++++-------- pkg/types/clusterconfig/cluster_config.go | 8 ++-- pkg/types/clusterconfig/errors.go | 8 ---- 6 files changed, 43 insertions(+), 31 deletions(-) diff --git a/pkg/lib/configreader/reader.go b/pkg/lib/configreader/reader.go index 3e9032eb52..73c7c5eaac 100644 --- a/pkg/lib/configreader/reader.go +++ b/pkg/lib/configreader/reader.go @@ -94,7 +94,7 @@ type StructListValidation struct { StructValidation *StructValidation Required bool AllowExplicitNull bool - TreatNullAsEmpty bool // If explicit null or if it's top level and the file is empty, treat as empty map + TreatNullAsEmpty bool // If explicit null or if it's top level and the file is empty, treat as empty list MinLength int MaxLength int InvalidLengths []int diff --git a/pkg/operator/resources/errors.go b/pkg/operator/resources/errors.go index a5e4748b5a..d8c58c2b66 100644 --- a/pkg/operator/resources/errors.go +++ b/pkg/operator/resources/errors.go @@ -44,6 +44,7 @@ const ( ErrRealtimeAPIUsedByTrafficSplitter = "resources.realtime_api_used_by_traffic_splitter" ErrAPIsNotDeployed = "resources.apis_not_deployed" ErrInvalidNodeGroupSelector = "resources.invalid_node_group_selector" + ErrNoNodeGroups = "resources.no_node_groups" ) func ErrorOperationIsOnlySupportedForKind(resource operator.DeployedResource, supportedKind userconfig.Kind, supportedKinds ...userconfig.Kind) error { @@ -118,6 +119,15 @@ func ErrorInvalidNodeGroupSelector(selected string, availableNodeGroups []string }) } +func ErrorNoNodeGroups() error { + return errors.WithStack(&errors.Error{ + Kind: ErrNoNodeGroups, + Message: fmt.Sprintf("your api cannot be deployed because your cluster doesn't have any node groups; create a node group with `cortex cluster configure CLUSTER_CONFIG_FILE`"), + }) +} + +// HELPERS + func podResourceRequestsTable(api *userconfig.API, compute userconfig.Compute) string { sidecarCPUNote := "" sidecarMemNote := "" diff --git a/pkg/operator/resources/validations.go b/pkg/operator/resources/validations.go index 3c240ad6d2..f112c99115 100644 --- a/pkg/operator/resources/validations.go +++ b/pkg/operator/resources/validations.go @@ -36,6 +36,10 @@ func ValidateClusterAPIs(apis []userconfig.API) error { return spec.ErrorNoAPIs() } + if len(config.ClusterConfig.NodeGroups) == 0 { + return ErrorNoNodeGroups() + } + virtualServices, err := config.K8s.ListVirtualServices(nil) if err != nil { return err diff --git a/pkg/types/clusterconfig/availability_zones.go b/pkg/types/clusterconfig/availability_zones.go index eef2b42d13..a59af304f6 100644 --- a/pkg/types/clusterconfig/availability_zones.go +++ b/pkg/types/clusterconfig/availability_zones.go @@ -47,9 +47,15 @@ func (cc *Config) setDefaultAvailabilityZones(awsClient *aws.Client) error { } instanceTypesSlice := instanceTypes.Slice() - zones, err := awsClient.ListSupportedAvailabilityZones(instanceTypesSlice[0], instanceTypesSlice[1:]...) - if err != nil { - // Try again without checking instance types + var zones strset.Set + var err error + + if len(instanceTypesSlice) > 0 { + zones, err = awsClient.ListSupportedAvailabilityZones(instanceTypesSlice[0], instanceTypesSlice[1:]...) + } + + if len(zones) == 0 || err != nil { + // Try without checking instance types zones, err = awsClient.ListAvailabilityZonesInRegion() if err != nil { return nil // Let eksctl choose the availability zones @@ -75,12 +81,6 @@ func (cc *Config) setDefaultAvailabilityZones(awsClient *aws.Client) error { } func (cc *Config) validateUserAvailabilityZones(awsClient *aws.Client) error { - instanceTypes := strset.New() - for _, ng := range cc.NodeGroups { - instanceTypes.Add(ng.InstanceType) - } - instanceTypesSlice := instanceTypes.Slice() - allZones, err := awsClient.ListAvailabilityZonesInRegion() if err != nil { return nil // Skip validation @@ -92,15 +92,23 @@ func (cc *Config) validateUserAvailabilityZones(awsClient *aws.Client) error { } } - supportedZones, err := awsClient.ListSupportedAvailabilityZones(instanceTypesSlice[0], instanceTypesSlice[1:]...) - if err != nil { - // Skip validation instance-based validation - supportedZones = strset.Difference(allZones, _azBlacklist) - } + if len(cc.NodeGroups) > 0 { + instanceTypes := strset.New() + for _, ng := range cc.NodeGroups { + instanceTypes.Add(ng.InstanceType) + } + instanceTypesSlice := instanceTypes.Slice() - for _, userZone := range cc.AvailabilityZones { - if !supportedZones.Has(userZone) { - return ErrorUnsupportedAvailabilityZone(userZone, instanceTypesSlice[0], instanceTypesSlice[1:]...) + supportedZones, err := awsClient.ListSupportedAvailabilityZones(instanceTypesSlice[0], instanceTypesSlice[1:]...) + if err != nil { + // Skip validation instance-based validation + supportedZones = strset.Difference(allZones, _azBlacklist) + } + + for _, userZone := range cc.AvailabilityZones { + if !supportedZones.Has(userZone) { + return ErrorUnsupportedAvailabilityZone(userZone, instanceTypesSlice[0], instanceTypesSlice[1:]...) + } } } diff --git a/pkg/types/clusterconfig/cluster_config.go b/pkg/types/clusterconfig/cluster_config.go index 6049aeeaf8..ad7667d403 100644 --- a/pkg/types/clusterconfig/cluster_config.go +++ b/pkg/types/clusterconfig/cluster_config.go @@ -517,8 +517,9 @@ var ManagedConfigStructFieldValidations = []*cr.StructFieldValidation{ { StructField: "NodeGroups", StructListValidation: &cr.StructListValidation{ - Required: true, - StructValidation: nodeGroupsFieldValidation, + AllowExplicitNull: true, + TreatNullAsEmpty: true, + StructValidation: nodeGroupsFieldValidation, }, }, { @@ -890,9 +891,6 @@ func (cc *CoreConfig) SQSNamePrefix() string { func (cc *Config) validate(awsClient *aws.Client) error { numNodeGroups := len(cc.NodeGroups) - if numNodeGroups == 0 { - return ErrorNoNodeGroupSpecified() - } if numNodeGroups > MaxNodePoolsOrGroups { return ErrorMaxNumOfNodeGroupsReached(MaxNodePoolsOrGroups) } diff --git a/pkg/types/clusterconfig/errors.go b/pkg/types/clusterconfig/errors.go index c6c13113ba..ca130e99fe 100644 --- a/pkg/types/clusterconfig/errors.go +++ b/pkg/types/clusterconfig/errors.go @@ -32,7 +32,6 @@ const ( ErrInvalidLegacyProvider = "clusterconfig.invalid_legacy_provider" ErrDisallowedField = "clusterconfig.disallowed_field" ErrInvalidRegion = "clusterconfig.invalid_region" - ErrNoNodeGroupSpecified = "clusterconfig.no_nodegroup_specified" ErrNodeGroupMaxInstancesIsZero = "clusterconfig.node_group_max_instances_is_zero" ErrMaxNumOfNodeGroupsReached = "clusterconfig.max_num_of_nodegroups_reached" ErrDuplicateNodeGroupName = "clusterconfig.duplicate_nodegroup_name" @@ -105,13 +104,6 @@ func ErrorInvalidRegion(region string) error { }) } -func ErrorNoNodeGroupSpecified() error { - return errors.WithStack(&errors.Error{ - Kind: ErrNoNodeGroupSpecified, - Message: "no nodegroup was specified; please specify at least 1 nodegroup", - }) -} - func ErrorNodeGroupMaxInstancesIsZero() error { return errors.WithStack(&errors.Error{ Kind: ErrNodeGroupMaxInstancesIsZero, From 89abe3483f2c45749e96d57608bcae636efed861 Mon Sep 17 00:00:00 2001 From: David Eliahu Date: Mon, 21 Jun 2021 15:39:28 -0700 Subject: [PATCH 2/3] Delete unnecessary comment --- pkg/operator/resources/errors.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/pkg/operator/resources/errors.go b/pkg/operator/resources/errors.go index d8c58c2b66..977e8a9257 100644 --- a/pkg/operator/resources/errors.go +++ b/pkg/operator/resources/errors.go @@ -126,8 +126,6 @@ func ErrorNoNodeGroups() error { }) } -// HELPERS - func podResourceRequestsTable(api *userconfig.API, compute userconfig.Compute) string { sidecarCPUNote := "" sidecarMemNote := "" From 29998ac240a6ce9825735fa6753e0a6bf5cbf109 Mon Sep 17 00:00:00 2001 From: David Eliahu Date: Mon, 21 Jun 2021 15:42:11 -0700 Subject: [PATCH 3/3] Delete new lines --- pkg/types/clusterconfig/availability_zones.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/pkg/types/clusterconfig/availability_zones.go b/pkg/types/clusterconfig/availability_zones.go index a59af304f6..0c5900b5d7 100644 --- a/pkg/types/clusterconfig/availability_zones.go +++ b/pkg/types/clusterconfig/availability_zones.go @@ -49,11 +49,9 @@ func (cc *Config) setDefaultAvailabilityZones(awsClient *aws.Client) error { var zones strset.Set var err error - if len(instanceTypesSlice) > 0 { zones, err = awsClient.ListSupportedAvailabilityZones(instanceTypesSlice[0], instanceTypesSlice[1:]...) } - if len(zones) == 0 || err != nil { // Try without checking instance types zones, err = awsClient.ListAvailabilityZonesInRegion()