2014-10-06 01:24:19 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2014 The Kubernetes Authors .
2014-10-06 01:24:19 +00:00
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 (
2017-08-31 18:16:54 +00:00
"encoding/json"
2014-11-01 22:44:03 +00:00
"fmt"
2014-10-06 01:24:19 +00:00
"io"
2017-05-19 21:24:39 +00:00
"strings"
2014-10-06 01:24:19 +00:00
2017-02-28 02:36:42 +00:00
"github.com/golang/glog"
2015-08-10 11:02:14 +00:00
"github.com/spf13/cobra"
2016-09-07 20:29:57 +00:00
2017-02-14 19:48:07 +00:00
kapierrors "k8s.io/apimachinery/pkg/api/errors"
2017-01-11 14:09:48 +00:00
"k8s.io/apimachinery/pkg/api/meta"
2017-08-31 18:16:54 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2017-01-11 14:09:48 +00:00
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/watch"
2017-08-31 18:16:54 +00:00
"k8s.io/kubernetes/pkg/api"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/kubectl"
2016-10-07 22:24:42 +00:00
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
2015-08-05 22:03:47 +00:00
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
2017-05-19 21:24:39 +00:00
"k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/kubectl/resource"
2017-07-07 04:04:11 +00:00
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
2017-02-19 22:56:11 +00:00
"k8s.io/kubernetes/pkg/printers"
2016-08-08 17:56:19 +00:00
"k8s.io/kubernetes/pkg/util/interrupt"
2014-10-06 01:24:19 +00:00
)
2015-08-14 18:46:43 +00:00
// GetOptions is the start of the data required to perform the operation. As new fields are added, add them here instead of
// referencing the cmd.Flags()
type GetOptions struct {
2016-08-17 18:28:07 +00:00
resource . FilenameOptions
2016-08-11 12:52:12 +00:00
2017-02-14 19:48:07 +00:00
IgnoreNotFound bool
Raw string
2015-08-14 18:46:43 +00:00
}
2016-05-20 17:49:56 +00:00
var (
2017-06-14 21:14:42 +00:00
getLong = templates . LongDesc ( `
2016-05-20 17:49:56 +00:00
Display one or many resources .
2014-10-06 01:24:19 +00:00
2017-02-16 03:47:00 +00:00
` + validResources + `
2014-10-06 01:24:19 +00:00
2017-03-01 23:33:08 +00:00
This command will hide resources that have completed , such as pods that are
in the Succeeded or Failed phases . You can see the full results for any
2017-08-11 06:21:44 +00:00
resource by providing the ' -- show - all ' flag , but this flag does not include
the uninitialized objects by default , unless ' -- include - uninitialized ' is explicitly set .
2016-07-13 16:00:33 +00:00
2016-05-20 17:49:56 +00:00
By specifying the output as ' template ' and providing a Go template as the value
2017-03-01 23:33:08 +00:00
of the -- template flag , you can filter the attributes of the fetched resources . ` )
2016-10-07 22:24:42 +00:00
2017-06-14 21:14:42 +00:00
getExample = templates . Examples ( i18n . T ( `
2016-05-20 17:49:56 +00:00
# List all pods in ps output format .
kubectl get pods
2014-10-06 01:24:19 +00:00
2016-05-20 17:49:56 +00:00
# List all pods in ps output format with more information ( such as node name ) .
kubectl get pods - o wide
2015-06-29 18:36:06 +00:00
2016-05-20 17:49:56 +00:00
# List a single replication controller with specified NAME in ps output format .
kubectl get replicationcontroller web
2014-10-06 01:24:19 +00:00
2016-05-20 17:49:56 +00:00
# List a single pod in JSON output format .
kubectl get - o json pod web - pod - 13 je7
2014-12-31 00:42:55 +00:00
2016-05-20 17:49:56 +00:00
# List a pod identified by type and name specified in "pod.yaml" in JSON output format .
kubectl get - f pod . yaml - o json
2015-08-10 11:02:14 +00:00
2016-05-20 17:49:56 +00:00
# Return only the phase value of the specified pod .
kubectl get - o template pod / web - pod - 13 je7 -- template = { { . status . phase } }
2015-02-03 17:59:21 +00:00
2016-05-20 17:49:56 +00:00
# List all replication controllers and services together in ps output format .
kubectl get rc , services
2015-03-25 05:01:07 +00:00
2016-05-20 17:49:56 +00:00
# List one or more resources by their type and names .
2016-11-29 06:45:10 +00:00
kubectl get rc / web service / frontend pods / web - pod - 13 je7
# List all resources with different types .
2017-03-15 03:49:10 +00:00
kubectl get all ` ) )
2015-02-20 21:28:43 +00:00
)
2015-02-03 17:59:21 +00:00
2017-05-19 21:24:39 +00:00
const (
useOpenAPIPrintColumnFlagLabel = "experimental-use-openapi-print-columns"
)
2015-02-20 21:28:43 +00:00
// NewCmdGet creates a command object for the generic "get" action, which
// retrieves one or more resources from a server.
2016-10-13 00:18:39 +00:00
func NewCmdGet ( f cmdutil . Factory , out io . Writer , errOut io . Writer ) * cobra . Command {
2015-08-14 18:46:43 +00:00
options := & GetOptions { }
2015-03-17 17:01:57 +00:00
2015-09-02 22:38:40 +00:00
// retrieve a list of handled resources from printer as valid args
2016-03-20 18:14:25 +00:00
validArgs , argAliases := [ ] string { } , [ ] string { }
2017-02-19 22:56:11 +00:00
p , err := f . Printer ( nil , printers . PrintOptions {
2016-06-23 14:49:31 +00:00
ColumnLabels : [ ] string { } ,
} )
2015-09-02 22:38:40 +00:00
cmdutil . CheckErr ( err )
if p != nil {
validArgs = p . HandledResources ( )
2016-03-20 18:14:25 +00:00
argAliases = kubectl . ResourceAliases ( validArgs )
2015-09-02 22:38:40 +00:00
}
2015-02-20 21:28:43 +00:00
cmd := & cobra . Command {
2016-07-06 12:03:09 +00:00
Use : "get [(-o|--output=)json|yaml|wide|custom-columns=...|custom-columns-file=...|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=...] (TYPE [NAME | -l label] | TYPE/NAME ...) [flags]" ,
2017-01-25 01:00:32 +00:00
Short : i18n . T ( "Display one or many resources" ) ,
2017-06-14 21:14:42 +00:00
Long : getLong ,
Example : getExample ,
2014-10-06 01:24:19 +00:00
Run : func ( cmd * cobra . Command , args [ ] string ) {
2016-07-13 16:00:33 +00:00
err := RunGet ( f , out , errOut , cmd , args , options )
2015-04-07 18:21:25 +00:00
cmdutil . CheckErr ( err )
2014-12-31 00:42:55 +00:00
} ,
2016-05-05 00:18:52 +00:00
SuggestFor : [ ] string { "list" , "ps" } ,
2016-03-20 18:14:25 +00:00
ValidArgs : validArgs ,
ArgAliases : argAliases ,
2014-12-31 00:42:55 +00:00
}
2015-04-07 18:21:25 +00:00
cmdutil . AddPrinterFlags ( cmd )
2017-08-17 12:27:11 +00:00
cmd . Flags ( ) . StringP ( "selector" , "l" , "" , "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)" )
2017-08-11 06:21:44 +00:00
cmdutil . AddIncludeUninitializedFlag ( cmd )
cmd . Flags ( ) . BoolP ( "watch" , "w" , false , "After listing/getting the requested object, watch for changes. Uninitialized objects are excluded if no object name is provided." )
2015-01-18 07:32:34 +00:00
cmd . Flags ( ) . Bool ( "watch-only" , false , "Watch for changes to the requested object(s), without listing/getting first." )
2016-06-29 22:02:08 +00:00
cmd . Flags ( ) . Bool ( "show-kind" , false , "If present, list the resource type for the requested object(s)." )
2015-05-12 11:14:31 +00:00
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." )
2017-02-14 19:48:07 +00:00
cmd . Flags ( ) . BoolVar ( & options . IgnoreNotFound , "ignore-not-found" , false , "Treat \"resource not found\" as a successful retrieval." )
2016-07-18 09:58:40 +00:00
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 options like -L label1 -L label2..." )
2015-12-02 20:20:10 +00:00
cmd . Flags ( ) . Bool ( "export" , false , "If true, use 'export' for the resources. Exported resources are stripped of cluster-specific information." )
2017-05-19 21:24:39 +00:00
addOpenAPIPrintColumnFlags ( cmd )
2016-08-17 18:28:07 +00:00
usage := "identifying the resource to get from a server."
cmdutil . AddFilenameOptionFlags ( cmd , & options . FilenameOptions , usage )
2016-03-10 01:27:19 +00:00
cmdutil . AddInclude3rdPartyFlags ( cmd )
2016-08-11 12:52:12 +00:00
cmd . Flags ( ) . StringVar ( & options . Raw , "raw" , options . Raw , "Raw URI to request from the server. Uses the transport specified by the kubeconfig file." )
2014-12-31 00:42:55 +00:00
return cmd
}
2014-10-27 19:56:34 +00:00
2014-12-31 00:42:55 +00:00
// RunGet implements the generic Get command
// TODO: convert all direct flag accessors to a struct and pass that instead of cmd
2016-10-13 00:18:39 +00:00
func RunGet ( f cmdutil . Factory , out , errOut io . Writer , cmd * cobra . Command , args [ ] string , options * GetOptions ) error {
2016-08-11 12:52:12 +00:00
if len ( options . Raw ) > 0 {
2016-09-07 20:29:57 +00:00
restClient , err := f . RESTClient ( )
2016-08-11 12:52:12 +00:00
if err != nil {
return err
}
2016-09-07 20:29:57 +00:00
stream , err := restClient . Get ( ) . RequestURI ( options . Raw ) . Stream ( )
2016-08-11 12:52:12 +00:00
if err != nil {
return err
}
defer stream . Close ( )
2016-10-06 15:42:19 +00:00
_ , err = io . Copy ( out , stream )
if err != nil && err != io . EOF {
return err
2016-08-11 12:52:12 +00:00
}
2016-10-06 15:42:19 +00:00
return nil
2016-08-11 12:52:12 +00:00
}
2017-08-02 20:23:07 +00:00
mapper , typer , err := f . UnstructuredObject ( )
2016-11-02 16:29:01 +00:00
if err != nil {
return err
}
2017-05-16 21:52:51 +00:00
2017-08-02 20:23:07 +00:00
selector := cmdutil . GetFlagString ( cmd , "selector" )
allNamespaces := cmdutil . GetFlagBool ( cmd , "all-namespaces" )
showKind := cmdutil . GetFlagBool ( cmd , "show-kind" )
builder := f . NewBuilder ( ) . Unstructured ( f . UnstructuredClientForMapping , mapper , typer )
2015-08-10 11:02:14 +00:00
cmdNamespace , enforceNamespace , err := f . DefaultNamespace ( )
2015-03-09 22:08:16 +00:00
if err != nil {
return err
}
2015-01-02 18:08:37 +00:00
2016-02-08 07:47:20 +00:00
if allNamespaces {
enforceNamespace = false
}
2017-06-14 21:14:42 +00:00
if len ( args ) == 0 && cmdutil . IsFilenameSliceEmpty ( options . Filenames ) {
2017-02-16 03:47:00 +00:00
fmt . Fprint ( errOut , "You must specify the type of resource to get. " , validResources )
2016-09-21 20:14:23 +00:00
fullCmdName := cmd . Parent ( ) . CommandPath ( )
usageString := "Required resource not specified."
2016-09-28 16:41:42 +00:00
if len ( fullCmdName ) > 0 && cmdutil . IsSiblingCommandExists ( cmd , "explain" ) {
2016-09-21 20:14:23 +00:00
usageString = fmt . Sprintf ( "%s\nUse \"%s explain <resource>\" for a detailed description of that resource (e.g. %[2]s explain pods)." , usageString , fullCmdName )
}
2017-06-14 21:14:42 +00:00
return cmdutil . UsageErrorf ( cmd , usageString )
2015-06-09 22:04:56 +00:00
}
2015-12-02 20:20:10 +00:00
export := cmdutil . GetFlagBool ( cmd , "export" )
2015-12-03 19:32:22 +00:00
2017-02-28 02:36:42 +00:00
filterFuncs := f . DefaultResourceFilterFunc ( )
filterOpts := f . DefaultResourceFilterOptions ( cmd , allNamespaces )
2014-12-31 00:42:55 +00:00
// handle watch separately since we cannot watch multiple resource types
2015-04-07 18:21:25 +00:00
isWatch , isWatchOnly := cmdutil . GetFlagBool ( cmd , "watch" ) , cmdutil . GetFlagBool ( cmd , "watch-only" )
2017-08-11 06:21:44 +00:00
var includeUninitialized bool
if isWatch && len ( args ) == 2 {
// include the uninitialized one for watching on a single object
// unless explicitly set --include-uninitialized=false
includeUninitialized = true
}
includeUninitialized = cmdutil . ShouldIncludeUninitialized ( cmd , includeUninitialized )
2014-12-31 00:42:55 +00:00
if isWatch || isWatchOnly {
2017-08-02 20:23:07 +00:00
r := f . NewBuilder ( ) .
Unstructured ( f . UnstructuredClientForMapping , mapper , typer ) .
2015-05-12 11:14:31 +00:00
NamespaceParam ( cmdNamespace ) . DefaultNamespace ( ) . AllNamespaces ( allNamespaces ) .
2016-08-17 18:28:07 +00:00
FilenameParam ( enforceNamespace , & options . FilenameOptions ) .
2014-12-31 00:42:55 +00:00
SelectorParam ( selector ) .
2015-12-02 20:20:10 +00:00
ExportParam ( export ) .
2017-08-10 09:22:03 +00:00
IncludeUninitialized ( includeUninitialized ) .
2015-02-12 14:59:58 +00:00
ResourceTypeOrNameArgs ( true , args ... ) .
2014-12-31 00:42:55 +00:00
SingleResourceType ( ) .
2015-08-10 11:02:14 +00:00
Latest ( ) .
2014-12-31 00:42:55 +00:00
Do ( )
2017-05-16 21:52:51 +00:00
err = r . Err ( )
2015-03-09 22:08:16 +00:00
if err != nil {
return err
}
2015-08-10 11:02:14 +00:00
infos , err := r . Infos ( )
2015-03-09 22:08:16 +00:00
if err != nil {
return err
}
2015-08-10 11:02:14 +00:00
if len ( infos ) != 1 {
2016-12-14 07:18:11 +00:00
return i18n . Errorf ( "watch is only supported on individual resources and resource collections - %d resources were found" , len ( infos ) )
2015-08-10 11:02:14 +00:00
}
2017-02-28 02:36:42 +00:00
if r . TargetsSingleItems ( ) {
filterFuncs = nil
}
2015-08-10 11:02:14 +00:00
info := infos [ 0 ]
mapping := info . ResourceMapping ( )
2017-05-16 21:52:51 +00:00
printer , err := f . PrinterForMapping ( cmd , false , nil , mapping , allNamespaces )
2015-03-09 22:08:16 +00:00
if err != nil {
return err
}
2014-12-31 00:42:55 +00:00
obj , err := r . Object ( )
2015-03-09 22:08:16 +00:00
if err != nil {
return err
}
2016-06-15 20:21:10 +00:00
// watching from resourceVersion 0, starts the watch at ~now and
// will return an initial watch event. Starting form ~now, rather
// the rv of the object will insure that we start the watch from
// inside the watch window, which the rv of the object might not be.
rv := "0"
isList := meta . IsListType ( obj )
if isList {
// the resourceVersion of list objects is ~now but won't return
// an initial watch event
rv , err = mapping . MetadataAccessor . ResourceVersion ( obj )
if err != nil {
return err
}
2015-03-09 22:08:16 +00:00
}
2014-12-31 00:42:55 +00:00
// print the current object
if ! isWatchOnly {
2017-02-28 22:45:09 +00:00
var objsToPrint [ ] runtime . Object
2017-03-22 05:26:18 +00:00
writer := printers . GetNewTabWriter ( out )
2017-02-28 22:45:09 +00:00
if isList {
objsToPrint , _ = meta . ExtractList ( obj )
} else {
objsToPrint = append ( objsToPrint , obj )
}
for _ , objToPrint := range objsToPrint {
2017-09-06 22:07:24 +00:00
if isFiltered , err := filterFuncs . Filter ( objToPrint , filterOpts ) ; ! isFiltered {
if err != nil {
glog . V ( 2 ) . Infof ( "Unable to filter resource: %v" , err )
} else if err := printer . PrintObj ( objToPrint , writer ) ; err != nil {
return fmt . Errorf ( "unable to output the provided object: %v" , err )
}
2017-02-28 22:45:09 +00:00
}
2014-12-31 00:42:55 +00:00
}
2017-03-22 05:26:18 +00:00
writer . Flush ( )
2014-12-31 00:42:55 +00:00
}
2014-10-27 19:56:34 +00:00
2014-12-31 00:42:55 +00:00
// print watched changes
w , err := r . Watch ( rv )
2015-03-09 22:08:16 +00:00
if err != nil {
return err
}
2014-10-27 19:56:34 +00:00
2016-06-15 20:21:10 +00:00
first := true
2016-08-08 17:56:19 +00:00
intr := interrupt . New ( nil , w . Stop )
intr . Run ( func ( ) error {
_ , err := watch . Until ( 0 , w , func ( e watch . Event ) ( bool , error ) {
if ! isList && first {
// drop the initial watch event in the single resource case
first = false
return false , nil
}
2017-09-06 22:07:24 +00:00
if isFiltered , err := filterFuncs . Filter ( e . Object , filterOpts ) ; ! isFiltered {
if err != nil {
glog . V ( 2 ) . Infof ( "Unable to filter resource: %v" , err )
} else if err := printer . PrintObj ( e . Object , out ) ; err != nil {
return false , err
}
}
return false , nil
2016-08-08 17:56:19 +00:00
} )
2016-07-13 16:00:33 +00:00
return err
2014-12-31 00:42:55 +00:00
} )
2015-03-09 22:08:16 +00:00
return nil
2014-12-31 00:42:55 +00:00
}
2014-10-27 19:56:34 +00:00
2017-05-16 21:52:51 +00:00
r := builder .
2015-05-12 11:14:31 +00:00
NamespaceParam ( cmdNamespace ) . DefaultNamespace ( ) . AllNamespaces ( allNamespaces ) .
2016-08-17 18:28:07 +00:00
FilenameParam ( enforceNamespace , & options . FilenameOptions ) .
2014-12-31 00:42:55 +00:00
SelectorParam ( selector ) .
2015-12-02 20:20:10 +00:00
ExportParam ( export ) .
2017-08-10 09:22:03 +00:00
IncludeUninitialized ( includeUninitialized ) .
2015-02-12 14:59:58 +00:00
ResourceTypeOrNameArgs ( true , args ... ) .
2015-03-25 05:01:07 +00:00
ContinueOnError ( ) .
2016-04-14 22:00:40 +00:00
Latest ( ) .
Flatten ( ) .
Do ( )
err = r . Err ( )
if err != nil {
return err
}
2017-05-16 21:52:51 +00:00
printer , err := f . PrinterForCommand ( cmd , false , nil , printers . PrintOptions { } )
2015-03-09 22:08:16 +00:00
if err != nil {
return err
}
2017-02-28 02:36:42 +00:00
if r . TargetsSingleItems ( ) {
filterFuncs = nil
}
2017-02-14 19:48:07 +00:00
if options . IgnoreNotFound {
r . IgnoreErrors ( kapierrors . IsNotFound )
}
2017-05-23 02:47:20 +00:00
if printer . IsGeneric ( ) {
2016-11-02 16:29:01 +00:00
// we flattened the data from the builder, so we have individual items, but now we'd like to either:
// 1. if there is more than one item, combine them all into a single list
// 2. if there is a single item and that item is a list, leave it as its specific list
// 3. if there is a single item and it is not a a list, leave it as a single item
2016-09-10 22:37:27 +00:00
var errs [ ] error
2017-01-09 19:21:24 +00:00
singleItemImplied := false
infos , err := r . IntoSingleItemImplied ( & singleItemImplied ) . Infos ( )
2016-06-02 06:57:43 +00:00
if err != nil {
2017-01-09 19:21:24 +00:00
if singleItemImplied {
2016-06-30 15:23:48 +00:00
return err
}
2016-09-10 22:37:27 +00:00
errs = append ( errs , err )
2016-06-02 06:57:43 +00:00
}
2016-04-14 22:00:40 +00:00
2017-02-14 19:48:07 +00:00
if len ( infos ) == 0 && options . IgnoreNotFound {
return utilerrors . Reduce ( utilerrors . Flatten ( utilerrors . NewAggregate ( errs ) ) )
}
2016-11-02 16:29:01 +00:00
var obj runtime . Object
2017-01-09 19:21:24 +00:00
if ! singleItemImplied || len ( infos ) > 1 {
2016-11-02 16:29:01 +00:00
// we have more than one item, so coerce all items into a list
2017-08-31 18:16:54 +00:00
// we have more than one item, so coerce all items into a list.
// we don't want an *unstructured.Unstructured list yet, as we
// may be dealing with non-unstructured objects. Compose all items
// into an api.List, and then decode using an unstructured scheme.
list := api . List {
TypeMeta : metav1 . TypeMeta {
Kind : "List" ,
APIVersion : "v1" ,
2016-11-02 16:29:01 +00:00
} ,
2017-08-31 18:16:54 +00:00
ListMeta : metav1 . ListMeta { } ,
2016-11-02 16:29:01 +00:00
}
for _ , info := range infos {
2017-08-31 18:16:54 +00:00
list . Items = append ( list . Items , info . Object )
2016-11-02 16:29:01 +00:00
}
2017-08-31 18:16:54 +00:00
listData , err := json . Marshal ( list )
if err != nil {
return err
2016-11-02 16:29:01 +00:00
}
2017-08-31 18:16:54 +00:00
converted , err := runtime . Decode ( unstructured . UnstructuredJSONScheme , listData )
if err != nil {
return err
}
obj = converted
2017-01-09 19:21:24 +00:00
} else {
obj = infos [ 0 ] . Object
2015-03-04 03:18:15 +00:00
}
2016-09-21 14:03:59 +00:00
isList := meta . IsListType ( obj )
if isList {
2017-03-01 23:34:47 +00:00
_ , items , err := cmdutil . FilterResourceList ( obj , filterFuncs , filterOpts )
2016-09-10 22:37:27 +00:00
if err != nil {
return err
2016-09-21 14:03:59 +00:00
}
2016-11-02 16:29:01 +00:00
// take the filtered items and create a new list for display
2016-12-04 04:30:51 +00:00
list := & unstructured . UnstructuredList {
2016-11-02 16:29:01 +00:00
Object : map [ string ] interface { } {
"kind" : "List" ,
"apiVersion" : "v1" ,
"metadata" : map [ string ] interface { } { } ,
} ,
}
if listMeta , err := meta . ListAccessor ( obj ) ; err == nil {
2017-03-31 09:27:25 +00:00
list . Object [ "metadata" ] = map [ string ] interface { } {
"selfLink" : listMeta . GetSelfLink ( ) ,
"resourceVersion" : listMeta . GetResourceVersion ( ) ,
}
2016-11-02 16:29:01 +00:00
}
for _ , item := range items {
2017-03-31 19:18:51 +00:00
list . Items = append ( list . Items , * item . ( * unstructured . Unstructured ) )
2016-09-21 14:03:59 +00:00
}
2016-11-02 16:29:01 +00:00
if err := printer . PrintObj ( list , out ) ; err != nil {
2016-09-10 22:37:27 +00:00
errs = append ( errs , err )
2016-09-21 14:03:59 +00:00
}
2016-09-10 22:37:27 +00:00
return utilerrors . Reduce ( utilerrors . Flatten ( utilerrors . NewAggregate ( errs ) ) )
2016-06-02 06:57:43 +00:00
}
2016-09-21 14:03:59 +00:00
if isFiltered , err := filterFuncs . Filter ( obj , filterOpts ) ; ! isFiltered {
if err != nil {
glog . V ( 2 ) . Infof ( "Unable to filter resource: %v" , err )
} else if err := printer . PrintObj ( obj , out ) ; err != nil {
2016-09-10 22:37:27 +00:00
errs = append ( errs , err )
2016-09-21 14:03:59 +00:00
}
}
2016-09-10 22:37:27 +00:00
return utilerrors . Reduce ( utilerrors . Flatten ( utilerrors . NewAggregate ( errs ) ) )
2016-06-02 06:57:43 +00:00
}
allErrs := [ ] error { }
2016-11-22 06:14:15 +00:00
errs := sets . NewString ( )
2016-06-02 06:57:43 +00:00
infos , err := r . Infos ( )
if err != nil {
allErrs = append ( allErrs , err )
2014-12-31 00:42:55 +00:00
}
2014-11-12 01:31:13 +00:00
2015-10-20 05:44:48 +00:00
objs := make ( [ ] runtime . Object , len ( infos ) )
for ix := range infos {
objs [ ix ] = infos [ ix ] . Object
}
sorting , err := cmd . Flags ( ) . GetString ( "sort-by" )
2016-07-19 03:09:44 +00:00
if err != nil {
return err
}
2015-10-20 05:44:48 +00:00
var sorter * kubectl . RuntimeSort
2016-08-19 06:34:27 +00:00
if len ( sorting ) > 0 && len ( objs ) > 1 {
2015-12-21 05:37:49 +00:00
// TODO: questionable
if sorter , err = kubectl . SortObjects ( f . Decoder ( true ) , objs , sorting ) ; err != nil {
2015-10-20 05:44:48 +00:00
return err
}
}
2014-12-31 00:42:55 +00:00
// use the default printer for each object
2015-10-13 18:36:22 +00:00
printer = nil
var lastMapping * meta . RESTMapping
2017-02-19 22:56:11 +00:00
w := printers . GetNewTabWriter ( out )
2015-10-20 05:44:48 +00:00
2017-05-19 21:24:39 +00:00
useOpenAPIPrintColumns := cmdutil . GetFlagBool ( cmd , useOpenAPIPrintColumnFlagLabel )
2016-11-29 17:25:10 +00:00
if resource . MultipleTypesRequested ( args ) || cmdutil . MustPrintWithKinds ( objs , infos , sorter ) {
2016-07-22 22:01:59 +00:00
showKind = true
2016-06-29 22:02:08 +00:00
}
2017-03-01 23:34:47 +00:00
filteredResourceCount := 0
2015-10-20 05:44:48 +00:00
for ix := range objs {
var mapping * meta . RESTMapping
2016-02-29 22:17:48 +00:00
var original runtime . Object
2017-05-19 21:24:39 +00:00
2015-10-20 05:44:48 +00:00
if sorter != nil {
mapping = infos [ sorter . OriginalPosition ( ix ) ] . Mapping
2016-02-29 22:17:48 +00:00
original = infos [ sorter . OriginalPosition ( ix ) ] . Object
2015-10-20 05:44:48 +00:00
} else {
mapping = infos [ ix ] . Mapping
2016-02-29 22:17:48 +00:00
original = infos [ ix ] . Object
2015-06-15 02:48:56 +00:00
}
2017-05-23 02:47:20 +00:00
if shouldGetNewPrinterForMapping ( printer , lastMapping , mapping ) {
2016-07-13 16:00:33 +00:00
if printer != nil {
w . Flush ( )
}
2017-05-19 21:24:39 +00:00
var outputOpts * printers . OutputOptions
// if cmd does not specify output format and useOpenAPIPrintColumnFlagLabel flag is true,
// then get the default output options for this mapping from OpenAPI schema.
if ! cmdSpecifiesOutputFmt ( cmd ) && useOpenAPIPrintColumns {
2017-08-08 22:00:23 +00:00
outputOpts , _ = outputOptsForMappingFromOpenAPI ( f , mapping )
2017-05-19 21:24:39 +00:00
}
2017-05-16 21:52:51 +00:00
printer , err = f . PrinterForMapping ( cmd , false , outputOpts , mapping , allNamespaces )
2015-10-13 18:36:22 +00:00
if err != nil {
2016-11-22 06:14:15 +00:00
if ! errs . Has ( err . Error ( ) ) {
errs . Insert ( err . Error ( ) )
allErrs = append ( allErrs , err )
}
2016-04-14 22:00:40 +00:00
continue
2015-10-13 18:36:22 +00:00
}
2016-09-28 18:21:46 +00:00
// add linebreak between resource groups (if there is more than one)
// skip linebreak above first resource group
noHeaders := cmdutil . GetFlagBool ( cmd , "no-headers" )
if lastMapping != nil && ! noHeaders {
fmt . Fprintf ( errOut , "%s\n" , "" )
}
2015-10-20 05:44:48 +00:00
lastMapping = mapping
2015-10-13 18:36:22 +00:00
}
2016-09-21 14:03:59 +00:00
2016-12-05 06:43:37 +00:00
// try to convert before apply filter func
decodedObj , _ := kubectl . DecodeUnknownObject ( original )
2016-09-21 14:03:59 +00:00
// filter objects if filter has been defined for current object
2016-12-05 06:43:37 +00:00
if isFiltered , err := filterFuncs . Filter ( decodedObj , filterOpts ) ; isFiltered {
2016-09-21 14:03:59 +00:00
if err == nil {
filteredResourceCount ++
continue
}
2016-11-22 06:14:15 +00:00
if ! errs . Has ( err . Error ( ) ) {
errs . Insert ( err . Error ( ) )
allErrs = append ( allErrs , err )
}
2016-09-21 14:03:59 +00:00
}
2017-02-19 22:56:11 +00:00
if resourcePrinter , found := printer . ( * printers . HumanReadablePrinter ) ; found {
2016-07-22 22:01:59 +00:00
resourceName := resourcePrinter . GetResourceKind ( )
if mapping != nil {
if resourceName == "" {
resourceName = mapping . Resource
}
if alias , ok := kubectl . ResourceShortFormFor ( mapping . Resource ) ; ok {
resourceName = alias
} else if resourceName == "" {
resourceName = "none"
}
} else {
2016-06-29 22:02:08 +00:00
resourceName = "none"
}
2016-07-22 22:01:59 +00:00
if showKind {
resourcePrinter . EnsurePrintWithKind ( resourceName )
}
2016-12-05 06:43:37 +00:00
if err := printer . PrintObj ( decodedObj , w ) ; err != nil {
2016-11-22 06:14:15 +00:00
if ! errs . Has ( err . Error ( ) ) {
errs . Insert ( err . Error ( ) )
allErrs = append ( allErrs , err )
}
2015-10-20 05:44:48 +00:00
}
2015-11-09 05:42:52 +00:00
continue
2015-10-20 05:44:48 +00:00
}
2017-05-19 21:24:39 +00:00
objToPrint := decodedObj
if printer . IsGeneric ( ) {
// use raw object as recieved from the builder when using generic
// printer instead of decodedObj
objToPrint = original
}
if err := printer . PrintObj ( objToPrint , w ) ; err != nil {
2016-11-22 06:14:15 +00:00
if ! errs . Has ( err . Error ( ) ) {
errs . Insert ( err . Error ( ) )
allErrs = append ( allErrs , err )
}
2016-04-14 22:00:40 +00:00
continue
2014-12-31 00:42:55 +00:00
}
2015-10-20 05:44:48 +00:00
}
2016-07-13 16:00:33 +00:00
w . Flush ( )
2017-03-17 13:55:46 +00:00
cmdutil . PrintFilterCount ( errOut , len ( objs ) , filteredResourceCount , len ( allErrs ) , filterOpts , options . IgnoreNotFound )
2016-06-02 06:57:43 +00:00
return utilerrors . NewAggregate ( allErrs )
2014-12-31 00:42:55 +00:00
}
2017-05-23 02:47:20 +00:00
2017-05-19 21:24:39 +00:00
func addOpenAPIPrintColumnFlags ( cmd * cobra . Command ) {
cmd . Flags ( ) . Bool ( useOpenAPIPrintColumnFlagLabel , false , "If true, use x-kubernetes-print-column metadata (if present) from openapi schema for displaying a resource." )
// marking it deprecated so that it is hidden from usage/help text.
2017-08-10 21:28:39 +00:00
cmd . Flags ( ) . MarkDeprecated ( useOpenAPIPrintColumnFlagLabel , "It's an experimental feature." )
2017-05-19 21:24:39 +00:00
}
2017-05-23 02:47:20 +00:00
func shouldGetNewPrinterForMapping ( printer printers . ResourcePrinter , lastMapping , mapping * meta . RESTMapping ) bool {
return printer == nil || lastMapping == nil || mapping == nil || mapping . Resource != lastMapping . Resource
}
2017-05-19 21:24:39 +00:00
func cmdSpecifiesOutputFmt ( cmd * cobra . Command ) bool {
return cmdutil . GetFlagString ( cmd , "output" ) != ""
}
// outputOptsForMappingFromOpenAPI looks for the output format metatadata in the
// openapi schema and returns the output options for the mapping if found.
2017-08-08 22:00:23 +00:00
func outputOptsForMappingFromOpenAPI ( f cmdutil . Factory , mapping * meta . RESTMapping ) ( * printers . OutputOptions , bool ) {
2017-05-19 21:24:39 +00:00
// user has not specified any output format, check if OpenAPI has
// default specification to print this resource type
2017-08-08 22:00:23 +00:00
api , err := f . OpenAPISchema ( )
2017-05-19 21:24:39 +00:00
if err != nil {
// Error getting schema
return nil , false
}
// Found openapi metadata for this resource
2017-09-06 18:34:28 +00:00
schema := api . LookupResource ( mapping . GroupVersionKind )
2017-06-14 23:30:57 +00:00
if schema == nil {
// Schema not found, return empty columns
2017-05-19 21:24:39 +00:00
return nil , false
}
2017-06-14 23:30:57 +00:00
columns , found := openapi . GetPrintColumns ( schema . GetExtensions ( ) )
2017-05-19 21:24:39 +00:00
if ! found {
// Extension not found, return empty columns
return nil , false
}
return outputOptsFromStr ( columns )
}
// outputOptsFromStr parses the print-column metadata and generates printer.OutputOptions object.
func outputOptsFromStr ( columnStr string ) ( * printers . OutputOptions , bool ) {
if columnStr == "" {
return nil , false
}
parts := strings . SplitN ( columnStr , "=" , 2 )
if len ( parts ) < 2 {
return nil , false
}
return & printers . OutputOptions {
FmtType : parts [ 0 ] ,
FmtArg : parts [ 1 ] ,
AllowMissingKeys : true ,
} , true
}