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

have basic kubectl crud agnostic of registered types #36085

Merged
merged 3 commits into from Nov 4, 2016

Conversation

deads2k
Copy link
Contributor

@deads2k deads2k commented Nov 2, 2016

Makes kubectl get agnostic to scheme (baked in API types). This means that it will now work against generic API servers that are "kube shaped".

This is similar to the work done for kubectl create last release. I'll split out the smaller command. kubectl get looks a lot different, but this eliminates all special casing for TPR in those cases.

@fabianofranz


This change is Reviewable

@@ -39,6 +39,14 @@ func GetItemsPtr(list runtime.Object) (interface{}, error) {
if err != nil {
return nil, err
}

// if we're a runtime.Unstructured, check to see if we have an `items` key
if unstructured, ok := list.(*runtime.Unstructured); ok {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@smarterclayton api/meta changes to more cleanly handle the way the unstructured decoder works. It doesn't make an UnstructuredList by default, which is annoying.

Copy link
Contributor

Choose a reason for hiding this comment

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

This needs a test.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixing

@@ -117,6 +125,13 @@ func SetList(list runtime.Object, objects []runtime.Object) error {
slice := reflect.MakeSlice(items.Type(), len(objects), len(objects))
for i := range objects {
dest := slice.Index(i)

// check to see if you're directly assignable
if reflect.TypeOf(objects[i]).AssignableTo(dest.Type()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

When you pass an UnstructuredList into this method, you don't want to dereference the items like you do in EnforcePtr below.

Copy link
Contributor

Choose a reason for hiding this comment

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

This needs a test.

Copy link
Contributor

@sttts sttts Nov 4, 2016

Choose a reason for hiding this comment

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

easier: if dest.Kind() == reflect.Ptr

Copy link
Contributor Author

Choose a reason for hiding this comment

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

easier: if dest.Kind() == reflect.Ptr

I prefer this express and I think this check is slightly different.

return err
// take the filtered items and create a new list for display
list := &runtime.UnstructuredList{
Object: map[string]interface{}{
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This looks nasty, but it serializes correctly and v1.List does not serialize correctly. :(

Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't this lose resourceVersion?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Doesn't this lose resourceVersion?

Will fix.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, turns out HEAD doesn't preserve the resourceversion.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

or selflink

@@ -48,28 +48,6 @@ func makeImageList(spec *api.PodSpec) string {
return strings.Join(listOfImages(spec), ",")
}

func NewThirdPartyResourceMapper(gvs []unversioned.GroupVersion, gvks []unversioned.GroupVersionKind) (meta.RESTMapper, error) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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


// check if the object is unstructured. If so, let's attempt to convert it to a type we can understand before
// trying to print, since the printers are keyed by type. This is extremely expensive.
if objBytes, err := runtime.Encode(api.Codecs.LegacyCodec(), obj); err == nil {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@smarterclayton will you let me get away with this to have the capability? It only hurts kubectl.

Copy link
Contributor

Choose a reason for hiding this comment

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

can you not check whether this is unstructured first? Or is it now always unstructured coming in to here? Not sure why you have to blanket encode?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

can you not check whether this is unstructured first? Or is it now always unstructured coming in to here? Not sure why you have to blanket encode?

I think its almost always unstructured, but I'm not certain enough to assume it.

I will gate on unstructured and unknown to start.

case reflect.Interface:
switch itype := i.Interface().(type) {
case uint8:
if jtype, ok := j.Interface().(uint8); ok {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Check precedence carefully through here.

@k8s-github-robot k8s-github-robot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. release-note-label-needed labels Nov 2, 2016
@k8s-ci-robot
Copy link
Contributor

Jenkins GCE Node e2e failed for commit 90d9fa4. Full PR test history.

The magic incantation to run this job again is @k8s-bot node e2e test this. Please help us cut down flakes by linking to an open flake issue when you hit one in your PR.

@deads2k deads2k added this to the v1.5 milestone Nov 3, 2016
@deads2k deads2k changed the title [WIP] have basic kubectl crud agnostic of registered types have basic kubectl crud agnostic of registered types Nov 3, 2016
@deads2k deads2k assigned smarterclayton and unassigned janetkuo Nov 3, 2016
@deads2k
Copy link
Contributor Author

deads2k commented Nov 3, 2016

This gets pretty deep into scheme/codec stuff. Moving to @smarterclayton.

This is ready for review.

// 2. if the specified output-version is a recognized, valid Scheme, then the list should use that scheme, and otherwise it will default to the client version, registered.GroupOrDie(api.GroupName).GroupVersion.String() in this test;
// 3a. if the specified output-version is a recognized, valid Scheme, in which the requested object (replicationcontroller) can be represented, then the object should be returned using that version;
// 3b. otherwise if the specified output-version is unrecognized, but the requested object (replicationcontroller) is recognized by the client's codec, then it will be converted to the client version, registered.GroupOrDie(api.GroupName).GroupVersion.String() in this test.
func TestGetUnknownSchemaObjectListGeneric(t *testing.T) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We no longer do anything with --output-version. I'd like to leave disconnecting/doc-ing that to a followup, but this this makes us generic for basic CRUD.

t.Fatal(actual)
}
for i, obj := range actual {
actualObj, err := runtime.Decode(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

encodes the unstructured (or whatever) and then decodes that back into internal for the comparison which this package is using.

@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 Nov 3, 2016
@@ -2447,6 +2533,20 @@ func (j *JSONPathPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
}
}

if unknown, ok := obj.(*runtime.Unknown); ok {
Copy link
Contributor

Choose a reason for hiding this comment

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

twitch

Copy link
Contributor Author

Choose a reason for hiding this comment

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

twitch

Found inside a list somewhere I think. Given the way this code works, the change here is actually correct. Well, more correct than it was before. The whole thing needs some rethinking.

@@ -2256,9 +2265,78 @@ func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) er
}
return resultValue.Interface().(error)
}

// we don't recognize this type, but we can still attempt to print some reasonable information about.
unstructured, ok := obj.(*runtime.Unstructured)
Copy link
Contributor

Choose a reason for hiding this comment

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

Keep in mind unstructured really is "generic API v1" when used this way (with accessors). So this code only works until someone changes metadata and then is horribly broken again. Which is not inconsistent with what we've said up till now, that we won't change v1 metadata until we have server side transformation (we can't, effectively).

@k8s-ci-robot
Copy link
Contributor

Jenkins GCE etcd3 e2e failed for commit 29d2a1d. Full PR test history.

The magic incantation to run this job again is @k8s-bot gce etcd3 e2e test this. Please help us cut down flakes by linking to an open flake issue when you hit one in your PR.

@k8s-ci-robot
Copy link
Contributor

Jenkins GCE e2e failed for commit 29d2a1d. Full PR test history.

The magic incantation to run this job again is @k8s-bot cvm gce e2e test this. Please help us cut down flakes by linking to an open flake issue when you hit one in your PR.

@k8s-ci-robot
Copy link
Contributor

Jenkins GCI GCE e2e failed for commit 29d2a1d. Full PR test history.

The magic incantation to run this job again is @k8s-bot gci gce e2e test this. Please help us cut down flakes by linking to an open flake issue when you hit one in your PR.

@deads2k
Copy link
Contributor Author

deads2k commented Nov 3, 2016

comments addressed.

@deads2k deads2k added release-note Denotes a PR that will be considered when it comes time to generate release notes. and removed release-note-label-needed labels Nov 3, 2016
@deads2k deads2k added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Nov 4, 2016
@sttts
Copy link
Contributor

sttts commented Nov 4, 2016

Much better now without the patch to GetFieldsPtr.

@k8s-github-robot
Copy link

@k8s-bot test this [submit-queue is verifying that this PR is safe to merge]

@k8s-github-robot
Copy link

Automatic merge from submit-queue

@k8s-github-robot k8s-github-robot merged commit 5a2c473 into kubernetes:master Nov 4, 2016
@smarterclayton
Copy link
Contributor

Fixing the failures?

@deads2k
Copy link
Contributor Author

deads2k commented Nov 7, 2016

Fixing the failures?

which failures on what?

@mengqiy
Copy link
Member

mengqiy commented Nov 10, 2016

@deads2k I'm working on isssue #36007, which is forked from #35791.
In #35791, people have discussed that there is a problem related how we register TPR. But it seems that piece of code has been removed by this PR.
Maybe I miss something. In current codebase, it seems that only UnstructuredObject() register TPR, while Object() don't do that.

Why we only do that for UnstructuredObject()?

@deads2k
Copy link
Contributor Author

deads2k commented Nov 10, 2016

@deads2k I'm working on isssue #36007, which is forked from #35791.
In #35791, people have discussed that there is a problem related how we register TPR. But it seems that piece of code has been removed by this PR.
Maybe I miss something. In current codebase, it seems that only UnstructuredObject() register TPR, while Object() don't do that.

Why we only do that for UnstructuredObject()?

As I recall, there's something wrong with the implementation of --validate that doesn't properly handle missing swagger so someone built a side-signal way to skip it instead of handling the case cleanly. It's been a while since I looked though.

@pwittrock
Copy link
Member

@deads2k

It looks like this changed the kubectl -o jsonpath behavior to now fail if it cannot find the field. We should make sure the release notes are clear about this as it could cause scripts that were depending on the old behavior to fail (e.g. if the script checks if the field exists by querying for it and looks for an empty value)

@smarterclayton
Copy link
Contributor

Hrm - that may have been something even older that I did in 1.4.

@pwittrock
Copy link
Member

@smarterclayton I suspect it is this PR. 1.4 has the "return empty" behavior, and the new behavior actually breaks version skew tests. This PR updated a kubectl.go e2e test to work around the change in behavior, but it is failing when running the old tests against a new client/server.

We could potentially revert to the old behavior by using the work you implemented in #31714

@pwittrock
Copy link
Member

@bgrant0607 FYI

I am not sure if we consider this a api compatibility breaking change. The json path doc does explicitly state what the behavior is when the field is not present.

1.4 behavior:

  • If the field is present in the struct, but missing from the JSON, return empty string
  • If the field is missing from the struct, exit 1 with an error

1.5 behavior:

  • If the field is missing from the JSON, exit 1 with an error

I have not been able to find a record of the original intention when the field is missing from the JSON. It would probably be best to support either behavior by exposing a flag to control the knobs introduced in #31714. I am not sure it is worth the risk introduced to get that into 1.5 though.

@bgrant0607
Copy link
Member

@pwittrock @smarterclayton Is there a reason why we wouldn't make the 1.4 behavior the default?

@pwittrock
Copy link
Member

Making the 1.4 behavior the default makes the most sense to me. My biggest concern would be around getting the change cherrypicked and tested in time for the 1.5 release. Today I will look into if this can be done as a simple change.

@pwittrock
Copy link
Member

Created issue #37991 for tracking

@pwittrock
Copy link
Member

@smarterclayton Looking more closely at the PR, you are right that it doesn't seem like this should have caused the change in behavior we are seeing. Still investigating the root cause.

@smarterclayton
Copy link
Contributor

smarterclayton commented Dec 3, 2016 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lgtm "Looks good to me", indicates that a PR is ready to be merged. priority/backlog Higher priority than priority/awaiting-more-evidence. 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.

None yet