Merge pull request #99507 from jiahuif/feature/leader-migration/options-and-defaults

Leader Migration (KEP-2477): options parsing
This commit is contained in:
Kubernetes Prow Robot 2021-03-01 18:19:33 -08:00 committed by GitHub
commit 5bf1c184e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 287 additions and 4 deletions

View File

@ -500,6 +500,8 @@ API rule violation: names_match,k8s.io/controller-manager/config/v1alpha1,Generi
API rule violation: names_match,k8s.io/controller-manager/config/v1alpha1,GenericControllerManagerConfiguration,Controllers
API rule violation: names_match,k8s.io/controller-manager/config/v1alpha1,GenericControllerManagerConfiguration,Debugging
API rule violation: names_match,k8s.io/controller-manager/config/v1alpha1,GenericControllerManagerConfiguration,LeaderElection
API rule violation: names_match,k8s.io/controller-manager/config/v1alpha1,GenericControllerManagerConfiguration,LeaderMigration
API rule violation: names_match,k8s.io/controller-manager/config/v1alpha1,GenericControllerManagerConfiguration,LeaderMigrationEnabled
API rule violation: names_match,k8s.io/controller-manager/config/v1alpha1,GenericControllerManagerConfiguration,MinResyncPeriod
API rule violation: names_match,k8s.io/controller-manager/config/v1alpha1,GenericControllerManagerConfiguration,Port
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,AttachDetachControllerConfiguration,DisableAttachDetachReconcilerSync

View File

@ -46,6 +46,10 @@ type GenericControllerManagerConfiguration struct {
Controllers []string
// DebuggingConfiguration holds configuration for Debugging related features.
Debugging componentbaseconfig.DebuggingConfiguration
// LeaderMigrationEnabled indicates whether Leader Migration should be enabled for the controller manager.
LeaderMigrationEnabled bool
// LeaderMigration holds the configuration for Leader Migration.
LeaderMigration LeaderMigrationConfiguration
}
// LeaderMigrationConfiguration provides versioned configuration for all migrating leader locks.

View File

@ -45,6 +45,10 @@ type GenericControllerManagerConfiguration struct {
Controllers []string
// DebuggingConfiguration holds configuration for Debugging related features.
Debugging componentbaseconfigv1alpha1.DebuggingConfiguration
// LeaderMigrationEnabled indicates whether Leader Migration should be enabled for the controller manager.
LeaderMigrationEnabled bool
// LeaderMigration holds the configuration for Leader Migration.
LeaderMigration LeaderMigrationConfiguration
}
// LeaderMigrationConfiguration provides versioned configuration for all migrating leader locks.

View File

@ -106,6 +106,10 @@ func autoConvert_v1alpha1_GenericControllerManagerConfiguration_To_config_Generi
if err := configv1alpha1.Convert_v1alpha1_DebuggingConfiguration_To_config_DebuggingConfiguration(&in.Debugging, &out.Debugging, s); err != nil {
return err
}
out.LeaderMigrationEnabled = in.LeaderMigrationEnabled
if err := Convert_v1alpha1_LeaderMigrationConfiguration_To_config_LeaderMigrationConfiguration(&in.LeaderMigration, &out.LeaderMigration, s); err != nil {
return err
}
return nil
}
@ -124,6 +128,10 @@ func autoConvert_config_GenericControllerManagerConfiguration_To_v1alpha1_Generi
if err := configv1alpha1.Convert_config_DebuggingConfiguration_To_v1alpha1_DebuggingConfiguration(&in.Debugging, &out.Debugging, s); err != nil {
return err
}
out.LeaderMigrationEnabled = in.LeaderMigrationEnabled
if err := Convert_config_LeaderMigrationConfiguration_To_v1alpha1_LeaderMigrationConfiguration(&in.LeaderMigration, &out.LeaderMigration, s); err != nil {
return err
}
return nil
}

View File

@ -53,6 +53,7 @@ func (in *GenericControllerManagerConfiguration) DeepCopyInto(out *GenericContro
copy(*out, *in)
}
in.Debugging.DeepCopyInto(&out.Debugging)
in.LeaderMigration.DeepCopyInto(&out.LeaderMigration)
return
}

View File

@ -53,6 +53,7 @@ func (in *GenericControllerManagerConfiguration) DeepCopyInto(out *GenericContro
copy(*out, *in)
}
out.Debugging = in.Debugging
in.LeaderMigration.DeepCopyInto(&out.LeaderMigration)
return
}

View File

