Skip to content
Merged
Show file tree
Hide file tree
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
17 changes: 17 additions & 0 deletions pkg/assets/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ func (r *Registry) ShouldApply(ctx context.Context, asset *AssetMetadata, evalCo
// IsManagedCRD reports whether crdName is the required CRD of at least one declared asset.
// Used by the CRD event handler to decide whether a CRD install/removal is relevant.
func (r *Registry) IsManagedCRD(crdName string) bool {
if crdName == "" {
return false
}
for i := range r.catalog.Assets {
if r.catalog.Assets[i].RequiredCRD == crdName {
return true
Expand Down Expand Up @@ -221,6 +224,20 @@ func crdNameFromGVK(apiVersion, kind string) string {
if len(parts) == 1 {
return "" // core API, no CRD
}

// Built-in Kubernetes API groups (not CRDs).
// All Kubernetes-owned groups use the .k8s.io or .apiserver.k8s.io suffix.
group := parts[0]
if strings.HasSuffix(group, ".k8s.io") || strings.HasSuffix(group, ".apiserver.k8s.io") {
return ""
}

// Legacy built-in groups that predate the .k8s.io convention.
switch group {
case "apps", "batch", "policy", "autoscaling":
return ""
}

return pluralizeKind(kind) + "." + parts[0]
}

Expand Down
48 changes: 48 additions & 0 deletions pkg/assets/registry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -514,3 +514,51 @@ func TestOptInAssetsHaveConditions(t *testing.T) {
len(violations), violations)
}
}

func TestCrdNameFromGVK(t *testing.T) {
tests := []struct {
name string
apiVersion string
kind string
want string
}{
// Core API (no group)
{"core v1 pod", "v1", "Pod", ""},
{"core v1 service", "v1", "Service", ""},

// Built-in API groups with .k8s.io suffix
{"rbac clusterrole", "rbac.authorization.k8s.io/v1", "ClusterRole", ""},
{"networking ingress", "networking.k8s.io/v1", "Ingress", ""},
{"admissionregistration mutatingwebhook", "admissionregistration.k8s.io/v1", "MutatingWebhookConfiguration", ""},
{"storage storageclass", "storage.k8s.io/v1", "StorageClass", ""},
{"apiextensions crd", "apiextensions.k8s.io/v1", "CustomResourceDefinition", ""},
{"coordination lease", "coordination.k8s.io/v1", "Lease", ""},
{"events event", "events.k8s.io/v1", "Event", ""},

// Built-in API groups with .apiserver.k8s.io suffix
{"flowcontrol prioritylevelconfiguration", "flowcontrol.apiserver.k8s.io/v1", "PriorityLevelConfiguration", ""},

// Legacy built-in API groups (no suffix)
{"apps deployment", "apps/v1", "Deployment", ""},
{"batch job", "batch/v1", "Job", ""},
{"policy poddisruptionbudget", "policy/v1", "PodDisruptionBudget", ""},
{"autoscaling hpa", "autoscaling/v2", "HorizontalPodAutoscaler", ""},

// Custom Resource Definitions (should return CRD name)
{"kubevirt hyperconverged", "hco.kubevirt.io/v1beta1", "HyperConverged", "hyperconvergeds.hco.kubevirt.io"},
{"forklift controller", "forklift.konveyor.io/v1beta1", "ForkliftController", "forkliftcontrollers.forklift.konveyor.io"},
{"metallb", "metallb.io/v1beta1", "MetalLB", "metallbs.metallb.io"},
{"monitoring prometheusrule", "monitoring.coreos.com/v1", "PrometheusRule", "prometheusrules.monitoring.coreos.com"},
{"openshift machineconfig", "machineconfiguration.openshift.io/v1", "MachineConfig", "machineconfigs.machineconfiguration.openshift.io"},
{"medik8s nodehealthcheck", "remediation.medik8s.io/v1alpha1", "NodeHealthCheck", "nodehealthchecks.remediation.medik8s.io"},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := crdNameFromGVK(tt.apiVersion, tt.kind)
if got != tt.want {
t.Errorf("crdNameFromGVK(%q, %q) = %q, want %q", tt.apiVersion, tt.kind, got, tt.want)
}
})
}
}