From 3a64e7faa4fdfb31aedf40dc5b91d42035e0ae6e Mon Sep 17 00:00:00 2001
From: Eric <ericpaulsen@coder.com>
Date: Mon, 21 Oct 2024 13:59:36 +0000
Subject: [PATCH 1/5] helm: add topologySpreadConstraints value

---
 helm/coder/values.yaml              | 11 ++++++++++-
 helm/libcoder/templates/_coder.yaml |  4 ++++
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/helm/coder/values.yaml b/helm/coder/values.yaml
index 5ecb28e6b9b42..3c9449e33aeec 100644
--- a/helm/coder/values.yaml
+++ b/helm/coder/values.yaml
@@ -47,7 +47,7 @@ coder:
     # if not set. If you're using the chart directly from git, the default
     # app version will not work and you'll need to set this value. The helm
     # chart helpfully fails quickly in this case.
-    tag: ""
+    tag: "v2.15.0"
     # coder.image.pullPolicy -- The pull policy to use for the image. See:
     # https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy
     pullPolicy: IfNotPresent
@@ -236,6 +236,15 @@ coder:
             topologyKey: kubernetes.io/hostname
           weight: 1
 
+  # coder.topologySpreadConstraints -- Topology spread constraints for the Coder pod.
+  topologySpreadConstraints:
+    - maxSkew: 1
+      topologyKey: kubernetes.io/hostname
+      whenUnsatisfiable: DoNotSchedule
+      labelSelector:
+        matchLabels:
+          app: coder
+
   # coder.tolerations -- Tolerations for tainted nodes.
   # See: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
   tolerations:
diff --git a/helm/libcoder/templates/_coder.yaml b/helm/libcoder/templates/_coder.yaml
index 77cdbb2a3dfe5..926f6d3776cc9 100644
--- a/helm/libcoder/templates/_coder.yaml
+++ b/helm/libcoder/templates/_coder.yaml
@@ -43,6 +43,10 @@ spec:
       nodeSelector:
       {{ toYaml . | nindent 8 }}
       {{- end }}
+      {{- with .Values.coder.topologySpreadConstraints }}
+      topologySpreadConstraints:
+      {{- toYaml .Values.coder.topologySpreadConstraints | nindent 8 }}
+      {{- end }}
       {{- with .Values.coder.initContainers }}
       initContainers:
       {{ toYaml . | nindent 8 }}

From 1f7b964241917a62a1595d0a5c481cfc84150a5b Mon Sep 17 00:00:00 2001
From: Eric <ericpaulsen@coder.com>
Date: Mon, 21 Oct 2024 14:33:13 +0000
Subject: [PATCH 2/5] rm values

---
 helm/coder/values.yaml | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/helm/coder/values.yaml b/helm/coder/values.yaml
index 3c9449e33aeec..d705f087e8d37 100644
--- a/helm/coder/values.yaml
+++ b/helm/coder/values.yaml
@@ -47,7 +47,7 @@ coder:
     # if not set. If you're using the chart directly from git, the default
     # app version will not work and you'll need to set this value. The helm
     # chart helpfully fails quickly in this case.
-    tag: "v2.15.0"
+    tag: ""
     # coder.image.pullPolicy -- The pull policy to use for the image. See:
     # https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy
     pullPolicy: IfNotPresent
@@ -236,14 +236,14 @@ coder:
             topologyKey: kubernetes.io/hostname
           weight: 1
 
-  # coder.topologySpreadConstraints -- Topology spread constraints for the Coder pod.
   topologySpreadConstraints:
-    - maxSkew: 1
-      topologyKey: kubernetes.io/hostname
-      whenUnsatisfiable: DoNotSchedule
-      labelSelector:
-        matchLabels:
-          app: coder
+    []
+    # - maxSkew: 1
+    #   topologyKey: kubernetes.io/hostname
+    #   whenUnsatisfiable: DoNotSchedule
+    #   labelSelector:
+    #     matchLabels:
+    #       app.kubernetes.io/instance: coder
 
   # coder.tolerations -- Tolerations for tainted nodes.
   # See: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/

From 008b8d9157dbd6bd7beb8d44cede0324488b8fc4 Mon Sep 17 00:00:00 2001
From: Eric <ericpaulsen@coder.com>
Date: Tue, 22 Oct 2024 16:42:30 +0000
Subject: [PATCH 3/5] toYaml .

---
 helm/coder/values.yaml              | 2 +-
 helm/libcoder/templates/_coder.yaml | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/helm/coder/values.yaml b/helm/coder/values.yaml
