Removes dependency on other k8s packages in featuregate pkg.

The removed packages are:

 * k8s.io/apimachinery/pkg/util/naming
 * k8s.io/klog/v2

Do note that removing naming package necessitates adding feature gate
name argument to featuregate.New().

Signed-off-by: Baek <seungtackbaek@google.com>
This commit is contained in:
Baek 2024-06-14 06:22:55 +00:00
parent 60e3f45469
commit 14e15bcaca
4 changed files with 32 additions and 37 deletions

4
go.mod
View File

@ -1,6 +1,6 @@
module go.etcd.io/etcd/v3 module go.etcd.io/etcd/v3
go 1.22.0 go 1.22
toolchain go1.22.4 toolchain go1.22.4
@ -95,6 +95,6 @@ require (
google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect sigs.k8s.io/yaml v1.4.0 // indirect
) )

4
go.sum
View File

@ -250,7 +250,7 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=

View File

@ -12,11 +12,10 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// featuregate package is copied from k8s.io/component-base@v0.30.1 to avoid any potential circular dependency between k8s and etcd. // Package featuregate is copied from k8s.io/component-base@v0.30.1 to avoid any potential circular dependency between k8s and etcd.
package featuregate package featuregate
import ( import (
"context"
"fmt" "fmt"
"sort" "sort"
"strconv" "strconv"
@ -25,9 +24,7 @@ import (
"sync/atomic" "sync/atomic"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"go.uber.org/zap"
"k8s.io/apimachinery/pkg/util/naming"
"k8s.io/klog/v2"
) )
type Feature string type Feature string
@ -128,6 +125,8 @@ type MutableFeatureGate interface {
// featureGate implements FeatureGate as well as pflag.Value for flag parsing. // featureGate implements FeatureGate as well as pflag.Value for flag parsing.
type featureGate struct { type featureGate struct {
lg *zap.Logger
featureGateName string featureGateName string
special map[Feature]func(map[Feature]FeatureSpec, map[Feature]bool, bool) special map[Feature]func(map[Feature]FeatureSpec, map[Feature]bool, bool)
@ -165,18 +164,15 @@ func setUnsetBetaGates(known map[Feature]FeatureSpec, enabled map[Feature]bool,
// Set, String, and Type implement pflag.Value // Set, String, and Type implement pflag.Value
var _ pflag.Value = &featureGate{} var _ pflag.Value = &featureGate{}
// internalPackages are packages that ignored when creating a name for featureGates. These packages are in the common func New(name string, lg *zap.Logger) *featureGate {
// call chains, so they'd be unhelpful as names.
var internalPackages = []string{"k8s.io/component-base/featuregate/feature_gate.go"}
func NewFeatureGate() *featureGate {
known := map[Feature]FeatureSpec{} known := map[Feature]FeatureSpec{}
for k, v := range defaultFeatures { for k, v := range defaultFeatures {
known[k] = v known[k] = v
} }
f := &featureGate{ f := &featureGate{
featureGateName: naming.GetNameFromCallsite(internalPackages...), lg: lg,
featureGateName: name,
special: specialFeatures, special: specialFeatures,
} }
f.known.Store(known) f.known.Store(known)
@ -239,9 +235,9 @@ func (f *featureGate) SetFromMap(m map[string]bool) error {
} }
if featureSpec.PreRelease == Deprecated { if featureSpec.PreRelease == Deprecated {
klog.Warningf("Setting deprecated feature gate %s=%t. It will be removed in a future release.", k, v) f.lg.Warn(fmt.Sprintf("Setting deprecated feature gate %s=%t. It will be removed in a future release.", k, v))
} else if featureSpec.PreRelease == GA { } else if featureSpec.PreRelease == GA {
klog.Warningf("Setting GA feature gate %s=%t. It will be removed in a future release.", k, v) f.lg.Warn(fmt.Sprintf("Setting GA feature gate %s=%t. It will be removed in a future release.", k, v))
} }
} }
@ -249,7 +245,7 @@ func (f *featureGate) SetFromMap(m map[string]bool) error {
f.known.Store(known) f.known.Store(known)
f.enabled.Store(enabled) f.enabled.Store(enabled)
klog.V(1).Infof("feature gates: %v", f.enabled) f.lg.Info(fmt.Sprintf("feature gates: %v", f.enabled))
return nil return nil
} }
@ -319,9 +315,9 @@ func (f *featureGate) OverrideDefault(name Feature, override bool) error {
case spec.LockToDefault: case spec.LockToDefault:
return fmt.Errorf("cannot override default: feature %q default is locked to %t", name, spec.Default) return fmt.Errorf("cannot override default: feature %q default is locked to %t", name, spec.Default)
case spec.PreRelease == Deprecated: case spec.PreRelease == Deprecated:
klog.Warningf("Overriding default of deprecated feature gate %s=%t. It will be removed in a future release.", name, override) f.lg.Warn(fmt.Sprintf("Overriding default of deprecated feature gate %s=%t. It will be removed in a future release.", name, override))
case spec.PreRelease == GA: case spec.PreRelease == GA:
klog.Warningf("Overriding default of GA feature gate %s=%t. It will be removed in a future release.", name, override) f.lg.Warn(fmt.Sprintf("Overriding default of GA feature gate %s=%t. It will be removed in a future release.", name, override))
} }
spec.Default = override spec.Default = override
@ -369,9 +365,7 @@ func (f *featureGate) AddFlag(fs *pflag.FlagSet) {
} }
func (f *featureGate) AddMetrics() { func (f *featureGate) AddMetrics() {
for feature, featureSpec := range f.GetAll() { // TODO(henrybear327): implement this.
featuremetrics.RecordFeatureInfo(context.Background(), string(feature), string(featureSpec.PreRelease), f.Enabled(feature))
}
} }
// KnownFeatures returns a slice of strings describing the FeatureGate's known features. // KnownFeatures returns a slice of strings describing the FeatureGate's known features.

