Repository: keikoproj/instance-manager (go)

Issue:
Kubernetes 1.16: Nodes fail to join due deprecated role label
Right now the controller adds two labels by default to define the role:
- `node.kubernetes.io/role=<ROLE>` => NEW STYLE LABEL
- `node-role.kubernetes.io/<ROLE>=""` => OLD STYLE LABEL

The old style label has been deprecated in 1.16 and causes nodes to FAIL to join the cluster.
We should release a version which adds the label according to the cluster version.

- Check by cluster name what is the cluster version
- If cluster version is >= 1.16, use the new style label
- If cluster version is < 1.16, use the old style label

We will need to release a hotfix 0.6.4 with this change

Pull request description:
Add label according to EKS cluster version
fixes #120 

Patch:
diff --git a/controllers/providers/aws/aws.go b/controllers/providers/aws/aws.go
index 1a52aaa..c68dd3d 100644
--- a/controllers/providers/aws/aws.go
+++ b/controllers/providers/aws/aws.go
@@ -421,6 +421,19 @@ func (w *AwsWorker) IsNodeGroupExist() bool {
 	return true
 }
 
+func (w *AwsWorker) DescribeEKSCluster(clusterName string) (*eks.Cluster, error) {
+	cluster := &eks.Cluster{}
+	input := &eks.DescribeClusterInput{
+		Name: aws.String(clusterName),
+	}
+
+	output, err := w.EksClient.DescribeCluster(input)
+	if err != nil {
+		return cluster, err
+	}
+	return output.Cluster, nil
+}
+
 // TODO: Rename - GetNodeGroup
 func (w *AwsWorker) GetSelfNodeGroup() (error, *eks.Nodegroup) {
 	input := &eks.DescribeNodegroupInput{
diff --git a/controllers/provisioners/eks/cloud.go b/controllers/provisioners/eks/cloud.go
index f57c133..f446df6 100644
--- a/controllers/provisioners/eks/cloud.go
+++ b/controllers/provisioners/eks/cloud.go
@@ -26,6 +26,7 @@ import (
 
 	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/service/autoscaling"
+	"github.com/aws/aws-sdk-go/service/eks"
 	"github.com/aws/aws-sdk-go/service/iam"
 	"github.com/pkg/errors"
 )
@@ -43,6 +44,7 @@ type DiscoveredState struct {
 	AttachedPolicies              []*iam.AttachedPolicy
 	InstanceProfile               *iam.InstanceProfile
 	Publisher                     kubeprovider.EventPublisher
+	Cluster                       *eks.Cluster
 }
 
 func (ctx *EksInstanceGroupContext) CloudDiscovery() error {
@@ -100,6 +102,12 @@ func (ctx *EksInstanceGroupContext) CloudDiscovery() error {
 		return errors.Wrap(err, "failed to describe autoscaling groups")
 	}
 
+	cluster, err := ctx.AwsWorker.DescribeEKSCluster(clusterName)
+	if err != nil {
+		return errors.Wrap(err, "failed to describe cluster")
+	}
+	state.SetCluster(cluster)
+
 	// find all owned scaling groups
 	ownedScalingGroups := ctx.findOwnedScalingGroups(scalingGroups)
 	state.SetOwnedScalingGroups(ownedScalingGroups)
@@ -187,6 +195,18 @@ func (d *DiscoveredState) GetScalingGroup() *autoscaling.Group {
 	}
 	return &autoscaling.Group{}
 }
+
+func (d *DiscoveredState) SetCluster(cluster *eks.Cluster) {
+	d.Cluster = cluster
+}
+
+func (d *DiscoveredState) GetClusterVersion() string {
+	if d.Cluster == nil {
+		return ""
+	}
+	return aws.StringValue(d.Cluster.Version)
+}
+
 func (d *DiscoveredState) SetOwnedScalingGroups(groups []*autoscaling.Group) {
 	d.OwnedScalingGroups = groups
 }
diff --git a/controllers/provisioners/eks/eks.go b/controllers/provisioners/eks/eks.go
index 989ff08..ad173fa 100644
--- a/controllers/provisioners/eks/eks.go
+++ b/controllers/provisioners/eks/eks.go
@@ -32,7 +32,9 @@ const (
 )
 
 var (
-	RoleLabelsFmt          = []string{"node.kubernetes.io/role=%s", "node-role.kubernetes.io/%s=\"\""}
+	RoleNewLabelFmt = "node.kubernetes.io/role=%s"
+	RoleOldLabelFmt = "node-role.kubernetes.io/%s=\"\""
+
 	DefaultManagedPolicies = []string{"AmazonEKSWorkerNodePolicy", "AmazonEKS_CNI_Policy", "AmazonEC2ContainerRegistryReadOnly"}
 )
 
diff --git a/controllers/provisioners/eks/helpers.go b/controllers/provisioners/eks/helpers.go
index a3324cc..f50471c 100644
--- a/controllers/provisioners/eks/helpers.go
+++ b/controllers/provisioners/eks/helpers.go
@@ -21,6 +21,7 @@ import (
 	"sort"
 	"strings"
 
+	"github.com/Masterminds/semver"
 	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/service/autoscaling"
 	"github.com/keikoproj/instance-manager/api/v1alpha1"
@@ -156,9 +157,22 @@ func (ctx *EksInstanceGroupContext) GetLabelList() []string {
 	}
 	sort.Strings(labelList)
 
-	// add role label
-	for _, label := range RoleLabelsFmt {
-		labelList = append(labelList, fmt.Sprintf(label, instanceGroup.GetName()))
+	// add the new style role label
+	labelList = append(labelList, fmt.Sprintf(RoleNewLabelFmt, instanceGroup.GetName()))
+
+	// add the old style role label if the cluster's k8s version is < 1.16
+	clusterVersion := ctx.DiscoveredState.GetClusterVersion()
+	ver, err := semver.NewVersion(clusterVersion)
+	if err != nil {
+		//log error
+		ctx.Log.Error(err, "Failed parsing the cluster's kubernetes version", "instancegroup", instanceGroup.GetName())
+		labelList = append(labelList, fmt.Sprintf(RoleOldLabelFmt, instanceGroup.GetName()))
+		return labelList
+	}
+
+	c, _ := semver.NewConstraint("< 1.16-0")
+	if addOldStyleRoleLabel := c.Check(ver); addOldStyleRoleLabel {
+		labelList = append(labelList, fmt.Sprintf(RoleOldLabelFmt, instanceGroup.GetName()))
 	}
 	return labelList
 }
diff --git a/go.mod b/go.mod
index 1f06647..a121aba 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,7 @@ module github.com/keikoproj/instance-manager
 go 1.13
 
 require (
+	github.com/Masterminds/semver v1.5.0
 	github.com/aws/aws-sdk-go v1.30.24
 	github.com/cucumber/godog v0.8.1
 	github.com/ghodss/yaml v1.0.0
diff --git a/go.sum b/go.sum
index b6435f2..dcaf892 100644
--- a/go.sum
+++ b/go.sum
@@ -14,6 +14,8 @@ github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6L
 github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
+github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
 github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
 github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
 github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
@@ -442,6 +444,7 @@ golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3
 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac h1:MQEvx39qSf8vyrx3XRaOe+j1UDIzKwkYOVObRgGPVqI=
 golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=


Test patch:
diff --git a/controllers/provisioners/eks/cloud_test.go b/controllers/provisioners/eks/cloud_test.go
index 8ac3a1d..635bee4 100644
--- a/controllers/provisioners/eks/cloud_test.go
+++ b/controllers/provisioners/eks/cloud_test.go
@@ -37,9 +37,10 @@ func TestCloudDiscoveryPositive(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 	state := ctx.GetDiscoveredState()
 	status := ig.GetStatus()
@@ -106,9 +107,10 @@ func TestCloudDiscoveryExistingRole(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 	configuration := ig.GetEKSConfiguration()
 	state := ctx.GetDiscoveredState()
@@ -138,9 +140,10 @@ func TestCloudDiscoverySpotPrice(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 	status := ig.GetStatus()
 	configuration := ig.GetEKSConfiguration()
@@ -218,9 +221,10 @@ func TestLaunchConfigDeletion(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 	configuration := ig.GetEKSConfiguration()
 
diff --git a/controllers/provisioners/eks/create_test.go b/controllers/provisioners/eks/create_test.go
index 37d9fc4..adde1be 100644
--- a/controllers/provisioners/eks/create_test.go
+++ b/controllers/provisioners/eks/create_test.go
@@ -24,6 +24,7 @@ import (
 	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/aws/awserr"
 	"github.com/aws/aws-sdk-go/service/autoscaling"
+	"github.com/aws/aws-sdk-go/service/eks"
 	"github.com/aws/aws-sdk-go/service/iam"
 	"github.com/keikoproj/instance-manager/api/v1alpha1"
 	"github.com/keikoproj/instance-manager/controllers/common"
@@ -38,11 +39,13 @@ func TestCreateManagedRolePositive(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 	state := ctx.GetDiscoveredState()
+	state.SetCluster(&eks.Cluster{Version: aws.String("1.15")})
 	state.Publisher.Client = k.Kubernetes
 
 	// Mock role/profile do not exist so they are always created
@@ -72,9 +75,10 @@ func TestCreateLaunchConfigurationPositive(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 
 	// Skip role creation
@@ -88,6 +92,9 @@ func TestCreateLaunchConfigurationPositive(t *testing.T) {
 		InstanceProfile: &iam.InstanceProfile{
 			Arn: aws.String("some-profile-arn"),
 		},
+		Cluster: &eks.Cluster{
+			Version: aws.String("1.15"),
+		},
 	})
 
 	lcName := fmt.Sprintf("my-cluster-%v-%v-%v", ig.GetNamespace(), ig.GetName(), common.GetTimeString())
@@ -110,9 +117,10 @@ func TestCreateScalingGroupPositive(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 
 	// skip role creation
@@ -150,9 +158,10 @@ func TestCreateNoOp(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 
 	// skip role creation
@@ -189,9 +198,10 @@ func TestCreateManagedRoleNegative(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 
 	// Mock role/profile do not exist so they are always created
@@ -236,9 +246,10 @@ func TestCreateLaunchConfigNegative(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 
 	ig.GetEKSConfiguration().SetRoleName("some-role")
@@ -251,6 +262,9 @@ func TestCreateLaunchConfigNegative(t *testing.T) {
 		InstanceProfile: &iam.InstanceProfile{
 			Arn: aws.String("arn"),
 		},
+		Cluster: &eks.Cluster{
+			Version: aws.String("1.15"),
+		},
 	})
 
 	asgMock.CreateLaunchConfigurationErr = errors.New("some-error")
@@ -272,9 +286,10 @@ func TestCreateAutoScalingGroupNegative(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 
 	ig.GetEKSConfiguration().SetRoleName("some-role")
diff --git a/controllers/provisioners/eks/delete_test.go b/controllers/provisioners/eks/delete_test.go
index 68d6445..57f4fe4 100644
--- a/controllers/provisioners/eks/delete_test.go
+++ b/controllers/provisioners/eks/delete_test.go
@@ -38,9 +38,10 @@ func TestDeletePositive(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 
 	ctx.SetDiscoveredState(&DiscoveredState{
@@ -65,9 +66,10 @@ func TestDeleteManagedRoleNegative(t *testing.T) {
 		configuration = ig.GetEKSConfiguration()
 		asgMock       = NewAutoScalingMocker()
 		iamMock       = NewIamMocker()
+		eksMock       = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 
 	ctx.SetDiscoveredState(&DiscoveredState{
@@ -96,9 +98,10 @@ func TestDeleteLaunchConfigurationNegative(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 
 	ctx.SetDiscoveredState(&DiscoveredState{
@@ -125,9 +128,10 @@ func TestDeleteAutoScalingGroupNegative(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 
 	ctx.SetDiscoveredState(&DiscoveredState{
@@ -152,9 +156,10 @@ func TestRemoveAuthRoleNegative(t *testing.T) {
 		ig2     = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 
 	// two instancegroups with same role arn
diff --git a/controllers/provisioners/eks/eks_test.go b/controllers/provisioners/eks/eks_test.go
index 1ab90dd..2e2a3c6 100644
--- a/controllers/provisioners/eks/eks_test.go
+++ b/controllers/provisioners/eks/eks_test.go
@@ -23,6 +23,8 @@ import (
 	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/service/autoscaling"
 	"github.com/aws/aws-sdk-go/service/autoscaling/autoscalingiface"
+	"github.com/aws/aws-sdk-go/service/eks"
+	"github.com/aws/aws-sdk-go/service/eks/eksiface"
 	"github.com/aws/aws-sdk-go/service/iam"
 	"github.com/aws/aws-sdk-go/service/iam/iamiface"
 	"github.com/keikoproj/instance-manager/api/v1alpha1"
@@ -58,10 +60,15 @@ func NewIamMocker() *MockIamClient {
 	return &MockIamClient{}
 }
 
-func MockAwsWorker(asgClient *MockAutoScalingClient, iamClient *MockIamClient) awsprovider.AwsWorker {
+func NewEksMocker() *MockEksClient {
+	return &MockEksClient{}
+}
+
+func MockAwsWorker(asgClient *MockAutoScalingClient, iamClient *MockIamClient, eksClient *MockEksClient) awsprovider.AwsWorker {
 	return awsprovider.AwsWorker{
 		AsgClient: asgClient,
 		IamClient: iamClient,
+		EksClient: eksClient,
 	}
 }
 
@@ -361,6 +368,16 @@ func (a *MockAutoScalingClient) UpdateAutoScalingGroup(input *autoscaling.Update
 	return &autoscaling.UpdateAutoScalingGroupOutput{}, a.UpdateAutoScalingGroupErr
 }
 
+type MockEksClient struct {
+	eksiface.EKSAPI
+	DescribeClusterErr error
+	EksCluster         *eks.Cluster
+}
+
+func (e *MockEksClient) DescribeCluster(input *eks.DescribeClusterInput) (*eks.DescribeClusterOutput, error) {
+	return &eks.DescribeClusterOutput{Cluster: e.EksCluster}, e.DescribeClusterErr
+}
+
 type MockIamClient struct {
 	iamiface.IAMAPI
 	CreateRoleErr                     error
diff --git a/controllers/provisioners/eks/helpers_test.go b/controllers/provisioners/eks/helpers_test.go
index af02ee8..0355b48 100644
--- a/controllers/provisioners/eks/helpers_test.go
+++ b/controllers/provisioners/eks/helpers_test.go
@@ -18,7 +18,9 @@ package eks
 import (
 	"testing"
 
+	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/service/autoscaling"
+	"github.com/aws/aws-sdk-go/service/eks"
 	awsprovider "github.com/keikoproj/instance-manager/controllers/providers/aws"
 	kubeprovider "github.com/keikoproj/instance-manager/controllers/providers/kubernetes"
 	"github.com/onsi/gomega"
@@ -31,9 +33,10 @@ func TestGetDisabledMetrics(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 
 	// No disable required
@@ -89,9 +92,10 @@ func TestGetEnabledMetrics(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 
 	// Enable all metrics
@@ -124,3 +128,73 @@ func TestGetEnabledMetrics(t *testing.T) {
 	g.Expect(ok).To(gomega.BeTrue())
 	g.Expect(metrics).To(gomega.ContainElement("GroupMaxSize"))
 }
+
+func TestGetLabelList(t *testing.T) {
+	var (
+		g                        = gomega.NewGomegaWithT(t)
+		k                        = MockKubernetesClientSet()
+		ig                       = MockInstanceGroup()
+		configuration            = ig.GetEKSConfiguration()
+		asgMock                  = NewAutoScalingMocker()
+		iamMock                  = NewIamMocker()
+		eksMock                  = NewEksMocker()
+		expectedLabels115        = []string{"node.kubernetes.io/role=instance-group-1", "node-role.kubernetes.io/instance-group-1=\"\""}
+		expectedLabels116        = []string{"node.kubernetes.io/role=instance-group-1"}
+		expectedLabelsWithCustom = []string{"node.kubernetes.io/role=instance-group-1", "testing.kubernetes.io=customlabel"}
+	)
+
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
+	ctx := MockContext(ig, k, w)
+
+	ctx.SetDiscoveredState(&DiscoveredState{
+		Publisher: kubeprovider.EventPublisher{
+			Client: k.Kubernetes,
+		},
+		Cluster: &eks.Cluster{
+			Version: aws.String("1.15"),
+		},
+	})
+
+	labels := ctx.GetLabelList()
+
+	g.Expect(labels).To(gomega.ConsistOf(expectedLabels115))
+
+	ctx.SetDiscoveredState(&DiscoveredState{
+		Publisher: kubeprovider.EventPublisher{
+			Client: k.Kubernetes,
+		},
+		Cluster: &eks.Cluster{
+			Version: aws.String("1.16"),
+		},
+	})
+
+	labels = ctx.GetLabelList()
+
+	g.Expect(labels).To(gomega.ConsistOf(expectedLabels116))
+	configuration.SetLabels(map[string]string{"testing.kubernetes.io": "customlabel"})
+	ctx.SetDiscoveredState(&DiscoveredState{
+		Publisher: kubeprovider.EventPublisher{
+			Client: k.Kubernetes,
+		},
+		Cluster: &eks.Cluster{
+			Version: aws.String("1.16"),
+		},
+	})
+
+	labels = ctx.GetLabelList()
+
+	g.Expect(labels).To(gomega.ConsistOf(expectedLabelsWithCustom))
+	configuration.SetLabels(map[string]string{})
+	ctx.SetDiscoveredState(&DiscoveredState{
+		Publisher: kubeprovider.EventPublisher{
+			Client: k.Kubernetes,
+		},
+		Cluster: &eks.Cluster{
+			Version: aws.String(""),
+		},
+	})
+
+	labels = ctx.GetLabelList()
+
+	g.Expect(labels).To(gomega.ConsistOf(expectedLabels115))
+}
diff --git a/controllers/provisioners/eks/state_test.go b/controllers/provisioners/eks/state_test.go
index 81ea238..6003cbc 100644
--- a/controllers/provisioners/eks/state_test.go
+++ b/controllers/provisioners/eks/state_test.go
@@ -34,9 +34,10 @@ func TestStateDiscovery(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 
 	tests := []struct {
@@ -83,9 +84,10 @@ func TestIsReady(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 
 	tests := []struct {
diff --git a/controllers/provisioners/eks/update_test.go b/controllers/provisioners/eks/update_test.go
index 606b191..380a601 100644
--- a/controllers/provisioners/eks/update_test.go
+++ b/controllers/provisioners/eks/update_test.go
@@ -22,6 +22,7 @@ import (
 
 	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/service/autoscaling"
+	"github.com/aws/aws-sdk-go/service/eks"
 	"github.com/aws/aws-sdk-go/service/iam"
 	"github.com/keikoproj/instance-manager/api/v1alpha1"
 	"github.com/onsi/gomega"
@@ -37,11 +38,21 @@ func TestUpdateScalingGroupPositive(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 
+	ctx.SetDiscoveredState(&DiscoveredState{
+		Publisher: kubeprovider.EventPublisher{
+			Client: k.Kubernetes,
+		},
+		Cluster: &eks.Cluster{
+			Version: aws.String("1.15"),
+		},
+	})
+
 	mockTags := []map[string]string{
 		{
 			"key":   "some-tag",
@@ -97,6 +108,9 @@ func TestUpdateScalingGroupPositive(t *testing.T) {
 		Publisher: kubeprovider.EventPublisher{
 			Client: k.Kubernetes,
 		},
+		Cluster: &eks.Cluster{
+			Version: aws.String("1.15"),
+		},
 		ScalingGroup:                  mockScalingGroup,
 		ActiveLaunchConfigurationName: "some-launch-config",
 		LaunchConfiguration:           mockLaunchConfig,
@@ -116,9 +130,10 @@ func TestUpdateWithDriftRotationPositive(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 
 	mockScalingGroup := &autoscaling.Group{
@@ -170,6 +185,9 @@ func TestUpdateWithDriftRotationPositive(t *testing.T) {
 			Arn: aws.String("some-instance-arn"),
 		},
 		ClusterNodes: nodes,
+		Cluster: &eks.Cluster{
+			Version: aws.String("1.15"),
+		},
 	})
 
 	err = ctx.Update()
@@ -185,11 +203,21 @@ func TestUpdateWithRotationPositive(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 
+	ctx.SetDiscoveredState(&DiscoveredState{
+		Publisher: kubeprovider.EventPublisher{
+			Client: k.Kubernetes,
+		},
+		Cluster: &eks.Cluster{
+			Version: aws.String("1.15"),
+		},
+	})
+
 	// avoid drift / rotation
 	input := ctx.GetLaunchConfigurationInput("some-launch-config")
 	mockLaunchConfig := MockLaunchConfigFromInput(input)
@@ -235,6 +263,9 @@ func TestUpdateWithRotationPositive(t *testing.T) {
 		ActiveLaunchConfigurationName: "some-launch-config",
 		LaunchConfiguration:           mockLaunchConfig,
 		ClusterNodes:                  nodes,
+		Cluster: &eks.Cluster{
+			Version: aws.String("1.15"),
+		},
 	})
 
 	err = ctx.Update()
@@ -249,10 +280,21 @@ func TestLaunchConfigurationDrifted(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
+
+	ctx.SetDiscoveredState(&DiscoveredState{
+		Publisher: kubeprovider.EventPublisher{
+			Client: k.Kubernetes,
+		},
+		Cluster: &eks.Cluster{
+			Version: aws.String("1.15"),
+		},
+	})
+
 	input := ctx.GetLaunchConfigurationInput("some-launch-config")
 
 	var (
@@ -298,6 +340,9 @@ func TestLaunchConfigurationDrifted(t *testing.T) {
 			},
 			ActiveLaunchConfigurationName: "some-launch-config",
 			LaunchConfiguration:           tc.input,
+			Cluster: &eks.Cluster{
+				Version: aws.String("1.15"),
+			},
 		})
 		got := ctx.LaunchConfigurationDrifted()
 		g.Expect(got).To(gomega.Equal(tc.expected))
@@ -311,9 +356,10 @@ func TestUpdateScalingGroupNegative(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 	ig.GetEKSConfiguration().SetMetricsCollection([]string{"GroupMinSize", "GroupMaxSize", "GroupDesiredCapacity"})
 
@@ -332,6 +378,9 @@ func TestUpdateScalingGroupNegative(t *testing.T) {
 		InstanceProfile: &iam.InstanceProfile{
 			Arn: aws.String("some-instance-arn"),
 		},
+		Cluster: &eks.Cluster{
+			Version: aws.String("1.15"),
+		},
 	})
 
 	asgMock.UpdateAutoScalingGroupErr = errors.New("some-update-error")
@@ -380,9 +429,10 @@ func TestScalingGroupUpdatePredicate(t *testing.T) {
 		configuration = ig.GetEKSConfiguration()
 		asgMock       = NewAutoScalingMocker()
 		iamMock       = NewIamMocker()
+		eksMock       = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 	spec.MinSize = int64(3)
 	spec.MaxSize = int64(6)
@@ -429,9 +479,10 @@ func TestUpdateManagedPolicies(t *testing.T) {
 		configuration = ig.GetEKSConfiguration()
 		asgMock       = NewAutoScalingMocker()
 		iamMock       = NewIamMocker()
+		eksMock       = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 
 	tests := []struct {
diff --git a/controllers/provisioners/eks/upgrade_test.go b/controllers/provisioners/eks/upgrade_test.go
index 9cde740..3fb15c7 100644
--- a/controllers/provisioners/eks/upgrade_test.go
+++ b/controllers/provisioners/eks/upgrade_test.go
@@ -111,9 +111,10 @@ func TestUpgradeInvalidStrategy(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 
 	// assume initial state of modifying
@@ -132,9 +133,10 @@ func TestBootstrapNodes(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 
 	// assume initial state of modifying
@@ -152,9 +154,10 @@ func TestUpgradeCRDStrategy(t *testing.T) {
 		crd     = MockCustomResourceDefinition()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 	ctx.SetDiscoveredState(&DiscoveredState{
 		Publisher: kubeprovider.EventPublisher{
@@ -215,9 +218,10 @@ func TestUpgradeRollingUpdateStrategyPositive(t *testing.T) {
 		ig      = MockInstanceGroup()
 		asgMock = NewAutoScalingMocker()
 		iamMock = NewIamMocker()
+		eksMock = NewEksMocker()
 	)
 
-	w := MockAwsWorker(asgMock, iamMock)
+	w := MockAwsWorker(asgMock, iamMock, eksMock)
 	ctx := MockContext(ig, k, w)
 
 	tests := []struct {