From 183c3ffab0fe2eb59f5e1ced3452275372b500c5 Mon Sep 17 00:00:00 2001 From: Mahmoud Saada Date: Mon, 20 Apr 2020 09:02:12 -0400 Subject: [PATCH] add support for metrics collection in scaling config add name to humans.txt reset go.mod make metrics optional add cloudformation mapping regenerate fix if statement apply pr review changes apply pr review changes WIP update schema and generated deepcopy add tests and update docs cleanup test comments --- examples/05-advanced-nodegroups.yaml | 13 ++++++++- pkg/apis/eksctl.io/v1alpha5/types.go | 11 ++++++++ .../v1alpha5/zz_generated.deepcopy.go | 28 +++++++++++++++++++ pkg/cfn/builder/api_test.go | 26 ++++++++++++++++- pkg/cfn/builder/nodegroup.go | 18 ++++++++++++ userdocs/src/usage/eks-managed-nodes.md | 1 + userdocs/src/usage/managing-nodegroups.md | 11 ++++++++ userdocs/src/usage/schema.md | 17 +++++++++++ 8 files changed, 123 insertions(+), 2 deletions(-) diff --git a/examples/05-advanced-nodegroups.yaml b/examples/05-advanced-nodegroups.yaml index d84e9b1806b..754c4a36f85 100644 --- a/examples/05-advanced-nodegroups.yaml +++ b/examples/05-advanced-nodegroups.yaml @@ -1,5 +1,5 @@ # An advanced example of ClusterConfig object with customised nodegroups: ---- +--- apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig @@ -42,6 +42,17 @@ nodeGroups: nodegroup-type: very-special-science-workloads classicLoadBalancerNames: - ng3-classic-load-balancer + asgMetricsCollection: + - granularity: 1Minute + metrics: + - GroupMinSize + - GroupMaxSize + - GroupDesiredCapacity + - GroupInServiceInstances + - GroupPendingInstances + - GroupStandbyInstances + - GroupTerminatingInstances + - GroupTotalInstances taints: special: "true:NoSchedule" privateNetworking: true diff --git a/pkg/apis/eksctl.io/v1alpha5/types.go b/pkg/apis/eksctl.io/v1alpha5/types.go index 60aa18c6cfc..01266571976 100644 --- a/pkg/apis/eksctl.io/v1alpha5/types.go +++ b/pkg/apis/eksctl.io/v1alpha5/types.go @@ -619,6 +619,8 @@ type NodeGroup struct { MinSize *int `json:"minSize,omitempty"` // +optional MaxSize *int `json:"maxSize,omitempty"` + // +optional + ASGMetricsCollection []MetricsCollection `json:"asgMetricsCollection,omitempty"` // +optional EBSOptimized *bool `json:"ebsOptimized,omitempty"` @@ -787,6 +789,15 @@ type ( } ) +// MetricsCollection used by the scaling config +// https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-metricscollection.html +type MetricsCollection struct { + // +required + Granularity string `json:"granularity"` + // +optional + Metrics []string `json:"metrics,omitempty"` +} + // ScalingConfig defines the scaling config type ScalingConfig struct { // +optional diff --git a/pkg/apis/eksctl.io/v1alpha5/zz_generated.deepcopy.go b/pkg/apis/eksctl.io/v1alpha5/zz_generated.deepcopy.go index 363dbacdd9c..7435ffadb4a 100644 --- a/pkg/apis/eksctl.io/v1alpha5/zz_generated.deepcopy.go +++ b/pkg/apis/eksctl.io/v1alpha5/zz_generated.deepcopy.go @@ -590,6 +590,27 @@ func (in *ManagedNodeGroup) DeepCopy() *ManagedNodeGroup { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricsCollection) DeepCopyInto(out *MetricsCollection) { + *out = *in + if in.Metrics != nil { + in, out := &in.Metrics, &out.Metrics + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricsCollection. +func (in *MetricsCollection) DeepCopy() *MetricsCollection { + if in == nil { + return nil + } + out := new(MetricsCollection) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Network) DeepCopyInto(out *Network) { *out = *in @@ -650,6 +671,13 @@ func (in *NodeGroup) DeepCopyInto(out *NodeGroup) { *out = new(int) **out = **in } + if in.ASGMetricsCollection != nil { + in, out := &in.ASGMetricsCollection, &out.ASGMetricsCollection + *out = make([]MetricsCollection, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } if in.EBSOptimized != nil { in, out := &in.EBSOptimized, &out.EBSOptimized *out = new(bool) diff --git a/pkg/cfn/builder/api_test.go b/pkg/cfn/builder/api_test.go index 2df9add3be8..dbfe28c31ab 100644 --- a/pkg/cfn/builder/api_test.go +++ b/pkg/cfn/builder/api_test.go @@ -73,6 +73,7 @@ type Properties struct { VPCZoneIdentifier interface{} LoadBalancerNames []string + MetricsCollection []interface{} TargetGroupARNs []string DesiredCapacity, MinSize, MaxSize string @@ -811,7 +812,15 @@ var _ = Describe("CloudFormation template builder API", func() { Context("NodeGroupAutoScaling", func() { cfg, ng := newClusterConfigAndNodegroup(true) - + ng.ASGMetricsCollection = []api.MetricsCollection{ + { + Granularity: "1Minute", + Metrics: []string{ + "GroupMinSize", + "GroupMaxSize", + }, + }, + } ng.ClassicLoadBalancerNames = []string{"clb-1", "clb-2"} ng.TargetGroupARNs = []string{"tg-arn-1", "tg-arn-2"} @@ -916,6 +925,21 @@ var _ = Describe("CloudFormation template builder API", func() { Expect(ng.Properties.LoadBalancerNames).To(Equal([]string{"clb-1", "clb-2"})) }) + It("should have metrics collections set", func() { + Expect(ngTemplate.Resources).To(HaveKey("NodeGroup")) + ng := ngTemplate.Resources["NodeGroup"] + Expect(ng).ToNot(BeNil()) + Expect(ng.Properties).ToNot(BeNil()) + + Expect(ng.Properties.MetricsCollection).ToNot(BeEmpty()) + var metricsCollection map[string]interface{} = ng.Properties.MetricsCollection[0].(map[string]interface{}) + Expect(metricsCollection).To(HaveKey("granularity")) + Expect(metricsCollection).To(HaveKey("metrics")) + Expect(metricsCollection["granularity"]).To(Equal("1Minute")) + Expect(metricsCollection["metrics"]).To(ContainElement("GroupMinSize")) + Expect(metricsCollection["metrics"]).To(ContainElement("GroupMaxSize")) + }) + It("should have target groups ARNs set", func() { Expect(ngTemplate.Resources).To(HaveKey("NodeGroup")) ng := ngTemplate.Resources["NodeGroup"] diff --git a/pkg/cfn/builder/nodegroup.go b/pkg/cfn/builder/nodegroup.go index cc799cebccb..ef793d95f42 100644 --- a/pkg/cfn/builder/nodegroup.go +++ b/pkg/cfn/builder/nodegroup.go @@ -274,6 +274,9 @@ func nodeGroupResource(launchTemplateName *gfn.Value, vpcZoneIdentifier interfac if ng.MaxSize != nil { ngProps["MaxSize"] = fmt.Sprintf("%d", *ng.MaxSize) } + if len(ng.ASGMetricsCollection) > 0 { + ngProps["MetricsCollection"] = *metricsCollectionResource(ng.ASGMetricsCollection) + } if len(ng.ClassicLoadBalancerNames) > 0 { ngProps["LoadBalancerNames"] = ng.ClassicLoadBalancerNames } @@ -345,3 +348,18 @@ func mixedInstancesPolicy(launchTemplateName *gfn.Value, ng *api.NodeGroup) *map return &policy } + +func metricsCollectionResource(asgMetricsCollection []api.MetricsCollection) *[]map[string]interface{} { + metricsCollections := make([]map[string]interface{}, len(asgMetricsCollection)) + for _, m := range asgMetricsCollection { + newCollection := make(map[string]interface{}) + + metrics := make([]string, len(m.Metrics)) + metrics = append(metrics, m.Metrics...) + newCollection["Metrics"] = metrics + newCollection["Granularity"] = m.Granularity + + metricsCollections = append(metricsCollections, newCollection) + } + return &metricsCollections +} diff --git a/userdocs/src/usage/eks-managed-nodes.md b/userdocs/src/usage/eks-managed-nodes.md index c051371b7a5..eb76abcf239 100644 --- a/userdocs/src/usage/eks-managed-nodes.md +++ b/userdocs/src/usage/eks-managed-nodes.md @@ -179,6 +179,7 @@ the provisioned Autoscaling Group like in unmanaged nodegroups. - Control over the node bootstrapping process and customization of the kubelet are not supported. This includes the following fields: `classicLoadBalancerNames`, `maxPodsPerNode`, `taints`, `targetGroupARNs`, `preBootstrapCommands`, `overrideBootstrapCommand`, `clusterDNS` and `kubeletExtraConfig`. +- No support for enabling metrics on AutoScalingGroups using `asgMetricsCollection` ## Note for eksctl versions below 0.12.0 - For clusters upgraded from EKS 1.13 to EKS 1.14, managed nodegroups will not be able to communicate with unmanaged diff --git a/userdocs/src/usage/managing-nodegroups.md b/userdocs/src/usage/managing-nodegroups.md index 72810d4d5bd..d5815196c85 100644 --- a/userdocs/src/usage/managing-nodegroups.md +++ b/userdocs/src/usage/managing-nodegroups.md @@ -76,6 +76,17 @@ nodeGroups: classicLoadBalancerNames: - dev-clb-1 - dev-clb-2 + asgMetricsCollection: + - granularity: 1Minute + metrics: + - GroupMinSize + - GroupMaxSize + - GroupDesiredCapacity + - GroupInServiceInstances + - GroupPendingInstances + - GroupStandbyInstances + - GroupTerminatingInstances + - GroupTotalInstances - name: ng-2-api labels: { role: api } instanceType: m5.2xlarge diff --git a/userdocs/src/usage/schema.md b/userdocs/src/usage/schema.md index 2b4194a38b2..279fa2207e3 100755 --- a/userdocs/src/usage/schema.md +++ b/userdocs/src/usage/schema.md @@ -353,6 +353,18 @@ ManagedNodeGroup: - ScalingConfig - privateNetworking type: object +MetricsCollection: + additionalProperties: false + properties: + granularity: + type: string + metrics: + items: + type: string + type: array + required: + - granularity + type: object Network: additionalProperties: false properties: @@ -369,6 +381,11 @@ NodeGroup: type: string amiFamily: type: string + asgMetricsCollection: + items: + $ref: '#/definitions/MetricsCollection' + $schema: http://json-schema.org/draft-04/schema# + type: array availabilityZones: items: type: string