mirror of
https://github.com/kyverno/kyverno.git
synced 2025-04-08 10:04:25 +00:00
fix: lookup GVK from GVR (#6516)
* fix: lookup GVK from GVR Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * fix Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * fix tests Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * error Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> --------- Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
parent
7eb4515e33
commit
89cfa88c1e
5 changed files with 64 additions and 44 deletions
pkg
|
@ -136,7 +136,7 @@ func (c *MutateExistingController) ProcessUR(ur *kyvernov1beta1.UpdateRequest) e
|
|||
} else if patchedTargetSubresourceName != "" {
|
||||
parentResourceGVR := r.PatchedTargetParentResourceGVR
|
||||
parentResourceGV := schema.GroupVersion{Group: parentResourceGVR.Group, Version: parentResourceGVR.Version}
|
||||
parentResourceGVK, err := c.client.Discovery().GetGVKFromGVR(parentResourceGV.String(), parentResourceGVR.Resource)
|
||||
parentResourceGVK, err := c.client.Discovery().GetGVKFromGVR(parentResourceGV.WithResource(parentResourceGVR.Resource))
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to get GVK from GVR", "GVR", parentResourceGVR)
|
||||
errs = append(errs, err)
|
||||
|
|
|
@ -19,7 +19,7 @@ type IDiscovery interface {
|
|||
FindResource(groupVersion string, kind string) (apiResource, parentAPIResource *metav1.APIResource, gvr schema.GroupVersionResource, err error)
|
||||
GetGVRFromKind(kind string) (schema.GroupVersionResource, error)
|
||||
GetGVRFromAPIVersionKind(groupVersion string, kind string) schema.GroupVersionResource
|
||||
GetGVKFromGVR(apiVersion, resourceName string) (schema.GroupVersionKind, error)
|
||||
GetGVKFromGVR(schema.GroupVersionResource) (schema.GroupVersionKind, error)
|
||||
GetServerVersion() (*version.Info, error)
|
||||
OpenAPISchema() (*openapiv2.Document, error)
|
||||
DiscoveryCache() discovery.CachedDiscoveryInterface
|
||||
|
@ -105,15 +105,15 @@ func (c serverResources) GetServerVersion() (*version.Info, error) {
|
|||
|
||||
// GetGVKFromGVR returns the Group Version Kind from Group Version Resource. The groupVersion has to be specified properly
|
||||
// for example, for corev1.Pod, the groupVersion has to be specified as `v1`, specifying empty groupVersion won't work.
|
||||
func (c serverResources) GetGVKFromGVR(groupVersion, resourceName string) (schema.GroupVersionKind, error) {
|
||||
gvk, err := c.findResourceFromResourceName(groupVersion, resourceName)
|
||||
func (c serverResources) GetGVKFromGVR(gvr schema.GroupVersionResource) (schema.GroupVersionKind, error) {
|
||||
gvk, err := c.findResourceFromResourceName(gvr)
|
||||
if err == nil {
|
||||
return gvk, nil
|
||||
}
|
||||
|
||||
if !c.cachedClient.Fresh() {
|
||||
c.cachedClient.Invalidate()
|
||||
if gvk, err := c.findResourceFromResourceName(groupVersion, resourceName); err == nil {
|
||||
if gvk, err := c.findResourceFromResourceName(gvr); err == nil {
|
||||
return gvk, nil
|
||||
}
|
||||
}
|
||||
|
@ -122,19 +122,19 @@ func (c serverResources) GetGVKFromGVR(groupVersion, resourceName string) (schem
|
|||
}
|
||||
|
||||
// findResourceFromResourceName returns the GVK for the a particular resourceName and groupVersion
|
||||
func (c serverResources) findResourceFromResourceName(groupVersion, resourceName string) (schema.GroupVersionKind, error) {
|
||||
func (c serverResources) findResourceFromResourceName(gvr schema.GroupVersionResource) (schema.GroupVersionKind, error) {
|
||||
_, serverGroupsAndResources, err := c.cachedClient.ServerGroupsAndResources()
|
||||
if err != nil && !strings.Contains(err.Error(), "Got empty response for") {
|
||||
if discovery.IsGroupDiscoveryFailedError(err) {
|
||||
logDiscoveryErrors(err)
|
||||
} else if isMetricsServerUnavailable(groupVersion, err) {
|
||||
} else if isMetricsServerUnavailable(gvr.GroupVersion(), err) {
|
||||
logger.V(3).Info("failed to find preferred resource version", "error", err.Error())
|
||||
} else {
|
||||
logger.Error(err, "failed to find preferred resource version")
|
||||
return schema.GroupVersionKind{}, err
|
||||
}
|
||||
}
|
||||
apiResource, err := findResourceFromResourceName(groupVersion, resourceName, serverGroupsAndResources)
|
||||
apiResource, err := findResourceFromResourceName(gvr, serverGroupsAndResources)
|
||||
if err != nil {
|
||||
return schema.GroupVersionKind{}, err
|
||||
}
|
||||
|
@ -166,11 +166,15 @@ func (c serverResources) findResource(groupVersion string, kind string) (apiReso
|
|||
) {
|
||||
serverPreferredResources, _ := c.cachedClient.ServerPreferredResources()
|
||||
_, serverGroupsAndResources, err := c.cachedClient.ServerGroupsAndResources()
|
||||
|
||||
if err != nil && !strings.Contains(err.Error(), "Got empty response for") {
|
||||
gv, err := schema.ParseGroupVersion(groupVersion)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to parse group/version", "groupVersion", groupVersion)
|
||||
return nil, nil, schema.GroupVersionResource{}, err
|
||||
}
|
||||
if discovery.IsGroupDiscoveryFailedError(err) {
|
||||
logDiscoveryErrors(err)
|
||||
} else if isMetricsServerUnavailable(groupVersion, err) {
|
||||
} else if isMetricsServerUnavailable(gv, err) {
|
||||
logger.V(3).Info("failed to find preferred resource version", "error", err.Error())
|
||||
} else {
|
||||
logger.Error(err, "failed to find preferred resource version")
|
||||
|
@ -246,8 +250,14 @@ func findResource(groupVersion string, kind string, serverPreferredResources, se
|
|||
Version: matchingServerResource.Version,
|
||||
}
|
||||
logger.V(6).Info("gv with resource", "gvWithResource", groupVersionResource)
|
||||
|
||||
parentAPIResource, err := findResourceFromResourceName(apiResourceWithListGV.listGV, strings.Split(matchingServerResource.Name, "/")[0], serverPreferredResources)
|
||||
gv, err := schema.ParseGroupVersion(apiResourceWithListGV.listGV)
|
||||
if err != nil {
|
||||
return nil, nil, schema.GroupVersionResource{}, fmt.Errorf("failed to parse group version %s: %v", apiResourceWithListGV.listGV, err)
|
||||
}
|
||||
parentAPIResource, err := findResourceFromResourceName(
|
||||
gv.WithResource(strings.Split(matchingServerResource.Name, "/")[0]),
|
||||
serverPreferredResources,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, schema.GroupVersionResource{}, fmt.Errorf("failed to find parent resource for subresource %s: %v", matchingServerResource.Name, err)
|
||||
}
|
||||
|
@ -311,20 +321,28 @@ func getMatchingServerResources(groupVersion string, kind string, serverGroupsAn
|
|||
}
|
||||
|
||||
// findResourceFromResourceName finds an API resource that matches 'resourceName', in the given serverResourcesList
|
||||
func findResourceFromResourceName(groupVersion string, resourceName string, serverGroupsAndResources []*metav1.APIResourceList) (*metav1.APIResource, error) {
|
||||
for _, serverResourceList := range serverGroupsAndResources {
|
||||
for _, apiResource := range serverResourceList.APIResources {
|
||||
serverResourceGroupVersion := getServerResourceGroupVersion(serverResourceList.GroupVersion, apiResource.Group, apiResource.Version)
|
||||
if serverResourceGroupVersion == groupVersion && apiResource.Name == resourceName {
|
||||
logger.V(6).Info("found preferred resource", "groupVersion", groupVersion, "resourceName", resourceName)
|
||||
groupVersion, _ := schema.ParseGroupVersion(serverResourceGroupVersion)
|
||||
apiResource.Group = groupVersion.Group
|
||||
apiResource.Version = groupVersion.Version
|
||||
return &apiResource, nil
|
||||
func findResourceFromResourceName(gvr schema.GroupVersionResource, serverGroupsAndResources []*metav1.APIResourceList) (*metav1.APIResource, error) {
|
||||
for _, list := range serverGroupsAndResources {
|
||||
gv, err := schema.ParseGroupVersion(list.GroupVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if gv.Group == gvr.Group && gv.Version == gvr.Version {
|
||||
for _, resource := range list.APIResources {
|
||||
if resource.Name == gvr.Resource {
|
||||
// if the matched resource has group or version set we don't need to copy from the parent list
|
||||
if resource.Group != "" || resource.Version != "" {
|
||||
return &resource, nil
|
||||
}
|
||||
result := resource.DeepCopy()
|
||||
result.Group = gv.Group
|
||||
result.Version = gv.Version
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("resource %s not found in group %s", resourceName, groupVersion)
|
||||
return nil, fmt.Errorf("resource %s not found in group %s", gvr.Resource, gvr.GroupVersion())
|
||||
}
|
||||
|
||||
// getServerResourceGroupVersion returns the groupVersion of the serverResource from the apiResourceMetadata
|
||||
|
|
|
@ -5,19 +5,17 @@ import (
|
|||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"gotest.tools/assert"
|
||||
"github.com/stretchr/testify/assert"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
var (
|
||||
networkPolicyAPIResource = metav1.APIResource{Name: "networkpolicies", SingularName: "", Namespaced: true, Kind: "NetworkPolicy"}
|
||||
networkPolicyStatusAPIResource = metav1.APIResource{Name: "networkpolicies/status", SingularName: "", Namespaced: true, Kind: "NetworkPolicy"}
|
||||
|
||||
podAPIResource = metav1.APIResource{Name: "pods", SingularName: "", Namespaced: true, Kind: "Pod"}
|
||||
podEvictionAPIResource = metav1.APIResource{Name: "pods/eviction", SingularName: "", Namespaced: true, Group: "policy", Version: "v1", Kind: "Eviction"}
|
||||
podLogAPIResource = metav1.APIResource{Name: "pods/log", SingularName: "", Namespaced: true, Kind: "Pod"}
|
||||
|
||||
cronJobAPIResource = metav1.APIResource{Name: "cronjobs", SingularName: "", Namespaced: true, Kind: "CronJob"}
|
||||
podAPIResource = metav1.APIResource{Name: "pods", SingularName: "", Namespaced: true, Kind: "Pod"}
|
||||
podEvictionAPIResource = metav1.APIResource{Name: "pods/eviction", SingularName: "", Namespaced: true, Group: "policy", Version: "v1", Kind: "Eviction"}
|
||||
podLogAPIResource = metav1.APIResource{Name: "pods/log", SingularName: "", Namespaced: true, Kind: "Pod"}
|
||||
cronJobAPIResource = metav1.APIResource{Name: "cronjobs", SingularName: "", Namespaced: true, Kind: "CronJob"}
|
||||
)
|
||||
|
||||
func Test_findSubresource(t *testing.T) {
|
||||
|
@ -40,7 +38,7 @@ func Test_findSubresource(t *testing.T) {
|
|||
}
|
||||
|
||||
apiResource, gvr, err := findSubresource("", "pods", "eviction", "Pod/eviction", serverGroupsAndResources)
|
||||
assert.NilError(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, gvr, schema.GroupVersionResource{Resource: "pods/eviction", Group: "policy", Version: "v1"})
|
||||
|
||||
// Not comparing directly because actual apiResource also contains fields like 'ShortNames' which are not set in the expected apiResource
|
||||
|
@ -50,7 +48,7 @@ func Test_findSubresource(t *testing.T) {
|
|||
assert.Equal(t, apiResource.Version, podEvictionAPIResource.Version)
|
||||
|
||||
apiResource, gvr, err = findSubresource("v1", "pods", "eviction", "Pod/eviction", serverGroupsAndResources)
|
||||
assert.NilError(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, gvr, schema.GroupVersionResource{Resource: "pods/eviction", Group: "policy", Version: "v1"})
|
||||
|
||||
// Not comparing directly because actual apiResource also contains fields like 'ShortNames' which are not set in the expected apiResource
|
||||
|
@ -60,7 +58,7 @@ func Test_findSubresource(t *testing.T) {
|
|||
assert.Equal(t, apiResource.Version, podEvictionAPIResource.Version)
|
||||
|
||||
apiResource, gvr, err = findSubresource("networking.k8s.io/*", "networkpolicies", "status", "NetworkPolicy/status", serverGroupsAndResources)
|
||||
assert.NilError(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, gvr, schema.GroupVersionResource{Resource: "networkpolicies/status", Group: "networking.k8s.io", Version: "v1"})
|
||||
|
||||
// Not comparing directly because actual apiResource also contains fields like 'ShortNames' which are not set in the expected apiResource
|
||||
|
@ -112,7 +110,7 @@ func Test_findResource(t *testing.T) {
|
|||
}
|
||||
|
||||
apiResource, parentAPIResource, gvr, err := findResource("", "Pod", serverPreferredResourcesList, serverGroupsAndResources)
|
||||
assert.NilError(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, gvr, schema.GroupVersionResource{Resource: "pods", Group: "", Version: "v1"})
|
||||
assert.Equal(t, parentAPIResource, (*metav1.APIResource)(nil))
|
||||
|
||||
|
@ -125,7 +123,7 @@ func Test_findResource(t *testing.T) {
|
|||
assert.Equal(t, apiResource.Version, "v1")
|
||||
|
||||
apiResource, parentAPIResource, gvr, err = findResource("policy/v1", "Eviction", serverPreferredResourcesList, serverGroupsAndResources)
|
||||
assert.NilError(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, gvr, schema.GroupVersionResource{Resource: "pods/eviction", Group: "policy", Version: "v1"})
|
||||
|
||||
assert.Equal(t, parentAPIResource.Name, podAPIResource.Name)
|
||||
|
@ -140,7 +138,7 @@ func Test_findResource(t *testing.T) {
|
|||
assert.Equal(t, apiResource.Version, podEvictionAPIResource.Version)
|
||||
|
||||
apiResource, parentAPIResource, gvr, err = findResource("", "CronJob", serverPreferredResourcesList, serverGroupsAndResources)
|
||||
assert.NilError(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, gvr, schema.GroupVersionResource{Resource: "cronjobs", Group: "batch", Version: "v1"})
|
||||
|
||||
assert.Equal(t, parentAPIResource, (*metav1.APIResource)(nil))
|
||||
|
@ -152,7 +150,7 @@ func Test_findResource(t *testing.T) {
|
|||
assert.Equal(t, apiResource.Version, "v1")
|
||||
|
||||
apiResource, parentAPIResource, gvr, err = findResource("batch/v1beta1", "CronJob", serverPreferredResourcesList, serverGroupsAndResources)
|
||||
assert.NilError(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, gvr, schema.GroupVersionResource{Resource: "cronjobs", Group: "batch", Version: "v1beta1"})
|
||||
|
||||
assert.Equal(t, parentAPIResource, (*metav1.APIResource)(nil))
|
||||
|
@ -189,15 +187,18 @@ func Test_findResourceFromResourceName(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
apiResource, err := findResourceFromResourceName("v1", "pods", serverGroupsAndResources)
|
||||
assert.NilError(t, err)
|
||||
apiResource, err := findResourceFromResourceName(schema.GroupVersionResource{Version: "v1", Resource: "pods"}, serverGroupsAndResources)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, apiResource.Name, podAPIResource.Name)
|
||||
assert.Equal(t, apiResource.Kind, podAPIResource.Kind)
|
||||
assert.Equal(t, apiResource.Group, "")
|
||||
assert.Equal(t, apiResource.Version, "v1")
|
||||
|
||||
apiResource, err = findResourceFromResourceName("policy/v1", "pods/eviction", serverGroupsAndResources)
|
||||
assert.NilError(t, err)
|
||||
apiResource, err = findResourceFromResourceName(schema.GroupVersionResource{Group: "policy", Version: "v1", Resource: "pods/eviction"}, serverGroupsAndResources)
|
||||
assert.Error(t, err)
|
||||
|
||||
apiResource, err = findResourceFromResourceName(schema.GroupVersionResource{Version: "v1", Resource: "pods/eviction"}, serverGroupsAndResources)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, apiResource.Name, podEvictionAPIResource.Name)
|
||||
assert.Equal(t, apiResource.Kind, podEvictionAPIResource.Kind)
|
||||
assert.Equal(t, apiResource.Group, podEvictionAPIResource.Group)
|
||||
|
|
|
@ -77,7 +77,7 @@ func (c *fakeDiscoveryClient) GetGVRFromKind(kind string) (schema.GroupVersionRe
|
|||
return c.getGVR(resource), nil
|
||||
}
|
||||
|
||||
func (c *fakeDiscoveryClient) GetGVKFromGVR(apiVersion, resourceName string) (schema.GroupVersionKind, error) {
|
||||
func (c *fakeDiscoveryClient) GetGVKFromGVR(schema.GroupVersionResource) (schema.GroupVersionKind, error) {
|
||||
return schema.GroupVersionKind{}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package dclient
|
|||
import (
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/discovery"
|
||||
)
|
||||
|
||||
|
@ -19,9 +20,9 @@ func logDiscoveryErrors(err error) {
|
|||
}
|
||||
}
|
||||
|
||||
func isMetricsServerUnavailable(groupVersion string, err error) bool {
|
||||
func isMetricsServerUnavailable(gv schema.GroupVersion, err error) bool {
|
||||
// error message is defined at:
|
||||
// https://github.com/kubernetes/apimachinery/blob/2456ebdaba229616fab2161a615148884b46644b/pkg/api/errors/errors.go#L432
|
||||
return (strings.HasPrefix(groupVersion, "metrics.k8s.io/") || strings.HasPrefix(groupVersion, "custom.metrics.k8s.io/") || strings.HasPrefix(groupVersion, "external.metrics.k8s.io/")) &&
|
||||
return (gv.Group == "metrics.k8s.io" || gv.Group == "custom.metrics.k8s.io" || gv.Group == "external.metrics.k8s.io") &&
|
||||
strings.Contains(err.Error(), "the server is currently unable to handle the request")
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue