Skip to content

Commit 92e8f3b

Browse files
author
Jonathan Yu
authored
feat: promote ingress settings to public (#177)
* Add ingress section to values.yaml and re-generate documentation * Add tests for ingress settings * Change comment syntax to {{/* */}} to prevent it from appearing in the generated Ingress spec
1 parent c44c747 commit 92e8f3b

File tree

7 files changed

+180
-10
lines changed

7 files changed

+180
-10
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ View [our docs](https://coder.com/docs/setup/installation) for detailed installa
6363
| coderd.trustProxyIP | bool | Whether Coder should trust X-Real-IP and/or X-Forwarded-For headers from your reverse proxy. This should only be turned on if you're using a reverse proxy that sets both of these headers. This is always enabled if the Nginx ingress is deployed. | `false` |
6464
| envbox | object | Required for running Docker inside containers. See requirements: https://coder.com/docs/coder/v1.19/admin/workspace-management/cvms | `{"image":""}` |
6565
| envbox.image | string | Injected by Coder during release. | `""` |
66+
| ingress | object | Configure an Ingress to route traffic to Coder services. | `{"annotations":{},"enable":false,"host":"","tls":{"enable":false}}` |
67+
| ingress.annotations | object | Additional annotations to add to the Ingress object. The behavior is typically dependent on the Ingress Controller implementation, and useful for managing features like TLS termination. | `{}` |
68+
| ingress.enable | bool | A boolean controlling whether to create an Ingress. | `false` |
69+
| ingress.host | string | The hostname to proxy to the Coder installation. The cluster Ingress Controller typically uses server name indication or the HTTP Host header to route traffic. | `""` |
70+
| ingress.tls | object | Configures TLS settings for the Ingress. | `{"enable":false}` |
71+
| ingress.tls.enable | bool | Determines whether the Ingress handles TLS. | `false` |
6672
| logging | object | Configures the logging format and output of Coder. | `{"human":"/dev/stderr","json":"","splunk":{"channel":"","token":"","url":""},"stackdriver":""}` |
6773
| logging.human | string | Location to send logs that are formatted for readability. Set to an empty string to disable. | `"/dev/stderr"` |
6874
| logging.json | string | Location to send logs that are formatted as JSON. Set to an empty string to disable. | `""` |

templates/ingress.yaml

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -433,15 +433,18 @@ spec:
433433
name: {{ include "coder.serviceName" . }}
434434
port:
435435
name: tcp-{{ include "coder.serviceName" . }}
436-
{{ $devURLHost := merge .Values dict | dig "coderd" "devurlsHost" "" }}
437-
# Regex docs on '*-suffix.example.com'. This is required as the original input including the suffix is
438-
# not a legal ingress host. We need to remove the suffic, and keep the wildcard '*'.
439-
# - '\\*' Starts with '*'
440-
# - '[^.]*' Suffix is 0 or more characters, '-suffix'
441-
# - '(' Start domain capture grp
442-
# - '\\.' The domain should be separated with a '.' from the subdomain
443-
# - '.*' Rest of the domain.
444-
# - ')' $1 is the ''.example.com'
436+
{{- /* Regex docs on '*-suffix.example.com'. This is required as the original
437+
* input including the suffix is not a legal ingress host. We need to
438+
* remove the suffix, and keep the wildcard '*'.
439+
*
440+
* - '\\*' Starts with '*'
441+
* - '[^.]*' Suffix is 0 or more characters, '-suffix'
442+
* - '(' Start domain capture group
443+
* - '\\.' The domain should be separated with a '.' from the subdomain
444+
* - '.*' Rest of the domain.
445+
* - ')' $1 is the ''.example.com'
446+
*/ -}}
447+
{{- $devURLHost := merge .Values dict | dig "coderd" "devurlsHost" "" }}
445448
- host: {{ regexReplaceAll "\\*[^.]*(\\..*)" $devURLHost "*${1}" | quote }}
446449
http:
447450
paths:

tests/go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module cdr.dev/enterprise-helm/tests
33
go 1.17
44

55
require (
6+
github.com/jinzhu/copier v0.3.4
67
github.com/stretchr/testify v1.7.0
78
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
89
helm.sh/helm/v3 v3.7.1

tests/go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,8 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
502502
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
503503
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
504504
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
505+
github.com/jinzhu/copier v0.3.4 h1:mfU6jI9PtCeUjkjQ322dlff9ELjGDu975C2p/nrubVI=
506+
github.com/jinzhu/copier v0.3.4/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
505507
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
506508
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
507509
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=

tests/ingress_test.go

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package tests
2+
3+
import (
4+
"testing"
5+
6+
netv1 "k8s.io/api/networking/v1"
7+
"k8s.io/utils/pointer"
8+
9+
"github.com/jinzhu/copier"
10+
"github.com/stretchr/testify/require"
11+
)
12+
13+
func TestIngress(t *testing.T) {
14+
chart := LoadChart(t)
15+
16+
pathTypePrefix := netv1.PathTypePrefix
17+
coderdIngressRule := netv1.IngressRuleValue{
18+
HTTP: &netv1.HTTPIngressRuleValue{
19+
Paths: []netv1.HTTPIngressPath{
20+
{
21+
Path: "/",
22+
PathType: &pathTypePrefix,
23+
Backend: netv1.IngressBackend{
24+
Service: &netv1.IngressServiceBackend{
25+
Name: "coderd",
26+
Port: netv1.ServiceBackendPort{
27+
Name: "tcp-coderd",
28+
},
29+
},
30+
},
31+
},
32+
},
33+
},
34+
}
35+
36+
tests := []struct {
37+
Name string
38+
// ValuesFunc is called to configure the values used in this test.
39+
// The function should override the CoderValues as appropriate for
40+
// the test in question.
41+
ValuesFunc func(v *CoderValues)
42+
// AssertFunc is called after rendering the chart, with the resulting
43+
// Ingress object. You can use it to assert properties about the
44+
// Ingress object.
45+
AssertFunc func(t *testing.T, ingress *netv1.Ingress)
46+
}{
47+
{
48+
Name: "simple-ingress",
49+
ValuesFunc: func(v *CoderValues) {
50+
v.Ingress.Enable = pointer.Bool(true)
51+
v.Ingress.Host = pointer.String("install.coder.com")
52+
v.Coderd.DevURLsHost = pointer.String("*.install.coder.app")
53+
},
54+
AssertFunc: func(t *testing.T, ingress *netv1.Ingress) {
55+
defaultAnnotations := map[string]string{
56+
"nginx.ingress.kubernetes.io/proxy-body-size": "0",
57+
}
58+
require.Equal(t, defaultAnnotations, ingress.Annotations)
59+
60+
expectedRules := []netv1.IngressRule{
61+
{
62+
Host: "install.coder.com",
63+
IngressRuleValue: coderdIngressRule,
64+
},
65+
{
66+
Host: "*.install.coder.app",
67+
IngressRuleValue: coderdIngressRule,
68+
},
69+
}
70+
require.Equal(t, expectedRules, ingress.Spec.Rules, "expected ingress spec to match")
71+
},
72+
},
73+
{
74+
Name: "devurl-suffix",
75+
ValuesFunc: func(v *CoderValues) {
76+
v.Ingress.Enable = pointer.Bool(true)
77+
v.Ingress.Host = pointer.String("install.coder.com")
78+
v.Coderd.DevURLsHost = pointer.String("*-dev.install.coder.app")
79+
},
80+
AssertFunc: func(t *testing.T, ingress *netv1.Ingress) {
81+
defaultAnnotations := map[string]string{
82+
"nginx.ingress.kubernetes.io/proxy-body-size": "0",
83+
}
84+
require.Equal(t, defaultAnnotations, ingress.Annotations)
85+
expectedRules := []netv1.IngressRule{
86+
{
87+
Host: "install.coder.com",
88+
IngressRuleValue: coderdIngressRule,
89+
},
90+
{
91+
Host: "*.install.coder.app",
92+
IngressRuleValue: coderdIngressRule,
93+
},
94+
}
95+
require.Equal(t, expectedRules, ingress.Spec.Rules, "expected ingress spec to match")
96+
},
97+
},
98+
}
99+
100+
for _, test := range tests {
101+
test := test
102+
103+
t.Run(test.Name, func(t *testing.T) {
104+
// Clone the original values
105+
values := &CoderValues{}
106+
copier.Copy(values, chart.OriginalValues)
107+
108+
// Run function to perform test-specific modifications of defaults
109+
test.ValuesFunc(values)
110+
111+
// Verify the results using AssertFunc
112+
objs, err := chart.Render(values, nil, nil)
113+
require.NoError(t, err, "chart render failed")
114+
115+
var found bool
116+
for _, obj := range objs {
117+
ingress, ok := obj.(*netv1.Ingress)
118+
if ok && ingress.Name == "coderd-ingress" {
119+
found = true
120+
test.AssertFunc(t, ingress)
121+
break
122+
}
123+
}
124+
require.True(t, found, "expected ingress in manifests")
125+
})
126+
}
127+
}

tests/values.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,10 @@ type Chart struct {
6060
//
6161
// TODO: generate these structs from a values.schema.json
6262
type CoderValues struct {
63-
Coderd *CoderdValues `json:"coderd" yaml:"coderd"`
6463
Certs *CertsValues `json:"certs" yaml:"certs"`
64+
Coderd *CoderdValues `json:"coderd" yaml:"coderd"`
6565
Envbox *EnvboxValues `json:"envbox" yaml:"envbox"`
66+
Ingress *IngressValues `json:"ingress" yaml:"ingress"`
6667
Logging *LoggingValues `json:"logging" yaml:"logging"`
6768
Metrics *MetricsValues `json:"metrics" yaml:"metrics"`
6869
Postgres *PostgresValues `json:"postgres" yaml:"postgres"`
@@ -166,6 +167,19 @@ type EnvboxValues struct {
166167
Image *string `json:"image" yaml:"image"`
167168
}
168169

170+
// IngressValues reflect values from ingress.
171+
type IngressValues struct {
172+
Enable *bool `json:"enable" yaml:"enable"`
173+
Host *string `json:"host" yaml:"host"`
174+
Annotations map[string]string `json:"annotations" yaml:"annotations"`
175+
TLS *IngressTLSValues `json:"tls" yaml:"tls"`
176+
}
177+
178+
// IngressTLSValues reflect values from ingress.tls.
179+
type IngressTLSValues struct {
180+
Enable *bool `json:"enable" yaml:"enable"`
181+
}
182+
169183
// LoggingValues reflect values from logging.
170184
type LoggingValues struct {
171185
Human *string `json:"human" yaml:"human"`

values.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,23 @@ coderd:
172172
# weight: 1
173173
# ```
174174

175+
# ingress -- Configure an Ingress to route traffic to Coder services.
176+
ingress:
177+
# ingress.enable -- A boolean controlling whether to create an Ingress.
178+
enable: false
179+
# ingress.host -- The hostname to proxy to the Coder installation.
180+
# The cluster Ingress Controller typically uses server name indication
181+
# or the HTTP Host header to route traffic.
182+
host: ""
183+
# ingress.annotations -- Additional annotations to add to the Ingress
184+
# object. The behavior is typically dependent on the Ingress Controller
185+
# implementation, and useful for managing features like TLS termination.
186+
annotations: {}
187+
# ingress.tls -- Configures TLS settings for the Ingress.
188+
tls:
189+
# ingress.tls.enable -- Determines whether the Ingress handles TLS.
190+
enable: false
191+
175192
# envbox -- Required for running Docker inside containers. See requirements:
176193
# https://coder.com/docs/coder/v1.19/admin/workspace-management/cvms
177194
envbox:

0 commit comments

Comments
 (0)