From c43637b73c524a86982951d77c13f02cab25f8c3 Mon Sep 17 00:00:00 2001 From: fabianofranz Date: Mon, 10 Nov 2014 15:09:32 -0200 Subject: [PATCH] Extract several kubectl helpers from cmd/cmd.go --- pkg/kubectl/cmd/cmd.go | 140 +++------------------------------- pkg/kubectl/cmd/create.go | 2 +- pkg/kubectl/cmd/createall.go | 4 +- pkg/kubectl/cmd/delete.go | 2 +- pkg/kubectl/cmd/get.go | 10 +-- pkg/kubectl/cmd/helpers.go | 143 +++++++++++++++++++++++++++++++++++ pkg/kubectl/cmd/namespace.go | 3 +- pkg/kubectl/cmd/proxy.go | 4 +- pkg/kubectl/cmd/resource.go | 2 +- pkg/kubectl/cmd/update.go | 2 +- pkg/kubectl/cmd/version.go | 2 +- 11 files changed, 170 insertions(+), 144 deletions(-) create mode 100644 pkg/kubectl/cmd/helpers.go diff --git a/pkg/kubectl/cmd/cmd.go b/pkg/kubectl/cmd/cmd.go index bdb5f06b6a6..e071e7a1081 100644 --- a/pkg/kubectl/cmd/cmd.go +++ b/pkg/kubectl/cmd/cmd.go @@ -19,11 +19,7 @@ package cmd import ( "fmt" "io" - "io/ioutil" - "net/http" "os" - "strconv" - "strings" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" @@ -128,66 +124,13 @@ func runHelp(cmd *cobra.Command, args []string) { cmd.Help() } -func getFlagString(cmd *cobra.Command, flag string) string { - f := cmd.Flags().Lookup(flag) - if f == nil { - glog.Fatalf("Flag accessed but not defined for command %s: %s", cmd.Name(), flag) - } - return f.Value.String() -} - -func getFlagBool(cmd *cobra.Command, flag string) bool { - f := cmd.Flags().Lookup(flag) - if f == nil { - glog.Fatalf("Flag accessed but not defined for command %s: %s", cmd.Name(), flag) - } - // Caseless compare. - if strings.ToLower(f.Value.String()) == "true" { - return true - } - return false -} - -// Returns nil if the flag wasn't set. -func getFlagBoolPtr(cmd *cobra.Command, flag string) *bool { - f := cmd.Flags().Lookup(flag) - if f == nil { - glog.Fatalf("Flag accessed but not defined for command %s: %s", cmd.Name(), flag) - } - // Check if flag was not set at all. - if !f.Changed && f.DefValue == f.Value.String() { - return nil - } - var ret bool - // Caseless compare. - if strings.ToLower(f.Value.String()) == "true" { - ret = true - } else { - ret = false - } - return &ret -} - -// Assumes the flag has a default value. -func getFlagInt(cmd *cobra.Command, flag string) int { - f := cmd.Flags().Lookup(flag) - if f == nil { - glog.Fatalf("Flag accessed but not defined for command %s: %s", cmd.Name(), 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. - checkErr(err) - return v -} - func getKubeNamespace(cmd *cobra.Command) string { result := api.NamespaceDefault - if ns := getFlagString(cmd, "namespace"); len(ns) > 0 { + if ns := GetFlagString(cmd, "namespace"); len(ns) > 0 { result = ns glog.V(2).Infof("Using namespace from -ns flag") } else { - nsPath := getFlagString(cmd, "ns-path") + nsPath := GetFlagString(cmd, "ns-path") nsInfo, err := kubectl.LoadNamespaceInfo(nsPath) if err != nil { glog.Fatalf("Error loading current namespace: %v", err) @@ -202,7 +145,7 @@ func getKubeNamespace(cmd *cobra.Command) string { // user explicitly provided on the command line, or false if no // such namespace was specified. func getExplicitKubeNamespace(cmd *cobra.Command) (string, bool) { - if ns := getFlagString(cmd, "namespace"); len(ns) > 0 { + if ns := GetFlagString(cmd, "namespace"); len(ns) > 0 { return ns, true } // TODO: determine when --ns-path is set but equal to the default @@ -214,7 +157,7 @@ func getKubeConfig(cmd *cobra.Command) *client.Config { config := &client.Config{} var host string - if hostFlag := getFlagString(cmd, "server"); len(hostFlag) > 0 { + if hostFlag := GetFlagString(cmd, "server"); len(hostFlag) > 0 { host = hostFlag glog.V(2).Infof("Using server from -s flag: %s", host) } else if len(os.Getenv("KUBERNETES_MASTER")) > 0 { @@ -231,7 +174,7 @@ func getKubeConfig(cmd *cobra.Command) *client.Config { // Get the values from the file on disk (or from the user at the // command line). Override them with the command line parameters, if // provided. - authPath := getFlagString(cmd, "auth-path") + authPath := GetFlagString(cmd, "auth-path") authInfo, err := kubectl.LoadAuthInfo(authPath, os.Stdin) if err != nil { glog.Fatalf("Error loading auth: %v", err) @@ -240,13 +183,13 @@ func getKubeConfig(cmd *cobra.Command) *client.Config { config.Username = authInfo.User config.Password = authInfo.Password // First priority is flag, then file. - config.CAFile = firstNonEmptyString(getFlagString(cmd, "certificate-authority"), authInfo.CAFile) - config.CertFile = firstNonEmptyString(getFlagString(cmd, "client-certificate"), authInfo.CertFile) - config.KeyFile = firstNonEmptyString(getFlagString(cmd, "client-key"), authInfo.KeyFile) + config.CAFile = FirstNonEmptyString(GetFlagString(cmd, "certificate-authority"), authInfo.CAFile) + config.CertFile = FirstNonEmptyString(GetFlagString(cmd, "client-certificate"), authInfo.CertFile) + config.KeyFile = FirstNonEmptyString(GetFlagString(cmd, "client-key"), authInfo.KeyFile) config.BearerToken = authInfo.BearerToken // For config.Insecure, the command line ALWAYS overrides the authInfo // file, regardless of its setting. - if insecureFlag := getFlagBoolPtr(cmd, "insecure-skip-tls-verify"); insecureFlag != nil { + if insecureFlag := GetFlagBoolPtr(cmd, "insecure-skip-tls-verify"); insecureFlag != nil { config.Insecure = *insecureFlag } else if authInfo.Insecure != nil { config.Insecure = *authInfo.Insecure @@ -254,7 +197,7 @@ func getKubeConfig(cmd *cobra.Command) *client.Config { } // The API version (e.g. v1beta1), not the binary version. - config.Version = getFlagString(cmd, "api-version") + config.Version = GetFlagString(cmd, "api-version") return config } @@ -263,7 +206,7 @@ func getKubeClient(cmd *cobra.Command) *client.Client { config := getKubeConfig(cmd) // The binary version. - matchVersion := getFlagBool(cmd, "match-server-version") + matchVersion := GetFlagBool(cmd, "match-server-version") c, err := kubectl.GetKubeClient(config, matchVersion) if err != nil { @@ -271,64 +214,3 @@ func getKubeClient(cmd *cobra.Command) *client.Client { } return c } - -// 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 { - for _, s := range args { - if len(s) > 0 { - return s - } - } - return "" -} - -// readConfigData reads the bytes from the specified filesytem or network -// location or from stdin if location == "-". -func readConfigData(location string) ([]byte, error) { - if len(location) == 0 { - return nil, fmt.Errorf("Location given but empty") - } - - if location == "-" { - // Read from stdin. - data, err := ioutil.ReadAll(os.Stdin) - if err != nil { - return nil, err - } - - if len(data) == 0 { - return nil, fmt.Errorf(`Read from stdin specified ("-") but no data found`) - } - - return data, nil - } - - // Use the location as a file path or URL. - return readConfigDataFromLocation(location) -} - -func readConfigDataFromLocation(location string) ([]byte, error) { - // we look for http:// or https:// to determine if valid URL, otherwise do normal file IO - if strings.Index(location, "http://") == 0 || strings.Index(location, "https://") == 0 { - resp, err := http.Get(location) - if err != nil { - return nil, fmt.Errorf("Unable to access URL %s: %v\n", location, err) - } - defer resp.Body.Close() - if resp.StatusCode != 200 { - return nil, fmt.Errorf("Unable to read URL, server reported %d %s", resp.StatusCode, resp.Status) - } - data, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("Unable to read URL %s: %v\n", location, err) - } - return data, nil - } else { - data, err := ioutil.ReadFile(location) - if err != nil { - return nil, fmt.Errorf("Unable to read %s: %v\n", location, err) - } - return data, nil - } -} diff --git a/pkg/kubectl/cmd/create.go b/pkg/kubectl/cmd/create.go index 24330ae9a62..2d2bbca7853 100644 --- a/pkg/kubectl/cmd/create.go +++ b/pkg/kubectl/cmd/create.go @@ -39,7 +39,7 @@ Examples: $ cat pod.json | kubectl create -f - `, Run: func(cmd *cobra.Command, args []string) { - filename := getFlagString(cmd, "filename") + filename := GetFlagString(cmd, "filename") if len(filename) == 0 { usageError(cmd, "Must specify filename to create") } diff --git a/pkg/kubectl/cmd/createall.go b/pkg/kubectl/cmd/createall.go index 55435484d1a..0f0b237036b 100644 --- a/pkg/kubectl/cmd/createall.go +++ b/pkg/kubectl/cmd/createall.go @@ -93,12 +93,12 @@ Examples: return getKubeClient(cmd).RESTClient, nil } - filename := getFlagString(cmd, "filename") + filename := GetFlagString(cmd, "filename") if len(filename) == 0 { usageError(cmd, "Must pass a filename to update") } - data, err := readConfigData(filename) + data, err := ReadConfigData(filename) checkErr(err) items, errs := DataToObjects(mapper, typer, data) diff --git a/pkg/kubectl/cmd/delete.go b/pkg/kubectl/cmd/delete.go index 1a8cf009b21..4bb2f2b701e 100644 --- a/pkg/kubectl/cmd/delete.go +++ b/pkg/kubectl/cmd/delete.go @@ -49,7 +49,7 @@ Examples: $ kubectl delete pod 1234-56-7890-234234-456456 `, Run: func(cmd *cobra.Command, args []string) { - filename := getFlagString(cmd, "filename") + filename := GetFlagString(cmd, "filename") mapping, namespace, name := ResourceFromArgsOrFile(cmd, args, filename, f.Typer, f.Mapper) client, err := f.Client(cmd, mapping) checkErr(err) diff --git a/pkg/kubectl/cmd/get.go b/pkg/kubectl/cmd/get.go index 88b72dd6d74..ea1f4dc0930 100644 --- a/pkg/kubectl/cmd/get.go +++ b/pkg/kubectl/cmd/get.go @@ -49,16 +49,16 @@ Examples: Run: func(cmd *cobra.Command, args []string) { mapping, namespace, name := ResourceOrTypeFromArgs(cmd, args, f.Mapper) - selector := getFlagString(cmd, "selector") + selector := GetFlagString(cmd, "selector") labels, err := labels.ParseSelector(selector) checkErr(err) client, err := f.Client(cmd, mapping) checkErr(err) - outputFormat := getFlagString(cmd, "output") - templateFile := getFlagString(cmd, "template") - defaultPrinter, err := f.Printer(cmd, mapping, getFlagBool(cmd, "no-headers")) + outputFormat := GetFlagString(cmd, "output") + templateFile := GetFlagString(cmd, "template") + defaultPrinter, err := f.Printer(cmd, mapping, GetFlagBool(cmd, "no-headers")) checkErr(err) printer, versioned, err := kubectl.GetPrinter(outputFormat, templateFile, defaultPrinter) @@ -68,7 +68,7 @@ Examples: checkErr(err) if versioned { - outputVersion := getFlagString(cmd, "output-version") + outputVersion := GetFlagString(cmd, "output-version") if len(outputVersion) == 0 { outputVersion = mapping.APIVersion } diff --git a/pkg/kubectl/cmd/helpers.go b/pkg/kubectl/cmd/helpers.go new file mode 100644 index 00000000000..ff3ce871047 --- /dev/null +++ b/pkg/kubectl/cmd/helpers.go @@ -0,0 +1,143 @@ +/* +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/ioutil" + "net/http" + "os" + "strconv" + "strings" + + "github.com/golang/glog" + "github.com/spf13/cobra" +) + +func GetFlagString(cmd *cobra.Command, flag string) string { + f := cmd.Flags().Lookup(flag) + if f == nil { + glog.Fatalf("Flag accessed but not defined for command %s: %s", cmd.Name(), flag) + } + return f.Value.String() +} + +func GetFlagBool(cmd *cobra.Command, flag string) bool { + f := cmd.Flags().Lookup(flag) + if f == nil { + glog.Fatalf("Flag accessed but not defined for command %s: %s", cmd.Name(), flag) + } + // Caseless compare. + if strings.ToLower(f.Value.String()) == "true" { + return true + } + return false +} + +// Returns nil if the flag wasn't set. +func GetFlagBoolPtr(cmd *cobra.Command, flag string) *bool { + f := cmd.Flags().Lookup(flag) + if f == nil { + glog.Fatalf("Flag accessed but not defined for command %s: %s", cmd.Name(), flag) + } + // Check if flag was not set at all. + if !f.Changed && f.DefValue == f.Value.String() { + return nil + } + var ret bool + // Caseless compare. + if strings.ToLower(f.Value.String()) == "true" { + ret = true + } else { + ret = false + } + return &ret +} + +// Assumes the flag has a default value. +func GetFlagInt(cmd *cobra.Command, flag string) int { + f := cmd.Flags().Lookup(flag) + if f == nil { + glog.Fatalf("Flag accessed but not defined for command %s: %s", cmd.Name(), 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. + 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 { + for _, s := range args { + if len(s) > 0 { + return s + } + } + return "" +} + +// ReadConfigData reads the bytes from the specified filesytem or network +// location or from stdin if location == "-". +func ReadConfigData(location string) ([]byte, error) { + if len(location) == 0 { + return nil, fmt.Errorf("Location given but empty") + } + + if location == "-" { + // Read from stdin. + data, err := ioutil.ReadAll(os.Stdin) + if err != nil { + return nil, err + } + + if len(data) == 0 { + return nil, fmt.Errorf(`Read from stdin specified ("-") but no data found`) + } + + return data, nil + } + + // Use the location as a file path or URL. + return ReadConfigDataFromLocation(location) +} + +func ReadConfigDataFromLocation(location string) ([]byte, error) { + // we look for http:// or https:// to determine if valid URL, otherwise do normal file IO + if strings.Index(location, "http://") == 0 || strings.Index(location, "https://") == 0 { + resp, err := http.Get(location) + if err != nil { + return nil, fmt.Errorf("Unable to access URL %s: %v\n", location, err) + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + return nil, fmt.Errorf("Unable to read URL, server reported %d %s", resp.StatusCode, resp.Status) + } + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("Unable to read URL %s: %v\n", location, err) + } + return data, nil + } else { + data, err := ioutil.ReadFile(location) + if err != nil { + return nil, fmt.Errorf("Unable to read %s: %v\n", location, err) + } + return data, nil + } +} diff --git a/pkg/kubectl/cmd/namespace.go b/pkg/kubectl/cmd/namespace.go index e008bd9077a..0ab73527ec7 100644 --- a/pkg/kubectl/cmd/namespace.go +++ b/pkg/kubectl/cmd/namespace.go @@ -20,6 +20,7 @@ import ( "io" "fmt" + "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl" "github.com/spf13/cobra" ) @@ -39,7 +40,7 @@ Examples: $ kubectl namespace other Set current namespace to other`, Run: func(cmd *cobra.Command, args []string) { - nsPath := getFlagString(cmd, "ns-path") + nsPath := GetFlagString(cmd, "ns-path") var err error var ns *kubectl.NamespaceInfo switch len(args) { diff --git a/pkg/kubectl/cmd/proxy.go b/pkg/kubectl/cmd/proxy.go index 0abb016084e..5a8892a6703 100644 --- a/pkg/kubectl/cmd/proxy.go +++ b/pkg/kubectl/cmd/proxy.go @@ -30,9 +30,9 @@ func NewCmdProxy(out io.Writer) *cobra.Command { Short: "Run a proxy to the Kubernetes API server", Long: `Run a proxy to the Kubernetes API server.`, Run: func(cmd *cobra.Command, args []string) { - port := getFlagInt(cmd, "port") + port := GetFlagInt(cmd, "port") glog.Infof("Starting to serve on localhost:%d", port) - server, err := kubectl.NewProxyServer(getFlagString(cmd, "www"), getKubeConfig(cmd), port) + server, err := kubectl.NewProxyServer(GetFlagString(cmd, "www"), getKubeConfig(cmd), port) checkErr(err) glog.Fatal(server.Serve()) }, diff --git a/pkg/kubectl/cmd/resource.go b/pkg/kubectl/cmd/resource.go index a9965a492e9..27559beb487 100644 --- a/pkg/kubectl/cmd/resource.go +++ b/pkg/kubectl/cmd/resource.go @@ -120,7 +120,7 @@ func ResourceOrTypeFromArgs(cmd *cobra.Command, args []string, mapper meta.RESTM // resolve to a known type an error is returned. The returned mapping can be used to determine // the correct REST endpoint to modify this resource with. func ResourceFromFile(filename string, typer runtime.ObjectTyper, mapper meta.RESTMapper) (mapping *meta.RESTMapping, namespace, name string, data []byte) { - configData, err := readConfigData(filename) + configData, err := ReadConfigData(filename) checkErr(err) data = configData diff --git a/pkg/kubectl/cmd/update.go b/pkg/kubectl/cmd/update.go index c9d262ca780..c59b75c8131 100644 --- a/pkg/kubectl/cmd/update.go +++ b/pkg/kubectl/cmd/update.go @@ -39,7 +39,7 @@ Examples: $ cat pod.json | kubectl update -f - `, Run: func(cmd *cobra.Command, args []string) { - filename := getFlagString(cmd, "filename") + filename := GetFlagString(cmd, "filename") if len(filename) == 0 { usageError(cmd, "Must specify filename to update") } diff --git a/pkg/kubectl/cmd/version.go b/pkg/kubectl/cmd/version.go index f0885808d79..0dc43da5abd 100644 --- a/pkg/kubectl/cmd/version.go +++ b/pkg/kubectl/cmd/version.go @@ -28,7 +28,7 @@ func NewCmdVersion(out io.Writer) *cobra.Command { Use: "version", Short: "Print version of client and server", Run: func(cmd *cobra.Command, args []string) { - if getFlagBool(cmd, "client") { + if GetFlagBool(cmd, "client") { kubectl.GetClientVersion(out) } else { kubectl.GetVersion(out, getKubeClient(cmd))