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

kubectl get and kubectl describe extensions #308

Merged
merged 6 commits into from
Jun 1, 2017
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
# Provide open-api extensions for kubectl get / kubectl describe columns

Status: Pending

Version: Alpha

## Motivation

`kubectl get` and `kubectl describe` do not provide a rich experience
for resources retrieved through federated apiservers and types not
compiled into the kubectl binary. Kubectl should support printing
columns configured per-type without having the types compiled in.

## Proposal

Allow the apiserver to define the type specific columns that will be
printed using the open-api swagger.json spec already fetched by kubectl.
This provides a limited describe to only print out fields on the object
and related events.
Copy link
Member

Choose a reason for hiding this comment

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

how do you envision this interacting with kubernetes/kubernetes#33900 ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good question. I guess I don't fully understand how that proposal is intended to interact with the swagger schema. I suspect that this proposal is a much lighter version of the sub-pieces of kubernetes/kubernetes#33900 dealing with getting metadata about objects.


**Note:** This solution will only work for types compiled into the apiserver
Copy link
Contributor

Choose a reason for hiding this comment

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

include federated apiservers?

providing the open-api swagger.json to kubectl. This solution will
not work for TPR, though TPR could possibly be solved in a similar
way by apply an annotation with the same key / value to the TPR.

## User Experience

### Use Cases

- As a user, when I run `kubectl get` on sig-service-catalog resources
defined in a federated apiserver, I want to see more than just the
name and the type of the resource.
- As a user, when I run `kubectl describe` on sig-service-catalog
resources defined in a federated apiserver, I want the command
to succeed, and to see events for the resource along with important
fields of the resource.

## Implementation

Define the open-api extensions `x-kubernetes-kubectl-get-columns` and
`x-kubernetes-kubectl-describe-columns`. These extensions have a
string value containing the columns to be printed by kubectl. The
string format is the same as the `--custom-columns` for `kubectl get`.
Copy link
Member

Choose a reason for hiding this comment

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

we don't have openapi schemas for third party resources... do we anticipate adding that in the future?

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for pointing that out. I just added some comments about this. The short answer is - Yes I would like to add support for TPR. My initial thought is that this can be done through an annotation on the TPR. If we implement this proposal by hooking into the RestMapper, supporting TPR should be relatively clean. If we hack this proposal in, then it would be less clean.


### Apiserver

- Populate the open-api extension value for resource types.

This is done by hardcoding the extension for types compiled into
the api server. As such this is only a solution for types
implemented using federated apiservers.

### Kubectl

Overview:

- In `kubectl get` use the `x-kubernetes-kubectl-get-columns` value
when printing an object iff 1) it is defined and 2) the output type
is "" (empty string) or "wide".

- In `kubectl describe` use the `x-kubernetes-kubectl-describe-columns` value
when printing an object iff 1) it is defined


#### Option 1: Re-parse the open-api swagger.json in a kubectl library

Re-parse the open-api swagger.json schema and build a map of group version kind -> columns
parsed from the schema. For this would look similar to validation/schema.go

In get.go and describe.go: After fetching the "Infos" from the
resource builder, lookup the group version kind from the populated map.

**Pros:**
- Simple and straightforward solution
- Scope of impacted Kubernetes components is minimal
- Doable in 1.6

**Cons:**
- Hacky solution
- Can not be cleanly extended to support TPR

#### Option 2: Modify api-machinery RestMapper

Modify the api-machinery RestMapper to parse extensions prefixed
with `x-kubernetes` and include them in the *RestMapping* used by the resource builder.

```go
type RESTMapping struct {
// Resource is a string representing the name of this resource as a REST client would see it
Resource string

GroupVersionKind schema.GroupVersionKind

// Scope contains the information needed to deal with REST Resources that are in a resource hierarchy
Scope RESTScope

runtime.ObjectConvertor
MetadataAccessor

// Extensions
ApiExtensions ApiExtensions
}

type ApiExtensions struct {
Extensions map[string]interface{}
}
```

The tags would then be easily accessible from the kubectl get / describe
functions through: `resource.Builder -> Infos -> Mapping -> DisplayOptions`

**Pros:**
- Clean + generalized solution
- The same strategy can be applied to support TPR
- Can support exposing future extensions such as patchStrategy and mergeKey
- Can be used by other clients / tools

**Cons:**
- Fields are only loosely tied to rest
- Complicated due to the broad scope and impact
- May not be doable in 1.6

#### Considerations

What should be used for oth an open-api extension columns tag AND a
compiled in printer exist for a type?

- Apiserver only provides `describe` for types that are never compiled in
- Compiled in `describe` is much more rich - aggregating data across many other types.
e.g. Node describe aggregating Pod data
- kubectl will not be able to provide any `describe` information for new types when version skewed against a newer server
- Always use the extensions if present
- Allows server to control columns. Adds new columns for types on old clients that maybe missing the columns.
- Always use the compiled in commands if present
- The compiled in `describe` is richer and provides aggregated information about many types.
- Always use the `get` extension if present. Always use the `describe` compiled in code if present.
- Inconsistent behavior across how extensions are handled

### Client/Server Backwards/Forwards compatibility

#### Newer client

Client doesn't find the open-api extensions. Fallback on 1.5 behavior.

In the future, this will provide stronger backwards / forwards compability
as it will allow clients to print objects

#### Newer server

Client doesn't respect open-api extensions. Uses 1.5 behavior.

## Alternatives considered

### Fork Kubectl and compile in go types

Fork kubectl and compile in the go types. Implement get / describe
for the new types in the forked version.

**Pros:** *This is what will happen for sig-service catalog if we take no action in 1.6*

**Cons:** Bad user experience. No clear solution for patching forked kubectl.
User has to use a separate kubectl binary per-apiserver. Bad president.

I really don't want this solution to be used.

### Kubectl describe fully implemented in the server

Implement a sub-resource "/describe" in the apiserver. This executes
the describe business logic for the object and returns either a string
or json blob for kubectl to print.

**Pros:** Higher fidelity. Can aggregate data and fetch other objects.

**Cons:** Higher complexity. Requires more api changes.

### Write per-type columns to kubectl.config or another local file

Support checking a local file containing per-type information including
the columns to print.

**Pros:** Simplest solution. Easy for user to override values.

**Cons:** Requires manual configuration on user side. Does not provide a consistent experience across clients.

### Write per-type go templates to kubectl.config or another local file

Support checking a local file containing per-type information including
the go template.

**Pros:** Higher fidelity. Easy for user to override values.

**Cons:** Higher complexity. Requires manual configuration on user side. Does not provide a consistent experience across clients.