Repository: keikoproj/instance-manager (go)

Issue:
Feature Request - native Cluster Autoscaler support
**Is this a BUG REPORT or FEATURE REQUEST?**:
Feature Request
**What happened**:
It would be nice if cluster autoscaler was supported natively. 
Today, registering instance groups with cluster autoscaler can be achieved through the manual addition of Tags in the CR, but this could be cumbersome for users to add to each and every CR - especially since most of the information is already present in the CR. 

**Proposal**
Add a new field like "useClusterAutoscaler" to the InstanceGroup defintion which, if set, would automatically tag the ASG with the following tags. 

```
k8s.io/cluster-autoscaler/<cluster-name>: owned
k8s.io/cluster-autoscaler/enabled: true
k8s.io/cluster-autoscaler/node-template/label/<my-label-key>: <my-label-value> (this would be repeated for each unique label) 
k8s.io/cluster-autoscaler/node-template/taint/my-taint: "true:NoSchedule" (this would be repeated for each unique taint)
``` 


Pull request:
Add capability to automatically add cluster autoscaler ASG tags
Closes #180

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/keikoproj/instance-manager/183)
<!-- Reviewable:end -->


Patch:
diff --git a/controllers/provisioners/eks/eks.go b/controllers/provisioners/eks/eks.go
index fc33d4e..6b189cc 100644
--- a/controllers/provisioners/eks/eks.go
+++ b/controllers/provisioners/eks/eks.go
@@ -31,6 +31,7 @@ const (
 	ProvisionerName                     = "eks"
 	defaultLaunchConfigurationRetention = 2
 	OverrideDefaultLabelsAnnotationKey  = "instancemgr.keikoproj.io/default-labels"
+	ClusterAutoscalerEnabledAnnotation  = "instancemgr.keikoproj.io/cluster-autoscaler-enabled"
 )
 
 var (
diff --git a/controllers/provisioners/eks/helpers.go b/controllers/provisioners/eks/helpers.go
index 29cff3e..0a4840c 100644
--- a/controllers/provisioners/eks/helpers.go
+++ b/controllers/provisioners/eks/helpers.go
@@ -206,6 +206,9 @@ func (ctx *EksInstanceGroupContext) GetAddedTags(asgName string) []*autoscaling.
 		instanceGroup = ctx.GetInstanceGroup()
 		configuration = instanceGroup.GetEKSConfiguration()
 		clusterName   = configuration.GetClusterName()
+		annotations   = instanceGroup.GetAnnotations()
+		labels 	      = configuration.GetLabels()
+		taints        = configuration.GetTaints()
 	)
 
 	tags = append(tags, ctx.AwsWorker.NewTag("Name", asgName, asgName))
@@ -214,6 +217,21 @@ func (ctx *EksInstanceGroupContext) GetAddedTags(asgName string) []*autoscaling.
 	tags = append(tags, ctx.AwsWorker.NewTag(provisioners.TagInstanceGroupNamespace, instanceGroup.GetNamespace(), asgName))
 	tags = append(tags, ctx.AwsWorker.NewTag(provisioners.TagInstanceGroupName, instanceGroup.GetName(), asgName))
 
