-
Notifications
You must be signed in to change notification settings - Fork 4.7k
/
Copy pathfeatureflag.go
170 lines (151 loc) · 5.86 KB
/
featureflag.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package featureflag implements simple feature-flagging.
// Feature flags can become an anti-pattern if abused.
// We should try to use them for two use-cases:
// * `Preview` feature flags enable a piece of functionality we haven't yet fully baked. The user needs to 'opt-in'.
// We expect these flags to be removed at some time. Normally these will default to false.
// * Escape-hatch feature flags turn off a default that we consider risky (e.g. pre-creating DNS records).
// This lets us ship a behaviour, and if we encounter unusual circumstances in the field, we can
// allow the user to turn the behaviour off. Normally these will default to true.
package featureflag
import (
"os"
"strings"
"sync"
"k8s.io/klog/v2"
)
const (
// Name is the name of the environment variable which encapsulates feature flags
Name = "KOPS_FEATURE_FLAGS"
)
func init() {
ParseFlags(os.Getenv(Name))
}
var (
flags = make(map[string]*FeatureFlag)
flagsMutex sync.Mutex
)
var (
// CacheNodeidentityInfo enables NodeidentityInfo caching
// in order to reduce the number of EC2 DescribeInstance calls.
CacheNodeidentityInfo = new("CacheNodeidentityInfo", 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))
// SpecOverrideFlag allows setting spec values on create
SpecOverrideFlag = new("SpecOverrideFlag", Bool(false))
// Spotinst toggles the use of Spotinst integration.
Spotinst = new("Spotinst", Bool(false))
// SpotinstOcean toggles the use of Spotinst Ocean instance group implementation.
SpotinstOcean = new("SpotinstOcean", Bool(false))
// SpotinstOceanTemplate toggles the use of Spotinst Ocean object as a template for Virtual Node Groups.
SpotinstOceanTemplate = new("SpotinstOceanTemplate", Bool(false))
// SpotinstHybrid toggles between hybrid and full instance group implementations.
SpotinstHybrid = new("SpotinstHybrid", Bool(false))
// SpotinstController toggles the installation of the Spotinst controller addon.
SpotinstController = new("SpotinstController", Bool(true))
// VFSVaultSupport enables setting Vault as secret/keystore
VFSVaultSupport = new("VFSVaultSupport", Bool(false))
// VPCSkipEnableDNSSupport if set will make that a VPC does not need DNSSupport enabled.
VPCSkipEnableDNSSupport = new("VPCSkipEnableDNSSupport", Bool(false))
// SkipEtcdVersionCheck will bypass the check that etcd-manager is using a supported etcd version
SkipEtcdVersionCheck = new("SkipEtcdVersionCheck", Bool(false))
// ClusterAddons activates experimental cluster-addons support
ClusterAddons = new("ClusterAddons", Bool(false))
// Azure toggles the Azure support.
Azure = new("Azure", Bool(false))
// KopsControllerStateStore enables fetching the kops state from kops-controller, instead of requiring access to S3/GCS/etc.
KopsControllerStateStore = new("KopsControllerStateStore", Bool(false))
// APIServerNodes enables ability to provision nodes that only run the kube-apiserver.
APIServerNodes = new("APIServerNodes", Bool(false))
// UseAddonOperators activates experimental addon operator support
UseAddonOperators = new("UseAddonOperators", Bool(false))
// TerraformManagedFiles enables rendering managed files into the Terraform configuration.
TerraformManagedFiles = new("TerraformManagedFiles", Bool(true))
// AlphaAllowGCE is a feature flag that gates GCE support while it is alpha.
AlphaAllowGCE = new("AlphaAllowGCE", Bool(false))
// Karpenter enables karpenter-managed Instance Groups
Karpenter = new("Karpenter", Bool(false))
// ImageDigest remaps all manifests with image digests
ImageDigest = new("ImageDigest", Bool(true))
// Hetzner toggles the Hetzner Cloud support.
Hetzner = new("Hetzner", 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
}
if f.defaultValue != nil {
return *f.defaultValue
}
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) {
flagsMutex.Lock()
defer flagsMutex.Unlock()
f = strings.TrimSpace(f)
for _, s := range strings.Split(f, ",") {
s = strings.TrimSpace(s)
if s == "" {
continue
}
enabled := true
var ff *FeatureFlag
if s[0] == '+' || s[0] == '-' {
ff = flags[s[1:]]
if s[0] == '-' {
enabled = false
}
} else {
ff = flags[s]
}
if ff != nil {
klog.Infof("FeatureFlag %q=%v", ff.Key, enabled)
ff.enabled = &enabled
} else {
klog.Infof("Unknown FeatureFlag %q", s)
}
}
}