---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: pod-reaper
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: pod-reaper
rules:
  # Nodes
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["get", "list", "watch"]

  # Pods
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "list", "watch", "delete"]

  # Controllers (ownerRefs)
  - apiGroups: ["apps"]
    resources:
      - deployments
      - replicasets
      - statefulsets
      - daemonsets
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: pod-reaper
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: pod-reaper
subjects:
  - kind: ServiceAccount
    name: pod-reaper
    namespace: kube-system
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: pod-reaper
  namespace: kube-system
spec:
  selector:
    matchLabels:
      app: pod-reaper
  template:
    metadata:
      labels:
        app: pod-reaper
    spec:
      serviceAccountName: pod-reaper

      # 🔒 Do not schedule on NotReady nodes
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: kubernetes.io/hostname
                    operator: Exists

      tolerations:
        # Control-plane nodes
        - key: node-role.kubernetes.io/control-plane
          operator: Exists
          effect: NoSchedule
        - key: node-role.kubernetes.io/master
          operator: Exists
          effect: NoSchedule

        # Required so it keeps running while other pods are evicted
        - key: node.kubernetes.io/not-ready
          operator: Exists
          effect: NoExecute
        - key: node.kubernetes.io/unreachable
          operator: Exists
          effect: NoExecute

      containers:
        - name: pod-reaper
          image: allardkrings/pod-reaper:1.0
          imagePullPolicy: IfNotPresent

          env:
            - name: POD_REAPER_NOT_READY_GRACE
              value: "300"   # seconds
            - name: POD_REAPER_DRY_RUN
              value: "false" # set true to simulate

          resources:
            requests:
              cpu: 10m
              memory: 32Mi
            limits:
              cpu: 100m
              memory: 128Mi

          securityContext:
            runAsNonRoot: true
            runAsUser: 1000
            runAsGroup: 1000
            allowPrivilegeEscalation: false

      restartPolicy: Always
