2019-01-12 04:58:27 +00:00
/ *
Copyright 2014 The Kubernetes Authors .
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 describe
import (
"fmt"
"strings"
"github.com/spf13/cobra"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/cli-runtime/pkg/genericclioptions"
2019-04-07 17:07:55 +00:00
"k8s.io/cli-runtime/pkg/resource"
2019-09-27 21:51:53 +00:00
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/describe"
"k8s.io/kubectl/pkg/util/i18n"
"k8s.io/kubectl/pkg/util/templates"
2019-01-12 04:58:27 +00:00
)
var (
describeLong = templates . LongDesc ( `
Show details of a specific resource or group of resources
Print a detailed description of the selected resources , including related resources such
as events or controllers . You may select a single object by name , all objects of that
type , provide a name prefix , or label selector . For example :
$ kubectl describe TYPE NAME_PREFIX
will first check for an exact match on TYPE and NAME_PREFIX . If no such resource
exists , it will output details for every resource that has a name prefixed with NAME_PREFIX . ` )
describeExample = templates . Examples ( i18n . T ( `
# Describe a node
kubectl describe nodes kubernetes - node - emt8 . c . myproject . internal
# Describe a pod
kubectl describe pods / nginx
# Describe a pod identified by type and name in "pod.json"
kubectl describe - f pod . json
# Describe all pods
kubectl describe pods
# Describe pods by label name = myLabel
kubectl describe po - l name = myLabel
# Describe all pods managed by the ' frontend ' replication controller ( rc - created pods
# get the name of the rc as a prefix in the pod the name ) .
kubectl describe pods frontend ` ) )
)
type DescribeOptions struct {
CmdParent string
Selector string
Namespace string
2020-03-26 21:07:15 +00:00
Describer func ( * meta . RESTMapping ) ( describe . ResourceDescriber , error )
2019-01-12 04:58:27 +00:00
NewBuilder func ( ) * resource . Builder
BuilderArgs [ ] string
2019-04-07 17:07:55 +00:00
EnforceNamespace bool
AllNamespaces bool
2019-01-12 04:58:27 +00:00
DescriberSettings * describe . DescriberSettings
FilenameOptions * resource . FilenameOptions
genericclioptions . IOStreams
}
func NewCmdDescribe ( parent string , f cmdutil . Factory , streams genericclioptions . IOStreams ) * cobra . Command {
o := & DescribeOptions {
FilenameOptions : & resource . FilenameOptions { } ,
DescriberSettings : & describe . DescriberSettings {
ShowEvents : true ,
} ,
CmdParent : parent ,
IOStreams : streams ,
}
cmd := & cobra . Command {
Use : "describe (-f FILENAME | TYPE [NAME_PREFIX | -l label] | TYPE/NAME)" ,
DisableFlagsInUseLine : true ,
Short : i18n . T ( "Show details of a specific resource or group of resources" ) ,
2019-04-07 17:07:55 +00:00
Long : describeLong + "\n\n" + cmdutil . SuggestAPIResources ( parent ) ,
2019-01-12 04:58:27 +00:00
Example : describeExample ,
Run : func ( cmd * cobra . Command , args [ ] string ) {
cmdutil . CheckErr ( o . Complete ( f , cmd , args ) )
cmdutil . CheckErr ( o . Run ( ) )
} ,
}
usage := "containing the resource to describe"
cmdutil . AddFilenameOptionFlags ( cmd , o . FilenameOptions , usage )
cmd . Flags ( ) . StringVarP ( & o . Selector , "selector" , "l" , o . Selector , "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)" )
2019-04-07 17:07:55 +00:00
cmd . Flags ( ) . BoolVarP ( & o . AllNamespaces , "all-namespaces" , "A" , o . AllNamespaces , "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace." )
2019-01-12 04:58:27 +00:00
cmd . Flags ( ) . BoolVar ( & o . DescriberSettings . ShowEvents , "show-events" , o . DescriberSettings . ShowEvents , "If true, display events related to the described object." )
return cmd
}
func ( o * DescribeOptions ) Complete ( f cmdutil . Factory , cmd * cobra . Command , args [ ] string ) error {
var err error
o . Namespace , o . EnforceNamespace , err = f . ToRawKubeConfigLoader ( ) . Namespace ( )
if err != nil {
return err
}
if o . AllNamespaces {
o . EnforceNamespace = false
}
2019-08-30 18:33:25 +00:00
if len ( args ) == 0 && cmdutil . IsFilenameSliceEmpty ( o . FilenameOptions . Filenames , o . FilenameOptions . Kustomize ) {
2019-04-07 17:07:55 +00:00
return fmt . Errorf ( "You must specify the type of resource to describe. %s\n" , cmdutil . SuggestAPIResources ( o . CmdParent ) )
2019-01-12 04:58:27 +00:00
}
o . BuilderArgs = args
2020-03-26 21:07:15 +00:00
o . Describer = func ( mapping * meta . RESTMapping ) ( describe . ResourceDescriber , error ) {
return describe . DescriberFn ( f , mapping )
2019-01-12 04:58:27 +00:00
}
o . NewBuilder = f . NewBuilder
return nil
}
func ( o * DescribeOptions ) Validate ( args [ ] string ) error {
return nil
}
func ( o * DescribeOptions ) Run ( ) error {
r := o . NewBuilder ( ) .
Unstructured ( ) .
ContinueOnError ( ) .
NamespaceParam ( o . Namespace ) . DefaultNamespace ( ) . AllNamespaces ( o . AllNamespaces ) .
FilenameParam ( o . EnforceNamespace , o . FilenameOptions ) .
LabelSelectorParam ( o . Selector ) .
ResourceTypeOrNameArgs ( true , o . BuilderArgs ... ) .
Flatten ( ) .
Do ( )
err := r . Err ( )
if err != nil {
return err
}
allErrs := [ ] error { }
infos , err := r . Infos ( )
if err != nil {
if apierrors . IsNotFound ( err ) && len ( o . BuilderArgs ) == 2 {
return o . DescribeMatchingResources ( err , o . BuilderArgs [ 0 ] , o . BuilderArgs [ 1 ] )
}
allErrs = append ( allErrs , err )
}
errs := sets . NewString ( )
first := true
for _ , info := range infos {
mapping := info . ResourceMapping ( )
describer , err := o . Describer ( mapping )
if err != nil {
if errs . Has ( err . Error ( ) ) {
continue
}
allErrs = append ( allErrs , err )
errs . Insert ( err . Error ( ) )
continue
}
s , err := describer . Describe ( info . Namespace , info . Name , * o . DescriberSettings )
if err != nil {
if errs . Has ( err . Error ( ) ) {
continue
}
allErrs = append ( allErrs , err )
errs . Insert ( err . Error ( ) )
continue
}
if first {
first = false
fmt . Fprint ( o . Out , s )
} else {
fmt . Fprintf ( o . Out , "\n\n%s" , s )
}
}
2020-03-26 21:07:15 +00:00
if len ( infos ) == 0 && len ( allErrs ) == 0 {
// if we wrote no output, and had no errors, be sure we output something.
if o . AllNamespaces {
fmt . Fprintln ( o . ErrOut , "No resources found" )
} else {
fmt . Fprintf ( o . ErrOut , "No resources found in %s namespace.\n" , o . Namespace )
}
}
2019-01-12 04:58:27 +00:00
return utilerrors . NewAggregate ( allErrs )
}
func ( o * DescribeOptions ) DescribeMatchingResources ( originalError error , resource , prefix string ) error {
r := o . NewBuilder ( ) .
Unstructured ( ) .
NamespaceParam ( o . Namespace ) . DefaultNamespace ( ) .
ResourceTypeOrNameArgs ( true , resource ) .
SingleResourceType ( ) .
Flatten ( ) .
Do ( )
mapping , err := r . ResourceMapping ( )
if err != nil {
return err
}
describer , err := o . Describer ( mapping )
if err != nil {
return err
}
infos , err := r . Infos ( )
if err != nil {
return err
}
isFound := false
for ix := range infos {
info := infos [ ix ]
if strings . HasPrefix ( info . Name , prefix ) {
isFound = true
s , err := describer . Describe ( info . Namespace , info . Name , * o . DescriberSettings )
if err != nil {
return err
}
fmt . Fprintf ( o . Out , "%s\n" , s )
}
}
if ! isFound {
return originalError
}
return nil
}