{{- if (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) }}
{{- if not (list "legacy" "migration" "cluster" | has .Values.clustermesh.apiserver.tls.authMode) -}}
{{- fail ".Values.clustermesh.apiserver.tls.authMode must be one of legacy, migration, cluster" -}}
{{- end -}}
apiVersion: apps/v1
kind: Deployment
metadata:
  name: clustermesh-apiserver
  namespace: {{ .Release.Namespace }}
  {{- with .Values.clustermesh.annotations }}
  annotations:
    {{- toYaml . | nindent 4 }}
  {{- end }}
  labels:
    k8s-app: clustermesh-apiserver
    app.kubernetes.io/part-of: cilium
    app.kubernetes.io/name: clustermesh-apiserver
spec:
  replicas: {{ .Values.clustermesh.apiserver.replicas }}
  selector:
    matchLabels:
      k8s-app: clustermesh-apiserver
  {{- with .Values.clustermesh.apiserver.updateStrategy }}
  strategy:
    {{- toYaml . | nindent 4 }}
  {{- end }}
  template:
    metadata:
      annotations:
        {{- with .Values.clustermesh.apiserver.podAnnotations }}
        {{- toYaml . | nindent 8 }}
        {{- end }}
      labels:
        app.kubernetes.io/part-of: cilium
        app.kubernetes.io/name: clustermesh-apiserver
        k8s-app: clustermesh-apiserver
        {{- with .Values.clustermesh.apiserver.podLabels }}
        {{- toYaml . | nindent 8 }}
        {{- end }}
    spec:
      {{- with .Values.imagePullSecrets }}
      imagePullSecrets:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.clustermesh.apiserver.podSecurityContext }}
      securityContext:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      initContainers:
      - name: etcd-init
        image: {{ include "cilium.image" .Values.clustermesh.apiserver.etcd.image | quote }}
        imagePullPolicy: {{ .Values.clustermesh.apiserver.etcd.image.pullPolicy }}
        command: ["/bin/sh", "-c"]
        args:
        - |
          rm -rf /var/run/etcd/*;
          /usr/local/bin/etcd --data-dir=/var/run/etcd --name=clustermesh-apiserver --listen-client-urls=http://127.0.0.1:2379 --advertise-client-urls=http://127.0.0.1:2379 --initial-cluster-token=clustermesh-apiserver --initial-cluster-state=new --auto-compaction-retention=1 &

          # The following key needs to be created before that the cilium agents
          # have the possibility of connecting to etcd.
          etcdctl put cilium/.has-cluster-config true

          etcdctl user add root --no-password;
          etcdctl user grant-role root root;
          etcdctl user add admin-{{ .Values.cluster.name }} --no-password;
          etcdctl user grant-role admin-{{ .Values.cluster.name }} root;
          etcdctl user add externalworkload --no-password;
          etcdctl role add externalworkload;
          etcdctl role grant-permission externalworkload --from-key read '';
          etcdctl role grant-permission externalworkload readwrite --prefix cilium/state/noderegister/v1/;
          etcdctl role grant-permission externalworkload readwrite --prefix cilium/.initlock/;
          etcdctl user grant-role externalworkload externalworkload;
          etcdctl user add remote --no-password;
          etcdctl role add remote;
          etcdctl role grant-permission remote --from-key read '';
          etcdctl user grant-role remote remote;
          etcdctl auth enable;
          exit
        env:
        - name: ETCDCTL_API
          value: "3"
        - name: HOSTNAME_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        volumeMounts:
        - name: etcd-data-dir
          mountPath: /var/run/etcd
        terminationMessagePolicy: FallbackToLogsOnError
        {{- with .Values.clustermesh.apiserver.etcd.init.resources }}
        resources:
          {{- toYaml . | nindent 10 }}
        {{- end }}
      containers:
      - name: etcd
        image: {{ include "cilium.image" .Values.clustermesh.apiserver.etcd.image | quote }}
        imagePullPolicy: {{ .Values.clustermesh.apiserver.etcd.image.pullPolicy }}
        command:
        - /usr/local/bin/etcd
        args:
        - --data-dir=/var/run/etcd
        - --name=clustermesh-apiserver
        - --client-cert-auth
        - --trusted-ca-file=/var/lib/etcd-secrets/ca.crt
        - --cert-file=/var/lib/etcd-secrets/tls.crt
        - --key-file=/var/lib/etcd-secrets/tls.key
        # Surrounding the IPv4 address with brackets works in this case, since etcd
        # uses net.SplitHostPort() internally and it accepts the that format.
        - --listen-client-urls=https://127.0.0.1:2379,https://[$(HOSTNAME_IP)]:2379
        - --advertise-client-urls=https://[$(HOSTNAME_IP)]:2379
        - --initial-cluster-token=clustermesh-apiserver
        - --auto-compaction-retention=1
        {{- if .Values.clustermesh.apiserver.metrics.etcd.enabled }}
        - --listen-metrics-urls=http://[$(HOSTNAME_IP)]:{{ .Values.clustermesh.apiserver.metrics.etcd.port }}
        - --metrics={{ .Values.clustermesh.apiserver.metrics.etcd.mode }}
        {{- end }}
        env:
        - name: ETCDCTL_API
          value: "3"
        - name: HOSTNAME_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        ports:
        - name: etcd
          containerPort: 2379
          protocol: TCP
        {{- if .Values.clustermesh.apiserver.metrics.etcd.enabled }}
        - name: etcd-metrics
          containerPort: {{ .Values.clustermesh.apiserver.metrics.etcd.port }}
          protocol: TCP
        {{- end }}
        volumeMounts:
        - name: etcd-server-secrets
          mountPath: /var/lib/etcd-secrets
          readOnly: true
        - name: etcd-data-dir
          mountPath: /var/run/etcd
        terminationMessagePolicy: FallbackToLogsOnError
        {{- with .Values.clustermesh.apiserver.etcd.resources }}
        resources:
          {{- toYaml . | nindent 10 }}
        {{- end }}
        {{- with .Values.clustermesh.apiserver.etcd.securityContext }}
        securityContext:
          {{- toYaml . | nindent 10 }}
        {{- end }}
        {{- with .Values.clustermesh.apiserver.etcd.lifecycle }}
        lifecycle:
          {{- toYaml . | nindent 10 }}
        {{- end }}
      - name: apiserver
        image: {{ include "cilium.image" .Values.clustermesh.apiserver.image | quote }}
        imagePullPolicy: {{ .Values.clustermesh.apiserver.image.pullPolicy }}
        command:
        - /usr/bin/clustermesh-apiserver
        args:
        {{- if .Values.debug.enabled }}
        - --debug
        {{- end }}
        - --cluster-name=$(CLUSTER_NAME)
        - --cluster-id=$(CLUSTER_ID)
        - --kvstore-opt
        - etcd.config=/var/lib/cilium/etcd-config.yaml
        {{- if ne .Values.clustermesh.apiserver.tls.authMode "legacy" }}
        - --cluster-users-enabled
        - --cluster-users-config-path=/var/lib/cilium/etcd-config/users.yaml
        {{- end }}
        - --enable-external-workloads={{ .Values.externalWorkloads.enabled }}
        {{- if .Values.clustermesh.apiserver.metrics.enabled }}
        - --prometheus-serve-addr=:{{ .Values.clustermesh.apiserver.metrics.port }}
        - --controller-group-metrics=all
        {{- end }}
        {{- with .Values.clustermesh.apiserver.extraArgs }}
        {{- toYaml . | trim | nindent 8 }}
        {{- end }}
        env:
        - name: CLUSTER_NAME
          valueFrom:
            configMapKeyRef:
              name: cilium-config
              key: cluster-name
        - name: CLUSTER_ID
          valueFrom:
            configMapKeyRef:
              name: cilium-config
              key: cluster-id
              optional: true
        - name: IDENTITY_ALLOCATION_MODE
          valueFrom:
            configMapKeyRef:
              name: cilium-config
              key: identity-allocation-mode
        - name: ENABLE_K8S_ENDPOINT_SLICE
          valueFrom:
            configMapKeyRef:
              name: cilium-config
              key: enable-k8s-endpoint-slice
              optional: true
        {{- with .Values.clustermesh.apiserver.extraEnv }}
        {{- toYaml . | trim | nindent 8 }}
        {{- end }}
        {{- if .Values.clustermesh.apiserver.metrics.enabled }}
        ports:
        - name: apiserv-metrics
          containerPort: {{ .Values.clustermesh.apiserver.metrics.port }}
          protocol: TCP
        {{- end }}
        {{- with .Values.clustermesh.apiserver.resources }}
        resources:
          {{- toYaml . | nindent 10 }}
        {{- end }}
        volumeMounts:
        - name: etcd-admin-client
          mountPath: /var/lib/cilium/etcd-secrets
          readOnly: true
        {{- if ne .Values.clustermesh.apiserver.tls.authMode "legacy" }}
        - name: etcd-users-config
          mountPath: /var/lib/cilium/etcd-config
          readOnly: true
        {{- end }}
        {{- with .Values.clustermesh.apiserver.extraVolumeMounts }}
        {{- toYaml . | nindent 8 }}
        {{- end }}
        terminationMessagePolicy: FallbackToLogsOnError
        {{- with .Values.clustermesh.apiserver.securityContext }}
        securityContext:
          {{- toYaml . | nindent 10 }}
        {{- end }}
        {{- with .Values.clustermesh.apiserver.lifecycle }}
        lifecycle:
          {{- toYaml . | nindent 10 }}
        {{- end }}
      {{- if .Values.clustermesh.apiserver.kvstoremesh.enabled }}
      - name: kvstoremesh
        image: {{ include "cilium.image" .Values.clustermesh.apiserver.kvstoremesh.image | quote }}
        imagePullPolicy: {{ .Values.clustermesh.apiserver.kvstoremesh.image.pullPolicy }}
        command:
        - /usr/bin/kvstoremesh
        args:
        {{- if .Values.debug.enabled }}
        - --debug
        {{- end }}
        - --cluster-name=$(CLUSTER_NAME)
        - --cluster-id=$(CLUSTER_ID)
        - --kvstore-opt=etcd.config=/var/lib/cilium/etcd-config.yaml
        - --kvstore-opt=etcd.qps=100
        - --kvstore-opt=etcd.maxInflight=10
        - --clustermesh-config=/var/lib/cilium/clustermesh
        {{- if .Values.clustermesh.apiserver.metrics.kvstoremesh.enabled }}
        - --prometheus-serve-addr=:{{ .Values.clustermesh.apiserver.metrics.kvstoremesh.port }}
        - --controller-group-metrics=all
        {{- end }}
        {{- with .Values.clustermesh.apiserver.kvstoremesh.extraArgs }}
        {{- toYaml . | trim | nindent 8 }}
        {{- end }}
        env:
        - name: CLUSTER_NAME
          valueFrom:
            configMapKeyRef:
              name: cilium-config
              key: cluster-name
        - name: CLUSTER_ID
          valueFrom:
            configMapKeyRef:
              name: cilium-config
              key: cluster-id
        {{- with .Values.clustermesh.apiserver.kvstoremesh.extraEnv }}
        {{- toYaml . | trim | nindent 8 }}
        {{- end }}
        {{- if .Values.clustermesh.apiserver.metrics.kvstoremesh.enabled }}
        ports:
        - name: kvmesh-metrics
          containerPort: {{ .Values.clustermesh.apiserver.metrics.kvstoremesh.port }}
          protocol: TCP
        {{- end }}
        {{- with .Values.clustermesh.apiserver.kvstoremesh.resources }}
        resources:
          {{- toYaml . | nindent 10 }}
        {{- end }}
        volumeMounts:
        - name: etcd-admin-client
          mountPath: /var/lib/cilium/etcd-secrets
          readOnly: true
        - name: kvstoremesh-secrets
          mountPath: /var/lib/cilium/clustermesh
          readOnly: true
        {{- with .Values.clustermesh.apiserver.kvstoremesh.extraVolumeMounts }}
        {{- toYaml . | nindent 8 }}
        {{- end }}
        terminationMessagePolicy: FallbackToLogsOnError
        {{- with .Values.clustermesh.apiserver.kvstoremesh.securityContext }}
        securityContext:
          {{- toYaml . | nindent 10 }}
        {{- end }}
        {{- with .Values.clustermesh.apiserver.kvstoremesh.lifecycle }}
        lifecycle:
          {{- toYaml . | nindent 10 }}
        {{- end }}
      {{- end }}
      volumes:
      - name: etcd-server-secrets
        projected:
          # note: the leading zero means this number is in octal representation: do not remove it
          defaultMode: 0400
          sources:
          - secret:
              name: clustermesh-apiserver-server-cert
              items:
              - key: tls.crt
                path: tls.crt
              - key: tls.key
                path: tls.key
          {{- if not .Values.tls.caBundle.enabled }}
              - key: ca.crt
                path: ca.crt
          {{- else }}
          - {{ .Values.tls.caBundle.useSecret | ternary "secret" "configMap" }}:
              name: {{ .Values.tls.caBundle.name }}
              items:
              - key: {{ .Values.tls.caBundle.key }}
                path: ca.crt
          {{- end }}
      - name: etcd-admin-client
        projected:
          # note: the leading zero means this number is in octal representation: do not remove it
          defaultMode: 0400
          sources:
          - secret:
              name: clustermesh-apiserver-admin-cert
              items:
              - key: tls.crt
                path: tls.crt
              - key: tls.key
                path: tls.key
          {{- if not .Values.tls.caBundle.enabled }}
              - key: ca.crt
                path: ca.crt
          {{- else }}
          - {{ .Values.tls.caBundle.useSecret | ternary "secret" "configMap" }}:
              name: {{ .Values.tls.caBundle.name }}
              items:
              - key: {{ .Values.tls.caBundle.key }}
                path: ca.crt
          {{- end }}
      {{- if ne .Values.clustermesh.apiserver.tls.authMode "legacy" }}
      - name: etcd-users-config
        configMap:
          name: clustermesh-remote-users
          # note: the leading zero means this number is in octal representation: do not remove it
          defaultMode: 0400
      {{- end }}
      - name: etcd-data-dir
        emptyDir: {}
      {{- if .Values.clustermesh.apiserver.kvstoremesh.enabled }}
      - name: kvstoremesh-secrets
        projected:
          # note: the leading zero means this number is in octal representation: do not remove it
          defaultMode: 0400
          sources:
          - secret:
              name: cilium-kvstoremesh
              optional: true
              # note: items are not explicitly listed here, since the entries of this secret
              # depend on the peers configured, and that would cause a restart of this pod
              # at every addition/removal. Leaving the field empty makes each secret entry
              # to be automatically projected into the volume as a file whose name is the key.
          - secret:
              name: clustermesh-apiserver-remote-cert
              optional: true
              items:
              - key: tls.key
                path: common-etcd-client.key
              - key: tls.crt
                path: common-etcd-client.crt
              - key: ca.crt
                path: common-etcd-client-ca.crt
      {{- end }}
      {{- with .Values.clustermesh.apiserver.extraVolumes }}
      {{- toYaml . | nindent 6 }}
      {{- end }}
      restartPolicy: Always
      priorityClassName: {{ include "cilium.priorityClass" (list $ .Values.clustermesh.apiserver.priorityClassName "system-cluster-critical") }}
      serviceAccount: {{ .Values.serviceAccounts.clustermeshApiserver.name | quote }}
      serviceAccountName: {{ .Values.serviceAccounts.clustermeshApiserver.name | quote }}
      terminationGracePeriodSeconds: {{ .Values.clustermesh.apiserver.terminationGracePeriodSeconds }}
      automountServiceAccountToken: {{ .Values.serviceAccounts.clustermeshApiserver.automount }}
      {{- with .Values.clustermesh.apiserver.affinity }}
      affinity:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.clustermesh.apiserver.topologySpreadConstraints }}
      topologySpreadConstraints:
        {{- range $constraint := . }}
      - {{ toYaml $constraint | nindent 8 | trim }}
          {{- if not $constraint.labelSelector }}
        labelSelector:
          matchLabels:
            k8s-app: clustermesh-apiserver
          {{- end }}
        {{- end }}
      {{- end }}
      {{- with .Values.clustermesh.apiserver.nodeSelector }}
      nodeSelector:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.clustermesh.apiserver.tolerations }}
      tolerations:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- if and .Values.clustermesh.config.enabled .Values.clustermesh.apiserver.kvstoremesh.enabled }}
      hostAliases:
      {{- range $cluster := .Values.clustermesh.config.clusters }}
      {{- range $ip := $cluster.ips }}
      - ip: {{ $ip }}
        hostnames: [ "{{ $cluster.name }}.{{ $.Values.clustermesh.config.domain }}" ]
      {{- end }}
      {{- end }}
      {{- end }}
{{- end }}
