mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-09 20:17:41 +00:00
Merge pull request #119867 from pohly/kube-proxy-verbosity
kube-proxy: fix combination of --config and logging command line flags
This commit is contained in:
commit
18c3c7efb3
@ -235,7 +235,7 @@ func NewOptions() *Options {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Complete completes all the required options.
|
// Complete completes all the required options.
|
||||||
func (o *Options) Complete() error {
|
func (o *Options) Complete(fs *pflag.FlagSet) error {
|
||||||
if len(o.ConfigFile) == 0 && len(o.WriteConfigTo) == 0 {
|
if len(o.ConfigFile) == 0 && len(o.WriteConfigTo) == 0 {
|
||||||
o.config.HealthzBindAddress = addressFromDeprecatedFlags(o.config.HealthzBindAddress, o.healthzPort)
|
o.config.HealthzBindAddress = addressFromDeprecatedFlags(o.config.HealthzBindAddress, o.healthzPort)
|
||||||
o.config.MetricsBindAddress = addressFromDeprecatedFlags(o.config.MetricsBindAddress, o.metricsPort)
|
o.config.MetricsBindAddress = addressFromDeprecatedFlags(o.config.MetricsBindAddress, o.metricsPort)
|
||||||
@ -247,6 +247,14 @@ func (o *Options) Complete() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Before we overwrite the config which holds the parsed
|
||||||
|
// command line parameters, we need to copy all modified
|
||||||
|
// logging settings over to the loaded config (i.e. logging
|
||||||
|
// command line flags have priority). Otherwise `--config
|
||||||
|
// ... -v=5` doesn't work (config resets verbosity even
|
||||||
|
// when it contains no logging settings).
|
||||||
|
copyLogsFromFlags(fs, &c.Logging)
|
||||||
o.config = c
|
o.config = c
|
||||||
|
|
||||||
if err := o.initWatcher(); err != nil {
|
if err := o.initWatcher(); err != nil {
|
||||||
@ -263,6 +271,39 @@ func (o *Options) Complete() error {
|
|||||||
return utilfeature.DefaultMutableFeatureGate.SetFromMap(o.config.FeatureGates)
|
return utilfeature.DefaultMutableFeatureGate.SetFromMap(o.config.FeatureGates)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// copyLogsFromFlags applies the logging flags from the given flag set to the given
|
||||||
|
// configuration. Fields for which the corresponding flag was not used are left
|
||||||
|
// unmodified. For fields that have multiple values (like vmodule), the values from
|
||||||
|
// the flags get joined so that the command line flags have priority.
|
||||||
|
//
|
||||||
|
// TODO (pohly): move this to logsapi
|
||||||
|
func copyLogsFromFlags(from *pflag.FlagSet, to *logsapi.LoggingConfiguration) error {
|
||||||
|
var cloneFS pflag.FlagSet
|
||||||
|
logsapi.AddFlags(to, &cloneFS)
|
||||||
|
vmodule := to.VModule
|
||||||
|
to.VModule = nil
|
||||||
|
var err error
|
||||||
|
cloneFS.VisitAll(func(f *pflag.Flag) {
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fsFlag := from.Lookup(f.Name)
|
||||||
|
if fsFlag == nil {
|
||||||
|
err = fmt.Errorf("logging flag %s not found in flag set", f.Name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !fsFlag.Changed {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if setErr := f.Value.Set(fsFlag.Value.String()); setErr != nil {
|
||||||
|
err = fmt.Errorf("copying flag %s value: %v", f.Name, setErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
to.VModule = append(to.VModule, vmodule...)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Creates a new filesystem watcher and adds watches for the config file.
|
// Creates a new filesystem watcher and adds watches for the config file.
|
||||||
func (o *Options) initWatcher() error {
|
func (o *Options) initWatcher() error {
|
||||||
fswatcher := filesystem.NewFsnotifyWatcher()
|
fswatcher := filesystem.NewFsnotifyWatcher()
|
||||||
@ -476,7 +517,7 @@ with the apiserver API to configure the proxy.`,
|
|||||||
return fmt.Errorf("failed os init: %w", err)
|
return fmt.Errorf("failed os init: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := opts.Complete(); err != nil {
|
if err := opts.Complete(cmd.Flags()); err != nil {
|
||||||
return fmt.Errorf("failed complete: %w", err)
|
return fmt.Errorf("failed complete: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/pflag"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
@ -563,7 +564,7 @@ detectLocalMode: "BridgeInterface"`)
|
|||||||
|
|
||||||
opt := NewOptions()
|
opt := NewOptions()
|
||||||
opt.ConfigFile = file.Name()
|
opt.ConfigFile = file.Name()
|
||||||
err = opt.Complete()
|
err = opt.Complete(new(pflag.FlagSet))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -19,13 +19,18 @@ package app
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"path"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
clientsetfake "k8s.io/client-go/kubernetes/fake"
|
clientsetfake "k8s.io/client-go/kubernetes/fake"
|
||||||
componentbaseconfig "k8s.io/component-base/config"
|
componentbaseconfig "k8s.io/component-base/config"
|
||||||
@ -364,6 +369,125 @@ func TestProcessHostnameOverrideFlag(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestOptionsComplete checks that command line flags are combined with a
|
||||||
|
// config properly.
|
||||||
|
func TestOptionsComplete(t *testing.T) {
|
||||||
|
header := `apiVersion: kubeproxy.config.k8s.io/v1alpha1
|
||||||
|
kind: KubeProxyConfiguration
|
||||||
|
`
|
||||||
|
|
||||||
|
// Determine default config (depends on platform defaults).
|
||||||
|
o := NewOptions()
|
||||||
|
require.NoError(t, o.Complete(new(pflag.FlagSet)))
|
||||||
|
expected := o.config
|
||||||
|
|
||||||
|
config := header + `logging:
|
||||||
|
format: json
|
||||||
|
flushFrequency: 1s
|
||||||
|
verbosity: 10
|
||||||
|
vmodule:
|
||||||
|
- filePattern: foo.go
|
||||||
|
verbosity: 6
|
||||||
|
- filePattern: bar.go
|
||||||
|
verbosity: 8
|
||||||
|
`
|
||||||
|
expectedLoggingConfig := logsapi.LoggingConfiguration{
|
||||||
|
Format: "json",
|
||||||
|
FlushFrequency: logsapi.TimeOrMetaDuration{Duration: metav1.Duration{Duration: time.Second}, SerializeAsString: true},
|
||||||
|
Verbosity: 10,
|
||||||
|
VModule: []logsapi.VModuleItem{
|
||||||
|
{
|
||||||
|
FilePattern: "foo.go",
|
||||||
|
Verbosity: 6,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
FilePattern: "bar.go",
|
||||||
|
Verbosity: 8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Options: logsapi.FormatOptions{
|
||||||
|
JSON: logsapi.JSONOptions{
|
||||||
|
InfoBufferSize: resource.QuantityValue{Quantity: resource.MustParse("0")},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, tc := range map[string]struct {
|
||||||
|
config string
|
||||||
|
flags []string
|
||||||
|
expected *kubeproxyconfig.KubeProxyConfiguration
|
||||||
|
}{
|
||||||
|
"empty": {
|
||||||
|
expected: expected,
|
||||||
|
},
|
||||||
|
"empty-config": {
|
||||||
|
config: header,
|
||||||
|
expected: expected,
|
||||||
|
},
|
||||||
|
"logging-config": {
|
||||||
|
config: config,
|
||||||
|
expected: func() *kubeproxyconfig.KubeProxyConfiguration {
|
||||||
|
c := expected.DeepCopy()
|
||||||
|
c.Logging = *expectedLoggingConfig.DeepCopy()
|
||||||
|
return c
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
"flags": {
|
||||||
|
flags: []string{
|
||||||
|
"-v=7",
|
||||||
|
"--vmodule", "goo.go=8",
|
||||||
|
},
|
||||||
|
expected: func() *kubeproxyconfig.KubeProxyConfiguration {
|
||||||
|
c := expected.DeepCopy()
|
||||||
|
c.Logging.Verbosity = 7
|
||||||
|
c.Logging.VModule = append(c.Logging.VModule, logsapi.VModuleItem{
|
||||||
|
FilePattern: "goo.go",
|
||||||
|
Verbosity: 8,
|
||||||
|
})
|
||||||
|
return c
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
"both": {
|
||||||
|
config: config,
|
||||||
|
flags: []string{
|
||||||
|
"-v=7",
|
||||||
|
"--vmodule", "goo.go=8",
|
||||||
|
"--ipvs-scheduler", "some-scheduler", // Overwritten by config.
|
||||||
|
},
|
||||||
|
expected: func() *kubeproxyconfig.KubeProxyConfiguration {
|
||||||
|
c := expected.DeepCopy()
|
||||||
|
c.Logging = *expectedLoggingConfig.DeepCopy()
|
||||||
|
// Flag wins.
|
||||||
|
c.Logging.Verbosity = 7
|
||||||
|
// Flag and config get merged with command line flags first.
|
||||||
|
c.Logging.VModule = append([]logsapi.VModuleItem{
|
||||||
|
{
|
||||||
|
FilePattern: "goo.go",
|
||||||
|
Verbosity: 8,
|
||||||
|
},
|
||||||
|
}, c.Logging.VModule...)
|
||||||
|
return c
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
options := NewOptions()
|
||||||
|
fs := new(pflag.FlagSet)
|
||||||
|
options.AddFlags(fs)
|
||||||
|
flags := tc.flags
|
||||||
|
if len(tc.config) > 0 {
|
||||||
|
tmp := t.TempDir()
|
||||||
|
configFile := path.Join(tmp, "kube-proxy.conf")
|
||||||
|
require.NoError(t, ioutil.WriteFile(configFile, []byte(tc.config), 0666))
|
||||||
|
flags = append(flags, "--config", configFile)
|
||||||
|
}
|
||||||
|
require.NoError(t, fs.Parse(flags))
|
||||||
|
require.NoError(t, options.Complete(fs))
|
||||||
|
assert.Equal(t, tc.expected, options.config)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type fakeProxyServerLongRun struct{}
|
type fakeProxyServerLongRun struct{}
|
||||||
|
|
||||||
// Run runs the specified ProxyServer.
|
// Run runs the specified ProxyServer.
|
||||||
|
Loading…
Reference in New Issue
Block a user