diff --git a/clusterdictionary/size.go b/clusterdictionary/size.go index 153f738f7..22b9dbf18 100644 --- a/clusterdictionary/size.go +++ b/clusterdictionary/size.go @@ -5,6 +5,11 @@ package clusterdictionary import ( + "strconv" + "strings" + + ec2Types "github.com/aws/aws-sdk-go-v2/service/ec2/types" + "github.com/gookit/goutil/arrutil" "github.com/mattermost/mattermost-cloud/model" "github.com/pkg/errors" ) @@ -130,6 +135,41 @@ func ApplyToPatchClusterSizeRequest(size string, request *model.PatchClusterSize return nil } +func processCustomSize(size string) (string, int64, int64, error) { + if len(size) == 0 { + return "", 0, 0, nil + } + + parts := strings.Split(size, ";") + ngType := ec2Types.InstanceType(parts[0]) + + if !arrutil.In[ec2Types.InstanceType](ngType, ngType.Values()) { + return "", 0, 0, errors.Errorf("%s is not a valid InstanceType", ngType) + } + + minCount := 2 + maxCount := 2 + + for _, part := range parts[1:] { + switch { + case strings.HasPrefix(part, "min="): + minCount, _ = strconv.Atoi(strings.TrimPrefix(part, "min=")) + case strings.HasPrefix(part, "max="): + maxCount, _ = strconv.Atoi(strings.TrimPrefix(part, "max=")) + } + } + + if minCount < 1 { + minCount = 1 + } + + if minCount > maxCount { + maxCount = minCount + } + + return string(ngType), int64(minCount), int64(maxCount), nil +} + // AddToCreateClusterRequest takes a map of size keywords and adds the corresponding // values to a CreateClusterRequest. func AddToCreateClusterRequest(sizes map[string]string, request *model.CreateClusterRequest) error { @@ -142,17 +182,15 @@ func AddToCreateClusterRequest(sizes map[string]string, request *model.CreateClu } for ng, ngSize := range sizes { - if !IsValidClusterSize(ngSize) { - return errors.Errorf("%s is not a valid size", ngSize) + ngType, minCount, maxCount, err := processCustomSize(ngSize) + if err != nil { + return err } - values := ValidSizes[ngSize] - request.AdditionalNodeGroups[ng] = model.NodeGroupMetadata{ - // These values are used in EKS configuration, but not in kops. - InstanceType: values.NodeInstanceType, - MinCount: values.NodeMinCount, - MaxCount: values.NodeMaxCount, + InstanceType: ngType, + MinCount: minCount, + MaxCount: maxCount, } } @@ -171,16 +209,15 @@ func AddToCreateNodegroupsRequest(sizes map[string]string, request *model.Create } for ng, ngSize := range sizes { - if !IsValidClusterSize(ngSize) { - return errors.Errorf("%s is not a valid size", ngSize) + ngType, minCount, maxCount, err := processCustomSize(ngSize) + if err != nil { + return err } - values := ValidSizes[ngSize] - request.Nodegroups[ng] = model.NodeGroupMetadata{ - InstanceType: values.NodeInstanceType, - MinCount: values.NodeMinCount, - MaxCount: values.NodeMaxCount, + InstanceType: ngType, + MinCount: minCount, + MaxCount: maxCount, } } diff --git a/cmd/cloud/cluster.go b/cmd/cloud/cluster.go index 07084beb0..b9b5bdc60 100644 --- a/cmd/cloud/cluster.go +++ b/cmd/cloud/cluster.go @@ -136,7 +136,7 @@ func executeClusterCreateCmd(flags clusterCreateFlags) error { continue } if _, f := flags.additionalNodegroups[ng]; !f { - return fmt.Errorf("nodegroup %s not provided as additional nodegroups", ng) + return fmt.Errorf("nodegroup %s not provided as an additional nodegroup", ng) } } @@ -145,7 +145,7 @@ func executeClusterCreateCmd(flags clusterCreateFlags) error { continue } if _, f := flags.additionalNodegroups[ng]; !f { - return fmt.Errorf("nodegroup %s not provided as additional nodegroups", ng) + return fmt.Errorf("nodegroup %s not provided as an additional nodegroup", ng) } } diff --git a/cmd/cloud/cluster_flag.go b/cmd/cloud/cluster_flag.go index a5cd92ecb..7aef53652 100644 --- a/cmd/cloud/cluster_flag.go +++ b/cmd/cloud/cluster_flag.go @@ -49,7 +49,7 @@ func (flags *createRequestOptions) addFlags(command *cobra.Command) { command.Flags().StringVar(&flags.clusterRoleARN, "cluster-role-arn", "", "AWS role ARN for cluster.") command.Flags().StringVar(&flags.nodeRoleARN, "node-role-arn", "", "AWS role ARN for node.") command.Flags().BoolVar(&flags.useEKS, "eks", false, "Create EKS cluster.") - command.Flags().StringToStringVar(&flags.additionalNodegroups, "additional-nodegroups", nil, "Additional nodegroups to create. The key is the name of the nodegroup and the value is the size constant.") + command.Flags().StringToStringVar(&flags.additionalNodegroups, "additional-nodegroups", nil, "Additional nodegroups to create. Example: --additional-nodegroups ng1=t3.medium;min=1;max=3") command.Flags().StringSliceVar(&flags.nodegroupsWithPublicSubnet, "nodegroups-with-public-subnet", nil, "Nodegroups to create with public subnet. The value is the name of the nodegroup.") command.Flags().StringSliceVar(&flags.nodegroupsWithSecurityGroup, "nodegroups-with-sg", nil, "Nodegroups to create with dedicated security group. The value is the name of the nodegroup.") } diff --git a/cmd/cloud/nodegroup_flag.go b/cmd/cloud/nodegroup_flag.go index 059e6fa77..6d42ad309 100644 --- a/cmd/cloud/nodegroup_flag.go +++ b/cmd/cloud/nodegroup_flag.go @@ -16,9 +16,9 @@ type clusterNodegroupsCreateFlags struct { func (flags *clusterNodegroupsCreateFlags) addFlags(command *cobra.Command) { command.Flags().StringVar(&flags.clusterID, "cluster", "", "The id of the cluster to be modified.") - command.Flags().StringToStringVar(&flags.nodegroups, "nodegroups", nil, "Additional nodegroups to create. The key is the name of the nodegroup and the value is the size constant.") - command.Flags().StringSliceVar(&flags.nodegroupsWithPublicSubnet, "nodegroups-with-public-subnet", nil, "Nodegroups to create with public subnet. The value is the name of the nodegroup.") - command.Flags().StringSliceVar(&flags.nodegroupsWithSecurityGroup, "nodegroups-with-sg", nil, "Nodegroups to create with dedicated security group. The value is the name of the nodegroup.") + command.Flags().StringToStringVar(&flags.nodegroups, "nodegroups", nil, "Additional nodegroups to create. Example: --nodegroups ng1=t3.medium;min=1;max=3") + command.Flags().StringSliceVar(&flags.nodegroupsWithPublicSubnet, "nodegroups-with-public-subnet", nil, "Nodegroups to create with public subnet. The value is the name of the nodegroups.") + command.Flags().StringSliceVar(&flags.nodegroupsWithSecurityGroup, "nodegroups-with-sg", nil, "Nodegroups to create with dedicated security group. The value is the name of the nodegroupa.") _ = command.MarkFlagRequired("cluster") _ = command.MarkFlagRequired("nodegroups") diff --git a/go.mod b/go.mod index 9a8548fc4..09226c425 100644 --- a/go.mod +++ b/go.mod @@ -28,6 +28,7 @@ require ( github.com/cloudflare/cloudflare-go v0.54.0 github.com/go-sql-driver/mysql v1.6.0 github.com/golang/mock v1.6.0 + github.com/gookit/goutil v0.6.8 github.com/gorilla/mux v1.8.0 github.com/gosuri/uilive v0.0.4 github.com/jmoiron/sqlx v1.3.5 @@ -49,7 +50,7 @@ require ( github.com/spf13/viper v1.14.0 github.com/stretchr/testify v1.8.1 github.com/vrischmann/envconfig v1.3.0 - golang.org/x/tools v0.2.0 + golang.org/x/tools v0.6.0 gopkg.in/yaml.v2 v2.4.0 k8s.io/api v0.23.0 k8s.io/apiextensions-apiserver v0.23.0 @@ -130,12 +131,12 @@ require ( go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.8.0 // indirect golang.org/x/crypto v0.1.0 // indirect - golang.org/x/mod v0.6.0 // indirect - golang.org/x/net v0.1.0 // indirect + golang.org/x/mod v0.8.0 // indirect + golang.org/x/net v0.6.0 // indirect golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect - golang.org/x/sys v0.1.0 // indirect - golang.org/x/term v0.1.0 // indirect - golang.org/x/text v0.4.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/term v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.28.1 // indirect diff --git a/go.sum b/go.sum index e82ac5c77..538412f42 100644 --- a/go.sum +++ b/go.sum @@ -767,6 +767,9 @@ github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2c github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gookit/color v1.5.3 h1:twfIhZs4QLCtimkP7MOxlF3A0U/5cDPseRT9M/+2SCE= +github.com/gookit/goutil v0.6.8 h1:B2XXSCGav5TXWtKRT9i/s/owOLXXB7sY6UsfqeSLroE= +github.com/gookit/goutil v0.6.8/go.mod h1:u+Isykc6RQcZ4GQzulsaGm+Famd97U5Tzp3aQyo+jyA= github.com/goph/emperror v0.17.2/go.mod h1:+ZbQ+fUNO/6FNiUo0ujtMjhgad9Xa6fQL9KhH4LNHic= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gophercloud/gophercloud v0.10.0/go.mod h1:gmC5oQqMDOMO1t1gq5DquX/yAU808e/4mzjjDA76+Ss= @@ -1492,6 +1495,7 @@ github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHM github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= @@ -1667,8 +1671,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= -golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180112015858-5ccada7d0a7b/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1742,8 +1746,8 @@ golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1781,6 +1785,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180117170059-2c42eef0765b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1896,15 +1901,15 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1916,8 +1921,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2021,8 +2026,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM= -golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= -golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/internal/api/cluster.go b/internal/api/cluster.go index 044307c18..232fcef84 100644 --- a/internal/api/cluster.go +++ b/internal/api/cluster.go @@ -193,7 +193,7 @@ func handleRetryCreateCluster(c *Context, w http.ResponseWriter, r *http.Request // Notify even if we didn't make changes, to expedite even the no-op operations above. unlockOnce() - c.Supervisor.Do() + _ = c.Supervisor.Do() w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) @@ -249,7 +249,7 @@ func handleProvisionCluster(c *Context, w http.ResponseWriter, r *http.Request) // Notify even if we didn't make changes, to expedite even the no-op operations above. unlockOnce() - c.Supervisor.Do() + _ = c.Supervisor.Do() w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) @@ -350,7 +350,7 @@ func handleUpgradeKubernetes(c *Context, w http.ResponseWriter, r *http.Request) } unlockOnce() - c.Supervisor.Do() + _ = c.Supervisor.Do() w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) @@ -423,7 +423,7 @@ func handleResizeCluster(c *Context, w http.ResponseWriter, r *http.Request) { } unlockOnce() - c.Supervisor.Do() + _ = c.Supervisor.Do() w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) @@ -448,7 +448,7 @@ func handleCreateNodegroups(c *Context, w http.ResponseWriter, r *http.Request) clusterDTO, status, unlockOnce := getClusterForTransition(c, clusterID, newState) if status != 0 { - c.Logger.Debug("Cluster is not in a valid state for nodegroup creation") + c.Logger.Debug("Cluster is not in a valid state for nodegroups creation") w.WriteHeader(status) return } @@ -463,7 +463,7 @@ func handleCreateNodegroups(c *Context, w http.ResponseWriter, r *http.Request) if clusterDTO.Provisioner == model.ProvisionerEKS { err = clusterDTO.ProvisionerMetadataEKS.ValidateNodegroupsCreateRequest(createNodegroupsRequest.Nodegroups) if err != nil { - c.Logger.WithError(err).Error("failed to validate nodegroups create request") + c.Logger.WithError(err).Error("Failed to validate nodegroups creation request") w.WriteHeader(http.StatusBadRequest) return } @@ -524,7 +524,7 @@ func handleDeleteNodegroup(c *Context, w http.ResponseWriter, r *http.Request) { if clusterDTO.Provisioner == model.ProvisionerEKS { err := clusterDTO.ProvisionerMetadataEKS.ValidateNodegroupDeleteRequest(nodegroup) if err != nil { - c.Logger.WithError(err).Error("failed to validate nodegroup delete request") + c.Logger.WithError(err).Error("Failed to validate nodegroup deletion request") w.WriteHeader(http.StatusBadRequest) return } @@ -636,7 +636,7 @@ func handleDeleteCluster(c *Context, w http.ResponseWriter, r *http.Request) { } unlockOnce() - c.Supervisor.Do() + _ = c.Supervisor.Do() w.WriteHeader(http.StatusAccepted) } diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go index 871f0635d..9a39fbbd9 100644 --- a/internal/metrics/metrics.go +++ b/internal/metrics/metrics.go @@ -36,11 +36,13 @@ type CloudMetrics struct { ClusterInstallationDeletionDurationHist *prometheus.HistogramVec // Cluster - ClusterCreationDurationHist *prometheus.HistogramVec - ClusterUpgradeDurationHist *prometheus.HistogramVec - ClusterProvisioningDurationHist *prometheus.HistogramVec - ClusterResizeDurationHist *prometheus.HistogramVec - ClusterDeletionDurationHist *prometheus.HistogramVec + ClusterCreationDurationHist *prometheus.HistogramVec + ClusterUpgradeDurationHist *prometheus.HistogramVec + ClusterProvisioningDurationHist *prometheus.HistogramVec + ClusterResizeDurationHist *prometheus.HistogramVec + ClusterDeletionDurationHist *prometheus.HistogramVec + ClusterNodegroupsCreationDurationHist *prometheus.HistogramVec + ClusterNodegroupsDeletionDurationHist *prometheus.HistogramVec } // New creates a new Prometheus-based Metrics object to be used @@ -191,6 +193,26 @@ func New() *CloudMetrics { }, []string{}, ), + ClusterNodegroupsCreationDurationHist: promauto.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: provisionerNamespace, + Subsystem: provisionerSubsystemApp, + Name: "cluster_nodegroups_creation_duration_seconds", + Help: "The duration of cluster nodegroups creation tasks", + Buckets: standardDurationBuckets(), + }, + []string{}, + ), + ClusterNodegroupsDeletionDurationHist: promauto.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: provisionerNamespace, + Subsystem: provisionerSubsystemApp, + Name: "cluster_nodegroups_deletion_duration_seconds", + Help: "The duration of cluster nodegroups deletion tasks", + Buckets: standardDurationBuckets(), + }, + []string{}, + ), } } diff --git a/internal/mocks/aws-tools/client.go b/internal/mocks/aws-tools/client.go index cdd865ba2..175960e46 100644 --- a/internal/mocks/aws-tools/client.go +++ b/internal/mocks/aws-tools/client.go @@ -446,33 +446,33 @@ func (mr *MockAWSMockRecorder) EnsureEKSClusterUpdated(cluster interface{}) *gom return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnsureEKSClusterUpdated", reflect.TypeOf((*MockAWS)(nil).EnsureEKSClusterUpdated), cluster) } -// EnsureEKSNodeGroup mocks base method -func (m *MockAWS) EnsureEKSNodeGroup(cluster *model.Cluster, nodeGroupPrefix string) (*types.Nodegroup, error) { +// EnsureEKSNodegroup mocks base method +func (m *MockAWS) EnsureEKSNodegroup(cluster *model.Cluster, nodeGroupPrefix string) (*types.Nodegroup, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EnsureEKSNodeGroup", cluster, nodeGroupPrefix) + ret := m.ctrl.Call(m, "EnsureEKSNodegroup", cluster, nodeGroupPrefix) ret0, _ := ret[0].(*types.Nodegroup) ret1, _ := ret[1].(error) return ret0, ret1 } -// EnsureEKSNodeGroup indicates an expected call of EnsureEKSNodeGroup -func (mr *MockAWSMockRecorder) EnsureEKSNodeGroup(cluster, nodeGroupPrefix interface{}) *gomock.Call { +// EnsureEKSNodegroup indicates an expected call of EnsureEKSNodegroup +func (mr *MockAWSMockRecorder) EnsureEKSNodegroup(cluster, nodeGroupPrefix interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnsureEKSNodeGroup", reflect.TypeOf((*MockAWS)(nil).EnsureEKSNodeGroup), cluster, nodeGroupPrefix) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnsureEKSNodegroup", reflect.TypeOf((*MockAWS)(nil).EnsureEKSNodegroup), cluster, nodeGroupPrefix) } -// EnsureEKSNodeGroupMigrated mocks base method -func (m *MockAWS) EnsureEKSNodeGroupMigrated(cluster *model.Cluster, nodeGroupPrefix string) error { +// EnsureEKSNodegroupMigrated mocks base method +func (m *MockAWS) EnsureEKSNodegroupMigrated(cluster *model.Cluster, nodeGroupPrefix string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EnsureEKSNodeGroupMigrated", cluster, nodeGroupPrefix) + ret := m.ctrl.Call(m, "EnsureEKSNodegroupMigrated", cluster, nodeGroupPrefix) ret0, _ := ret[0].(error) return ret0 } -// EnsureEKSNodeGroupMigrated indicates an expected call of EnsureEKSNodeGroupMigrated -func (mr *MockAWSMockRecorder) EnsureEKSNodeGroupMigrated(cluster, nodeGroupPrefix interface{}) *gomock.Call { +// EnsureEKSNodegroupMigrated indicates an expected call of EnsureEKSNodegroupMigrated +func (mr *MockAWSMockRecorder) EnsureEKSNodegroupMigrated(cluster, nodeGroupPrefix interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnsureEKSNodeGroupMigrated", reflect.TypeOf((*MockAWS)(nil).EnsureEKSNodeGroupMigrated), cluster, nodeGroupPrefix) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnsureEKSNodegroupMigrated", reflect.TypeOf((*MockAWS)(nil).EnsureEKSNodegroupMigrated), cluster, nodeGroupPrefix) } // GetActiveEKSCluster mocks base method @@ -490,33 +490,33 @@ func (mr *MockAWSMockRecorder) GetActiveEKSCluster(clusterName interface{}) *gom return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActiveEKSCluster", reflect.TypeOf((*MockAWS)(nil).GetActiveEKSCluster), clusterName) } -// GetActiveEKSNodeGroup mocks base method -func (m *MockAWS) GetActiveEKSNodeGroup(clusterName, nodeGroupName string) (*types.Nodegroup, error) { +// GetActiveEKSNodegroup mocks base method +func (m *MockAWS) GetActiveEKSNodegroup(clusterName, nodeGroupName string) (*types.Nodegroup, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetActiveEKSNodeGroup", clusterName, nodeGroupName) + ret := m.ctrl.Call(m, "GetActiveEKSNodegroup", clusterName, nodeGroupName) ret0, _ := ret[0].(*types.Nodegroup) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetActiveEKSNodeGroup indicates an expected call of GetActiveEKSNodeGroup -func (mr *MockAWSMockRecorder) GetActiveEKSNodeGroup(clusterName, nodeGroupName interface{}) *gomock.Call { +// GetActiveEKSNodegroup indicates an expected call of GetActiveEKSNodegroup +func (mr *MockAWSMockRecorder) GetActiveEKSNodegroup(clusterName, nodeGroupName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActiveEKSNodeGroup", reflect.TypeOf((*MockAWS)(nil).GetActiveEKSNodeGroup), clusterName, nodeGroupName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActiveEKSNodegroup", reflect.TypeOf((*MockAWS)(nil).GetActiveEKSNodegroup), clusterName, nodeGroupName) } -// EnsureEKSNodeGroupDeleted mocks base method -func (m *MockAWS) EnsureEKSNodeGroupDeleted(clusterName, nodeGroupName string) error { +// EnsureEKSNodegroupDeleted mocks base method +func (m *MockAWS) EnsureEKSNodegroupDeleted(clusterName, nodeGroupName string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EnsureEKSNodeGroupDeleted", clusterName, nodeGroupName) + ret := m.ctrl.Call(m, "EnsureEKSNodegroupDeleted", clusterName, nodeGroupName) ret0, _ := ret[0].(error) return ret0 } -// EnsureEKSNodeGroupDeleted indicates an expected call of EnsureEKSNodeGroupDeleted -func (mr *MockAWSMockRecorder) EnsureEKSNodeGroupDeleted(clusterName, nodeGroupName interface{}) *gomock.Call { +// EnsureEKSNodegroupDeleted indicates an expected call of EnsureEKSNodegroupDeleted +func (mr *MockAWSMockRecorder) EnsureEKSNodegroupDeleted(clusterName, nodeGroupName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnsureEKSNodeGroupDeleted", reflect.TypeOf((*MockAWS)(nil).EnsureEKSNodeGroupDeleted), clusterName, nodeGroupName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnsureEKSNodegroupDeleted", reflect.TypeOf((*MockAWS)(nil).EnsureEKSNodegroupDeleted), clusterName, nodeGroupName) } // EnsureEKSClusterDeleted mocks base method @@ -562,33 +562,33 @@ func (mr *MockAWSMockRecorder) WaitForActiveEKSCluster(clusterName, timeout inte return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitForActiveEKSCluster", reflect.TypeOf((*MockAWS)(nil).WaitForActiveEKSCluster), clusterName, timeout) } -// WaitForActiveEKSNodeGroup mocks base method -func (m *MockAWS) WaitForActiveEKSNodeGroup(clusterName, nodeGroupName string, timeout int) (*types.Nodegroup, error) { +// WaitForActiveEKSNodegroup mocks base method +func (m *MockAWS) WaitForActiveEKSNodegroup(clusterName, nodeGroupName string, timeout int) (*types.Nodegroup, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "WaitForActiveEKSNodeGroup", clusterName, nodeGroupName, timeout) + ret := m.ctrl.Call(m, "WaitForActiveEKSNodegroup", clusterName, nodeGroupName, timeout) ret0, _ := ret[0].(*types.Nodegroup) ret1, _ := ret[1].(error) return ret0, ret1 } -// WaitForActiveEKSNodeGroup indicates an expected call of WaitForActiveEKSNodeGroup -func (mr *MockAWSMockRecorder) WaitForActiveEKSNodeGroup(clusterName, nodeGroupName, timeout interface{}) *gomock.Call { +// WaitForActiveEKSNodegroup indicates an expected call of WaitForActiveEKSNodegroup +func (mr *MockAWSMockRecorder) WaitForActiveEKSNodegroup(clusterName, nodeGroupName, timeout interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitForActiveEKSNodeGroup", reflect.TypeOf((*MockAWS)(nil).WaitForActiveEKSNodeGroup), clusterName, nodeGroupName, timeout) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitForActiveEKSNodegroup", reflect.TypeOf((*MockAWS)(nil).WaitForActiveEKSNodegroup), clusterName, nodeGroupName, timeout) } -// WaitForEKSNodeGroupToBeDeleted mocks base method -func (m *MockAWS) WaitForEKSNodeGroupToBeDeleted(clusterName, nodeGroupName string, timeout int) error { +// WaitForEKSNodegroupToBeDeleted mocks base method +func (m *MockAWS) WaitForEKSNodegroupToBeDeleted(clusterName, nodeGroupName string, timeout int) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "WaitForEKSNodeGroupToBeDeleted", clusterName, nodeGroupName, timeout) + ret := m.ctrl.Call(m, "WaitForEKSNodegroupToBeDeleted", clusterName, nodeGroupName, timeout) ret0, _ := ret[0].(error) return ret0 } -// WaitForEKSNodeGroupToBeDeleted indicates an expected call of WaitForEKSNodeGroupToBeDeleted -func (mr *MockAWSMockRecorder) WaitForEKSNodeGroupToBeDeleted(clusterName, nodeGroupName, timeout interface{}) *gomock.Call { +// WaitForEKSNodegroupToBeDeleted indicates an expected call of WaitForEKSNodegroupToBeDeleted +func (mr *MockAWSMockRecorder) WaitForEKSNodegroupToBeDeleted(clusterName, nodeGroupName, timeout interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitForEKSNodeGroupToBeDeleted", reflect.TypeOf((*MockAWS)(nil).WaitForEKSNodeGroupToBeDeleted), clusterName, nodeGroupName, timeout) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitForEKSNodegroupToBeDeleted", reflect.TypeOf((*MockAWS)(nil).WaitForEKSNodegroupToBeDeleted), clusterName, nodeGroupName, timeout) } // WaitForEKSClusterToBeDeleted mocks base method diff --git a/internal/provisioner/eks_provisioner.go b/internal/provisioner/eks_provisioner.go index f9f0a70ac..25c48bedf 100644 --- a/internal/provisioner/eks_provisioner.go +++ b/internal/provisioner/eks_provisioner.go @@ -66,7 +66,7 @@ func (provisioner *EKSProvisioner) PrepareCluster(cluster *model.Cluster) bool { } // Generate the EKS name using the cluster id. - cluster.ProvisionerMetadataEKS.Name = fmt.Sprintf("%s-eks-k8s-local", cluster.ID) + cluster.ProvisionerMetadataEKS.Name = fmt.Sprintf("%s-eks-k8s", cluster.ID) return true } @@ -77,22 +77,22 @@ func (provisioner *EKSProvisioner) CreateCluster(cluster *model.Cluster) error { eksMetadata := cluster.ProvisionerMetadataEKS if eksMetadata == nil { - return errors.New("EKS Metadata not set when creating EKS cluster") + return errors.New("metadata not found to create EKS cluster") } err := eksMetadata.ValidateChangeRequest() if err != nil { - return errors.Wrap(err, "EKS Metadata ChangeRequest failed validation") + return errors.Wrap(err, "failed to validate ChangeRequest for EKS cluster") } if eksMetadata.ChangeRequest.AMI != "" && eksMetadata.ChangeRequest.AMI != "latest" { var isAMIValid bool isAMIValid, err = provisioner.awsClient.IsValidAMI(eksMetadata.ChangeRequest.AMI, logger) if err != nil { - return errors.Wrapf(err, "error checking the AWS AMI image %s", eksMetadata.ChangeRequest.AMI) + return errors.Wrapf(err, "failed to validate AMI %s", eksMetadata.ChangeRequest.AMI) } if !isAMIValid { - return errors.Errorf("invalid AWS AMI image %s", eksMetadata.ChangeRequest.AMI) + return errors.Errorf("provided AMI %s is not valid", eksMetadata.ChangeRequest.AMI) } } @@ -102,12 +102,12 @@ func (provisioner *EKSProvisioner) CreateCluster(cluster *model.Cluster) error { if eksMetadata.ChangeRequest.VPC != "" && provisioner.params.UseExistingAWSResources { clusterResources, err = provisioner.awsClient.ClaimVPC(eksMetadata.ChangeRequest.VPC, cluster, provisioner.params.Owner, logger) if err != nil { - return errors.Wrap(err, "couldn't claim VPC") + return errors.Wrap(err, "failed to claim VPC") } } else if provisioner.params.UseExistingAWSResources { clusterResources, err = provisioner.awsClient.GetAndClaimVpcResources(cluster, provisioner.params.Owner, logger) if err != nil { - return err + return errors.Wrap(err, "failed to get and claim VPC resources") } } @@ -118,19 +118,19 @@ func (provisioner *EKSProvisioner) CreateCluster(cluster *model.Cluster) error { if err != nil { releaseErr := provisioner.awsClient.ReleaseVpc(cluster, logger) if releaseErr != nil { - logger.WithError(releaseErr).Error("Unable to release VPC") + logger.WithError(releaseErr).Error("Failed to release VPC") } - return errors.Wrap(err, "unable to create EKS cluster") + return errors.Wrap(err, "failed to ensure EKS cluster") } err = provisioner.clusterUpdateStore.UpdateCluster(cluster) if err != nil { releaseErr := provisioner.awsClient.ReleaseVpc(cluster, logger) if releaseErr != nil { - logger.WithError(releaseErr).Error("Failed to release VPC after failed update") + logger.WithError(releaseErr).Error("Failed to release VPC") } - return errors.Wrap(err, "failed to update EKS metadata with VPC ID") + return errors.Wrap(err, "failed to update cluster metadata after creating EKS cluster") } return nil @@ -141,7 +141,7 @@ func (provisioner *EKSProvisioner) CheckClusterCreated(cluster *model.Cluster) ( logger := provisioner.logger.WithField("cluster", cluster.ID) if cluster.ProvisionerMetadataEKS == nil { - return false, errors.New("expected EKS metadata not to be nil") + return false, errors.New("metadata not found to check EKS cluster") } eksMetadata := cluster.ProvisionerMetadataEKS @@ -164,36 +164,38 @@ func (provisioner *EKSProvisioner) CheckClusterCreated(cluster *model.Cluster) ( err = provisioner.clusterUpdateStore.UpdateCluster(cluster) if err != nil { - return false, errors.Wrap(err, "failed to store cluster") + return false, errors.Wrap(err, "failed to save updated cluster metadata") } return true, nil } -func (provisioner *EKSProvisioner) prepareLaunchTemplate(cluster *model.Cluster, ngPrefix string, withSG bool, logger log.FieldLogger) error { +func (provisioner *EKSProvisioner) prepareLaunchTemplate(cluster *model.Cluster, ngPrefix string, ngMetadata model.NodeGroupMetadata, logger log.FieldLogger) error { eksMetadata := cluster.ProvisionerMetadataEKS changeRequest := eksMetadata.ChangeRequest var err error var securityGroups []string - if withSG { + if ngMetadata.WithSecurityGroup { vpc := changeRequest.VPC if vpc == "" { vpc = eksMetadata.VPC } securityGroups, err = provisioner.awsClient.ClaimSecurityGroups(cluster, ngPrefix, vpc, logger) if err != nil { - return errors.Wrap(err, "failed to get security groups") + return errors.Wrap(err, "failed to claim security groups") } } launchTemplateData := &model.LaunchTemplateData{ - Name: fmt.Sprintf("%s-%s", eksMetadata.Name, ngPrefix), - ClusterName: eksMetadata.Name, - SecurityGroups: securityGroups, - AMI: changeRequest.AMI, - MaxPodsPerNode: changeRequest.MaxPodsPerNode, + Name: fmt.Sprintf("%s-%s", eksMetadata.Name, ngPrefix), + ClusterName: eksMetadata.Name, + SecurityGroups: securityGroups, + AMI: changeRequest.AMI, + MaxPodsPerNode: changeRequest.MaxPodsPerNode, + InstanceType: ngMetadata.InstanceType, + WithPublicSubnet: ngMetadata.WithPublicSubnet, } if launchTemplateData.AMI == "" { @@ -206,7 +208,7 @@ func (provisioner *EKSProvisioner) prepareLaunchTemplate(cluster *model.Cluster, launchTemplateName := fmt.Sprintf("%s-%s", eksMetadata.Name, ngPrefix) isAvailable, err := provisioner.awsClient.IsLaunchTemplateAvailable(launchTemplateName) if err != nil { - return errors.Wrap(err, "failed to check launch template availability") + return errors.Wrap(err, "failed to check if launch template is available") } if isAvailable { @@ -230,7 +232,7 @@ func (provisioner *EKSProvisioner) CreateNodegroups(cluster *model.Cluster) erro eksMetadata := cluster.ProvisionerMetadataEKS if eksMetadata == nil { - return errors.New("EKS Metadata not set when creating EKS NodeGroup") + return errors.New("metadata not found to create EKS nodegroups") } eksMetadata = provisioner.setMissingChangeRequest(eksMetadata) @@ -244,18 +246,22 @@ func (provisioner *EKSProvisioner) CreateNodegroups(cluster *model.Cluster) erro wg.Add(1) go func(ngPrefix string, ngMetadata model.NodeGroupMetadata) { defer wg.Done() - logger.Debugf("Creating EKS NodeGroup %s", ngMetadata.Name) + logger.Debugf("Creating EKS nodegroup %s", ngMetadata.Name) - err := provisioner.prepareLaunchTemplate(cluster, ngPrefix, ngMetadata.WithSecurityGroup, logger) + oldMetadata := eksMetadata.NodeGroups[ngPrefix] + ngMetadata.CopyMissingFieldsFrom(oldMetadata) + changeRequest.NodeGroups[ngPrefix] = ngMetadata + + err := provisioner.prepareLaunchTemplate(cluster, ngPrefix, ngMetadata, logger) if err != nil { - logger.WithError(err).Error("failed to ensure launch template") + logger.WithError(err).Error("Failed to prepare launch template") errOccurred = true return } - _, err = provisioner.awsClient.EnsureEKSNodeGroup(cluster, ngPrefix) + _, err = provisioner.awsClient.EnsureEKSNodegroup(cluster, ngPrefix) if err != nil { - logger.WithError(err).Errorf("failed to create EKS NodeGroup %s", ngMetadata.Name) + logger.WithError(err).Errorf("Failed to create EKS nodegroup %s", ngMetadata.Name) errOccurred = true return } @@ -265,12 +271,12 @@ func (provisioner *EKSProvisioner) CreateNodegroups(cluster *model.Cluster) erro wg.Wait() if errOccurred { - return errors.New("failed to create one of the EKS NodeGroups") + return errors.New("failed to create one of the EKS nodegroups") } err := provisioner.clusterUpdateStore.UpdateCluster(cluster) if err != nil { - return errors.Wrap(err, "failed to store cluster") + return errors.Wrap(err, "failed to update cluster metadata after creating nodegroups") } return nil @@ -296,11 +302,11 @@ func (provisioner *EKSProvisioner) CheckNodegroupsCreated(cluster *model.Cluster defer wg.Done() wait := 300 - logger.Infof("Waiting up to %d seconds for EKS NodeGroup %s to become active...", wait, ngMetadata.Name) + logger.Infof("Waiting up to %d seconds for EKS nodegroup %s to become active...", wait, ngMetadata.Name) - nodeGroup, err := provisioner.awsClient.WaitForActiveEKSNodeGroup(eksMetadata.Name, ngMetadata.Name, wait) + nodeGroup, err := provisioner.awsClient.WaitForActiveEKSNodegroup(eksMetadata.Name, ngMetadata.Name, wait) if err != nil { - logger.WithError(err).Errorf("failed to wait for EKS NodeGroup %s to become active", ngMetadata.Name) + logger.WithError(err).Errorf("Failed to wait for EKS nodegroup %s to become active", ngMetadata.Name) errOccurred = true return } @@ -308,7 +314,7 @@ func (provisioner *EKSProvisioner) CheckNodegroupsCreated(cluster *model.Cluster eksMetadata.NodeGroups[ngPrefix] = model.NodeGroupMetadata{ Name: ngMetadata.Name, Type: ngMetadata.Type, - InstanceType: nodeGroup.InstanceTypes[0], + InstanceType: ngMetadata.InstanceType, MinCount: int64(ptr.ToInt32(nodeGroup.ScalingConfig.MinSize)), MaxCount: int64(ptr.ToInt32(nodeGroup.ScalingConfig.MaxSize)), WithPublicSubnet: ngMetadata.WithPublicSubnet, @@ -319,15 +325,15 @@ func (provisioner *EKSProvisioner) CheckNodegroupsCreated(cluster *model.Cluster wg.Wait() - logger.Debugf("All EKS NodeGroups are active") + logger.Debugf("All EKS nodegroups are active") if errOccurred { - return false, errors.New("one of the EKS NodeGroups failed to become active") + return false, errors.New("one of the EKS nodegroups failed to become active") } err := provisioner.awsClient.InstallEKSAddons(cluster) if err != nil { - return false, errors.Wrap(err, "failed to install EKS EBS Addon") + return false, errors.Wrap(err, "failed to install an EKS addon") } eksMetadata.NodeRoleARN = changeRequest.NodeRoleARN @@ -337,24 +343,24 @@ func (provisioner *EKSProvisioner) CheckNodegroupsCreated(cluster *model.Cluster err = provisioner.clusterUpdateStore.UpdateCluster(cluster) if err != nil { - return false, errors.Wrap(err, "failed to store cluster") + return false, errors.Wrap(err, "failed to save updated cluster metadata") } return true, nil } -// DeleteNodegroups deletes the EKS nodegroup. +// DeleteNodegroups deletes the EKS nodegroups. func (provisioner *EKSProvisioner) DeleteNodegroups(cluster *model.Cluster) error { logger := provisioner.logger.WithField("cluster", cluster.ID) eksMetadata := cluster.ProvisionerMetadataEKS if eksMetadata == nil { - return errors.New("EKS Metadata not set when deleting EKS NodeGroup") + return errors.New("metadata not found to delete EKS nodegroups") } changeRequest := eksMetadata.ChangeRequest if changeRequest == nil || changeRequest.NodeGroups == nil { - return errors.New("nodegroup change request not set when deleting EKS NodeGroup") + return errors.New("metadata ChangeRequest not found to delete EKS nodegroups") } nodeGroups := changeRequest.NodeGroups @@ -367,18 +373,18 @@ func (provisioner *EKSProvisioner) DeleteNodegroups(cluster *model.Cluster) erro go func(ngPrefix string, ngMetadata model.NodeGroupMetadata) { defer wg.Done() - err := provisioner.awsClient.EnsureEKSNodeGroupDeleted(eksMetadata.Name, ngMetadata.Name) + err := provisioner.awsClient.EnsureEKSNodegroupDeleted(eksMetadata.Name, ngMetadata.Name) if err != nil { - logger.WithError(err).Errorf("failed to delete EKS NodeGroup %s", ngMetadata.Name) + logger.WithError(err).Errorf("Failed to delete EKS nodedroup %s", ngMetadata.Name) errOccurred = true return } wait := 600 - logger.Infof("Waiting up to %d seconds for NodeGroup %s to be deleted...", wait, ngMetadata.Name) - err = provisioner.awsClient.WaitForEKSNodeGroupToBeDeleted(eksMetadata.Name, ngMetadata.Name, wait) + logger.Infof("Waiting up to %d seconds for EKS nodegroup %s to be deleted...", wait, ngMetadata.Name) + err = provisioner.awsClient.WaitForEKSNodegroupToBeDeleted(eksMetadata.Name, ngMetadata.Name, wait) if err != nil { - logger.WithError(err).Errorf("failed to delete EKS NodeGroup %s", ngMetadata.Name) + logger.WithError(err).Errorf("Failed to delete EKS nodegroup %s", ngMetadata.Name) errOccurred = true return } @@ -386,19 +392,19 @@ func (provisioner *EKSProvisioner) DeleteNodegroups(cluster *model.Cluster) erro launchTemplateName := fmt.Sprintf("%s-%s", eksMetadata.Name, ngPrefix) err = provisioner.awsClient.DeleteLaunchTemplate(launchTemplateName) if err != nil { - logger.WithError(err).Errorf("failed to delete EKS LaunchTemplate %s", launchTemplateName) + logger.WithError(err).Errorf("Failed to delete launch template %s", launchTemplateName) errOccurred = true return } - logger.Debugf("Successfully deleted EKS NodeGroup %s", ngMetadata.Name) + logger.Debugf("Successfully deleted EKS nodegroup %s", ngMetadata.Name) }(ng, meta) } wg.Wait() if errOccurred { - return errors.New("failed to delete one of the nodegroups") + return errors.New("failed to delete one of the EKS nodegroups") } for ng := range nodeGroups { @@ -414,7 +420,7 @@ func (provisioner *EKSProvisioner) ProvisionCluster(cluster *model.Cluster) erro eksMetadata := cluster.ProvisionerMetadataEKS if eksMetadata == nil { - return errors.New("expected EKS metadata not to be nil when using EKS Provisioner") + return errors.New("metadata not found to provision EKS cluster") } kubeConfigPath, err := provisioner.getKubeConfigPath(cluster) @@ -434,17 +440,17 @@ func (provisioner *EKSProvisioner) UpgradeCluster(cluster *model.Cluster) error err := eksMetadata.ValidateChangeRequest() if err != nil { - return errors.Wrap(err, "eks Metadata ChangeRequest failed validation") + return errors.Wrap(err, "failed to validate ChangeRequest for EKS cluster") } if changeRequest.AMI != "" && changeRequest.AMI != "latest" { var isAMIValid bool isAMIValid, err = provisioner.awsClient.IsValidAMI(eksMetadata.ChangeRequest.AMI, logger) if err != nil { - return errors.Wrapf(err, "error checking the AWS ami image %s", eksMetadata.ChangeRequest.AMI) + return errors.Wrapf(err, "failed to validate AMI %s", eksMetadata.ChangeRequest.AMI) } if !isAMIValid { - return errors.Errorf("invalid AWS ami image %s", eksMetadata.ChangeRequest.AMI) + return errors.Errorf("provided AMI %s is not valid", eksMetadata.ChangeRequest.AMI) } } @@ -457,22 +463,22 @@ func (provisioner *EKSProvisioner) UpgradeCluster(cluster *model.Cluster) error wg.Add(1) go func(ngPrefix string, ngMetadata model.NodeGroupMetadata) { defer wg.Done() - logger.Debugf("Migrating EKS NodeGroup for %s", ngPrefix) + logger.Debugf("Migrating EKS nodegroup for %s", ngPrefix) oldMetadata := eksMetadata.NodeGroups[ngPrefix] ngMetadata.CopyMissingFieldsFrom(oldMetadata) changeRequest.NodeGroups[ngPrefix] = ngMetadata - err = provisioner.prepareLaunchTemplate(cluster, ngPrefix, ngMetadata.WithSecurityGroup, logger) + err = provisioner.prepareLaunchTemplate(cluster, ngPrefix, ngMetadata, logger) if err != nil { - logger.WithError(err).Error("failed to ensure launch template") + logger.WithError(err).Error("Failed to prepare launch template") errOccurred = true return } - err = provisioner.awsClient.EnsureEKSNodeGroupMigrated(cluster, ngPrefix) + err = provisioner.awsClient.EnsureEKSNodegroupMigrated(cluster, ngPrefix) if err != nil { - logger.WithError(err).Errorf("failed to migrate EKS NodeGroup for %s", ngPrefix) + logger.WithError(err).Errorf("Failed to migrate EKS nodegroup for %s", ngPrefix) errOccurred = true return } @@ -480,14 +486,14 @@ func (provisioner *EKSProvisioner) UpgradeCluster(cluster *model.Cluster) error oldMetadata.Name = ngMetadata.Name eksMetadata.NodeGroups[ngPrefix] = oldMetadata - logger.Debugf("Successfully migrated EKS NodeGroup for %s", ngPrefix) + logger.Debugf("Successfully migrated EKS nodegroup for %s", ngPrefix) }(ng, meta) } wg.Wait() if errOccurred { - return errors.New("failed to migrate one of the EKS NodeGroups") + return errors.New("failed to migrate one of the EKS nodegroups") } if changeRequest.AMI != "" { @@ -499,7 +505,7 @@ func (provisioner *EKSProvisioner) UpgradeCluster(cluster *model.Cluster) error err = provisioner.clusterUpdateStore.UpdateCluster(cluster) if err != nil { - return errors.Wrap(err, "failed to store cluster") + return errors.Wrap(err, "failed to update cluster metadata") } } @@ -522,7 +528,7 @@ func (provisioner *EKSProvisioner) UpgradeCluster(cluster *model.Cluster) error err = provisioner.clusterUpdateStore.UpdateCluster(cluster) if err != nil { - return errors.Wrap(err, "failed to store cluster") + return errors.Wrap(err, "failed to update cluster metadata") } } @@ -534,40 +540,6 @@ func (provisioner *EKSProvisioner) RotateClusterNodes(cluster *model.Cluster) er return nil } -func (provisioner *EKSProvisioner) isMigrationRequired(oldNodeGroup *eksTypes.Nodegroup, eksMetadata *model.EKSMetadata, ngPrefix string, logger log.FieldLogger) bool { - changeRequest := eksMetadata.ChangeRequest - - if oldNodeGroup == nil { - logger.Debug("Old EKS NodeGroup is nil") - return false - } - - ngChangeRequest, found := changeRequest.NodeGroups[ngPrefix] - if !found { - logger.Debugf("NodeGroup %s not found in ChangeRequest", ngPrefix) - return false - } - - if changeRequest.MaxPodsPerNode > 0 || changeRequest.AMI != "" { - return true - } - - if oldNodeGroup.InstanceTypes != nil && len(oldNodeGroup.InstanceTypes) > 0 && - oldNodeGroup.InstanceTypes[0] != ngChangeRequest.InstanceType { - return true - } - - scalingInfo := oldNodeGroup.ScalingConfig - if *scalingInfo.MinSize != int32(ngChangeRequest.MinCount) { - return true - } - if *scalingInfo.MaxSize != int32(ngChangeRequest.MaxCount) { - return true - } - - return false -} - // ResizeCluster resizes cluster - not implemented. func (provisioner *EKSProvisioner) ResizeCluster(cluster *model.Cluster) error { logger := provisioner.logger.WithField("cluster", cluster.ID) @@ -577,7 +549,7 @@ func (provisioner *EKSProvisioner) ResizeCluster(cluster *model.Cluster) error { err := eksMetadata.ValidateChangeRequest() if err != nil { - return errors.Wrap(err, "eks Metadata ChangeRequest failed validation") + return errors.Wrap(err, "failed to validate ChangeRequest for EKS cluster") } var wg sync.WaitGroup @@ -587,69 +559,78 @@ func (provisioner *EKSProvisioner) ResizeCluster(cluster *model.Cluster) error { wg.Add(1) go func(ngPrefix string, ngMetadata model.NodeGroupMetadata) { defer wg.Done() - logger.Debugf("Migrating EKS NodeGroup for %s", ngPrefix) + logger.Debugf("Migrating EKS nodegroup for %s", ngPrefix) oldMetadata := eksMetadata.NodeGroups[ngPrefix] ngMetadata.CopyMissingFieldsFrom(oldMetadata) changeRequest.NodeGroups[ngPrefix] = ngMetadata - oldEKSNodeGroup, err2 := provisioner.awsClient.GetActiveEKSNodeGroup(eksMetadata.Name, oldMetadata.Name) + oldEKSNodeGroup, err2 := provisioner.awsClient.GetActiveEKSNodegroup(eksMetadata.Name, oldMetadata.Name) if err2 != nil { - logger.WithError(err2).Errorf("failed to get EKS NodeGroup for %s", ngPrefix) + logger.WithError(err2).Errorf("Failed to get the existing EKS nodegroup for %s", ngPrefix) errOccurred = true return } if oldEKSNodeGroup == nil || oldEKSNodeGroup.Status != eksTypes.NodegroupStatusActive { - logger.Debugf("No active EKS NodeGroup found for %s", ngPrefix) + logger.Debugf("No active EKS nodegroup found for %s", ngPrefix) + return + } + + if oldMetadata.InstanceType == ngMetadata.InstanceType && + oldMetadata.MinCount == ngMetadata.MinCount && + oldMetadata.MaxCount == ngMetadata.MaxCount { + logger.Debugf("No change in EKS nodegroup for %s", ngPrefix) return } - if !provisioner.isMigrationRequired(oldEKSNodeGroup, eksMetadata, ngPrefix, logger) { - logger.Debugf("EKS NodeGroup migration not required for %s", ngPrefix) + err = provisioner.prepareLaunchTemplate(cluster, ngPrefix, ngMetadata, logger) + if err != nil { + logger.WithError(err).Error("Failed to prepare launch template") + errOccurred = true return } - err = provisioner.awsClient.EnsureEKSNodeGroupMigrated(cluster, ngPrefix) + err = provisioner.awsClient.EnsureEKSNodegroupMigrated(cluster, ngPrefix) if err != nil { - logger.WithError(err).Errorf("failed to migrate EKS NodeGroup for %s", ngPrefix) + logger.WithError(err).Errorf("Failed to migrate EKS nodegroup for %s", ngPrefix) errOccurred = true return } - nodeGroup, err2 := provisioner.awsClient.GetActiveEKSNodeGroup(eksMetadata.Name, ngMetadata.Name) + nodeGroup, err2 := provisioner.awsClient.GetActiveEKSNodegroup(eksMetadata.Name, ngMetadata.Name) if err2 != nil { - logger.WithError(err2).Errorf("failed to get EKS NodeGroup %s", ngMetadata.Name) + logger.WithError(err2).Errorf("Failed to get EKS nodegroup %s", ngMetadata.Name) errOccurred = true return } if nodeGroup == nil { - logger.WithError(err2).Errorf("EKS NodeGroup %s not found", ngMetadata.Name) + logger.WithError(err2).Errorf("EKS nodegroup %s not found", ngMetadata.Name) errOccurred = true return } oldNodeGroup := eksMetadata.NodeGroups[ngPrefix] oldNodeGroup.Name = ngMetadata.Name - oldNodeGroup.InstanceType = nodeGroup.InstanceTypes[0] + oldNodeGroup.InstanceType = ngMetadata.InstanceType oldNodeGroup.MinCount = int64(ptr.ToInt32(nodeGroup.ScalingConfig.MinSize)) oldNodeGroup.MaxCount = int64(ptr.ToInt32(nodeGroup.ScalingConfig.MaxSize)) eksMetadata.NodeGroups[ngPrefix] = oldNodeGroup - logger.Debugf("Successfully migrated EKS NodeGroup for %s", ngPrefix) + logger.Debugf("Successfully migrated EKS nodegroup for %s", ngPrefix) }(ng, meta) } wg.Wait() if errOccurred { - return errors.New("failed to migrate one of the nodegroups") + return errors.New("failed to migrate one of the EKS nodegroups") } err = provisioner.clusterUpdateStore.UpdateCluster(cluster) if err != nil { - return errors.Wrap(err, "failed to store cluster") + return errors.Wrap(err, "failed to update cluster metadata") } return nil @@ -691,18 +672,18 @@ func (provisioner *EKSProvisioner) cleanupCluster(cluster *model.Cluster) error go func(ngPrefix string, ngMetadata model.NodeGroupMetadata) { defer wg.Done() - err = provisioner.awsClient.EnsureEKSNodeGroupDeleted(eksMetadata.Name, ngMetadata.Name) + err = provisioner.awsClient.EnsureEKSNodegroupDeleted(eksMetadata.Name, ngMetadata.Name) if err != nil { - logger.WithError(err).Errorf("failed to delete EKS NodeGroup %s", ngMetadata.Name) + logger.WithError(err).Errorf("Failed to delete EKS nodegroup %s", ngMetadata.Name) errOccurred = true return } wait := 600 - logger.Infof("Waiting up to %d seconds for NodeGroup %s to be deleted...", wait, ngMetadata.Name) - err = provisioner.awsClient.WaitForEKSNodeGroupToBeDeleted(eksMetadata.Name, ngMetadata.Name, wait) + logger.Infof("Waiting up to %d seconds for nodegroup %s to be deleted...", wait, ngMetadata.Name) + err = provisioner.awsClient.WaitForEKSNodegroupToBeDeleted(eksMetadata.Name, ngMetadata.Name, wait) if err != nil { - logger.WithError(err).Errorf("failed to delete EKS NodeGroup %s", ngMetadata.Name) + logger.WithError(err).Errorf("Failed to delete EKS nodegroup %s", ngMetadata.Name) errOccurred = true return } @@ -710,19 +691,19 @@ func (provisioner *EKSProvisioner) cleanupCluster(cluster *model.Cluster) error launchTemplateName := fmt.Sprintf("%s-%s", eksMetadata.Name, ngPrefix) err = provisioner.awsClient.DeleteLaunchTemplate(launchTemplateName) if err != nil { - logger.WithError(err).Errorf("failed to delete EKS LaunchTemplate %s", launchTemplateName) + logger.WithError(err).Errorf("Failed to delete launch template %s", launchTemplateName) errOccurred = true return } - logger.Debugf("Successfully deleted EKS NodeGroup %s", ngMetadata.Name) + logger.Debugf("Successfully deleted EKS nodegroup %s", ngMetadata.Name) }(ng, meta) } wg.Wait() if errOccurred { - return errors.New("failed to delete one of the nodegroups") + return errors.New("failed to delete one of the EKS nodegroups") } err = provisioner.awsClient.EnsureEKSClusterDeleted(eksMetadata.Name) @@ -767,11 +748,11 @@ func (provisioner *EKSProvisioner) setMissingChangeRequest(eksMetadata *model.EK func (provisioner *EKSProvisioner) DeleteCluster(cluster *model.Cluster) (bool, error) { logger := provisioner.logger.WithField("cluster", cluster.ID) - logger.Info("Deleting cluster") + logger.Info("Deleting EKS cluster") eksMetadata := cluster.ProvisionerMetadataEKS if eksMetadata == nil { - return false, errors.New("expected EKS metadata not to be nil when using EKS Provisioner") + return false, errors.New("metadata not found to delete EKS cluster") } eksCluster, err := provisioner.awsClient.GetActiveEKSCluster(eksMetadata.Name) @@ -814,7 +795,7 @@ func (provisioner *EKSProvisioner) getKubeConfigPath(cluster *model.Cluster) (st return "", errors.Wrap(err, "failed to get EKS cluster") } if eksCluster == nil { - return "", errors.New("EKS cluster not ready") + return "", errors.Errorf("No active EKS cluster found with name %s", clusterName) } kubeconfig, err := newEKSKubeConfig(eksCluster, provisioner.awsClient) @@ -824,7 +805,7 @@ func (provisioner *EKSProvisioner) getKubeConfigPath(cluster *model.Cluster) (st kubeconfigFile, err := os.CreateTemp("", clusterName) if err != nil { - return "", errors.Wrap(err, "failed to create kubeconfig tempfile") + return "", errors.Wrap(err, "failed to create temp file for kubeconfig") } defer kubeconfigFile.Close() @@ -843,7 +824,7 @@ func (provisioner *EKSProvisioner) getKubeConfigPath(cluster *model.Cluster) (st func (provisioner *EKSProvisioner) getKubeClient(cluster *model.Cluster) (*k8s.KubeClient, error) { configLocation, err := provisioner.getKubeConfigPath(cluster) if err != nil { - return nil, errors.Wrap(err, "failed to get kube config") + return nil, errors.Wrap(err, "failed to get kubeconfig") } var k8sClient *k8s.KubeClient diff --git a/internal/supervisor/cluster.go b/internal/supervisor/cluster.go index 6ac370f3b..f7dd8f547 100644 --- a/internal/supervisor/cluster.go +++ b/internal/supervisor/cluster.go @@ -130,7 +130,7 @@ func (s *ClusterSupervisor) Supervise(cluster *model.Cluster) { cluster, err = s.store.GetCluster(cluster.ID) if err != nil { - logger.WithError(err).Warnf("failed to get cluster and thus persist state %s", newState) + logger.WithError(err).Warnf("Failed to get cluster and thus persist state %s", newState) return } @@ -142,7 +142,7 @@ func (s *ClusterSupervisor) Supervise(cluster *model.Cluster) { cluster.State = newState err = s.store.UpdateCluster(cluster) if err != nil { - logger.WithError(err).Warnf("failed to set cluster state to %s", newState) + logger.WithError(err).Warnf("Failed to set cluster state to %s", newState) return } @@ -226,10 +226,10 @@ func (s *ClusterSupervisor) upgradeCluster(cluster *model.Cluster, logger log.Fi err := s.provisioner.GetClusterProvisioner(cluster.Provisioner).UpgradeCluster(cluster) if err != nil { logger.WithError(err).Error("Failed to upgrade cluster") - logger.Info("Updating cluster store with latest cluster data") + logger.Info("Updating cluster metadata to reflect upgrade failure") err = s.store.UpdateCluster(cluster) if err != nil { - logger.WithError(err).Error("Failed to save updated cluster metadata") + logger.WithError(err).Error("Failed to update cluster metadata to reflect upgrade failure") return model.ClusterStateRefreshMetadata } return model.ClusterStateUpgradeFailed @@ -259,7 +259,7 @@ func (s *ClusterSupervisor) createNodegroups(cluster *model.Cluster, logger log. _, err = s.provisioner.GetClusterProvisioner(cluster.Provisioner).CheckNodegroupsCreated(cluster) if err != nil { - logger.WithError(err).Error("Failed to create nodegroups") + logger.WithError(err).Error("Failed to check if nodegroups are created") return model.ClusterStateNodegroupsCreationFailed } @@ -274,7 +274,7 @@ func (s *ClusterSupervisor) deleteNodegroups(cluster *model.Cluster, logger log. return model.ClusterStateNodegroupsDeletionFailed } - logger.Info("Finished deleting nodegroup") + logger.Info("Finished deleting nodegroups") return s.refreshClusterMetadata(cluster, logger) } @@ -282,13 +282,13 @@ func (s *ClusterSupervisor) refreshClusterMetadata(cluster *model.Cluster, logge err := s.provisioner.GetClusterProvisioner(cluster.Provisioner).RefreshClusterMetadata(cluster) if err != nil { - logger.WithError(err).Error("Failed to refresh cluster") + logger.WithError(err).Error("Failed to refresh cluster metadata") return model.ClusterStateRefreshMetadata } err = s.store.UpdateCluster(cluster) if err != nil { - logger.WithError(err).Error("Failed to save updated cluster metadata") + logger.WithError(err).Error("Failed to update cluster metadata") return model.ClusterStateRefreshMetadata } @@ -308,7 +308,7 @@ func (s *ClusterSupervisor) deleteCluster(cluster *model.Cluster, logger log.Fie err = s.store.DeleteCluster(cluster.ID) if err != nil { - logger.WithError(err).Error("Failed to record updated cluster after deletion") + logger.WithError(err).Error("Failed to delete cluster from store") return model.ClusterStateDeletionFailed } @@ -329,7 +329,7 @@ func (s *ClusterSupervisor) checkClusterCreated(cluster *model.Cluster, logger l err = s.provisioner.GetClusterProvisioner(cluster.Provisioner).CreateNodegroups(cluster) if err != nil { - logger.WithError(err).Error("Failed to create cluster nodes") + logger.WithError(err).Error("Failed to create cluster nodegroups") return model.ClusterStateCreationFailed } @@ -340,11 +340,11 @@ func (s *ClusterSupervisor) checkNodesCreated(cluster *model.Cluster, logger log ready, err := s.provisioner.GetClusterProvisioner(cluster.Provisioner).CheckNodegroupsCreated(cluster) if err != nil { - logger.WithError(err).Error("Failed to check if node creation finished") + logger.WithError(err).Error("Failed to check if nodegroups are created") return model.ClusterStateCreationFailed } if !ready { - logger.Debug("Cluster nodes are not ready yet") + logger.Debug("Cluster nodegroups not yet ready") return model.ClusterStateWaitingForNodes } @@ -390,6 +390,12 @@ func (s *ClusterSupervisor) processClusterMetrics(cluster *model.Cluster, logger case model.ClusterStateDeletionRequested: s.metrics.ClusterDeletionDurationHist.WithLabelValues().Observe(elapsedSeconds) logger.Debugf("Cluster was deleted in %d seconds", int(elapsedSeconds)) + case model.ClusterStateNodegroupsCreationRequested: + s.metrics.ClusterNodegroupsCreationDurationHist.WithLabelValues().Observe(elapsedSeconds) + logger.Debugf("Cluster nodegroups were created in %d seconds", int(elapsedSeconds)) + case model.ClusterStateNodegroupsDeletionRequested: + s.metrics.ClusterNodegroupsDeletionDurationHist.WithLabelValues().Observe(elapsedSeconds) + logger.Debugf("Cluster nodegroups were deleted in %d seconds", int(elapsedSeconds)) default: return errors.Errorf("failed to handle event %s with new state %s", event.Event.ID, event.StateChange.NewState) } diff --git a/internal/supervisor/installation_test.go b/internal/supervisor/installation_test.go index 3d6baac0c..8e50d8359 100644 --- a/internal/supervisor/installation_test.go +++ b/internal/supervisor/installation_test.go @@ -425,7 +425,7 @@ func (a *mockAWS) WaitForEKSClusterUpdateToBeCompleted(clusterName, updateID str return nil } -func (a *mockAWS) WaitForActiveEKSNodeGroup(clusterName, workerName string, timeout int) (*eksTypes.Nodegroup, error) { +func (a *mockAWS) WaitForActiveEKSNodegroup(clusterName, workerName string, timeout int) (*eksTypes.Nodegroup, error) { return nil, nil } @@ -433,7 +433,7 @@ func (a *mockAWS) WaitForEKSClusterToBeDeleted(clusterName string, timeout int) return nil } -func (a *mockAWS) WaitForEKSNodeGroupToBeDeleted(clusterName, workerName string, timeout int) error { +func (a *mockAWS) WaitForEKSNodegroupToBeDeleted(clusterName, workerName string, timeout int) error { return nil } @@ -441,15 +441,15 @@ func (a *mockAWS) EnsureEKSClusterUpdated(cluster *model.Cluster) (*eksTypes.Upd return nil, nil } -func (a *mockAWS) EnsureEKSNodeGroupMigrated(cluster *model.Cluster, ngPrefix string) error { +func (a *mockAWS) EnsureEKSNodegroupMigrated(cluster *model.Cluster, ngPrefix string) error { return nil } -func (a *mockAWS) GetActiveEKSNodeGroup(clusterName, workerName string) (*eksTypes.Nodegroup, error) { +func (a *mockAWS) GetActiveEKSNodegroup(clusterName, workerName string) (*eksTypes.Nodegroup, error) { return nil, nil } -func (a *mockAWS) EnsureEKSNodeGroupDeleted(clusterName, workerName string) error { +func (a *mockAWS) EnsureEKSNodegroupDeleted(clusterName, workerName string) error { return nil } @@ -506,7 +506,7 @@ func (a *mockAWS) EnsureEKSCluster(cluster *model.Cluster, resources aws.Cluster return &eksTypes.Cluster{}, nil } -func (a *mockAWS) EnsureEKSNodeGroup(cluster *model.Cluster, nodeGroupPrefix string) (*eksTypes.Nodegroup, error) { +func (a *mockAWS) EnsureEKSNodegroup(cluster *model.Cluster, nodeGroupPrefix string) (*eksTypes.Nodegroup, error) { return &eksTypes.Nodegroup{}, nil } diff --git a/internal/tools/aws/client.go b/internal/tools/aws/client.go index 0c5fa7f4e..059a56dc5 100644 --- a/internal/tools/aws/client.go +++ b/internal/tools/aws/client.go @@ -69,16 +69,16 @@ type AWS interface { EnsureEKSCluster(cluster *model.Cluster, resources ClusterResources) (*eksTypes.Cluster, error) EnsureEKSClusterUpdated(cluster *model.Cluster) (*eksTypes.Update, error) - EnsureEKSNodeGroup(cluster *model.Cluster, nodeGroupPrefix string) (*eksTypes.Nodegroup, error) - EnsureEKSNodeGroupMigrated(cluster *model.Cluster, nodeGroupPrefix string) error + EnsureEKSNodegroup(cluster *model.Cluster, nodeGroupPrefix string) (*eksTypes.Nodegroup, error) + EnsureEKSNodegroupMigrated(cluster *model.Cluster, nodeGroupPrefix string) error GetActiveEKSCluster(clusterName string) (*eksTypes.Cluster, error) - GetActiveEKSNodeGroup(clusterName, nodeGroupName string) (*eksTypes.Nodegroup, error) - EnsureEKSNodeGroupDeleted(clusterName, nodeGroupName string) error + GetActiveEKSNodegroup(clusterName, nodeGroupName string) (*eksTypes.Nodegroup, error) + EnsureEKSNodegroupDeleted(clusterName, nodeGroupName string) error EnsureEKSClusterDeleted(clusterName string) error InstallEKSAddons(cluster *model.Cluster) error WaitForActiveEKSCluster(clusterName string, timeout int) (*eksTypes.Cluster, error) - WaitForActiveEKSNodeGroup(clusterName, nodeGroupName string, timeout int) (*eksTypes.Nodegroup, error) - WaitForEKSNodeGroupToBeDeleted(clusterName, nodeGroupName string, timeout int) error + WaitForActiveEKSNodegroup(clusterName, nodeGroupName string, timeout int) (*eksTypes.Nodegroup, error) + WaitForEKSNodegroupToBeDeleted(clusterName, nodeGroupName string, timeout int) error WaitForEKSClusterToBeDeleted(clusterName string, timeout int) error WaitForEKSClusterUpdateToBeCompleted(clusterName, updateID string, timeout int) error diff --git a/internal/tools/aws/ec2.go b/internal/tools/aws/ec2.go index b7b16be34..788566dcd 100644 --- a/internal/tools/aws/ec2.go +++ b/internal/tools/aws/ec2.go @@ -179,18 +179,28 @@ func (a *Client) CreateLaunchTemplate(data *model.LaunchTemplateData) error { eksCluster, err := a.getEKSCluster(data.ClusterName) if err != nil { - return errors.Wrap(err, "failed to get eks cluster") + return errors.Wrap(err, "failed to get EKS cluster") } userData := getLaunchTemplateUserData(eksCluster, data) encodedUserData := base64.StdEncoding.EncodeToString([]byte(userData)) - launchTemplate, err := a.Service().ec2.CreateLaunchTemplate(context.TODO(), &ec2.CreateLaunchTemplateInput{ - LaunchTemplateData: &ec2Types.RequestLaunchTemplateData{ - ImageId: aws.String(data.AMI), - UserData: aws.String(encodedUserData), - SecurityGroupIds: data.SecurityGroups, + templateData := &ec2Types.RequestLaunchTemplateData{ + ImageId: aws.String(data.AMI), + InstanceType: ec2Types.InstanceType(data.InstanceType), + UserData: aws.String(encodedUserData), + NetworkInterfaces: []ec2Types.LaunchTemplateInstanceNetworkInterfaceSpecificationRequest{ + { + AssociatePublicIpAddress: aws.Bool(data.WithPublicSubnet), + DeleteOnTermination: aws.Bool(true), + DeviceIndex: aws.Int32(0), + Groups: data.SecurityGroups, + }, }, + } + + launchTemplate, err := a.Service().ec2.CreateLaunchTemplate(context.TODO(), &ec2.CreateLaunchTemplateInput{ + LaunchTemplateData: templateData, LaunchTemplateName: aws.String(data.Name), }) if err != nil { @@ -198,11 +208,11 @@ func (a *Client) CreateLaunchTemplate(data *model.LaunchTemplateData) error { a.logger.Debugf("Launch template %s already exists", data.Name) return nil } - return errors.Wrap(err, "failed to create eks launch template") + return errors.Wrap(err, "failed to create EKS launch template") } if launchTemplate == nil || launchTemplate.LaunchTemplate == nil { - return errors.New("failed to create eks launch template") + return errors.New("failed to create EKS launch template") } return nil @@ -215,29 +225,39 @@ func (a *Client) UpdateLaunchTemplate(data *model.LaunchTemplateData) error { eksCluster, err := a.getEKSCluster(data.ClusterName) if err != nil { - return errors.Wrap(err, "failed to get eks cluster") + return errors.Wrap(err, "failed to get ESK cluster") } userData := getLaunchTemplateUserData(eksCluster, data) encodedUserData := base64.StdEncoding.EncodeToString([]byte(userData)) - launchTemplate, err := a.Service().ec2.CreateLaunchTemplateVersion(context.TODO(), &ec2.CreateLaunchTemplateVersionInput{ - LaunchTemplateData: &ec2Types.RequestLaunchTemplateData{ - ImageId: aws.String(data.AMI), - UserData: aws.String(encodedUserData), - SecurityGroupIds: data.SecurityGroups, + templateData := &ec2Types.RequestLaunchTemplateData{ + ImageId: aws.String(data.AMI), + InstanceType: ec2Types.InstanceType(data.InstanceType), + UserData: aws.String(encodedUserData), + NetworkInterfaces: []ec2Types.LaunchTemplateInstanceNetworkInterfaceSpecificationRequest{ + { + AssociatePublicIpAddress: aws.Bool(data.WithPublicSubnet), + DeleteOnTermination: aws.Bool(true), + DeviceIndex: aws.Int32(0), + Groups: data.SecurityGroups, + }, }, + } + + launchTemplate, err := a.Service().ec2.CreateLaunchTemplateVersion(context.TODO(), &ec2.CreateLaunchTemplateVersionInput{ + LaunchTemplateData: templateData, LaunchTemplateName: aws.String(data.Name), }) if err != nil { if IsErrorCode(err, "InvalidLaunchTemplateName.NotFoundException") { return a.CreateLaunchTemplate(data) } - return errors.Wrap(err, "failed to create eks launch template version") + return errors.Wrap(err, "failed to create EKS launch template version") } if launchTemplate == nil || launchTemplate.LaunchTemplateVersion == nil { - return errors.New("failed to create eks launch template version") + return errors.New("failed to create ESK launch template version") } return nil @@ -250,7 +270,7 @@ func (a *Client) DeleteLaunchTemplate(launchTemplateName string) error { } if launchTemplate == nil { - a.logger.Debugf("launch template %s not found, assuming deleted", launchTemplateName) + a.logger.Debugf("Launch template %s not found, assuming deleted", launchTemplateName) return nil } @@ -262,7 +282,7 @@ func (a *Client) DeleteLaunchTemplate(launchTemplateName string) error { a.logger.Debugf("launch template %s not found, assuming deleted", launchTemplateName) return nil } - return errors.Wrap(err, "failed to delete eks launch template") + return errors.Wrap(err, "failed to delete EKS launch template") } return nil @@ -299,6 +319,7 @@ func getLaunchTemplateUserData(eksCluster *eksTypes.Cluster, data *model.LaunchT dataTemplate := ` #!/bin/bash set -o xtrace -/etc/eks/bootstrap.sh '%s' --apiserver-endpoint '%s' --b64-cluster-ca '%s' --use-max-pods false --kubelet-extra-args '--max-pods=%d'` +/etc/eks/bootstrap.sh '%s' --apiserver-endpoint '%s' --b64-cluster-ca '%s' --use-max-pods false --kubelet-extra-args '--max-pods=%d --kube-reserved cpu=250m,memory=1Gi,ephemeral-storage=1Gi --system-reserved cpu=250m,memory=0.2Gi,ephemeral-storage=1Gi --eviction-hard memory.available<0.2Gi,nodefs.available<10%%' +` return fmt.Sprintf(dataTemplate, *eksCluster.Name, *eksCluster.Endpoint, *eksCluster.CertificateAuthority.Data, data.MaxPodsPerNode) } diff --git a/internal/tools/aws/eks.go b/internal/tools/aws/eks.go index 05fc52af9..cd87bac76 100644 --- a/internal/tools/aws/eks.go +++ b/internal/tools/aws/eks.go @@ -26,7 +26,6 @@ func (c *Client) createEKSCluster(cluster *model.Cluster, resources ClusterResou // TODO: we do not expect to query that many subnets but for safety // we can check the NextToken. subnetsOut, err := c.Service().ec2.DescribeSubnets(ctx, &ec2.DescribeSubnetsInput{ - // TODO: is it public/private SubnetIds: resources.PrivateSubnetIDs, }) if err != nil { @@ -60,7 +59,6 @@ func (c *Client) createEKSCluster(cluster *model.Cluster, resources ClusterResou } eksMetadata := cluster.ProvisionerMetadataEKS - // TODO: we can allow further parametrization in the future input := eks.CreateClusterInput{ Name: aws.String(eksMetadata.Name), ResourcesVpcConfig: &vpcConfig, @@ -85,7 +83,7 @@ func (a *Client) getEKSCluster(clusterName string) (*eksTypes.Cluster, error) { }) if err != nil { if !IsErrorResourceNotFound(err) { - return nil, errors.Wrap(err, "failed to describe cluster") + return nil, errors.Wrap(err, "failed to describe EKS cluster") } } @@ -113,32 +111,44 @@ func (c *Client) EnsureEKSCluster(cluster *model.Cluster, resources ClusterResou // InstallEKSAddons installs EKS EBS addon to the existing cluster. func (a *Client) InstallEKSAddons(cluster *model.Cluster) error { - input := eks.CreateAddonInput{ - AddonName: aws.String("aws-ebs-csi-driver"), - ClusterName: aws.String(cluster.ProvisionerMetadataEKS.Name), - } - _, err := a.Service().eks.CreateAddon(context.TODO(), &input) - if err != nil { - // In case addon already configured we do not want to fail. - if IsErrorResourceInUseException(err) { - return nil - } - return errors.Wrap(err, "failed to create ebs-csi addon") - } - input = eks.CreateAddonInput{ - AddonName: aws.String("vpc-cni"), - ClusterName: aws.String(cluster.ProvisionerMetadataEKS.Name), - ConfigurationValues: aws.String("{\"env\":{\"ENABLE_PREFIX_DELEGATION\":\"true\"}}"), - ResolveConflicts: eksTypes.ResolveConflictsOverwrite, + var addons = []eks.CreateAddonInput{ + { + AddonName: aws.String("coredns"), + AddonVersion: aws.String("v1.8.7-eksbuild.1"), + ClusterName: aws.String(cluster.ProvisionerMetadataEKS.Name), + ResolveConflicts: eksTypes.ResolveConflictsOverwrite, + }, + { + AddonName: aws.String("kube-proxy"), + AddonVersion: aws.String("v1.22.6-eksbuild.1"), + ClusterName: aws.String(cluster.ProvisionerMetadataEKS.Name), + ResolveConflicts: eksTypes.ResolveConflictsOverwrite, + }, + { + AddonName: aws.String("vpc-cni"), + AddonVersion: aws.String("v1.11.0-eksbuild.1"), + ClusterName: aws.String(cluster.ProvisionerMetadataEKS.Name), + ConfigurationValues: aws.String("{\"env\":{\"ENABLE_PREFIX_DELEGATION\":\"true\"}}"), + ResolveConflicts: eksTypes.ResolveConflictsOverwrite, + }, + { + AddonName: aws.String("aws-ebs-csi-driver"), + AddonVersion: aws.String("v1.11.2-eksbuild.1"), + ClusterName: aws.String(cluster.ProvisionerMetadataEKS.Name), + ResolveConflicts: eksTypes.ResolveConflictsOverwrite, + }, } - _, err = a.Service().eks.CreateAddon(context.TODO(), &input) - if err != nil { - // In case addon already configured we do not want to fail. - if IsErrorResourceInUseException(err) { - return nil + + for i, addon := range addons { + _, err := a.Service().eks.CreateAddon(context.TODO(), &addons[i]) + if err != nil { + // In case addon already configured we do not want to fail. + if IsErrorResourceInUseException(err) { + return nil + } + return errors.Wrapf(err, "failed to create %s addon", *addon.AddonName) } - return errors.Wrap(err, "failed to create vpc-cni addon") } return nil @@ -152,11 +162,11 @@ func (c *Client) EnsureEKSClusterUpdated(cluster *model.Cluster) (*eksTypes.Upda } if eksCluster == nil { - return nil, errors.Errorf("cluster %s does not exist", clusterName) + return nil, errors.Errorf("requested EKS cluster %s does not exist", clusterName) } if eksCluster.Status != eksTypes.ClusterStatusActive { - return nil, errors.Errorf("cluster %s is not active", clusterName) + return nil, errors.Errorf("requested EKS cluster %s is not active", clusterName) } eksMetadata := cluster.ProvisionerMetadataEKS @@ -181,7 +191,7 @@ func (a *Client) createEKSNodeGroup(cluster *model.Cluster, ngPrefix string) (*e eksMetadata := cluster.ProvisionerMetadataEKS changeRequest := eksMetadata.ChangeRequest if changeRequest == nil { - return nil, errors.New("change request is nil") + return nil, errors.New("metadata ChangeRequest is nil") } clusterResource, err := a.GetVpcResourcesByVpcID(changeRequest.VPC, a.logger) @@ -229,7 +239,6 @@ func (a *Client) createEKSNodeGroup(cluster *model.Cluster, ngPrefix string) (*e nodeGroupReq := eks.CreateNodegroupInput{ ClusterName: aws.String(clusterName), - InstanceTypes: []string{ngChangeRequest.InstanceType}, NodeRole: &changeRequest.NodeRoleARN, NodegroupName: aws.String(ngChangeRequest.Name), AmiType: eksTypes.AMITypesCustom, @@ -263,21 +272,21 @@ func (a *Client) createEKSNodeGroup(cluster *model.Cluster, ngPrefix string) (*e out, err := a.Service().eks.CreateNodegroup(context.TODO(), &nodeGroupReq) if err != nil { - return nil, errors.Wrap(err, "failed to create EKS NodeGroup") + return nil, errors.Wrap(err, "failed to create EKS nodegroup") } return out.Nodegroup, nil } -func (c *Client) getEKSNodeGroup(clusterName, workerName string) (*eksTypes.Nodegroup, error) { +func (c *Client) getEKSNodeGroup(clusterName, nodegroupName string) (*eksTypes.Nodegroup, error) { output, err := c.Service().eks.DescribeNodegroup(context.TODO(), &eks.DescribeNodegroupInput{ ClusterName: aws.String(clusterName), - NodegroupName: aws.String(workerName), + NodegroupName: aws.String(nodegroupName), }) if err != nil { if !IsErrorResourceNotFound(err) { - return nil, errors.Wrap(err, "failed to describe EKS NodeGroup") + return nil, errors.Wrap(err, "failed to describe EKS nodegroup") } } @@ -288,8 +297,8 @@ func (c *Client) getEKSNodeGroup(clusterName, workerName string) (*eksTypes.Node return nil, nil } -// EnsureEKSNodeGroup ensures EKS cluster node groups are created. -func (c *Client) EnsureEKSNodeGroup(cluster *model.Cluster, ngPrefix string) (*eksTypes.Nodegroup, error) { +// EnsureEKSNodegroup ensures EKS nodegroup is created. +func (c *Client) EnsureEKSNodegroup(cluster *model.Cluster, ngPrefix string) (*eksTypes.Nodegroup, error) { clusterName := cluster.ProvisionerMetadataEKS.Name @@ -298,12 +307,12 @@ func (c *Client) EnsureEKSNodeGroup(cluster *model.Cluster, ngPrefix string) (*e ngChangeRequest, found := changeRequest.NodeGroups[ngPrefix] if !found { - return nil, errors.Errorf("nodegroup %s not found in change request", ngPrefix) + return nil, errors.Errorf("nodegroup metadata for %s not found in ChangeRequest", ngPrefix) } nodeGroup, err := c.getEKSNodeGroup(clusterName, ngChangeRequest.Name) if err != nil { - return nil, errors.Wrapf(err, "failed to get an EKS NodeGroup %s", ngChangeRequest.Name) + return nil, errors.Wrapf(err, "failed to get an EKS nodegroup %s", ngChangeRequest.Name) } if nodeGroup != nil { @@ -313,8 +322,8 @@ func (c *Client) EnsureEKSNodeGroup(cluster *model.Cluster, ngPrefix string) (*e return c.createEKSNodeGroup(cluster, ngPrefix) } -// EnsureEKSNodeGroupMigrated updates EKS cluster node group. -func (c *Client) EnsureEKSNodeGroupMigrated(cluster *model.Cluster, ngPrefix string) error { +// EnsureEKSNodegroupMigrated updates EKS nodegroup. +func (c *Client) EnsureEKSNodegroupMigrated(cluster *model.Cluster, ngPrefix string) error { logger := c.logger.WithField("cluster", cluster.ID) eksMetadata := cluster.ProvisionerMetadataEKS @@ -322,7 +331,7 @@ func (c *Client) EnsureEKSNodeGroupMigrated(cluster *model.Cluster, ngPrefix str ngChangeRequest, found := changeRequest.NodeGroups[ngPrefix] if !found { - return errors.Errorf("nodegroup meta for %s not found in change request", ngPrefix) + return errors.Errorf("nodegroup metadata for %s not found in ChangeRequest", ngPrefix) } clusterName := eksMetadata.Name @@ -335,26 +344,26 @@ func (c *Client) EnsureEKSNodeGroupMigrated(cluster *model.Cluster, ngPrefix str _, err := c.createEKSNodeGroup(cluster, ngPrefix) if err != nil { - return errors.Wrapf(err, "failed to create a new EKS NodeGroup %s", ngChangeRequest.Name) + return errors.Wrapf(err, "failed to create a new EKS nodegroup %s", ngChangeRequest.Name) } wait := 600 // seconds - logger.Infof("Waiting up to %d seconds for EKS NodeGroup %s to become active...", wait, ngChangeRequest.Name) + logger.Infof("Waiting up to %d seconds for EKS nodegroup %s to become active...", wait, ngChangeRequest.Name) - _, err = c.WaitForActiveEKSNodeGroup(eksMetadata.Name, ngChangeRequest.Name, wait) + _, err = c.WaitForActiveEKSNodegroup(eksMetadata.Name, ngChangeRequest.Name, wait) if err != nil { return err } - logger.Debugf("Deleting the old EKS NodeGroup %s", oldNodeGroupName) + logger.Debugf("Deleting the old EKS nodegroup %s", oldNodeGroupName) - err = c.EnsureEKSNodeGroupDeleted(clusterName, oldNodeGroupName) + err = c.EnsureEKSNodegroupDeleted(clusterName, oldNodeGroupName) if err != nil { - return errors.Wrapf(err, "failed to delete the old EKS NodeGroup %s", oldNodeGroupName) + return errors.Wrapf(err, "failed to delete the old EKS nodegroup %s", oldNodeGroupName) } - logger.Infof("Waiting up to %d seconds for EKS NodeGroup %s to be deleted...", wait, oldNodeGroupName) - err = c.WaitForEKSNodeGroupToBeDeleted(eksMetadata.Name, oldNodeGroupName, wait) + logger.Infof("Waiting up to %d seconds for EKS nodegroup %s to be deleted...", wait, oldNodeGroupName) + err = c.WaitForEKSNodegroupToBeDeleted(eksMetadata.Name, oldNodeGroupName, wait) if err != nil { return err } @@ -381,7 +390,7 @@ func (a *Client) EnsureEKSClusterDeleted(clusterName string) error { } if eksCluster.Status == eksTypes.ClusterStatusFailed { - return errors.New("cluster is in failed state") + return errors.New("requested EKS cluster is in failed state") } delInput := &eks.DeleteClusterInput{Name: aws.String(clusterName)} @@ -394,35 +403,35 @@ func (a *Client) EnsureEKSClusterDeleted(clusterName string) error { return nil } -// EnsureEKSNodeGroupDeleted ensures EKS node groups are deleted. -func (a *Client) EnsureEKSNodeGroupDeleted(clusterName, workerName string) error { - if workerName == "" { +// EnsureEKSNodegroupDeleted ensures EKS nodegroup is deleted. +func (a *Client) EnsureEKSNodegroupDeleted(clusterName, nodegroupName string) error { + if nodegroupName == "" { return nil } - nodeGroups, err := a.getEKSNodeGroup(clusterName, workerName) + nodeGroup, err := a.getEKSNodeGroup(clusterName, nodegroupName) if err != nil { - return errors.Wrap(err, "failed to get NodeGroup") + return errors.Wrap(err, "failed to get EKS nodegroup") } - // Node groups deleted, we can return - if nodeGroups == nil { + + if nodeGroup == nil { return nil } - if nodeGroups.Status == eksTypes.NodegroupStatusDeleting { + if nodeGroup.Status == eksTypes.NodegroupStatusDeleting { return nil } - if nodeGroups.Status == eksTypes.NodegroupStatusDeleteFailed { - return errors.Wrapf(err, "node group deletion failed %q", *nodeGroups.NodegroupName) + if nodeGroup.Status == eksTypes.NodegroupStatusDeleteFailed { + return errors.Wrapf(err, "failed to delete EKS nodegroup %s", nodegroupName) } _, err = a.Service().eks.DeleteNodegroup(context.TODO(), &eks.DeleteNodegroupInput{ ClusterName: aws.String(clusterName), - NodegroupName: nodeGroups.NodegroupName, + NodegroupName: nodeGroup.NodegroupName, }) if err != nil { - return errors.Wrap(err, "failed to delete NodeGroup") + return errors.Wrap(err, "failed to delete EKS nodegroup") } return nil @@ -440,7 +449,7 @@ func (c *Client) GetActiveEKSCluster(clusterName string) (*eksTypes.Cluster, err } if cluster.Status == eksTypes.ClusterStatusFailed { - return nil, errors.New("cluster creation failed") + return nil, errors.New("requested EKS cluster is in failed state") } if cluster.Status == eksTypes.ClusterStatusActive { @@ -450,11 +459,11 @@ func (c *Client) GetActiveEKSCluster(clusterName string) (*eksTypes.Cluster, err return nil, nil } -// GetActiveEKSNodeGroup returns the EKS node group if active. -func (c *Client) GetActiveEKSNodeGroup(clusterName, workerName string) (*eksTypes.Nodegroup, error) { +// GetActiveEKSNodegroup returns the EKS nodegroup if active. +func (c *Client) GetActiveEKSNodegroup(clusterName, workerName string) (*eksTypes.Nodegroup, error) { nodeGroup, err := c.getEKSNodeGroup(clusterName, workerName) if err != nil { - return nil, errors.Wrap(err, "failed to get NodeGroup") + return nil, errors.Wrap(err, "failed to get EKS nodegroup") } if nodeGroup == nil { @@ -462,7 +471,7 @@ func (c *Client) GetActiveEKSNodeGroup(clusterName, workerName string) (*eksType } if nodeGroup.Status == eksTypes.NodegroupStatusCreateFailed { - return nil, errors.New("EKS NodeGroup creation failed") + return nil, errors.New("failed to create EKS nodegroup") } if nodeGroup.Status == eksTypes.NodegroupStatusActive { @@ -495,7 +504,7 @@ func (c *Client) WaitForActiveEKSCluster(clusterName string, timeout int) (*eksT } } -func (c *Client) WaitForActiveEKSNodeGroup(clusterName, nodeGroupName string, timeout int) (*eksTypes.Nodegroup, error) { +func (c *Client) WaitForActiveEKSNodegroup(clusterName, nodeGroupName string, timeout int) (*eksTypes.Nodegroup, error) { timeoutTimer := time.NewTimer(time.Duration(timeout) * time.Second) defer timeoutTimer.Stop() tick := time.NewTicker(5 * time.Second) @@ -504,11 +513,11 @@ func (c *Client) WaitForActiveEKSNodeGroup(clusterName, nodeGroupName string, ti for { select { case <-timeoutTimer.C: - return nil, errors.New("timed out waiting for EKS NodeGroup to become active") + return nil, errors.New("timed out waiting for EKS nodegroup to become active") case <-tick.C: - nodeGroup, err := c.GetActiveEKSNodeGroup(clusterName, nodeGroupName) + nodeGroup, err := c.GetActiveEKSNodegroup(clusterName, nodeGroupName) if err != nil { - return nil, errors.Wrap(err, "failed to check if EKS NodeGroup is active") + return nil, errors.Wrap(err, "failed to check if EKS nodegroup is active") } if nodeGroup != nil { return nodeGroup, nil @@ -517,7 +526,7 @@ func (c *Client) WaitForActiveEKSNodeGroup(clusterName, nodeGroupName string, ti } } -func (c *Client) WaitForEKSNodeGroupToBeDeleted(clusterName, workerName string, timeout int) error { +func (c *Client) WaitForEKSNodegroupToBeDeleted(clusterName, workerName string, timeout int) error { timeoutTimer := time.NewTimer(time.Duration(timeout) * time.Second) defer timeoutTimer.Stop() tick := time.NewTicker(5 * time.Second) @@ -526,11 +535,11 @@ func (c *Client) WaitForEKSNodeGroupToBeDeleted(clusterName, workerName string, for { select { case <-timeoutTimer.C: - return errors.New("timed out waiting for EKS NodeGroup to become ready") + return errors.New("timed out waiting for EKS nodegroup to be deleted") case <-tick.C: nodeGroup, err := c.getEKSNodeGroup(clusterName, workerName) if err != nil { - return errors.Wrap(err, "failed to describe NodeGroup") + return errors.Wrap(err, "failed to describe EKS nodegroup") } if nodeGroup == nil { return nil @@ -578,7 +587,7 @@ func (c *Client) WaitForEKSClusterUpdateToBeCompleted(clusterName, updateID stri } if updateStatus == eksTypes.UpdateStatusFailed { - return errors.New("EKS cluster update failed") + return errors.New("failed to update EKS cluster") } if updateStatus == eksTypes.UpdateStatusSuccessful { @@ -594,7 +603,7 @@ func (c *Client) getEKSClusterUpdateStatus(clusterName, updateID string) (eksTyp UpdateId: ptr.String(updateID), }) if err != nil { - return "", errors.Wrap(err, "failed to describe EKS cluster update") + return "", errors.Wrap(err, "failed to describe update for EKS cluster") } return output.Update.Status, nil diff --git a/model/aws_types.go b/model/aws_types.go index 96724daeb..e0970116a 100644 --- a/model/aws_types.go +++ b/model/aws_types.go @@ -10,9 +10,11 @@ type Certificate struct { } type LaunchTemplateData struct { - Name string - ClusterName string - AMI string - MaxPodsPerNode int64 - SecurityGroups []string + Name string + ClusterName string + InstanceType string + AMI string + MaxPodsPerNode int64 + WithPublicSubnet bool + SecurityGroups []string } diff --git a/model/cluster_request.go b/model/cluster_request.go index f64dbd39e..a7e3113ea 100644 --- a/model/cluster_request.go +++ b/model/cluster_request.go @@ -183,8 +183,8 @@ func (request *CreateClusterRequest) Validate() error { if ng.MinCount < 1 { return errors.Errorf("node min count (%d) must be 1 or greater for node group %s", ng.MinCount, name) } - if ng.MaxCount != ng.MinCount { - return errors.Errorf("node min (%d) and max (%d) counts must match for node group %s", ng.MinCount, ng.MaxCount, name) + if ng.MinCount > ng.MaxCount { + return errors.Errorf("node min count (%d) cannot be greater than max count (%d) for nodegroup %s", ng.MinCount, ng.MaxCount, name) } } } @@ -409,10 +409,10 @@ func (request *CreateNodegroupsRequest) SetDefaults() { func (request *CreateNodegroupsRequest) Validate() error { for ng, meta := range request.Nodegroups { if meta.MinCount < 1 { - return errors.Errorf("nodegroup %s min count has to be 1 or greater", ng) + return errors.Errorf("minimum node count has to be 1 or greater for nodegroup %s", ng) } if meta.MaxCount < meta.MinCount { - return errors.Errorf("nodegroup %s max count (%d) can't be less than min count (%d)", ng, meta.MaxCount, meta.MinCount) + return errors.Errorf("maximum node count (%d) can't be less than minimum node count (%d) for nodegroup %s", meta.MaxCount, meta.MinCount, ng) } } @@ -421,7 +421,7 @@ func (request *CreateNodegroupsRequest) Validate() error { continue } if _, f := request.Nodegroups[ng]; !f { - return errors.Errorf("invalid nodegroup %s to use public subnets", ng) + return errors.Errorf("nodegroup %s not found to use public subnet", ng) } } @@ -430,7 +430,7 @@ func (request *CreateNodegroupsRequest) Validate() error { continue } if _, f := request.Nodegroups[ng]; !f { - return errors.Errorf("invalid nodegroup %s to use security group", ng) + return errors.Errorf("nodegroup %s not found to use security group", ng) } } diff --git a/model/eks_metadata.go b/model/eks_metadata.go index 6b606adf9..946be465e 100644 --- a/model/eks_metadata.go +++ b/model/eks_metadata.go @@ -163,7 +163,7 @@ func (em *EKSMetadata) ValidateClusterSizePatch(patchRequest *PatchClusterSizeRe nodeGroups := patchRequest.NodeGroups if len(em.NodeGroups) == 0 { - return errors.New("no nodegroups available to resize") + return errors.New("no nodegroups are available to resize") } if len(nodeGroups) == 0 { @@ -183,7 +183,7 @@ func (em *EKSMetadata) ValidateClusterSizePatch(patchRequest *PatchClusterSizeRe if patchRequest.NodeMinCount != nil && patchRequest.NodeMaxCount != nil { if *patchRequest.NodeMinCount > *patchRequest.NodeMaxCount { - return errors.New("min node count cannot be greater than max node count") + return errors.New("minimum node count cannot be greater than maximum node count") } return nil } @@ -193,7 +193,7 @@ func (em *EKSMetadata) ValidateClusterSizePatch(patchRequest *PatchClusterSizeRe ng := em.NodeGroups[ngToResize] nodeMaxCount := ng.MaxCount if *patchRequest.NodeMinCount > nodeMaxCount { - return errors.New("resize patch would set min node count higher than max node count") + return errors.New("resize patch would set minimum node count higher than maximum node count") } } } @@ -203,7 +203,7 @@ func (em *EKSMetadata) ValidateClusterSizePatch(patchRequest *PatchClusterSizeRe ng := em.NodeGroups[ngToResize] nodeMinCount := ng.MinCount if *patchRequest.NodeMaxCount < nodeMinCount { - return errors.New("resize patch would set max node count lower than min node count") + return errors.New("resize patch would set maximum node count lower than minimum node count") } } } @@ -257,7 +257,7 @@ func (em *EKSMetadata) ApplyClusterSizePatch(patchRequest *PatchClusterSizeReque func (em *EKSMetadata) ValidateChangeRequest() error { changeRequest := em.ChangeRequest if changeRequest == nil { - return errors.New("the EKS Metadata ChangeRequest is nil") + return errors.New("metadata ChangeRequest is nil") } changeAllowed := false @@ -277,7 +277,7 @@ func (em *EKSMetadata) ValidateChangeRequest() error { } if !changeAllowed { - return errors.New("the EKS Metadata ChangeRequest has no change values set") + return errors.New("metadata ChangeRequest has no changes to apply") } return nil