Move Ingress godeps to vendor/

This commit is contained in:
Manuel de Brito Fontes 2016-05-10 10:30:56 -03:00
parent 0d4f49e50e
commit ca620e4074
2059 changed files with 3706 additions and 213845 deletions

View file

@ -0,0 +1,127 @@
/*
Copyright 2014 The Kubernetes Authors 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 util
import (
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/client/restclient"
client "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
)
func NewClientCache(loader clientcmd.ClientConfig) *ClientCache {
return &ClientCache{
clients: make(map[unversioned.GroupVersion]*client.Client),
configs: make(map[unversioned.GroupVersion]*restclient.Config),
loader: loader,
}
}
// ClientCache caches previously loaded clients for reuse, and ensures MatchServerVersion
// is invoked only once
type ClientCache struct {
loader clientcmd.ClientConfig
clients map[unversioned.GroupVersion]*client.Client
configs map[unversioned.GroupVersion]*restclient.Config
defaultConfig *restclient.Config
defaultClient *client.Client
matchVersion bool
}
// ClientConfigForVersion returns the correct config for a server
func (c *ClientCache) ClientConfigForVersion(version *unversioned.GroupVersion) (*restclient.Config, error) {
if c.defaultConfig == nil {
config, err := c.loader.ClientConfig()
if err != nil {
return nil, err
}
c.defaultConfig = config
if c.matchVersion {
if err := client.MatchesServerVersion(c.defaultClient, config); err != nil {
return nil, err
}
}
}
if version != nil {
if config, ok := c.configs[*version]; ok {
return config, nil
}
}
// TODO: have a better config copy method
config := *c.defaultConfig
// TODO these fall out when we finish the refactor
var preferredGV *unversioned.GroupVersion
if version != nil {
versionCopy := *version
preferredGV = &versionCopy
}
negotiatedVersion, err := client.NegotiateVersion(c.defaultClient, &config, preferredGV, registered.EnabledVersions())
if err != nil {
return nil, err
}
config.GroupVersion = negotiatedVersion
client.SetKubernetesDefaults(&config)
if version != nil {
c.configs[*version] = &config
}
// `version` does not necessarily equal `config.Version`. However, we know that we call this method again with
// `config.Version`, we should get the the config we've just built.
configCopy := config
c.configs[*config.GroupVersion] = &configCopy
return &config, nil
}
// ClientForVersion initializes or reuses a client for the specified version, or returns an
// error if that is not possible
func (c *ClientCache) ClientForVersion(version *unversioned.GroupVersion) (*client.Client, error) {
if version != nil {
if client, ok := c.clients[*version]; ok {
return client, nil
}
}
config, err := c.ClientConfigForVersion(version)
if err != nil {
return nil, err
}
kubeclient, err := client.New(config)
if err != nil {
return nil, err
}
c.clients[*config.GroupVersion] = kubeclient
// `version` does not necessarily equal `config.Version`. However, we know that if we call this method again with
// `version`, we should get a client based on the same config we just found. There's no guarantee that a client
// is copiable, so create a new client and save it in the cache.
if version != nil {
configCopy := *config
kubeclient, err := client.New(&configCopy)
if err != nil {
return nil, err
}
c.clients[*version] = kubeclient
}
return kubeclient, nil
}

1039
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/util/factory.go generated vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,530 @@
/*
Copyright 2014 The Kubernetes Authors 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 util
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/url"
"os"
"strings"
"time"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/client/typed/discovery"
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/runtime"
utilerrors "k8s.io/kubernetes/pkg/util/errors"
"k8s.io/kubernetes/pkg/util/strategicpatch"
"github.com/evanphx/json-patch"
"github.com/golang/glog"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
const (
ApplyAnnotationsFlag = "save-config"
)
type debugError interface {
DebugError() (msg string, args []interface{})
}
// AddSourceToErr adds handleResourcePrefix and source string to error message.
// verb is the string like "creating", "deleting" etc.
// souce is the filename or URL to the template file(*.json or *.yaml), or stdin to use to handle the resource.
func AddSourceToErr(verb string, source string, err error) error {
if source != "" {
if statusError, ok := err.(errors.APIStatus); ok {
status := statusError.Status()
status.Message = fmt.Sprintf("error when %s %q: %v", verb, source, status.Message)
return &errors.StatusError{ErrStatus: status}
}
return fmt.Errorf("error when %s %q: %v", verb, source, err)
}
return err
}
var fatalErrHandler = fatal
// BehaviorOnFatal allows you to override the default behavior when a fatal
// error occurs, which is call os.Exit(1). You can pass 'panic' as a function
// here if you prefer the panic() over os.Exit(1).
func BehaviorOnFatal(f func(string)) {
fatalErrHandler = f
}
// DefaultBehaviorOnFatal allows you to undo any previous override. Useful in
// tests.
func DefaultBehaviorOnFatal() {
fatalErrHandler = fatal
}
// fatal prints the message and then exits. If V(2) or greater, glog.Fatal
// is invoked for extended information.
func fatal(msg string) {
// add newline if needed
if !strings.HasSuffix(msg, "\n") {
msg += "\n"
}
if glog.V(2) {
glog.FatalDepth(2, msg)
}
fmt.Fprint(os.Stderr, msg)
os.Exit(1)
}
// CheckErr prints a user friendly error to STDERR and exits with a non-zero
// exit code. Unrecognized errors will be printed with an "error: " prefix.
//
// This method is generic to the command in use and may be used by non-Kubectl
// commands.
func CheckErr(err error) {
checkErr(err, fatalErrHandler)
}
func checkErr(err error, handleErr func(string)) {
if err == nil {
return
}
if errors.IsInvalid(err) {
details := err.(*errors.StatusError).Status().Details
prefix := fmt.Sprintf("The %s %q is invalid.\n", details.Kind, details.Name)
errs := statusCausesToAggrError(details.Causes)
handleErr(MultilineError(prefix, errs))
}
if meta.IsNoResourceMatchError(err) {
noMatch := err.(*meta.NoResourceMatchError)
switch {
case len(noMatch.PartialResource.Group) > 0 && len(noMatch.PartialResource.Version) > 0:
handleErr(fmt.Sprintf("the server doesn't have a resource type %q in group %q and version %q", noMatch.PartialResource.Resource, noMatch.PartialResource.Group, noMatch.PartialResource.Version))
case len(noMatch.PartialResource.Group) > 0:
handleErr(fmt.Sprintf("the server doesn't have a resource type %q in group %q", noMatch.PartialResource.Resource, noMatch.PartialResource.Group))
case len(noMatch.PartialResource.Version) > 0:
handleErr(fmt.Sprintf("the server doesn't have a resource type %q in version %q", noMatch.PartialResource.Resource, noMatch.PartialResource.Version))
default:
handleErr(fmt.Sprintf("the server doesn't have a resource type %q", noMatch.PartialResource.Resource))
}
return
}
// handle multiline errors
if clientcmd.IsConfigurationInvalid(err) {
handleErr(MultilineError("Error in configuration: ", err))
}
if agg, ok := err.(utilerrors.Aggregate); ok && len(agg.Errors()) > 0 {
handleErr(MultipleErrors("", agg.Errors()))
}
msg, ok := StandardErrorMessage(err)
if !ok {
msg = err.Error()
if !strings.HasPrefix(msg, "error: ") {
msg = fmt.Sprintf("error: %s", msg)
}
}
handleErr(msg)
}
func statusCausesToAggrError(scs []unversioned.StatusCause) utilerrors.Aggregate {
errs := make([]error, len(scs))
for i, sc := range scs {
errs[i] = fmt.Errorf("%s: %s", sc.Field, sc.Message)
}
return utilerrors.NewAggregate(errs)
}
// StandardErrorMessage translates common errors into a human readable message, or returns
// false if the error is not one of the recognized types. It may also log extended
// information to glog.
//
// This method is generic to the command in use and may be used by non-Kubectl
// commands.
func StandardErrorMessage(err error) (string, bool) {
if debugErr, ok := err.(debugError); ok {
glog.V(4).Infof(debugErr.DebugError())
}
status, isStatus := err.(errors.APIStatus)
switch {
case isStatus:
switch s := status.Status(); {
case s.Reason == "Unauthorized":
return fmt.Sprintf("error: You must be logged in to the server (%s)", s.Message), true
default:
return fmt.Sprintf("Error from server: %s", err.Error()), true
}
case errors.IsUnexpectedObjectError(err):
return fmt.Sprintf("Server returned an unexpected response: %s", err.Error()), true
}
switch t := err.(type) {
case *url.Error:
glog.V(4).Infof("Connection error: %s %s: %v", t.Op, t.URL, t.Err)
switch {
case strings.Contains(t.Err.Error(), "connection refused"):
host := t.URL
if server, err := url.Parse(t.URL); err == nil {
host = server.Host
}
return fmt.Sprintf("The connection to the server %s was refused - did you specify the right host or port?", host), true
}
return fmt.Sprintf("Unable to connect to the server: %v", t.Err), true
}
return "", false
}
// MultilineError returns a string representing an error that splits sub errors into their own
// lines. The returned string will end with a newline.
func MultilineError(prefix string, err error) string {
if agg, ok := err.(utilerrors.Aggregate); ok {
errs := utilerrors.Flatten(agg).Errors()
buf := &bytes.Buffer{}
switch len(errs) {
case 0:
return fmt.Sprintf("%s%v\n", prefix, err)
case 1:
return fmt.Sprintf("%s%v\n", prefix, messageForError(errs[0]))
default:
fmt.Fprintln(buf, prefix)
for _, err := range errs {
fmt.Fprintf(buf, "* %v\n", messageForError(err))
}
return buf.String()
}
}
return fmt.Sprintf("%s%s\n", prefix, err)
}
// MultipleErrors returns a newline delimited string containing
// the prefix and referenced errors in standard form.
func MultipleErrors(prefix string, errs []error) string {
buf := &bytes.Buffer{}
for _, err := range errs {
fmt.Fprintf(buf, "%s%v\n", prefix, messageForError(err))
}
return buf.String()
}
// messageForError returns the string representing the error.
func messageForError(err error) string {
msg, ok := StandardErrorMessage(err)
if !ok {
msg = err.Error()
}
return msg
}
func UsageError(cmd *cobra.Command, format string, args ...interface{}) error {
msg := fmt.Sprintf(format, args...)
return fmt.Errorf("%s\nSee '%s -h' for help and examples.", msg, cmd.CommandPath())
}
// Whether this cmd need watching objects.
func isWatch(cmd *cobra.Command) bool {
if w, err := cmd.Flags().GetBool("watch"); w && err == nil {
return true
}
if wo, err := cmd.Flags().GetBool("watch-only"); wo && err == nil {
return true
}
return false
}
func getFlag(cmd *cobra.Command, flag string) *pflag.Flag {
f := cmd.Flags().Lookup(flag)
if f == nil {
glog.Fatalf("flag accessed but not defined for command %s: %s", cmd.Name(), flag)
}
return f
}
func GetFlagString(cmd *cobra.Command, flag string) string {
s, err := cmd.Flags().GetString(flag)
if err != nil {
glog.Fatalf("err accessing flag %s for command %s: %v", flag, cmd.Name(), err)
}
return s
}
// GetFlagStringList can be used to accept multiple argument with flag repetition (e.g. -f arg1 -f arg2 ...)
func GetFlagStringSlice(cmd *cobra.Command, flag string) []string {
s, err := cmd.Flags().GetStringSlice(flag)
if err != nil {
glog.Fatalf("err accessing flag %s for command %s: %v", flag, cmd.Name(), err)
}
return s
}
// GetWideFlag is used to determine if "-o wide" is used
func GetWideFlag(cmd *cobra.Command) bool {
f := cmd.Flags().Lookup("output")
if f.Value.String() == "wide" {
return true
}
return false
}
func GetFlagBool(cmd *cobra.Command, flag string) bool {
b, err := cmd.Flags().GetBool(flag)
if err != nil {
glog.Fatalf("err accessing flag %s for command %s: %v", flag, cmd.Name(), err)
}
return b
}
// Assumes the flag has a default value.
func GetFlagInt(cmd *cobra.Command, flag string) int {
i, err := cmd.Flags().GetInt(flag)
if err != nil {
glog.Fatalf("err accessing flag %s for command %s: %v", flag, cmd.Name(), err)
}
return i
}
// Assumes the flag has a default value.
func GetFlagInt64(cmd *cobra.Command, flag string) int64 {
i, err := cmd.Flags().GetInt64(flag)
if err != nil {
glog.Fatalf("err accessing flag %s for command %s: %v", flag, cmd.Name(), err)
}
return i
}
func GetFlagDuration(cmd *cobra.Command, flag string) time.Duration {
d, err := cmd.Flags().GetDuration(flag)
if err != nil {
glog.Fatalf("err accessing flag %s for command %s: %v", flag, cmd.Name(), err)
}
return d
}
func AddValidateFlags(cmd *cobra.Command) {
cmd.Flags().Bool("validate", true, "If true, use a schema to validate the input before sending it")
cmd.Flags().String("schema-cache-dir", fmt.Sprintf("~/%s/%s", clientcmd.RecommendedHomeDir, clientcmd.RecommendedSchemaName), fmt.Sprintf("If non-empty, load/store cached API schemas in this directory, default is '$HOME/%s/%s'", clientcmd.RecommendedHomeDir, clientcmd.RecommendedSchemaName))
cmd.MarkFlagFilename("schema-cache-dir")
}
func AddRecursiveFlag(cmd *cobra.Command, value *bool) {
cmd.Flags().BoolVarP(value, "recursive", "R", *value, "If true, process directory recursively.")
}
func AddApplyAnnotationFlags(cmd *cobra.Command) {
cmd.Flags().Bool(ApplyAnnotationsFlag, false, "If true, the configuration of current object will be saved in its annotation. This is useful when you want to perform kubectl apply on this object in the future.")
}
// AddGeneratorFlags adds flags common to resource generation commands
// TODO: need to take a pass at other generator commands to use this set of flags
func AddGeneratorFlags(cmd *cobra.Command, defaultGenerator string) {
cmd.Flags().String("generator", defaultGenerator, "The name of the API generator to use.")
cmd.Flags().Bool("dry-run", false, "If true, only print the object that would be sent, without sending it.")
}
func ReadConfigDataFromReader(reader io.Reader, source string) ([]byte, error) {
data, err := ioutil.ReadAll(reader)
if err != nil {
return nil, err
}
if len(data) == 0 {
return nil, fmt.Errorf(`Read from %s but no data found`, source)
}
return data, nil
}
// Merge requires JSON serialization
// TODO: merge assumes JSON serialization, and does not properly abstract API retrieval
func Merge(codec runtime.Codec, dst runtime.Object, fragment, kind string) (runtime.Object, error) {
// encode dst into versioned json and apply fragment directly too it
target, err := runtime.Encode(codec, dst)
if err != nil {
return nil, err
}
patched, err := jsonpatch.MergePatch(target, []byte(fragment))
if err != nil {
return nil, err
}
out, err := runtime.Decode(codec, patched)
if err != nil {
return nil, err
}
return out, nil
}
// DumpReaderToFile writes all data from the given io.Reader to the specified file
// (usually for temporary use).
func DumpReaderToFile(reader io.Reader, filename string) error {
f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
defer f.Close()
if err != nil {
return err
}
buffer := make([]byte, 1024)
for {
count, err := reader.Read(buffer)
if err == io.EOF {
break
}
if err != nil {
return err
}
_, err = f.Write(buffer[:count])
if err != nil {
return err
}
}
return nil
}
// UpdateObject updates resource object with updateFn
func UpdateObject(info *resource.Info, codec runtime.Codec, updateFn func(runtime.Object) error) (runtime.Object, error) {
helper := resource.NewHelper(info.Client, info.Mapping)
if err := updateFn(info.Object); err != nil {
return nil, err
}
// Update the annotation used by kubectl apply
if err := kubectl.UpdateApplyAnnotation(info, codec); err != nil {
return nil, err
}
if _, err := helper.Replace(info.Namespace, info.Name, true, info.Object); err != nil {
return nil, err
}
return info.Object, nil
}
// AddCmdRecordFlag adds --record flag to command
func AddRecordFlag(cmd *cobra.Command) {
cmd.Flags().Bool("record", false, "Record current kubectl command in the resource annotation.")
}
func GetRecordFlag(cmd *cobra.Command) bool {
return GetFlagBool(cmd, "record")
}
// RecordChangeCause annotate change-cause to input runtime object.
func RecordChangeCause(obj runtime.Object, changeCause string) error {
accessor, err := meta.Accessor(obj)
if err != nil {
return err
}
annotations := accessor.GetAnnotations()
if annotations == nil {
annotations = make(map[string]string)
}
annotations[kubectl.ChangeCauseAnnotation] = changeCause
accessor.SetAnnotations(annotations)
return nil
}
// ChangeResourcePatch creates a strategic merge patch between the origin input resource info
// and the annotated with change-cause input resource info.
func ChangeResourcePatch(info *resource.Info, changeCause string) ([]byte, error) {
oldData, err := json.Marshal(info.Object)
if err != nil {
return nil, err
}
if err := RecordChangeCause(info.Object, changeCause); err != nil {
return nil, err
}
newData, err := json.Marshal(info.Object)
if err != nil {
return nil, err
}
return strategicpatch.CreateTwoWayMergePatch(oldData, newData, info.Object)
}
// containsChangeCause checks if input resource info contains change-cause annotation.
func ContainsChangeCause(info *resource.Info) bool {
annotations, err := info.Mapping.MetadataAccessor.Annotations(info.Object)
if err != nil {
return false
}
return len(annotations[kubectl.ChangeCauseAnnotation]) > 0
}
// ShouldRecord checks if we should record current change cause
func ShouldRecord(cmd *cobra.Command, info *resource.Info) bool {
return GetRecordFlag(cmd) || ContainsChangeCause(info)
}
func GetThirdPartyGroupVersions(discovery discovery.DiscoveryInterface) ([]unversioned.GroupVersion, []unversioned.GroupVersionKind, error) {
result := []unversioned.GroupVersion{}
gvks := []unversioned.GroupVersionKind{}
groupList, err := discovery.ServerGroups()
if err != nil {
// On forbidden or not found, just return empty lists.
if errors.IsForbidden(err) || errors.IsNotFound(err) {
return result, gvks, nil
}
return nil, nil, err
}
for ix := range groupList.Groups {
group := &groupList.Groups[ix]
for jx := range group.Versions {
gv, err2 := unversioned.ParseGroupVersion(group.Versions[jx].GroupVersion)
if err2 != nil {
return nil, nil, err
}
// Skip GroupVersionKinds that have been statically registered.
if registered.IsRegisteredVersion(gv) {
continue
}
result = append(result, gv)
resourceList, err := discovery.ServerResourcesForGroupVersion(group.Versions[jx].GroupVersion)
if err != nil {
return nil, nil, err
}
for kx := range resourceList.APIResources {
gvks = append(gvks, gv.WithKind(resourceList.APIResources[kx].Kind))
}
}
}
return result, gvks, nil
}
func GetIncludeThirdPartyAPIs(cmd *cobra.Command) bool {
if cmd.Flags().Lookup("include-extended-apis") == nil {
return false
}
return GetFlagBool(cmd, "include-extended-apis")
}
func AddInclude3rdPartyFlags(cmd *cobra.Command) {
cmd.Flags().Bool("include-extended-apis", true, "If true, include definitions of new APIs via calls to the API server. [default true]")
}

View file

@ -0,0 +1,136 @@
/*
Copyright 2014 The Kubernetes Authors 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 util
import (
"fmt"
"io"
"strings"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/kubectl"
"github.com/spf13/cobra"
)
// AddPrinterFlags adds printing related flags to a command (e.g. output format, no headers, template path)
func AddPrinterFlags(cmd *cobra.Command) {
cmd.Flags().StringP("output", "o", "", "Output format. One of: json|yaml|wide|name|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=... See golang template [http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template [http://releases.k8s.io/HEAD/docs/user-guide/jsonpath.md].")
cmd.Flags().String("output-version", "", "Output the formatted object with the given group version (for ex: 'extensions/v1beta1').")
cmd.Flags().Bool("no-headers", false, "When using the default output, don't print headers.")
cmd.Flags().Bool("show-labels", false, "When printing, show all labels as the last column (default hide labels column)")
cmd.Flags().String("template", "", "Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].")
cmd.MarkFlagFilename("template")
cmd.Flags().String("sort-by", "", "If non-empty, sort list types using this field specification. The field specification is expressed as a JSONPath expression (e.g. '{.metadata.name}'). The field in the API resource specified by this JSONPath expression must be an integer or a string.")
cmd.Flags().BoolP("show-all", "a", false, "When printing, show all resources (default hide terminated pods.)")
}
// AddOutputFlagsForMutation adds output related flags to a command. Used by mutations only.
func AddOutputFlagsForMutation(cmd *cobra.Command) {
cmd.Flags().StringP("output", "o", "", "Output mode. Use \"-o name\" for shorter output (resource/name).")
}
// PrintSuccess prints message after finishing mutating operations
func PrintSuccess(mapper meta.RESTMapper, shortOutput bool, out io.Writer, resource string, name string, operation string) {
resource, _ = mapper.ResourceSingularizer(resource)
if shortOutput {
// -o name: prints resource/name
if len(resource) > 0 {
fmt.Fprintf(out, "%s/%s\n", resource, name)
} else {
fmt.Fprintf(out, "%s\n", name)
}
} else {
// understandable output by default
if len(resource) > 0 {
fmt.Fprintf(out, "%s \"%s\" %s\n", resource, name, operation)
} else {
fmt.Fprintf(out, "\"%s\" %s\n", name, operation)
}
}
}
// ValidateOutputArgs validates -o flag args for mutations
func ValidateOutputArgs(cmd *cobra.Command) error {
outputMode := GetFlagString(cmd, "output")
if outputMode != "" && outputMode != "name" {
return UsageError(cmd, "Unexpected -o output mode: %v. We only support '-o name'.", outputMode)
}
return nil
}
// OutputVersion returns the preferred output version for generic content (JSON, YAML, or templates)
// defaultVersion is never mutated. Nil simply allows clean passing in common usage from client.Config
func OutputVersion(cmd *cobra.Command, defaultVersion *unversioned.GroupVersion) (unversioned.GroupVersion, error) {
outputVersionString := GetFlagString(cmd, "output-version")
if len(outputVersionString) == 0 {
if defaultVersion == nil {
return unversioned.GroupVersion{}, nil
}
return *defaultVersion, nil
}
return unversioned.ParseGroupVersion(outputVersionString)
}
// PrinterForCommand returns the default printer for this command.
// Requires that printer flags have been added to cmd (see AddPrinterFlags).
func PrinterForCommand(cmd *cobra.Command) (kubectl.ResourcePrinter, bool, error) {
outputFormat := GetFlagString(cmd, "output")
// templates are logically optional for specifying a format.
// TODO once https://github.com/kubernetes/kubernetes/issues/12668 is fixed, this should fall back to GetFlagString
templateFile, _ := cmd.Flags().GetString("template")
if len(outputFormat) == 0 && len(templateFile) != 0 {
outputFormat = "template"
}
templateFormat := []string{
"go-template=", "go-template-file=", "jsonpath=", "jsonpath-file=", "custom-columns=", "custom-columns-file=",
}
for _, format := range templateFormat {
if strings.HasPrefix(outputFormat, format) {
templateFile = outputFormat[len(format):]
outputFormat = format[:len(format)-1]
}
}
printer, generic, err := kubectl.GetPrinter(outputFormat, templateFile)
if err != nil {
return nil, generic, err
}
return maybeWrapSortingPrinter(cmd, printer), generic, nil
}
func maybeWrapSortingPrinter(cmd *cobra.Command, printer kubectl.ResourcePrinter) kubectl.ResourcePrinter {
sorting, err := cmd.Flags().GetString("sort-by")
if err != nil {
// error can happen on missing flag or bad flag type. In either case, this command didn't intent to sort
return printer
}
if len(sorting) != 0 {
return &kubectl.SortingPrinter{
Delegate: printer,
SortField: fmt.Sprintf("{%s}", sorting),
}
}
return printer
}