diff --git a/cmd/kubeadm/app/cmd/upgrade/BUILD b/cmd/kubeadm/app/cmd/upgrade/BUILD index f0a1d60e56..f22be4b443 100644 --- a/cmd/kubeadm/app/cmd/upgrade/BUILD +++ b/cmd/kubeadm/app/cmd/upgrade/BUILD @@ -5,6 +5,7 @@ go_library( srcs = [ "apply.go", "common.go", + "diff.go", "plan.go", "upgrade.go", ], @@ -29,7 +30,9 @@ go_library( "//cmd/kubeadm/app/util/kubeconfig:go_default_library", "//pkg/util/version:go_default_library", "//vendor/github.com/golang/glog:go_default_library", + "//vendor/github.com/pmezard/go-difflib/difflib:go_default_library", "//vendor/github.com/spf13/cobra:go_default_library", + "//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/client-go/discovery/fake:go_default_library", "//vendor/k8s.io/client-go/kubernetes:go_default_library", diff --git a/cmd/kubeadm/app/cmd/upgrade/diff.go b/cmd/kubeadm/app/cmd/upgrade/diff.go new file mode 100644 index 0000000000..957b05f72e --- /dev/null +++ b/cmd/kubeadm/app/cmd/upgrade/diff.go @@ -0,0 +1,139 @@ +/* +Copyright 2018 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 ( + "io/ioutil" + "os" + + "github.com/golang/glog" + "github.com/pmezard/go-difflib/difflib" + "github.com/spf13/cobra" + corev1 "k8s.io/api/core/v1" + kubeadmv1alpha2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha2" + cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util" + "k8s.io/kubernetes/cmd/kubeadm/app/constants" + "k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane" + kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" + configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config" + "k8s.io/kubernetes/pkg/util/version" +) + +type diffFlags struct { + apiServerManifestPath string + controllerManagerManifestPath string + schedulerManifestPath string + newK8sVersionStr string + contextLines int + parent *cmdUpgradeFlags +} + +var ( + defaultAPIServerManifestPath = constants.GetStaticPodFilepath(constants.KubeAPIServer, constants.GetStaticPodDirectory()) + defaultControllerManagerManifestPath = constants.GetStaticPodFilepath(constants.KubeControllerManager, constants.GetStaticPodDirectory()) + defaultSchedulerManifestPath = constants.GetStaticPodFilepath(constants.KubeScheduler, constants.GetStaticPodDirectory()) +) + +// NewCmdDiff returns the cobra command for `kubeadm upgrade diff` +func NewCmdDiff(parentflags *cmdUpgradeFlags) *cobra.Command { + flags := &diffFlags{ + parent: parentflags, + } + + cmd := &cobra.Command{ + Use: "diff [version]", + Short: "Show what differences would be applied to existing static pod manifests. See also: kubeadm upgrade apply --dry-run", + Run: func(cmd *cobra.Command, args []string) { + kubeadmutil.CheckErr(runDiff(flags, args)) + }, + } + + cmd.Flags().StringVar(&flags.apiServerManifestPath, "api-server-manifest", defaultAPIServerManifestPath, "path to API server manifest") + cmd.Flags().StringVar(&flags.controllerManagerManifestPath, "controller-manager-manifest", defaultControllerManagerManifestPath, "path to controller manifest") + cmd.Flags().StringVar(&flags.schedulerManifestPath, "scheduler-manifest", defaultSchedulerManifestPath, "path to scheduler manifest") + cmd.Flags().IntVarP(&flags.contextLines, "context-lines", "c", 3, "How many lines of context in the diff") + + return cmd +} + +func runDiff(flags *diffFlags, args []string) error { + + // If the version is specified in config file, pick up that value. + glog.V(1).Infof("fetching configuration from file", flags.parent.cfgPath) + cfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(flags.parent.cfgPath, &kubeadmv1alpha2.MasterConfiguration{}) + if err != nil { + return err + } + + if cfg.KubernetesVersion != "" { + flags.newK8sVersionStr = cfg.KubernetesVersion + } + + // If the new version is already specified in config file, version arg is optional. + if flags.newK8sVersionStr == "" { + if err := cmdutil.ValidateExactArgNumber(args, []string{"version"}); err != nil { + return err + } + } + + // If option was specified in both args and config file, args will overwrite the config file. + if len(args) == 1 { + flags.newK8sVersionStr = args[0] + } + + k8sVer, err := version.ParseSemantic(flags.newK8sVersionStr) + if err != nil { + return err + } + + specs := controlplane.GetStaticPodSpecs(cfg, k8sVer) + for spec, pod := range specs { + var path string + switch spec { + case constants.KubeAPIServer: + path = flags.apiServerManifestPath + case constants.KubeControllerManager: + path = flags.controllerManagerManifestPath + case constants.KubeScheduler: + path = flags.schedulerManifestPath + default: + glog.Errorf("[diff] unknown spec %v", spec) + continue + } + + newManifest, err := kubeadmutil.MarshalToYaml(&pod, corev1.SchemeGroupVersion) + if err != nil { + return err + } + existingManifest, err := ioutil.ReadFile(path) + if err != nil { + return err + } + + // Populated and write out the diff + diff := difflib.UnifiedDiff{ + A: difflib.SplitLines(string(existingManifest)), + B: difflib.SplitLines(string(newManifest)), + FromFile: path, + ToFile: "new manifest", + Context: flags.contextLines, + } + + difflib.WriteUnifiedDiff(os.Stdout, diff) + } + return nil +} diff --git a/cmd/kubeadm/app/cmd/upgrade/upgrade.go b/cmd/kubeadm/app/cmd/upgrade/upgrade.go index a78a3dad01..1993e67a22 100644 --- a/cmd/kubeadm/app/cmd/upgrade/upgrade.go +++ b/cmd/kubeadm/app/cmd/upgrade/upgrade.go @@ -71,6 +71,7 @@ func NewCmdUpgrade(out io.Writer) *cobra.Command { cmd.AddCommand(NewCmdApply(flags)) cmd.AddCommand(NewCmdPlan(flags)) + cmd.AddCommand(NewCmdDiff(flags)) return cmd } diff --git a/docs/.generated_docs b/docs/.generated_docs index 03be070e47..75fef06ed8 100644 --- a/docs/.generated_docs +++ b/docs/.generated_docs @@ -75,6 +75,7 @@ docs/admin/kubeadm_token_generate.md docs/admin/kubeadm_token_list.md docs/admin/kubeadm_upgrade.md docs/admin/kubeadm_upgrade_apply.md +docs/admin/kubeadm_upgrade_diff.md docs/admin/kubeadm_upgrade_plan.md docs/admin/kubeadm_version.md docs/admin/kubelet.md @@ -152,6 +153,7 @@ docs/man/man1/kubeadm-token-generate.1 docs/man/man1/kubeadm-token-list.1 docs/man/man1/kubeadm-token.1 docs/man/man1/kubeadm-upgrade-apply.1 +docs/man/man1/kubeadm-upgrade-diff.1 docs/man/man1/kubeadm-upgrade-plan.1 docs/man/man1/kubeadm-upgrade.1 docs/man/man1/kubeadm-version.1 diff --git a/docs/admin/kubeadm_upgrade_diff.md b/docs/admin/kubeadm_upgrade_diff.md new file mode 100644 index 0000000000..b6fd7a0f98 --- /dev/null +++ b/docs/admin/kubeadm_upgrade_diff.md @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/kubeadm-upgrade-diff.1 b/docs/man/man1/kubeadm-upgrade-diff.1 new file mode 100644 index 0000000000..b6fd7a0f98 --- /dev/null +++ b/docs/man/man1/kubeadm-upgrade-diff.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file.