apiVersion: policy.open-cluster-management.io/v1
kind: Policy
metadata:
  name: policy-gatekeeper-replica-limits
  namespace: policies
spec:
  remediationAction: inform 
  disabled: false
  policy-templates:
    - objectDefinition:
        apiVersion: templates.gatekeeper.sh/v1beta1
        kind: ConstraintTemplate
        metadata:
          name: k8sreplicalimits
          annotations:
            metadata.gatekeeper.sh/title: "Replica Limits"
            metadata.gatekeeper.sh/version: 1.0.1
            description: >-
              Requires that objects with the field `spec.replicas` (Deployments,
              ReplicaSets, etc.) specify a number of replicas within defined ranges.
        spec:
          crd:
            spec:
              names:
                kind: K8sReplicaLimits
              validation:
                # Schema for the `parameters` field
                openAPIV3Schema:
                  type: object
                  properties:
                    ranges:
                      type: array
                      description: Allowed ranges for numbers of replicas.  Values are inclusive.
                      items:
                        type: object
                        description: A range of allowed replicas.  Values are inclusive.
                        properties:
                          min_replicas:
                            description: The minimum number of replicas allowed, inclusive.
                            type: integer
                          max_replicas:
                            description: The maximum number of replicas allowed, inclusive.
                            type: integer
          targets:
            - target: admission.k8s.gatekeeper.sh
              rego: |
                package k8sreplicalimits
        
                object_name = input.review.object.metadata.name
                object_kind = input.review.kind.kind
        
                violation[{"msg": msg}] {
                    spec := input.review.object.spec
                    not input_replica_limit(spec)
                    msg := sprintf("The provided number of replicas is not allowed for %v: %v. Allowed ranges: %v", [object_kind, object_name, input.parameters])
                }
        
                input_replica_limit(spec) {
                    provided := input.review.object.spec.replicas
                    count(input.parameters.ranges) > 0
                    range := input.parameters.ranges[_]
                    value_within_range(range, provided)
                }
        
                value_within_range(range, value) {
                    range.min_replicas <= value
                    range.max_replicas >= value
                }

    - objectDefinition:
        apiVersion: constraints.gatekeeper.sh/v1beta1
        kind: K8sReplicaLimits
        metadata:
          name: replica-limits
        spec:
          enforcementAction: warn
          match:
            kinds:
              - apiGroups: ["apps"]
                kinds: ["Deployment"]
            excludedNamespaces: 
              - "kube-*" 
              - "openshift-*"
              - "open-cluster-management-agent-addon"
              - "open-cluster-management*"
              - "multicluster-engine"
          parameters:
            ranges:
            - min_replicas: 3
              max_replicas: 50

---
apiVersion: policy.open-cluster-management.io/v1
kind: PlacementBinding
metadata:
  name: binding-policy-gatekeeper-replica-limits
  namespace: policies
placementRef:
  name: placement-policy-gatekeeper-replica-limits
  kind: PlacementRule
  apiGroup: apps.open-cluster-management.io
subjects:
- name: policy-gatekeeper-replica-limits
  kind: Policy
  apiGroup: policy.open-cluster-management.io
---
apiVersion: apps.open-cluster-management.io/v1
kind: PlacementRule
metadata:
  name: placement-policy-gatekeeper-replica-limits
  namespace: policies
spec:
  clusterSelector:
    matchExpressions:
      - key: local-cluster
        operator: In
        values:
          - 'true'