View File

@ -21,6 +21,7 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go.uber.org/zap/zaptest"
) )
func TestFeatureGateFlag(t *testing.T) { func TestFeatureGateFlag(t *testing.T) {
@ -203,7 +204,7 @@ func TestFeatureGateFlag(t *testing.T) {
for i, test := range tests { for i, test := range tests {
t.Run(test.arg, func(t *testing.T) { t.Run(test.arg, func(t *testing.T) {
fs := pflag.NewFlagSet("testfeaturegateflag", pflag.ContinueOnError) fs := pflag.NewFlagSet("testfeaturegateflag", pflag.ContinueOnError)
f := NewFeatureGate() f := New("test", zaptest.NewLogger(t))
f.Add(map[Feature]FeatureSpec{ f.Add(map[Feature]FeatureSpec{
testAlphaGate: {Default: false, PreRelease: Alpha}, testAlphaGate: {Default: false, PreRelease: Alpha},
testBetaGate: {Default: false, PreRelease: Beta}, testBetaGate: {Default: false, PreRelease: Beta},
@ -232,7 +233,7 @@ func TestFeatureGateOverride(t *testing.T) {
const testBetaGate Feature = "TestBeta" const testBetaGate Feature = "TestBeta"
// Don't parse the flag, assert defaults are used. // Don't parse the flag, assert defaults are used.
var f *featureGate = NewFeatureGate() var f = New("test", zaptest.NewLogger(t))
f.Add(map[Feature]FeatureSpec{ f.Add(map[Feature]FeatureSpec{
testAlphaGate: {Default: false, PreRelease: Alpha}, testAlphaGate: {Default: false, PreRelease: Alpha},
testBetaGate: {Default: false, PreRelease: Beta}, testBetaGate: {Default: false, PreRelease: Beta},
@ -261,7 +262,7 @@ func TestFeatureGateFlagDefaults(t *testing.T) {
const testBetaGate Feature = "TestBeta" const testBetaGate Feature = "TestBeta"
// Don't parse the flag, assert defaults are used. // Don't parse the flag, assert defaults are used.
var f *featureGate = NewFeatureGate() var f = New("test", zaptest.NewLogger(t))
f.Add(map[Feature]FeatureSpec{ f.Add(map[Feature]FeatureSpec{
testAlphaGate: {Default: false, PreRelease: Alpha}, testAlphaGate: {Default: false, PreRelease: Alpha},
testBetaGate: {Default: true, PreRelease: Beta}, testBetaGate: {Default: true, PreRelease: Beta},
@ -285,7 +286,7 @@ func TestFeatureGateKnownFeatures(t *testing.T) {
) )
// Don't parse the flag, assert defaults are used. // Don't parse the flag, assert defaults are used.
var f *featureGate = NewFeatureGate() var f = New("test", zaptest.NewLogger(t))
f.Add(map[Feature]FeatureSpec{ f.Add(map[Feature]FeatureSpec{
testAlphaGate: {Default: false, PreRelease: Alpha}, testAlphaGate: {Default: false, PreRelease: Alpha},
testBetaGate: {Default: true, PreRelease: Beta}, testBetaGate: {Default: true, PreRelease: Beta},
@ -392,7 +393,7 @@ func TestFeatureGateSetFromMap(t *testing.T) {
} }
for i, test := range tests { for i, test := range tests {
t.Run(fmt.Sprintf("SetFromMap %s", test.name), func(t *testing.T) { t.Run(fmt.Sprintf("SetFromMap %s", test.name), func(t *testing.T) {
f := NewFeatureGate() f := New("test", zaptest.NewLogger(t))
f.Add(map[Feature]FeatureSpec{ f.Add(map[Feature]FeatureSpec{
testAlphaGate: {Default: false, PreRelease: Alpha}, testAlphaGate: {Default: false, PreRelease: Alpha},
testBetaGate: {Default: false, PreRelease: Beta}, testBetaGate: {Default: false, PreRelease: Beta},
@ -462,7 +463,7 @@ func TestFeatureGateString(t *testing.T) {
} }
for i, test := range tests { for i, test := range tests {
t.Run(fmt.Sprintf("SetFromMap %s", test.expect), func(t *testing.T) { t.Run(fmt.Sprintf("SetFromMap %s", test.expect), func(t *testing.T) {
f := NewFeatureGate() f := New("test", zaptest.NewLogger(t))
f.Add(featuremap) f.Add(featuremap)
f.SetFromMap(test.setmap) f.SetFromMap(test.setmap)
result := f.String() result := f.String()
@ -475,7 +476,7 @@ func TestFeatureGateString(t *testing.T) {
func TestFeatureGateOverrideDefault(t *testing.T) { func TestFeatureGateOverrideDefault(t *testing.T) {
t.Run("overrides take effect", func(t *testing.T) { t.Run("overrides take effect", func(t *testing.T) {
f := NewFeatureGate() f := New("test", zaptest.NewLogger(t))
if err := f.Add(map[Feature]FeatureSpec{ if err := f.Add(map[Feature]FeatureSpec{
"TestFeature1": {Default: true}, "TestFeature1": {Default: true},
"TestFeature2": {Default: false}, "TestFeature2": {Default: false},
@ -497,7 +498,7 @@ func TestFeatureGateOverrideDefault(t *testing.T) {
}) })
t.Run("overrides are preserved across deep copies", func(t *testing.T) { t.Run("overrides are preserved across deep copies", func(t *testing.T) {
f := NewFeatureGate() f := New("test", zaptest.NewLogger(t))
if err := f.Add(map[Feature]FeatureSpec{"TestFeature": {Default: false}}); err != nil { if err := f.Add(map[Feature]FeatureSpec{"TestFeature": {Default: false}}); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -511,7 +512,7 @@ func TestFeatureGateOverrideDefault(t *testing.T) {
}) })
t.Run("reflected in known features", func(t *testing.T) { t.Run("reflected in known features", func(t *testing.T) {
f := NewFeatureGate() f := New("test", zaptest.NewLogger(t))
if err := f.Add(map[Feature]FeatureSpec{"TestFeature": { if err := f.Add(map[Feature]FeatureSpec{"TestFeature": {
Default: false, Default: false,
PreRelease: Alpha, PreRelease: Alpha,
@ -537,7 +538,7 @@ func TestFeatureGateOverrideDefault(t *testing.T) {
}) })
t.Run("may not change default for specs with locked defaults", func(t *testing.T) { t.Run("may not change default for specs with locked defaults", func(t *testing.T) {
f := NewFeatureGate() f := New("test", zaptest.NewLogger(t))
if err := f.Add(map[Feature]FeatureSpec{ if err := f.Add(map[Feature]FeatureSpec{
"LockedFeature": { "LockedFeature": {
Default: true, Default: true,
@ -555,7 +556,7 @@ func TestFeatureGateOverrideDefault(t *testing.T) {
}) })
t.Run("does not supersede explicitly-set value", func(t *testing.T) { t.Run("does not supersede explicitly-set value", func(t *testing.T) {
f := NewFeatureGate() f := New("test", zaptest.NewLogger(t))
if err := f.Add(map[Feature]FeatureSpec{"TestFeature": {Default: true}}); err != nil { if err := f.Add(map[Feature]FeatureSpec{"TestFeature": {Default: true}}); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -571,7 +572,7 @@ func TestFeatureGateOverrideDefault(t *testing.T) {
}) })
t.Run("prevents re-registration of feature spec after overriding default", func(t *testing.T) { t.Run("prevents re-registration of feature spec after overriding default", func(t *testing.T) {
f := NewFeatureGate() f := New("test", zaptest.NewLogger(t))
if err := f.Add(map[Feature]FeatureSpec{ if err := f.Add(map[Feature]FeatureSpec{
"TestFeature": { "TestFeature": {
Default: true, Default: true,
@ -594,14 +595,14 @@ func TestFeatureGateOverrideDefault(t *testing.T) {
}) })
t.Run("does not allow override for an unknown feature", func(t *testing.T) { t.Run("does not allow override for an unknown feature", func(t *testing.T) {
f := NewFeatureGate() f := New("test", zaptest.NewLogger(t))
if err := f.OverrideDefault("TestFeature", true); err == nil { if err := f.OverrideDefault("TestFeature", true); err == nil {
t.Error("expected an error to be returned in attempt to override default for unregistered feature") t.Error("expected an error to be returned in attempt to override default for unregistered feature")
} }
}) })
t.Run("returns error if already added to flag set", func(t *testing.T) { t.Run("returns error if already added to flag set", func(t *testing.T) {
f := NewFeatureGate() f := New("test", zaptest.NewLogger(t))
fs := pflag.NewFlagSet("test", pflag.ContinueOnError) fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
f.AddFlag(fs) f.AddFlag(fs)