From 30a7ab7db22c323a6723e1da4b55fffcea755ac1 Mon Sep 17 00:00:00 2001 From: Colin Adler Date: Mon, 6 Dec 2021 16:18:50 -0600 Subject: [PATCH 1/6] feat: support postgres mtls --- templates/_common.tpl | 50 +++++++++++++++++++++++++++++++++++++++---- templates/coderd.yaml | 1 + values.yaml | 21 ++++++++++++++++++ 3 files changed, 68 insertions(+), 4 deletions(-) diff --git a/templates/_common.tpl b/templates/_common.tpl index 91013e04..5fd8dc89 100644 --- a/templates/_common.tpl +++ b/templates/_common.tpl @@ -40,15 +40,27 @@ storageClassName: {{ $storageClass | default "" | quote }} value: {{ .Values.postgres.sslMode | quote }} - name: DB_NAME value: {{ .Values.postgres.database | quote }} +{{- if ne .Values.postgres.ssl.certSecret.name "" }} +- name: DB_CERT + value: "/etc/ssl/certs/pg/cert/{{ .Values.postgres.ssl.certSecret.key }}" +{{- end }} +{{- if ne .Values.postgres.ssl.keySecret.name "" }} +- name: DB_KEY + value: "/etc/ssl/certs/pg/key/{{ .Values.postgres.ssl.keySecret.key }}" +{{- end }} +{{- if ne .Values.postgres.ssl.rootCertSecret.name "" }} +- name: DB_ROOT_CERT + value: "/etc/ssl/certs/pg/rootcert/{{ .Values.postgres.ssl.rootCertSecret.key }}" +{{- end }} {{- end }} {{- end }} {{/* coder.volumes adds a volumes stanza if a cert.secret is provided. */}} {{- define "coder.volumes" }} -{{- if or (merge .Values dict | dig "certs" "secret" "name" false) (ne (include "movedValue" (dict "Values" .Values "Key" "coderd.tls.hostSecretName")) "") }} volumes: -{{- end }} + - name: tmp-pgcerts + emptyDir: {} {{- if (merge .Values dict | dig "certs" "secret" "name" false) }} - name: {{ .Values.certs.secret.name | quote }} secret: @@ -64,15 +76,30 @@ volumes: secret: secretName: {{ include "movedValue" (dict "Values" .Values "Key" "coderd.tls.devurlsHostSecretName") }} {{- end }} +{{- if ne .Values.postgres.ssl.certSecret.name "" }} + - name: pgcert + secret: + secretName: {{ .Values.postgres.ssl.certSecret.name | quote }} +{{- end }} +{{- if ne .Values.postgres.ssl.keySecret.name "" }} + - name: pgkey + secret: + secretName: {{ .Values.postgres.ssl.keySecret.name | quote }} +{{- end }} +{{- if ne .Values.postgres.ssl.rootCertSecret.name "" }} + - name: pgrootcert + secret: + secretName: {{ .Values.postgres.ssl.rootCertSecret.name | quote }} +{{- end }} {{- end }} {{/* coder.volumeMounts adds a volume mounts stanza if a cert.secret is provided. */}} {{- define "coder.volumeMounts" }} -{{- if or (merge .Values dict | dig "certs" "secret" "name" false) (ne (include "movedValue" (dict "Values" .Values "Key" "coderd.tls.hostSecretName")) "") }} volumeMounts: -{{- end }} + - name: tmp-pgcerts + mountPath: /tmp/pgcerts {{- if (merge .Values dict | dig "certs" "secret" "name" false) }} - name: {{ .Values.certs.secret.name | quote }} mountPath: /etc/ssl/certs/{{ .Values.certs.secret.key }} @@ -88,6 +115,21 @@ volumeMounts: mountPath: /etc/ssl/certs/devurls readOnly: true {{- end }} +{{- if ne .Values.postgres.ssl.certSecret.name "" }} + - name: pgcert + mountPath: /etc/ssl/certs/pg/cert + readOnly: true +{{- end }} +{{- if ne .Values.postgres.ssl.keySecret.name "" }} + - name: pgkey + mountPath: /etc/ssl/certs/pg/key + readOnly: true +{{- end }} +{{- if ne .Values.postgres.ssl.rootCertSecret.name "" }} + - name: pgrootcert + mountPath: /etc/ssl/certs/pg/rootcert + readOnly: true +{{- end }} {{- end }} {{/* coder.serviceTolerations adds tolerations if any are specified to diff --git a/templates/coderd.yaml b/templates/coderd.yaml index 31193cf4..242f90a8 100644 --- a/templates/coderd.yaml +++ b/templates/coderd.yaml @@ -90,6 +90,7 @@ spec: {{- else }} {{- toYaml .Values.coderd.securityContext | nindent 12 }} {{- end }} +{{- include "coder.volumeMounts" . | indent 10 }} {{- end }} containers: - name: {{ include "coder.serviceName" . }} diff --git a/values.yaml b/values.yaml index cc2fe51a..0057aa3e 100644 --- a/values.yaml +++ b/values.yaml @@ -218,6 +218,27 @@ postgres: # the PostgreSQL connection. For acceptable values, see: # https://www.postgresql.org/docs/9.1/libpq-ssl.html sslMode: "require" + # postgres.ssl -- Options for configuring the SSL cert, key, and root cert + # when connecting to Postgres. + ssl: + # postgres.ssl.certSecret -- Secret containing a PEM encoded cert file. + certSecret: + # postgres.ssl.certSecret.name -- Name of the secret. + name: "" + # postgres.ssl.certSecret.key -- Key pointing to a certificate in the secret. + key: "" + # postgres.ssl.keySecret -- Secret containing a PEM encoded key file. + keySecret: + # postgres.ssl.keytSecret.name -- Name of the secret. + name: "" + # postgres.ssl.keySecret.key -- Key pointing to a certificate in the secret. + key: "" + # postgres.ssl.rootCertSecret -- Secret containing a PEM encoded root cert file. + rootCertSecret: + # postgres.ssl.rootCertSecret.name -- Name of the secret. + name: "" + # postgres.ssl.rootCertSecret.key -- Key pointing to a certificate in the secret. + key: "" # postgres.default -- Configure a built-in PostgreSQL deployment. default: From 6de6352b2733e8eab4c904fbbb8db6d5dbf3738e Mon Sep 17 00:00:00 2001 From: Colin Adler Date: Wed, 8 Dec 2021 14:34:48 -0600 Subject: [PATCH 2/6] add ssl tests --- tests/examples_test.go | 97 ++++++++++++++----------------- tests/pgssl_test.go | 70 +++++++++++++++++++++++ tests/values.go | 126 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 228 insertions(+), 65 deletions(-) create mode 100644 tests/pgssl_test.go diff --git a/tests/examples_test.go b/tests/examples_test.go index 80e06404..067961a7 100644 --- a/tests/examples_test.go +++ b/tests/examples_test.go @@ -3,11 +3,10 @@ package tests import ( "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v3/pkg/engine" - appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/utils/pointer" ) @@ -17,14 +16,12 @@ import ( func TestExamples(t *testing.T) { t.Parallel() - chart, err := loader.LoadDir("..") - require.NoError(t, err, "loaded chart successfully") - require.NotNil(t, chart, "chart must be non-nil") + chart := LoadChart(t) - exampleOpenShift, err := ReadValuesAsMap("../examples/openshift/openshift.values.yaml") + exampleOpenShift, err := ReadValuesFileAsMap("../examples/openshift/openshift.values.yaml") require.NoError(t, err, "failed to load OpenShift example values") - exampleKind, err := ReadValuesAsMap("../examples/kind/kind.values.yaml") + exampleKind, err := ReadValuesFileAsMap("../examples/kind/kind.values.yaml") require.NoError(t, err, "failed to load Kind example values") tests := []struct { @@ -32,35 +29,11 @@ func TestExamples(t *testing.T) { Values map[string]interface{} PodSecurityContext *corev1.PodSecurityContext ContainerSecurityContext *corev1.SecurityContext + Postgres *PostgresValues }{ { Name: "default", Values: nil, - PodSecurityContext: &corev1.PodSecurityContext{ - RunAsUser: pointer.Int64(1000), - RunAsGroup: nil, - RunAsNonRoot: pointer.Bool(true), - SeccompProfile: &corev1.SeccompProfile{ - Type: corev1.SeccompProfileTypeRuntimeDefault, - LocalhostProfile: nil, - }, - }, - ContainerSecurityContext: &corev1.SecurityContext{ - RunAsUser: nil, - RunAsGroup: nil, - RunAsNonRoot: nil, - Capabilities: nil, - Privileged: nil, - SELinuxOptions: nil, - WindowsOptions: nil, - ReadOnlyRootFilesystem: pointer.Bool(true), - AllowPrivilegeEscalation: pointer.Bool(false), - ProcMount: nil, - SeccompProfile: &corev1.SeccompProfile{ - Type: corev1.SeccompProfileTypeRuntimeDefault, - LocalhostProfile: nil, - }, - }, }, { Name: "openshift", Values: exampleOpenShift, @@ -113,40 +86,58 @@ func TestExamples(t *testing.T) { }, } + var ( + defaultPsp = &corev1.PodSecurityContext{ + RunAsUser: pointer.Int64(1000), + RunAsNonRoot: pointer.Bool(true), + SeccompProfile: &corev1.SeccompProfile{ + Type: corev1.SeccompProfileTypeRuntimeDefault, + }, + } + + defaultCsc = &corev1.SecurityContext{ + ReadOnlyRootFilesystem: pointer.Bool(true), + AllowPrivilegeEscalation: pointer.Bool(false), + SeccompProfile: &corev1.SeccompProfile{ + Type: corev1.SeccompProfileTypeRuntimeDefault, + }, + } + ) + for _, test := range tests { test := test + + if test.PodSecurityContext == nil { + test.PodSecurityContext = defaultPsp + } + if test.ContainerSecurityContext == nil { + test.ContainerSecurityContext = defaultCsc + } + t.Run(test.Name, func(t *testing.T) { t.Parallel() - values, err := chartutil.ToRenderValues(chart, test.Values, DefaultReleaseOptions(), chartutil.DefaultCapabilities.Copy()) + values, err := chartutil.ToRenderValues(chart.chart, test.Values, DefaultReleaseOptions(), chartutil.DefaultCapabilities.Copy()) require.NoError(t, err, "failed to generate render values") - manifests, err := engine.Render(chart, values) + manifests, err := engine.Render(chart.chart, values) require.NoError(t, err, "failed to render chart") objs, err := LoadObjectsFromManifests(manifests) require.NoError(t, err, "failed to convert manifests to objects") // Find the coderd Deployment - var found bool - for _, obj := range objs { - deployment, ok := obj.(*appsv1.Deployment) - if ok && deployment.Name == "coderd" { - found = true - - require.Equal(t, test.PodSecurityContext, - deployment.Spec.Template.Spec.SecurityContext, - "expected matching pod securityContext") - require.Len(t, deployment.Spec.Template.Spec.Containers, 1, - "expected one container") - require.Equal(t, test.ContainerSecurityContext, - deployment.Spec.Template.Spec.Containers[0].SecurityContext, - "expected matching container securityContext") - - break - } - } - require.True(t, found, "expected coderd deployment in manifests") + coderd := FindDeployment(t, objs, "coderd") + + assert.Equal(t, test.PodSecurityContext, coderd.Spec.Template.Spec.SecurityContext, + "expected matching pod securityContext", + ) + require.Len(t, coderd.Spec.Template.Spec.Containers, 1, + "expected one container", + ) + assert.Equal(t, test.ContainerSecurityContext, coderd.Spec.Template.Spec.Containers[0].SecurityContext, + "expected matching container securityContext", + ) }) } } diff --git a/tests/pgssl_test.go b/tests/pgssl_test.go new file mode 100644 index 00000000..eb8588c4 --- /dev/null +++ b/tests/pgssl_test.go @@ -0,0 +1,70 @@ +package tests + +import ( + "path" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + "k8s.io/utils/pointer" +) + +func TestPgSSL(t *testing.T) { + t.Parallel() + + var ( + secretName = pointer.String("pg-certs") + cv = &CoderValues{ + Postgres: &PostgresValues{ + Default: &PostgresDefaultValues{Enable: pointer.Bool(false)}, + Host: pointer.String("1.1.1.1"), + Port: pointer.String("5432"), + User: pointer.String("postgres"), + Database: pointer.String("postgres"), + PasswordSecret: pointer.String("pg-pass"), + SSLMode: pointer.String("require"), + SSL: &PostgresSSLValues{ + CertSecret: &CertsSecretValues{ + Name: secretName, + Key: pointer.String("cert"), + }, + KeySecret: &CertsSecretValues{ + Name: secretName, + Key: pointer.String("key"), + }, + RootCertSecret: &CertsSecretValues{ + Name: secretName, + Key: pointer.String("rootcert"), + }, + }, + }, + } + + objs = RenderChart(t, cv) + coderd = FindDeployment(t, objs, "coderd") + ) + + for _, vol := range []string{"pgcert", "pgkey", "pgrootcert"} { + AssertVolume(t, coderd.Spec.Template.Spec.Volumes, vol, func(t testing.TB, v corev1.Volume) { + require.NotNil(t, v.Secret) + assert.Equal(t, "pg-certs", v.Secret.SecretName) + }) + } + + for _, cnt := range []string{"migrations", "coderd"} { + // Combine both init and regular containers. + cnts := append(coderd.Spec.Template.Spec.InitContainers, coderd.Spec.Template.Spec.Containers...) + + AssertContainer(t, cnts, cnt, func(t testing.TB, c corev1.Container) { + for _, vol := range []string{"pgcert", "pgkey", "pgrootcert"} { + AssertVolumeMount(t, c.VolumeMounts, vol, func(t testing.TB, v corev1.VolumeMount) { + assert.Equal(t, vol, v.Name) + assert.True(t, v.ReadOnly) + assert.Equal(t, path.Join("/etc/ssl/certs/pg/", strings.TrimPrefix(v.Name, "pg")), v.MountPath) + }) + } + }) + } +} diff --git a/tests/values.go b/tests/values.go index 181a7777..f3d77af3 100644 --- a/tests/values.go +++ b/tests/values.go @@ -60,14 +60,14 @@ type Chart struct { // // TODO: generate these structs from a values.schema.json type CoderValues struct { - Certs *CertsValues `json:"certs" yaml:"certs"` - Coderd *CoderdValues `json:"coderd" yaml:"coderd"` - Envbox *EnvboxValues `json:"envbox" yaml:"envbox"` - Ingress *IngressValues `json:"ingress" yaml:"ingress"` - Logging *LoggingValues `json:"logging" yaml:"logging"` - Metrics *MetricsValues `json:"metrics" yaml:"metrics"` - Postgres *PostgresValues `json:"postgres" yaml:"postgres"` - Services *ServicesValues `json:"services" yaml:"services"` + Certs *CertsValues `json:"certs,omitempty" yaml:"certs,omitempty"` + Coderd *CoderdValues `json:"coderd,omitempty" yaml:"coderd,omitempty"` + Envbox *EnvboxValues `json:"envbox,omitempty" yaml:"envbox,omitempty"` + Ingress *IngressValues `json:"ingress,omitempty" yaml:"ingress,omitempty"` + Logging *LoggingValues `json:"logging,omitempty" yaml:"logging,omitempty"` + Metrics *MetricsValues `json:"metrics,omitempty" yaml:"metrics,omitempty"` + Postgres *PostgresValues `json:"postgres,omitempty" yaml:"postgres,omitempty"` + Services *ServicesValues `json:"services,omitempty" yaml:"services,omitempty"` } // CoderdValues reflect values from coderd. @@ -220,6 +220,13 @@ type PostgresValues struct { Database *string `json:"database" yaml:"database"` PasswordSecret *string `json:"passwordSecret" yaml:"passwordSecret"` Default *PostgresDefaultValues `json:"default" yaml:"default"` + SSL *PostgresSSLValues `json:"ssl" yaml:"ssl"` +} + +type PostgresSSLValues struct { + CertSecret *CertsSecretValues `json:"certSecret" yaml:"certSecret"` + KeySecret *CertsSecretValues `json:"keySecret" yaml:"keySecret"` + RootCertSecret *CertsSecretValues `json:"rootCertSecret" yaml:"rootCertSecret"` } // PostgresDefaultValues reflect the values from @@ -305,7 +312,7 @@ func ConvertMapToCoderValues(v map[string]interface{}, strict bool) (*CoderValue // LoadChart is a utility function that loads the chart from the // unpacked source directory. -func LoadChart(t *testing.T) *Chart { +func LoadChart(t testing.TB) *Chart { chart, err := loader.LoadDir("..") require.NoError(t, err, "loaded chart successfully") require.NotNil(t, chart, "chart must be non-nil") @@ -385,6 +392,15 @@ func (c *Chart) Render(values *CoderValues, options *chartutil.ReleaseOptions, c return objs, nil } +func RenderChart(t testing.TB, values *CoderValues) []runtime.Object { + chart := LoadChart(t) + + objs, err := chart.Render(values, nil, nil) + require.NoError(t, err, "render chart") + + return objs +} + func DefaultReleaseOptions() chartutil.ReleaseOptions { return chartutil.ReleaseOptions{ Name: "coder", @@ -465,7 +481,7 @@ func NewScheme() *runtime.Scheme { return scheme } -// ReadValues reads the values.yaml from a file +// ReadValues reads the values.yaml from a file. func ReadValues(path string) (*CoderValues, error) { file, err := os.Open(path) if err != nil { @@ -482,8 +498,8 @@ func ReadValues(path string) (*CoderValues, error) { return &values, nil } -// ReadValuesAsMap reads the values.yaml from a file -func ReadValuesAsMap(path string) (map[string]interface{}, error) { +// ReadValuesFileAsMap reads the values.yaml from a file. +func ReadValuesFileAsMap(path string) (map[string]interface{}, error) { file, err := os.Open(path) if err != nil { return nil, fmt.Errorf("failed to open %q: %w", path, err) @@ -498,3 +514,89 @@ func ReadValuesAsMap(path string) (map[string]interface{}, error) { return values, nil } + +// ReadValuesAsMap reads the values.yaml from a string. +func ReadValuesAsMap(valuesStr string) (map[string]interface{}, error) { + var values map[string]interface{} + decoder := yaml.NewYAMLToJSONDecoder(strings.NewReader(valuesStr)) + err := decoder.Decode(&values) + if err != nil { + return nil, fmt.Errorf("error decoding yaml: %w", err) + } + + return values, nil +} + +func ReadChartValues(t testing.TB, chart *chart.Chart, valuesStr string) chartutil.Values { + valuesMap, err := ReadValuesAsMap(valuesStr) + require.NoError(t, err, "read values as map") + + values, err := chartutil.ToRenderValues(chart, valuesMap, DefaultReleaseOptions(), chartutil.DefaultCapabilities.Copy()) + require.NoError(t, err, "to render values") + + return values +} + +// FindDeployment finds a deployment in the given slice of objects with the +// given name. +func FindDeployment(t testing.TB, objs []runtime.Object, name string) *appsv1.Deployment { + names := []string{} + for _, obj := range objs { + if deployment, ok := obj.(*appsv1.Deployment); ok { + if deployment.Name == name { + return deployment + } + names = append(names, deployment.Name) + } + } + + t.Fatalf("failed to find deployment %q, found %v", name, names) + return nil +} + +// AssertVolume asserts that a volume exists of the given name in the given +// slice of volumes. If it exists, it also runs fn against the named volume. +func AssertVolume(t testing.TB, vols []corev1.Volume, name string, fn func(t testing.TB, v corev1.Volume)) { + names := []string{} + for _, v := range vols { + if v.Name == name { + fn(t, v) + return + } + names = append(names, v.Name) + } + + t.Fatalf("failed to find volume %q, found %v", name, names) +} + +// AssertVolumeMount asserts that a volume mount exists of the given name in the +// given slice of volume mounts. If it exists, it also runs fn against the named +// volume mount. +func AssertVolumeMount(t testing.TB, vols []corev1.VolumeMount, name string, fn func(t testing.TB, v corev1.VolumeMount)) { + names := []string{} + for _, v := range vols { + if v.Name == name { + fn(t, v) + return + } + names = append(names, v.Name) + } + + t.Fatalf("failed to find volume mount %q, found %v", name, names) +} + +// AssertContainer asserts that a container exists of the given name in the +// given slice of containers. If it exists, it also runs fn against the named +// container. +func AssertContainer(t testing.TB, cnts []corev1.Container, name string, fn func(t testing.TB, v corev1.Container)) { + names := []string{} + for _, c := range cnts { + if c.Name == name { + fn(t, c) + return + } + names = append(names, c.Name) + } + + t.Fatalf("failed to find container %q, found %v", name, names) +} From f77dffeaa413395d3200d0a09a4c3cc51de8dc2f Mon Sep 17 00:00:00 2001 From: Colin Adler Date: Wed, 8 Dec 2021 16:24:16 -0600 Subject: [PATCH 3/6] review fixes --- tests/examples_test.go | 2 +- tests/pgssl_test.go | 4 ++-- tests/values.go | 34 +++++----------------------------- 3 files changed, 8 insertions(+), 32 deletions(-) diff --git a/tests/examples_test.go b/tests/examples_test.go index 067961a7..48e3d9b1 100644 --- a/tests/examples_test.go +++ b/tests/examples_test.go @@ -127,7 +127,7 @@ func TestExamples(t *testing.T) { require.NoError(t, err, "failed to convert manifests to objects") // Find the coderd Deployment - coderd := FindDeployment(t, objs, "coderd") + coderd := MustFindDeployment(t, objs, "coderd") assert.Equal(t, test.PodSecurityContext, coderd.Spec.Template.Spec.SecurityContext, "expected matching pod securityContext", diff --git a/tests/pgssl_test.go b/tests/pgssl_test.go index eb8588c4..c72708c6 100644 --- a/tests/pgssl_test.go +++ b/tests/pgssl_test.go @@ -42,8 +42,8 @@ func TestPgSSL(t *testing.T) { }, } - objs = RenderChart(t, cv) - coderd = FindDeployment(t, objs, "coderd") + objs = LoadChart(t).MustRender(t, cv) + coderd = MustFindDeployment(t, objs, "coderd") ) for _, vol := range []string{"pgcert", "pgkey", "pgrootcert"} { diff --git a/tests/values.go b/tests/values.go index f3d77af3..5c36c901 100644 --- a/tests/values.go +++ b/tests/values.go @@ -392,10 +392,8 @@ func (c *Chart) Render(values *CoderValues, options *chartutil.ReleaseOptions, c return objs, nil } -func RenderChart(t testing.TB, values *CoderValues) []runtime.Object { - chart := LoadChart(t) - - objs, err := chart.Render(values, nil, nil) +func (c *Chart) MustRender(t testing.TB, values *CoderValues) []runtime.Object { + objs, err := c.Render(values, nil, nil) require.NoError(t, err, "render chart") return objs @@ -515,31 +513,9 @@ func ReadValuesFileAsMap(path string) (map[string]interface{}, error) { return values, nil } -// ReadValuesAsMap reads the values.yaml from a string. -func ReadValuesAsMap(valuesStr string) (map[string]interface{}, error) { - var values map[string]interface{} - decoder := yaml.NewYAMLToJSONDecoder(strings.NewReader(valuesStr)) - err := decoder.Decode(&values) - if err != nil { - return nil, fmt.Errorf("error decoding yaml: %w", err) - } - - return values, nil -} - -func ReadChartValues(t testing.TB, chart *chart.Chart, valuesStr string) chartutil.Values { - valuesMap, err := ReadValuesAsMap(valuesStr) - require.NoError(t, err, "read values as map") - - values, err := chartutil.ToRenderValues(chart, valuesMap, DefaultReleaseOptions(), chartutil.DefaultCapabilities.Copy()) - require.NoError(t, err, "to render values") - - return values -} - -// FindDeployment finds a deployment in the given slice of objects with the -// given name. -func FindDeployment(t testing.TB, objs []runtime.Object, name string) *appsv1.Deployment { +// MustFindDeployment finds a deployment in the given slice of objects with the +// given name, or fails the test. +func MustFindDeployment(t testing.TB, objs []runtime.Object, name string) *appsv1.Deployment { names := []string{} for _, obj := range objs { if deployment, ok := obj.(*appsv1.Deployment); ok { From 7e3b86551c649b00b68c6cc812a144f8d21fd779 Mon Sep 17 00:00:00 2001 From: Colin Adler Date: Wed, 8 Dec 2021 16:26:28 -0600 Subject: [PATCH 4/6] 9.1 -> 11 --- values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/values.yaml b/values.yaml index 0057aa3e..2cb3d560 100644 --- a/values.yaml +++ b/values.yaml @@ -216,7 +216,7 @@ postgres: passwordSecret: "" # postgres.sslMode -- Provides variable levels of protection for # the PostgreSQL connection. For acceptable values, see: - # https://www.postgresql.org/docs/9.1/libpq-ssl.html + # https://www.postgresql.org/docs/11/libpq-ssl.html sslMode: "require" # postgres.ssl -- Options for configuring the SSL cert, key, and root cert # when connecting to Postgres. From 7ac67af94ab1d68232389b0274f336f3b08c4994 Mon Sep 17 00:00:00 2001 From: Colin Adler Date: Wed, 8 Dec 2021 16:45:21 -0600 Subject: [PATCH 5/6] remove omitempty --- tests/pgssl_test.go | 44 +++++++++++++++++++++----------------------- tests/values.go | 25 ++++++++++++++++--------- 2 files changed, 37 insertions(+), 32 deletions(-) diff --git a/tests/pgssl_test.go b/tests/pgssl_test.go index c72708c6..a6347429 100644 --- a/tests/pgssl_test.go +++ b/tests/pgssl_test.go @@ -16,33 +16,31 @@ func TestPgSSL(t *testing.T) { var ( secretName = pointer.String("pg-certs") - cv = &CoderValues{ - Postgres: &PostgresValues{ - Default: &PostgresDefaultValues{Enable: pointer.Bool(false)}, - Host: pointer.String("1.1.1.1"), - Port: pointer.String("5432"), - User: pointer.String("postgres"), - Database: pointer.String("postgres"), - PasswordSecret: pointer.String("pg-pass"), - SSLMode: pointer.String("require"), - SSL: &PostgresSSLValues{ - CertSecret: &CertsSecretValues{ - Name: secretName, - Key: pointer.String("cert"), - }, - KeySecret: &CertsSecretValues{ - Name: secretName, - Key: pointer.String("key"), - }, - RootCertSecret: &CertsSecretValues{ - Name: secretName, - Key: pointer.String("rootcert"), - }, + pgval = &PostgresValues{ + Default: &PostgresDefaultValues{Enable: pointer.Bool(false)}, + Host: pointer.String("1.1.1.1"), + Port: pointer.String("5432"), + User: pointer.String("postgres"), + Database: pointer.String("postgres"), + PasswordSecret: pointer.String("pg-pass"), + SSLMode: pointer.String("require"), + SSL: &PostgresSSLValues{ + CertSecret: &CertsSecretValues{ + Name: secretName, + Key: pointer.String("cert"), + }, + KeySecret: &CertsSecretValues{ + Name: secretName, + Key: pointer.String("key"), + }, + RootCertSecret: &CertsSecretValues{ + Name: secretName, + Key: pointer.String("rootcert"), }, }, } - objs = LoadChart(t).MustRender(t, cv) + objs = LoadChart(t).MustRender(t, func(cv *CoderValues) { cv.Postgres = pgval }) coderd = MustFindDeployment(t, objs, "coderd") ) diff --git a/tests/values.go b/tests/values.go index 5c36c901..13e8e676 100644 --- a/tests/values.go +++ b/tests/values.go @@ -10,6 +10,7 @@ import ( "strings" "testing" + "github.com/jinzhu/copier" "github.com/stretchr/testify/require" "golang.org/x/xerrors" "helm.sh/helm/v3/pkg/chart" @@ -60,14 +61,14 @@ type Chart struct { // // TODO: generate these structs from a values.schema.json type CoderValues struct { - Certs *CertsValues `json:"certs,omitempty" yaml:"certs,omitempty"` - Coderd *CoderdValues `json:"coderd,omitempty" yaml:"coderd,omitempty"` - Envbox *EnvboxValues `json:"envbox,omitempty" yaml:"envbox,omitempty"` - Ingress *IngressValues `json:"ingress,omitempty" yaml:"ingress,omitempty"` - Logging *LoggingValues `json:"logging,omitempty" yaml:"logging,omitempty"` - Metrics *MetricsValues `json:"metrics,omitempty" yaml:"metrics,omitempty"` - Postgres *PostgresValues `json:"postgres,omitempty" yaml:"postgres,omitempty"` - Services *ServicesValues `json:"services,omitempty" yaml:"services,omitempty"` + Certs *CertsValues `json:"certs" yaml:"certs"` + Coderd *CoderdValues `json:"coderd" yaml:"coderd"` + Envbox *EnvboxValues `json:"envbox" yaml:"envbox"` + Ingress *IngressValues `json:"ingress" yaml:"ingress"` + Logging *LoggingValues `json:"logging" yaml:"logging"` + Metrics *MetricsValues `json:"metrics" yaml:"metrics"` + Postgres *PostgresValues `json:"postgres" yaml:"postgres"` + Services *ServicesValues `json:"services" yaml:"services"` } // CoderdValues reflect values from coderd. @@ -392,7 +393,13 @@ func (c *Chart) Render(values *CoderValues, options *chartutil.ReleaseOptions, c return objs, nil } -func (c *Chart) MustRender(t testing.TB, values *CoderValues) []runtime.Object { +// MustRender renders a chart or fails the test. Use `fn` to modify the default +// chart values. +func (c *Chart) MustRender(t testing.TB, fn func(*CoderValues)) []runtime.Object { + values := &CoderValues{} + copier.Copy(values, c.OriginalValues) + fn(values) + objs, err := c.Render(values, nil, nil) require.NoError(t, err, "render chart") From 90575b199b147b14318d8243488a80a55b8c36ca Mon Sep 17 00:00:00 2001 From: Colin Adler Date: Wed, 8 Dec 2021 16:50:45 -0600 Subject: [PATCH 6/6] better failure messages --- tests/pgssl_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/pgssl_test.go b/tests/pgssl_test.go index a6347429..3f9aaa44 100644 --- a/tests/pgssl_test.go +++ b/tests/pgssl_test.go @@ -46,8 +46,8 @@ func TestPgSSL(t *testing.T) { for _, vol := range []string{"pgcert", "pgkey", "pgrootcert"} { AssertVolume(t, coderd.Spec.Template.Spec.Volumes, vol, func(t testing.TB, v corev1.Volume) { - require.NotNil(t, v.Secret) - assert.Equal(t, "pg-certs", v.Secret.SecretName) + require.NotNilf(t, v.Secret, "secret nil for %q", vol) + assert.Equalf(t, "pg-certs", v.Secret.SecretName, "secret name incorrect for %q", vol) }) } @@ -58,9 +58,9 @@ func TestPgSSL(t *testing.T) { AssertContainer(t, cnts, cnt, func(t testing.TB, c corev1.Container) { for _, vol := range []string{"pgcert", "pgkey", "pgrootcert"} { AssertVolumeMount(t, c.VolumeMounts, vol, func(t testing.TB, v corev1.VolumeMount) { - assert.Equal(t, vol, v.Name) - assert.True(t, v.ReadOnly) - assert.Equal(t, path.Join("/etc/ssl/certs/pg/", strings.TrimPrefix(v.Name, "pg")), v.MountPath) + assert.Equalf(t, vol, v.Name, "volume mount name incorrect for %q", vol) + assert.Truef(t, v.ReadOnly, "readonly incorrect for %q", vol) + assert.Equalf(t, path.Join("/etc/ssl/certs/pg/", strings.TrimPrefix(v.Name, "pg")), v.MountPath, "mount path incorrect for %q", vol) }) } })