A lightweight daemon that monitors OCM Policy compliance status on a managed cluster and reflects the result in a ClusterClaim.
It periodically checks all policies in a target namespace and updates a ClusterClaim resource with one of three states: compliant, noncompliant, or empty. The claim is only set to compliant after policies remain stable for a configurable duration, preventing transient flaps.
This component is used in the Optimization Using DSF workflow.
policy-watcher/
├── Dockerfile # Container image definition
├── README.md # This file
├── main.py # Main daemon loop (Kubernetes client)
├── pyproject.toml # Python project metadata and dependencies
└── deployment.yaml # Kubernetes Deployment/RBAC manifest (envsubst-based)
- On startup, connects to the Kubernetes API (in-cluster or via kubeconfig).
- Every
POLL_INTERVAL_SECseconds, lists all OCMPolicyresources inWATCH_NAMESPACE. - Determines the aggregate compliance state:
compliant— All policies areCompliant.noncompliant— At least one policy is notCompliant.empty— No policies exist in the namespace.
- For the
compliantstate, waitsSTABLE_DURATION_SECseconds of continuous compliance before updating theClusterClaim(debounce). - Updates the
ClusterClaim(TARGET_CLAIM_NAME) with the current state.
| Variable | Default | Description |
|---|---|---|
POLL_INTERVAL_SEC |
30 |
Polling interval in seconds |
STABLE_DURATION_SEC |
120 |
Duration (seconds) policies must remain compliant before claim is updated |
TARGET_CLAIM_NAME |
policy-watcher-claim |
Name of the ClusterClaim to update |
WATCH_NAMESPACE |
default |
Namespace to watch for OCM Policy resources |
cd samples/policy-watcher
podman build -t policy-watcher .podman run -d \
--name policy-watcher \
-v $HOME/.kube/config:/root/.kube/config:ro \
-e WATCH_NAMESPACE=cluster1 \
-e POLL_INTERVAL_SEC=10 \
--replace \
policy-watcherpodman logs -f policy-watcherThe deployment.yaml uses envsubst to inject the cluster name as the watch namespace.
export CLUSTER_NAME=cluster1
kind load docker-image quay.io/dynamic-scoring/policy-watcher:v0.1.0 --name $CLUSTER_NAME
CLUSTER_NAME=$CLUSTER_NAME envsubst < deployment.yaml | kubectl apply -f - --context kind-$CLUSTER_NAMERepeat for each managed cluster (e.g. cluster2).
kubectl get clusterclaims policy-watcher-claim --context kind-cluster1 -o yaml | grep value:
# Expected: value: empty | compliant | noncompliantThe deployment.yaml includes the required RBAC resources:
- ClusterRole —
get,listonpolicies.policy.open-cluster-management.io;get,patch,updateonclusterclaims.cluster.open-cluster-management.io. - ServiceAccount —
policy-watcher-saindynamic-scoringnamespace. - ClusterRoleBinding — Binds the above.