Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Fix hardcoded string, add fetch validResource from APIServer #51324

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions pkg/kubectl/cmd/annotate.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,15 @@ type AnnotateOptions struct {
}

var (
annotateLong = templates.LongDesc(`
annotateLong = `
Update the annotations on one or more resources.

* An annotation is a key/value pair that can hold larger (compared to a label), and possibly not human-readable, data.
* It is intended to store non-identifying auxiliary data, especially data manipulated by tools and system extensions.
* If --overwrite is true, then existing annotations can be overwritten, otherwise attempting to overwrite an annotation will result in an error.
* If --resource-version is specified, then updates will use this resource version, otherwise the existing resource-version will be used.

` + validResources)
%[1]s`

annotateExample = templates.Examples(i18n.T(`
# Update pod 'foo' with the annotation 'description' and the value 'my frontend'.
Expand Down Expand Up @@ -113,7 +113,7 @@ func NewCmdAnnotate(f cmdutil.Factory, out io.Writer) *cobra.Command {
cmd := &cobra.Command{
Use: "annotate [--overwrite] (-f FILENAME | TYPE NAME) KEY_1=VAL_1 ... KEY_N=VAL_N [--resource-version=version]",
Short: i18n.T("Update the annotations on a resource"),
Long: annotateLong,
Long: templates.LongDesc(fmt.Sprintf(annotateLong, f.ValidResourcesFromDiscoveryClient())),
Copy link
Member

@liggitt liggitt Sep 2, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should ever talk to the server to display help. I'd rather see a dedicated command for displaying available resources, and reference that command in this help string

Copy link
Contributor Author

@shiywang shiywang Sep 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wrote a proposal for this feature, ptal kubernetes/community#1017

Example: annotateExample,
Run: func(cmd *cobra.Command, args []string) {
if err := options.Complete(out, cmd, args); err != nil {
Expand Down
45 changes: 0 additions & 45 deletions pkg/kubectl/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,51 +195,6 @@ __custom_func() {
esac
}
`

// If you add a resource to this list, please also take a look at pkg/kubectl/kubectl.go
// and add a short forms entry in expandResourceShortcut() when appropriate.
// TODO: This should be populated using the discovery information from apiserver.
validResources = `Valid resource types include:

* all
* certificatesigningrequests (aka 'csr')
* clusterrolebindings
* clusterroles
* clusters (valid only for federation apiservers)
* componentstatuses (aka 'cs')
* configmaps (aka 'cm')
* controllerrevisions
* cronjobs
* customresourcedefinition (aka 'crd')
* daemonsets (aka 'ds')
* deployments (aka 'deploy')
* endpoints (aka 'ep')
* events (aka 'ev')
* horizontalpodautoscalers (aka 'hpa')
* ingresses (aka 'ing')
* jobs
* limitranges (aka 'limits')
* namespaces (aka 'ns')
* networkpolicies (aka 'netpol')
* nodes (aka 'no')
* persistentvolumeclaims (aka 'pvc')
* persistentvolumes (aka 'pv')
* poddisruptionbudgets (aka 'pdb')
* podpreset
* pods (aka 'po')
* podsecuritypolicies (aka 'psp')
* podtemplates
* replicasets (aka 'rs')
* replicationcontrollers (aka 'rc')
* resourcequotas (aka 'quota')
* rolebindings
* roles
* secrets
* serviceaccounts (aka 'sa')
* services (aka 'svc')
* statefulsets
* storageclasses
`
)

var (
Expand Down
12 changes: 6 additions & 6 deletions pkg/kubectl/cmd/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import (
)

var (
describe_long = templates.LongDesc(`
describeLong = `
Show details of a specific resource or group of resources.
This command joins many API calls together to form a detailed description of a
given resource or group of resources.
Expand All @@ -47,9 +47,9 @@ var (
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.

` + validResources)
%[1]s`

describe_example = templates.Examples(i18n.T(`
describeExample = templates.Examples(i18n.T(`
# Describe a node
kubectl describe nodes kubernetes-node-emt8.c.myproject.internal

Expand Down Expand Up @@ -82,8 +82,8 @@ func NewCmdDescribe(f cmdutil.Factory, out, cmdErr io.Writer) *cobra.Command {
cmd := &cobra.Command{
Use: "describe (-f FILENAME | TYPE [NAME_PREFIX | -l label] | TYPE/NAME)",
Short: i18n.T("Show details of a specific resource or group of resources"),
Long: describe_long,
Example: describe_example,
Long: templates.LongDesc(fmt.Sprintf(describeLong, f.ValidResourcesFromDiscoveryClient())),
Example: describeExample,
Run: func(cmd *cobra.Command, args []string) {
err := RunDescribe(f, out, cmdErr, cmd, args, options, describerSettings)
cmdutil.CheckErr(err)
Expand Down Expand Up @@ -111,7 +111,7 @@ func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, a
enforceNamespace = false
}
if len(args) == 0 && cmdutil.IsFilenameSliceEmpty(options.Filenames) {
fmt.Fprint(cmdErr, "You must specify the type of resource to describe. ", validResources)
fmt.Fprint(cmdErr, "You must specify the type of resource to describe. ", f.ValidResourcesFromDiscoveryClient())
return cmdutil.UsageErrorf(cmd, "Required resource not specified.")
}

Expand Down
8 changes: 4 additions & 4 deletions pkg/kubectl/cmd/explain.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ import (
)

var (
explainLong = templates.LongDesc(`
explainLong = `
Documentation of resources.

` + validResources)
%[1]s`

explainExamples = templates.Examples(i18n.T(`
# Get the documentation of the resource and its fields
Expand All @@ -49,7 +49,7 @@ func NewCmdExplain(f cmdutil.Factory, out, cmdErr io.Writer) *cobra.Command {
cmd := &cobra.Command{
Use: "explain RESOURCE",
Short: i18n.T("Documentation of resources"),
Long: explainLong,
Long: templates.LongDesc(fmt.Sprintf(explainLong, f.ValidResourcesFromDiscoveryClient())),
Example: explainExamples,
Run: func(cmd *cobra.Command, args []string) {
err := RunExplain(f, out, cmdErr, cmd, args)
Expand All @@ -65,7 +65,7 @@ func NewCmdExplain(f cmdutil.Factory, out, cmdErr io.Writer) *cobra.Command {
// RunExplain executes the appropriate steps to print a model's documentation
func RunExplain(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, args []string) error {
if len(args) == 0 {
fmt.Fprintf(cmdErr, "You must specify the type of resource to explain. %s\n", validResources)
fmt.Fprintf(cmdErr, "You must specify the type of resource to explain. %s\n", f.ValidResourcesFromDiscoveryClient())
return cmdutil.UsageErrorf(cmd, "Required resource not specified.")
}
if len(args) > 1 {
Expand Down
12 changes: 6 additions & 6 deletions pkg/kubectl/cmd/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,17 @@ type GetOptions struct {
}

var (
getLong = templates.LongDesc(`
getLong = `
Display one or many resources.

` + validResources + `
%[1]s` +

This command will hide resources that have completed, such as pods that are
`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
resource by providing the '--show-all' flag.

By specifying the output as 'template' and providing a Go template as the value
of the --template flag, you can filter the attributes of the fetched resources.`)
of the --template flag, you can filter the attributes of the fetched resources.`

getExample = templates.Examples(i18n.T(`
# List all pods in ps output format.
Expand Down Expand Up @@ -115,7 +115,7 @@ func NewCmdGet(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Comman
cmd := &cobra.Command{
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]",
Short: i18n.T("Display one or many resources"),
Long: getLong,
Long: templates.LongDesc(fmt.Sprintf(getLong, f.ValidResourcesFromDiscoveryClient())),
Example: getExample,
Run: func(cmd *cobra.Command, args []string) {
err := RunGet(f, out, errOut, cmd, args, options)
Expand Down Expand Up @@ -183,7 +183,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
}

if len(args) == 0 && cmdutil.IsFilenameSliceEmpty(options.Filenames) {
fmt.Fprint(errOut, "You must specify the type of resource to get. ", validResources)
fmt.Fprint(errOut, "You must specify the type of resource to get. ", f.ValidResourcesFromDiscoveryClient())

fullCmdName := cmd.Parent().CommandPath()
usageString := "Required resource not specified."
Expand Down
8 changes: 8 additions & 0 deletions pkg/kubectl/cmd/testing/fake.go
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,10 @@ func (f *FakeFactory) OpenAPISchema(cacheDir string) (openapi.Resources, error)
return nil, nil
}

func (f *FakeFactory) ValidResourcesFromDiscoveryClient() string {
return ""
}

func (f *FakeFactory) DefaultNamespace() (string, bool, error) {
return f.tf.Namespace, false, f.tf.Err
}
Expand Down Expand Up @@ -803,6 +807,10 @@ func (f *fakeAPIFactory) OpenAPISchema(cacheDir string) (openapi.Resources, erro
return nil, nil
}

func (f *fakeAPIFactory) ValidResourcesFromDiscoveryClient() string {
return ""
}

func NewAPIFactory() (cmdutil.Factory, *TestFactory, runtime.Codec, runtime.NegotiatedSerializer) {
t := &TestFactory{
Validator: validation.NullSchema{},
Expand Down
2 changes: 2 additions & 0 deletions pkg/kubectl/cmd/util/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,8 @@ type ObjectMappingFactory interface {
SwaggerSchema(schema.GroupVersionKind) (*swagger.ApiDeclaration, error)
// OpenAPISchema returns the schema openapi schema definiton
OpenAPISchema(cacheDir string) (openapi.Resources, error)
// ValidResourcesFromDiscoveryClient fetch valiedResource from apiserver.
ValidResourcesFromDiscoveryClient() string
}

// BuilderFactory holds the second level of factory methods. These functions depend upon ObjectMappingFactory and ClientAccessFactory methods.
Expand Down
67 changes: 67 additions & 0 deletions pkg/kubectl/cmd/util/factory_object_mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"os"
"path"
"sort"
"strings"
"sync"
"time"

Expand Down Expand Up @@ -489,3 +490,69 @@ func (f *ring1Factory) OpenAPISchema(cacheDir string) (openapi.Resources, error)
// Delegate to the OpenAPIGetter
return f.openAPIGetter.getter.Get()
}

func (f *ring1Factory) ValidResourcesFromDiscoveryClient() string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this method ought to return []string of just the resources strings

Copy link
Contributor Author

@shiywang shiywang Aug 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resources strings only contain resource name ? or we can directly return sorted []APIResources then write a wrapper/helper function to concatenate those APIResource.Name and APIREsource.ShortNames to string output ?

resourceMap := make(map[string]metav1.APIResource)
var keys []string
discoveryClient, err := f.clientAccessFactory.DiscoveryClient()
if err != nil {
return validLegacyGroupResources
}
apiResList, err := discoveryClient.ServerResources()
if err != nil {
return validLegacyGroupResources
}

for _, apiResources := range apiResList {
for _, apiRes := range apiResources.APIResources {
if !strings.Contains(apiRes.Name, "/") {
if _, ok := resourceMap[apiRes.Name]; !ok {
resourceMap[apiRes.Name] = apiRes
keys = append(keys, apiRes.Name)
}
}
}
}
sort.Strings(keys)
row := "Valid resource types include:\n\n * all\n"
for _, k := range keys {
//add resource name
row = row + fmt.Sprintf(" * %s ", resourceMap[k].Name)
//concatenate shortnames
if len(resourceMap[k].ShortNames) > 0 {
row = row + " (aka "
for i, shortName := range resourceMap[k].ShortNames {
row = row + "'" + shortName + "'"
if i < len(resourceMap[k].ShortNames)-1 {
row = row + ","
}
}
row = row + ")"
}
//add newline
row = row + "\n"
}
return row
}

const validLegacyGroupResources = `Valid resource types include:

* all
* bindings
* componentstatuses (aka 'cs')
* configmaps (aka 'cm')
* endpoints (aka 'ep')
* events (aka 'ev')
* limitranges (aka 'limits')
* namespaces (aka 'ns')
* nodes (aka 'no')
* persistentvolumeclaims (aka 'pvc')
* persistentvolumes (aka 'pv')
* pods (aka 'po')
* podtemplates
* replicationcontrollers (aka 'rc')
* resourcequotas (aka 'quota')
* secrets
* serviceaccounts (aka 'sa')
* services (aka 'svc')
`