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

thirdpartyresource add multiple version support #36977

Closed
wants to merge 1 commit into from

Conversation

adohe-zz
Copy link

@adohe-zz adohe-zz commented Nov 17, 2016

This change is Reviewable

// any versions the user provides take priority
priorities := m.KindPriority
if len(versions) > 0 {
priorities = make([]unversioned.GroupVersionKind, 0, len(m.KindPriority)+len(versions))
for _, version := range versions {
if strings.Count(version, "/") == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't look right. Doesn't ParseGroupVersion already do this? Also, open an issue to fix this method signature. Either it gets a version or a groupversion, but we shouldn't have strings floating around anymore.

Copy link
Author

@adohe-zz adohe-zz Nov 18, 2016

Choose a reason for hiding this comment

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

The problem with ParseGroupVersion is if version parameter doesn't match group/version, for example v2, it will return GroupVersion{"", "v2"} with empty group. And this is not correct if a TPR schema has multi versions: v1, v2, and user provides v2, this will fail to recognize. Why not use group field of groupkind?

Copy link
Member

Choose a reason for hiding this comment

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

v2 with empty group is not valid. All TPR would have somegroup/v2

Copy link
Author

Choose a reason for hiding this comment

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

the question is when version would be group/version or version when call restmapper?

Copy link
Author

Choose a reason for hiding this comment

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

@deads2k @liggitt I want to know why ParseGroupVersion use empty group when version is not group/version format, I think it should respect groupKind not use empty group.

Copy link
Contributor

Choose a reason for hiding this comment

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

@deads2k @liggitt I want to know why ParseGroupVersion use empty group when version is not group/version format, I think it should respect groupKind not use empty group.

versions should be just the version part. Group should come from the GroupKind.

Copy link
Author

Choose a reason for hiding this comment

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

I will open a separate issue to describe this.

@@ -108,6 +108,7 @@ func (a *APIInstaller) NewWebService() *restful.WebService {
mediaTypes, streamMediaTypes := mediaTypesForSerializer(a.group.Serializer)
ws.Produces(append(mediaTypes, streamMediaTypes...)...)
ws.ApiVersion(a.group.GroupVersion.String())
ws.SetDynamicRoutes(true)
Copy link
Contributor

Choose a reason for hiding this comment

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

This change isn't obvious to me. Why would make this the new default?

Copy link
Author

Choose a reason for hiding this comment

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

Given our failed TPR integration test for example, if we create two TPR schemas: foo.company.com and bar.company.com, both with v1, thirdparty server will create a WebService, but if we delete bar.company.com, thirdparty server does nothing. And of course we cannot remove the entire web service, but we can remove bar.company.com related routes, as for go-restful, if we don't enable dynamic routes, we are note allowed to remove these routes.

Copy link
Member

Choose a reason for hiding this comment

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

I'm wary of changes that affect things other than the TPR endpoints. What if we made the resource endpoint a nested web service? Those were allowed to be added/removed previously without this setting

Copy link
Author

Choose a reason for hiding this comment

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

@liggitt this attribute is just webservice level, which gives us chance to remove routes handler of a specific webservice. I am not quite clear what you mean nested web service were allowed to be removed, would you mind explain more?

Copy link
Contributor

Choose a reason for hiding this comment

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

@liggitt this attribute is just webservice level, which gives us chance to remove routes handler of a specific webservice. I am not quite clear what you mean nested web service were allowed to be removed, would you mind explain more?

Can you create a webservice with a narrower scope for each TPR group? This sort of change is why we're interested in breaking TPRs out of the main API server.

Copy link
Member

Choose a reason for hiding this comment

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

+1 for putting TPRs in a separate ws, so that there's no way of accidentally removing a route for a built-in API.

Copy link
Author

Choose a reason for hiding this comment

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

@lavalamp I will try to update this, but what I am really confused is whether I should go on this PR against current apiserver or I should start working on a add-on server?

Copy link
Contributor

Choose a reason for hiding this comment

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

@adohe is there already an addon server in developing status?

Copy link
Member

Choose a reason for hiding this comment

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

IMO it's not bad to make improvements to the existing TPR implementation. We won't be moving it this quarter, I'm pretty sure.

@@ -192,6 +193,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
if err != nil {
return nil, err
}
fmt.Printf("register resource handler for path: %s and the fqKind is: %v\n", path, fqKindToRegister)
Copy link
Contributor

Choose a reason for hiding this comment

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

debug

Copy link
Author

Choose a reason for hiding this comment

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

Done.

@@ -54,12 +54,14 @@ func (m *Mapper) InfoForData(data []byte, source string) (*Info, error) {
return nil, fmt.Errorf("unable to decode %q: %v", source, err)
}

fmt.Printf("info for data gvk is: %v\n", gvk)
Copy link
Contributor

Choose a reason for hiding this comment

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

debug

Copy link
Author

Choose a reason for hiding this comment

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

Done.

@k8s-github-robot k8s-github-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Nov 18, 2016
@k8s-github-robot k8s-github-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Nov 18, 2016
return false, nil
}
}
return true, nil
}

