# Cache Enforcer DaemonSet
# Installs iptables rules on runner nodes to block direct outbound access to
# external container registries and PyPI, forcing traffic through internal
# caches (Harbor at harbor:30002, pypi-cache at localhost:8080).
#
# Runs only on runner nodes (workload-type: github-runner).
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: cache-enforcer
  namespace: kube-system
  labels:
    osdc.io/module: cache-enforcer
    app: cache-enforcer
    app.kubernetes.io/name: cache-enforcer
    app.kubernetes.io/component: node-configuration
spec:
  selector:
    matchLabels:
      app: cache-enforcer

  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: "25%"

  template:
    metadata:
      labels:
        app: cache-enforcer

    spec:
      hostNetwork: true
      hostPID: true

      priorityClassName: system-node-critical

      # Tolerate every taint. The DS gates on its own node-init.osdc.io/
      # cache-enforcer startup taint AND must coexist with the other
      # node-init.osdc.io/* startup taints Karpenter emits — listing each
      # explicitly creates a chicken-and-egg deadlock if any sibling is
      # missed. `operator: Exists` matches every taint and avoids that
      # whole class of bug. Scheduling isolation is enforced by nodeAffinity
      # below (workload-type=github-runner AND not a release runner), not by
      # the toleration list.
      tolerations:
        - operator: Exists

      # Run on Karpenter-managed runner nodes only
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: workload-type
                    operator: In
                    values:
                      - github-runner
                  - key: osdc.io/runner-class
                    operator: DoesNotExist

      serviceAccountName: cache-enforcer

      initContainers:
        - name: enforce-cache
          image: public.ecr.aws/amazonlinux/amazonlinux:2023
          command: ["/bin/bash", "-c"]
          args:
            # Two-stage init:
            #   1. nsenter into the host mount/PID/IPC/uts/net NS and run the
            #      iptables script — modprobe + iptables + xt_string only
            #      work in the host's mount namespace where kernel modules
            #      are reachable.
            #   2. Back in the container's mount NS, call taint_remover.py
            #      from the node-taint-remover-lib ConfigMap mount and the
            #      in-cluster ServiceAccount token (neither is reachable
            #      from inside nsenter, where the host root is mounted).
            # stdin redirection on the nsenter line reads the script from
            # the container's ConfigMap mount before nsenter switches NS.
            - |
              set -e
              /proc/1/root/usr/bin/nsenter -t 1 -m -u -i -n -- /bin/bash < /scripts/enforce-cache.sh
              python3 /scripts/taint-remover/taint_remover.py node-init.osdc.io/cache-enforcer

          env:
            - name: NODE_NAME
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName

          securityContext:
            privileged: true

          volumeMounts:
            - name: scripts
              mountPath: /scripts
              readOnly: true
            - name: taint-remover-lib
              mountPath: /scripts/taint-remover
              readOnly: true

      containers:
        - name: sleep
          image: public.ecr.aws/docker/library/alpine:3.19
          command:
            - /bin/sh
            - -c
            - "echo 'Cache enforcer rules applied. Sleeping...'; sleep infinity"

          resources:
            requests:
              cpu: 10m
              memory: 32Mi
            limits:
              cpu: 50m
              memory: 64Mi

      volumes:
        - name: scripts
          configMap:
            name: cache-enforcer-script
            defaultMode: 0755

        - name: taint-remover-lib
          configMap:
            name: node-taint-remover-lib

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: cache-enforcer
  namespace: kube-system
  labels:
    osdc.io/module: cache-enforcer
    app: cache-enforcer
