kubeadm: Fix omitempty in v1beta2

There are a couple of problems with regards to the `omitempty` in v1beta1:

- It is not applied to certain fields. This makes emitting YAML configuration
  files in v1beta1 config format verbose by both kubeadm and third party Go
  lang tools. Certain fields, that were never given an explicit value would
  show up in the marshalled YAML document. This can cause confusion and even
  misconfiguration.

- It can be used in inappropriate places. In this case it's used for fields,
  that need to be always serialized. The only one such field at the moment is
  `NodeRegistrationOptions.Taints`. If the `Taints` field is nil, then it's
  defaulted to a slice containing a single control plane node taint. If it's
  an empty slice, no taints are applied, thus, the cluster behaves differently.
  With that in mind, a Go program, that uses v1beta1 with `omitempty` on the
  `Taints` field has no way to specify an explicit empty slice of taints, as
  this would get lost after marshalling to YAML.

To fix these issues the following is done in this change:

- A whole bunch of additional omitemptys are placed at many fields in v1beta2.
- `omitempty` is removed from `NodeRegistrationOptions.Taints`
- A test, that verifies the ability to specify empty slice value for `Taints`
  is included.

Signed-off-by: Rostislav M. Georgiev <rostislavg@vmware.com>
This commit is contained in:
Rostislav M. Georgiev
2019-05-02 18:41:33 +03:00
parent 1626aa56d0
commit 81e3adc53b
5 changed files with 101 additions and 29 deletions

View File

@@ -68,6 +68,7 @@ go_test(
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
"//vendor/github.com/lithammer/dedent:go_default_library",
"//vendor/github.com/pmezard/go-difflib/difflib:go_default_library",
"//vendor/sigs.k8s.io/yaml:go_default_library",
],
)

View File

@@ -26,7 +26,11 @@ import (
"github.com/pmezard/go-difflib/difflib"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kubeadmapiv1beta2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2"
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
"sigs.k8s.io/yaml"
)
func diff(expected, actual []byte) string {
@@ -283,3 +287,80 @@ apiVersion: foo.k8s.io/v1
})
}
}
func TestDefaultTaintsMarshaling(t *testing.T) {
tests := []struct {
desc string
cfg kubeadmapiv1beta2.InitConfiguration
expectedTaintCnt int
}{
{
desc: "Uninitialized nodeRegistration field produces a single taint (the master one)",
cfg: kubeadmapiv1beta2.InitConfiguration{
TypeMeta: metav1.TypeMeta{
APIVersion: "kubeadm.k8s.io/v1beta2",
Kind: constants.InitConfigurationKind,
},
},
expectedTaintCnt: 1,
},
{
desc: "Uninitialized taints field produces a single taint (the master one)",
cfg: kubeadmapiv1beta2.InitConfiguration{
TypeMeta: metav1.TypeMeta{
APIVersion: "kubeadm.k8s.io/v1beta2",
Kind: constants.InitConfigurationKind,
},
NodeRegistration: kubeadmapiv1beta2.NodeRegistrationOptions{},
},
expectedTaintCnt: 1,
},
{
desc: "Forsing taints to an empty slice produces no taints",
cfg: kubeadmapiv1beta2.InitConfiguration{
TypeMeta: metav1.TypeMeta{
APIVersion: "kubeadm.k8s.io/v1beta2",
Kind: constants.InitConfigurationKind,
},
NodeRegistration: kubeadmapiv1beta2.NodeRegistrationOptions{
Taints: []v1.Taint{},
},
},
expectedTaintCnt: 0,
},
{
desc: "Custom taints are used",
cfg: kubeadmapiv1beta2.InitConfiguration{
TypeMeta: metav1.TypeMeta{
APIVersion: "kubeadm.k8s.io/v1beta2",
Kind: constants.InitConfigurationKind,
},
NodeRegistration: kubeadmapiv1beta2.NodeRegistrationOptions{
Taints: []v1.Taint{
{Key: "taint1"},
{Key: "taint2"},
},
},
},
expectedTaintCnt: 2,
},
}
for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
b, err := yaml.Marshal(tc.cfg)
if err != nil {
t.Fatalf("unexpected error while marshalling to YAML: %v", err)
}
cfg, err := BytesToInitConfiguration(b)
if err != nil {
t.Fatalf("unexpected error of BytesToInitConfiguration: %v\nconfig: %s", err, string(b))
}
if tc.expectedTaintCnt != len(cfg.NodeRegistration.Taints) {
t.Fatalf("unexpected taints count\nexpected: %d\ngot: %d\ntaints: %v", tc.expectedTaintCnt, len(cfg.NodeRegistration.Taints), cfg.NodeRegistration.Taints)
}
})
}
}

View File

@@ -11,3 +11,4 @@ kind: JoinConfiguration
nodeRegistration:
criSocket: /var/run/dockershim.sock
name: thegopher
taints: null