mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-31 05:40:42 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			230 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			230 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
| Copyright 2018 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 cmd
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"sort"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/spf13/cobra"
 | |
| 
 | |
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | |
| 	"k8s.io/apimachinery/pkg/runtime/schema"
 | |
| 	"k8s.io/apimachinery/pkg/util/sets"
 | |
| 	"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
 | |
| 	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
 | |
| 	"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
 | |
| 	"k8s.io/kubernetes/pkg/printers"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	apiresourcesExample = templates.Examples(`
 | |
| 		# Print the supported API Resources
 | |
| 		kubectl api-resources
 | |
| 
 | |
| 		# Print the supported API Resources with more information
 | |
| 		kubectl api-resources -o wide
 | |
| 
 | |
| 		# Print the supported namespaced resources
 | |
| 		kubectl api-resources --namespaced=true
 | |
| 
 | |
| 		# Print the supported non-namespaced resources
 | |
| 		kubectl api-resources --namespaced=false
 | |
| 
 | |
| 		# Print the supported API Resources with specific APIGroup
 | |
| 		kubectl api-resources --api-group=extensions`)
 | |
| )
 | |
| 
 | |
| // ApiResourcesOptions 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 ApiResourcesOptions struct {
 | |
| 	Output     string
 | |
| 	APIGroup   string
 | |
| 	Namespaced bool
 | |
| 	Verbs      []string
 | |
| 	NoHeaders  bool
 | |
| 	Cached     bool
 | |
| 
 | |
| 	genericclioptions.IOStreams
 | |
| }
 | |
| 
 | |
| // groupResource contains the APIGroup and APIResource
 | |
| type groupResource struct {
 | |
| 	APIGroup    string
 | |
| 	APIResource metav1.APIResource
 | |
| }
 | |
| 
 | |
