Skip to content
This repository was archived by the owner on May 14, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 2 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
8 changes: 4 additions & 4 deletions pkg/sync/sync_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,7 @@ func (sc *syncContext) getSyncTasks() (_ syncTasks, successful bool) {

// check permissions
for _, task := range tasks {
serverRes, err := kube.ServerResourceForGroupVersionKind(sc.disco, task.groupVersionKind())
serverRes, err := kube.ServerResourceForGroupVersionKind(sc.disco, task.groupVersionKind(), "get")
if err != nil {
// Special case for custom resources: if CRD is not yet known by the K8s API server,
// and the CRD is part of this sync or the resource is annotated with SkipDryRunOnMissingResource=true,
Expand Down Expand Up @@ -1000,15 +1000,15 @@ func (sc *syncContext) Terminate() {

func (sc *syncContext) deleteResource(task *syncTask) error {
sc.log.WithValues("task", task).V(1).Info("Deleting resource")
resIf, err := sc.getResourceIf(task)
resIf, err := sc.getResourceIf(task, "delete")
if err != nil {
return err
}
return resIf.Delete(context.TODO(), task.name(), sc.getDeleteOptions())
}

func (sc *syncContext) getResourceIf(task *syncTask) (dynamic.ResourceInterface, error) {
apiResource, err := kube.ServerResourceForGroupVersionKind(sc.disco, task.groupVersionKind())
func (sc *syncContext) getResourceIf(task *syncTask, verb string) (dynamic.ResourceInterface, error) {
apiResource, err := kube.ServerResourceForGroupVersionKind(sc.disco, task.groupVersionKind(), verb)
if err != nil {
return nil, err
}
Expand Down
14 changes: 8 additions & 6 deletions pkg/sync/sync_context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,23 @@ import (
testingutils "github.com/argoproj/gitops-engine/pkg/utils/testing"
)

var standardVerbs = v1.Verbs{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"}

func newTestSyncCtx(opts ...SyncOpt) *syncContext {
fakeDisco := &fakedisco.FakeDiscovery{Fake: &testcore.Fake{}}
fakeDisco.Resources = append(make([]*v1.APIResourceList, 0),
&v1.APIResourceList{
GroupVersion: "v1",
APIResources: []v1.APIResource{
{Kind: "Pod", Group: "", Version: "v1", Namespaced: true},
{Kind: "Service", Group: "", Version: "v1", Namespaced: true},
{Kind: "Namespace", Group: "", Version: "v1", Namespaced: false},
{Kind: "Pod", Group: "", Version: "v1", Namespaced: true, Verbs: standardVerbs},
{Kind: "Service", Group: "", Version: "v1", Namespaced: true, Verbs: standardVerbs},
{Kind: "Namespace", Group: "", Version: "v1", Namespaced: false, Verbs: standardVerbs},
},
},
&v1.APIResourceList{
GroupVersion: "apps/v1",
APIResources: []v1.APIResource{
{Kind: "Deployment", Group: "apps", Version: "v1", Namespaced: true},
{Kind: "Deployment", Group: "apps", Version: "v1", Namespaced: true, Verbs: standardVerbs},
},
})
sc := syncContext{
Expand Down Expand Up @@ -161,7 +163,7 @@ func TestSyncCustomResources(t *testing.T) {

knownCustomResourceTypes := []v1.APIResource{}
if tt.fields.crdAlreadyPresent {
knownCustomResourceTypes = append(knownCustomResourceTypes, v1.APIResource{Kind: "TestCrd", Group: "argoproj.io", Version: "v1", Namespaced: true})
knownCustomResourceTypes = append(knownCustomResourceTypes, v1.APIResource{Kind: "TestCrd", Group: "argoproj.io", Version: "v1", Namespaced: true, Verbs: standardVerbs})
}

syncCtx := newTestSyncCtx()
Expand All @@ -173,7 +175,7 @@ func TestSyncCustomResources(t *testing.T) {
{
GroupVersion: "apiextensions.k8s.io/v1beta1",
APIResources: []v1.APIResource{
{Kind: "CustomResourceDefinition", Group: "apiextensions.k8s.io", Version: "v1beta1", Namespaced: true},
{Kind: "CustomResourceDefinition", Group: "apiextensions.k8s.io", Version: "v1beta1", Namespaced: true, Verbs: standardVerbs},
},
},
}
Expand Down
15 changes: 10 additions & 5 deletions pkg/utils/kube/ctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"io/ioutil"
"strings"

"github.com/go-logr/logr"
"golang.org/x/sync/errgroup"
Expand Down Expand Up @@ -102,10 +103,14 @@ func (k *KubectlCmd) filterAPIResources(config *rest.Config, preferred bool, res
return apiResIfs, nil
}

// isSupportedVerb returns whether or not a APIResource supports a specific verb
// isSupportedVerb returns whether or not a APIResource supports a specific verb.
// The verb will be matched case-insensitive.
func isSupportedVerb(apiResource *metav1.APIResource, verb string) bool {
if verb == "" || verb == "*" {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this something that can happen? As far as I can tell, all instances of the argument are hard-coded as values others than these two.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good question. This is intended to allow the caller to just say "I don't care about the support verbs, just resolve it". It might be a valid use-case for some.

return true
}
for _, v := range apiResource.Verbs {
if v == verb {
if strings.EqualFold(v, verb) {
return true
}
}
Expand Down Expand Up @@ -194,7 +199,7 @@ func (k *KubectlCmd) GetResource(ctx context.Context, config *rest.Config, gvk s
if err != nil {
return nil, err
}
apiResource, err := ServerResourceForGroupVersionKind(disco, gvk)
apiResource, err := ServerResourceForGroupVersionKind(disco, gvk, "get")
if err != nil {
return nil, err
}
Expand All @@ -217,7 +222,7 @@ func (k *KubectlCmd) PatchResource(ctx context.Context, config *rest.Config, gvk
if err != nil {
return nil, err
}
apiResource, err := ServerResourceForGroupVersionKind(disco, gvk)
apiResource, err := ServerResourceForGroupVersionKind(disco, gvk, "patch")
if err != nil {
return nil, err
}
Expand All @@ -240,7 +245,7 @@ func (k *KubectlCmd) DeleteResource(ctx context.Context, config *rest.Config, gv
if err != nil {
return err
}
apiResource, err := ServerResourceForGroupVersionKind(disco, gvk)
apiResource, err := ServerResourceForGroupVersionKind(disco, gvk, "delete")
if err != nil {
return err
}
Expand Down
9 changes: 7 additions & 2 deletions pkg/utils/kube/kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,14 +172,19 @@ func IsCRD(obj *unstructured.Unstructured) bool {
return IsCRDGroupVersionKind(obj.GroupVersionKind())
}

// ServerResourceForGroupVersionKind looks up and returns the API resource from
// the server for a given GVK scheme. If verb is set to the non-empty string,
// it will return the API resource which supports the verb. There are some edge
// cases, where the same GVK is represented by more than one API.
//
// See: https://github.com/ksonnet/ksonnet/blob/master/utils/client.go
func ServerResourceForGroupVersionKind(disco discovery.DiscoveryInterface, gvk schema.GroupVersionKind) (*metav1.APIResource, error) {
func ServerResourceForGroupVersionKind(disco discovery.DiscoveryInterface, gvk schema.GroupVersionKind, verb string) (*metav1.APIResource, error) {
resources, err := disco.ServerResourcesForGroupVersion(gvk.GroupVersion().String())
if err != nil {
return nil, err
}
for _, r := range resources.APIResources {
if r.Kind == gvk.Kind {
if r.Kind == gvk.Kind && isSupportedVerb(&r, verb) {

@jessesuen jessesuen Jun 27, 2022

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure if users will ever run into a misleading message where we report NotFound error in logs, not because the GVK doesn't exist, but rather the verb isn't supported and we did not distinguish between the two. Since it's a pretty rare corner case, I don't think it's necessary but wanted to point it out.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I actually agree with this comment, @jessesuen. Edge case or not, I'm going to fix this.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Changed the logic to return MethodNotSupported if the GVK resolves to a resource which does not support the given verb.

Also, added some unit tests around all that.

return &r, nil
}
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/utils/kube/resource_ops.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ func (k *kubectlResourceOperations) UpdateResource(ctx context.Context, obj *uns
if err != nil {
return nil, err
}
apiResource, err := ServerResourceForGroupVersionKind(disco, gvk)
apiResource, err := ServerResourceForGroupVersionKind(disco, gvk, "update")
if err != nil {
return nil, err
}
Expand Down