1
0

feature_gate.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. // Copyright 2025 The frp Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package featuregate
  15. import (
  16. "fmt"
  17. "sort"
  18. "strings"
  19. "sync"
  20. "sync/atomic"
  21. )
  22. // Feature represents a feature gate name
  23. type Feature string
  24. // FeatureStage represents the maturity level of a feature
  25. type FeatureStage string
  26. const (
  27. // Alpha means the feature is experimental and disabled by default
  28. Alpha FeatureStage = "ALPHA"
  29. // Beta means the feature is more stable but still might change and is disabled by default
  30. Beta FeatureStage = "BETA"
  31. // GA means the feature is generally available and enabled by default
  32. GA FeatureStage = ""
  33. )
  34. // FeatureSpec describes a feature and its properties
  35. type FeatureSpec struct {
  36. // Default is the default enablement state for the feature
  37. Default bool
  38. // LockToDefault indicates the feature cannot be changed from its default
  39. LockToDefault bool
  40. // Stage indicates the maturity level of the feature
  41. Stage FeatureStage
  42. }
  43. // Define all available features here
  44. var (
  45. VirtualNet = Feature("VirtualNet")
  46. )
  47. // defaultFeatures defines default features with their specifications
  48. var defaultFeatures = map[Feature]FeatureSpec{
  49. // Actual features
  50. VirtualNet: {Default: false, Stage: Alpha},
  51. }
  52. // FeatureGate indicates whether a given feature is enabled or not
  53. type FeatureGate interface {
  54. // Enabled returns true if the key is enabled
  55. Enabled(key Feature) bool
  56. // KnownFeatures returns a slice of strings describing the known features
  57. KnownFeatures() []string
  58. }
  59. // MutableFeatureGate allows for dynamic feature gate configuration
  60. type MutableFeatureGate interface {
  61. FeatureGate
  62. // SetFromMap sets feature gate values from a map[string]bool
  63. SetFromMap(m map[string]bool) error
  64. // Add adds features to the feature gate
  65. Add(features map[Feature]FeatureSpec) error
  66. // String returns a string representing the feature gate configuration
  67. String() string
  68. }
  69. // featureGate implements the FeatureGate and MutableFeatureGate interfaces
  70. type featureGate struct {
  71. // lock guards writes to known, enabled, and reads/writes of closed
  72. lock sync.Mutex
  73. // known holds a map[Feature]FeatureSpec
  74. known atomic.Value
  75. // enabled holds a map[Feature]bool
  76. enabled atomic.Value
  77. // closed is set to true once the feature gates are considered immutable
  78. closed bool
  79. }
  80. // NewFeatureGate creates a new feature gate with the default features
  81. func NewFeatureGate() MutableFeatureGate {
  82. known := map[Feature]FeatureSpec{}
  83. for k, v := range defaultFeatures {
  84. known[k] = v
  85. }
  86. f := &featureGate{}
  87. f.known.Store(known)
  88. f.enabled.Store(map[Feature]bool{})
  89. return f
  90. }
  91. // SetFromMap sets feature gate values from a map[string]bool
  92. func (f *featureGate) SetFromMap(m map[string]bool) error {
  93. f.lock.Lock()
  94. defer f.lock.Unlock()
  95. // Copy existing state
  96. known := map[Feature]FeatureSpec{}
  97. for k, v := range f.known.Load().(map[Feature]FeatureSpec) {
  98. known[k] = v
  99. }
  100. enabled := map[Feature]bool{}
  101. for k, v := range f.enabled.Load().(map[Feature]bool) {
  102. enabled[k] = v
  103. }
  104. // Apply the new settings
  105. for k, v := range m {
  106. k := Feature(k)
  107. featureSpec, ok := known[k]
  108. if !ok {
  109. return fmt.Errorf("unrecognized feature gate: %s", k)
  110. }
  111. if featureSpec.LockToDefault && featureSpec.Default != v {
  112. return fmt.Errorf("cannot set feature gate %v to %v, feature is locked to %v", k, v, featureSpec.Default)
  113. }
  114. enabled[k] = v
  115. }
  116. // Persist the changes
  117. f.known.Store(known)
  118. f.enabled.Store(enabled)
  119. return nil
  120. }
  121. // Add adds features to the feature gate
  122. func (f *featureGate) Add(features map[Feature]FeatureSpec) error {
  123. f.lock.Lock()
  124. defer f.lock.Unlock()
  125. if f.closed {
  126. return fmt.Errorf("cannot add feature gates after the feature gate is closed")
  127. }
  128. // Copy existing state
  129. known := map[Feature]FeatureSpec{}
  130. for k, v := range f.known.Load().(map[Feature]FeatureSpec) {
  131. known[k] = v
  132. }
  133. // Add new features
  134. for name, spec := range features {
  135. if existingSpec, found := known[name]; found {
  136. if existingSpec == spec {
  137. continue
  138. }
  139. return fmt.Errorf("feature gate %q with different spec already exists: %v", name, existingSpec)
  140. }
  141. known[name] = spec
  142. }
  143. // Persist changes
  144. f.known.Store(known)
  145. return nil
  146. }
  147. // String returns a string containing all enabled feature gates, formatted as "key1=value1,key2=value2,..."
  148. func (f *featureGate) String() string {
  149. pairs := []string{}
  150. for k, v := range f.enabled.Load().(map[Feature]bool) {
  151. pairs = append(pairs, fmt.Sprintf("%s=%t", k, v))
  152. }
  153. sort.Strings(pairs)
  154. return strings.Join(pairs, ",")
  155. }
  156. // Enabled returns true if the key is enabled
  157. func (f *featureGate) Enabled(key Feature) bool {
  158. if v, ok := f.enabled.Load().(map[Feature]bool)[key]; ok {
  159. return v
  160. }
  161. if v, ok := f.known.Load().(map[Feature]FeatureSpec)[key]; ok {
  162. return v.Default
  163. }
  164. return false
  165. }
  166. // KnownFeatures returns a slice of strings describing the FeatureGate's known features
  167. // GA features are hidden from the list
  168. func (f *featureGate) KnownFeatures() []string {
  169. knownFeatures := f.known.Load().(map[Feature]FeatureSpec)
  170. known := make([]string, 0, len(knownFeatures))
  171. for k, v := range knownFeatures {
  172. if v.Stage == GA {
  173. continue
  174. }
  175. known = append(known, fmt.Sprintf("%s=true|false (%s - default=%t)", k, v.Stage, v.Default))
  176. }
  177. sort.Strings(known)
  178. return known
  179. }
  180. // Default feature gates instance
  181. var DefaultFeatureGates = NewFeatureGate()
  182. // Enabled checks if a feature is enabled in the default feature gates
  183. func Enabled(name Feature) bool {
  184. return DefaultFeatureGates.Enabled(name)
  185. }
  186. // SetFromMap sets feature gate values from a map in the default feature gates
  187. func SetFromMap(featureMap map[string]bool) error {
  188. return DefaultFeatureGates.SetFromMap(featureMap)
  189. }