index d705f087e8d37..24ed91b6d087f 100644
--- a/helm/coder/values.yaml
+++ b/helm/coder/values.yaml
@@ -47,7 +47,7 @@ coder:
     # if not set. If you're using the chart directly from git, the default
     # app version will not work and you'll need to set this value. The helm
     # chart helpfully fails quickly in this case.
-    tag: ""
+    tag: "v2.15.0"
     # coder.image.pullPolicy -- The pull policy to use for the image. See:
     # https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy
     pullPolicy: IfNotPresent
diff --git a/helm/libcoder/templates/_coder.yaml b/helm/libcoder/templates/_coder.yaml
index 926f6d3776cc9..183d85091f44a 100644
--- a/helm/libcoder/templates/_coder.yaml
+++ b/helm/libcoder/templates/_coder.yaml
@@ -45,7 +45,7 @@ spec:
       {{- end }}
       {{- with .Values.coder.topologySpreadConstraints }}
       topologySpreadConstraints:
-      {{- toYaml .Values.coder.topologySpreadConstraints | nindent 8 }}
+      {{- toYaml . | nindent 8 }}
       {{- end }}
       {{- with .Values.coder.initContainers }}
       initContainers:

From 11b1af0f9fb00212ea8be6c2c60e30c27242e8c6 Mon Sep 17 00:00:00 2001
From: Eric <ericpaulsen@coder.com>
Date: Tue, 22 Oct 2024 17:01:21 +0000
Subject: [PATCH 4/5] rm tag

---
 helm/coder/values.yaml | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/helm/coder/values.yaml b/helm/coder/values.yaml
index 24ed91b6d087f..17a647a908141 100644
--- a/helm/coder/values.yaml
+++ b/helm/coder/values.yaml
@@ -47,7 +47,7 @@ coder:
     # if not set. If you're using the chart directly from git, the default
     # app version will not work and you'll need to set this value. The helm
     # chart helpfully fails quickly in this case.
-    tag: "v2.15.0"
+    tag: ""
     # coder.image.pullPolicy -- The pull policy to use for the image. See:
     # https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy
     pullPolicy: IfNotPresent
@@ -237,7 +237,6 @@ coder:
           weight: 1
 
   topologySpreadConstraints:
-    []
     # - maxSkew: 1
     #   topologyKey: kubernetes.io/hostname
     #   whenUnsatisfiable: DoNotSchedule

From e744e17bb2365d8451569fbbf10d85084c277b2d Mon Sep 17 00:00:00 2001
From: Ethan Dickson <ethan@coder.com>
Date: Thu, 24 Oct 2024 10:34:56 +0000
Subject: [PATCH 5/5] add test

---
 helm/coder/tests/chart_test.go            |   4 +
 helm/coder/tests/testdata/topology.golden | 197 ++++++++++++++++++++++
 helm/coder/tests/testdata/topology.yaml   |  10 ++
 3 files changed, 211 insertions(+)
 create mode 100644 helm/coder/tests/testdata/topology.golden
 create mode 100644 helm/coder/tests/testdata/topology.yaml

diff --git a/helm/coder/tests/chart_test.go b/helm/coder/tests/chart_test.go
index c04e075da6e43..76436f37d58e8 100644
--- a/helm/coder/tests/chart_test.go
+++ b/helm/coder/tests/chart_test.go
@@ -92,6 +92,10 @@ var testCases = []testCase{
 		name:          "sa_disabled",
 		expectedError: "",
 	},
+	{
+		name:          "topology",
+		expectedError: "",
+	},
 }
 
 type testCase struct {
diff --git a/helm/coder/tests/testdata/topology.golden b/helm/coder/tests/testdata/topology.golden
new file mode 100644
index 0000000000000..5f6bb512a30a6
--- /dev/null
+++ b/helm/coder/tests/testdata/topology.golden
@@ -0,0 +1,197 @@
+---
+# Source: coder/templates/coder.yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  annotations: {}
+  labels:
+    app.kubernetes.io/instance: release-name
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/name: coder
+    app.kubernetes.io/part-of: coder
+    app.kubernetes.io/version: 0.1.0
+    helm.sh/chart: coder-0.1.0
+  name: coder
+---
+# Source: coder/templates/rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: coder-workspace-perms
+rules:
+  - apiGroups: [""]
+    resources: ["pods"]
+    verbs:
+    - create
+    - delete
+    - deletecollection
+    - get
+    - list
+    - patch
+    - update
+    - watch
+  - apiGroups: [""]
+    resources: ["persistentvolumeclaims"]
+    verbs:
+    - create
+    - delete
+    - deletecollection
+    - get
+    - list
+    - patch
+    - update
+    - watch
+  - apiGroups:
+    - apps
+    resources:
+    - deployments
+    verbs:
+    - create
+    - delete
+    - deletecollection
+    - get
+    - list
+    - patch
+    - update
+    - watch
+---
+# Source: coder/templates/rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: "coder"
+subjects:
+  - kind: ServiceAccount
+    name: "coder"
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: coder-workspace-perms
+---
+# Source: coder/templates/service.yaml
+apiVersion: v1
+kind: Service
+metadata:
+  name: coder
+  labels:
+    helm.sh/chart: coder-0.1.0
+    app.kubernetes.io/name: coder
+    app.kubernetes.io/instance: release-name
+    app.kubernetes.io/part-of: coder
+    app.kubernetes.io/version: "0.1.0"
+    app.kubernetes.io/managed-by: Helm
+  annotations:
+    {}
+spec:
+  type: LoadBalancer
+  sessionAffinity: None
+  ports:
+    - name: "http"
+      port: 80
+      targetPort: "http"
+      protocol: TCP
+      
+  externalTrafficPolicy: "Cluster"
+  selector:
+    app.kubernetes.io/name: coder
+    app.kubernetes.io/instance: release-name
+---
+# Source: coder/templates/coder.yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  annotations: {}
+  labels:
+    app.kubernetes.io/instance: release-name
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/name: coder
+    app.kubernetes.io/part-of: coder
+    app.kubernetes.io/version: 0.1.0
+    helm.sh/chart: coder-0.1.0
+  name: coder
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app.kubernetes.io/instance: release-name
+      app.kubernetes.io/name: coder
+  template:
+    metadata:
+      annotations: {}
+      labels:
+        app.kubernetes.io/instance: release-name
+        app.kubernetes.io/managed-by: Helm
+        app.kubernetes.io/name: coder
+        app.kubernetes.io/part-of: coder
+        app.kubernetes.io/version: 0.1.0
+        helm.sh/chart: coder-0.1.0
+    spec:
+      affinity:
+        podAntiAffinity:
+          preferredDuringSchedulingIgnoredDuringExecution:
+          - podAffinityTerm:
+              labelSelector:
+                matchExpressions:
+                - key: app.kubernetes.io/instance
+                  operator: In
+                  values:
+                  - coder
+              topologyKey: kubernetes.io/hostname
+            weight: 1
+      containers:
+      - args:
+        - server
+        command:
+        - /opt/coder
+        env:
+        - name: CODER_HTTP_ADDRESS
+          value: 0.0.0.0:8080
+        - name: CODER_PROMETHEUS_ADDRESS
+          value: 0.0.0.0:2112
+        - name: CODER_ACCESS_URL
+          value: http://coder.default.svc.cluster.local
+        - name: KUBE_POD_IP
+          valueFrom:
+            fieldRef:
+              fieldPath: status.podIP
+        - name: CODER_DERP_SERVER_RELAY_URL
+          value: http://$(KUBE_POD_IP):8080
+        image: ghcr.io/coder/coder:latest
+        imagePullPolicy: IfNotPresent
+        lifecycle: {}
+        livenessProbe:
+          httpGet:
+            path: /healthz
+            port: http
+            scheme: HTTP
+        name: coder
+        ports:
+        - containerPort: 8080
+          name: http
+          protocol: TCP
+        readinessProbe:
+          httpGet:
+            path: /healthz
+            port: http
+            scheme: HTTP
+        resources: {}
+        securityContext:
+          allowPrivilegeEscalation: false
+          readOnlyRootFilesystem: null
+          runAsGroup: 1000
+          runAsNonRoot: true
+          runAsUser: 1000
+          seccompProfile:
+            type: RuntimeDefault
+        volumeMounts: []
+      restartPolicy: Always
+      serviceAccountName: coder
+      terminationGracePeriodSeconds: 60
+      topologySpreadConstraints:
+      - labelSelector:
+          matchLabels:
+            app.kubernetes.io/instance: coder
+        maxSkew: 1
+        topologyKey: kubernetes.io/hostname
+        whenUnsatisfiable: DoNotSchedule
+      volumes: []
diff --git a/helm/coder/tests/testdata/topology.yaml b/helm/coder/tests/testdata/topology.yaml
new file mode 100644
index 0000000000000..b74ab42d37e87
--- /dev/null
+++ b/helm/coder/tests/testdata/topology.yaml
@@ -0,0 +1,10 @@
+coder:
+  image:
+    tag: latest
+  topologySpreadConstraints:
+    - maxSkew: 1
+      topologyKey: kubernetes.io/hostname
+      whenUnsatisfiable: DoNotSchedule
+      labelSelector:
+        matchLabels:
+          app.kubernetes.io/instance: coder