Skip to content

Commit

Permalink
Create missing namespaces for operator policy
Browse files Browse the repository at this point in the history
This provides a nice convenience to the user.

Relates:
https://issues.redhat.com/browse/ACM-11403

Signed-off-by: mprahl <mprahl@users.noreply.github.com>
  • Loading branch information
mprahl committed Apr 30, 2024
1 parent 546d950 commit cb90acf
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 2 deletions.
51 changes: 49 additions & 2 deletions controllers/operatorpolicy_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ func (r *OperatorPolicyReconciler) musthaveOpGroup(
earlyConds = append(earlyConds, calculateComplianceCondition(policy))
}

err := r.Create(ctx, desiredOpGroup)
err := r.createWithNamespace(ctx, policy, desiredOpGroup)
if err != nil {
return nil, changed, fmt.Errorf("error creating the OperatorGroup: %w", err)
}
Expand Down Expand Up @@ -719,6 +719,53 @@ func (r *OperatorPolicyReconciler) musthaveOpGroup(
}
}

// createWithNamespace will create the input object and the object's namespace if needed.
func (r *OperatorPolicyReconciler) createWithNamespace(
ctx context.Context, policy *policyv1beta1.OperatorPolicy, object client.Object,
) error {
err := r.Create(ctx, object)
if err == nil {
return nil
}

// If the error is not due to a missing namespace or the namespace is not set on the object, return the error.
if !isNamespaceNotFound(err) || object.GetNamespace() == "" {
return err
}

log.Info("Creating the namespace since it didn't exist", "name", object.GetNamespace(), "policy", policy.Name)

ns := corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: object.GetNamespace(),
},
}

err = r.Create(ctx, &ns)
if err != nil && !k8serrors.IsAlreadyExists(err) {
return err
}

// Try creating the object again now that the namespace was created.
return r.Create(ctx, object)
}

// isNamespaceNotFound detects if the input error from r.Create failed due to the specified namespace not existing.
func isNamespaceNotFound(err error) bool {
if !k8serrors.IsNotFound(err) {
return false
}

statusErr := &k8serrors.StatusError{}
if !errors.As(err, &statusErr) {
return false
}

status := statusErr.Status()

return status.Details != nil && status.Details.Kind == "namespaces"
}

func (r *OperatorPolicyReconciler) mustnothaveOpGroup(
ctx context.Context,
policy *policyv1beta1.OperatorPolicy,
Expand Down Expand Up @@ -863,7 +910,7 @@ func (r *OperatorPolicyReconciler) musthaveSubscription(
earlyConds = append(earlyConds, calculateComplianceCondition(policy))
}

err := r.Create(ctx, desiredSub)
err := r.createWithNamespace(ctx, policy, desiredSub)
if err != nil {
return nil, nil, changed, fmt.Errorf("error creating the Subscription: %w", err)
}
Expand Down
33 changes: 33 additions & 0 deletions test/e2e/case38_install_operator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,39 @@ var _ = Describe("Testing OperatorPolicy", Ordered, func() {
)
})
})

Describe("Testing namespace creation", Ordered, func() {
const (
opPolYAML = "../resources/case38_operator_install/operator-policy-no-group-enforce.yaml"
opPolName = "oppol-no-group-enforce"
)
BeforeAll(func() {
DeferCleanup(func() {
utils.Kubectl(
"delete", "-f", parentPolicyYAML, "-n", testNamespace, "--ignore-not-found", "--cascade=foreground",
)
utils.Kubectl("delete", "ns", opPolTestNS, "--ignore-not-found")
})

createObjWithParent(
parentPolicyYAML, parentPolicyName, opPolYAML, testNamespace, gvrPolicy, gvrOperatorPolicy,
)
})

It("Should be compliant when enforced", func() {
By("Waiting for the operator policy " + opPolName + " to be compliant")
Eventually(func() string {
opPolicy := utils.GetWithTimeout(
clientManagedDynamic, gvrOperatorPolicy, opPolName, testNamespace, true, defaultTimeoutSeconds,
)

compliance, _, _ := unstructured.NestedString(opPolicy.Object, "status", "compliant")

return compliance
}, defaultTimeoutSeconds*2, 1).Should(Equal("Compliant"))
})
})

Describe("Testing OperatorGroup behavior when it is specified in the policy", Ordered, func() {
const (
opPolYAML = "../resources/case38_operator_install/operator-policy-with-group.yaml"
Expand Down

0 comments on commit cb90acf

Please sign in to comment.