{{- if not .Values.experimental.isolatedControlPlane.headless }}
{{- if or .Values.controlPlane.backingStore.etcd.deploy.enabled (include "vcluster.etcd.embedded.migrate" .) }}
{{- if .Values.controlPlane.backingStore.etcd.deploy.statefulSet.enabled }}
{{- $externalEtcd := .Values.controlPlane.backingStore.etcd.deploy.statefulSet }}
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: {{ .Release.Name }}-etcd
  namespace: {{ .Release.Namespace }}
  labels:
    app: vcluster-etcd
    chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
    release: "{{ .Release.Name }}"
    heritage: "{{ .Release.Service }}"
{{- if $externalEtcd.labels }}
{{ toYaml $externalEtcd.labels | indent 4 }}
{{- end }}
  {{- $annotations := merge dict .Values.controlPlane.advanced.globalMetadata.annotations $externalEtcd.annotations }}
  {{- if $annotations }}
  annotations:
{{ toYaml $annotations | indent 4 }}
  {{- end }}
spec:
  replicas: {{ $externalEtcd.highAvailability.replicas }}
  podManagementPolicy: {{ $externalEtcd.scheduling.podManagementPolicy }}
  serviceName: {{ .Release.Name }}-etcd-headless
  {{- if eq $externalEtcd.persistence.volumeClaim.retentionPolicy "Delete" }}
  {{- if ge (int .Capabilities.KubeVersion.Minor) 27 }}
  persistentVolumeClaimRetentionPolicy:
    whenDeleted: {{ $externalEtcd.persistence.volumeClaim.retentionPolicy }}
  {{- end }}
  {{- end }}
  selector:
    matchLabels:
      app: vcluster-etcd
      release: {{ .Release.Name }}
  {{- if $externalEtcd.persistence.volumeClaimTemplates }}
  volumeClaimTemplates:
{{ toYaml $externalEtcd.persistence.volumeClaimTemplates | indent 4 }}
  {{- else if $externalEtcd.persistence.volumeClaim.enabled }}
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: {{ $externalEtcd.persistence.volumeClaim.accessModes }}
        {{- if $externalEtcd.persistence.volumeClaim.storageClass }}
        storageClassName: {{ $externalEtcd.persistence.volumeClaim.storageClass }}
        {{- end }}
        resources:
          requests:
            storage: {{ $externalEtcd.persistence.volumeClaim.size }}
  {{- end }}
  template:
    metadata:
      {{- if $externalEtcd.pods.annotations }}
      annotations:
{{ toYaml $externalEtcd.pods.annotations | indent 8 }}
      {{- end }}
      labels:
        app: vcluster-etcd
        release: {{ .Release.Name }}
        {{- range $k, $v := $externalEtcd.pods.labels }}
        {{ $k }}: {{ $v | quote }}
        {{- end }}
    spec:
      terminationGracePeriodSeconds: 10
      {{- if $externalEtcd.scheduling.affinity }}
      affinity:
{{ toYaml $externalEtcd.scheduling.affinity | indent 8 }}
      {{- else }}
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          # if possible avoid scheduling more than one pod on one node
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - vcluster-etcd
                - key: release
                  operator: In
                  values:
                  - {{ .Release.Name }}
              topologyKey: "kubernetes.io/hostname"
          # if possible avoid scheduling pod onto node that is in the same zone as one or more vcluster pods are running
          - weight: 50
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - vcluster-etcd
                - key: release
                  operator: In
                  values:
                  - {{ .Release.Name }}
              topologyKey: topology.kubernetes.io/zone
      {{- end }}
      {{- if $externalEtcd.scheduling.topologySpreadConstraints }}
      topologySpreadConstraints:
{{ toYaml $externalEtcd.scheduling.topologySpreadConstraints | indent 8 }}
      {{- end }}
      nodeSelector:
{{ toYaml $externalEtcd.scheduling.nodeSelector | indent 8 }}
      tolerations:
{{ toYaml $externalEtcd.scheduling.tolerations | indent 8 }}
      automountServiceAccountToken: false
      {{- if .Values.controlPlane.advanced.serviceAccount.name }}
      serviceAccountName: {{ .Values.controlPlane.advanced.serviceAccount.name }}
      {{- else }}
      serviceAccountName: vc-{{ .Release.Name }}
      {{- end }}
      volumes:
        - name: certs
          secret:
            secretName: {{ .Release.Name }}-certs
      {{- if $externalEtcd.persistence.addVolumes }}
{{ toYaml $externalEtcd.persistence.addVolumes | indent 8 }}
      {{- end }}
      {{- if not $externalEtcd.persistence.volumeClaim.enabled }}
        - name: data
          emptyDir: {}
      {{- end }}
      {{- if $externalEtcd.scheduling.priorityClassName }}
      priorityClassName: {{ $externalEtcd.scheduling.priorityClassName }}
      {{- end }}
      {{- if $externalEtcd.security.podSecurityContext }}
      securityContext:
{{ toYaml $externalEtcd.security.podSecurityContext | indent 8 }}
      {{- end }}
      enableServiceLinks: {{ .Values.controlPlane.backingStore.etcd.deploy.statefulSet.enableServiceLinks }}
      containers:
      - name: etcd
        image: '{{ include "vcluster.image" (dict "defaultImageRegistry" .Values.controlPlane.advanced.defaultImageRegistry "registry" $externalEtcd.image.registry "repository" $externalEtcd.image.repository "tag" $externalEtcd.image.tag) }}'
        command:
          - etcd
          - '--cert-file=/run/config/pki/etcd-server.crt'
          - '--client-cert-auth=true'
          - '--data-dir=/var/lib/etcd'
          - '--advertise-client-urls=https://$(NAME).{{ .Release.Name }}-etcd-headless.{{ .Release.Namespace }}:2379'
          - '--initial-advertise-peer-urls=https://$(NAME).{{ .Release.Name }}-etcd-headless.{{ .Release.Namespace }}:2380'
          {{- $releaseName := .Release.Name -}}
          {{- $releaseNamespace := .Release.Namespace }}
          - '--initial-cluster={{ range $index := untilStep 0 (int $externalEtcd.highAvailability.replicas) 1 }}{{ if (ne (int $index) 0) }},{{ end }}{{ $releaseName }}-etcd-{{ $index }}=https://{{ $releaseName }}-etcd-{{ $index }}.{{ $releaseName }}-etcd-headless.{{ $releaseNamespace }}:2380{{ end }}'
          - '--initial-cluster-token={{ .Release.Name }}'
          - '--initial-cluster-state=new'
          - '--listen-client-urls=https://0.0.0.0:2379'
          - '--listen-metrics-urls=http://0.0.0.0:2381'
          - '--listen-peer-urls=https://0.0.0.0:2380'
          - '--key-file=/run/config/pki/etcd-server.key'
          - '--name=$(NAME)'
          - '--peer-cert-file=/run/config/pki/etcd-peer.crt'
          - '--peer-client-cert-auth=true'
          - '--peer-key-file=/run/config/pki/etcd-peer.key'
          - '--peer-trusted-ca-file=/run/config/pki/etcd-ca.crt'
          - '--snapshot-count=10000'
          - '--trusted-ca-file=/run/config/pki/etcd-ca.crt'
          {{- range $f := $externalEtcd.extraArgs }}
          - {{ $f | quote }}
          {{- end }}
        {{- if $externalEtcd.security.containerSecurityContext }}
        securityContext:
{{ toYaml $externalEtcd.security.containerSecurityContext | indent 10 }}
        {{- end }}
        env:
          - name: NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
        {{- if $externalEtcd.env }}
{{ toYaml $externalEtcd.env | indent 10 }}
        {{- end }}
        volumeMounts:
          - name: data
            mountPath: /var/lib/etcd
          - mountPath: /run/config/pki
            name: certs
            readOnly: true
        {{- if $externalEtcd.persistence.addVolumeMounts }}
{{ toYaml $externalEtcd.persistence.addVolumeMounts | indent 10 }}
        {{- end }}
        resources:
{{ toYaml $externalEtcd.resources | indent 10 }}
        livenessProbe:
          httpGet:
            path: /health
            port: 2381
            scheme: HTTP
          initialDelaySeconds: 10
          timeoutSeconds: 15
          periodSeconds: 10
          successThreshold: 1
          failureThreshold: 8
        startupProbe:
          httpGet:
            path: /health
            port: 2381
            scheme: HTTP
          initialDelaySeconds: 10
          timeoutSeconds: 15
          periodSeconds: 10
          successThreshold: 1
          failureThreshold: 24
        {{- if $externalEtcd.imagePullPolicy }}
        imagePullPolicy: {{ $externalEtcd.imagePullPolicy }}
        {{- end }}
{{- end }}
{{- end }}
{{- end }}
