diff --git a/api/v1alpha1/instancegroup_types.go b/api/v1alpha1/instancegroup_types.go index 0c616113..2dcfb1ec 100644 --- a/api/v1alpha1/instancegroup_types.go +++ b/api/v1alpha1/instancegroup_types.go @@ -227,6 +227,7 @@ type EKSConfiguration struct { MixedInstancesPolicy *MixedInstancesPolicySpec `json:"mixedInstancesPolicy,omitempty"` LicenseSpecifications []string `json:"licenseSpecifications,omitempty"` Placement *PlacementSpec `json:"placement,omitempty"` + MetadataOptions *MetadataOptions `json:"metadataOptions,omitempty"` } const ( @@ -250,6 +251,12 @@ type PlacementSpec struct { Tenancy string `json:"tenancy,omitempty"` } +type MetadataOptions struct { + HttpEndpoint string `json:"httpEndpoint,omitempty"` + HttpTokens string `json:"httpTokens,omitempty"` + HttpPutHopLimit int64 `json:"httpPutHopLimit,omitempty"` +} + type InstanceTypeSpec struct { Type string `json:"type"` Weight int64 `json:"weight,omitempty"` @@ -721,6 +728,9 @@ func (c *EKSConfiguration) GetRoleName() string { func (c *EKSConfiguration) GetMixedInstancesPolicy() *MixedInstancesPolicySpec { return c.MixedInstancesPolicy } +func (c *EKSConfiguration) GetMetadataOptions() *MetadataOptions { + return c.MetadataOptions +} func (c *EKSConfiguration) GetPlacement() *PlacementSpec { return c.Placement } diff --git a/api/v1alpha1/instancegroup_types_test.go b/api/v1alpha1/instancegroup_types_test.go index c3188d16..3160dce5 100644 --- a/api/v1alpha1/instancegroup_types_test.go +++ b/api/v1alpha1/instancegroup_types_test.go @@ -231,6 +231,35 @@ func TestInstanceGroupSpecValidate(t *testing.T) { }, want: "", }, + { + name: "eks with metadataoptions validates", + args: args{ + instancegroup: MockInstanceGroup("eks", "rollingUpdate", &EKSSpec{ + MaxSize: 1, + MinSize: 1, + Type: "LaunchTemplate", + EKSConfiguration: &EKSConfiguration{ + EksClusterName: "my-eks-cluster", + NodeSecurityGroups: []string{"sg-123456789"}, + Image: "ami-12345", + InstanceType: "m5.large", + KeyPairName: "thisShouldBeOptional", + Subnets: []string{"subnet-1111111", "subnet-222222"}, + Placement: &PlacementSpec{ + AvailabilityZone: "us-west-2a", + HostResourceGroupArn: "arn:aws:resource-groups:us-west-2:1122334455:group/resourceName", + Tenancy: "host", + }, + MetadataOptions: &MetadataOptions{ + HttpEndpoint: "enabled", + HttpTokens: "required", + HttpPutHopLimit: 1, + }, + }, + }, nil, nil), + }, + want: "", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 5ec42fe8..90f591c7 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -177,6 +177,11 @@ func (in *EKSConfiguration) DeepCopyInto(out *EKSConfiguration) { *out = new(PlacementSpec) **out = **in } + if in.MetadataOptions != nil { + in, out := &in.MetadataOptions, &out.MetadataOptions + *out = new(MetadataOptions) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EKSConfiguration. @@ -496,6 +501,21 @@ func (in *LifecycleHookSpec) DeepCopy() *LifecycleHookSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetadataOptions) DeepCopyInto(out *MetadataOptions) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetadataOptions. +func (in *MetadataOptions) DeepCopy() *MetadataOptions { + if in == nil { + return nil + } + out := new(MetadataOptions) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MixedInstancesPolicySpec) DeepCopyInto(out *MixedInstancesPolicySpec) { *out = *in diff --git a/config/crd/bases/instancemgr.keikoproj.io_instancegroups.yaml b/config/crd/bases/instancemgr.keikoproj.io_instancegroups.yaml index cea433d9..3021d8e6 100644 --- a/config/crd/bases/instancemgr.keikoproj.io_instancegroups.yaml +++ b/config/crd/bases/instancemgr.keikoproj.io_instancegroups.yaml @@ -124,6 +124,16 @@ spec: items: type: string type: array + metadataOptions: + properties: + httpEndpoint: + type: string + httpPutHopLimit: + format: int64 + type: integer + httpTokens: + type: string + type: object metricsCollection: items: type: string diff --git a/controllers/provisioners/eks/create.go b/controllers/provisioners/eks/create.go index c426209c..e8392151 100644 --- a/controllers/provisioners/eks/create.go +++ b/controllers/provisioners/eks/create.go @@ -44,6 +44,7 @@ func (ctx *EksInstanceGroupContext) Create() error { sgs = ctx.ResolveSecurityGroups() spotPrice = configuration.GetSpotPrice() placement = configuration.GetPlacement() + metadataOptions = configuration.GetMetadataOptions() ) ctx.SetState(v1alpha1.ReconcileModifying) @@ -73,6 +74,7 @@ func (ctx *EksInstanceGroupContext) Create() error { SpotPrice: spotPrice, LicenseSpecifications: configuration.LicenseSpecifications, Placement: placement, + MetadataOptions: metadataOptions, } if err := scalingConfig.Create(config); err != nil { diff --git a/controllers/provisioners/eks/scaling/interface.go b/controllers/provisioners/eks/scaling/interface.go index 09783829..7beb32cc 100644 --- a/controllers/provisioners/eks/scaling/interface.go +++ b/controllers/provisioners/eks/scaling/interface.go @@ -61,6 +61,7 @@ type CreateConfigurationInput struct { SpotPrice string LicenseSpecifications []string Placement *v1alpha1.PlacementSpec + MetadataOptions *v1alpha1.MetadataOptions } func ConvertToLaunchTemplate(resource interface{}) *ec2.LaunchTemplate { diff --git a/controllers/provisioners/eks/scaling/launchconfig.go b/controllers/provisioners/eks/scaling/launchconfig.go index 59897699..186348ff 100644 --- a/controllers/provisioners/eks/scaling/launchconfig.go +++ b/controllers/provisioners/eks/scaling/launchconfig.go @@ -89,6 +89,7 @@ func (lc *LaunchConfiguration) Create(input *CreateConfigurationInput) error { SecurityGroups: aws.StringSlice(input.SecurityGroups), UserData: aws.String(input.UserData), BlockDeviceMappings: devices, + MetadataOptions: lc.metadataOptions(input.MetadataOptions), } if !common.StringEmpty(input.SpotPrice) { @@ -231,6 +232,16 @@ func (lc *LaunchConfiguration) Drifted(input *CreateConfigurationInput) bool { drift = true } + metadataOptions := lc.metadataOptions(input.MetadataOptions) + + if !reflect.DeepEqual(metadataOptions, existingConfig.MetadataOptions) { + log.Info("detected drift", "reason", "metadata options have changed", "instancegroup", lc.OwnerName, + "previousValue", existingConfig.MetadataOptions, + "newValue", metadataOptions, + ) + drift = true + } + if !drift { log.Info("drift not detected", "instancegroup", lc.OwnerName) } @@ -282,6 +293,17 @@ func (lc *LaunchConfiguration) blockDeviceList(volumes []v1alpha1.NodeVolume) [] return sortConfigDevices(devices) } +func (lc *LaunchConfiguration) metadataOptions(input *v1alpha1.MetadataOptions) *autoscaling.InstanceMetadataOptions { + if input == nil { + return nil + } + return &autoscaling.InstanceMetadataOptions{ + HttpEndpoint: aws.String(input.HttpEndpoint), + HttpPutResponseHopLimit: aws.Int64(input.HttpPutHopLimit), + HttpTokens: aws.String(input.HttpTokens), + } +} + func getPrefixedConfigurations(configs []*autoscaling.LaunchConfiguration, prefix string) []*autoscaling.LaunchConfiguration { prefixed := []*autoscaling.LaunchConfiguration{} for _, lc := range configs { diff --git a/controllers/provisioners/eks/scaling/launchconfig_test.go b/controllers/provisioners/eks/scaling/launchconfig_test.go index 6ba2e819..30690c47 100644 --- a/controllers/provisioners/eks/scaling/launchconfig_test.go +++ b/controllers/provisioners/eks/scaling/launchconfig_test.go @@ -475,6 +475,16 @@ func TestLaunchConfigurationDrifted(t *testing.T) { }, shouldDrift: true, }, + { + launchConfig: &autoscaling.LaunchConfiguration{ + LaunchConfigurationName: aws.String("my-launch-config"), + }, + input: &CreateConfigurationInput{ + SecurityGroups: []string{}, + MetadataOptions: &v1alpha1.MetadataOptions{HttpEndpoint: "enabled"}, + }, + shouldDrift: true, + }, } for i, tc := range tests { diff --git a/controllers/provisioners/eks/scaling/launchtemplate.go b/controllers/provisioners/eks/scaling/launchtemplate.go index 0233c861..6a1d269e 100644 --- a/controllers/provisioners/eks/scaling/launchtemplate.go +++ b/controllers/provisioners/eks/scaling/launchtemplate.go @@ -102,6 +102,7 @@ func (lt *LaunchTemplate) Create(input *CreateConfigurationInput) error { BlockDeviceMappings: lt.blockDeviceListRequest(input.Volumes), LicenseSpecifications: lt.LaunchTemplateLicenseConfigurationRequest(input.LicenseSpecifications), Placement: lt.launchTemplatePlacementRequest(input.Placement), + MetadataOptions: lt.metadataOptionsRequest(input.MetadataOptions), } if !lt.Provisioned() { @@ -270,6 +271,16 @@ func (lt *LaunchTemplate) Drifted(input *CreateConfigurationInput) bool { drift = true } + metadataOptions := lt.metadataOptions(input.MetadataOptions) + + if !reflect.DeepEqual(metadataOptions, latestVersion.LaunchTemplateData.MetadataOptions) { + log.Info("detected drift", "reason", "metadata options have changed", "instancegroup", lt.OwnerName, + "previousValue", latestVersion.LaunchTemplateData.MetadataOptions, + "newValue", metadataOptions, + ) + drift = true + } + if !drift { log.Info("drift not detected", "instancegroup", lt.OwnerName) } @@ -345,6 +356,28 @@ func (lt *LaunchTemplate) launchTemplatePlacementRequest(input *v1alpha1.Placeme return lt.LaunchTemplatePlacementRequest(input.AvailabilityZone, input.HostResourceGroupArn, input.Tenancy) } +func (lt *LaunchTemplate) metadataOptions(input *v1alpha1.MetadataOptions) *ec2.LaunchTemplateInstanceMetadataOptions { + if input == nil { + return nil + } + return &ec2.LaunchTemplateInstanceMetadataOptions{ + HttpEndpoint: aws.String(input.HttpEndpoint), + HttpPutResponseHopLimit: aws.Int64(input.HttpPutHopLimit), + HttpTokens: aws.String(input.HttpTokens), + } +} + +func (lt *LaunchTemplate) metadataOptionsRequest(input *v1alpha1.MetadataOptions) *ec2.LaunchTemplateInstanceMetadataOptionsRequest { + if input == nil { + return nil + } + return &ec2.LaunchTemplateInstanceMetadataOptionsRequest{ + HttpEndpoint: aws.String(input.HttpEndpoint), + HttpPutResponseHopLimit: aws.Int64(input.HttpPutHopLimit), + HttpTokens: aws.String(input.HttpTokens), + } +} + func (lt *LaunchTemplate) launchTemplatePlacement(input *v1alpha1.PlacementSpec) *ec2.LaunchTemplatePlacement { if input == nil { return &ec2.LaunchTemplatePlacement{} diff --git a/controllers/provisioners/eks/scaling/launchtemplate_test.go b/controllers/provisioners/eks/scaling/launchtemplate_test.go index 235d2ebc..ce0a894d 100644 --- a/controllers/provisioners/eks/scaling/launchtemplate_test.go +++ b/controllers/provisioners/eks/scaling/launchtemplate_test.go @@ -612,6 +612,16 @@ func TestLaunchTemplateDrifted(t *testing.T) { }, shouldDrift: true, }, + { + launchTemplate: MockLaunchTemplate("my-launch-template"), + latestVersion: MockLaunchTemplateVersion(), + input: &CreateConfigurationInput{ + MetadataOptions: &v1alpha1.MetadataOptions{ + HttpEndpoint: "Enabled", + }, + }, + shouldDrift: true, + }, } for i, tc := range tests { diff --git a/controllers/provisioners/eks/update.go b/controllers/provisioners/eks/update.go index 3c9dabed..17512bfe 100644 --- a/controllers/provisioners/eks/update.go +++ b/controllers/provisioners/eks/update.go @@ -52,6 +52,7 @@ func (ctx *EksInstanceGroupContext) Update() error { sgs = ctx.ResolveSecurityGroups() spotPrice = configuration.GetSpotPrice() placement = configuration.GetPlacement() + metadataOptions = configuration.GetMetadataOptions() ) ctx.SetState(v1alpha1.ReconcileModifying) @@ -75,6 +76,7 @@ func (ctx *EksInstanceGroupContext) Update() error { SpotPrice: spotPrice, LicenseSpecifications: configuration.LicenseSpecifications, Placement: placement, + MetadataOptions: metadataOptions, } // create new launchconfig if it has drifted