feature_gate.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. package feature
  2. import (
  3. "flag"
  4. "fmt"
  5. "os"
  6. "sort"
  7. "strconv"
  8. "strings"
  9. "sync"
  10. "sync/atomic"
  11. "github.com/pkg/errors"
  12. )
  13. // Feature is the feature name
  14. type Feature string
  15. const (
  16. flagName = "feature-gates"
  17. )
  18. var (
  19. // DefaultGate is a shared global Gate.
  20. DefaultGate = NewGate()
  21. )
  22. // Spec is the spec of the feature
  23. type Spec struct {
  24. Default bool
  25. }
  26. // Gate parses and stores flag gates for known features from
  27. // a string like feature1=true,feature2=false,...
  28. type Gate interface {
  29. // AddFlag adds a flag for setting global feature gates to the specified FlagSet.
  30. AddFlag(fs *flag.FlagSet)
  31. // Set parses and stores flag gates for known features
  32. // from a string like feature1=true,feature2=false,...
  33. Set(value string) error
  34. // SetFromMap stores flag gates for known features from a map[string]bool or returns an error
  35. SetFromMap(m map[string]bool) error
  36. // Enabled returns true if the key is enabled.
  37. Enabled(key Feature) bool
  38. // Add adds features to the featureGate.
  39. Add(features map[Feature]Spec) error
  40. // KnownFeatures returns a slice of strings describing the Gate's known features.
  41. KnownFeatures() []string
  42. // DeepCopy returns a deep copy of the Gate object, such that gates can be
  43. // set on the copy without mutating the original. This is useful for validating
  44. // config against potential feature gate changes before committing those changes.
  45. DeepCopy() Gate
  46. }
  47. // featureGate implements Gate as well as flag.Value for flag parsing.
  48. type featureGate struct {
  49. // lock guards writes to known, enabled, and reads/writes of closed
  50. lock sync.Mutex
  51. // known holds a map[Feature]Spec
  52. known atomic.Value
  53. // enabled holds a map[Feature]bool
  54. enabled atomic.Value
  55. // closed is set to true when AddFlag is called, and prevents subsequent calls to Add
  56. closed bool
  57. }
  58. // Set, String, and Type implement flag.Value
  59. var _ flag.Value = &featureGate{}
  60. // NewGate create a feature gate.
  61. func NewGate() *featureGate {
  62. known := map[Feature]Spec{}
  63. knownValue := atomic.Value{}
  64. knownValue.Store(known)
  65. enabled := map[Feature]bool{}
  66. enabledValue := atomic.Value{}
  67. enabledValue.Store(enabled)
  68. f := &featureGate{
  69. known: knownValue,
  70. enabled: enabledValue,
  71. }
  72. return f
  73. }
  74. // Set parses a string of the form "key1=value1,key2=value2,..." into a
  75. // map[string]bool of known keys or returns an error.
  76. func (f *featureGate) Set(value string) error {
  77. f.lock.Lock()
  78. defer f.lock.Unlock()
  79. // Copy existing state
  80. known := map[Feature]Spec{}
  81. for k, v := range f.known.Load().(map[Feature]Spec) {
  82. known[k] = v
  83. }
  84. enabled := map[Feature]bool{}
  85. for k, v := range f.enabled.Load().(map[Feature]bool) {
  86. enabled[k] = v
  87. }
  88. for _, s := range strings.Split(value, ",") {
  89. if len(s) == 0 {
  90. continue
  91. }
  92. arr := strings.SplitN(s, "=", 2)
  93. k := Feature(strings.TrimSpace(arr[0]))
  94. _, ok := known[k]
  95. if !ok {
  96. return errors.Errorf("unrecognized key: %s", k)
  97. }
  98. if len(arr) != 2 {
  99. return errors.Errorf("missing bool value for %s", k)
  100. }
  101. v := strings.TrimSpace(arr[1])
  102. boolValue, err := strconv.ParseBool(v)
  103. if err != nil {
  104. return errors.Errorf("invalid value of %s: %s, err: %v", k, v, err)
  105. }
  106. enabled[k] = boolValue
  107. }
  108. // Persist changes
  109. f.known.Store(known)
  110. f.enabled.Store(enabled)
  111. fmt.Fprintf(os.Stderr, "feature gates: %v", enabled)
  112. return nil
  113. }
  114. // SetFromMap stores flag gates for known features from a map[string]bool or returns an error
  115. func (f *featureGate) SetFromMap(m map[string]bool) error {
  116. f.lock.Lock()
  117. defer f.lock.Unlock()
  118. // Copy existing state
  119. known := map[Feature]Spec{}
  120. for k, v := range f.known.Load().(map[Feature]Spec) {
  121. known[k] = v
  122. }
  123. enabled := map[Feature]bool{}
  124. for k, v := range f.enabled.Load().(map[Feature]bool) {
  125. enabled[k] = v
  126. }
  127. for k, v := range m {
  128. k := Feature(k)
  129. _, ok := known[k]
  130. if !ok {
  131. return errors.Errorf("unrecognized key: %s", k)
  132. }
  133. enabled[k] = v
  134. }
  135. // Persist changes
  136. f.known.Store(known)
  137. f.enabled.Store(enabled)
  138. fmt.Fprintf(os.Stderr, "feature gates: %v", f.enabled)
  139. return nil
  140. }
  141. // String returns a string containing all enabled feature gates, formatted as "key1=value1,key2=value2,...".
  142. func (f *featureGate) String() string {
  143. pairs := []string{}
  144. enabled, ok := f.enabled.Load().(map[Feature]bool)
  145. if !ok {
  146. return ""
  147. }
  148. for k, v := range enabled {
  149. pairs = append(pairs, fmt.Sprintf("%s=%t", k, v))
  150. }
  151. sort.Strings(pairs)
  152. return strings.Join(pairs, ",")
  153. }
  154. func (f *featureGate) Type() string {
  155. return "mapStringBool"
  156. }
  157. // Add adds features to the featureGate.
  158. func (f *featureGate) Add(features map[Feature]Spec) error {
  159. f.lock.Lock()
  160. defer f.lock.Unlock()
  161. if f.closed {
  162. return errors.Errorf("cannot add a feature gate after adding it to the flag set")
  163. }
  164. // Copy existing state
  165. known := map[Feature]Spec{}
  166. for k, v := range f.known.Load().(map[Feature]Spec) {
  167. known[k] = v
  168. }
  169. for name, spec := range features {
  170. if existingSpec, found := known[name]; found {
  171. if existingSpec == spec {
  172. continue
  173. }
  174. return errors.Errorf("feature gate %q with different spec already exists: %v", name, existingSpec)
  175. }
  176. known[name] = spec
  177. }
  178. // Persist updated state
  179. f.known.Store(known)
  180. return nil
  181. }
  182. // Enabled returns true if the key is enabled.
  183. func (f *featureGate) Enabled(key Feature) bool {
  184. if v, ok := f.enabled.Load().(map[Feature]bool)[key]; ok {
  185. return v
  186. }
  187. return f.known.Load().(map[Feature]Spec)[key].Default
  188. }
  189. // AddFlag adds a flag for setting global feature gates to the specified FlagSet.
  190. func (f *featureGate) AddFlag(fs *flag.FlagSet) {
  191. f.lock.Lock()
  192. // TODO(mtaufen): Shouldn't we just close it on the first Set/SetFromMap instead?
  193. // Not all components expose a feature gates flag using this AddFlag method, and
  194. // in the future, all components will completely stop exposing a feature gates flag,
  195. // in favor of componentconfig.
  196. f.closed = true
  197. f.lock.Unlock()
  198. known := f.KnownFeatures()
  199. fs.Var(f, flagName, ""+
  200. "A set of key=value pairs that describe feature gates for alpha/experimental features. "+
  201. "Options are:\n"+strings.Join(known, "\n"))
  202. }
  203. // KnownFeatures returns a slice of strings describing the Gate's known features.
  204. func (f *featureGate) KnownFeatures() []string {
  205. var known []string
  206. for k, v := range f.known.Load().(map[Feature]Spec) {
  207. known = append(known, fmt.Sprintf("%s=true|false (default=%t)", k, v.Default))
  208. }
  209. sort.Strings(known)
  210. return known
  211. }
  212. // DeepCopy returns a deep copy of the Gate object, such that gates can be
  213. // set on the copy without mutating the original. This is useful for validating
  214. // config against potential feature gate changes before committing those changes.
  215. func (f *featureGate) DeepCopy() Gate {
  216. // Copy existing state.
  217. known := map[Feature]Spec{}
  218. for k, v := range f.known.Load().(map[Feature]Spec) {
  219. known[k] = v
  220. }
  221. enabled := map[Feature]bool{}
  222. for k, v := range f.enabled.Load().(map[Feature]bool) {
  223. enabled[k] = v
  224. }
  225. // Store copied state in new atomics.
  226. knownValue := atomic.Value{}
  227. knownValue.Store(known)
  228. enabledValue := atomic.Value{}
  229. enabledValue.Store(enabled)
  230. // Construct a new featureGate around the copied state.
  231. // We maintain the value of f.closed across the copy.
  232. return &featureGate{
  233. known: knownValue,
  234. enabled: enabledValue,
  235. closed: f.closed,
  236. }
  237. }