diff --git a/cmd/descheduler/app/options/options.go b/cmd/descheduler/app/options/options.go index 34f8b84fc..1d9523c05 100644 --- a/cmd/descheduler/app/options/options.go +++ b/cmd/descheduler/app/options/options.go @@ -18,36 +18,55 @@ limitations under the License. package options import ( + "github.com/spf13/pflag" + utilerrors "k8s.io/apimachinery/pkg/util/errors" clientset "k8s.io/client-go/kubernetes" - // install the componentconfig api so we get its defaulting and conversion functions + "k8s.io/component-base/logs" "sigs.k8s.io/descheduler/pkg/apis/componentconfig" "sigs.k8s.io/descheduler/pkg/apis/componentconfig/v1alpha1" deschedulerscheme "sigs.k8s.io/descheduler/pkg/descheduler/scheme" - - "github.com/spf13/pflag" ) // DeschedulerServer configuration type DeschedulerServer struct { componentconfig.DeschedulerConfiguration Client clientset.Interface + Logs *logs.Options } // NewDeschedulerServer creates a new DeschedulerServer with default parameters -func NewDeschedulerServer() *DeschedulerServer { - versioned := v1alpha1.DeschedulerConfiguration{} - deschedulerscheme.Scheme.Default(&versioned) - cfg := componentconfig.DeschedulerConfiguration{} - deschedulerscheme.Scheme.Convert(versioned, &cfg, nil) - s := DeschedulerServer{ - DeschedulerConfiguration: cfg, +func NewDeschedulerServer() (*DeschedulerServer, error) { + cfg, err := newDefaultComponentConfig() + if err != nil { + return nil, err } - return &s + return &DeschedulerServer{ + DeschedulerConfiguration: *cfg, + Logs: logs.NewOptions(), + }, nil +} + +// Validation checks for DeschedulerServer. +func (s *DeschedulerServer) Validate() error { + var errs []error + errs = append(errs, s.Logs.Validate()...) + return utilerrors.NewAggregate(errs) +} + +func newDefaultComponentConfig() (*componentconfig.DeschedulerConfiguration, error) { + versionedCfg := v1alpha1.DeschedulerConfiguration{} + deschedulerscheme.Scheme.Default(&versionedCfg) + cfg := componentconfig.DeschedulerConfiguration{} + if err := deschedulerscheme.Scheme.Convert(&versionedCfg, &cfg, nil); err != nil { + return nil, err + } + return &cfg, nil } // AddFlags adds flags for a specific SchedulerServer to the specified FlagSet func (rs *DeschedulerServer) AddFlags(fs *pflag.FlagSet) { + fs.StringVar(&rs.Logging.Format, "logging-format", rs.Logging.Format, `Sets the log format. Permitted formats: "text", "json". Non-default formats don't honor these flags: --add-dir-header, --alsologtostderr, --log-backtrace-at, --log-dir, --log-file, --log-file-max-size, --logtostderr, --skip-headers, --skip-log-headers, --stderrthreshold, --log-flush-frequency.\nNon-default choices are currently alpha and subject to change without warning.`) fs.DurationVar(&rs.DeschedulingInterval, "descheduling-interval", rs.DeschedulingInterval, "Time interval between two consecutive descheduler executions. Setting this value instructs the descheduler to run in a continuous loop at the interval specified.") fs.StringVar(&rs.KubeconfigFile, "kubeconfig", rs.KubeconfigFile, "File with kube configuration.") fs.StringVar(&rs.PolicyConfigFile, "policy-config-file", rs.PolicyConfigFile, "File with descheduler policy configuration.") diff --git a/cmd/descheduler/app/server.go b/cmd/descheduler/app/server.go index b4b10de00..0b47cff5f 100644 --- a/cmd/descheduler/app/server.go +++ b/cmd/descheduler/app/server.go @@ -27,28 +27,35 @@ import ( "github.com/spf13/cobra" aflag "k8s.io/component-base/cli/flag" - "k8s.io/component-base/logs" "k8s.io/klog/v2" ) // NewDeschedulerCommand creates a *cobra.Command object with default parameters func NewDeschedulerCommand(out io.Writer) *cobra.Command { - s := options.NewDeschedulerServer() + s, err := options.NewDeschedulerServer() + + if err != nil { + klog.ErrorS(err, "unable to initialize server") + } + cmd := &cobra.Command{ Use: "descheduler", Short: "descheduler", Long: `The descheduler evicts pods which may be bound to less desired nodes`, Run: func(cmd *cobra.Command, args []string) { - logs.InitLogs() - defer logs.FlushLogs() + s.Logs.LogFormat = s.Logging.Format + s.Logs.Apply() + + if err := s.Validate(); err != nil { + klog.ErrorS(err, "failed to validate server configuration") + } err := Run(s) if err != nil { klog.ErrorS(err, "descheduler server") } }, } - cmd.SetOutput(out) - + cmd.SetOut(out) flags := cmd.Flags() flags.SetNormalizeFunc(aflag.WordSepNormalizeFunc) flags.AddGoFlagSet(flag.CommandLine) diff --git a/cmd/descheduler/descheduler.go b/cmd/descheduler/descheduler.go index c09348bfc..3f3d5c0f0 100644 --- a/cmd/descheduler/descheduler.go +++ b/cmd/descheduler/descheduler.go @@ -17,10 +17,9 @@ limitations under the License. package main import ( - "flag" "fmt" + "k8s.io/component-base/logs" "os" - "sigs.k8s.io/descheduler/cmd/descheduler/app" ) @@ -28,7 +27,10 @@ func main() { out := os.Stdout cmd := app.NewDeschedulerCommand(out) cmd.AddCommand(app.NewVersionCommand()) - flag.CommandLine.Parse([]string{}) + + logs.InitLogs() + defer logs.FlushLogs() + if err := cmd.Execute(); err != nil { fmt.Println(err) os.Exit(1) diff --git a/go.mod b/go.mod index 17da5bd15..eeb10455d 100644 --- a/go.mod +++ b/go.mod @@ -5,11 +5,11 @@ go 1.15 require ( github.com/spf13/cobra v0.0.5 github.com/spf13/pflag v1.0.5 - k8s.io/api v0.19.0 - k8s.io/apimachinery v0.19.0 + k8s.io/api v0.19.2 + k8s.io/apimachinery v0.19.2 k8s.io/apiserver v0.19.0 - k8s.io/client-go v0.19.0 + k8s.io/client-go v0.19.2 k8s.io/code-generator v0.19.0 - k8s.io/component-base v0.19.0 + k8s.io/component-base v0.19.2 k8s.io/klog/v2 v2.2.0 ) diff --git a/go.sum b/go.sum index 9d1b74925..626e4942a 100644 --- a/go.sum +++ b/go.sum @@ -513,16 +513,24 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= k8s.io/api v0.19.0 h1:XyrFIJqTYZJ2DU7FBE/bSPz7b1HvbVBuBf07oeo6eTc= k8s.io/api v0.19.0/go.mod h1:I1K45XlvTrDjmj5LoM5LuP/KYrhWbjUKT/SoPG0qTjw= +k8s.io/api v0.19.2 h1:q+/krnHWKsL7OBZg/rxnycsl9569Pud76UJ77MvKXms= +k8s.io/api v0.19.2/go.mod h1:IQpK0zFQ1xc5iNIQPqzgoOwuFugaYHK4iCknlAQP9nI= k8s.io/apimachinery v0.19.0 h1:gjKnAda/HZp5k4xQYjL0K/Yb66IvNqjthCb03QlKpaQ= k8s.io/apimachinery v0.19.0/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apimachinery v0.19.2 h1:5Gy9vQpAGTKHPVOh5c4plE274X8D/6cuEiTO2zve7tc= +k8s.io/apimachinery v0.19.2/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= k8s.io/apiserver v0.19.0 h1:jLhrL06wGAADbLUUQm8glSLnAGP6c7y5R3p19grkBoY= k8s.io/apiserver v0.19.0/go.mod h1:XvzqavYj73931x7FLtyagh8WibHpePJ1QwWrSJs2CLk= k8s.io/client-go v0.19.0 h1:1+0E0zfWFIWeyRhQYWzimJOyAk2UT7TiARaLNwJCf7k= k8s.io/client-go v0.19.0/go.mod h1:H9E/VT95blcFQnlyShFgnFT9ZnJOAceiUHM3MlRC+mU= +k8s.io/client-go v0.19.2 h1:gMJuU3xJZs86L1oQ99R4EViAADUPMHHtS9jFshasHSc= +k8s.io/client-go v0.19.2/go.mod h1:S5wPhCqyDNAlzM9CnEdgTGV4OqhsW3jGO1UM1epwfJA= k8s.io/code-generator v0.19.0 h1:r0BxYnttP/r8uyKd4+Njg0B57kKi8wLvwEzaaVy3iZ8= k8s.io/code-generator v0.19.0/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk= k8s.io/component-base v0.19.0 h1:OueXf1q3RW7NlLlUCj2Dimwt7E1ys6ZqRnq53l2YuoE= k8s.io/component-base v0.19.0/go.mod h1:dKsY8BxkA+9dZIAh2aWJLL/UdASFDNtGYTCItL4LM7Y= +k8s.io/component-base v0.19.2 h1:jW5Y9RcZTb79liEhW3XDVTW7MuvEGP0tQZnfSX6/+gs= +k8s.io/component-base v0.19.2/go.mod h1:g5LrsiTiabMLZ40AR6Hl45f088DevyGY+cCE2agEIVo= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14 h1:t4L10Qfx/p7ASH3gXCdIUtPbbIuegCoUJf3TMSFekjw= k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= diff --git a/pkg/apis/componentconfig/types.go b/pkg/apis/componentconfig/types.go index 1588d59f5..02b5915cb 100644 --- a/pkg/apis/componentconfig/types.go +++ b/pkg/apis/componentconfig/types.go @@ -20,6 +20,7 @@ import ( "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + componentbaseconfig "k8s.io/component-base/config" ) // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object @@ -48,4 +49,8 @@ type DeschedulerConfiguration struct { // EvictLocalStoragePods allows pods using local storage to be evicted. EvictLocalStoragePods bool + + // Logging specifies the options of logging. + // Refer [Logs Options](https://github.com/kubernetes/component-base/blob/master/logs/options.go) for more information. + Logging componentbaseconfig.LoggingConfiguration } diff --git a/pkg/descheduler/descheduler_test.go b/pkg/descheduler/descheduler_test.go index 6b8fc3b49..d3c95e771 100644 --- a/pkg/descheduler/descheduler_test.go +++ b/pkg/descheduler/descheduler_test.go @@ -38,7 +38,10 @@ func TestTaintsUpdated(t *testing.T) { stopChannel := make(chan struct{}) defer close(stopChannel) - rs := options.NewDeschedulerServer() + rs, err := options.NewDeschedulerServer() + if err != nil { + t.Fatalf("Unable to initialize server: %v", err) + } rs.Client = client rs.DeschedulingInterval = 100 * time.Millisecond go func() { diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 05bafa0e4..d8f445db0 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -567,7 +567,10 @@ func TestDeschedulingInterval(t *testing.T) { } // By default, the DeschedulingInterval param should be set to 0, meaning Descheduler only runs once then exits - s := options.NewDeschedulerServer() + s, err := options.NewDeschedulerServer() + if err != nil { + t.Fatalf("Unable to initialize server: %v", err) + } s.Client = clientSet deschedulerPolicy := &api.DeschedulerPolicy{} diff --git a/vendor/k8s.io/client-go/tools/cache/controller.go b/vendor/k8s.io/client-go/tools/cache/controller.go index 916ca9cc1..3ad9b53bb 100644 --- a/vendor/k8s.io/client-go/tools/cache/controller.go +++ b/vendor/k8s.io/client-go/tools/cache/controller.go @@ -144,11 +144,11 @@ func (c *controller) Run(stopCh <-chan struct{}) { c.reflectorMutex.Unlock() var wg wait.Group - defer wg.Wait() wg.StartWithChannel(stopCh, r.Run) wait.Until(c.processLoop, time.Second, stopCh) + wg.Wait() } // Returns true once this controller has completed an initial resource listing diff --git a/vendor/k8s.io/client-go/tools/cache/reflector.go b/vendor/k8s.io/client-go/tools/cache/reflector.go index a92b36f2c..e995abe25 100644 --- a/vendor/k8s.io/client-go/tools/cache/reflector.go +++ b/vendor/k8s.io/client-go/tools/cache/reflector.go @@ -570,5 +570,26 @@ func isExpiredError(err error) bool { } func isTooLargeResourceVersionError(err error) bool { - return apierrors.HasStatusCause(err, metav1.CauseTypeResourceVersionTooLarge) + if apierrors.HasStatusCause(err, metav1.CauseTypeResourceVersionTooLarge) { + return true + } + // In Kubernetes 1.17.0-1.18.5, the api server doesn't set the error status cause to + // metav1.CauseTypeResourceVersionTooLarge to indicate that the requested minimum resource + // version is larger than the largest currently available resource version. To ensure backward + // compatibility with these server versions we also need to detect the error based on the content + // of the error message field. + if !apierrors.IsTimeout(err) { + return false + } + apierr, ok := err.(apierrors.APIStatus) + if !ok || apierr == nil || apierr.Status().Details == nil { + return false + } + for _, cause := range apierr.Status().Details.Causes { + // Matches the message returned by api server 1.17.0-1.18.5 for this error condition + if cause.Message == "Too large resource version" { + return true + } + } + return false } diff --git a/vendor/k8s.io/component-base/config/OWNERS b/vendor/k8s.io/component-base/config/OWNERS new file mode 100644 index 000000000..11d499d75 --- /dev/null +++ b/vendor/k8s.io/component-base/config/OWNERS @@ -0,0 +1,14 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +# Disable inheritance as this is an api owners file +options: + no_parent_owners: true +approvers: +- api-approvers +reviewers: +- api-reviewers +- luxas +- mtaufen +- sttts +labels: +- kind/api-change diff --git a/vendor/k8s.io/component-base/config/doc.go b/vendor/k8s.io/component-base/config/doc.go new file mode 100644 index 000000000..dd0a5a53a --- /dev/null +++ b/vendor/k8s.io/component-base/config/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2018 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. +*/ + +// +k8s:deepcopy-gen=package + +package config // import "k8s.io/component-base/config" diff --git a/vendor/k8s.io/component-base/config/types.go b/vendor/k8s.io/component-base/config/types.go new file mode 100644 index 000000000..489cd880b --- /dev/null +++ b/vendor/k8s.io/component-base/config/types.go @@ -0,0 +1,88 @@ +/* +Copyright 2018 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 config + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ClientConnectionConfiguration contains details for constructing a client. +type ClientConnectionConfiguration struct { + // kubeconfig is the path to a KubeConfig file. + Kubeconfig string + // acceptContentTypes defines the Accept header sent by clients when connecting to a server, overriding the + // default value of 'application/json'. This field will control all connections to the server used by a particular + // client. + AcceptContentTypes string + // contentType is the content type used when sending data to the server from this client. + ContentType string + // qps controls the number of queries per second allowed for this connection. + QPS float32 + // burst allows extra queries to accumulate when a client is exceeding its rate. + Burst int32 +} + +// LeaderElectionConfiguration defines the configuration of leader election +// clients for components that can run with leader election enabled. +type LeaderElectionConfiguration struct { + // leaderElect enables a leader election client to gain leadership + // before executing the main loop. Enable this when running replicated + // components for high availability. + LeaderElect bool + // leaseDuration is the duration that non-leader candidates will wait + // after observing a leadership renewal until attempting to acquire + // leadership of a led but unrenewed leader slot. This is effectively the + // maximum duration that a leader can be stopped before it is replaced + // by another candidate. This is only applicable if leader election is + // enabled. + LeaseDuration metav1.Duration + // renewDeadline is the interval between attempts by the acting master to + // renew a leadership slot before it stops leading. This must be less + // than or equal to the lease duration. This is only applicable if leader + // election is enabled. + RenewDeadline metav1.Duration + // retryPeriod is the duration the clients should wait between attempting + // acquisition and renewal of a leadership. This is only applicable if + // leader election is enabled. + RetryPeriod metav1.Duration + // resourceLock indicates the resource object type that will be used to lock + // during leader election cycles. + ResourceLock string + // resourceName indicates the name of resource object that will be used to lock + // during leader election cycles. + ResourceName string + // resourceName indicates the namespace of resource object that will be used to lock + // during leader election cycles. + ResourceNamespace string +} + +// DebuggingConfiguration holds configuration for Debugging related features. +type DebuggingConfiguration struct { + // enableProfiling enables profiling via web interface host:port/debug/pprof/ + EnableProfiling bool + // enableContentionProfiling enables lock contention profiling, if + // enableProfiling is true. + EnableContentionProfiling bool +} + +// LoggingConfiguration contains logging options +type LoggingConfiguration struct { + // Format Flag specifies the structure of log messages. + // default value of format is `text` + // Refer [Logs Options](https://github.com/kubernetes/component-base/blob/master/logs/options.go) for more information. + Format string +} diff --git a/vendor/k8s.io/component-base/config/zz_generated.deepcopy.go b/vendor/k8s.io/component-base/config/zz_generated.deepcopy.go new file mode 100644 index 000000000..77260a06f --- /dev/null +++ b/vendor/k8s.io/component-base/config/zz_generated.deepcopy.go @@ -0,0 +1,88 @@ +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package config + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClientConnectionConfiguration) DeepCopyInto(out *ClientConnectionConfiguration) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientConnectionConfiguration. +func (in *ClientConnectionConfiguration) DeepCopy() *ClientConnectionConfiguration { + if in == nil { + return nil + } + out := new(ClientConnectionConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DebuggingConfiguration) DeepCopyInto(out *DebuggingConfiguration) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DebuggingConfiguration. +func (in *DebuggingConfiguration) DeepCopy() *DebuggingConfiguration { + if in == nil { + return nil + } + out := new(DebuggingConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LeaderElectionConfiguration) DeepCopyInto(out *LeaderElectionConfiguration) { + *out = *in + out.LeaseDuration = in.LeaseDuration + out.RenewDeadline = in.RenewDeadline + out.RetryPeriod = in.RetryPeriod + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LeaderElectionConfiguration. +func (in *LeaderElectionConfiguration) DeepCopy() *LeaderElectionConfiguration { + if in == nil { + return nil + } + out := new(LeaderElectionConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LoggingConfiguration) DeepCopyInto(out *LoggingConfiguration) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoggingConfiguration. +func (in *LoggingConfiguration) DeepCopy() *LoggingConfiguration { + if in == nil { + return nil + } + out := new(LoggingConfiguration) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/k8s.io/component-base/logs/registry.go b/vendor/k8s.io/component-base/logs/registry.go index 515bba280..c71899db6 100644 --- a/vendor/k8s.io/component-base/logs/registry.go +++ b/vendor/k8s.io/component-base/logs/registry.go @@ -18,6 +18,7 @@ package logs import ( "fmt" + "sort" "github.com/go-logr/logr" json "k8s.io/component-base/logs/json" @@ -84,12 +85,13 @@ func (lfr *LogFormatRegistry) Delete(name string) error { return nil } -// List names of registered log formats +// List names of registered log formats (sorted) func (lfr *LogFormatRegistry) List() []string { formats := make([]string, 0, len(lfr.registry)) for f := range lfr.registry { formats = append(formats, f) } + sort.Strings(formats) return formats } diff --git a/vendor/modules.txt b/vendor/modules.txt index ea8cfdd90..dd5ce4333 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -183,7 +183,7 @@ google.golang.org/protobuf/types/known/timestamppb gopkg.in/inf.v0 # gopkg.in/yaml.v2 v2.2.8 gopkg.in/yaml.v2 -# k8s.io/api v0.19.0 +# k8s.io/api v0.19.2 ## explicit k8s.io/api/admissionregistration/v1 k8s.io/api/admissionregistration/v1beta1 @@ -226,7 +226,7 @@ k8s.io/api/settings/v1alpha1 k8s.io/api/storage/v1 k8s.io/api/storage/v1alpha1 k8s.io/api/storage/v1beta1 -# k8s.io/apimachinery v0.19.0 +# k8s.io/apimachinery v0.19.2 ## explicit k8s.io/apimachinery/pkg/api/errors k8s.io/apimachinery/pkg/api/meta @@ -273,7 +273,7 @@ k8s.io/apimachinery/third_party/forked/golang/reflect # k8s.io/apiserver v0.19.0 ## explicit k8s.io/apiserver/pkg/util/feature -# k8s.io/client-go v0.19.0 +# k8s.io/client-go v0.19.2 ## explicit k8s.io/client-go/discovery k8s.io/client-go/discovery/fake @@ -525,9 +525,10 @@ k8s.io/code-generator/cmd/set-gen k8s.io/code-generator/pkg/namer k8s.io/code-generator/pkg/util k8s.io/code-generator/third_party/forked/golang/reflect -# k8s.io/component-base v0.19.0 +# k8s.io/component-base v0.19.2 ## explicit k8s.io/component-base/cli/flag +k8s.io/component-base/config k8s.io/component-base/featuregate k8s.io/component-base/logs k8s.io/component-base/logs/json