Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Require extra flag when updating cluster with downgraded kops version #9362

Merged
merged 1 commit into from
Jul 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions cmd/kops/update_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,12 @@ var (
)

type UpdateClusterOptions struct {
Yes bool
Target string
OutDir string
SSHPublicKey string
RunTasksOptions fi.RunTasksOptions
Yes bool
Target string
OutDir string
SSHPublicKey string
RunTasksOptions fi.RunTasksOptions
AllowKopsDowngrade bool

CreateKubecfg bool
admin bool
Expand Down Expand Up @@ -117,6 +118,7 @@ func NewCmdUpdateCluster(f *util.Factory, out io.Writer) *cobra.Command {
cmd.Flags().BoolVar(&options.CreateKubecfg, "create-kube-config", options.CreateKubecfg, "Will control automatically creating the kube config file on your local filesystem")
cmd.Flags().BoolVar(&options.admin, "admin", options.admin, "Also export the admin user. Implies --create-kube-config")
cmd.Flags().StringVar(&options.user, "user", options.user, "Existing user to add to the cluster context. Implies --create-kube-config")
cmd.Flags().BoolVar(&options.AllowKopsDowngrade, "allow-kops-downgrade", options.AllowKopsDowngrade, "Allow an older version of kops to update the cluster than last used")
cmd.Flags().StringVar(&options.Phase, "phase", options.Phase, "Subset of tasks to run: "+strings.Join(cloudup.Phases.List(), ", "))
cmd.Flags().StringSliceVar(&options.LifecycleOverrides, "lifecycle-overrides", options.LifecycleOverrides, "comma separated list of phase overrides, example: SecurityGroups=Ignore,InternetGateway=ExistsAndWarnIfChanges")
viper.BindPFlag("lifecycle-overrides", cmd.Flags().Lookup("lifecycle-overrides"))
Expand Down Expand Up @@ -259,6 +261,7 @@ func RunUpdateCluster(ctx context.Context, f *util.Factory, clusterName string,
Clientset: clientset,
Cluster: cluster,
DryRun: isDryrun,
AllowKopsDowngrade: c.AllowKopsDowngrade,
RunTasksOptions: &c.RunTasksOptions,
OutDir: c.OutDir,
Phase: phase,
Expand Down
1 change: 1 addition & 0 deletions docs/cli/kops_update_cluster.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ kops update cluster [flags]

```
--admin Also export the admin user. Implies --create-kube-config
--allow-kops-downgrade Allow an older version of kops to update the cluster than last used
--create-kube-config Will control automatically creating the kube config file on your local filesystem
-h, --help help for cluster
--lifecycle-overrides strings comma separated list of phase overrides, example: SecurityGroups=Ignore,InternetGateway=ExistsAndWarnIfChanges
Expand Down
3 changes: 3 additions & 0 deletions docs/releases/1.19-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ Similarly, `kops export kubecfg` will also require passing either the `--admin`

* New clusters running Cilium will have enabled BPF NodePort by default if kubernetes version is 1.12 or newer.

* The `kops update cluster` command will now refuse to run on a cluster that
has been updated by a newer version of kops unless it is given the `--allow-kops-downgrade` flag.

# Breaking changes

* Support for Kubernetes 1.9 and 1.10 has been removed.
Expand Down
2 changes: 2 additions & 0 deletions pkg/apis/kops/registry/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ const (
PathCluster = "config"
// Path for completed cluster spec in the state store
PathClusterCompleted = "cluster.spec"
// PathKopsVersionUpdated is the path for the version of kops last used to apply the cluster.
PathKopsVersionUpdated = "kops-version.txt"
)

func ConfigBase(c *api.Cluster) (vfs.Path, error) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/client/simple/vfsclientset/clientset.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ func DeleteAllClusterState(basePath vfs.Path) error {
continue
}

if relativePath == "config" || relativePath == "cluster.spec" {
if relativePath == "config" || relativePath == "cluster.spec" || relativePath == registry.PathKopsVersionUpdated {
continue
}
if strings.HasPrefix(relativePath, "addons/") {
Expand Down
1 change: 1 addition & 0 deletions upup/pkg/fi/cloudup/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ go_library(
"//dnsprovider/pkg/dnsprovider:go_default_library",
"//dnsprovider/pkg/dnsprovider/providers/aws/route53:go_default_library",
"//dnsprovider/pkg/dnsprovider/rrstype:go_default_library",
"//pkg/acls:go_default_library",
"//pkg/apis/kops:go_default_library",
"//pkg/apis/kops/model:go_default_library",
"//pkg/apis/kops/registry:go_default_library",
Expand Down
48 changes: 43 additions & 5 deletions upup/pkg/fi/cloudup/apply_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package cloudup

import (
"bytes"
"context"
"fmt"
"net/url"
Expand All @@ -28,6 +29,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/klog"
kopsbase "k8s.io/kops"
"k8s.io/kops/pkg/acls"
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/apis/kops/registry"
"k8s.io/kops/pkg/apis/kops/util"
Expand Down Expand Up @@ -112,6 +114,9 @@ type ApplyClusterCmd struct {
// DryRun is true if this is only a dry run
DryRun bool

// AllowKopsDowngrade permits applying with a kops version older than what was last used to apply to the cluster.
AllowKopsDowngrade bool

// RunTasksOptions defines parameters for task execution, e.g. retry interval
RunTasksOptions *fi.RunTasksOptions

Expand Down Expand Up @@ -229,6 +234,35 @@ func (c *ApplyClusterCmd) Run(ctx context.Context) error {

cluster := c.Cluster

configBase, err := vfs.Context.BuildVfsPath(cluster.Spec.ConfigBase)
if err != nil {
return fmt.Errorf("error parsing config base %q: %v", cluster.Spec.ConfigBase, err)
}

if !c.AllowKopsDowngrade {
kopsVersionUpdatedBytes, err := configBase.Join(registry.PathKopsVersionUpdated).ReadFile()
if err == nil {
kopsVersionUpdated := strings.TrimSpace(string(kopsVersionUpdatedBytes))
version, err := semver.Parse(kopsVersionUpdated)
if err != nil {
return fmt.Errorf("error parsing last kops version updated: %v", err)
}
if version.GT(semver.MustParse(kopsbase.Version)) {
fmt.Printf("\n")
fmt.Printf("%s\n", starline)
fmt.Printf("\n")
fmt.Printf("The cluster was last updated by kops version %s\n", kopsVersionUpdated)
fmt.Printf("To permit updating by the older version %s, run with the --allow-kops-downgrade flag\n", kopsbase.Version)
fmt.Printf("\n")
fmt.Printf("%s\n", starline)
fmt.Printf("\n")
return fmt.Errorf("kops version older than last used to update the cluster")
}
} else if err != os.ErrNotExist {
return fmt.Errorf("error reading last kops version used to update: %v", err)
}
}

cloud, err := BuildCloud(cluster)
if err != nil {
return err
Expand All @@ -250,11 +284,6 @@ func (c *ApplyClusterCmd) Run(ctx context.Context) error {
l.Init()
l.Cluster = c.Cluster

configBase, err := vfs.Context.BuildVfsPath(cluster.Spec.ConfigBase)
if err != nil {
return fmt.Errorf("error parsing config base %q: %v", cluster.Spec.ConfigBase, err)
}

keyStore, err := c.Clientset.KeyStore(cluster)
if err != nil {
return err
Expand Down Expand Up @@ -743,6 +772,15 @@ func (c *ApplyClusterCmd) Run(ctx context.Context) error {
c.Target = target

if !dryRun {
acl, err := acls.GetACL(configBase, cluster)
if err != nil {
return err
}
err = configBase.Join(registry.PathKopsVersionUpdated).WriteFile(bytes.NewReader([]byte(kopsbase.Version)), acl)
if err != nil {
return fmt.Errorf("error writing kops version: %v", err)
}

err = registry.WriteConfigDeprecated(cluster, configBase.Join(registry.PathClusterCompleted), c.Cluster)
if err != nil {
return fmt.Errorf("error writing completed cluster spec: %v", err)
Expand Down