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

Smarter generic getters and describers #44222

Conversation

fabianofranz
Copy link
Contributor

@fabianofranz fabianofranz commented Apr 7, 2017

Makes printers and describers smarter for generic resources.

This traverses unstructured objects and prints their attributes for generic resources (TPR, federated API, etc) in kubectl get and kubectl describe. Makes use of the object's field names to come up with a best guess for describer labels and get headers, and field value types to understand how to better print it, indent, etc.

A nice intermediate solution while we don't have get and describe extensions.

Examples:

$ kubectl get serviceclasses
NAME                    KIND                                          BINDABLE   BROKER NAME   OSB GUID
user-provided-service   ServiceClass.v1alpha1.servicecatalog.k8s.io   false      ups-broker    4f6e6cf6-ffdd-425f-a2c7-3c9258ad2468
$ kubectl describe serviceclasses/user-provided-service
Name:		user-provided-service
Namespace:	
Labels:		<none>
Annotations:	FOO=BAR
		openshift.io/deployment.phase=test
OSB Metadata:	<nil>
Kind:		ServiceClass
Metadata:
  Self Link:		/apis/servicecatalog.k8s.io/v1alpha1/serviceclassesuser-provided-service
  UID:			1509bd96-1b05-11e7-98bd-0242ac110006
  Resource Version:	256
  Creation Timestamp:	2017-04-06T20:10:29Z
Broker Name:		ups-broker
Bindable:		false
Plan Updatable:		false
OSB GUID:		4f6e6cf6-ffdd-425f-a2c7-3c9258ad2468
API Version:		servicecatalog.k8s.io/v1alpha1
Plans:
  Name:		default
  OSB GUID:	86064792-7ea2-467b-af93-ac9694d96d52
  OSB Free:	true
  OSB Metadata:	<nil>
Events:		<none>

Release note:

Improved output on 'kubectl get' and 'kubectl describe' for generic objects.

PTAL @pmorie @pwittrock @kubernetes/sig-cli-pr-reviews

@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Apr 7, 2017
@k8s-reviewable
Copy link

This change is Reviewable

@k8s-github-robot k8s-github-robot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. release-note Denotes a PR that will be considered when it comes time to generate release notes. labels Apr 7, 2017
@fabianofranz
Copy link
Contributor Author

Also @liggitt since you wrote the previous version.

@fabianofranz fabianofranz force-pushed the better_generic_getters_and_describers branch from 29b6665 to 8bfe8d3 Compare April 7, 2017 20:37
@fabianofranz
Copy link
Contributor Author

@k8s-bot gci gce e2e test this

@fabianofranz fabianofranz changed the title Better generic getters and describers Smarter generic getters and describers Apr 7, 2017
@pmorie
Copy link
Member

pmorie commented Apr 8, 2017

I'm extremely interested in this PR for service-catalog, just for the record

@fabianofranz
Copy link
Contributor Author

fyi @jwforres

@ericchiang
Copy link
Contributor

I'm assigned but pretty unfamiliar with this code. Maybe someone else would be a better reviewer?

@pwittrock
Copy link
Member

@fabianofranz Does this print all the fields, or how does it decide which ones to print?

@k8s-github-robot k8s-github-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Apr 10, 2017
@fabianofranz
Copy link
Contributor Author

@pwittrock Current rules are

  • describe prints all fields, and knows the field levels (for indentation) based on the field type (e.g. it's a slice or map inside another map then it's one level below, etc)
  • get first calculates how many columns are left to be used by discovered fields (depending on the number of columns already taken by --show-labels, --label-columns, etc) and fills those "n" columns left with the first "n" top-level fields not yet printed, in lexical order.

@fabianofranz fabianofranz force-pushed the better_generic_getters_and_describers branch from 8bfe8d3 to c34168f Compare April 11, 2017 00:56
@k8s-github-robot k8s-github-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Apr 11, 2017
@pwittrock
Copy link
Member

first "n" top-level fields not yet printed

What are top-level fields? Are those the first leaf nodes encountered in a breadth-first search? Does it include both spec and status, or just spec?

@fabianofranz
Copy link
Contributor Author

@pwittrock Sorry, yeah I meant leaf nodes at the tree root (so in a BFS), taken in lexical order.

Meaning, in the yam below it would print:

  • first 2 columns with the name and apiVersion+kind (these are hardcoded and always printed)
  • then 3 columns chosen from leaf nodes at root in a BFS, in lexical order: bindable, brokerName, osbGuid.
apiVersion: servicecatalog.k8s.io/v1alpha1
kind: ServiceClass
metadata:
  creationTimestamp: 2017-03-03T04:11:17Z
  name: user-provided-service
  resourceVersion: "7"
  selfLink: /apis/servicecatalog.k8s.io/v1alpha1/serviceclassesuser-provided-service
  uid: 72fef5ce-ffc7-11e6-b111-0242ac110005
brokerName: ups-broker
osbGuid: 4F6E6CF6-FFDD-425F-A2C7-3C9258AD2468
bindable: false
planUpdatable: false
plans:
- name: default
  osbFree: true
  osbGuid: 86064792-7ea2-467b-af93-ac9694d96d52

