Skip to content

Commit a43150b

Browse files
committed
Fix user-provided namespace ownership e2e assertion
check that the namespace has no owner references after successful installation instead of asserting that PSA labels are absent. Signed-off-by: Nader Ziada <nziada@redhat.com>
1 parent a632214 commit a43150b

2 files changed

Lines changed: 58 additions & 3 deletions

File tree

‎test/e2e/features/namespace.feature‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ Feature: Namespace PSA Management
22

33
As an OLM user, when I install an operator that declares PSA requirements
44
via the suggested-namespace-template CSV annotation, operator-controller
5-
should create a managed namespace with PSA labels applied.
5+
should create a managed namespace with PSA labels applied and leave
6+
user-provided namespaces unmanaged.
67

78
Background:
89
Given OLM is available
@@ -30,13 +31,14 @@ Feature: Namespace PSA Management
3031
"""
3132
Then ClusterExtension is rolled out
3233
And ClusterExtension is available
34+
And namespace "${PACKAGE:test}-system" is managed by OLM
3335
And namespace "${PACKAGE:test}-system" has labels
3436
| key | value |
3537
| pod-security.kubernetes.io/enforce | privileged |
3638
| pod-security.kubernetes.io/audit | privileged |
3739
| pod-security.kubernetes.io/warn | privileged |
3840

39-
Scenario: User-provided namespace does not get PSA labels
41+
Scenario: User-provided namespace remains unmanaged
4042
Given namespace "${TEST_NAMESPACE}" is available
4143
And a catalog "test" with packages:
4244
| package | version | channel | replaces | contents |
@@ -59,4 +61,5 @@ Feature: Namespace PSA Management
5961
"""
6062
Then ClusterExtension is rolled out
6163
And ClusterExtension is available
62-
And namespace "${TEST_NAMESPACE}" does not have label "pod-security.kubernetes.io/enforce"
64+
# Other cluster controllers may apply PSA labels to user-provided namespaces.
65+
And namespace "${TEST_NAMESPACE}" has no owner references

‎test/e2e/steps/steps.go‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,9 @@ func RegisterSteps(sc *godog.ScenarioContext) {
186186
sc.Step(`^(?i)ValidatingAdmissionPolicy "([^"]+)" is active$`, ValidatingAdmissionPolicyIsActive)
187187

188188
sc.Step(`^(?i)namespace "([^"]+)" has labels$`, NamespaceHasLabels)
189+
sc.Step(`^(?i)namespace "([^"]+)" is managed by OLM$`, NamespaceIsManagedByOLM)
189190
sc.Step(`^(?i)namespace "([^"]+)" does not have label "([^"]+)"$`, NamespaceDoesNotHaveLabel)
191+
sc.Step(`^(?i)namespace "([^"]+)" has no owner references$`, NamespaceHasNoOwnerReferences)
190192

191193
sc.Step(`^(?i)operator "([^"]+)" target namespace is "([^"]+)"$`, OperatorTargetNamespace)
192194
sc.Step(`^(?i)Prometheus metrics are returned in the response$`, PrometheusMetricsAreReturned)
@@ -2513,6 +2515,56 @@ func NamespaceDoesNotHaveLabel(ctx context.Context, nsName string, labelKey stri
25132515
return nil
25142516
}
25152517

2518+
// NamespaceIsManagedByOLM waits for a namespace to be owned by the extension's active ClusterObjectSet.
2519+
func NamespaceIsManagedByOLM(ctx context.Context, nsName string) error {
2520+
sc := scenarioCtx(ctx)
2521+
nsName = substituteScenarioVars(nsName, sc)
2522+
2523+
waitFor(ctx, func() bool {
2524+
revision, err := latestActiveRevisionForExtension(sc.clusterExtensionName)
2525+
if err != nil {
2526+
logger.V(1).Error(err, "failed to get active revision", "extension", sc.clusterExtensionName)
2527+
return false
2528+
}
2529+
out, err := k8sClient(ctx, "get", "namespace", nsName, "-o", "json")
2530+
if err != nil {
2531+
return false
2532+
}
2533+
var ns corev1.Namespace
2534+
if err := json.Unmarshal([]byte(out), &ns); err != nil {
2535+
return false
2536+
}
2537+
owner := metav1.GetControllerOf(&ns)
2538+
if owner == nil || owner.APIVersion != ocv1.GroupVersion.String() ||
2539+
owner.Kind != ocv1.ClusterObjectSetKind || owner.Name != revision.Name || owner.UID != revision.UID {
2540+
logger.V(1).Info("Namespace is not yet owned by the extension's active revision",
2541+
"namespace", nsName, "revision", revision.Name, "owner", owner)
2542+
return false
2543+
}
2544+
return true
2545+
})
2546+
return nil
2547+
}
2548+
2549+
// NamespaceHasNoOwnerReferences verifies a namespace remains unmanaged after installation.
2550+
func NamespaceHasNoOwnerReferences(ctx context.Context, nsName string) error {
2551+
sc := scenarioCtx(ctx)
2552+
nsName = substituteScenarioVars(nsName, sc)
2553+
2554+
out, err := k8sClient(ctx, "get", "namespace", nsName, "-o", "json")
2555+
if err != nil {
2556+
return fmt.Errorf("failed to get namespace %q: %w", nsName, err)
2557+
}
2558+
var obj unstructured.Unstructured
2559+
if err := json.Unmarshal([]byte(out), &obj); err != nil {
2560+
return fmt.Errorf("failed to unmarshal namespace: %w", err)
2561+
}
2562+
if refs := obj.GetOwnerReferences(); len(refs) != 0 {
2563+
return fmt.Errorf("namespace %q has unexpected owner references: %v", nsName, refs)
2564+
}
2565+
return nil
2566+
}
2567+
25162568
// nestedString traverses a nested map[string]interface{} by the given keys
25172569
// and returns the leaf value as a string.
25182570
func nestedString(obj map[string]interface{}, keys ...string) (string, bool) {

0 commit comments

Comments
 (0)