apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: cluster-autoscaler
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
rules:
  - apiGroups: [""]
    resources: ["events", "endpoints"]
    verbs: ["create", "patch"]
  - apiGroups: [""]
    resources: ["pods/eviction"]
    verbs: ["create"]
  - apiGroups: [""]
    resources: ["pods/status"]
    verbs: ["update"]
  - apiGroups: [""]
    resources: ["endpoints"]
    resourceNames: ["cluster-autoscaler"]
    verbs: ["get", "update"]
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["watch", "list", "get", "update"]
  - apiGroups: [""]
    resources:
      - "namespaces"
      - "pods"
      - "services"
      - "replicationcontrollers"
      - "persistentvolumeclaims"
      - "persistentvolumes"
    verbs: ["watch", "list", "get"]
  - apiGroups: ["extensions"]
    resources: ["replicasets", "daemonsets"]
    verbs: ["watch", "list", "get"]
  - apiGroups: ["policy"]
    resources: ["poddisruptionbudgets"]
    verbs: ["watch", "list"]
  - apiGroups: ["apps"]
    resources: ["statefulsets", "replicasets", "daemonsets"]
    verbs: ["watch", "list", "get"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses", "csinodes", "csidrivers", "csistoragecapacities", "volumeattachments"]
    verbs: ["watch", "list", "get"]
  - apiGroups: ["batch", "extensions"]
    resources: ["jobs"]
    verbs: ["get", "list", "watch", "patch"]
  - apiGroups: ["coordination.k8s.io"]
    resources: ["leases"]
    verbs: ["create"]
  - apiGroups: ["coordination.k8s.io"]
    resourceNames: ["cluster-autoscaler"]
    resources: ["leases"]
    verbs: ["get", "update"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: cluster-autoscaler
  namespace: kube-system
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
rules:
  - apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["create", "list", "watch"]
  - apiGroups: [""]
    resources: ["configmaps"]
    resourceNames: ["cluster-autoscaler-status", "cluster-autoscaler-priority-expander"]
    verbs: ["delete", "get", "update", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: cluster-autoscaler
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-autoscaler
subjects:
  - kind: ServiceAccount
    name: cluster-autoscaler
    namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: cluster-autoscaler
  namespace: kube-system
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: cluster-autoscaler
subjects:
  - kind: ServiceAccount
    name: cluster-autoscaler
    namespace: kube-system
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: cluster-autoscaler-priority-expander
  namespace: kube-system
data:
  # Higher number wins. The zone tiers are load-bearing, not cosmetic: TiKV
  # primary replicas live in the primary zone, so a TiDB node scaled up in the
  # standby/witness zone turns every TiDB->TiKV read into billed cross-AZ
  # traffic. Keep every primary-zone tier strictly above every standby/witness
  # tier so the autoscaler only reaches for another zone once the primary zone
  # cannot take the pod at all.
  priorities: |-
    1:
      - .*
    20:
      - .*-{{ mustRegexReplaceAll "^.*-(.*)$" .Values.witnessZone "${1}" }}-.*{{ .Values.releaseTag }}*
    30:
      - .*-{{ mustRegexReplaceAll "^.*-(.*)$" .Values.standbyZone "${1}" }}-.*{{ .Values.releaseTag }}*
    40:
      - .*-{{ mustRegexReplaceAll "^.*-(.*)$" .Values.standbyZone "${1}" }}-tidb-od-[a-z0-9]+xl.*{{ .Values.releaseTag }}.*
    50:
      - .*-{{ mustRegexReplaceAll "^.*-(.*)$" .Values.standbyZone "${1}" }}-tidb-[a-z0-9]+xl.*{{ .Values.releaseTag }}.*
    79:
      - .*-{{ mustRegexReplaceAll "^.*-(.*)$" .Values.primaryZone "${1}" }}-.*{{ .Values.releaseTag }}*
    89:
      - .*-{{ mustRegexReplaceAll "^.*-(.*)$" .Values.primaryZone "${1}" }}-tidb-od-[a-z0-9]+xl.*{{ .Values.releaseTag }}.*
    99:
      - .*-{{ mustRegexReplaceAll "^.*-(.*)$" .Values.primaryZone "${1}" }}-tidb-[a-z0-9]+xl.*{{ .Values.releaseTag }}.*
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cluster-autoscaler
  namespace: kube-system
  labels:
    app: cluster-autoscaler
spec:
  replicas: 2
  selector:
    matchLabels:
      app: cluster-autoscaler
  template:
    metadata:
      labels:
        app: cluster-autoscaler
      annotations:
        prometheus.io/scrape: 'true'
        prometheus.io/port: '8085'
    spec:
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: serverless.tidbcloud.com/zone
          whenUnsatisfiable: DoNotSchedule
          labelSelector:
            matchLabels:
              app: cluster-autoscaler
      serviceAccountName: cluster-autoscaler
      priorityClassName: system-node-critical
      securityContext:
        runAsUser: 65532
      containers:
        - image: {{ .Values.caImage }}:{{ .Values.caVersion }}
          name: cluster-autoscaler
          resources:
            limits:
              cpu: 600m
              memory: 1500Mi
            requests:
              cpu: 200m
              memory: 500Mi
          command:
            - ./cluster-autoscaler
            - --v=4
            - --stderrthreshold=info
            - --cloud-provider=aws
            - --skip-nodes-with-local-storage=false
            - --skip-nodes-with-system-pods=false
            - --node-group-auto-discovery=asg:tag=kubernetes.io/cluster/{{ .Values.clusterName }}=owned
            # https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#im-running-cluster-with-nodes-in-multiple-zones-for-ha-purposes-is-that-supported-by-cluster-autoscaler
            - --balance-similar-node-groups
            - --balancing-label=serverless.tidbcloud.com/nodegroup
            - --balancing-label=serverless.tidbcloud.com/kubelet-version
            - --scale-down-utilization-threshold={{ .Values.downThreshold }}
            - --daemonset-eviction-for-occupied-nodes=false
            - --max-node-provision-time=2m
            - --max-total-unready-percentage=100
            {{- if eq .Values.caImage "registry.k8s.io/autoscaling/cluster-autoscaler" }}
            - --initial-node-group-backoff-duration=30m
            - --expander=priority
            {{- else }}
            - --cost-optimization-enabled={{ .Values.costOptimization }}
            - --expander=priority,alternatives
            {{- end }}
          volumeMounts:
            - name: ssl-certs
              mountPath: /etc/ssl/certs/ca-certificates.crt #/etc/ssl/certs/ca-bundle.crt for Amazon Linux Worker Nodes
              readOnly: true
          imagePullPolicy: "Always"
          securityContext:
            allowPrivilegeEscalation: false
      volumes:
        - name: ssl-certs
          hostPath:
            path: "/etc/ssl/certs/ca-bundle.crt"
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: cluster-autoscaler
  namespace: kube-system
spec:
  maxUnavailable: 1
  selector:
    matchLabels:
      app: cluster-autoscaler