If spec and status have children (which is the case in "Broker" objects in the svc catalog, for example) they would never be printed in this generic rule for get.

This is the current state, but I could improve if it makes sense, like trying to take something from the children of spec and status if they are present. The only concern is to try to be generic and not add too much special purpose code.

@pwittrock
Copy link
Member

@fabianofranz I agree keeping it as simple as possible for as long as possible is best. Spec and Status are relatively standard, so it is too bad this won't work well for them, but I think that is ok for now.

if events != nil {
DescribeEvents(events, w)
}
return nil
})
}

func printUnstructuredContent(w PrefixWriter, level int, content map[string]interface{}, skipPrefix string, skip ...string) {
for field, value := range content {
Copy link
Member

@pwittrock pwittrock Apr 11, 2017

Choose a reason for hiding this comment

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

Do the values always appear in the same order? If not, can we make them consistent?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not in describe, but if we want it consistent I can use the same strategy used in get (an ordered slice of the map keys).

Copy link
Member

Choose a reason for hiding this comment

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

If you don't mind, lets do that. I think it would be frustrating if you run the same describe command 2x and the output is reordered. Esp if you are trying to debug - e.g. describe, look for field, do something, describe, look for field (where did it go?)

expected: "\n Creation Timestamp:\t2017-04-01T00:00:00Z\n",
},
{
expected: "\nItems:\n Item Bool:\ttrue\n",
Copy link
Member

Choose a reason for hiding this comment

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

why is itemInt missing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's not missing, I just didn't care to test it. I'll add.

var discoveredFieldNames []string // we want it predictable so this will be used to sort
ignoreIfDiscovered := []string{"kind", "apiVersion"} // these are already covered
for field, value := range content {
if slice.ContainsString(ignoreIfDiscovered, field, nil) {
Copy link
Member

Choose a reason for hiding this comment

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

Does this always discover the same fields? Is the order always the same?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, here in get the order is always the same so it will always discover the same fields.

@fabianofranz fabianofranz force-pushed the better_generic_getters_and_describers branch from c34168f to 5062f1f Compare April 11, 2017 21:24
@fabianofranz
Copy link
Contributor Author

@pwittrock thanks for the review, comments addressed.

@@ -201,8 +204,51 @@ func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) er
}

if _, err := meta.Accessor(obj); err == nil {
// we don't recognize this type, but we can still attempt to print some reasonable information about.
Copy link
Member

Choose a reason for hiding this comment

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

Is there a test for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added some in humanreadable_test.go.

printUnstructuredContent(w, LEVEL_0, obj.UnstructuredContent(), "", ".dummy1", ".metadata.dummy3")
output := out.String()

for _, test := range testCases {
Copy link
Member

Choose a reason for hiding this comment

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

Now that the order is consistent, we should make sure we test the ordering. Doing so should simplify this check.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@fabianofranz fabianofranz force-pushed the better_generic_getters_and_describers branch from 5062f1f to ccf8e6a Compare April 13, 2017 01:14
@k8s-github-robot k8s-github-robot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Apr 13, 2017
@fabianofranz
Copy link
Contributor Author

@pwittrock comments addressed.

@fabianofranz fabianofranz force-pushed the better_generic_getters_and_describers branch from ccf8e6a to b276f17 Compare April 17, 2017 18:43
@@ -49,6 +49,20 @@ func ShuffleStrings(s []string) []string {
return shuffled
}

// ContainsString checks if a given slice of strings contains the provided string.
// If a modifier func is provided, it is called with the slice item before the comparation.
func ContainsString(slice []string, s string, modifier func(s string) string) bool {
Copy link
Member

Choose a reason for hiding this comment

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

Is this still used?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, still in a few other places.

@pwittrock
Copy link
Member

/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Apr 17, 2017
@fabianofranz
Copy link
Contributor Author

Needs approval, @smarterclayton mind taking a look?

@fabianofranz
Copy link
Contributor Author

Needs approval, @smarterclayton mind taking a look?

Or @bgrant0607

@smarterclayton
Copy link
Contributor

Approve but one minor nit. If you want to do in a follow up that's fine

/approve

@k8s-github-robot
Copy link

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: fabianofranz, pwittrock, smarterclayton

Needs approval from an approver in each of these OWNERS Files:

You can indicate your approval by writing /approve in a comment
You can cancel your approval by writing /approve cancel in a comment

@k8s-github-robot k8s-github-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Apr 18, 2017
@fabianofranz
Copy link
Contributor Author

@k8s-bot cvm gce e2e test this

@k8s-github-robot
Copy link

Automatic merge from submit-queue (batch tested with PRs 44222, 44614, 44292, 44638)

@k8s-github-robot k8s-github-robot merged commit 409b0a6 into kubernetes:master Apr 19, 2017
@smarterclayton
Copy link
Contributor

In 1.8 we'll have most of the generic printing on the server in place. Any objections to taking this specific part out and relying on that? In general, any object will return name and age, CRD can return based on their openapi extensions, and extension APIs can return full structured fields.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm "Looks good to me", indicates that a PR is ready to be merged. release-note Denotes a PR that will be considered when it comes time to generate release notes. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants