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.
This commit is contained in:
Ed Bartosh 2018-10-19 18:05:48 +03:00
parent b7c2d923ef
commit ebb0af9e8f
2 changed files with 27 additions and 6 deletions

View File

@ -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
}

View File

@ -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)
}
}