kubeadm: skip upgrade if manifest is not changed

When doing upgrades kubeadm generates new manifest and
waits until kubelet restarts correspondent pod.

However, kubelet won't restart pod if there are no changes
in the manifest. That makes kubeadm stuck waiting for
restarted pod.

Skipping upgrade if new component manifest is the same as
current manifest should solve this.

Fixes: kubernetes/kubeadm#1054
This commit is contained in:
Ed Bartosh 2018-10-16 18:01:53 +03:00
parent ef195428a0
commit ad0179897d
4 changed files with 98 additions and 0 deletions

View File

@ -37,6 +37,7 @@ go_library(
"//cmd/kubeadm/app/util/apiclient:go_default_library",
"//cmd/kubeadm/app/util/dryrun:go_default_library",
"//cmd/kubeadm/app/util/etcd:go_default_library",
"//cmd/kubeadm/app/util/staticpod:go_default_library",
"//pkg/version:go_default_library",
"//staging/src/k8s.io/api/apps/v1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",

View File

@ -32,6 +32,7 @@ import (
"k8s.io/kubernetes/cmd/kubeadm/app/util"
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
etcdutil "k8s.io/kubernetes/cmd/kubeadm/app/util/etcd"
"k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod"
)
const (
@ -201,6 +202,16 @@ func upgradeComponent(component string, waiter apiclient.Waiter, pathMgr StaticP
// Store the backup path in the recover list. If something goes wrong now, this component will be rolled back.
recoverManifests[component] = backupManifestPath
// Skip upgrade if current and new manifests are equal
equal, err := staticpod.ManifestFilesAreEqual(currentManifestPath, newManifestPath)
if err != nil {
return err
}
if equal {
fmt.Printf("[upgrade/staticpods] current and new manifests of %s are equal, skipping upgrade\n", component)
return nil
}
// Move the old manifest into the old-manifests directory
if err := pathMgr.MoveFile(currentManifestPath, backupManifestPath); err != nil {
return rollbackOldManifests(recoverManifests, err, pathMgr, recoverEtcd)

View File

@ -17,6 +17,7 @@ limitations under the License.
package staticpod
import (
"bytes"
"fmt"
"io/ioutil"
"net"
@ -288,3 +289,17 @@ func GetProbeAddress(cfg *kubeadmapi.InitConfiguration, componentName string) st
}
return "127.0.0.1"
}
// ManifestFilesAreEqual compares 2 files. It returns true if their contents are equal, false otherwise
func ManifestFilesAreEqual(path1, path2 string) (bool, error) {
content1, err := ioutil.ReadFile(path1)
if err != nil {
return false, err
}
content2, err := ioutil.ReadFile(path2)
if err != nil {
return false, err
}
return bytes.Equal(content1, content2), nil
}

View File

@ -22,6 +22,7 @@ import (
"path/filepath"
"reflect"
"sort"
"strconv"
"testing"
"k8s.io/api/core/v1"
@ -622,3 +623,73 @@ func TestReadStaticPodFromDisk(t *testing.T) {
}
}
}
func TestManifestFilesAreEqual(t *testing.T) {
var tests = []struct {
description string
podYamls []string
expectedResult bool
expectErr bool
}{
{
description: "manifests are equal",
podYamls: []string{validPod, validPod},
expectedResult: true,
expectErr: false,
},
{
description: "manifests are not equal",
podYamls: []string{validPod, validPod + "\n"},
expectedResult: false,
expectErr: false,
},
{
description: "first manifest doesn't exist",
podYamls: []string{validPod, ""},
expectedResult: false,
expectErr: true,
},
{
description: "second manifest doesn't exist",
podYamls: []string{"", validPod},
expectedResult: false,
expectErr: true,
},
}
for _, rt := range tests {
tmpdir := testutil.SetupTempDir(t)
defer os.RemoveAll(tmpdir)
// write 2 manifests
for i := 0; i < 2; i++ {
if rt.podYamls[i] != "" {
manifestPath := filepath.Join(tmpdir, strconv.Itoa(i)+".yaml")
err := ioutil.WriteFile(manifestPath, []byte(rt.podYamls[i]), 0644)
if err != nil {
t.Fatalf("Failed to write manifest file\n%s\n\tfatal error: %v", rt.description, err)
}
}
}
// compare them
result, actualErr := ManifestFilesAreEqual(filepath.Join(tmpdir, "0.yaml"), filepath.Join(tmpdir, "1.yaml"))
if result != rt.expectedResult {
t.Errorf(
"ManifestFilesAreEqual failed\n%s\nexpected result: %t\nactual result: %t",
rt.description,
rt.expectedResult,
result,
)
}
if (actualErr != nil) != rt.expectErr {
t.Errorf(
"ManifestFilesAreEqual failed\n%s\n\texpected error: %t\n\tgot: %t\n\tactual error: %v",
rt.description,
rt.expectErr,
(actualErr != nil),
actualErr,
)
}
}
}