Merge pull request #6512 from gambol99/launch_templates

Launch Template Feature Flag
This commit is contained in:
Kubernetes Prow Robot 2019-03-17 22:37:09 -07:00 committed by GitHub
commit a60dc513e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 112 additions and 79 deletions

View File

@ -32,67 +32,84 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
) )
// Bool returns a pointer to the boolean value const (
func Bool(b bool) *bool { // Name is the name of the environment variable which encapsulates feature flags
return &b Name = "KOPS_FEATURE_FLAGS"
} )
// 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
func init() { 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 { type FeatureFlag struct {
Key string Key string
enabled *bool enabled *bool
defaultValue *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 { func (f *FeatureFlag) Enabled() bool {
if f.enabled != nil { if f.enabled != nil {
return *f.enabled return *f.enabled
@ -103,6 +120,12 @@ func (f *FeatureFlag) Enabled() bool {
return false 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) { func ParseFlags(f string) {
f = strings.TrimSpace(f) f = strings.TrimSpace(f)
for _, s := range strings.Split(f, ",") { for _, s := range strings.Split(f, ",") {
@ -124,22 +147,3 @@ func ParseFlags(f string) {
ff.enabled = &enabled 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
}

View File

@ -77,7 +77,6 @@ func (b *AutoscalingGroupModelBuilder) Build(c *fi.ModelBuilderContext) error {
default: default:
tsk.LaunchConfiguration = task.(*awstasks.LaunchConfiguration) tsk.LaunchConfiguration = task.(*awstasks.LaunchConfiguration)
} }
c.AddTask(tsk) c.AddTask(tsk)
// @step: add any external load balancer attachments // @step: add any external load balancer attachments

View File

@ -18,6 +18,7 @@ package awsmodel
import ( import (
"k8s.io/kops/pkg/apis/kops" "k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/featureflag"
"k8s.io/kops/pkg/model" "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 // UseLaunchTemplate checks if we need to use a launch template rather than configuration
func UseLaunchTemplate(ig *kops.InstanceGroup) bool { 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
} }

View File

@ -46,7 +46,7 @@ func (b *StorageAclBuilder) Build(c *fi.ModelBuilderContext) error {
return fmt.Errorf("error fetching ServiceAccount: %v", err) return fmt.Errorf("error fetching ServiceAccount: %v", err)
} }
if featureflag.GoogleCloudBucketAcl.Enabled() { if featureflag.GoogleCloudBucketACL.Enabled() {
clusterPath := b.Cluster.Spec.ConfigBase clusterPath := b.Cluster.Spec.ConfigBase
p, err := vfs.Context.BuildVfsPath(clusterPath) p, err := vfs.Context.BuildVfsPath(clusterPath)
if err != nil { if err != nil {

View File

@ -252,10 +252,20 @@ func (v *AutoscalingGroup) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *Autos
VPCZoneIdentifier: fi.String(strings.Join(e.AutoscalingGroupSubnets(), ",")), VPCZoneIdentifier: fi.String(strings.Join(e.AutoscalingGroupSubnets(), ",")),
} }
// @check are we using a launchconfiguation
if e.LaunchConfiguration != nil { if e.LaunchConfiguration != nil {
request.LaunchConfigurationName = e.LaunchConfiguration.ID 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() { 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{ request.MixedInstancesPolicy = &autoscaling.MixedInstancesPolicy{
InstancesDistribution: &autoscaling.InstancesDistribution{ InstancesDistribution: &autoscaling.InstancesDistribution{
OnDemandPercentageAboveBaseCapacity: e.MixedOnDemandAboveBase, OnDemandPercentageAboveBaseCapacity: e.MixedOnDemandAboveBase,
@ -464,12 +474,21 @@ func (e *AutoscalingGroup) UseMixedInstancesPolicy() bool {
if e.LaunchTemplate == nil { if e.LaunchTemplate == nil {
return false return false
} }
items := []interface{}{e.MixedOnDemandAboveBase, e.MixedOnDemandBase, e.MixedSpotAllocationStrategy, e.MixedSpotInstancePools} // @check if any of the mixed instance policies settings are toggled
if e.MixedOnDemandAboveBase != nil {
for _, x := range items { return true
if x != 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 return false