kind: ConfigMap
apiVersion: v1
metadata:
  namespace: openshift-kube-proxy
  name: proxy-config
data:
  kube-proxy-config.yaml: |-
{{.KubeProxyConfig | indent 4}}

---
kind: DaemonSet
apiVersion: apps/v1
metadata:
  name: openshift-kube-proxy
  namespace: openshift-kube-proxy
  annotations:
    kubernetes.io/description: |
      This daemonset is the kubernetes service proxy (kube-proxy).
    release.openshift.io/version: "{{.ReleaseVersion}}"
spec:
  selector:
    matchLabels:
      app: kube-proxy
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: kube-proxy
        component: network
        type: infra
        openshift.io/component: network
    spec:
      serviceAccountName: openshift-kube-proxy
      hostNetwork: true
      priorityClassName: system-node-critical
      containers:
      - name: kube-proxy
        image: {{.KubeProxyImage}}
        command:
        - /bin/bash
        - -c
        - exec /usr/bin/kube-proxy --config=/config/kube-proxy-config.yaml --hostname-override "${K8S_NODE_NAME}"
        securityContext:
          privileged: true
        env:
        # Tell kube-proxy to talk to the apiserver directly.
        - name: KUBERNETES_SERVICE_PORT
          value: "{{.KUBERNETES_SERVICE_PORT}}"
        - name: KUBERNETES_SERVICE_HOST
          value: "{{.KUBERNETES_SERVICE_HOST}}"
        - name: K8S_NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        volumeMounts:
        # Because we don't actually run iptables locally, but chroot in to the host
        - mountPath: /host
          name: host-slash
          readOnly: true
          mountPropagation: HostToContainer
        - mountPath: /config
          name: config
          readOnly: true
        terminationMessagePolicy: FallbackToLogsOnError
        ports:
        - name: healthz
          containerPort: {{.HealthzPort}}
        livenessProbe:
          httpGet:
            path: /healthz
            port: healthz
        readinessProbe:
          httpGet:
            path: /healthz
            port: healthz
          initialDelaySeconds: 5
          periodSeconds: 5
        resources:
          requests:
            cpu: 100m
            memory: 200Mi
      - name: kube-rbac-proxy
        image: {{.KubeRBACProxyImage}}
        command:
        - /bin/bash
        - -c
        - |
          #!/bin/bash
          set -euo pipefail
          TLS_PK=/etc/pki/tls/metrics-certs/tls.key
          TLS_CERT=/etc/pki/tls/metrics-certs/tls.crt

          # As the secret mount is optional we must wait for the files to be present.
          # The service is created in monitor.yaml and this is created in kube-proxy.yaml.
          # If it isn't created there is probably an issue so we want to crashloop.
          retries=0
          while [[ "${retries}" -lt 100 ]]; do
            TS=$(
              curl \
                -s \
                --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
                -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
                "https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}/api/v1/namespaces/openshift-kube-proxy/services/openshift-kube-proxy" |
                  python -c 'import json,sys; print(json.load(sys.stdin)["metadata"]["creationTimestamp"])' 2>/dev/null || true
            )
            if [ -n "${TS}" ]; then
              break
            fi
            (( retries += 1 ))
            echo $(date -Iseconds) INFO: Failed to get openshift-kube-proxy service from API. Retry "${retries}"/100 1>&2
            sleep 20
          done
          if [ "${retries}" -ge 20 ]; then
            echo $(date -Iseconds) FATAL: Unable to get openshift-kube-proxy service from API.
            exit 1
          fi

          TS=$(date -d "${TS}" +%s)
          WARN_TS=$(( ${TS} + $(( 20 * 60)) ))
          HAS_LOGGED_INFO=0

          log_missing_certs(){
              CUR_TS=$(date +%s)
              if [[ "${CUR_TS}" -gt "WARN_TS"  ]]; then
                echo $(date -Iseconds) WARN: kube-proxy-metrics-certs not mounted after 20 minutes.
              elif [[ "${HAS_LOGGED_INFO}" -eq 0 ]] ; then
                echo $(date -Iseconds) INFO: kube-proxy-metrics-certs not mounted. Waiting 20 minutes.
                HAS_LOGGED_INFO=1
              fi
          }

          while [[ ! -f "${TLS_PK}" ||  ! -f "${TLS_CERT}" ]] ; do
            log_missing_certs
            sleep 5
          done

          exec /usr/bin/kube-rbac-proxy \
            --logtostderr \
            --secure-listen-address=:{{.MetricsPort}} \
            --tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 \
            --upstream=http://127.0.0.1:29102/ \
            --tls-private-key-file=${TLS_PK} \
            --tls-cert-file=${TLS_CERT}
        ports:
        - containerPort: {{.MetricsPort}}
          name: https
        resources:
          requests:
            cpu: 10m
            memory: 20Mi
        terminationMessagePolicy: FallbackToLogsOnError
        volumeMounts:
        - name: kube-proxy-metrics-certs
          mountPath: /etc/pki/tls/metrics-certs
          readOnly: True
      restartPolicy: Always
      tolerations:
      - operator: Exists
      nodeSelector:
        kubernetes.io/os: linux
      volumes:
      - name: host-slash
        hostPath:
          path: /
      - name: config
        configMap:
          name: proxy-config
      # Must be optional because the sdn-metrics-certs is a service serving
      # certificate and those cannot be generated without the service proxy
      # running
      - name: kube-proxy-metrics-certs
        secret:
          secretName: kube-proxy-metrics-certs
          optional: true