func (m *ThirdPartyResourceServer) removeThirdPartyStorage(path, resource string) error {
Copy link
Member

Choose a reason for hiding this comment

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

Can we change the signature so we get the info we need without string parsing?

Copy link
Author

Choose a reason for hiding this comment

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

how about change this to removeThirdPartyStorage(group, version, resource string), wdyt?

Copy link
Member

Choose a reason for hiding this comment

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

or gvr unversioned.GroupVersionResource

Copy link
Author

Choose a reason for hiding this comment

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

Done.

}

if ws != nil {
pattern := path + "/.*/" + resource + ".*"
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 the trailing .* needed

Copy link
Author

Choose a reason for hiding this comment

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

there should be some problem with this regexp, I am fixing it.

Copy link
Author

Choose a reason for hiding this comment

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

Done.

@k8s-github-robot k8s-github-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Nov 19, 2016
@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Nov 21, 2016
@k8s-github-robot k8s-github-robot added needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. and removed needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. labels Nov 21, 2016
@k8s-github-robot k8s-github-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Dec 1, 2016
@k8s-ci-robot
Copy link
Contributor

Jenkins GCE etcd3 e2e failed for commit 3d6a4c9. 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 Kubemark GCE e2e failed for commit 3d6a4c9. Full PR test history.

The magic incantation to run this job again is @k8s-bot kubemark 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 3d6a4c9. 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 GKE smoke e2e failed for commit 3d6a4c9. Full PR test history.

The magic incantation to run this job again is @k8s-bot gci gke 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 kops AWS e2e failed for commit 3d6a4c9. Full PR test history.

The magic incantation to run this job again is @k8s-bot kops aws 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 Node e2e failed for commit 3d6a4c9. 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.

@adohe-zz
Copy link
Author

I get some time to get this updated, and fix all tests failure. @deads2k @liggitt @smarterclayton please take a look, and give a deep review. I would like to get this merged and then go on with TPR finalizers.

@k8s-github-robot k8s-github-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Dec 14, 2016
@k8s-github-robot k8s-github-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Dec 14, 2016
@@ -76,19 +78,31 @@ func (t *ThirdPartyController) SyncResources() error {
}

func (t *ThirdPartyController) syncResourceList(list runtime.Object) error {
existing := sets.String{}
existing := map[metav1.GroupVersionResource]sets.Empty{}
Copy link
Contributor

Choose a reason for hiding this comment

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

map[]struct{}

Copy link
Author

Choose a reason for hiding this comment

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

Done.

switch list := list.(type) {
case *extensions.ThirdPartyResourceList:
// Loop across all schema objects for third party resources
for ix := range list.Items {
item := &list.Items[ix]
// extract the api group and resource kind from the schema
_, group, err := thirdpartyresourcedata.ExtractApiGroupAndKind(item)
kind, group, err := thirdpartyresourcedata.ExtractApiGroupAndKind(item)
Copy link
Contributor

Choose a reason for hiding this comment

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

Seems like this API should return GroupKind and GroupResource for you.

Copy link
Author

Choose a reason for hiding this comment

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

I will check this when I return from ooo.

Copy link
Author

Choose a reason for hiding this comment

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

maybe we can return GroupKind here, seems we cannot extract GroupResource from item, wdyt?

ListThirdPartyResources() []string
// List all currently installed third party resources, return
// collection of all groupVersionResource
ListThirdPartyResources() []metav1.GroupVersionResource
Copy link
Contributor

Choose a reason for hiding this comment

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

good change.

found = true
break
}
}
// not expected, delete the resource
if !found {
if err := t.master.RemoveThirdPartyResource(installedAPI); err != nil {
if err := t.master.RemoveThirdPartyResource(installedGvr); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

I see the fake for this changed, and the interface, but I can't seem to find where the actual impl changed.

Copy link
Contributor

Choose a reason for hiding this comment

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

nm, github helpfully hid the diff.

Copy link
Author

Choose a reason for hiding this comment

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

actually, the implementation changed a lot :)

@@ -84,12 +88,25 @@ func NewThirdPartyResourceServer(genericAPIServer *genericapiserver.GenericAPISe
return ret
}

// thirdPartyEntry combines objects storage and API group into one struct
type thirdPartyGroup struct {
versionedEntry map[string]*thirdPartyEntry
Copy link
Contributor

Choose a reason for hiding this comment

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

document the key for this map. Version?

Copy link
Author

Choose a reason for hiding this comment

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

Done.

group metav1.APIGroup
}

// thirdPartyEntry combines objects storage into one struct
// for easy lookup.
type thirdPartyEntry struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

tprVersionStorage?

Copy link
Author

Choose a reason for hiding this comment

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

good suggestion :)


func (g *thirdPartyGroup) versionInstalled(version string) bool {
for installedVersion := range g.versionedEntry {
if reflect.DeepEqual(version, installedVersion) {
Copy link
Contributor

Choose a reason for hiding this comment

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

deep equal on string is weird.

Copy link
Author

Choose a reason for hiding this comment

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

Done.

// map from api path to a tuple of (storage for the objects, APIGroup)
thirdPartyResources map[string]*thirdPartyEntry
// map from api path to a tuple of (versioned storage for the objects, APIGroup)
thirdPartyResources map[string]*thirdPartyGroup
Copy link
Contributor

Choose a reason for hiding this comment

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

keying by path is weird. Why not key by group name and have the tprGroup hold a path value?

return false, nil
}
plural, _ := meta.KindToResource(schema.GroupVersionKind{
Group: group,
Version: rsrc.Versions[0].Name,
Kind: kind,
})
_, found := entry.storage[plural.Resource]
return found, nil
for _, version := range rsrc.Versions {
Copy link
Contributor

Choose a reason for hiding this comment

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

Please rename rsrc to tpr. I keep having to look up what this is.

Copy link
Author

Choose a reason for hiding this comment

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

Done.

return true
}
}
return false
}

// HasThirdPartyResource returns true if a particular third party resource currently installed.
Copy link
Contributor

Choose a reason for hiding this comment

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

if its installed in one version and not another, what's the behavior?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think I actually expect this to take a GVR. That would make it unambiguous.

Copy link
Author

Choose a reason for hiding this comment

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

if we change HasThirdPartyResource(rsrc) to HasThirdPartyResource(gvr), then I would suppose we should make the same change to InstallThirdPartyResource, which means we should update the thirdparty controller. wdyt?

Copy link
Author

Choose a reason for hiding this comment

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

one TPR schema could define multiple GroupVersionResource identified resource, so update method to accept gvr parameter could make sense.

if !found {
return nil
}
storage, found := entry.storage[resource]
storage, found := entry.storage[gvr.Resource]
if !found {
return nil
}
if err := m.removeAllThirdPartyResources(storage); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this method just misnamed? Is it deleting a single storage?

Copy link
Author

Choose a reason for hiding this comment

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

actually it is deleting all TPR data in this storage registry.

}

if ws != nil {
pattern := path + "/.*" + gvr.Resource + ".*"
Copy link
Contributor

Choose a reason for hiding this comment

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

why the wildcarding? This looks like it would hit false positives.

Copy link
Author

Choose a reason for hiding this comment

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

yes, this is still not correct.

@deads2k
Copy link
Contributor

deads2k commented Dec 16, 2016

I think this may just be too big to fix inside of our current API server. The changes are pervasive and are changing attributes our current RESTHandler to allow removal. I worry about accidentally removing something important.

@lavalamp @kubernetes/sig-api-machinery-misc If we ran TPRs out of a addon API server, we could have a completely separate handler chain and have confidence of containment for changes like this.

@k8s-github-robot k8s-github-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Dec 20, 2016
@k8s-github-robot
Copy link

@adohe PR needs rebase

@adohe-zz
Copy link
Author

@lavalamp could you please take a look? If we decide to run TPRs out of a addon API server, I would start building this addon server, and add this to that server.

@k8s-github-robot
Copy link

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

We suggest the following people:
cc @brendandburns @ixdy
You can indicate your approval by writing /approve in a comment
You can cancel your approval by writing /approve cancel in a comment

@bgrant0607
Copy link
Member

See also #24299

@liggitt
Copy link
Member

liggitt commented Feb 7, 2017

Since TPRs cannot be converted between versions by the server, we cannot enable multiple versions in the API server and behave like a standard Kubernetes API.

@adohe-zz
Copy link
Author

@liggitt yes, so I am going to close this and will re-implement it in an addon server.

@jamiehannaford
Copy link
Contributor

@adohe Did you get a chance to start work on the addon server? I'm interested in helping out with TPRs, so was interested in the current status of things

@deads2k
Copy link
Contributor

deads2k commented Apr 21, 2017

@adohe Did you get a chance to start work on the addon server? I'm interested in helping out with TPRs, so was interested in the current status of things

We're looking at this proposal to move things forward: kubernetes/community#524.

@k8s-github-robot
Copy link

This PR hasn't been active in 31 days. It will be closed in 58 days (Jul 20, 2017).

cc @adohe @smarterclayton

You can add 'keep-open' label to prevent this from happening, or add a comment to keep it open another 90 days

@adohe-zz adohe-zz closed this May 31, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. 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