From 47c573fba64379c242b2031305091f124d10bf85 Mon Sep 17 00:00:00 2001 From: Michael Taufen Date: Thu, 19 Oct 2017 15:42:07 -0700 Subject: [PATCH 1/2] Lift embedded structure out of eviction-related KubeletConfiguration fields - Changes the following KubeletConfiguration fields from `string` to `map[string]string`: - `EvictionHard` - `EvictionSoft` - `EvictionSoftGracePeriod` - `EvictionMinimumReclaim` - Adds flag parsing shims to maintain Kubelet's public flags API, while enabling structured input in the file API. - Also removes `kubeletconfig.ConfigurationMap`, which was an ad-hoc flag parsing shim living in the kubeletconfig API group, and replaces it with the `MapStringString` shim introduced in this PR. Flag parsing shims belong in a common place, not in the kubeletconfig API. I manually audited these to ensure that this wouldn't cause errors parsing the command line for syntax that would have previously been error free (`kubeletconfig.ConfigurationMap` was unique in that it allowed keys to be provided on the CLI without values. I believe this was done in `flags.ConfigurationMap` to facilitate the `--node-labels` flag, which rightfully accepts value-free keys, and that this shim was then just copied to `kubeletconfig`). Fortunately, the affected fields (`ExperimentalQOSReserved`, `SystemReserved`, and `KubeReserved`) expect non-empty strings in the values of the map, and as a result passing the empty string is already an error. Thus requiring keys shouldn't break anyone's scripts. - Updates code and tests accordingly. Regarding eviction operators, directionality is already implicit in the signal type (for a given signal, the decision to evict will be made when crossing the threshold from either above or below, never both). There is no need to expose an operator, such as `<`, in the API. By changing `EvictionHard` and `EvictionSoft` to `map[string]string`, this PR simplifies the experience of working with these fields via the `KubeletConfiguration` type. Again, flags stay the same. Other things: - There is another flag parsing shim, `flags.ConfigurationMap`, from the shared flag utility. The `NodeLabels` field still uses `flags.ConfigurationMap`. This PR moves the allocation of the `map[string]string` for the `NodeLabels` field from `AddKubeletConfigFlags` to the defaulter for the external `KubeletConfiguration` type. Flags are layered on top of an internal object that has undergone conversion from a defaulted external object, which means that previously the mere registration of flags would have overwritten any previously-defined defaults for `NodeLabels` (fortunately there were none). Kubernetes-commit: 1085b6f7304d46697ab9ed2131774ae9d4550ce2 --- pkg/util/flag/BUILD | 10 +- .../langle_separated_map_string_string.go | 87 +++++++++++ ...langle_separated_map_string_string_test.go | 144 ++++++++++++++++++ pkg/util/flag/map_string_bool.go | 42 ++++- pkg/util/flag/map_string_bool_test.go | 125 ++++++++++++--- pkg/util/flag/map_string_string.go | 87 +++++++++++ pkg/util/flag/map_string_string_test.go | 144 ++++++++++++++++++ 7 files changed, 604 insertions(+), 35 deletions(-) create mode 100644 pkg/util/flag/langle_separated_map_string_string.go create mode 100644 pkg/util/flag/langle_separated_map_string_string_test.go create mode 100644 pkg/util/flag/map_string_string.go create mode 100644 pkg/util/flag/map_string_string_test.go diff --git a/pkg/util/flag/BUILD b/pkg/util/flag/BUILD index 9bf629d1a..9cf2715c6 100644 --- a/pkg/util/flag/BUILD +++ b/pkg/util/flag/BUILD @@ -10,16 +10,14 @@ go_test( name = "go_default_test", srcs = [ "colon_separated_multimap_string_string_test.go", + "langle_separated_map_string_string_test.go", "map_string_bool_test.go", + "map_string_string_test.go", "namedcertkey_flag_test.go", ], importpath = "k8s.io/apiserver/pkg/util/flag", library = ":go_default_library", - deps = [ - "//vendor/github.com/spf13/pflag:go_default_library", - "//vendor/github.com/stretchr/testify/assert:go_default_library", - "//vendor/github.com/stretchr/testify/require:go_default_library", - ], + deps = ["//vendor/github.com/spf13/pflag:go_default_library"], ) go_library( @@ -28,7 +26,9 @@ go_library( "colon_separated_multimap_string_string.go", "configuration_map.go", "flags.go", + "langle_separated_map_string_string.go", "map_string_bool.go", + "map_string_string.go", "namedcertkey_flag.go", "string_flag.go", "tristate.go", diff --git a/pkg/util/flag/langle_separated_map_string_string.go b/pkg/util/flag/langle_separated_map_string_string.go new file mode 100644 index 000000000..c2b950e77 --- /dev/null +++ b/pkg/util/flag/langle_separated_map_string_string.go @@ -0,0 +1,87 @@ +/* +Copyright 2017 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 flag + +import ( + "fmt" + "sort" + "strings" +) + +// LangleSeparatedMapStringString can be set from the command line with the format `--flag "string Date: Thu, 16 Nov 2017 14:47:39 -0800 Subject: [PATCH 2/2] omitempty Kubernetes-commit: 617b49858fad83a72ce072356bb2808a259943c5 --- pkg/util/flag/BUILD | 1 + .../langle_separated_map_string_string.go | 15 ++++------ ...langle_separated_map_string_string_test.go | 29 ++++++++++++++----- pkg/util/flag/map_string_bool.go | 15 ++++------ pkg/util/flag/map_string_bool_test.go | 29 ++++++++++++++----- pkg/util/flag/map_string_string.go | 15 ++++------ pkg/util/flag/map_string_string_test.go | 29 ++++++++++++++----- pkg/util/flag/omitempty.go | 24 +++++++++++++++ 8 files changed, 106 insertions(+), 51 deletions(-) create mode 100644 pkg/util/flag/omitempty.go diff --git a/pkg/util/flag/BUILD b/pkg/util/flag/BUILD index 9cf2715c6..57ab4058d 100644 --- a/pkg/util/flag/BUILD +++ b/pkg/util/flag/BUILD @@ -30,6 +30,7 @@ go_library( "map_string_bool.go", "map_string_string.go", "namedcertkey_flag.go", + "omitempty.go", "string_flag.go", "tristate.go", ], diff --git a/pkg/util/flag/langle_separated_map_string_string.go b/pkg/util/flag/langle_separated_map_string_string.go index c2b950e77..bf8dbfb9b 100644 --- a/pkg/util/flag/langle_separated_map_string_string.go +++ b/pkg/util/flag/langle_separated_map_string_string.go @@ -38,10 +38,6 @@ func NewLangleSeparatedMapStringString(m *map[string]string) *LangleSeparatedMap // String implements github.com/spf13/pflag.Value func (m *LangleSeparatedMapStringString) String() string { - if *m.Map == nil { - return "nil" - } - pairs := []string{} for k, v := range *m.Map { pairs = append(pairs, fmt.Sprintf("%s<%s", k, v)) @@ -55,12 +51,6 @@ func (m *LangleSeparatedMapStringString) Set(value string) error { if m.Map == nil { return fmt.Errorf("no target (nil pointer to map[string]string)") } - // allow explicit nil map - if value == "nil" { - *m.Map = nil - m.initialized = true - return nil - } if !m.initialized || *m.Map == nil { // clear default values, or allocate if no existing map *m.Map = make(map[string]string) @@ -85,3 +75,8 @@ func (m *LangleSeparatedMapStringString) Set(value string) error { func (*LangleSeparatedMapStringString) Type() string { return "mapStringString" } + +// Empty implements OmitEmpty +func (m *LangleSeparatedMapStringString) Empty() bool { + return len(*m.Map) == 0 +} diff --git a/pkg/util/flag/langle_separated_map_string_string_test.go b/pkg/util/flag/langle_separated_map_string_string_test.go index fd2ca25a5..80c67c32b 100644 --- a/pkg/util/flag/langle_separated_map_string_string_test.go +++ b/pkg/util/flag/langle_separated_map_string_string_test.go @@ -28,7 +28,7 @@ func TestStringLangleSeparatedMapStringString(t *testing.T) { m *LangleSeparatedMapStringString expect string }{ - {"nil", NewLangleSeparatedMapStringString(&nilMap), "nil"}, + {"nil", NewLangleSeparatedMapStringString(&nilMap), ""}, {"empty", NewLangleSeparatedMapStringString(&map[string]string{}), ""}, {"one key", NewLangleSeparatedMapStringString(&map[string]string{"one": "foo"}), "one