Skip to content
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
86 changes: 86 additions & 0 deletions cmd/kops/reconcile_cluster.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
Copyright 2024 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 main

import (
"context"
"fmt"
"io"

"k8s.io/kops/cmd/kops/util"
"k8s.io/kops/pkg/apis/kops"
)

// ReconcileCluster updates the cluster to the desired state, including rolling updates where necessary.
// To respect skew policy, it updates the control plane first, then updates the nodes.
// "update" is probably now smart enough to automatically not update the control plane if it is already at the desired version,
// but we do it explicitly here to be clearer / safer.
func ReconcileCluster(ctx context.Context, f *util.Factory, out io.Writer, c *UpdateClusterOptions) error {
fmt.Fprintf(out, "Updating control plane configuration\n")
{
opt := *c
opt.Reconcile = false // Prevent infinite loop
opt.InstanceGroupRoles = []string{
string(kops.InstanceGroupRoleAPIServer),
string(kops.InstanceGroupRoleControlPlane),
}
if _, err := RunUpdateCluster(ctx, f, out, &opt); err != nil {
return err
}
}

fmt.Fprintf(out, "Doing rolling-update for control plane\n")
{
opt := &RollingUpdateOptions{}
opt.InitDefaults()
opt.ClusterName = c.ClusterName
opt.InstanceGroupRoles = []string{
string(kops.InstanceGroupRoleAPIServer),
string(kops.InstanceGroupRoleControlPlane),
}
opt.Yes = c.Yes
if err := RunRollingUpdateCluster(ctx, f, out, opt); err != nil {
return err
}
}

fmt.Fprintf(out, "Updating node configuration\n")
{
opt := *c
opt.Reconcile = false // Prevent infinite loop
// Do all roles this time, though we only expect changes to node & bastion roles
opt.InstanceGroupRoles = nil
if _, err := RunUpdateCluster(ctx, f, out, &opt); err != nil {
return err
}
}

fmt.Fprintf(out, "Doing rolling-update for nodes\n")
{
opt := &RollingUpdateOptions{}
opt.InitDefaults()
opt.ClusterName = c.ClusterName
// Do all roles this time, though we only expect changes to node & bastion roles
opt.InstanceGroupRoles = nil
opt.Yes = c.Yes
if err := RunRollingUpdateCluster(ctx, f, out, opt); err != nil {
return err
}
}

return nil
}
16 changes: 16 additions & 0 deletions cmd/kops/update_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ type UpdateClusterOptions struct {
// The goal is that the cluster can keep running even during more disruptive
// infrastructure changes.
Prune bool

// Reconcile is true if we should reconcile the cluster by rolling the control plane and nodes sequentially
Reconcile bool
}

func (o *UpdateClusterOptions) InitDefaults() {
Expand All @@ -117,6 +120,7 @@ func (o *UpdateClusterOptions) InitDefaults() {
o.CreateKubecfg = true

o.Prune = false
o.Reconcile = false

o.RunTasksOptions.InitDefaults()
}
Expand Down Expand Up @@ -174,6 +178,8 @@ func NewCmdUpdateCluster(f *util.Factory, out io.Writer) *cobra.Command {
cmd.Flags().BoolVar(&options.Prune, "prune", options.Prune, "Delete old revisions of cloud resources that were needed during an upgrade")
cmd.Flags().BoolVar(&options.IgnoreKubeletVersionSkew, "ignore-kubelet-version-skew", options.IgnoreKubeletVersionSkew, "Setting this to true will force updating the kubernetes version on all instance groups, regardles of which control plane version is running")

cmd.Flags().BoolVar(&options.Reconcile, "reconcile", options.Reconcile, "Reconcile the cluster by rolling the control plane and nodes sequentially")

return cmd
}

Expand All @@ -193,6 +199,16 @@ type UpdateClusterResults struct {
}

func RunUpdateCluster(ctx context.Context, f *util.Factory, out io.Writer, c *UpdateClusterOptions) (*UpdateClusterResults, error) {
if c.Reconcile {
if !c.Yes {
return nil, fmt.Errorf("--reconcile is only supported with --yes")
}
if c.Target == cloudup.TargetTerraform {
return nil, fmt.Errorf("--reconcile is not supported with terraform")
}
return nil, ReconcileCluster(ctx, f, out, c)
}

results := &UpdateClusterResults{}

isDryrun := false
Expand Down
1 change: 1 addition & 0 deletions docs/cli/kops_update_cluster.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading