diff --git a/pkg/featureflag/featureflag.go b/pkg/featureflag/featureflag.go index a8e053b219..d5a2669451 100644 --- a/pkg/featureflag/featureflag.go +++ b/pkg/featureflag/featureflag.go @@ -32,67 +32,84 @@ import ( "github.com/golang/glog" ) -// Bool returns a pointer to the boolean value -func Bool(b bool) *bool { - return &b -} - -// ExperimentalClusterDNS allows for setting the kubelet dns flag to experimental values. -// It allows for experiments with alternative DNS configurations - in particular local proxies. -var ExperimentalClusterDNS = New("ExperimentalClusterDNS", Bool(false)) - -// KeepLaunchConfigurations can be set to prevent garbage collection of old launch configurations -var KeepLaunchConfigurations = New("KeepLaunchConfigurations", Bool(false)) - -// DNSPreCreate controls whether we pre-create DNS records. -var DNSPreCreate = New("DNSPreCreate", Bool(true)) - -// DrainAndValidateRollingUpdate if set will use new rolling update code that will drain and validate. -var DrainAndValidateRollingUpdate = New("DrainAndValidateRollingUpdate", Bool(true)) - -// VPCSkipEnableDNSSupport if set will make that a VPC does not need DNSSupport enabled. -var VPCSkipEnableDNSSupport = New("VPCSkipEnableDNSSupport", Bool(false)) - -// SkipTerraformFormat if set will mean that we will not `tf fmt` the generated terraform. -var SkipTerraformFormat = New("SkipTerraformFormat", Bool(false)) - -var VSphereCloudProvider = New("VSphereCloudProvider", Bool(false)) - -var EnableExternalDNS = New("EnableExternalDNS", Bool(false)) - -//EnableExternalCloudController toggles the use of cloud-controller-manager introduced in v1.7 -var EnableExternalCloudController = New("EnableExternalCloudController", Bool(false)) - -// EnableSeparateConfigBase allows a config-base that is different from the state store -var EnableSeparateConfigBase = New("EnableSeparateConfigBase", Bool(false)) - -// SpecOverrideFlag allows setting spec values on create -var SpecOverrideFlag = New("SpecOverrideFlag", Bool(false)) - -// GoogleCloudBucketAcl means the ACL will be set on a bucket when using GCS -// In particular, this is the only (?) way to grant the bucket.list permission -// However we should no longer need it, with the keyset.yaml fix -var GoogleCloudBucketAcl = New("GoogleCloudBucketAcl", Bool(false)) - -// EnableNodeAuthorization enables the node authorization features -var EnableNodeAuthorization = New("EnableNodeAuthorization", Bool(false)) - -// Spotinst toggles the use of Spotinst integration. -var Spotinst = New("Spotinst", Bool(false)) - -var flags = make(map[string]*FeatureFlag) -var flagsMutex sync.Mutex +const ( + // Name is the name of the environment variable which encapsulates feature flags + Name = "KOPS_FEATURE_FLAGS" +) func init() { - ParseFlags(os.Getenv("KOPS_FEATURE_FLAGS")) + ParseFlags(os.Getenv(Name)) } +var ( + flags = make(map[string]*FeatureFlag) + flagsMutex sync.Mutex +) + +var ( + // DNSPreCreate controls whether we pre-create DNS records. + DNSPreCreate = New("DNSPreCreate", Bool(true)) + // DrainAndValidateRollingUpdate if set will use new rolling update code that will drain and validate. + DrainAndValidateRollingUpdate = New("DrainAndValidateRollingUpdate", Bool(true)) + // EnableLaunchTemplates indicates we wish to switch to using launch templates rather than launchconfigurations + EnableLaunchTemplates = New("EnableLaunchTemplates", Bool(false)) + //EnableExternalCloudController toggles the use of cloud-controller-manager introduced in v1.7 + EnableExternalCloudController = New("EnableExternalCloudController", Bool(false)) + // EnableExternalDNS enables external DNS + EnableExternalDNS = New("EnableExternalDNS", Bool(false)) + // EnableNodeAuthorization enables the node authorization features + EnableNodeAuthorization = New("EnableNodeAuthorization", Bool(false)) + // EnableSeparateConfigBase allows a config-base that is different from the state store + EnableSeparateConfigBase = New("EnableSeparateConfigBase", Bool(false)) + // ExperimentalClusterDNS allows for setting the kubelet dns flag to experimental values. + ExperimentalClusterDNS = New("ExperimentalClusterDNS", Bool(false)) + // GoogleCloudBucketACL means the ACL will be set on a bucket when using GCS + GoogleCloudBucketACL = New("GoogleCloudBucketAcl", Bool(false)) + // KeepLaunchConfigurations can be set to prevent garbage collection of old launch configurations + KeepLaunchConfigurations = New("KeepLaunchConfigurations", Bool(false)) + // SkipTerraformFormat if set means we will not `tf fmt` the generated terraform. + // However we should no longer need it, with the keyset.yaml fix + // In particular, this is the only (?) way to grant the bucket.list permission + // It allows for experiments with alternative DNS configurations - in particular local proxies. + SkipTerraformFormat = New("SkipTerraformFormat", Bool(false)) + // SpecOverrideFlag allows setting spec values on create + SpecOverrideFlag = New("SpecOverrideFlag", Bool(false)) + // Spotinst toggles the use of Spotinst integration. + Spotinst = New("Spotinst", Bool(false)) + // VPCSkipEnableDNSSupport if set will make that a VPC does not need DNSSupport enabled. + VPCSkipEnableDNSSupport = New("VPCSkipEnableDNSSupport", Bool(false)) + // VSphereCloudProvider enables the vsphere cloud provider + VSphereCloudProvider = New("VSphereCloudProvider", Bool(false)) +) + +// FeatureFlag defines a feature flag type FeatureFlag struct { Key string enabled *bool defaultValue *bool } +// New creates a new feature flag +func New(key string, defaultValue *bool) *FeatureFlag { + flagsMutex.Lock() + defer flagsMutex.Unlock() + + f := flags[key] + if f == nil { + f = &FeatureFlag{ + Key: key, + } + flags[key] = f + } + + if f.defaultValue == nil { + f.defaultValue = defaultValue + } + + return f +} + +// Enabled checks if the flag is enabled func (f *FeatureFlag) Enabled() bool { if f.enabled != nil { return *f.enabled @@ -103,6 +120,12 @@ func (f *FeatureFlag) Enabled() bool { return false } +// Bool returns a pointer to the boolean value +func Bool(b bool) *bool { + return &b +} + +// ParseFlags responsible for parse out the feature flag usage func ParseFlags(f string) { f = strings.TrimSpace(f) for _, s := range strings.Split(f, ",") { @@ -124,22 +147,3 @@ func ParseFlags(f string) { ff.enabled = &enabled } } - -func New(key string, defaultValue *bool) *FeatureFlag { - flagsMutex.Lock() - defer flagsMutex.Unlock() - - f := flags[key] - if f == nil { - f = &FeatureFlag{ - Key: key, - } - flags[key] = f - } - - if f.defaultValue == nil { - f.defaultValue = defaultValue - } - - return f -} diff --git a/pkg/model/awsmodel/autoscalinggroup.go b/pkg/model/awsmodel/autoscalinggroup.go index b4c596ae84..5be6de4e6c 100644 --- a/pkg/model/awsmodel/autoscalinggroup.go +++ b/pkg/model/awsmodel/autoscalinggroup.go @@ -77,7 +77,6 @@ func (b *AutoscalingGroupModelBuilder) Build(c *fi.ModelBuilderContext) error { default: tsk.LaunchConfiguration = task.(*awstasks.LaunchConfiguration) } - c.AddTask(tsk) // @step: add any external load balancer attachments diff --git a/pkg/model/awsmodel/context.go b/pkg/model/awsmodel/context.go index 74e1afdf14..2a3c922c4d 100644 --- a/pkg/model/awsmodel/context.go +++ b/pkg/model/awsmodel/context.go @@ -18,6 +18,7 @@ package awsmodel import ( "k8s.io/kops/pkg/apis/kops" + "k8s.io/kops/pkg/featureflag" "k8s.io/kops/pkg/model" ) @@ -28,5 +29,15 @@ type AWSModelContext struct { // UseLaunchTemplate checks if we need to use a launch template rather than configuration func UseLaunchTemplate(ig *kops.InstanceGroup) bool { - return ig.Spec.MixedInstancesPolicy != nil + if featureflag.EnableLaunchTemplates.Enabled() { + return true + } + // @note: this mixed instance polices was added before the feature flag, to keep the + // same behviour we also check this. But since the feature hasn't been cut into a tagged + // release it possible to use just the feature flag?? + if ig.Spec.MixedInstancesPolicy != nil { + return true + } + + return false } diff --git a/pkg/model/gcemodel/storageacl.go b/pkg/model/gcemodel/storageacl.go index daa69a141b..05c7420860 100644 --- a/pkg/model/gcemodel/storageacl.go +++ b/pkg/model/gcemodel/storageacl.go @@ -46,7 +46,7 @@ func (b *StorageAclBuilder) Build(c *fi.ModelBuilderContext) error { return fmt.Errorf("error fetching ServiceAccount: %v", err) } - if featureflag.GoogleCloudBucketAcl.Enabled() { + if featureflag.GoogleCloudBucketACL.Enabled() { clusterPath := b.Cluster.Spec.ConfigBase p, err := vfs.Context.BuildVfsPath(clusterPath) if err != nil { diff --git a/upup/pkg/fi/cloudup/awstasks/autoscalinggroup.go b/upup/pkg/fi/cloudup/awstasks/autoscalinggroup.go index 01417e9f5b..35c9a93af7 100644 --- a/upup/pkg/fi/cloudup/awstasks/autoscalinggroup.go +++ b/upup/pkg/fi/cloudup/awstasks/autoscalinggroup.go @@ -252,10 +252,20 @@ func (v *AutoscalingGroup) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *Autos VPCZoneIdentifier: fi.String(strings.Join(e.AutoscalingGroupSubnets(), ",")), } + // @check are we using a launchconfiguation if e.LaunchConfiguration != nil { request.LaunchConfigurationName = e.LaunchConfiguration.ID } + // @check are we using launch template + if e.LaunchTemplate != nil { + request.LaunchTemplate = &autoscaling.LaunchTemplateSpecification{ + LaunchTemplateName: e.LaunchTemplate.ID, + } + } + // @check if we are using mixed instance policies if e.UseMixedInstancesPolicy() { + // we can zero this out for now and use the mixed instance policy for definition + request.LaunchTemplate = nil request.MixedInstancesPolicy = &autoscaling.MixedInstancesPolicy{ InstancesDistribution: &autoscaling.InstancesDistribution{ OnDemandPercentageAboveBaseCapacity: e.MixedOnDemandAboveBase, @@ -464,12 +474,21 @@ func (e *AutoscalingGroup) UseMixedInstancesPolicy() bool { if e.LaunchTemplate == nil { return false } - items := []interface{}{e.MixedOnDemandAboveBase, e.MixedOnDemandBase, e.MixedSpotAllocationStrategy, e.MixedSpotInstancePools} - - for _, x := range items { - if x != nil { - return true - } + // @check if any of the mixed instance policies settings are toggled + if e.MixedOnDemandAboveBase != nil { + return true + } + if e.MixedOnDemandBase != nil { + return true + } + if e.MixedSpotAllocationStrategy != nil { + return true + } + if e.MixedSpotInstancePools != nil { + return true + } + if len(e.MixedInstanceOverrides) > 0 { + return true } return false