From ebb0af9e8f30a19c8e08cb2c2bbd62463e5bf9f2 Mon Sep 17 00:00:00 2001 From: Ed Bartosh Date: Fri, 19 Oct 2018 18:05:48 +0300 Subject: [PATCH] kubeadm: sort pod Volumes and VolumeMounts Order of Volumes and VolumeMounts in the pod objects created by kubeadm is undefined as they're represended as maps in the controlPlaneHostPathMounts struct. This influences 'kubeadm upgrade' logic in a way that even when manifest of the component is not changed kubeadm tries to upgrade it because most of the time current and new pods are not equal due to the different order of Volumes and VolumeMounts. For example 'kubeadm apply diff' almost always shows difference in Volumes and VolumeMounts because of this: volumeMounts: + - mountPath: /etc/kubernetes/pki + name: k8s-certs + readOnly: true - mountPath: /etc/ssl/certs name: ca-certs + readOnly: true + - mountPath: /etc/pki + name: etc-pki + readOnly: true + - mountPath: /usr/share/ca-certificates + name: usr-share-ca-certificates readOnly: true - mountPath: /etc/ca-certificates name: etc-ca-certificates readOnly: true - - mountPath: /etc/pki - name: etc-pki - readOnly: true - - mountPath: /etc/kubernetes/pki - name: k8s-certs - readOnly: true - - mountPath: /usr/share/ca-certificates - name: usr-share-ca-certificates - readOnly: true Sorting Volumes and VolumeMounts should fix this issue and help to avoid unnecessary upgrades. --- cmd/kubeadm/app/util/staticpod/utils.go | 9 ++++++++ cmd/kubeadm/app/util/staticpod/utils_test.go | 24 +++++++++++++++----- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/cmd/kubeadm/app/util/staticpod/utils.go b/cmd/kubeadm/app/util/staticpod/utils.go index 8df649594af..9b0e56e872e 100644 --- a/cmd/kubeadm/app/util/staticpod/utils.go +++ b/cmd/kubeadm/app/util/staticpod/utils.go @@ -22,6 +22,7 @@ import ( "net" "net/url" "os" + "sort" "strings" "k8s.io/api/core/v1" @@ -147,6 +148,10 @@ func VolumeMapToSlice(volumes map[string]v1.Volume) []v1.Volume { v = append(v, vol) } + sort.Slice(v, func(i, j int) bool { + return strings.Compare(v[i].Name, v[j].Name) == -1 + }) + return v } @@ -158,6 +163,10 @@ func VolumeMountMapToSlice(volumeMounts map[string]v1.VolumeMount) []v1.VolumeMo v = append(v, volMount) } + sort.Slice(v, func(i, j int) bool { + return strings.Compare(v[i].Name, v[j].Name) == -1 + }) + return v } diff --git a/cmd/kubeadm/app/util/staticpod/utils_test.go b/cmd/kubeadm/app/util/staticpod/utils_test.go index ea9a1657d4e..288bb5f4c27 100644 --- a/cmd/kubeadm/app/util/staticpod/utils_test.go +++ b/cmd/kubeadm/app/util/staticpod/utils_test.go @@ -481,13 +481,19 @@ func TestVolumeMapToSlice(t *testing.T) { "foo": { Name: "foo", }, + "bar": { + Name: "bar", + }, } volumeSlice := VolumeMapToSlice(testVolumes) - if len(volumeSlice) != 1 { + if len(volumeSlice) != 2 { t.Errorf("Expected slice length of 1, got %d", len(volumeSlice)) } - if volumeSlice[0].Name != "foo" { - t.Errorf("Expected volume name \"foo\", got %s", volumeSlice[0].Name) + if volumeSlice[0].Name != "bar" { + t.Errorf("Expected first volume name \"bar\", got %s", volumeSlice[0].Name) + } + if volumeSlice[1].Name != "foo" { + t.Errorf("Expected second volume name \"foo\", got %s", volumeSlice[1].Name) } } @@ -496,13 +502,19 @@ func TestVolumeMountMapToSlice(t *testing.T) { "foo": { Name: "foo", }, + "bar": { + Name: "bar", + }, } volumeMountSlice := VolumeMountMapToSlice(testVolumeMounts) - if len(volumeMountSlice) != 1 { + if len(volumeMountSlice) != 2 { t.Errorf("Expected slice length of 1, got %d", len(volumeMountSlice)) } - if volumeMountSlice[0].Name != "foo" { - t.Errorf("Expected volume mount name \"foo\", got %s", volumeMountSlice[0].Name) + if volumeMountSlice[0].Name != "bar" { + t.Errorf("Expected first volume mount name \"bar\", got %s", volumeMountSlice[0].Name) + } + if volumeMountSlice[1].Name != "foo" { + t.Errorf("Expected second volume name \"foo\", got %s", volumeMountSlice[1].Name) } }