Use the pflag StringSlice instead of implementing it ourselves

Saves code and makes our code easier to read because we just use normal
[]string instead of custom type.
This commit is contained in:
Eric Paris
2015-08-05 10:21:47 -04:00
parent 76896bf244
commit 7cbb52ce04
17 changed files with 82 additions and 180 deletions

View File

@@ -20,34 +20,11 @@ package kubectl
import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"k8s.io/kubernetes/pkg/util"
)
func AddJsonFilenameFlag(cmd *cobra.Command, value *util.StringList, usage string) {
func AddJsonFilenameFlag(cmd *cobra.Command, usage string) {
cmd.Flags().StringSliceP("filename", "f", []string{}, usage)
annotations := []string{"json", "yaml", "yml"}
annotation := make(map[string][]string)
annotation[cobra.BashCompFilenameExt] = annotations
flag := &pflag.Flag{
Name: "filename",
Shorthand: "f",
Usage: usage,
Value: value,
DefValue: value.String(),
Annotations: annotation,
}
cmd.Flags().AddFlag(flag)
}
// AddLabelsToColumnsFlag added a user flag to print resource labels into columns. Currently used in kubectl get command
func AddLabelsToColumnsFlag(cmd *cobra.Command, value *util.StringList, usage string) {
flag := &pflag.Flag{
Name: "label-columns",
Shorthand: "L",
Usage: usage,
Value: value,
DefValue: value.String(),
}
cmd.Flags().AddFlag(flag)
cmd.Flags().SetAnnotation("filename", cobra.BashCompFilenameExt, annotations)
}

View File

@@ -28,7 +28,6 @@ import (
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util"
)
const (
@@ -43,7 +42,6 @@ $ cat pod.json | kubectl create -f -`
)
func NewCmdCreate(f *cmdutil.Factory, out io.Writer) *cobra.Command {
var filenames util.StringList
cmd := &cobra.Command{
Use: "create -f FILENAME",
Short: "Create a resource by filename or stdin",
@@ -52,13 +50,12 @@ func NewCmdCreate(f *cmdutil.Factory, out io.Writer) *cobra.Command {
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(ValidateArgs(cmd, args))
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
cmdutil.CheckErr(RunCreate(f, out, filenames, shortOutput))
cmdutil.CheckErr(RunCreate(f, cmd, out))
},
}
usage := "Filename, directory, or URL to file to use to create the resource"
kubectl.AddJsonFilenameFlag(cmd, &filenames, usage)
kubectl.AddJsonFilenameFlag(cmd, usage)
cmd.MarkFlagRequired("filename")
cmdutil.AddOutputFlagsForMutation(cmd)
@@ -72,7 +69,8 @@ func ValidateArgs(cmd *cobra.Command, args []string) error {
return nil
}
func RunCreate(f *cmdutil.Factory, out io.Writer, filenames util.StringList, shortOutput bool) error {
func RunCreate(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer) error {
schema, err := f.Validator()
if err != nil {
return err
@@ -83,6 +81,7 @@ func RunCreate(f *cmdutil.Factory, out io.Writer, filenames util.StringList, sho
return err
}
filenames := cmdutil.GetFlagStringSlice(cmd, "filename")
mapper, typer := f.Object()
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
Schema(schema).
@@ -108,6 +107,7 @@ func RunCreate(f *cmdutil.Factory, out io.Writer, filenames util.StringList, sho
}
count++
info.Refresh(obj, true)
shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
if !shortOutput {
printObjectSpecificMessage(info.Object, out)
}

View File

@@ -29,7 +29,6 @@ import (
"k8s.io/kubernetes/pkg/kubectl"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/util"
)
const (
@@ -59,7 +58,6 @@ $ kubectl delete pods --all`
)
func NewCmdDelete(f *cmdutil.Factory, out io.Writer) *cobra.Command {
var filenames util.StringList
cmd := &cobra.Command{
Use: "delete ([-f FILENAME] | TYPE [(NAME | -l label | --all)])",
Short: "Delete resources by filenames, stdin, resources and names, or by resources and label selector.",
@@ -67,13 +65,12 @@ func NewCmdDelete(f *cmdutil.Factory, out io.Writer) *cobra.Command {
Example: delete_example,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
err := RunDelete(f, out, cmd, args, filenames, shortOutput)
err := RunDelete(f, out, cmd, args)
cmdutil.CheckErr(err)
},
}
usage := "Filename, directory, or URL to a file containing the resource to delete."
kubectl.AddJsonFilenameFlag(cmd, &filenames, usage)
kubectl.AddJsonFilenameFlag(cmd, usage)
cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on.")
cmd.Flags().Bool("all", false, "[-all] to select all the specified resources.")
cmd.Flags().Bool("ignore-not-found", false, "Treat \"resource not found\" as a successful delete. Defaults to \"true\" when --all is specified.")
@@ -84,7 +81,7 @@ func NewCmdDelete(f *cmdutil.Factory, out io.Writer) *cobra.Command {
return cmd
}
func RunDelete(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, filenames util.StringList, shortOutput bool) error {
func RunDelete(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error {
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
if err != nil {
return err
@@ -94,7 +91,7 @@ func RunDelete(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, filenames...).
FilenameParam(enforceNamespace, cmdutil.GetFlagStringSlice(cmd, "filename")...).
SelectorParam(cmdutil.GetFlagString(cmd, "selector")).
SelectAllParam(deleteAll).
ResourceTypeOrNameArgs(false, args...).RequireObject(false).
@@ -118,6 +115,7 @@ func RunDelete(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str
}
}
shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
// By default use a reaper to delete all related resources.
if cmdutil.GetFlagBool(cmd, "cascade") {
return ReapResult(r, f, out, cmdutil.GetFlagBool(cmd, "cascade"), ignoreNotFound, cmdutil.GetFlagDuration(cmd, "timeout"), cmdutil.GetFlagInt(cmd, "grace-period"), shortOutput, mapper)

View File

@@ -26,7 +26,6 @@ import (
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/client"
"k8s.io/kubernetes/pkg/util"
)
func TestDeleteObjectByTuple(t *testing.T) {
@@ -147,8 +146,7 @@ func TestDeleteObjectNotFound(t *testing.T) {
cmd.Flags().Set("filename", "../../../examples/guestbook/redis-master-controller.yaml")
cmd.Flags().Set("cascade", "false")
cmd.Flags().Set("output", "name")
filenames := cmd.Flags().Lookup("filename").Value.(*util.StringList)
err := RunDelete(f, buf, cmd, []string{}, *filenames, true)
err := RunDelete(f, buf, cmd, []string{})
if err == nil || !errors.IsNotFound(err) {
t.Errorf("unexpected error: expected NotFound, got %v", err)
}
@@ -218,8 +216,9 @@ func TestDeleteAllNotFound(t *testing.T) {
cmd.Flags().Set("cascade", "false")
// Make sure we can explicitly choose to fail on NotFound errors, even with --all
cmd.Flags().Set("ignore-not-found", "false")
cmd.Flags().Set("output", "name")
err := RunDelete(f, buf, cmd, []string{"services"}, nil, true)
err := RunDelete(f, buf, cmd, []string{"services"})
if err == nil || !errors.IsNotFound(err) {
t.Errorf("unexpected error: expected NotFound, got %v", err)
}
@@ -326,9 +325,7 @@ func TestDeleteMultipleObjectContinueOnMissing(t *testing.T) {
cmd.Flags().Set("filename", "../../../examples/guestbook/frontend-service.yaml")
cmd.Flags().Set("cascade", "false")
cmd.Flags().Set("output", "name")
filenames := cmd.Flags().Lookup("filename").Value.(*util.StringList)
t.Logf("filenames: %v\n", filenames)
err := RunDelete(f, buf, cmd, []string{}, *filenames, true)
err := RunDelete(f, buf, cmd, []string{})
if err == nil || !errors.IsNotFound(err) {
t.Errorf("unexpected error: expected NotFound, got %v", err)
}

View File

@@ -23,7 +23,6 @@ import (
"k8s.io/kubernetes/pkg/kubectl"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/util"
"k8s.io/kubernetes/pkg/watch"
"github.com/spf13/cobra"
@@ -83,7 +82,7 @@ func NewCmdGet(f *cmdutil.Factory, out io.Writer) *cobra.Command {
cmd.Flags().BoolP("watch", "w", false, "After listing/getting the requested object, watch for changes.")
cmd.Flags().Bool("watch-only", false, "Watch for changes to the requested object(s), without listing/getting first.")
cmd.Flags().Bool("all-namespaces", false, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.")
kubectl.AddLabelsToColumnsFlag(cmd, &util.StringList{}, "Accepts a comma separated list of labels that are going to be presented as columns. Names are case-sensitive. You can also use multiple flag statements like -L label1 -L label2...")
cmd.Flags().StringSliceP("label-columns", "L", []string{}, "Accepts a comma separated list of labels that are going to be presented as columns. Names are case-sensitive. You can also use multiple flag statements like -L label1 -L label2...")
return cmd
}

View File

@@ -29,7 +29,6 @@ import (
"k8s.io/kubernetes/pkg/kubectl"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/util"
)
const (
@@ -49,7 +48,6 @@ kubectl replace --force -f ./pod.json`
)
func NewCmdReplace(f *cmdutil.Factory, out io.Writer) *cobra.Command {
var filenames util.StringList
cmd := &cobra.Command{
Use: "replace -f FILENAME",
// update is deprecated.
@@ -59,13 +57,12 @@ func NewCmdReplace(f *cmdutil.Factory, out io.Writer) *cobra.Command {
Example: replace_example,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
err := RunReplace(f, out, cmd, args, filenames, shortOutput)
err := RunReplace(f, out, cmd, args)
cmdutil.CheckErr(err)
},
}
usage := "Filename, directory, or URL to file to use to replace the resource."
kubectl.AddJsonFilenameFlag(cmd, &filenames, usage)
kubectl.AddJsonFilenameFlag(cmd, usage)
cmd.MarkFlagRequired("filename")
cmd.Flags().Bool("force", false, "Delete and re-create the specified resource")
cmd.Flags().Bool("cascade", false, "Only relevant during a force replace. If true, cascade the deletion of the resources managed by this resource (e.g. Pods created by a ReplicationController). Default true.")
@@ -75,7 +72,7 @@ func NewCmdReplace(f *cmdutil.Factory, out io.Writer) *cobra.Command {
return cmd
}
func RunReplace(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, filenames util.StringList, shortOutput bool) error {
func RunReplace(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error {
if len(os.Args) > 1 && os.Args[1] == "update" {
printDeprecationWarning("replace", "update")
}
@@ -90,10 +87,12 @@ func RunReplace(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []st
}
force := cmdutil.GetFlagBool(cmd, "force")
filenames := cmdutil.GetFlagStringSlice(cmd, "filename")
if len(filenames) == 0 {
return cmdutil.UsageError(cmd, "Must specify --filename to replace")
}
shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
if force {
return forceReplace(f, out, cmd, args, filenames, shortOutput)
}
@@ -127,7 +126,7 @@ func RunReplace(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []st
})
}
func forceReplace(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, filenames util.StringList, shortOutput bool) error {
func forceReplace(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, filenames []string, shortOutput bool) error {
schema, err := f.Validator()
if err != nil {
return err

View File

@@ -21,6 +21,7 @@ import (
"fmt"
"io"
"os"
"time"
"github.com/golang/glog"
@@ -34,9 +35,6 @@ import (
)
const (
updatePeriod = "1m0s"
timeout = "5m0s"
pollInterval = "3s"
rollingUpdate_long = `Perform a rolling update of the given ReplicationController.
Replaces the specified replication controller with a new replication controller by updating one pod at a time to use the
@@ -57,6 +55,12 @@ $ kubectl rolling-update frontend --image=image:v2
`
)
var (
updatePeriod, _ = time.ParseDuration("1m0s")
timeout, _ = time.ParseDuration("5m0s")
pollInterval, _ = time.ParseDuration("3s")
)
func NewCmdRollingUpdate(f *cmdutil.Factory, out io.Writer) *cobra.Command {
cmd := &cobra.Command{
Use: "rolling-update OLD_CONTROLLER_NAME ([NEW_CONTROLLER_NAME] --image=NEW_CONTAINER_IMAGE | -f NEW_CONTROLLER_SPEC)",
@@ -70,9 +74,9 @@ func NewCmdRollingUpdate(f *cmdutil.Factory, out io.Writer) *cobra.Command {
cmdutil.CheckErr(err)
},
}
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 for replication controller status after the update. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".`)
cmd.Flags().String("timeout", timeout, `Max time to wait for a replication controller to update before giving up. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".`)
cmd.Flags().Duration("update-period", updatePeriod, `Time to wait between updating pods. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".`)
cmd.Flags().Duration("poll-interval", pollInterval, `Time delay between polling for replication controller status after the update. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".`)
cmd.Flags().Duration("timeout", timeout, `Max time to wait for a replication 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 replication controller.")
cmd.Flags().String("image", "", "Image to use for upgrading the replication controller. Can not be used with --filename/-f")
cmd.Flags().String("deployment-label-key", "deployment", "The key to use to differentiate between two different controllers, default 'deployment'. Only relevant when --image is specified, ignored otherwise")

View File

@@ -23,7 +23,6 @@ import (
"k8s.io/kubernetes/pkg/kubectl"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/util"
)
const (
@@ -48,9 +47,6 @@ $ kubectl stop -f path/to/resources`
)
func NewCmdStop(f *cmdutil.Factory, out io.Writer) *cobra.Command {
flags := &struct {
Filenames util.StringList
}{}
cmd := &cobra.Command{
Use: "stop (-f FILENAME | TYPE (NAME | -l label | --all))",
Short: "Deprecated: Gracefully shut down a resource by name or filename.",
@@ -58,12 +54,11 @@ func NewCmdStop(f *cmdutil.Factory, out io.Writer) *cobra.Command {
Example: stop_example,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
cmdutil.CheckErr(RunStop(f, cmd, args, flags.Filenames, out, shortOutput))
cmdutil.CheckErr(RunStop(f, cmd, args, out))
},
}
usage := "Filename, directory, or URL to file of resource(s) to be stopped."
kubectl.AddJsonFilenameFlag(cmd, &flags.Filenames, usage)
kubectl.AddJsonFilenameFlag(cmd, usage)
cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on.")
cmd.Flags().Bool("all", false, "[-all] to select all the specified resources.")
cmd.Flags().Bool("ignore-not-found", false, "Treat \"resource not found\" as a successful stop.")
@@ -73,11 +68,13 @@ func NewCmdStop(f *cmdutil.Factory, out io.Writer) *cobra.Command {
return cmd
}
func RunStop(f *cmdutil.Factory, cmd *cobra.Command, args []string, filenames util.StringList, out io.Writer, shortOutput bool) error {
func RunStop(f *cmdutil.Factory, cmd *cobra.Command, args []string, out io.Writer) error {
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
if err != nil {
return err
}
filenames := cmdutil.GetFlagStringSlice(cmd, "filename")
mapper, typer := f.Object()
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
ContinueOnError().
@@ -91,5 +88,6 @@ func RunStop(f *cmdutil.Factory, cmd *cobra.Command, args []string, filenames ut
if r.Err() != nil {
return r.Err()
}
shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
return ReapResult(r, f, out, false, cmdutil.GetFlagBool(cmd, "ignore-not-found"), cmdutil.GetFlagDuration(cmd, "timeout"), cmdutil.GetFlagInt(cmd, "grace-period"), shortOutput, mapper)
}

View File

@@ -396,7 +396,12 @@ func (f *Factory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMappin
}
printer = kubectl.NewVersionedPrinter(printer, mapping.ObjectConvertor, version, mapping.APIVersion)
} else {
printer, err = f.Printer(mapping, GetFlagBool(cmd, "no-headers"), withNamespace, GetWideFlag(cmd), GetFlagStringList(cmd, "label-columns"))
// Some callers do not have "label-columns" so we can't use the GetFlagStringSlice() helper
columnLabel, err := cmd.Flags().GetStringSlice("label-columns")
if err != nil {
columnLabel = []string{}
}
printer, err = f.Printer(mapping, GetFlagBool(cmd, "no-headers"), withNamespace, GetWideFlag(cmd), columnLabel)
if err != nil {
return nil, err
}

View File

@@ -25,7 +25,6 @@ import (
"net/http"
"net/url"
"os"
"strconv"
"strings"
"time"
@@ -37,7 +36,6 @@ import (
"k8s.io/kubernetes/pkg/client/clientcmd"
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util"
utilerrors "k8s.io/kubernetes/pkg/util/errors"
"github.com/golang/glog"
@@ -211,17 +209,20 @@ func getFlag(cmd *cobra.Command, flag string) *pflag.Flag {
}
func GetFlagString(cmd *cobra.Command, flag string) string {
f := getFlag(cmd, flag)
return f.Value.String()
s, err := cmd.Flags().GetString(flag)
if err != nil {
glog.Fatalf("err %v accessing flag %s for command %s: %s", err, flag, cmd.Name())
}
return s
}
// GetFlagStringList can be used to accept multiple argument with flag repetition (e.g. -f arg1 -f arg2 ...)
func GetFlagStringList(cmd *cobra.Command, flag string) util.StringList {
f := cmd.Flags().Lookup(flag)
if f == nil {
return util.StringList{}
func GetFlagStringSlice(cmd *cobra.Command, flag string) []string {
s, err := cmd.Flags().GetStringSlice(flag)
if err != nil {
glog.Fatalf("err %v accessing flag %s for command %s: %s", err, flag, cmd.Name())
}
return *f.Value.(*util.StringList)
return s
}
// GetWideFlag is used to determine if "-o wide" is used
@@ -234,33 +235,28 @@ func GetWideFlag(cmd *cobra.Command) bool {
}
func GetFlagBool(cmd *cobra.Command, flag string) bool {
f := getFlag(cmd, flag)
result, err := strconv.ParseBool(f.Value.String())
b, err := cmd.Flags().GetBool(flag)
if err != nil {
glog.Fatalf("Invalid value for a boolean flag: %s", f.Value.String())
glog.Fatalf("err %v accessing flag %s for command %s: %s", err, flag, cmd.Name())
}
return result
return b
}
// Assumes the flag has a default value.
func GetFlagInt(cmd *cobra.Command, flag string) int {
f := getFlag(cmd, flag)
v, err := strconv.Atoi(f.Value.String())
// This is likely not a sufficiently friendly error message, but cobra
// should prevent non-integer values from reaching here.
i, err := cmd.Flags().GetInt(flag)
if err != nil {
glog.Fatalf("unable to convert flag value to int: %v", err)
glog.Fatalf("err: %v accessing flag %s for command %s: %s", err, flag, cmd.Name())
}
return v
return i
}
func GetFlagDuration(cmd *cobra.Command, flag string) time.Duration {
f := getFlag(cmd, flag)
v, err := time.ParseDuration(f.Value.String())
d, err := cmd.Flags().GetDuration(flag)
if err != nil {
glog.Fatalf("unable to convert flag value to Duration: %v", err)
glog.Fatalf("err: %v accessing flag %s for command %s: %s", err, flag, cmd.Name())
}
return v
return d
}
func ReadConfigDataFromReader(reader io.Reader, source string) ([]byte, error) {