Skip to content

Commit d0e2f61

Browse files
mprahlopenshift-merge-bot[bot]
authored andcommitted
Record compliance events on the compliance events history API
If a policy controller sends a Kubernetes event with the policy.open-cluster-management.io/policy-compliance-db-id annotation set. The compliance event will be recorded on the compliance events history API. Also, when the policy is disabled/deleted, a compliance event is recorded on the compliance events history API. Note that to enable this functionality, the --compliance-api-url must be passed to this controller. Relates: https://issues.redhat.com/browse/ACM-6889 Signed-off-by: mprahl <[email protected]>
1 parent 1b5ccdc commit d0e2f61

File tree

17 files changed

+938
-24
lines changed

17 files changed

+938
-24
lines changed

.github/workflows/kind.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ jobs:
8686
export COVERAGE_E2E_OUT=coverage_e2e_hosted_mode.out
8787
KUBECONFIG=${PWD}/kubeconfig_managed make e2e-test-coverage
8888
89+
- name: E2E Tests for Compliance Events API Integration
90+
run: |
91+
KUBECONFIG=${PWD}/kubeconfig_managed make e2e-test-coverage-compliance-events-api
92+
8993
- name: Verify Deployment Configuration
9094
run: |
9195
make build-images

Makefile

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ GOOS = $(shell go env GOOS)
2727
TESTARGS_DEFAULT := -v
2828
export TESTARGS ?= $(TESTARGS_DEFAULT)
2929

30+
COMPLIANCE_API_URL ?= http://127.0.0.1:8385
31+
3032
# Get the branch of the PR target or Push in Github Action
3133
ifeq ($(GITHUB_EVENT_NAME), pull_request) # pull request
3234
BRANCH := $(GITHUB_BASE_REF)
@@ -50,10 +52,11 @@ HUB_CONFIG_INTERNAL ?= $(PWD)/kubeconfig_hub_internal
5052
MANAGED_CONFIG ?= $(PWD)/kubeconfig_managed
5153
deployOnHub ?= false
5254
CONTROLLER_NAME ?= $(shell cat COMPONENT_NAME 2> /dev/null)
55+
E2E_FILTER = --label-filter="!compliance-events-api"
5356
# Set the Kind version tag
5457
ifeq ($(KIND_VERSION), minimum)
5558
KIND_ARGS = --image kindest/node:v1.19.16
56-
E2E_FILTER = --label-filter="!skip-minimum"
59+
E2E_FILTER = --label-filter="!skip-minimum && !compliance-events-api"
5760
else ifneq ($(KIND_VERSION), latest)
5861
KIND_ARGS = --image kindest/node:$(KIND_VERSION)
5962
else
@@ -219,10 +222,10 @@ install-resources:
219222

220223
.PHONY: e2e-test
221224
e2e-test: e2e-dependencies
222-
$(GINKGO) -v --fail-fast $(E2E_TEST_ARGS) test/e2e
225+
$(GINKGO) -v --fail-fast $(E2E_TEST_ARGS) $(E2E_FILTER) test/e2e
223226

224227
.PHONY: e2e-test-coverage
225-
e2e-test-coverage: E2E_TEST_ARGS = --json-report=report_e2e.json --output-dir=. $(E2E_FILTER)
228+
e2e-test-coverage: E2E_TEST_ARGS = --json-report=report_e2e.json --output-dir=.
226229
e2e-test-coverage: e2e-run-instrumented e2e-test e2e-stop-instrumented
227230

228231
.PHONY: e2e-test-coverage-foreground
@@ -239,6 +242,16 @@ e2e-test-uninistall:
239242
e2e-test-uninstall-coverage: COVERAGE_E2E_OUT = coverage_e2e_uninstall_controller.out
240243
e2e-test-uninstall-coverage: e2e-run-instrumented scale-down-deployment e2e-test-uninistall e2e-stop-instrumented
241244

