-
Notifications
You must be signed in to change notification settings - Fork 39.8k
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
Get command uses print-column extn from Openapi schema #46235
Conversation
Thanks for your pull request. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). 📝 Please follow instructions at https://github.com/kubernetes/kubernetes/wiki/CLA-FAQ to sign the CLA. It may take a couple minutes for the CLA signature to be fully registered; after that, please reply here with a new comment and we'll verify. Thanks.
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
Hi @droot. Thanks for your PR. I'm waiting for a kubernetes member to verify that this patch is reasonable to test. If it is, they should reply with Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
pkg/api/v1/types.go
Outdated
@@ -2568,6 +2568,7 @@ type PodStatusResult struct { | |||
|
|||
// Pod is a collection of containers that can run on a host. This resource is created | |||
// by clients and scheduled onto hosts. | |||
// +k8s:openapi-gen=x-kubernetes-print-columns:custom-columns=NAME:.metadata.name,RSRC:.metadata.resourceVersion |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good for testing, but we don't want to merge this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, took it out.
pkg/kubectl/cmd/get.go
Outdated
@@ -139,6 +139,8 @@ func NewCmdGet(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Comman | |||
// RunGet implements the generic Get command | |||
// TODO: convert all direct flag accessors to a struct and pass that instead of cmd | |||
func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args []string, options *GetOptions) error { | |||
go f.OpenAPISchema(cmdutil.GetOpenAPICacheDir(cmd)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets flag guard this, default off until Antoine's optimization is merged
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens to this if the command exits before this is finished? Should we defer waiting for this to finish or something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Flag guarding is a good idea. I realized we will have to flag guard in other places as well.
About command exiting before this is finished, can potentially cause issues. We will have to fool proof OpenAPI cache reading/writing logic (basically making them idempotent in case of errors). For ex. we may fail while updating the cache (can happen in this case if we don't wait or crash in middle). Will discuss with Antoine about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where does the result of this function go? Why is this running asynchronously? How do we not care about the fetched resource?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is to trigger eager-loading of OpenAPI schema in cache. This is running asynchronously because we don't want to block the processing of Get command because OpenAPI cache may or may for the Get command processing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It at least deserves a comment.
// default specification to print this resource type | ||
outputFormatFromOpenAPI := f.lookupDisplayColumnsFromOpenAPI(cmd, mapping) | ||
if outputFormatFromOpenAPI != "" { | ||
outputOpts = f.getOutputOptsFromOpenAPISpec(outputFormatFromOpenAPI) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this line be wrapped into: lookupDisplayColumnsFromOpenAPI
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved this piece of code inside RunGet in get.go because printerForMapping should not deal with the business logic of output format for a mapping. That details belongs in Get command handling.
About your comment, pl. take a look at the new code and see if that looks OK.
pkg/kubectl/cmd/util/printing.go
Outdated
@@ -162,6 +142,48 @@ func PrintResourceInfoForCommand(cmd *cobra.Command, info *resource.Info, f Fact | |||
return printer.PrintObj(info.Object, out) | |||
} | |||
|
|||
func extractOutputOptions(cmd *cobra.Command) *printers.OutputOptions { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
much better. add some documentation to the function before merge plz
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
pkg/printers/customcolumn.go
Outdated
@@ -153,6 +153,7 @@ type CustomColumnsPrinter struct { | |||
Columns []Column | |||
Decoder runtime.Decoder | |||
NoHeaders bool | |||
lastType reflect.Type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is this and why is it needed? (add comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added comment. lastType records the type of resource printed last. This is to avoid repeating headers while printing same types of resources. So header gets printed only when type changes.
generally looks good. will want to add some tests. |
/assign mengqiy |
76904f0
to
3ce6b91
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the review @pwittrock . Addressed the comments. PTAL.
pkg/printers/customcolumn.go
Outdated
@@ -153,6 +153,7 @@ type CustomColumnsPrinter struct { | |||
Columns []Column | |||
Decoder runtime.Decoder | |||
NoHeaders bool | |||
lastType reflect.Type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added comment. lastType records the type of resource printed last. This is to avoid repeating headers while printing same types of resources. So header gets printed only when type changes.
pkg/kubectl/cmd/util/printing.go
Outdated
@@ -162,6 +142,48 @@ func PrintResourceInfoForCommand(cmd *cobra.Command, info *resource.Info, f Fact | |||
return printer.PrintObj(info.Object, out) | |||
} | |||
|
|||
func extractOutputOptions(cmd *cobra.Command) *printers.OutputOptions { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
// default specification to print this resource type | ||
outputFormatFromOpenAPI := f.lookupDisplayColumnsFromOpenAPI(cmd, mapping) | ||
if outputFormatFromOpenAPI != "" { | ||
outputOpts = f.getOutputOptsFromOpenAPISpec(outputFormatFromOpenAPI) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved this piece of code inside RunGet in get.go because printerForMapping should not deal with the business logic of output format for a mapping. That details belongs in Get command handling.
About your comment, pl. take a look at the new code and see if that looks OK.
pkg/kubectl/cmd/get.go
Outdated
@@ -139,6 +139,8 @@ func NewCmdGet(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Comman | |||
// RunGet implements the generic Get command | |||
// TODO: convert all direct flag accessors to a struct and pass that instead of cmd | |||
func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args []string, options *GetOptions) error { | |||
go f.OpenAPISchema(cmdutil.GetOpenAPICacheDir(cmd)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Flag guarding is a good idea. I realized we will have to flag guard in other places as well.
About command exiting before this is finished, can potentially cause issues. We will have to fool proof OpenAPI cache reading/writing logic (basically making them idempotent in case of errors). For ex. we may fail while updating the cache (can happen in this case if we don't wait or crash in middle). Will discuss with Antoine about it.
pkg/api/v1/types.go
Outdated
@@ -2568,6 +2568,7 @@ type PodStatusResult struct { | |||
|
|||
// Pod is a collection of containers that can run on a host. This resource is created | |||
// by clients and scheduled onto hosts. | |||
// +k8s:openapi-gen=x-kubernetes-print-columns:custom-columns=NAME:.metadata.name,RSRC:.metadata.resourceVersion |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, took it out.
pkg/kubectl/cmd/get.go
Outdated
@@ -501,7 +513,9 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [ | |||
} | |||
continue | |||
} | |||
if err := printer.PrintObj(decodedObj, w); err != nil { | |||
// TODO: understand if passing original is safe here |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should resolve this TODO or at least make it more specific before merging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I am working on it.
pkg/kubectl/cmd/get.go
Outdated
} | ||
parts := strings.SplitN(columnStr, "=", 2) | ||
if len(parts) < 2 { | ||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be returning (opts *OutputOptions, ok bool)
in accordance with Golang style guides.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Thanks for the suggestion.
pkg/printers/interface.go
Outdated
|
||
// OutputOptions represents resource output options which is used to generate a resource printer. | ||
type OutputOptions struct { | ||
FmtType string // e.g. json, yaml, template, jsonpath etc. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this comment should point where I can find the actual list of possible values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. Unfortunately, these are not defined as constant types in the code. For now, I have mentioned the filename where the supported format types are listed inside a function. I would like to make a separate change for defining these valid format types as constants.
pkg/kubectl/cmd/util/printing.go
Outdated
allowMissingTemplateKeys := false | ||
if cmd.Flags().Lookup("allow-missing-template-keys") != nil { | ||
allowMissingTemplateKeys = GetFlagBool(cmd, "allow-missing-template-keys") | ||
} | ||
printer, generic, err := printers.GetStandardPrinter( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can simplify the signature of GetStandardPrinter()
by passing in outputOptions
instead of outputFormat, templateFile,allowMissingTemplateKeys
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Thanks for the suggestion.
pkg/kubectl/cmd/get.go
Outdated
if err := printer.PrintObj(decodedObj, w); err != nil { | ||
// TODO: understand if passing original is safe here | ||
// if err := printer.PrintObj(decodedObj, w); err != nil { | ||
if err := printer.PrintObj(original, w); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should use decodedObj
, original may be an unversioned object.
Is there any issue when using decodedObj
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ran in to a few cases where using an output format like custom-column with spec "NAME:.metadata.name,RSRC:.metadata.resourceVersion" fails with errors saying "metadata" is missing in object when passed decoded object. It works fine with original object though.
I have to root cause it but I am getting lost in the decoding function. There is some magic which I do not quite understand at this point.
3ce6b91
to
b84cccc
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed comments and also updated the PR. PTAL.
pkg/kubectl/cmd/get.go
Outdated
@@ -139,6 +139,8 @@ func NewCmdGet(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Comman | |||
// RunGet implements the generic Get command | |||
// TODO: convert all direct flag accessors to a struct and pass that instead of cmd | |||
func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args []string, options *GetOptions) error { | |||
go f.OpenAPISchema(cmdutil.GetOpenAPICacheDir(cmd)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is to trigger eager-loading of OpenAPI schema in cache. This is running asynchronously because we don't want to block the processing of Get command because OpenAPI cache may or may for the Get command processing.
pkg/kubectl/cmd/get.go
Outdated
@@ -501,7 +513,9 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [ | |||
} | |||
continue | |||
} | |||
if err := printer.PrintObj(decodedObj, w); err != nil { | |||
// TODO: understand if passing original is safe here |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I am working on it.
pkg/kubectl/cmd/get.go
Outdated
if err := printer.PrintObj(decodedObj, w); err != nil { | ||
// TODO: understand if passing original is safe here | ||
// if err := printer.PrintObj(decodedObj, w); err != nil { | ||
if err := printer.PrintObj(original, w); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ran in to a few cases where using an output format like custom-column with spec "NAME:.metadata.name,RSRC:.metadata.resourceVersion" fails with errors saying "metadata" is missing in object when passed decoded object. It works fine with original object though.
I have to root cause it but I am getting lost in the decoding function. There is some magic which I do not quite understand at this point.
pkg/kubectl/cmd/get.go
Outdated
} | ||
parts := strings.SplitN(columnStr, "=", 2) | ||
if len(parts) < 2 { | ||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Thanks for the suggestion.
pkg/kubectl/cmd/util/printing.go
Outdated
allowMissingTemplateKeys := false | ||
if cmd.Flags().Lookup("allow-missing-template-keys") != nil { | ||
allowMissingTemplateKeys = GetFlagBool(cmd, "allow-missing-template-keys") | ||
} | ||
printer, generic, err := printers.GetStandardPrinter( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Thanks for the suggestion.
pkg/printers/interface.go
Outdated
|
||
// OutputOptions represents resource output options which is used to generate a resource printer. | ||
type OutputOptions struct { | ||
FmtType string // e.g. json, yaml, template, jsonpath etc. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. Unfortunately, these are not defined as constant types in the code. For now, I have mentioned the filename where the supported format types are listed inside a function. I would like to make a separate change for defining these valid format types as constants.
7c13dce
to
0e83d2a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed comments and updated the PR with additional comments. @pwittrock @mengqiy PTAL.
Um, given how this overlaps with server side get, I'm not sure I approve this. |
I do not want to add this to the client in 1.7. I want this to be on the server side. If we add this to the client, we'll just remove it in 1.8. What's the point of that? |
How did this get into the queue without the discussion resolution from the original proposal, saying that this is moving to the server. |
My primary concern is that this is moving to the server in 1.8, so this flag would be removed and no one would every specify it. So given that, if the desire to get something in for service catalog is very high, this needs to be an |
f597694
to
3930410
Compare
@smarterclayton I have updated the PR and renamed the flag to '--experimental-use-openapi-print-columns'. Can you pl. take a look and remove "do-not-merge" label. Lets re-evaluate if we want to deprecate or remove this functionality from kubectl when we move this logic to server side in 1.8. |
@smarterclayton Please refer to the email thread "get consensus on displaying resources - sig-apimachinery / sig-cli" (sent April 17). There you requested that we get together quickly over VC and resolve the discussion since it had been languishing. The consensus was that while there was some overlap in the 2 solutions, they were not mutually exclusive. One of the artifacts from that discussion was - should clients be able to print an object they have without making a request to the server. e.g. does a Java client that wants to print an object it already fetch need to make a second request to the server to display the object? Also how can clients display object configuration for resources defined locally or deleted from the server? We agreed that it would be useful for clients to have some notion for how to print resources without a server roundtrip. |
Making the flag experimental is good idea and we should do that. I would also make it deprecated so it is hidden. |
Ok, I vaguely recall us saying:
I had assumed that when the rest of the server side get plumbing went in, there would be no need for the flag when offline (since we would simply determine that the object was unrecognized, make a best effort pass to get the open api spec, and then print). The rename to "experimental" satisfies my concerns about the public API shape, objection withdrawn with that change. For 1.8, I'd expect for us to remove the flag and do the best effort fetch alongside the server side fetch attempt. |
Get command now uses metadata x-kubernetes-print-columns, if present, in Openapi schema to format output for a resource. This functionality is guarded by a boolean flag 'use-openapi-print-columns'.
3930410
to
f768a63
Compare
Thanks @smarterclayton |
@k8s-bot pull-kubernetes-bazel test this |
@smarterclayton SGTM. Yes, this will be a best effort fetch and very small and fast in 1.8 (when using the zipped binary proto + cache). Thanks. |
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: droot, fabianofranz, pwittrock, wojtek-t Associated issue: 22 The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these OWNERS Files:
You can indicate your approval by writing |
@k8s-bot test this [submit-queue is verifying that this PR is safe to merge] |
Automatic merge from submit-queue (batch tested with PRs 46235, 44786, 46833, 46756, 46669) |
@droot: The following tests failed, say
Full PR test history. Your PR dashboard. Please help us cut down on flakes by linking to an open issue when you hit one in your PR. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
Why did we introduce OutputOptions instead of adding those fields to PrintOptions? I don't see anything special about them that justifies a separate object. If there's no reason to have it separate, I'm going to move it into print options. |
@smarterclayton I think the main distinction is that OutputOptions is used to determine a printer type to use while PrintOptions are simply args to a given Printer to format the output. |
What this PR does / why we need it:
Kubectl Get command now uses metadata 'x-kubernetes-print-column' from Openapi schema to display a resource. This is to enable richer experience for non-compiled types (like service catalog API resources) in Kubectl. This functionality is currently guarded by a boolean flag "use-openapi-print-columns".
Which issue this PR fixes (optional, in
fixes #<issue number>(, fixes #<issue_number>, ...)
format, will close that issue when PR gets merged): fixes #fixes kubernetes/kubectl#22
Special notes for your reviewer:
Release note: