mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-10-31 18:28:13 +00:00 
			
		
		
		
	Merge pull request #129784 from soltysh/refactor_explain
Refactors explain command to split flags from options
This commit is contained in:
		| @@ -98,14 +98,10 @@ var ( | |||||||
| `) | `) | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func boundObjectKindToAPIVersions() map[string]string { | var boundObjectKinds = map[string]string{ | ||||||
| 	kinds := map[string]string{ | 	"Pod":    "v1", | ||||||
| 		"Pod":    "v1", | 	"Secret": "v1", | ||||||
| 		"Secret": "v1", | 	"Node":   "v1", | ||||||
| 		"Node":   "v1", |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return kinds |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func NewTokenOpts(ioStreams genericiooptions.IOStreams) *TokenOptions { | func NewTokenOpts(ioStreams genericiooptions.IOStreams) *TokenOptions { | ||||||
| @@ -149,7 +145,7 @@ func NewCmdCreateToken(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) | |||||||
| 	cmd.Flags().DurationVar(&o.Duration, "duration", o.Duration, "Requested lifetime of the issued token. If not set or if set to 0, the lifetime will be determined by the server automatically. The server may return a token with a longer or shorter lifetime.") | 	cmd.Flags().DurationVar(&o.Duration, "duration", o.Duration, "Requested lifetime of the issued token. If not set or if set to 0, the lifetime will be determined by the server automatically. The server may return a token with a longer or shorter lifetime.") | ||||||
|  |  | ||||||
| 	cmd.Flags().StringVar(&o.BoundObjectKind, "bound-object-kind", o.BoundObjectKind, "Kind of an object to bind the token to. "+ | 	cmd.Flags().StringVar(&o.BoundObjectKind, "bound-object-kind", o.BoundObjectKind, "Kind of an object to bind the token to. "+ | ||||||
| 		"Supported kinds are "+strings.Join(sets.List(sets.KeySet(boundObjectKindToAPIVersions())), ", ")+". "+ | 		"Supported kinds are "+strings.Join(sets.List(sets.KeySet(boundObjectKinds)), ", ")+". "+ | ||||||
| 		"If set, --bound-object-name must be provided.") | 		"If set, --bound-object-name must be provided.") | ||||||
| 	cmd.Flags().StringVar(&o.BoundObjectName, "bound-object-name", o.BoundObjectName, "Name of an object to bind the token to. "+ | 	cmd.Flags().StringVar(&o.BoundObjectName, "bound-object-name", o.BoundObjectName, "Name of an object to bind the token to. "+ | ||||||
| 		"The token will expire when the object is deleted. "+ | 		"The token will expire when the object is deleted. "+ | ||||||
| @@ -226,8 +222,8 @@ func (o *TokenOptions) Validate() error { | |||||||
| 			return fmt.Errorf("--bound-object-uid can only be set if --bound-object-kind is provided") | 			return fmt.Errorf("--bound-object-uid can only be set if --bound-object-kind is provided") | ||||||
| 		} | 		} | ||||||
| 	} else { | 	} else { | ||||||
| 		if _, ok := boundObjectKindToAPIVersions()[o.BoundObjectKind]; !ok { | 		if _, ok := boundObjectKinds[o.BoundObjectKind]; !ok { | ||||||
| 			return fmt.Errorf("supported --bound-object-kind values are %s", strings.Join(sets.List(sets.KeySet(boundObjectKindToAPIVersions())), ", ")) | 			return fmt.Errorf("supported --bound-object-kind values are %s", strings.Join(sets.List(sets.KeySet(boundObjectKinds)), ", ")) | ||||||
| 		} | 		} | ||||||
| 		if len(o.BoundObjectName) == 0 { | 		if len(o.BoundObjectName) == 0 { | ||||||
| 			return fmt.Errorf("--bound-object-name is required if --bound-object-kind is provided") | 			return fmt.Errorf("--bound-object-name is required if --bound-object-kind is provided") | ||||||
| @@ -250,7 +246,7 @@ func (o *TokenOptions) Run() error { | |||||||
| 	if len(o.BoundObjectKind) > 0 { | 	if len(o.BoundObjectKind) > 0 { | ||||||
| 		request.Spec.BoundObjectRef = &authenticationv1.BoundObjectReference{ | 		request.Spec.BoundObjectRef = &authenticationv1.BoundObjectReference{ | ||||||
| 			Kind:       o.BoundObjectKind, | 			Kind:       o.BoundObjectKind, | ||||||
| 			APIVersion: boundObjectKindToAPIVersions()[o.BoundObjectKind], | 			APIVersion: boundObjectKinds[o.BoundObjectKind], | ||||||
| 			Name:       o.BoundObjectName, | 			Name:       o.BoundObjectName, | ||||||
| 			UID:        types.UID(o.BoundObjectUID), | 			UID:        types.UID(o.BoundObjectUID), | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -56,44 +56,77 @@ var ( | |||||||
|  |  | ||||||
| 		# Get the documentation of a specific field of a resource | 		# Get the documentation of a specific field of a resource | ||||||
| 		kubectl explain pods.spec.containers | 		kubectl explain pods.spec.containers | ||||||
| 		 |  | ||||||
| 		# Get the documentation of resources in different format | 		# Get the documentation of resources in different format | ||||||
| 		kubectl explain deployment --output=plaintext-openapiv2`)) | 		kubectl explain deployment --output=plaintext-openapiv2`)) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const ( | ||||||
| 	plaintextTemplateName          = "plaintext" | 	plaintextTemplateName          = "plaintext" | ||||||
| 	plaintextOpenAPIV2TemplateName = "plaintext-openapiv2" | 	plaintextOpenAPIV2TemplateName = "plaintext-openapiv2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type ExplainOptions struct { | // ExplainFlags directly reflect the information that CLI is gathering via flags. | ||||||
| 	genericiooptions.IOStreams | // They will be converted to Options, which reflect the runtime requirements for | ||||||
|  | // the command. | ||||||
| 	CmdParent  string | type ExplainFlags struct { | ||||||
| 	APIVersion string | 	APIVersion   string | ||||||
| 	Recursive  bool |  | ||||||
|  |  | ||||||
| 	args []string |  | ||||||
|  |  | ||||||
| 	Mapper        meta.RESTMapper |  | ||||||
| 	openAPIGetter openapi.OpenAPIResourcesGetter |  | ||||||
|  |  | ||||||
| 	// Name of the template to use with the openapiv3 template renderer. |  | ||||||
| 	OutputFormat string | 	OutputFormat string | ||||||
|  | 	Recursive    bool | ||||||
|  |  | ||||||
| 	// Client capable of fetching openapi documents from the user's cluster | 	genericiooptions.IOStreams | ||||||
| 	OpenAPIV3Client openapiclient.Client |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func NewExplainOptions(parent string, streams genericiooptions.IOStreams) *ExplainOptions { | // NewExplainFlags returns a default ExplainFlags | ||||||
| 	return &ExplainOptions{ | func NewExplainFlags(streams genericiooptions.IOStreams) *ExplainFlags { | ||||||
| 		IOStreams:    streams, | 	return &ExplainFlags{ | ||||||
| 		CmdParent:    parent, |  | ||||||
| 		OutputFormat: plaintextTemplateName, | 		OutputFormat: plaintextTemplateName, | ||||||
|  | 		IOStreams:    streams, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // AddFlags registers flags for a cli | ||||||
|  | func (flags *ExplainFlags) AddFlags(cmd *cobra.Command) { | ||||||
|  | 	cmd.Flags().BoolVar(&flags.Recursive, "recursive", flags.Recursive, "Print the fields of fields (Currently only 1 level deep)") | ||||||
|  | 	cmd.Flags().StringVar(&flags.APIVersion, "api-version", flags.APIVersion, "Get different explanations for particular API version (API group/version)") | ||||||
|  | 	cmd.Flags().StringVar(&flags.OutputFormat, "output", plaintextTemplateName, "Format in which to render the schema (plaintext, plaintext-openapiv2)") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ToOptions converts from CLI inputs to runtime input | ||||||
|  | func (flags *ExplainFlags) ToOptions(f cmdutil.Factory, parent string, args []string) (*ExplainOptions, error) { | ||||||
|  | 	mapper, err := f.ToRESTMapper() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Only openapi v3 needs the discovery client. | ||||||
|  | 	openAPIV3Client, err := f.OpenAPIV3Client() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	o := &ExplainOptions{ | ||||||
|  | 		IOStreams: flags.IOStreams, | ||||||
|  |  | ||||||
|  | 		Recursive:    flags.Recursive, | ||||||
|  | 		APIVersion:   flags.APIVersion, | ||||||
|  | 		OutputFormat: flags.OutputFormat, | ||||||
|  |  | ||||||
|  | 		CmdParent: parent, | ||||||
|  | 		args:      args, | ||||||
|  |  | ||||||
|  | 		Mapper:        mapper, | ||||||
|  | 		openAPIGetter: f, | ||||||
|  |  | ||||||
|  | 		OpenAPIV3Client: openAPIV3Client, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return o, nil | ||||||
|  | } | ||||||
|  |  | ||||||
| // NewCmdExplain returns a cobra command for swagger docs | // NewCmdExplain returns a cobra command for swagger docs | ||||||
| func NewCmdExplain(parent string, f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { | func NewCmdExplain(parent string, f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { | ||||||
| 	o := NewExplainOptions(parent, streams) | 	flags := NewExplainFlags(streams) | ||||||
|  |  | ||||||
| 	cmd := &cobra.Command{ | 	cmd := &cobra.Command{ | ||||||
| 		Use:                   "explain TYPE [--recursive=FALSE|TRUE] [--api-version=api-version-group] [-o|--output=plaintext|plaintext-openapiv2]", | 		Use:                   "explain TYPE [--recursive=FALSE|TRUE] [--api-version=api-version-group] [-o|--output=plaintext|plaintext-openapiv2]", | ||||||
| @@ -102,37 +135,34 @@ func NewCmdExplain(parent string, f cmdutil.Factory, streams genericiooptions.IO | |||||||
| 		Long:                  explainLong + "\n\n" + cmdutil.SuggestAPIResources(parent), | 		Long:                  explainLong + "\n\n" + cmdutil.SuggestAPIResources(parent), | ||||||
| 		Example:               explainExamples, | 		Example:               explainExamples, | ||||||
| 		Run: func(cmd *cobra.Command, args []string) { | 		Run: func(cmd *cobra.Command, args []string) { | ||||||
| 			cmdutil.CheckErr(o.Complete(f, cmd, args)) | 			o, err := flags.ToOptions(f, parent, args) | ||||||
|  | 			cmdutil.CheckErr(err) | ||||||
| 			cmdutil.CheckErr(o.Validate()) | 			cmdutil.CheckErr(o.Validate()) | ||||||
| 			cmdutil.CheckErr(o.Run()) | 			cmdutil.CheckErr(o.Run()) | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| 	cmd.Flags().BoolVar(&o.Recursive, "recursive", o.Recursive, "When true, print the name of all the fields recursively. Otherwise, print the available fields with their description.") |  | ||||||
| 	cmd.Flags().StringVar(&o.APIVersion, "api-version", o.APIVersion, "Use given api-version (group/version) of the resource.") |  | ||||||
|  |  | ||||||
| 	// Only enable --output as a valid flag if the feature is enabled | 	flags.AddFlags(cmd) | ||||||
| 	cmd.Flags().StringVarP(&o.OutputFormat, "output", "o", plaintextTemplateName, "Format in which to render the schema. Valid values are: (plaintext, plaintext-openapiv2).") |  | ||||||
|  |  | ||||||
| 	return cmd | 	return cmd | ||||||
| } | } | ||||||
|  |  | ||||||
| func (o *ExplainOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { | type ExplainOptions struct { | ||||||
| 	var err error | 	genericiooptions.IOStreams | ||||||
| 	o.Mapper, err = f.ToRESTMapper() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Only openapi v3 needs the discovery client. | 	Recursive  bool | ||||||
| 	o.OpenAPIV3Client, err = f.OpenAPIV3Client() | 	APIVersion string | ||||||
| 	if err != nil { | 	// Name of the template to use with the openapiv3 template renderer. | ||||||
| 		return err | 	OutputFormat string | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Lazy-load the OpenAPI V2 Resources, so they're not loaded when using OpenAPI V3. | 	CmdParent string | ||||||
| 	o.openAPIGetter = f | 	args      []string | ||||||
| 	o.args = args |  | ||||||
| 	return nil | 	Mapper        meta.RESTMapper | ||||||
|  | 	openAPIGetter openapi.OpenAPIResourcesGetter | ||||||
|  |  | ||||||
|  | 	// Client capable of fetching openapi documents from the user's cluster | ||||||
|  | 	OpenAPIV3Client openapiclient.Client | ||||||
| } | } | ||||||
|  |  | ||||||
| func (o *ExplainOptions) Validate() error { | func (o *ExplainOptions) Validate() error { | ||||||
|   | |||||||
| @@ -57,9 +57,9 @@ func TestExplainInvalidArgs(t *testing.T) { | |||||||
| 	tf := cmdtesting.NewTestFactory() | 	tf := cmdtesting.NewTestFactory() | ||||||
| 	defer tf.Cleanup() | 	defer tf.Cleanup() | ||||||
|  |  | ||||||
| 	opts := explain.NewExplainOptions("kubectl", genericiooptions.NewTestIOStreamsDiscard()) | 	flags := explain.NewExplainFlags(genericiooptions.NewTestIOStreamsDiscard()) | ||||||
| 	cmd := explain.NewCmdExplain("kubectl", tf, genericiooptions.NewTestIOStreamsDiscard()) |  | ||||||
| 	err := opts.Complete(tf, cmd, []string{}) | 	opts, err := flags.ToOptions(tf, "kubectl", []string{}) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatalf("unexpected error %v", err) | 		t.Fatalf("unexpected error %v", err) | ||||||
| 	} | 	} | ||||||
| @@ -69,7 +69,7 @@ func TestExplainInvalidArgs(t *testing.T) { | |||||||
| 		t.Error("unexpected non-error") | 		t.Error("unexpected non-error") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	err = opts.Complete(tf, cmd, []string{"resource1", "resource2"}) | 	opts, err = flags.ToOptions(tf, "kubectl", []string{"resource1", "resource2"}) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatalf("unexpected error %v", err) | 		t.Fatalf("unexpected error %v", err) | ||||||
| 	} | 	} | ||||||
| @@ -84,9 +84,9 @@ func TestExplainNotExistResource(t *testing.T) { | |||||||
| 	tf := cmdtesting.NewTestFactory() | 	tf := cmdtesting.NewTestFactory() | ||||||
| 	defer tf.Cleanup() | 	defer tf.Cleanup() | ||||||
|  |  | ||||||
| 	opts := explain.NewExplainOptions("kubectl", genericiooptions.NewTestIOStreamsDiscard()) | 	flags := explain.NewExplainFlags(genericiooptions.NewTestIOStreamsDiscard()) | ||||||
| 	cmd := explain.NewCmdExplain("kubectl", tf, genericiooptions.NewTestIOStreamsDiscard()) |  | ||||||
| 	err := opts.Complete(tf, cmd, []string{"foo"}) | 	opts, err := flags.ToOptions(tf, "kubectl", []string{"foo"}) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatalf("unexpected error %v", err) | 		t.Fatalf("unexpected error %v", err) | ||||||
| 	} | 	} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Kubernetes Prow Robot
					Kubernetes Prow Robot