diff --git a/artifacthub/library/general/poddisruptionbudget/1.0.5/artifacthub-pkg.yml b/artifacthub/library/general/poddisruptionbudget/1.0.5/artifacthub-pkg.yml new file mode 100644 index 000000000..1416d6ba0 --- /dev/null +++ b/artifacthub/library/general/poddisruptionbudget/1.0.5/artifacthub-pkg.yml @@ -0,0 +1,25 @@ +version: 1.0.5 +name: k8spoddisruptionbudget +displayName: Pod Disruption Budget +createdAt: "2026-06-23T11:44:53Z" +description: |- + Disallow the following scenarios when deploying PodDisruptionBudgets or resources that implement the replica subresource (e.g. Deployment, ReplicationController, ReplicaSet, StatefulSet): 1. Deployment of PodDisruptionBudgets with .spec.maxUnavailable == 0 2. Deployment of PodDisruptionBudgets with .spec.minAvailable == .spec.replicas of the resource with replica subresource This will prevent PodDisruptionBudgets from blocking voluntary disruptions such as node draining. + https://kubernetes.io/docs/concepts/workloads/pods/disruptions/ +digest: 3a184a16d293c7c23740cce1101f28b03c9edf0d4af6d91195f4ad96062e4061 +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/poddisruptionbudget +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # Pod Disruption Budget + Disallow the following scenarios when deploying PodDisruptionBudgets or resources that implement the replica subresource (e.g. Deployment, ReplicationController, ReplicaSet, StatefulSet): 1. Deployment of PodDisruptionBudgets with .spec.maxUnavailable == 0 2. Deployment of PodDisruptionBudgets with .spec.minAvailable == .spec.replicas of the resource with replica subresource This will prevent PodDisruptionBudgets from blocking voluntary disruptions such as node draining. + https://kubernetes.io/docs/concepts/workloads/pods/disruptions/ +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/general/poddisruptionbudget/1.0.5/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/general/poddisruptionbudget/1.0.5/kustomization.yaml b/artifacthub/library/general/poddisruptionbudget/1.0.5/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/general/poddisruptionbudget/1.0.5/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/constraint.yaml b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/constraint.yaml new file mode 100644 index 000000000..d378a1841 --- /dev/null +++ b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/constraint.yaml @@ -0,0 +1,13 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPodDisruptionBudget +metadata: + name: pod-distruption-budget +spec: + match: + kinds: + - apiGroups: ["apps"] + kinds: ["Deployment", "StatefulSet"] + - apiGroups: ["policy"] + kinds: ["PodDisruptionBudget"] + - apiGroups: [""] + kinds: ["ReplicationController"] diff --git a/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_allowed_deployment1.yaml b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_allowed_deployment1.yaml new file mode 100644 index 000000000..6b70a8932 --- /dev/null +++ b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_allowed_deployment1.yaml @@ -0,0 +1,24 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment-allowed-1 + namespace: default + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + example: allowed-deployment-1 + template: + metadata: + labels: + app: nginx + example: allowed-deployment-1 + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_allowed_deployment2.yaml b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_allowed_deployment2.yaml new file mode 100644 index 000000000..ae96d99a9 --- /dev/null +++ b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_allowed_deployment2.yaml @@ -0,0 +1,24 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment-allowed-2 + namespace: default + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + example: allowed-deployment-2 + template: + metadata: + labels: + app: nginx + example: allowed-deployment-2 + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_allowed_deployment3.yaml b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_allowed_deployment3.yaml new file mode 100644 index 000000000..154f44484 --- /dev/null +++ b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_allowed_deployment3.yaml @@ -0,0 +1,24 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment-allowed-3 + namespace: default + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + example: allowed-deployment-3 + template: + metadata: + labels: + app: nginx + example: allowed-deployment-3 + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_allowed_deployment4.yaml b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_allowed_deployment4.yaml new file mode 100644 index 000000000..7c2d2e8ed --- /dev/null +++ b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_allowed_deployment4.yaml @@ -0,0 +1,24 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment-allowed-4 + namespace: default + labels: + app: non-matching-nginx +spec: + replicas: 1 + selector: + matchLabels: + app: non-matching-nginx + example: allowed-deployment-4 + template: + metadata: + labels: + app: non-matching-nginx + example: allowed-deployment-4 + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_allowed_pdb.yaml b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_allowed_pdb.yaml new file mode 100644 index 000000000..f860777fb --- /dev/null +++ b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_allowed_pdb.yaml @@ -0,0 +1,10 @@ +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: nginx-pdb-allowed + namespace: default +spec: + maxUnavailable: 1 + selector: + matchLabels: + foo: bar diff --git a/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_disallowed_deployment.yaml b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_disallowed_deployment.yaml new file mode 100644 index 000000000..76044a6c9 --- /dev/null +++ b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_disallowed_deployment.yaml @@ -0,0 +1,24 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment-disallowed + namespace: default + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + example: disallowed-deployment + template: + metadata: + labels: + app: nginx + example: disallowed-deployment + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_disallowed_pdb.yaml b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_disallowed_pdb.yaml new file mode 100644 index 000000000..41d0b9162 --- /dev/null +++ b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_disallowed_pdb.yaml @@ -0,0 +1,10 @@ +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: nginx-pdb-disallowed + namespace: default +spec: + maxUnavailable: 0 + selector: + matchLabels: + foo: bar diff --git a/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_inventory_allowed1.yaml b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_inventory_allowed1.yaml new file mode 100644 index 000000000..df1cd233e --- /dev/null +++ b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_inventory_allowed1.yaml @@ -0,0 +1,11 @@ +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: inventory-nginx-pdb-allowed-1 + namespace: default +spec: + minAvailable: 2 + selector: + matchLabels: + app: nginx + example: allowed-deployment-1 diff --git a/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_inventory_allowed2.yaml b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_inventory_allowed2.yaml new file mode 100644 index 000000000..e4ccb63be --- /dev/null +++ b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_inventory_allowed2.yaml @@ -0,0 +1,11 @@ +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: inventory-nginx-pdb-allowed-2 + namespace: default +spec: + maxUnavailable: 1 + selector: + matchLabels: + app: nginx + example: allowed-deployment-2 diff --git a/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_inventory_allowed3.yaml b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_inventory_allowed3.yaml new file mode 100644 index 000000000..18a0eeb47 --- /dev/null +++ b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_inventory_allowed3.yaml @@ -0,0 +1,10 @@ +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: inventory-nginx-pdb-allowed-3 + namespace: default +spec: + minAvailable: 2 + selector: + matchLabels: + app: nginx diff --git a/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_inventory_allowed4.yaml b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_inventory_allowed4.yaml new file mode 100644 index 000000000..90f150163 --- /dev/null +++ b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_inventory_allowed4.yaml @@ -0,0 +1,11 @@ +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: inventory-mongo-pdb-allowed-3 + namespace: default +spec: + minAvailable: 2 + selector: + matchLabels: + app: mongo + example: non-matching-deployment-3 diff --git a/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_inventory_disallowed.yaml b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_inventory_disallowed.yaml new file mode 100644 index 000000000..a35c58b48 --- /dev/null +++ b/artifacthub/library/general/poddisruptionbudget/1.0.5/samples/poddisruptionbudget/example_inventory_disallowed.yaml @@ -0,0 +1,11 @@ +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: inventory-nginx-pdb-disallowed + namespace: default +spec: + minAvailable: 3 + selector: + matchLabels: + app: nginx + example: disallowed-deployment diff --git a/artifacthub/library/general/poddisruptionbudget/1.0.5/suite.yaml b/artifacthub/library/general/poddisruptionbudget/1.0.5/suite.yaml new file mode 100644 index 000000000..0e30d6b35 --- /dev/null +++ b/artifacthub/library/general/poddisruptionbudget/1.0.5/suite.yaml @@ -0,0 +1,47 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: poddisruptionbudget +tests: +- name: pod-disruption-budget + template: template.yaml + constraint: samples/poddisruptionbudget/constraint.yaml + cases: + - name: example-allowed-pdb + object: samples/poddisruptionbudget/example_allowed_pdb.yaml + assertions: + - violations: no + - name: example-disallowed-pdb + object: samples/poddisruptionbudget/example_disallowed_pdb.yaml + assertions: + - violations: yes + - name: example-allowed-min-available + object: samples/poddisruptionbudget/example_allowed_deployment1.yaml + inventory: + - samples/poddisruptionbudget/example_inventory_allowed1.yaml + assertions: + - violations: no + - name: example-allowed-max-unavailable + object: samples/poddisruptionbudget/example_allowed_deployment2.yaml + inventory: + - samples/poddisruptionbudget/example_inventory_allowed2.yaml + assertions: + - violations: no + - name: example-allowed-subset-selector + object: samples/poddisruptionbudget/example_allowed_deployment3.yaml + inventory: + - samples/poddisruptionbudget/example_inventory_allowed3.yaml + assertions: + - violations: no + - name: example-allowed-nomatch-selector + object: samples/poddisruptionbudget/example_allowed_deployment4.yaml + inventory: + - samples/poddisruptionbudget/example_inventory_allowed4.yaml + assertions: + - violations: no + - name: example-disallowed-min-available + object: samples/poddisruptionbudget/example_disallowed_deployment.yaml + inventory: + - samples/poddisruptionbudget/example_inventory_disallowed.yaml + assertions: + - violations: yes diff --git a/artifacthub/library/general/poddisruptionbudget/1.0.5/sync.yaml b/artifacthub/library/general/poddisruptionbudget/1.0.5/sync.yaml new file mode 100644 index 000000000..0977d2904 --- /dev/null +++ b/artifacthub/library/general/poddisruptionbudget/1.0.5/sync.yaml @@ -0,0 +1,11 @@ +apiVersion: config.gatekeeper.sh/v1alpha1 +kind: Config +metadata: + name: config + namespace: "gatekeeper-system" +spec: + sync: + syncOnly: + - group: "policy" + version: "v1" + kind: "PodDisruptionBudget" diff --git a/artifacthub/library/general/poddisruptionbudget/1.0.5/template.yaml b/artifacthub/library/general/poddisruptionbudget/1.0.5/template.yaml new file mode 100644 index 000000000..cfe51d843 --- /dev/null +++ b/artifacthub/library/general/poddisruptionbudget/1.0.5/template.yaml @@ -0,0 +1,90 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8spoddisruptionbudget + annotations: + metadata.gatekeeper.sh/title: "Pod Disruption Budget" + metadata.gatekeeper.sh/version: 1.0.5 + metadata.gatekeeper.sh/requires-sync-data: | + "[ + [ + { + "groups":["policy"], + "versions": ["v1"], + "kinds": ["PodDisruptionBudget"] + } + ] + ]" + description: >- + Disallow the following scenarios when deploying PodDisruptionBudgets or resources that implement the replica subresource (e.g. Deployment, ReplicationController, ReplicaSet, StatefulSet): + 1. Deployment of PodDisruptionBudgets with .spec.maxUnavailable == 0 + 2. Deployment of PodDisruptionBudgets with .spec.minAvailable == .spec.replicas of the resource with replica subresource + This will prevent PodDisruptionBudgets from blocking voluntary disruptions such as node draining. + + https://kubernetes.io/docs/concepts/workloads/pods/disruptions/ +spec: + crd: + spec: + names: + kind: K8sPodDisruptionBudget + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8spoddisruptionbudget + + violation[{"msg": msg}] { + input.review.kind.kind == "PodDisruptionBudget" + pdb := input.review.object + + not valid_pdb_max_unavailable(pdb) + msg := sprintf( + "PodDisruptionBudget <%v> has maxUnavailable of 0, only positive integers are allowed for maxUnavailable", + [pdb.metadata.name], + ) + } + + violation[{"msg": msg}] { + obj := input.review.object + pdb := data.inventory.namespace[obj.metadata.namespace]["policy/v1"].PodDisruptionBudget[_] + + matchLabels := { [label, value] | some label; value := pdb.spec.selector.matchLabels[label] } + labels := { [label, value] | some label; value := obj.spec.template.metadata.labels[label] } + count(matchLabels - labels) == 0 + + not valid_pdb_max_unavailable(pdb) + msg := sprintf( + "%v <%v> has been selected by PodDisruptionBudget <%v> but has maxUnavailable of 0, only positive integers are allowed for maxUnavailable", + [obj.kind, obj.metadata.name, pdb.metadata.name], + ) + } + + violation[{"msg": msg}] { + obj := input.review.object + pdb := data.inventory.namespace[obj.metadata.namespace]["policy/v1"].PodDisruptionBudget[_] + + matchLabels := { [label, value] | some label; value := pdb.spec.selector.matchLabels[label] } + labels := { [label, value] | some label; value := obj.spec.template.metadata.labels[label] } + count(matchLabels - labels) == 0 + + not valid_pdb_min_available(obj, pdb) + msg := sprintf( + "%v <%v> has %v replica(s) but PodDisruptionBudget <%v> has minAvailable of %v, PodDisruptionBudget count should always be lower than replica(s), and not used when replica(s) is set to 1", + [obj.kind, obj.metadata.name, obj.spec.replicas, pdb.metadata.name, pdb.spec.minAvailable], + ) + } + + valid_pdb_min_available(obj, pdb) { + # default to -1 if minAvailable is not set so valid_pdb_min_available is always true + # for objects with >= 0 replicas. If minAvailable defaults to >= 0, objects with + # replicas field might violate this constraint if they are equal to the default set here + min_available := object.get(pdb.spec, "minAvailable", -1) + obj.spec.replicas > min_available + } + + valid_pdb_max_unavailable(pdb) { + # default to 1 if maxUnavailable is not set so valid_pdb_max_unavailable always returns true. + # If maxUnavailable defaults to 0, it violates this constraint because all pods needs to be + # available and no pods can be evicted voluntarily + max_unavailable := object.get(pdb.spec, "maxUnavailable", 1) + max_unavailable > 0 + } diff --git a/library/general/poddisruptionbudget/template.yaml b/library/general/poddisruptionbudget/template.yaml index c06d3d647..9cac73907 100644 --- a/library/general/poddisruptionbudget/template.yaml +++ b/library/general/poddisruptionbudget/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8spoddisruptionbudget annotations: metadata.gatekeeper.sh/title: "Pod Disruption Budget" - metadata.gatekeeper.sh/version: 1.0.4 + metadata.gatekeeper.sh/version: 1.0.5 metadata.gatekeeper.sh/requires-sync-data: | "[ [ @@ -48,7 +48,7 @@ spec: pdb := data.inventory.namespace[obj.metadata.namespace]["policy/v1"].PodDisruptionBudget[_] matchLabels := { [label, value] | some label; value := pdb.spec.selector.matchLabels[label] } - labels := { [label, value] | some label; value := obj.spec.selector.matchLabels[label] } + labels := { [label, value] | some label; value := obj.spec.template.metadata.labels[label] } count(matchLabels - labels) == 0 not valid_pdb_max_unavailable(pdb) @@ -63,7 +63,7 @@ spec: pdb := data.inventory.namespace[obj.metadata.namespace]["policy/v1"].PodDisruptionBudget[_] matchLabels := { [label, value] | some label; value := pdb.spec.selector.matchLabels[label] } - labels := { [label, value] | some label; value := obj.spec.selector.matchLabels[label] } + labels := { [label, value] | some label; value := obj.spec.template.metadata.labels[label] } count(matchLabels - labels) == 0 not valid_pdb_min_available(obj, pdb) diff --git a/src/general/poddisruptionbudget/constraint.tmpl b/src/general/poddisruptionbudget/constraint.tmpl index 4ec6be3ff..e370e8b4c 100644 --- a/src/general/poddisruptionbudget/constraint.tmpl +++ b/src/general/poddisruptionbudget/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8spoddisruptionbudget annotations: metadata.gatekeeper.sh/title: "Pod Disruption Budget" - metadata.gatekeeper.sh/version: 1.0.4 + metadata.gatekeeper.sh/version: 1.0.5 metadata.gatekeeper.sh/requires-sync-data: | "[ [ diff --git a/src/general/poddisruptionbudget/src.rego b/src/general/poddisruptionbudget/src.rego index cb3376739..5ca2975d6 100644 --- a/src/general/poddisruptionbudget/src.rego +++ b/src/general/poddisruptionbudget/src.rego @@ -16,7 +16,7 @@ violation[{"msg": msg}] { pdb := data.inventory.namespace[obj.metadata.namespace]["policy/v1"].PodDisruptionBudget[_] matchLabels := { [label, value] | some label; value := pdb.spec.selector.matchLabels[label] } - labels := { [label, value] | some label; value := obj.spec.selector.matchLabels[label] } + labels := { [label, value] | some label; value := obj.spec.template.metadata.labels[label] } count(matchLabels - labels) == 0 not valid_pdb_max_unavailable(pdb) @@ -31,7 +31,7 @@ violation[{"msg": msg}] { pdb := data.inventory.namespace[obj.metadata.namespace]["policy/v1"].PodDisruptionBudget[_] matchLabels := { [label, value] | some label; value := pdb.spec.selector.matchLabels[label] } - labels := { [label, value] | some label; value := obj.spec.selector.matchLabels[label] } + labels := { [label, value] | some label; value := obj.spec.template.metadata.labels[label] } count(matchLabels - labels) == 0 not valid_pdb_min_available(obj, pdb) diff --git a/src/general/poddisruptionbudget/src_test.rego b/src/general/poddisruptionbudget/src_test.rego index 73f1327cf..0b50225f7 100644 --- a/src/general/poddisruptionbudget/src_test.rego +++ b/src/general/poddisruptionbudget/src_test.rego @@ -7,6 +7,8 @@ match_labels := {"matchLabels": { "key2": "val2", }} +labels := object.union(match_labels["matchLabels"], {"key3": "val3"}) + test_input_pdb_0_max_unavailable { inp := {"review": input_pdb_max_unavailable(0)} results := violation with input as inp @@ -47,6 +49,13 @@ test_input_deployment_pdb_1_max_unavailable { count(results) == 0 } +test_input_deployment_pdb_matches_template_labels_not_selector { + inp := {"review": input_deployment_with_selector(1, match_labels["matchLabels"])} + inv := inv_pdb_min_available_with_selector(1, {"matchLabels": {"key3": "val3"}}) + results := violation with input as inp with data.inventory as inv + count(results) == 1 +} + pdb_min_available(min_available) = output { output := { "apiVersion": "policy/v1", @@ -62,6 +71,21 @@ pdb_min_available(min_available) = output { } } +pdb_min_available_with_selector(min_available, selector) = output { + output := { + "apiVersion": "policy/v1", + "kind": "PodDisruptionBudget", + "metadata": { + "name": "pdb-1", + "namespace": "namespace-1", + }, + "spec": { + "selector": selector, + "minAvailable": min_available, + }, + } +} + pdb_max_unavailable(max_unavailable) = output { output := { "apiVersion": "policy/v1", @@ -77,6 +101,28 @@ pdb_max_unavailable(max_unavailable) = output { } } +deployment_with_selector(replicas, selector) = output { + output := { + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "name": "deployment-1", + "namespace": "namespace-1", + }, + "spec": { + "replicas": replicas, + "selector": { + "matchLabels": selector, + }, + "template": { + "metadata": { + "labels": labels, + } + } + }, + } +} + deployment(replicas) = output { output := { "apiVersion": "apps/v1", @@ -87,11 +133,22 @@ deployment(replicas) = output { }, "spec": { "replicas": replicas, - "selector": match_labels, + "template": { + "metadata": { + "labels": labels, + } + } }, } } +input_deployment_with_selector(replicas, selector) = output { + output := { + "kind": {"kind": "Deployment"}, + "object": deployment_with_selector(replicas, selector), + } +} + input_pdb_max_unavailable(max_unavailable) = output { output := { "kind": {"kind": "PodDisruptionBudget"}, @@ -115,6 +172,11 @@ inv_pdb_min_available(min_available) = output { output := inventory(pdb) } +inv_pdb_min_available_with_selector(min_available, selector) = output { + pdb = pdb_min_available_with_selector(min_available, selector) + output := inventory(pdb) +} + inv_pdb_max_unavailable(max_unavailable) = output { pdb = pdb_max_unavailable(max_unavailable) output := inventory(pdb) diff --git a/website/docs/validation/poddisruptionbudget.md b/website/docs/validation/poddisruptionbudget.md index 77f75ea70..32a764505 100644 --- a/website/docs/validation/poddisruptionbudget.md +++ b/website/docs/validation/poddisruptionbudget.md @@ -17,7 +17,7 @@ metadata: name: k8spoddisruptionbudget annotations: metadata.gatekeeper.sh/title: "Pod Disruption Budget" - metadata.gatekeeper.sh/version: 1.0.4 + metadata.gatekeeper.sh/version: 1.0.5 metadata.gatekeeper.sh/requires-sync-data: | "[ [ @@ -61,7 +61,7 @@ spec: pdb := data.inventory.namespace[obj.metadata.namespace]["policy/v1"].PodDisruptionBudget[_] matchLabels := { [label, value] | some label; value := pdb.spec.selector.matchLabels[label] } - labels := { [label, value] | some label; value := obj.spec.selector.matchLabels[label] } + labels := { [label, value] | some label; value := obj.spec.template.metadata.labels[label] } count(matchLabels - labels) == 0 not valid_pdb_max_unavailable(pdb) @@ -76,7 +76,7 @@ spec: pdb := data.inventory.namespace[obj.metadata.namespace]["policy/v1"].PodDisruptionBudget[_] matchLabels := { [label, value] | some label; value := pdb.spec.selector.matchLabels[label] } - labels := { [label, value] | some label; value := obj.spec.selector.matchLabels[label] } + labels := { [label, value] | some label; value := obj.spec.template.metadata.labels[label] } count(matchLabels - labels) == 0 not valid_pdb_min_available(obj, pdb)