| func NewAPIResourceOptions(ioStreams genericclioptions.IOStreams) *ApiResourcesOptions {
 | |
| 	return &ApiResourcesOptions{
 | |
| 		IOStreams:  ioStreams,
 | |
| 		Namespaced: true,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func NewCmdApiResources(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
 | |
| 	o := NewAPIResourceOptions(ioStreams)
 | |
| 
 | |
| 	cmd := &cobra.Command{
 | |
| 		Use:     "api-resources",
 | |
| 		Short:   "Print the supported API resources on the server",
 | |
| 		Long:    "Print the supported API resources on the server",
 | |
| 		Example: apiresourcesExample,
 | |
| 		Run: func(cmd *cobra.Command, args []string) {
 | |
| 			cmdutil.CheckErr(o.Validate(cmd))
 | |
| 			cmdutil.CheckErr(o.RunApiResources(cmd, f))
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	cmd.Flags().BoolVar(&o.NoHeaders, "no-headers", o.NoHeaders, "When using the default or custom-column output format, don't print headers (default print headers).")
 | |
| 	cmd.Flags().StringVarP(&o.Output, "output", "o", o.Output, "Output format. One of: wide|name.")
 | |
| 
 | |
| 	cmd.Flags().StringVar(&o.APIGroup, "api-group", o.APIGroup, "Limit to resources in the specified API group.")
 | |
| 	cmd.Flags().BoolVar(&o.Namespaced, "namespaced", o.Namespaced, "If false, non-namespaced resources will be returned, otherwise returning namespaced resources by default.")
 | |
| 	cmd.Flags().StringSliceVar(&o.Verbs, "verbs", o.Verbs, "Limit to resources that support the specified verbs.")
 | |
| 	cmd.Flags().BoolVar(&o.Cached, "cached", o.Cached, "Use the cached list of resources if available.")
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| func (o *ApiResourcesOptions) Validate(cmd *cobra.Command) error {
 | |
| 	supportedOutputTypes := sets.NewString("", "wide", "name")
 | |
| 	if !supportedOutputTypes.Has(o.Output) {
 | |
| 		return fmt.Errorf("--output %v is not available", o.Output)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (o *ApiResourcesOptions) RunApiResources(cmd *cobra.Command, f cmdutil.Factory) error {
 | |
| 	w := printers.GetNewTabWriter(o.Out)
 | |
| 	defer w.Flush()
 | |
| 
 | |
| 	discoveryclient, err := f.ToDiscoveryClient()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	if !o.Cached {
 | |
| 		// Always request fresh data from the server
 | |
| 		discoveryclient.Invalidate()
 | |
| 	}
 | |
| 
 | |
| 	lists, err := discoveryclient.ServerPreferredResources()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	resources := []groupResource{}
 | |
| 
 | |
| 	groupChanged := cmd.Flags().Changed("api-group")
 | |
| 	nsChanged := cmd.Flags().Changed("namespaced")
 | |
| 
 | |
| 	for _, list := range lists {
 | |
| 		if len(list.APIResources) == 0 {
 | |
| 			continue
 | |
| 		}
 | |
| 		gv, err := schema.ParseGroupVersion(list.GroupVersion)
 | |
| 		if err != nil {
 | |
| 			continue
 | |
| 		}
 | |
| 		for _, resource := range list.APIResources {
 | |
| 			if len(resource.Verbs) == 0 {
 | |
| 				continue
 | |
| 			}
 | |
| 			// filter apiGroup
 | |
| 			if groupChanged && o.APIGroup != gv.Group {
 | |
| 				continue
 | |
| 			}
 | |
| 			// filter namespaced
 | |
| 			if nsChanged && o.Namespaced != resource.Namespaced {
 | |
| 				continue
 | |
| 			}
 | |
| 			// filter to resources that support the specified verbs
 | |
| 			if len(o.Verbs) > 0 && !sets.NewString(resource.Verbs...).HasAll(o.Verbs...) {
 | |
| 				continue
 | |
| 			}
 | |
| 			resources = append(resources, groupResource{
 | |
| 				APIGroup:    gv.Group,
 | |
| 				APIResource: resource,
 | |
| 			})
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if o.NoHeaders == false && o.Output != "name" {
 | |
| 		if err = printContextHeaders(w, o.Output); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	sort.Stable(sortableGroupResource(resources))
 | |
| 	for _, r := range resources {
 | |
| 		switch o.Output {
 | |
| 		case "name":
 | |
| 			name := r.APIResource.Name
 | |
| 			if len(r.APIGroup) > 0 {
 | |
| 				name += "." + r.APIGroup
 | |
| 			}
 | |
| 			if _, err := fmt.Fprintf(w, "%s\n", name); err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 		case "wide":
 | |
| 			if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%v\t%s\t%v\n",
 | |
| 				r.APIResource.Name,
 | |
| 				strings.Join(r.APIResource.ShortNames, ","),
 | |
| 				r.APIGroup,
 | |
| 				r.APIResource.Namespaced,
 | |
| 				r.APIResource.Kind,
 | |
| 				r.APIResource.Verbs); err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 		case "":
 | |
| 			if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%v\t%s\n",
 | |
| 				r.APIResource.Name,
 | |
| 				strings.Join(r.APIResource.ShortNames, ","),
 | |
| 				r.APIGroup,
 | |
| 				r.APIResource.Namespaced,
 | |
| 				r.APIResource.Kind); err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func printContextHeaders(out io.Writer, output string) error {
 | |
| 	columnNames := []string{"NAME", "SHORTNAMES", "APIGROUP", "NAMESPACED", "KIND"}
 | |
| 	if output == "wide" {
 | |
| 		columnNames = append(columnNames, "VERBS")
 | |
| 	}
 | |
| 	_, err := fmt.Fprintf(out, "%s\n", strings.Join(columnNames, "\t"))
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| type sortableGroupResource []groupResource
 | |
| 
 | |
| func (s sortableGroupResource) Len() int      { return len(s) }
 | |
| func (s sortableGroupResource) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
 | |
| func (s sortableGroupResource) Less(i, j int) bool {
 | |
| 	ret := strings.Compare(s[i].APIGroup, s[j].APIGroup)
 | |
| 	if ret > 0 {
 | |
| 		return false
 | |
| 	} else if ret == 0 {
 | |
| 		return strings.Compare(s[i].APIResource.Name, s[j].APIResource.Name) < 0
 | |
| 	}
 | |
| 	return true
 | |
| }
 |