mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-16 22:53:22 +00:00
Add a rollingupdate lib and command to kubectl
Also decouple conditions from client for testability.
This commit is contained in:
@@ -118,6 +118,7 @@ Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`,
|
||||
|
||||
cmds.AddCommand(NewCmdNamespace(out))
|
||||
cmds.AddCommand(f.NewCmdLog(out))
|
||||
cmds.AddCommand(f.NewCmdRollingUpdate(out))
|
||||
|
||||
if err := cmds.Execute(); err != nil {
|
||||
os.Exit(1)
|
||||
|
@@ -24,6 +24,7 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -82,6 +83,16 @@ func GetFlagInt(cmd *cobra.Command, flag string) int {
|
||||
return v
|
||||
}
|
||||
|
||||
func GetFlagDuration(cmd *cobra.Command, flag string) time.Duration {
|
||||
f := cmd.Flags().Lookup(flag)
|
||||
if f == nil {
|
||||
glog.Fatalf("Flag accessed but not defined for command %s: %s", cmd.Name(), flag)
|
||||
}
|
||||
v, err := time.ParseDuration(f.Value.String())
|
||||
checkErr(err)
|
||||
return v
|
||||
}
|
||||
|
||||
// Returns the first non-empty string out of the ones provided. If all
|
||||
// strings are empty, returns an empty string.
|
||||
func FirstNonEmptyString(args ...string) string {
|
||||
|
109
pkg/kubectl/cmd/rollingupdate.go
Normal file
109
pkg/kubectl/cmd/rollingupdate.go
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
Copyright 2014 Google Inc. All rights reserved.
|
||||
|
||||
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 cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
updatePeriod = "1m0s"
|
||||
timeout = "5m0s"
|
||||
pollInterval = "3s"
|
||||
)
|
||||
|
||||
func (f *Factory) NewCmdRollingUpdate(out io.Writer) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "rollingupdate <old-controller-name> -f <new-controller.json>",
|
||||
Short: "Perform a rolling update of the given replicationController",
|
||||
Long: `Perform a rolling update of the given replicationController.",
|
||||
|
||||
Replaces named controller with new controller, updating one pod at a time to use the
|
||||
new PodTemplate. The new-controller.json must specify the same namespace as the
|
||||
existing controller and overwrite at least one (common) label in its replicaSelector.
|
||||
|
||||
Examples:
|
||||
$ kubectl rollingupdate frontend-v1 -f frontend-v2.json
|
||||
<update pods of frontend-v1 using new controller data in frontend-v2.json>
|
||||
|
||||
$ cat frontend-v2.json | kubectl rollingupdate frontend-v1 -f -
|
||||
<update pods of frontend-v1 using json data passed into stdin>`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
filename := GetFlagString(cmd, "filename")
|
||||
if len(filename) == 0 {
|
||||
usageError(cmd, "Must specify filename for new controller")
|
||||
}
|
||||
period := GetFlagDuration(cmd, "update-period")
|
||||
interval := GetFlagDuration(cmd, "poll-interval")
|
||||
timeout := GetFlagDuration(cmd, "timeout")
|
||||
if len(args) != 1 {
|
||||
usageError(cmd, "Must specify the controller to update")
|
||||
}
|
||||
oldName := args[0]
|
||||
schema, err := f.Validator(cmd)
|
||||
checkErr(err)
|
||||
mapping, namespace, newName, data := ResourceFromFile(cmd, filename, f.Typer, f.Mapper, schema)
|
||||
if mapping.Kind != "ReplicationController" {
|
||||
usageError(cmd, "%s does not specify a valid ReplicationController", filename)
|
||||
}
|
||||
err = CompareNamespaceFromFile(cmd, namespace)
|
||||
checkErr(err)
|
||||
|
||||
client, err := f.ClientBuilder.Client()
|
||||
checkErr(err)
|
||||
obj, err := mapping.Codec.Decode(data)
|
||||
checkErr(err)
|
||||
newRc := obj.(*api.ReplicationController)
|
||||
|
||||
updater := kubectl.NewRollingUpdater(namespace, client)
|
||||
|
||||
// fetch rc
|
||||
oldRc, err := client.ReplicationControllers(namespace).Get(oldName)
|
||||
checkErr(err)
|
||||
|
||||
var hasLabel bool
|
||||
for key, oldValue := range oldRc.Spec.Selector {
|
||||
if newValue, ok := newRc.Spec.Selector[key]; ok && newValue != oldValue {
|
||||
hasLabel = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasLabel {
|
||||
usageError(cmd, "%s must specify a matching key with non-equal value in Selector for %s",
|
||||
filename, oldName)
|
||||
}
|
||||
// TODO: handle resizes during rolling update
|
||||
if newRc.Spec.Replicas == 0 {
|
||||
newRc.Spec.Replicas = oldRc.Spec.Replicas
|
||||
}
|
||||
err = updater.Update(out, oldRc, newRc, period, interval, timeout)
|
||||
checkErr(err)
|
||||
|
||||
fmt.Fprintf(out, "%s\n", newName)
|
||||
},
|
||||
}
|
||||
cmd.Flags().String("update-period", updatePeriod, `Time to wait between updating pods. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".`)
|
||||
cmd.Flags().String("poll-interval", pollInterval, `Time delay between polling controller status after update. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".`)
|
||||
cmd.Flags().String("timeout", timeout, `Max time to wait for a controller to update before giving up. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".`)
|
||||
cmd.Flags().StringP("filename", "f", "", "Filename or URL to file to use to create the new controller")
|
||||
return cmd
|
||||
}
|
Reference in New Issue
Block a user