+	if annotations[ClusterAutoscalerEnabledAnnotation] == "true" {
+		tags = append(tags, ctx.AwsWorker.NewTag(fmt.Sprintf("k8s.io/cluster-autoscaler/%v", clusterName), "owned", asgName))
+		tags = append(tags, ctx.AwsWorker.NewTag("k8s.io/cluster-autoscaler/enabled", "true", asgName))
+
+		for label, labelValue := range labels {
+			tags = append(tags, ctx.AwsWorker.NewTag(fmt.Sprintf("k8s.io/cluster-autoscaler/node-template/label/%v", label), labelValue, asgName))
+		}
+
+		for _, taint := range taints {
+			tagValue := fmt.Sprintf("%v:%v", taint.Value, taint.Effect)
+			tag := ctx.AwsWorker.NewTag(fmt.Sprintf("k8s.io/cluster-autoscaler/node-template/taint/%s", taint.Key), tagValue, asgName)
+			tags = append(tags, tag)
+		}
+	}
+
 	// custom tags
 	for _, tagSlice := range configuration.GetTags() {
 		tags = append(tags, ctx.AwsWorker.NewTag(tagSlice["key"], tagSlice["value"], asgName))


Test patch:
diff --git a/controllers/provisioners/eks/eks_test.go b/controllers/provisioners/eks/eks_test.go
index 21f3d87..e0de528 100644
--- a/controllers/provisioners/eks/eks_test.go
+++ b/controllers/provisioners/eks/eks_test.go
@@ -106,6 +106,9 @@ func MockInstanceGroup() *v1alpha1.InstanceGroup {
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      "instance-group-1",
 			Namespace: "instance-manager",
+			Annotations: map[string]string{
+				ClusterAutoscalerEnabledAnnotation: "true",
+			},
 		},
 		Spec: v1alpha1.InstanceGroupSpec{
 			Provisioner: ProvisionerName,
diff --git a/controllers/provisioners/eks/helpers_test.go b/controllers/provisioners/eks/helpers_test.go
index daf5ba6..59b8103 100644
--- a/controllers/provisioners/eks/helpers_test.go
+++ b/controllers/provisioners/eks/helpers_test.go
@@ -17,6 +17,7 @@ package eks
 
 import (
 	"fmt"
+	corev1 "k8s.io/api/core/v1"
 	"sort"
 	"testing"
 
@@ -31,6 +32,54 @@ import (
 	"github.com/pkg/errors"
 )
 
+func TestAutoscalerTags(t *testing.T) {
+	var (
+		k       = MockKubernetesClientSet()
+		ig      = MockInstanceGroup()
+		asgMock = NewAutoScalingMocker()
+		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
+		ec2Mock = NewEc2Mocker()
+	)
+
+	w := MockAwsWorker(asgMock, iamMock, eksMock, ec2Mock)
+
+	ig.Annotations = map[string]string{
+		ClusterAutoscalerEnabledAnnotation: "true",
+	}
+
+	ig.Spec.EKSSpec.EKSConfiguration.Labels = make(map[string]string)
+	ig.Spec.EKSSpec.EKSConfiguration.Labels["foo"] = "bar"
+
+	ig.Spec.EKSSpec.EKSConfiguration.Taints = []corev1.Taint{}
+	ig.Spec.EKSSpec.EKSConfiguration.Taints = append(ig.Spec.EKSSpec.EKSConfiguration.Taints, corev1.Taint{
+		Key:       "red",
+		Value:     "green",
+		Effect:    "NoSchedule",
+	})
+	ctx := MockContext(ig, k, w)
+
+	tags := make(map[string]string)
+	expectedTags := make(map[string]string)
+
+	expectedTags["k8s.io/cluster-autoscaler/enabled"] = "true"
+	expectedTags["k8s.io/cluster-autoscaler/" + ig.Spec.EKSSpec.EKSConfiguration.EksClusterName] = "owned"
+	expectedTags["k8s.io/cluster-autoscaler/node-template/label/foo"] = "bar"
+	expectedTags["k8s.io/cluster-autoscaler/node-template/taint/red"] = "green:NoSchedule"
+
+	tagSlice := ctx.GetAddedTags("foo")
+	for _, tag := range tagSlice {
+		tags[*tag.Key] = *tag.Value
+	}
+	for expectedKey, expectedValue  := range expectedTags {
+		if tags[expectedKey] != expectedValue {
+			t.Fatalf("Expected %v=%v, Got %v",expectedKey,expectedValue,tags[expectedKey])
+		}
+	}
+
+
+}
+
 func TestResolveSecurityGroups(t *testing.T) {
 	var (
 		g       = gomega.NewGomegaWithT(t)