245+
.PHONY: e2e-test-compliance-events-api
246+
e2e-test-compliance-events-api:
247+
COMPLIANCE_API_URL=$(COMPLIANCE_API_URL) $(GINKGO) -v --fail-fast $(E2E_TEST_ARGS) --label-filter="compliance-events-api" test/e2e
248+
249+
.PHONY: e2e-test-coverage-compliance-events-api
250+
e2e-test-coverage-compliance-events-api:
251+
COVERAGE_E2E_OUT=coverage_e2e_compliance_events_api.out COMPLIANCE_API_URL=$(COMPLIANCE_API_URL) $(MAKE) e2e-run-instrumented
252+
$(MAKE) e2e-test-compliance-events-api
253+
$(MAKE) e2e-stop-instrumented
254+
242255
.PHONY: scale-down-deployment
243256
scale-down-deployment:
244257
kubectl scale deployment $(IMG) -n $(KIND_NAMESPACE) --replicas=0 --kubeconfig=$(MANAGED_CONFIG)_e2e

controllers/specsync/policy_spec_sync.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ import (
1010

1111
"k8s.io/apimachinery/pkg/api/errors"
1212
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1314
"k8s.io/apimachinery/pkg/runtime"
1415
"k8s.io/apimachinery/pkg/types"
1516
"k8s.io/client-go/tools/record"
17+
"k8s.io/client-go/util/workqueue"
1618
policiesv1 "open-cluster-management.io/governance-policy-propagator/api/v1"
1719
"open-cluster-management.io/governance-policy-propagator/controllers/common"
1820
ctrl "sigs.k8s.io/controller-runtime"
@@ -52,6 +54,9 @@ type PolicyReconciler struct {
5254
// The namespace that the replicated policies should be synced to.
5355
TargetNamespace string
5456
ConcurrentReconciles int
57+
// EventsQueue is a queue that accepts ComplianceAPIEventRequest to then be recorded in the compliance events
58+
// API by StartComplianceEventsSyncer. If the compliance events API is disabled, this will be nil.
59+
EventsQueue workqueue.RateLimitingInterface
5560
}
5661

5762
//+kubebuilder:rbac:groups=policy.open-cluster-management.io,resources=policies,verbs=create;delete;get;list;patch;update;watch
@@ -88,6 +93,23 @@ func (r *PolicyReconciler) Reconcile(ctx context.Context, request reconcile.Requ
8893
// replicated policy on hub was deleted, remove policy on managed cluster
8994
reqLogger.Info("Policy was deleted, removing on managed cluster...")
9095

96+
managedPolicy := &policiesv1.Policy{}
97+
if r.EventsQueue != nil {
98+
err := r.ManagedClient.Get(
99+
ctx, types.NamespacedName{Namespace: r.TargetNamespace, Name: request.Name}, managedPolicy,
100+
)
101+
if errors.IsNotFound(err) {
102+
// The policy is already deleted on the managed cluster so there is nothing to delete
103+
return reconcile.Result{}, nil
104+
}
105+
106+
if err != nil {
107+
reqLogger.Error(err, "Failed to get the replicated policy on the managed cluster")
108+
109+
return reconcile.Result{}, err
110+
}
111+
}
112+
91113
err = r.ManagedClient.Delete(ctx, &policiesv1.Policy{
92114
TypeMeta: metav1.TypeMeta{
93115
Kind: policiesv1.Kind,
@@ -105,6 +127,32 @@ func (r *PolicyReconciler) Reconcile(ctx context.Context, request reconcile.Requ
105127
return reconcile.Result{}, err
106128
}
107129

130+
if r.EventsQueue != nil {
131+
for _, tmplEntry := range managedPolicy.Spec.PolicyTemplates {
132+
tmpl := &unstructured.Unstructured{}
133+
134+
err := tmpl.UnmarshalJSON(tmplEntry.ObjectDefinition.Raw)
135+
if err != nil {
136+
continue
137+
}
138+
139+
if tmpl.GetAnnotations()[utils.PolicyDBIDAnnotation] == "" {
140+
continue
141+
}
142+
143+
ce, err := utils.GenerateDisabledEvent(
144+
managedPolicy,
145+
tmpl,
146+
"The policy was removed because the parent policy no longer applies to this cluster",
147+
)
148+
if err != nil {
149+
log.Error(err, "Failed to generate a disabled compliance API event")
150+
} else {
151+
r.EventsQueue.Add(ce)
152+
}
153+
}
154+
}
155+
108156
reqLogger.Info("Policy has been removed from managed cluster...Reconciliation complete.")
109157

110158
return reconcile.Result{}, nil

0 commit comments

Comments
 (0)