@ -24,12 +24,15 @@ import (
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/component-base/config/options"
cmconfig "k8s.io/controller-manager/config"
migration "k8s.io/controller-manager/pkg/leadermigration/options"
)
// GenericControllerManagerConfigurationOptions holds the options which are generic.
type GenericControllerManagerConfigurationOptions struct {
*cmconfig.GenericControllerManagerConfiguration
Debugging *DebuggingOptions
// LeaderMigration is the options for leader migration, a nil indicates default options should be applied.
LeaderMigration *migration.LeaderMigrationOptions
}
// NewGenericControllerManagerConfigurationOptions returns generic configuration default values for both
@ -39,6 +42,7 @@ func NewGenericControllerManagerConfigurationOptions(cfg *cmconfig.GenericContro
o := &GenericControllerManagerConfigurationOptions{
GenericControllerManagerConfiguration: cfg,
Debugging: RecommendedDebuggingOptions(),
LeaderMigration: nil,
}
return o
@ -51,6 +55,7 @@ func (o *GenericControllerManagerConfigurationOptions) AddFlags(fss *cliflag.Nam
}
o.Debugging.AddFlags(fss.FlagSet("debugging"))
o.LeaderMigration.AddFlags(fss.FlagSet("leader-migration"))
genericfs := fss.FlagSet("generic")
genericfs.DurationVar(&o.MinResyncPeriod.Duration, "min-resync-period", o.MinResyncPeriod.Duration, "The resync period in reflectors will be random between MinResyncPeriod and 2*MinResyncPeriod.")
genericfs.StringVar(&o.ClientConnection.ContentType, "kube-api-content-type", o.ClientConnection.ContentType, "Content type of requests sent to apiserver.")
@ -74,7 +79,9 @@ func (o *GenericControllerManagerConfigurationOptions) ApplyTo(cfg *cmconfig.Gen
if err := o.Debugging.ApplyTo(&cfg.Debugging); err != nil {
return err
}
if err := o.LeaderMigration.ApplyTo(cfg); err != nil {
return err
}
cfg.Port = o.Port
cfg.Address = o.Address
cfg.MinResyncPeriod = o.MinResyncPeriod

View File

@ -50,6 +50,12 @@ const (
// Enables ipv6 dual stack
// Original copy from k8s.io/kubernetes/pkg/features/kube_features.go
IPv6DualStack featuregate.Feature = "IPv6DualStack"
// owner: @jiahuif
// alpha: v1.21
//
// Enables Leader Migration for kube-controller-manager and cloud-controller-manager
ControllerManagerLeaderMigration featuregate.Feature = "ControllerManagerLeaderMigration"
)
func SetupCurrentKubernetesSpecificFeatureGates(featuregates featuregate.MutableFeatureGate) error {
@ -59,7 +65,8 @@ func SetupCurrentKubernetesSpecificFeatureGates(featuregates featuregate.Mutable
// cloudPublicFeatureGates consists of cloud-specific feature keys.
// To add a new feature, define a key for it at k8s.io/api/pkg/features and add it here.
var cloudPublicFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
LegacyNodeRoleBehavior: {Default: false, PreRelease: featuregate.GA, LockToDefault: true},
ServiceNodeExclusion: {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
IPv6DualStack: {Default: true, PreRelease: featuregate.Beta},
LegacyNodeRoleBehavior: {Default: false, PreRelease: featuregate.GA, LockToDefault: true},
ServiceNodeExclusion: {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
IPv6DualStack: {Default: true, PreRelease: featuregate.Beta},
ControllerManagerLeaderMigration: {Default: false, PreRelease: featuregate.Alpha},
}

View File

@ -0,0 +1,28 @@
/*
Copyright 2021 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 leadermigration
import (
"k8s.io/apiserver/pkg/util/feature"
"k8s.io/controller-manager/pkg/features"
_ "k8s.io/controller-manager/pkg/features/register"
)
// FeatureEnabled tells if leader migration is enabled through the feature gate.
func FeatureEnabled() bool {
return feature.DefaultMutableFeatureGate.Enabled(features.ControllerManagerLeaderMigration)
}

View File

@ -0,0 +1,88 @@
/*
Copyright 2021 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 options
import (
"fmt"
"github.com/spf13/pflag"
"k8s.io/controller-manager/config"
"k8s.io/controller-manager/pkg/leadermigration"
migrationconfig "k8s.io/controller-manager/pkg/leadermigration/config"
)
// LeaderMigrationOptions is the set of options for Leader Migration,
// which is given to the controller manager through flags
type LeaderMigrationOptions struct {
// Enabled indicates whether leader migration is enabled through the --enabled-leader-migration flag.
Enabled bool
// ControllerMigrationConfig is the path to the file of LeaderMigrationConfiguration type.
// It can be set with --leader-migration-config flag
// If the path is "" (default vaule), the default vaule will be used.
ControllerMigrationConfig string
}
// DefaultLeaderMigrationOptions returns a LeaderMigrationOptions with default values.
func DefaultLeaderMigrationOptions() *LeaderMigrationOptions {
return &LeaderMigrationOptions{
Enabled: false,
ControllerMigrationConfig: "",
}
}
// AddFlags adds all flags related to leader migration to given flag set.
func (o *LeaderMigrationOptions) AddFlags(fs *pflag.FlagSet) {
if o == nil {
return
}
fs.BoolVar(&o.Enabled, "enable-leader-migration", false, "Whether to enable controller leader migration.")
fs.StringVar(&o.ControllerMigrationConfig, "leader-migration-config", "",
"Path to the config file for controller leader migration, "+
"or empty to use the value that reflects default configuration of the controller manager. "+
"The config file should be of type LeaderMigrationConfiguration, group controllermanager.config.k8s.io, version v1alpha1.")
}
// ApplyTo applies the options of leader migration to generic configuration.
func (o *LeaderMigrationOptions) ApplyTo(cfg *config.GenericControllerManagerConfiguration) error {
if o == nil {
// an nil LeaderMigrationOptions indicates that default options should be used
// in which case leader migration will be disabled
cfg.LeaderMigrationEnabled = false
return nil
}
if o.Enabled && !leadermigration.FeatureEnabled() {
return fmt.Errorf("Leader Migration is not enabled through feature gate")
}
cfg.LeaderMigrationEnabled = o.Enabled
if !cfg.LeaderMigrationEnabled {
return nil
}
if o.ControllerMigrationConfig == "" {
return fmt.Errorf("--leader-migration-config is required")
}
leaderMigrationConfig, err := migrationconfig.ReadLeaderMigrationConfiguration(o.ControllerMigrationConfig)
if err != nil {
return err
}
errs := migrationconfig.ValidateLeaderMigrationConfiguration(leaderMigrationConfig)
if len(errs) != 0 {
return fmt.Errorf("failed to parse leader migration configuration: %v", errs)
}
cfg.LeaderMigration = *leaderMigrationConfig
return nil
}

View File

@ -0,0 +1,130 @@
/*
Copyright 2021 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 options
import (
"io/ioutil"
"os"
"reflect"
"testing"
"github.com/spf13/pflag"
utilfeature "k8s.io/apiserver/pkg/util/feature"
featuregatetesting "k8s.io/component-base/featuregate/testing"
"k8s.io/controller-manager/config"
"k8s.io/controller-manager/pkg/features"
)
func TestLeaderMigrationOptions(t *testing.T) {
testCases := []struct {
name string
flags []string
configContent string
expectEnabled bool
expectErr bool
enableFeatureGate bool
expectConfig *config.LeaderMigrationConfiguration
}{
{
name: "default (disabled), with feature gate disabled",
flags: []string{},
enableFeatureGate: false,
expectEnabled: false,
expectErr: false,
},
{
name: "enabled, with feature gate disabled",
flags: []string{"--enable-leader-migration"},
enableFeatureGate: false,
expectErr: true,
},
{
name: "enabled, but missing configuration file",
flags: []string{"--enable-leader-migration"},
enableFeatureGate: true,
expectEnabled: true,
expectErr: true,
},
{
name: "enabled, with custom configuration file",
flags: []string{"--enable-leader-migration"},
enableFeatureGate: true,
expectEnabled: true,
configContent: `
apiVersion: controllermanager.config.k8s.io/v1alpha1
kind: LeaderMigrationConfiguration
leaderName: test-leader-migration
resourceLock: leases
controllerLeaders: []
`,
expectErr: false,
expectConfig: &config.LeaderMigrationConfiguration{
LeaderName: "test-leader-migration",
ResourceLock: "leases",
ControllerLeaders: []config.ControllerLeaderConfiguration{},
},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ControllerManagerLeaderMigration, tc.enableFeatureGate)()
flags := tc.flags
if tc.configContent != "" {
configFile, err := ioutil.TempFile("", tc.name)
if err != nil {
t.Fatal(err)
}
defer os.Remove(configFile.Name())
err = ioutil.WriteFile(configFile.Name(), []byte(tc.configContent), os.FileMode(0755))
if err != nil {
t.Fatal(err)
}
flags = append(flags, "--leader-migration-config="+configFile.Name())
}
genericConfig := new(config.GenericControllerManagerConfiguration)
options := new(LeaderMigrationOptions)
fs := pflag.NewFlagSet("addflagstest", pflag.ContinueOnError)
options.AddFlags(fs)
err := fs.Parse(flags)
if err != nil {
t.Errorf("cannot parse leader-migration-config: %v", err)
return
}
err = options.ApplyTo(genericConfig)
if err != nil {
if !tc.expectErr {
t.Errorf("unexpected error: %v", err)
return
}
// expect err and got err, finish the test case.
return
}
if err == nil && tc.expectErr {
t.Errorf("expected error but got nil")
return
}
if genericConfig.LeaderMigrationEnabled != tc.expectEnabled {
t.Errorf("expected Enabled=%v, got %v", tc.expectEnabled, options.Enabled)
return
}
if tc.expectEnabled && !reflect.DeepEqual(tc.expectConfig, &genericConfig.LeaderMigration) {
t.Errorf("expected config %#v but got %#v", tc.expectConfig, genericConfig.LeaderMigration)
}
})
}
}

3
vendor/modules.txt vendored
View File

@ -2255,6 +2255,9 @@ k8s.io/controller-manager/pkg/clientbuilder
k8s.io/controller-manager/pkg/features
k8s.io/controller-manager/pkg/features/register
k8s.io/controller-manager/pkg/informerfactory
k8s.io/controller-manager/pkg/leadermigration
k8s.io/controller-manager/pkg/leadermigration/config
k8s.io/controller-manager/pkg/leadermigration/options
# k8s.io/cri-api v0.0.0 => ./staging/src/k8s.io/cri-api
## explicit
# k8s.io/cri-api => ./staging/src/k8s.io/cri-api