kubeadm: Retire MarshalClusterConfigurationToBytes

MarshalClusterConfigurationToBytes has capabilities to output the component
configs, as separate YAML documents, besides the kubeadm ClusterConfiguration
kind. This is no longer necessary for the following reasons:

- All current use cases of this function require only the ClusterConfiguration.
- It will output component configs only if they are not the default ones. This
  can produce undeterministic output and, thus, cause potential problems.
- There are only hacky ways to dump the ClusterConfiguration only (without the
  component configs).

Hence, we simplify things by replacing the function with direct calls to the
underlaying MarshalToYamlForCodecs. Thus marshalling only ClusterConfiguration,
when needed.

Signed-off-by: Rostislav M. Georgiev <rostislavg@vmware.com>
This commit is contained in:
Rostislav M. Georgiev 2019-06-19 17:06:47 +03:00
parent 4e0b76469f
commit 94c56c81ba
3 changed files with 1 additions and 152 deletions

View File

@ -41,8 +41,6 @@ func MarshalKubeadmConfigObject(obj runtime.Object) ([]byte, error) {
switch internalcfg := obj.(type) {
case *kubeadmapi.InitConfiguration:
return MarshalInitConfigurationToBytes(internalcfg, kubeadmapiv1beta2.SchemeGroupVersion)
case *kubeadmapi.ClusterConfiguration:
return MarshalClusterConfigurationToBytes(internalcfg, kubeadmapiv1beta2.SchemeGroupVersion)
default:
return kubeadmutil.MarshalToYamlForCodecs(obj, kubeadmapiv1beta2.SchemeGroupVersion, kubeadmscheme.Codecs)
}

View File

@ -21,8 +21,6 @@ import (
"fmt"
"io/ioutil"
"net"
"reflect"
"sort"
"strconv"
"github.com/pkg/errors"
@ -342,7 +340,7 @@ func MarshalInitConfigurationToBytes(cfg *kubeadmapi.InitConfiguration, gv schem
// Exception: If the specified groupversion is targeting the internal type, don't print embedded ClusterConfiguration contents
// This is mostly used for unit testing. In a real scenario the internal version of the API is never marshalled as-is.
if gv.Version != runtime.APIVersionInternal {
clusterbytes, err := MarshalClusterConfigurationToBytes(&cfg.ClusterConfiguration, gv)
clusterbytes, err := kubeadmutil.MarshalToYamlForCodecs(&cfg.ClusterConfiguration, gv, kubeadmscheme.Codecs)
if err != nil {
return []byte{}, err
}
@ -350,60 +348,3 @@ func MarshalInitConfigurationToBytes(cfg *kubeadmapi.InitConfiguration, gv schem
}
return bytes.Join(allFiles, []byte(kubeadmconstants.YAMLDocumentSeparator)), nil
}
// MarshalClusterConfigurationToBytes marshals the internal ClusterConfiguration object to bytes. It writes the embedded
// ComponentConfiguration objects out as separate YAML documents
func MarshalClusterConfigurationToBytes(clustercfg *kubeadmapi.ClusterConfiguration, gv schema.GroupVersion) ([]byte, error) {
clusterbytes, err := kubeadmutil.MarshalToYamlForCodecs(clustercfg, gv, kubeadmscheme.Codecs)
if err != nil {
return []byte{}, err
}
allFiles := [][]byte{clusterbytes}
componentConfigContent := map[string][]byte{}
defaultedcfg := defaultedInternalConfig()
for kind, registration := range componentconfigs.Known {
// If the ComponentConfig struct for the current registration is nil, skip it when marshalling
realobj, ok := registration.GetFromInternalConfig(clustercfg)
if !ok {
continue
}
defaultedobj, ok := registration.GetFromInternalConfig(defaultedcfg)
// Invalid: The caller asked to not print the componentconfigs if defaulted, but defaultComponentConfigs() wasn't able to create default objects to use for reference
if !ok {
return []byte{}, errors.New("couldn't create a default componentconfig object")
}
// If the real ComponentConfig object differs from the default, print it out. If not, there's no need to print it out, so skip it
if !reflect.DeepEqual(realobj, defaultedobj) {
contentBytes, err := registration.Marshal(realobj)
if err != nil {
return []byte{}, err
}
componentConfigContent[string(kind)] = contentBytes
}
}
// Sort the ComponentConfig files by kind when marshalling
sortedComponentConfigFiles := consistentOrderByteSlice(componentConfigContent)
allFiles = append(allFiles, sortedComponentConfigFiles...)
return bytes.Join(allFiles, []byte(kubeadmconstants.YAMLDocumentSeparator)), nil
}
// consistentOrderByteSlice takes a map of a string key and a byte slice, and returns a byte slice of byte slices
// with consistent ordering, where the keys in the map determine the ordering of the return value. This has to be
// done as the order of a for...range loop over a map in go is undeterministic, and could otherwise lead to flakes
// in e.g. unit tests when marshalling content with a random order
func consistentOrderByteSlice(content map[string][]byte) [][]byte {
keys := []string{}
sortedContent := [][]byte{}
for key := range content {
keys = append(keys, key)
}
sort.Strings(keys)
for _, key := range keys {
sortedContent = append(sortedContent, content[key])
}
return sortedContent
}

View File

@ -21,7 +21,6 @@ import (
"io/ioutil"
"os"
"path/filepath"
"reflect"
"testing"
"github.com/pmezard/go-difflib/difflib"
@ -199,95 +198,6 @@ func TestInitConfigurationMarshallingFromFile(t *testing.T) {
}
*/
func TestConsistentOrderByteSlice(t *testing.T) {
var (
aKind = "Akind"
aFile = []byte(`
kind: Akind
apiVersion: foo.k8s.io/v1
`)
aaKind = "Aakind"
aaFile = []byte(`
kind: Aakind
apiVersion: foo.k8s.io/v1
`)
abKind = "Abkind"
abFile = []byte(`
kind: Abkind
apiVersion: foo.k8s.io/v1
`)
)
var tests = []struct {
name string
in map[string][]byte
expected [][]byte
}{
{
name: "a_aa_ab",
in: map[string][]byte{
aKind: aFile,
aaKind: aaFile,
abKind: abFile,
},
expected: [][]byte{aaFile, abFile, aFile},
},
{
name: "a_ab_aa",
in: map[string][]byte{
aKind: aFile,
abKind: abFile,
aaKind: aaFile,
},
expected: [][]byte{aaFile, abFile, aFile},
},
{
name: "aa_a_ab",
in: map[string][]byte{
aaKind: aaFile,
aKind: aFile,
abKind: abFile,
},
expected: [][]byte{aaFile, abFile, aFile},
},
{
name: "aa_ab_a",
in: map[string][]byte{
aaKind: aaFile,
abKind: abFile,
aKind: aFile,
},
expected: [][]byte{aaFile, abFile, aFile},
},
{
name: "ab_a_aa",
in: map[string][]byte{
abKind: abFile,
aKind: aFile,
aaKind: aaFile,
},
expected: [][]byte{aaFile, abFile, aFile},
},
{
name: "ab_aa_a",
in: map[string][]byte{
abKind: abFile,
aaKind: aaFile,
aKind: aFile,
},
expected: [][]byte{aaFile, abFile, aFile},
},
}
for _, rt := range tests {
t.Run(rt.name, func(t2 *testing.T) {
actual := consistentOrderByteSlice(rt.in)
if !reflect.DeepEqual(rt.expected, actual) {
t2.Errorf("the expected and actual output differs.\n\texpected: %s\n\tout: %s\n", rt.expected, actual)
}
})
}
}
func TestDefaultTaintsMarshaling(t *testing.T) {
tests := []struct {
desc string