diff --git a/helm/coder/values.yaml b/helm/coder/values.yaml index 17a647a908141..75c7dda7742ba 100644 --- a/helm/coder/values.yaml +++ b/helm/coder/values.yaml @@ -113,7 +113,7 @@ coder: annotations: {} # coder.serviceAccount.name -- The service account name name: coder - # coder.serviceAccount.name -- Whether to create the service account or use existing service account + # coder.serviceAccount.disableCreate -- Whether to create the service account or use existing service account. disableCreate: false # coder.securityContext -- Fields related to the container's security diff --git a/helm/provisioner/README.md b/helm/provisioner/README.md index 33d9772658662..e1ea1f5aaf44c 100644 --- a/helm/provisioner/README.md +++ b/helm/provisioner/README.md @@ -32,5 +32,118 @@ coder: value: "0.0.0.0:2112" replicaCount: 10 provisionerDaemon: - pskSecretName: "coder-provisioner-psk" + keySecretName: "coder-provisionerd-key" + keySecretKey: "provisionerd-key" ``` + +## Specific Examples + +Below are some common specific use-cases when deploying a Coder provisioner. + +### Set Labels and Annotations + +If you need to set deployment- or pod-level labels and annotations, set `coder.{annotations,labels}` or `coder.{podAnnotations,podLabels}`. + +Example: + +```yaml +coder: + # ... + annotations: + com.coder/annotation/foo: bar + com.coder/annotation/baz: qux + labels: + com.coder/label/foo: bar + com.coder/label/baz: qux + podAnnotations: + com.coder/podAnnotation/foo: bar + com.coder/podAnnotation/baz: qux + podLabels: + com.coder/podLabel/foo: bar + com.coder/podLabel/baz: qux +``` + +### Additional Templates + +You can include extra Kubernetes manifests in `extraTemplates`. + +The below example will also create a `ConfigMap` along with the Helm release: + +```yaml +coder: + # ... +provisionerDaemon: + # ... +extraTemplates: + - | + apiVersion: v1 + kind: ConfigMap + metadata: + name: some-config + namespace: {{ .Release.Namespace }} + data: + key: some-value +``` + +### Disable Service Account Creation + +### Deploying multiple provisioners in the same namespace + +To deploy multiple provisioners in the same namespace, set the following values explicitly to avoid conflicts: + +- `nameOverride`: controls the name of the provisioner deployment +- `serviceAccount.name`: controls the name of the service account. + +Note that `nameOverride` does not apply to `extraTemplates`, as illustrated below: + +```yaml +coder: + # ... + serviceAccount: + name: other-coder-provisioner +provisionerDaemon: + # ... +nameOverride: "other-coder-provisioner" +extraTemplates: + - | + apiVersion: v1 + kind: ConfigMap + metadata: + name: some-other-config + namespace: {{ .Release.Namespace }} + data: + key: some-other-value +``` + +If you wish to deploy a second provisioner that references an existing service account, you can do so as follows: + +- Set `coder.serviceAccount.disableCreate=true` to disable service account creation, +- Set `coder.serviceAccount.workspacePerms=false` to disable creation of a role and role binding, +- Set `coder.serviceAccount.nameOverride` to the name of an existing service account. + +See below for a concrete example: + +```yaml +coder: + # ... + serviceAccount: + name: preexisting-service-account + disableCreate: true + workspacePerms: false +provisionerDaemon: + # ... +nameOverride: "other-coder-provisioner" +``` + +# Testing + +The test suite for this chart lives in `./tests/chart_test.go`. + +Each test case runs `helm template` against the corresponding `test_case.yaml`, and compares the output with that of the corresponding `test_case.golden` in `./tests/testdata`. +If `expectedError` is not empty for that specific test case, no corresponding `.golden` file is required. + +To add a new test case: + +- Create an appropriately named `.yaml` file in `testdata/` along with a corresponding `.golden` file, if required. +- Add the test case to the array in `chart_test.go`, setting `name` to the name of the files you added previously (without the extension). If appropriate, set `expectedError`. +- Run the tests and ensure that no regressions in existing test cases occur: `go test ./tests`. diff --git a/helm/provisioner/templates/coder.yaml b/helm/provisioner/templates/coder.yaml index 65eaac00ac001..da809e877e42f 100644 --- a/helm/provisioner/templates/coder.yaml +++ b/helm/provisioner/templates/coder.yaml @@ -1,5 +1,7 @@ --- +{{- if not .Values.coder.serviceAccount.disableCreate }} {{ include "libcoder.serviceaccount" (list . "coder.serviceaccount") }} +{{- end }} --- {{ include "libcoder.deployment" (list . "coder.deployment") }} diff --git a/helm/provisioner/tests/chart_test.go b/helm/provisioner/tests/chart_test.go index 4bb54e2d787ed..0c27771ce369a 100644 --- a/helm/provisioner/tests/chart_test.go +++ b/helm/provisioner/tests/chart_test.go @@ -78,6 +78,18 @@ var testCases = []testCase{ name: "extra_templates", expectedError: "", }, + { + name: "sa_disabled", + expectedError: "", + }, + { + name: "name_override", + expectedError: "", + }, + { + name: "name_override_existing_sa", + expectedError: "", + }, } type testCase struct { diff --git a/helm/provisioner/tests/testdata/name_override.golden b/helm/provisioner/tests/testdata/name_override.golden new file mode 100644 index 0000000000000..8f828d73d201a --- /dev/null +++ b/helm/provisioner/tests/testdata/name_override.golden @@ -0,0 +1,144 @@ +--- +# Source: coder-provisioner/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: other-coder-provisioner + app.kubernetes.io/part-of: other-coder-provisioner + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: coder-provisioner-0.1.0 + name: other-coder-provisioner +--- +# Source: coder-provisioner/templates/extra-templates.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: some-config + namespace: default +data: + key: some-value +--- +# Source: coder-provisioner/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: other-coder-provisioner-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-provisioner/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: "other-coder-provisioner" +subjects: + - kind: ServiceAccount + name: "other-coder-provisioner" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: other-coder-provisioner-workspace-perms +--- +# Source: coder-provisioner/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: other-coder-provisioner + app.kubernetes.io/part-of: other-coder-provisioner + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: coder-provisioner-0.1.0 + name: other-coder-provisioner +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/instance: release-name + app.kubernetes.io/name: other-coder-provisioner + template: + metadata: + annotations: {} + labels: + app.kubernetes.io/instance: release-name + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: other-coder-provisioner + app.kubernetes.io/part-of: other-coder-provisioner + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: coder-provisioner-0.1.0 + spec: + containers: + - args: + - provisionerd + - start + command: + - /opt/coder + env: + - name: CODER_PROMETHEUS_ADDRESS + value: 0.0.0.0:2112 + - name: CODER_PROVISIONER_DAEMON_PSK + valueFrom: + secretKeyRef: + key: psk + name: coder-provisioner-psk + - name: CODER_URL + value: http://coder.default.svc.cluster.local + image: ghcr.io/coder/coder:latest + imagePullPolicy: IfNotPresent + lifecycle: {} + name: coder + ports: null + resources: {} + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: null + runAsGroup: 1000 + runAsNonRoot: true + runAsUser: 1000 + seccompProfile: + type: RuntimeDefault + volumeMounts: [] + restartPolicy: Always + serviceAccountName: other-coder-provisioner + terminationGracePeriodSeconds: 600 + volumes: [] diff --git a/helm/provisioner/tests/testdata/name_override.yaml b/helm/provisioner/tests/testdata/name_override.yaml new file mode 100644 index 0000000000000..892eb434481f1 --- /dev/null +++ b/helm/provisioner/tests/testdata/name_override.yaml @@ -0,0 +1,16 @@ +coder: + image: + tag: latest + serviceAccount: + name: other-coder-provisioner +nameOverride: "other-coder-provisioner" +# Note that extraTemplates does not respect nameOverride. +extraTemplates: + - | + apiVersion: v1 + kind: ConfigMap + metadata: + name: some-config + namespace: {{ .Release.Namespace }} + data: + key: some-value diff --git a/helm/provisioner/tests/testdata/name_override_existing_sa.golden b/helm/provisioner/tests/testdata/name_override_existing_sa.golden new file mode 100644 index 0000000000000..8fd4790f6170b --- /dev/null +++ b/helm/provisioner/tests/testdata/name_override_existing_sa.golden @@ -0,0 +1,67 @@ +--- +# Source: coder-provisioner/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: other-coder-provisioner + app.kubernetes.io/part-of: other-coder-provisioner + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: coder-provisioner-0.1.0 + name: other-coder-provisioner +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/instance: release-name + app.kubernetes.io/name: other-coder-provisioner + template: + metadata: + annotations: {} + labels: + app.kubernetes.io/instance: release-name + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: other-coder-provisioner + app.kubernetes.io/part-of: other-coder-provisioner + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: coder-provisioner-0.1.0 + spec: + containers: + - args: + - provisionerd + - start + command: + - /opt/coder + env: + - name: CODER_PROMETHEUS_ADDRESS + value: 0.0.0.0:2112 + - name: CODER_PROVISIONER_DAEMON_PSK + valueFrom: + secretKeyRef: + key: psk + name: coder-provisioner-psk + - name: CODER_URL + value: http://coder.default.svc.cluster.local + image: ghcr.io/coder/coder:latest + imagePullPolicy: IfNotPresent + lifecycle: {} + name: coder + ports: null + resources: {} + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: null + runAsGroup: 1000 + runAsNonRoot: true + runAsUser: 1000 + seccompProfile: + type: RuntimeDefault + volumeMounts: [] + restartPolicy: Always + serviceAccountName: existing-coder-provisioner-serviceaccount + terminationGracePeriodSeconds: 600 + volumes: [] diff --git a/helm/provisioner/tests/testdata/name_override_existing_sa.yaml b/helm/provisioner/tests/testdata/name_override_existing_sa.yaml new file mode 100644 index 0000000000000..90cc877421b25 --- /dev/null +++ b/helm/provisioner/tests/testdata/name_override_existing_sa.yaml @@ -0,0 +1,8 @@ +coder: + image: + tag: latest + serviceAccount: + name: "existing-coder-provisioner-serviceaccount" + disableCreate: true + workspacePerms: false +nameOverride: "other-coder-provisioner" diff --git a/helm/provisioner/tests/testdata/sa_disabled.golden b/helm/provisioner/tests/testdata/sa_disabled.golden new file mode 100644 index 0000000000000..583bbe707c502 --- /dev/null +++ b/helm/provisioner/tests/testdata/sa_disabled.golden @@ -0,0 +1,67 @@ +--- +# Source: coder-provisioner/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-provisioner + app.kubernetes.io/part-of: coder-provisioner + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: coder-provisioner-0.1.0 + name: coder-provisioner +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/instance: release-name + app.kubernetes.io/name: coder-provisioner + template: + metadata: + annotations: {} + labels: + app.kubernetes.io/instance: release-name + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: coder-provisioner + app.kubernetes.io/part-of: coder-provisioner + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: coder-provisioner-0.1.0 + spec: + containers: + - args: + - provisionerd + - start + command: + - /opt/coder + env: + - name: CODER_PROMETHEUS_ADDRESS + value: 0.0.0.0:2112 + - name: CODER_PROVISIONER_DAEMON_PSK + valueFrom: + secretKeyRef: + key: psk + name: coder-provisioner-psk + - name: CODER_URL + value: http://coder.default.svc.cluster.local + image: ghcr.io/coder/coder:latest + imagePullPolicy: IfNotPresent + lifecycle: {} + name: coder + ports: null + resources: {} + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: null + runAsGroup: 1000 + runAsNonRoot: true + runAsUser: 1000 + seccompProfile: + type: RuntimeDefault + volumeMounts: [] + restartPolicy: Always + serviceAccountName: coder-provisioner + terminationGracePeriodSeconds: 600 + volumes: [] diff --git a/helm/provisioner/tests/testdata/sa_disabled.yaml b/helm/provisioner/tests/testdata/sa_disabled.yaml new file mode 100644 index 0000000000000..ca27e63250443 --- /dev/null +++ b/helm/provisioner/tests/testdata/sa_disabled.yaml @@ -0,0 +1,6 @@ +coder: + image: + tag: latest + serviceAccount: + workspacePerms: false + disableCreate: true diff --git a/helm/provisioner/values.yaml b/helm/provisioner/values.yaml index 869ddc876c78b..ac920cbb71f50 100644 --- a/helm/provisioner/values.yaml +++ b/helm/provisioner/values.yaml @@ -74,6 +74,8 @@ coder: annotations: {} # coder.serviceAccount.name -- The service account name name: coder-provisioner + # coder.serviceAccount.disableCreate -- Whether to create the service account or use existing service account. + disableCreate: false # coder.securityContext -- Fields related to the container's security # context (as opposed to the pod). Some fields are also present in the pod