diff --git a/cmd/kubeadm/app/phases/upgrade/BUILD b/cmd/kubeadm/app/phases/upgrade/BUILD index 670706876a71..c8b3f47b5528 100644 --- a/cmd/kubeadm/app/phases/upgrade/BUILD +++ b/cmd/kubeadm/app/phases/upgrade/BUILD @@ -8,7 +8,6 @@ go_library( "health.go", "policy.go", "postupgrade.go", - "postupgrade_v18_19.go", "prepull.go", "selfhosted.go", "staticpods.go", @@ -49,6 +48,7 @@ go_library( "//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/client-go/kubernetes:go_default_library", + "//vendor/k8s.io/client-go/util/cert:go_default_library", ], ) @@ -71,7 +71,7 @@ go_test( srcs = [ "compute_test.go", "policy_test.go", - "postupgrade_v18_19_test.go", + "postupgrade_test.go", "prepull_test.go", "staticpods_test.go", ], diff --git a/cmd/kubeadm/app/phases/upgrade/postupgrade.go b/cmd/kubeadm/app/phases/upgrade/postupgrade.go index a7e98be66ac7..fcfab59b0fad 100644 --- a/cmd/kubeadm/app/phases/upgrade/postupgrade.go +++ b/cmd/kubeadm/app/phases/upgrade/postupgrade.go @@ -19,12 +19,14 @@ package upgrade import ( "fmt" "os" + "path/filepath" "time" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/errors" clientset "k8s.io/client-go/kubernetes" + certutil "k8s.io/client-go/util/cert" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" @@ -41,6 +43,9 @@ import ( "k8s.io/kubernetes/pkg/util/version" ) +var v190alpha3 = version.MustParseSemantic("v1.9.0-alpha.3") +var expiry = 180 * 24 * time.Hour + // PerformPostUpgradeTasks runs nearly the same functions as 'kubeadm init' would do // Note that the markmaster phase is left out, not needed, and no token is created as that doesn't belong to the upgrade func PerformPostUpgradeTasks(client clientset.Interface, cfg *kubeadmapi.MasterConfiguration, newK8sVer *version.Version, dryRun bool) error { @@ -84,7 +89,7 @@ func PerformPostUpgradeTasks(client clientset.Interface, cfg *kubeadmapi.MasterC } certAndKeyDir := kubeadmapiext.DefaultCertificatesDir - shouldBackup, err := shouldBackupAPIServerCertAndKey(certAndKeyDir, newK8sVer) + shouldBackup, err := shouldBackupAPIServerCertAndKey(certAndKeyDir) // Don't fail the upgrade phase if failing to determine to backup kube-apiserver cert and key. if err != nil { fmt.Printf("[postupgrade] WARNING: failed to determine to backup kube-apiserver cert and key: %v", err) @@ -157,3 +162,58 @@ func getWaiter(dryRun bool, client clientset.Interface) apiclient.Waiter { } return apiclient.NewKubeWaiter(client, 30*time.Minute, os.Stdout) } + +// backupAPIServerCertAndKey backups the old cert and key of kube-apiserver to a specified directory. +func backupAPIServerCertAndKey(certAndKeyDir string) error { + subDir := filepath.Join(certAndKeyDir, "expired") + if err := os.Mkdir(subDir, 0766); err != nil { + return fmt.Errorf("failed to created backup directory %s: %v", subDir, err) + } + + filesToMove := map[string]string{ + filepath.Join(certAndKeyDir, kubeadmconstants.APIServerCertName): filepath.Join(subDir, kubeadmconstants.APIServerCertName), + filepath.Join(certAndKeyDir, kubeadmconstants.APIServerKeyName): filepath.Join(subDir, kubeadmconstants.APIServerKeyName), + } + return moveFiles(filesToMove) +} + +// moveFiles moves files from one directory to another. +func moveFiles(files map[string]string) error { + filesToRecover := map[string]string{} + for from, to := range files { + if err := os.Rename(from, to); err != nil { + return rollbackFiles(filesToRecover, err) + } + filesToRecover[to] = from + } + return nil +} + +// rollbackFiles moves the files back to the original directory. +func rollbackFiles(files map[string]string, originalErr error) error { + errs := []error{originalErr} + for from, to := range files { + if err := os.Rename(from, to); err != nil { + errs = append(errs, err) + } + } + return fmt.Errorf("couldn't move these files: %v. Got errors: %v", files, errors.NewAggregate(errs)) +} + +// shouldBackupAPIServerCertAndKey checks if the cert of kube-apiserver will be expired in 180 days. +func shouldBackupAPIServerCertAndKey(certAndKeyDir string) (bool, error) { + apiServerCert := filepath.Join(certAndKeyDir, kubeadmconstants.APIServerCertName) + certs, err := certutil.CertsFromFile(apiServerCert) + if err != nil { + return false, fmt.Errorf("couldn't load the certificate file %s: %v", apiServerCert, err) + } + if len(certs) == 0 { + return false, fmt.Errorf("no certificate data found") + } + + if time.Now().Sub(certs[0].NotBefore) > expiry { + return true, nil + } + + return false, nil +} diff --git a/cmd/kubeadm/app/phases/upgrade/postupgrade_v18_19_test.go b/cmd/kubeadm/app/phases/upgrade/postupgrade_test.go similarity index 91% rename from cmd/kubeadm/app/phases/upgrade/postupgrade_v18_19_test.go rename to cmd/kubeadm/app/phases/upgrade/postupgrade_test.go index 6720202f64bc..652dee2e40bf 100644 --- a/cmd/kubeadm/app/phases/upgrade/postupgrade_v18_19_test.go +++ b/cmd/kubeadm/app/phases/upgrade/postupgrade_test.go @@ -29,7 +29,6 @@ import ( certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs" "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil" testutil "k8s.io/kubernetes/cmd/kubeadm/test" - "k8s.io/kubernetes/pkg/util/version" ) func TestBackupAPIServerCertAndKey(t *testing.T) { @@ -139,20 +138,13 @@ func TestShouldBackupAPIServerCertAndKey(t *testing.T) { for desc, test := range map[string]struct { adjustedExpiry time.Duration - k8sVersion *version.Version expected bool }{ - "1.8 version doesn't need to backup": { - k8sVersion: version.MustParseSemantic("v1.8.0"), - expected: false, + "default: cert not older than 180 days doesn't needs to backup": { + expected: false, }, - "1.9 version with cert not older than 180 days doesn't needs to backup": { - k8sVersion: version.MustParseSemantic("v1.9.0"), - expected: false, - }, - "1.9 version with cert older than 180 days need to backup": { + "cert older than 180 days need to backup": { adjustedExpiry: expiry + 100*time.Hour, - k8sVersion: version.MustParseSemantic("v1.9.0"), expected: true, }, } { @@ -180,7 +172,7 @@ func TestShouldBackupAPIServerCertAndKey(t *testing.T) { } } - shouldBackup, err := shouldBackupAPIServerCertAndKey(tmpdir, test.k8sVersion) + shouldBackup, err := shouldBackupAPIServerCertAndKey(tmpdir) if err != nil { t.Fatalf("Test %s: failed to check shouldBackupAPIServerCertAndKey: %v", desc, err) } diff --git a/cmd/kubeadm/app/phases/upgrade/postupgrade_v18_19.go b/cmd/kubeadm/app/phases/upgrade/postupgrade_v18_19.go deleted file mode 100644 index ef8f5d305d5f..000000000000 --- a/cmd/kubeadm/app/phases/upgrade/postupgrade_v18_19.go +++ /dev/null @@ -1,106 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package upgrade - -import ( - "crypto/x509" - "encoding/pem" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "time" - - "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/kubernetes/cmd/kubeadm/app/constants" - "k8s.io/kubernetes/pkg/util/version" -) - -// TODO: Maybe move these constants elsewhere in future releases -var v190 = version.MustParseSemantic("v1.9.0") -var v190alpha3 = version.MustParseSemantic("v1.9.0-alpha.3") -var expiry = 180 * 24 * time.Hour - -// backupAPIServerCertAndKey backups the old cert and key of kube-apiserver to a specified directory. -func backupAPIServerCertAndKey(certAndKeyDir string) error { - subDir := filepath.Join(certAndKeyDir, "expired") - if err := os.Mkdir(subDir, 0766); err != nil { - return fmt.Errorf("failed to created backup directory %s: %v", subDir, err) - } - - filesToMove := map[string]string{ - filepath.Join(certAndKeyDir, constants.APIServerCertName): filepath.Join(subDir, constants.APIServerCertName), - filepath.Join(certAndKeyDir, constants.APIServerKeyName): filepath.Join(subDir, constants.APIServerKeyName), - } - return moveFiles(filesToMove) -} - -// moveFiles moves files from one directory to another. -func moveFiles(files map[string]string) error { - filesToRecover := map[string]string{} - for from, to := range files { - if err := os.Rename(from, to); err != nil { - return rollbackFiles(filesToRecover, err) - } - filesToRecover[to] = from - } - return nil -} - -// rollbackFiles moves the files back to the original directory. -func rollbackFiles(files map[string]string, originalErr error) error { - errs := []error{originalErr} - for from, to := range files { - if err := os.Rename(from, to); err != nil { - errs = append(errs, err) - } - } - return fmt.Errorf("couldn't move these files: %v. Got errors: %v", files, errors.NewAggregate(errs)) -} - -// shouldBackupAPIServerCertAndKey check if the new k8s version is at least 1.9.0 -// and kube-apiserver will be expired in 60 days. -func shouldBackupAPIServerCertAndKey(certAndKeyDir string, newK8sVer *version.Version) (bool, error) { - if newK8sVer.LessThan(v190) { - return false, nil - } - - apiServerCert := filepath.Join(certAndKeyDir, constants.APIServerCertName) - data, err := ioutil.ReadFile(apiServerCert) - if err != nil { - return false, fmt.Errorf("failed to read kube-apiserver certificate from disk: %v", err) - } - - block, _ := pem.Decode(data) - if block == nil { - return false, fmt.Errorf("expected the kube-apiserver certificate to be PEM encoded") - } - - certs, err := x509.ParseCertificates(block.Bytes) - if err != nil { - return false, fmt.Errorf("unable to parse certificate data: %v", err) - } - if len(certs) == 0 { - return false, fmt.Errorf("no certificate data found") - } - - if time.Now().Sub(certs[0].NotBefore) > expiry { - return true, nil - } - - return false, nil -}