{{- $proxy := mustMergeOverwrite (mustDeepCopy .Values) .Values.proxy -}}
{{- $replicable := or $proxy.highAvailability.certManager.enabled $proxy.tls.existingSecretName -}}
{{- $projectedServiceAccountToken := semverCompare ">=1.20.0-0" .Capabilities.KubeVersion.Version }}
# Deployment is {{ if not $replicable }}not {{end}}replicable
{{- if and $proxy.highAvailability.certManager.enabled $proxy.tls.existingSecretName }}
{{- fail "Cannot set both highAvailability.certManager.enabled and tls.existingSecretName, choose one or the other" }}
{{- end }}
{{- if and $proxy.acme $proxy.tls.existingSecretName }}
{{- fail "Cannot set both acme.enabled and tls.existingSecretName, choose one or the other" }}
{{- end }}
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-proxy
  namespace: {{ .Release.Namespace }}
  labels: {{- include "teleport-cluster.proxy.labels" . | nindent 4 }}
{{- if $proxy.annotations.deployment }}
  annotations: {{- toYaml $proxy.annotations.deployment | nindent 4 }}
{{- end }}
spec:
{{- /*
  If proxies cannot be replicated we use a single replica.
  By default we want to upgrade all users to at least 2 replicas, if they had a higher replica count we take it.
  If a user wants to force a single proxy, they can use the `proxy` specific override.

  $proxySpecificHA is a hack to avoid .Values.proxy.highAvailability to be nil, which would cause a fail when
  accessing .Values.proxy.highAvailability.replicaCount.
*/}}
{{- if $replicable }}
  {{- $proxySpecificHA := default (dict) .Values.proxy.highAvailability }}
  {{- if $proxySpecificHA.replicaCount }}
  replicas: {{ $proxySpecificHA.replicaCount }}
  {{- else }}
  replicas: {{ max .Values.highAvailability.replicaCount 2 }}
  {{- end }}
  {{- if $proxy.highAvailability.minReadySeconds }}
  minReadySeconds: {{ $proxy.highAvailability.minReadySeconds }}
  {{- end }}
{{- else }}
  replicas: 1
{{- end }}
  selector:
    matchLabels: {{- include "teleport-cluster.proxy.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      annotations:
        # ConfigMap checksum, to recreate the pod on config changes.
        checksum/config: {{ include (print $.Template.BasePath "/proxy/config.yaml") . | sha256sum }}
{{- if $proxy.annotations.pod }}
  {{- toYaml $proxy.annotations.pod | nindent 8 }}
{{- end }}
      labels: {{- include "teleport-cluster.proxy.labels" . | nindent 8 }}
    spec:
{{- if $proxy.nodeSelector }}
      nodeSelector: {{- toYaml $proxy.nodeSelector | nindent 8 }}
{{- end }}
      affinity:
{{- if $proxy.affinity }}
  {{- if $proxy.highAvailability.requireAntiAffinity }}
    {{- fail "Cannot use highAvailability.requireAntiAffinity when affinity is also set in chart values - unset one or the other" }}
  {{- end }}
  {{- toYaml $proxy.affinity | nindent 8 }}
{{- else }}
        podAntiAffinity:
  {{- if $proxy.highAvailability.requireAntiAffinity }}
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app.kubernetes.io/instance
                operator: In
                values:
                  - {{ .Release.Name }}
              - key: app.kubernetes.io/component
                operator: In
                values:
                - proxy
            topologyKey: "kubernetes.io/hostname"
  {{- else if gt (int $proxy.highAvailability.replicaCount) 1 }}
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 50
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app.kubernetes.io/instance
                  operator: In
                  values:
                    - {{ .Release.Name }}
                - key: app.kubernetes.io/component
                  operator: In
                  values:
                    - proxy
              topologyKey: "kubernetes.io/hostname"
  {{- end }}
{{- end }}
{{- if $proxy.tolerations }}
      tolerations: {{- toYaml $proxy.tolerations | nindent 6 }}
{{- end }}
{{- if $proxy.imagePullSecrets }}
      imagePullSecrets:
  {{- toYaml $proxy.imagePullSecrets | nindent 6 }}
{{- end }}
      initContainers:
        # wait-auth-update is responsible for holding off the proxy rollout until all auths are running the
        # next major version in case of major upgrade.
        - name: wait-auth-update
          image: '{{ if $proxy.enterprise }}{{ $proxy.enterpriseImage }}{{ else }}{{ $proxy.image }}{{ end }}:{{ include "teleport-cluster.version" . }}'
          command:
            - teleport
            - wait
            - no-resolve
            - '{{ include "teleport-cluster.auth.previousVersionServiceName" . }}.{{ .Release.Namespace }}.svc.cluster.local'
{{- if $proxy.securityContext }}
          securityContext: {{- toYaml $proxy.securityContext | nindent 12 }}
{{- end }}
{{- if $proxy.initContainers }}
  {{- range $initContainer := $proxy.initContainers }}
    {{- if and (not $initContainer.resources) $proxy.resources }}
      {{- $_ := set $initContainer "resources" $proxy.resources }}
    {{- end }}
    {{- list $initContainer | toYaml | nindent 8 }}
    {{- /* Note: this will break if the user sets volumeMounts to its initContainer */}}
          volumeMounts:
    {{- if or $proxy.highAvailability.certManager.enabled $proxy.tls.existingSecretName }}
          - mountPath: /etc/teleport-tls
            name: "teleport-tls"
            readOnly: true
    {{- end }}
          - mountPath: /etc/teleport
            name: "config"
            readOnly: true
          - mountPath: /var/lib/teleport
            name: "data"
    {{- if $proxy.extraVolumeMounts }}
      {{- toYaml $proxy.extraVolumeMounts | nindent 10 }}
    {{- end }}
  {{- end }}
{{- end }}
      containers:
      - name: "teleport"
        image: '{{ if $proxy.enterprise }}{{ $proxy.enterpriseImage }}{{ else }}{{ $proxy.image }}{{ end }}:{{ include "teleport-cluster.version" . }}'
        imagePullPolicy: {{ $proxy.imagePullPolicy }}
        {{- if or $proxy.extraEnv $proxy.tls.existingCASecretName }}
        env:
        {{- if (gt (len $proxy.extraEnv) 0) }}
          {{- toYaml $proxy.extraEnv | nindent 8 }}
        {{- end }}
        {{- if $proxy.tls.existingCASecretName }}
        - name: SSL_CERT_FILE
          value: /etc/teleport-tls-ca/ca.pem
        {{- end }}
        {{- end }}
        args:
        - "--diag-addr=0.0.0.0:3000"
        {{- if $proxy.insecureSkipProxyTLSVerify }}
        - "--insecure"
        {{- end }}
        {{- if $proxy.extraArgs }}
          {{- toYaml $proxy.extraArgs | nindent 8 }}
        {{- end }}
        ports:
        - name: tls
          containerPort: 3080
          protocol: TCP
        {{- if $proxy.enterprise }}
        - name: proxypeering
          containerPort: 3021
          protocol: TCP
        {{- end }}
        {{- if ne $proxy.proxyListenerMode "multiplex" }}
        - name: sshproxy
          containerPort: 3023
          protocol: TCP
        - name: sshtun
          containerPort: 3024
          protocol: TCP
        - name: kube
          containerPort: 3026
          protocol: TCP
        - name: mysql
          containerPort: 3036
          protocol: TCP
        {{- if $proxy.separatePostgresListener }}
        - name: postgres
          containerPort: 5432
          protocol: TCP
        {{- end }}
        {{- if $proxy.separateMongoListener }}
        - name: mongo
          containerPort: 27017
          protocol: TCP
        {{- end }}
        {{- end }}
        - name: diag
          containerPort: 3000
          protocol: TCP
        livenessProbe:
          httpGet:
            path: /healthz
            port: diag
          initialDelaySeconds: 5 # wait 5s for agent to start
          periodSeconds: 5 # poll health every 5s
          failureThreshold: 6 # consider agent unhealthy after 30s (6 * 5s)
          timeoutSeconds: {{ $proxy.probeTimeoutSeconds }}
        readinessProbe:
          httpGet:
            path: /readyz
            port: diag
          initialDelaySeconds: 5 # wait 5s for agent to register
          periodSeconds: 5 # poll health every 5s
          failureThreshold: 12 # consider agent unhealthy after 60s (12 * 5s)
          timeoutSeconds: {{ $proxy.probeTimeoutSeconds }}
        lifecycle:
          # waiting during preStop ensures no new request will hit the Terminating pod
          # on clusters using kube-proxy (kube-proxy syncs the node iptables rules every 30s)
          preStop:
            exec:
              command:
                - teleport
                - wait
                - duration
                - 30s
{{- if $proxy.postStart.command }}
          postStart:
            exec:
              command: {{ toYaml $proxy.postStart.command | nindent 14 }}
{{- end }}
{{- if $proxy.resources }}
        resources:
  {{- toYaml $proxy.resources | nindent 10 }}
{{- end }}
{{- if $proxy.securityContext }}
        securityContext: {{- toYaml $proxy.securityContext | nindent 10 }}
{{- end }}
        volumeMounts:
{{- if or $proxy.highAvailability.certManager.enabled $proxy.tls.existingSecretName }}
        - mountPath: /etc/teleport-tls
          name: "teleport-tls"
          readOnly: true
{{- end }}
{{- if $proxy.tls.existingCASecretName }}
        - mountPath: /etc/teleport-tls-ca
          name: "teleport-tls-ca"
          readOnly: true
{{- end }}
        - mountPath: /etc/teleport
          name: "config"
          readOnly: true
        - mountPath: /var/lib/teleport
          name: "data"
{{- if $projectedServiceAccountToken }}
        - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
          name: proxy-serviceaccount-token
          readOnly: true
{{- end }}
{{- if $proxy.extraVolumeMounts }}
  {{- toYaml $proxy.extraVolumeMounts | nindent 8 }}
{{- end }}
{{- if $proxy.extraContainers }}
  {{- toYaml $proxy.extraContainers | nindent 6 }}
{{- end }}
{{- if $projectedServiceAccountToken }}
      automountServiceAccountToken: false
{{- end }}
      volumes:
{{- if $projectedServiceAccountToken }}
      # This projected token volume mimics the `automountServiceAccountToken`
      # behaviour but defaults to a 1h TTL instead of 1y.
      - name: proxy-serviceaccount-token
        projected:
          sources:
            - serviceAccountToken:
                path: token
            - configMap:
                items:
                - key: ca.crt
                  path: ca.crt
                name: kube-root-ca.crt
            - downwardAPI:
                items:
                  - path: "namespace"
                    fieldRef:
                      fieldPath: metadata.namespace
{{- end }}
{{- if $proxy.highAvailability.certManager.enabled }}
      - name: teleport-tls
        secret:
          secretName: teleport-tls
{{- else if $proxy.tls.existingSecretName }}
      - name: teleport-tls
        secret:
          secretName: {{ $proxy.tls.existingSecretName }}
{{- end }}
{{- if $proxy.tls.existingCASecretName }}
      - name: teleport-tls-ca
        secret:
          secretName: {{ $proxy.tls.existingCASecretName }}
{{- end }}
      - name: "config"
        configMap:
          name: {{ .Release.Name }}-proxy
      - name: "data"
        emptyDir: {}
{{- if $proxy.extraVolumes }}
  {{- toYaml $proxy.extraVolumes | nindent 6 }}
{{- end }}
{{- if $proxy.priorityClassName }}
      priorityClassName: {{ $proxy.priorityClassName }}
{{- end }}
      serviceAccountName: {{ include "teleport-cluster.proxy.serviceAccountName" . }}
      terminationGracePeriodSeconds: {{ $proxy.terminationGracePeriodSeconds }}
