git.iko.soy/typeable/oauth2-proxy
on master help sign in
Make the Upstreams mux configurable

This commit changes Upstreams from []Upstream to a struct{} moving the previous []Upstream into .Configs and adjusts all uses of it.

commit12ab4ef52958ab18d1156cd1cee0618ed38efe32 authorFabian Stelzer <fs@gigacodes.de> dateMon 9 Aug 2021, 13:32 (5 years ago) parentae72beb
11 files changed+283−231
main_test.go+12−9 oauthproxy_test.go+49−33 pkg/apis/options/legacy_options.go+2−2 pkg/apis/options/legacy_options_test.go+41−39 pkg/apis/options/load_test.go+13−10 pkg/apis/options/upstreams.go+5−1 pkg/upstream/proxy.go+2−2 pkg/upstream/proxy_test.go+77−75 pkg/validation/options_test.go+1−1 pkg/validation/upstreams.go+1−1 pkg/validation/upstreams_test.go+80−58
main_test.go+12−9
@@ -25,6 +25,7 @@ client_secret="b2F1dGgyLXByb3h5LWNsaWVudC1zZWNyZXQK"
2525
2626 const testAlphaConfig = `
2727upstreams:
28+ configs:
2829 - id: /
2930 path: /
3031 uri: http://httpbin
@@ -101,13 +102,15 @@ redirect_url="http://localhost:4180/oauth2/callback"
101102 opts.RawRedirectURL = "http://localhost:4180/oauth2/callback"
102103
103104 opts.UpstreamServers = options.Upstreams{
104− {
105− ID: "/",
106− Path: "/",
107− URI: "http://httpbin",
108− FlushInterval: durationPtr(options.DefaultUpstreamFlushInterval),
109− PassHostHeader: boolPtr(true),
110− ProxyWebSockets: boolPtr(true),
105+ Configs: []options.Upstream{
106+ {
107+ ID: "/",
108+ Path: "/",
109+ URI: "http://httpbin",
110+ FlushInterval: durationPtr(options.DefaultUpstreamFlushInterval),
111+ PassHostHeader: boolPtr(true),
112+ ProxyWebSockets: boolPtr(true),
113+ },
111114 },
112115 }
113116
@@ -130,7 +133,7 @@ redirect_url="http://localhost:4180/oauth2/callback"
130133 opts.InjectResponseHeaders = append(opts.InjectResponseHeaders, authHeader)
131134
132135 opts.Providers = options.Providers{
133− {
136+ options.Provider{
134137 ID: "google=oauth2-proxy",
135138 Type: "google",
136139 ClientSecret: "b2F1dGgyLXByb3h5LWNsaWVudC1zZWNyZXQK",
@@ -230,7 +233,7 @@ redirect_url="http://localhost:4180/oauth2/callback"
230233 configContent: testCoreConfig,
231234 alphaConfigContent: testAlphaConfig + ":",
232235 expectedOptions: func() *options.Options { return nil },
233− expectedErr: errors.New("failed to load alpha options: error unmarshalling config: error converting YAML to JSON: yaml: line 49: did not find expected key"),
236+ expectedErr: errors.New("failed to load alpha options: error unmarshalling config: error converting YAML to JSON: yaml: line 50: did not find expected key"),
234237 }),
235238 Entry("with alpha configuration and bad core configuration", loadConfigurationTableInput{
236239 configContent: testCoreConfig + "unknown_field=\"something\"",
oauthproxy_test.go+49−33
@@ -198,10 +198,12 @@ func TestBasicAuthPassword(t *testing.T) {
198198 basicAuthPassword := "This is a secure password"
199199 opts := baseTestOptions()
200200 opts.UpstreamServers = options.Upstreams{
201− {
202− ID: providerServer.URL,
203− Path: "/",
204− URI: providerServer.URL,
201+ Configs: []options.Upstream{
202+ {
203+ ID: providerServer.URL,
204+ Path: "/",
205+ URI: providerServer.URL,
206+ },
205207 },
206208 }
207209
@@ -347,14 +349,16 @@ func NewPassAccessTokenTest(opts PassAccessTokenTestOptions) (*PassAccessTokenTe
347349
348350 patt.opts = baseTestOptions()
349351 patt.opts.UpstreamServers = options.Upstreams{
350− {
351− ID: patt.providerServer.URL,
352− Path: "/",
353− URI: patt.providerServer.URL,
352+ Configs: []options.Upstream{
353+ {
354+ ID: patt.providerServer.URL,
355+ Path: "/",
356+ URI: patt.providerServer.URL,
357+ },
354358 },
355359 }
356360 if opts.ProxyUpstream.ID != "" {
357− patt.opts.UpstreamServers = append(patt.opts.UpstreamServers, opts.ProxyUpstream)
361+ patt.opts.UpstreamServers.Configs = append(patt.opts.UpstreamServers.Configs, opts.ProxyUpstream)
358362 }
359363
360364 patt.opts.Cookie.Secure = false
@@ -1270,10 +1274,12 @@ func TestAuthSkippedForPreflightRequests(t *testing.T) {
12701274
12711275 opts := baseTestOptions()
12721276 opts.UpstreamServers = options.Upstreams{
1273− {
1274− ID: upstreamServer.URL,
1275− Path: "/",
1276− URI: upstreamServer.URL,
1277+ Configs: []options.Upstream{
1278+ {
1279+ ID: upstreamServer.URL,
1280+ Path: "/",
1281+ URI: upstreamServer.URL,
1282+ },
12771283 },
12781284 }
12791285 opts.SkipAuthPreflight = true
@@ -1345,10 +1351,12 @@ func NewSignatureTest() (*SignatureTest, error) {
13451351 return nil, err
13461352 }
13471353 opts.UpstreamServers = options.Upstreams{
1348− {
1349− ID: upstreamServer.URL,
1350− Path: "/",
1351− URI: upstreamServer.URL,
1354+ Configs: []options.Upstream{
1355+ {
1356+ ID: upstreamServer.URL,
1357+ Path: "/",
1358+ URI: upstreamServer.URL,
1359+ },
13521360 },
13531361 }
13541362
@@ -1781,10 +1789,12 @@ func Test_noCacheHeaders(t *testing.T) {
17811789
17821790 opts := baseTestOptions()
17831791 opts.UpstreamServers = options.Upstreams{
1784− {
1785− ID: upstreamServer.URL,
1786− Path: "/",
1787− URI: upstreamServer.URL,
1792+ Configs: []options.Upstream{
1793+ {
1794+ ID: upstreamServer.URL,
1795+ Path: "/",
1796+ URI: upstreamServer.URL,
1797+ },
17881798 },
17891799 }
17901800 opts.SkipAuthRegex = []string{".*"}
@@ -2051,10 +2061,12 @@ func TestTrustedIPs(t *testing.T) {
20512061 t.Run(tt.name, func(t *testing.T) {
20522062 opts := baseTestOptions()
20532063 opts.UpstreamServers = options.Upstreams{
2054− {
2055− ID: "static",
2056− Path: "/",
2057− Static: true,
2064+ Configs: []options.Upstream{
2065+ {
2066+ ID: "static",
2067+ Path: "/",
2068+ Static: true,
2069+ },
20582070 },
20592071 }
20602072 opts.TrustedIPs = tt.trustedIPs
@@ -2244,10 +2256,12 @@ func TestAllowedRequest(t *testing.T) {
22442256
22452257 opts := baseTestOptions()
22462258 opts.UpstreamServers = options.Upstreams{
2247− {
2248− ID: upstreamServer.URL,
2249− Path: "/",
2250− URI: upstreamServer.URL,
2259+ Configs: []options.Upstream{
2260+ {
2261+ ID: upstreamServer.URL,
2262+ Path: "/",
2263+ URI: upstreamServer.URL,
2264+ },
22512265 },
22522266 }
22532267 opts.SkipAuthRegex = []string{
@@ -2359,10 +2373,12 @@ func TestProxyAllowedGroups(t *testing.T) {
23592373 test, err := NewProcessCookieTestWithOptionsModifiers(func(opts *options.Options) {
23602374 opts.Providers[0].AllowedGroups = tt.allowedGroups
23612375 opts.UpstreamServers = options.Upstreams{
2362− {
2363− ID: upstreamServer.URL,
2364− Path: "/",
2365− URI: upstreamServer.URL,
2376+ Configs: []options.Upstream{
2377+ {
2378+ ID: upstreamServer.URL,
2379+ Path: "/",
2380+ URI: upstreamServer.URL,
2381+ },
23662382 },
23672383 }
23682384 })
pkg/apis/options/legacy_options.go+2−2
@@ -120,7 +120,7 @@ func (l *LegacyUpstreams) convert() (Upstreams, error) {
120120 for _, upstreamString := range l.Upstreams {
121121 u, err := url.Parse(upstreamString)
122122 if err != nil {
123− return nil, fmt.Errorf("could not parse upstream %q: %v", upstreamString, err)
123+ return Upstreams{}, fmt.Errorf("could not parse upstream %q: %v", upstreamString, err)
124124 }
125125
126126 if u.Path == "" {
@@ -169,7 +169,7 @@ func (l *LegacyUpstreams) convert() (Upstreams, error) {
169169 upstream.FlushInterval = nil
170170 }
171171
172− upstreams = append(upstreams, upstream)
172+ upstreams.Configs = append(upstreams.Configs, upstream)
173173 }
174174
175175 return upstreams, nil
pkg/apis/options/legacy_options_test.go+41−39
@@ -27,34 +27,36 @@ var _ = Describe("Legacy Options", func() {
2727 truth := true
2828 staticCode := 204
2929 opts.UpstreamServers = Upstreams{
30− {
31− ID: "/baz",
32− Path: "/baz",
33− URI: "http://foo.bar/baz",
34− FlushInterval: &flushInterval,
35− InsecureSkipTLSVerify: true,
36− PassHostHeader: &truth,
37− ProxyWebSockets: &truth,
38− },
39− {
40− ID: "/bar",
41− Path: "/bar",
42− URI: "file:///var/lib/website",
43− FlushInterval: &flushInterval,
44− InsecureSkipTLSVerify: true,
45− PassHostHeader: &truth,
46− ProxyWebSockets: &truth,
47− },
48− {
49− ID: "static://204",
50− Path: "/",
51− URI: "",
52− Static: true,
53− StaticCode: &staticCode,
54− FlushInterval: nil,
55− InsecureSkipTLSVerify: false,
56− PassHostHeader: nil,
57− ProxyWebSockets: nil,
30+ Configs: []Upstream{
31+ {
32+ ID: "/baz",
33+ Path: "/baz",
34+ URI: "http://foo.bar/baz",
35+ FlushInterval: &flushInterval,
36+ InsecureSkipTLSVerify: true,
37+ PassHostHeader: &truth,
38+ ProxyWebSockets: &truth,
39+ },
40+ {
41+ ID: "/bar",
42+ Path: "/bar",
43+ URI: "file:///var/lib/website",
44+ FlushInterval: &flushInterval,
45+ InsecureSkipTLSVerify: true,
46+ PassHostHeader: &truth,
47+ ProxyWebSockets: &truth,
48+ },
49+ {
50+ ID: "static://204",
51+ Path: "/",
52+ URI: "",
53+ Static: true,
54+ StaticCode: &staticCode,
55+ FlushInterval: nil,
56+ InsecureSkipTLSVerify: false,
57+ PassHostHeader: nil,
58+ ProxyWebSockets: nil,
59+ },
5860 },
5961 }
6062
@@ -124,7 +126,7 @@ var _ = Describe("Legacy Options", func() {
124126 Context("Legacy Upstreams", func() {
125127 type convertUpstreamsTableInput struct {
126128 upstreamStrings []string
127− expectedUpstreams Upstreams
129+ expectedUpstreams []Upstream
128130 errMsg string
129131 }
130132
@@ -219,51 +221,51 @@ var _ = Describe("Legacy Options", func() {
219221 Expect(err).ToNot(HaveOccurred())
220222 }
221223
222− Expect(upstreams).To(ConsistOf(in.expectedUpstreams))
224+ Expect(upstreams.Configs).To(ConsistOf(in.expectedUpstreams))
223225 },
224226 Entry("with no upstreams", &convertUpstreamsTableInput{
225227 upstreamStrings: []string{},
226− expectedUpstreams: Upstreams{},
228+ expectedUpstreams: []Upstream{},
227229 errMsg: "",
228230 }),
229231 Entry("with a valid HTTP upstream", &convertUpstreamsTableInput{
230232 upstreamStrings: []string{validHTTP},
231− expectedUpstreams: Upstreams{validHTTPUpstream},
233+ expectedUpstreams: []Upstream{validHTTPUpstream},
232234 errMsg: "",
233235 }),
234236 Entry("with a HTTP upstream with an empty path", &convertUpstreamsTableInput{
235237 upstreamStrings: []string{emptyPathHTTP},
236− expectedUpstreams: Upstreams{emptyPathHTTPUpstream},
238+ expectedUpstreams: []Upstream{emptyPathHTTPUpstream},
237239 errMsg: "",
238240 }),
239241 Entry("with a valid File upstream with a fragment", &convertUpstreamsTableInput{
240242 upstreamStrings: []string{validFileWithFragment},
241− expectedUpstreams: Upstreams{validFileWithFragmentUpstream},
243+ expectedUpstreams: []Upstream{validFileWithFragmentUpstream},
242244 errMsg: "",
243245 }),
244246 Entry("with a valid static upstream", &convertUpstreamsTableInput{
245247 upstreamStrings: []string{validStatic},
246− expectedUpstreams: Upstreams{validStaticUpstream},
248+ expectedUpstreams: []Upstream{validStaticUpstream},
247249 errMsg: "",
248250 }),
249251 Entry("with an invalid static upstream, code is 200", &convertUpstreamsTableInput{
250252 upstreamStrings: []string{invalidStatic},
251− expectedUpstreams: Upstreams{invalidStaticUpstream},
253+ expectedUpstreams: []Upstream{invalidStaticUpstream},
252254 errMsg: "",
253255 }),
254256 Entry("with an invalid HTTP upstream", &convertUpstreamsTableInput{
255257 upstreamStrings: []string{invalidHTTP},
256− expectedUpstreams: Upstreams{},
258+ expectedUpstreams: []Upstream{},
257259 errMsg: invalidHTTPErrMsg,
258260 }),
259261 Entry("with an invalid HTTP upstream and other upstreams", &convertUpstreamsTableInput{
260262 upstreamStrings: []string{validHTTP, invalidHTTP},
261− expectedUpstreams: Upstreams{},
263+ expectedUpstreams: []Upstream{},
262264 errMsg: invalidHTTPErrMsg,
263265 }),
264266 Entry("with multiple valid upstreams", &convertUpstreamsTableInput{
265267 upstreamStrings: []string{validHTTP, validFileWithFragment, validStatic},
266− expectedUpstreams: Upstreams{validHTTPUpstream, validFileWithFragmentUpstream, validStaticUpstream},
268+ expectedUpstreams: []Upstream{validHTTPUpstream, validFileWithFragmentUpstream, validStaticUpstream},
267269 errMsg: "",
268270 }),
269271 )
pkg/apis/options/load_test.go+13−10
@@ -470,10 +470,11 @@ sub:
470470 It("should load a full example AlphaOptions", func() {
471471 config := []byte(`
472472upstreams:
473−- id: httpbin
474− path: /
475− uri: http://httpbin
476− flushInterval: 500ms
473+ configs:
474+ - id: httpbin
475+ path: /
476+ uri: http://httpbin
477+ flushInterval: 500ms
477478injectRequestHeaders:
478479- name: X-Forwarded-User
479480 values:
@@ -502,12 +503,14 @@ injectResponseHeaders:
502503 flushInterval := Duration(500 * time.Millisecond)
503504
504505 Expect(into).To(Equal(&AlphaOptions{
505− Upstreams: []Upstream{
506− {
507− ID: "httpbin",
508− Path: "/",
509− URI: "http://httpbin",
510− FlushInterval: &flushInterval,
506+ Upstreams: Upstreams{
507+ Configs: []Upstream{
508+ {
509+ ID: "httpbin",
510+ Path: "/",
511+ URI: "http://httpbin",
512+ FlushInterval: &flushInterval,
513+ },
511514 },
512515 },
513516 InjectRequestHeaders: []Header{
pkg/apis/options/upstreams.go+5−1
@@ -8,7 +8,11 @@ const (
88)
99
1010// Upstreams is a collection of definitions for upstream servers.
11−type Upstreams []Upstream
11+type Upstreams struct {
12+ // Upstream represents the configuration for an upstream server.
13+ // Requests will be proxied to this upstream if the path matches the request path.
14+ Configs []Upstream `json:"configs,omitempty"`
15+}
1216
1317// Upstream represents the configuration for an upstream server.
1418// Requests will be proxied to this upstream if the path matches the request path.
pkg/upstream/proxy.go+2−2
@@ -27,7 +27,7 @@ func NewProxy(upstreams options.Upstreams, sigData *options.SignatureData, write
2727 serveMux: mux.NewRouter(),
2828 }
2929
30− for _, upstream := range sortByPathLongest(upstreams) {
30+ for _, upstream := range sortByPathLongest(upstreams.Configs) {
3131 if upstream.Static {
3232 if err := m.registerStaticResponseHandler(upstream, writer); err != nil {
3333 return nil, fmt.Errorf("could not register static upstream %q: %v", upstream.ID, err)
@@ -153,7 +153,7 @@ func registerTrailingSlashHandler(serveMux *mux.Router) {
153153// precedence (note this is the input to the rewrite logic).
154154// This does not account for when a rewrite would actually make the path shorter.
155155// This should maintain the sorting behaviour of the standard go serve mux.
156−func sortByPathLongest(in options.Upstreams) options.Upstreams {
156+func sortByPathLongest(in []options.Upstream) []options.Upstream {
157157 sort.Slice(in, func(i, j int) bool {
158158 iRW := in[i].RewriteTarget
159159 jRW := in[j].RewriteTarget
pkg/upstream/proxy_test.go+77−75
@@ -33,61 +33,63 @@ var _ = Describe("Proxy Suite", func() {
3333 accepted := http.StatusAccepted
3434
3535 upstreams := options.Upstreams{
36− {
37− ID: "http-backend",
38− Path: "/http/",
39− URI: serverAddr,
40− },
41− {
42− ID: "file-backend",
43− Path: "/files/",
44− URI: fmt.Sprintf("file:///%s", filesDir),
45− },
46− {
47− ID: "static-backend",
48− Path: "/static/",
49− Static: true,
50− StaticCode: &ok,
51− },
52− {
53− ID: "static-backend-no-trailing-slash",
54− Path: "/static",
55− Static: true,
56− StaticCode: &accepted,
57− },
58− {
59− ID: "static-backend-long",
60− Path: "/static/long",
61− Static: true,
62− StaticCode: &accepted,
63− },
64− {
65− ID: "bad-http-backend",
66− Path: "/bad-http/",
67− URI: "http://::1",
68− },
69− {
70− ID: "single-path-backend",
71− Path: "/single-path",
72− Static: true,
73− StaticCode: &ok,
74− },
75− {
76− ID: "backend-with-rewrite-prefix",
77− Path: "^/rewrite-prefix/(.*)",
78− RewriteTarget: "/different/backend/path/$1",
79− URI: serverAddr,
80− },
81− {
82− ID: "double-match-plain",
83− Path: "/double-match/",
84− URI: serverAddr,
85− },
86− {
87− ID: "double-match-rewrite",
88− Path: "^/double-match/(.*)",
89− RewriteTarget: "/double-match/rewrite/$1",
90− URI: serverAddr,
36+ Configs: []options.Upstream{
37+ {
38+ ID: "http-backend",
39+ Path: "/http/",
40+ URI: serverAddr,
41+ },
42+ {
43+ ID: "file-backend",
44+ Path: "/files/",
45+ URI: fmt.Sprintf("file:///%s", filesDir),
46+ },
47+ {
48+ ID: "static-backend",
49+ Path: "/static/",
50+ Static: true,
51+ StaticCode: &ok,
52+ },
53+ {
54+ ID: "static-backend-no-trailing-slash",
55+ Path: "/static",
56+ Static: true,
57+ StaticCode: &accepted,
58+ },
59+ {
60+ ID: "static-backend-long",
61+ Path: "/static/long",
62+ Static: true,
63+ StaticCode: &accepted,
64+ },
65+ {
66+ ID: "bad-http-backend",
67+ Path: "/bad-http/",
68+ URI: "http://::1",
69+ },
70+ {
71+ ID: "single-path-backend",
72+ Path: "/single-path",
73+ Static: true,
74+ StaticCode: &ok,
75+ },
76+ {
77+ ID: "backend-with-rewrite-prefix",
78+ Path: "^/rewrite-prefix/(.*)",
79+ RewriteTarget: "/different/backend/path/$1",
80+ URI: serverAddr,
81+ },
82+ {
83+ ID: "double-match-plain",
84+ Path: "/double-match/",
85+ URI: serverAddr,
86+ },
87+ {
88+ ID: "double-match-rewrite",
89+ Path: "^/double-match/(.*)",
90+ RewriteTarget: "/double-match/rewrite/$1",
91+ URI: serverAddr,
92+ },
9193 },
9294 }
9395
@@ -315,8 +317,8 @@ var _ = Describe("Proxy Suite", func() {
315317
316318 Context("sortByPathLongest", func() {
317319 type sortByPathLongestTableInput struct {
318− input options.Upstreams
319− expectedOutput options.Upstreams
320+ input []options.Upstream
321+ expectedOutput []options.Upstream
320322 }
321323
322324 var httpPath = options.Upstream{
@@ -346,40 +348,40 @@ var _ = Describe("Proxy Suite", func() {
346348 Expect(sortByPathLongest(in.input)).To(Equal(in.expectedOutput))
347349 },
348350 Entry("with a mix of paths registered", sortByPathLongestTableInput{
349− input: options.Upstreams{httpPath, httpSubPath, shortSubPathWithRewrite, longerPath, shortPathWithRewrite},
350− expectedOutput: options.Upstreams{shortSubPathWithRewrite, shortPathWithRewrite, longerPath, httpSubPath, httpPath},
351+ input: []options.Upstream{httpPath, httpSubPath, shortSubPathWithRewrite, longerPath, shortPathWithRewrite},
352+ expectedOutput: []options.Upstream{shortSubPathWithRewrite, shortPathWithRewrite, longerPath, httpSubPath, httpPath},
351353 }),
352354 Entry("when a subpath is registered (in order)", sortByPathLongestTableInput{
353− input: options.Upstreams{httpSubPath, httpPath},
354− expectedOutput: options.Upstreams{httpSubPath, httpPath},
355+ input: []options.Upstream{httpSubPath, httpPath},
356+ expectedOutput: []options.Upstream{httpSubPath, httpPath},
355357 }),
356358 Entry("when a subpath is registered (out of order)", sortByPathLongestTableInput{
357− input: options.Upstreams{httpPath, httpSubPath},
358− expectedOutput: options.Upstreams{httpSubPath, httpPath},
359+ input: []options.Upstream{httpPath, httpSubPath},
360+ expectedOutput: []options.Upstream{httpSubPath, httpPath},
359361 }),
360362 Entry("when longer paths are registered (in order)", sortByPathLongestTableInput{
361− input: options.Upstreams{longerPath, httpPath},
362− expectedOutput: options.Upstreams{longerPath, httpPath},
363+ input: []options.Upstream{longerPath, httpPath},
364+ expectedOutput: []options.Upstream{longerPath, httpPath},
363365 }),
364366 Entry("when longer paths are registered (out of order)", sortByPathLongestTableInput{
365− input: options.Upstreams{httpPath, longerPath},
366− expectedOutput: options.Upstreams{longerPath, httpPath},
367+ input: []options.Upstream{httpPath, longerPath},
368+ expectedOutput: []options.Upstream{longerPath, httpPath},
367369 }),
368370 Entry("when a rewrite target is registered (in order)", sortByPathLongestTableInput{
369− input: options.Upstreams{shortPathWithRewrite, longerPath},
370− expectedOutput: options.Upstreams{shortPathWithRewrite, longerPath},
371+ input: []options.Upstream{shortPathWithRewrite, longerPath},
372+ expectedOutput: []options.Upstream{shortPathWithRewrite, longerPath},
371373 }),
372374 Entry("when a rewrite target is registered (out of order)", sortByPathLongestTableInput{
373− input: options.Upstreams{longerPath, shortPathWithRewrite},
374− expectedOutput: options.Upstreams{shortPathWithRewrite, longerPath},
375+ input: []options.Upstream{longerPath, shortPathWithRewrite},
376+ expectedOutput: []options.Upstream{shortPathWithRewrite, longerPath},
375377 }),
376378 Entry("with multiple rewrite targets registered (in order)", sortByPathLongestTableInput{
377− input: options.Upstreams{shortSubPathWithRewrite, shortPathWithRewrite},
378− expectedOutput: options.Upstreams{shortSubPathWithRewrite, shortPathWithRewrite},
379+ input: []options.Upstream{shortSubPathWithRewrite, shortPathWithRewrite},
380+ expectedOutput: []options.Upstream{shortSubPathWithRewrite, shortPathWithRewrite},
379381 }),
380382 Entry("with multiple rewrite targets registered (out of order)", sortByPathLongestTableInput{
381− input: options.Upstreams{shortPathWithRewrite, shortSubPathWithRewrite},
382− expectedOutput: options.Upstreams{shortSubPathWithRewrite, shortPathWithRewrite},
383+ input: []options.Upstream{shortPathWithRewrite, shortSubPathWithRewrite},
384+ expectedOutput: []options.Upstream{shortSubPathWithRewrite, shortPathWithRewrite},
383385 }),
384386 )
385387 })
pkg/validation/options_test.go+1−1
@@ -22,7 +22,7 @@ const (
2222
2323func testOptions() *options.Options {
2424 o := options.NewOptions()
25− o.UpstreamServers = append(o.UpstreamServers, options.Upstream{
25+ o.UpstreamServers.Configs = append(o.UpstreamServers.Configs, options.Upstream{
2626 ID: "upstream",
2727 Path: "/",
2828 URI: "http://127.0.0.1:8080/",
pkg/validation/upstreams.go+1−1
@@ -12,7 +12,7 @@ func validateUpstreams(upstreams options.Upstreams) []string {
1212 ids := make(map[string]struct{})
1313 paths := make(map[string]struct{})
1414
15− for _, upstream := range upstreams {
15+ for _, upstream := range upstreams.Configs {
1616 msgs = append(msgs, validateUpstream(upstream, ids, paths)...)
1717 }
1818
pkg/validation/upstreams_test.go+80−58
@@ -59,83 +59,99 @@ var _ = Describe("Upstreams", func() {
5959 }),
6060 Entry("with valid upstreams", &validateUpstreamTableInput{
6161 upstreams: options.Upstreams{
62− validHTTPUpstream,
63− validStaticUpstream,
64− validFileUpstream,
62+ Configs: []options.Upstream{
63+ validHTTPUpstream,
64+ validStaticUpstream,
65+ validFileUpstream,
66+ },
6567 },
6668 errStrings: []string{},
6769 }),
6870 Entry("with an empty ID", &validateUpstreamTableInput{
6971 upstreams: options.Upstreams{
70− {
71− ID: "",
72− Path: "/foo",
73− URI: "http://localhost:8080",
72+ Configs: []options.Upstream{
73+ {
74+ ID: "",
75+ Path: "/foo",
76+ URI: "http://localhost:8080",
77+ },
7478 },
7579 },
7680 errStrings: []string{emptyIDMsg},
7781 }),
7882 Entry("with an empty Path", &validateUpstreamTableInput{
7983 upstreams: options.Upstreams{
80− {
81− ID: "foo",
82− Path: "",
83− URI: "http://localhost:8080",
84+ Configs: []options.Upstream{
85+ {
86+ ID: "foo",
87+ Path: "",
88+ URI: "http://localhost:8080",
89+ },
8490 },
8591 },
8692 errStrings: []string{emptyPathMsg},
8793 }),
8894 Entry("with an empty Path", &validateUpstreamTableInput{
8995 upstreams: options.Upstreams{
90− {
91− ID: "foo",
92− Path: "",
93− URI: "http://localhost:8080",
96+ Configs: []options.Upstream{
97+ {
98+ ID: "foo",
99+ Path: "",
100+ URI: "http://localhost:8080",
101+ },
94102 },
95103 },
96104 errStrings: []string{emptyPathMsg},
97105 }),
98106 Entry("with an empty URI", &validateUpstreamTableInput{
99107 upstreams: options.Upstreams{
100− {
101− ID: "foo",
102− Path: "/foo",
103− URI: "",
108+ Configs: []options.Upstream{
109+ {
110+ ID: "foo",
111+ Path: "/foo",
112+ URI: "",
113+ },
104114 },
105115 },
106116 errStrings: []string{emptyURIMsg},
107117 }),
108118 Entry("with an invalid URI", &validateUpstreamTableInput{
109119 upstreams: options.Upstreams{
110− {
111− ID: "foo",
112− Path: "/foo",
113− URI: ":",
120+ Configs: []options.Upstream{
121+ {
122+ ID: "foo",
123+ Path: "/foo",
124+ URI: ":",
125+ },
114126 },
115127 },
116128 errStrings: []string{invalidURIMsg},
117129 }),
118130 Entry("with an invalid URI scheme", &validateUpstreamTableInput{
119131 upstreams: options.Upstreams{
120− {
121− ID: "foo",
122− Path: "/foo",
123− URI: "ftp://foo",
132+ Configs: []options.Upstream{
133+ {
134+ ID: "foo",
135+ Path: "/foo",
136+ URI: "ftp://foo",
137+ },
124138 },
125139 },
126140 errStrings: []string{invalidURISchemeMsg},
127141 }),
128142 Entry("with a static upstream and invalid optons", &validateUpstreamTableInput{
129143 upstreams: options.Upstreams{
130− {
131− ID: "foo",
132− Path: "/foo",
133− URI: "ftp://foo",
134− Static: true,
135− FlushInterval: &flushInterval,
136− PassHostHeader: &truth,
137− ProxyWebSockets: &truth,
138− InsecureSkipTLSVerify: true,
144+ Configs: []options.Upstream{
145+ {
146+ ID: "foo",
147+ Path: "/foo",
148+ URI: "ftp://foo",
149+ Static: true,
150+ FlushInterval: &flushInterval,
151+ PassHostHeader: &truth,
152+ ProxyWebSockets: &truth,
153+ InsecureSkipTLSVerify: true,
154+ },
139155 },
140156 },
141157 errStrings: []string{
@@ -148,40 +164,46 @@ var _ = Describe("Upstreams", func() {
148164 }),
149165 Entry("with duplicate IDs", &validateUpstreamTableInput{
150166 upstreams: options.Upstreams{
151− {
152− ID: "foo",
153− Path: "/foo1",
154− URI: "http://foo",
155− },
156− {
157− ID: "foo",
158− Path: "/foo2",
159− URI: "http://foo",
167+ Configs: []options.Upstream{
168+ {
169+ ID: "foo",
170+ Path: "/foo1",
171+ URI: "http://foo",
172+ },
173+ {
174+ ID: "foo",
175+ Path: "/foo2",
176+ URI: "http://foo",
177+ },
160178 },
161179 },
162180 errStrings: []string{multipleIDsMsg},
163181 }),
164182 Entry("with duplicate Paths", &validateUpstreamTableInput{
165183 upstreams: options.Upstreams{
166− {
167− ID: "foo1",
168− Path: "/foo",
169− URI: "http://foo",
170− },
171− {
172− ID: "foo2",
173− Path: "/foo",
174− URI: "http://foo",
184+ Configs: []options.Upstream{
185+ {
186+ ID: "foo1",
187+ Path: "/foo",
188+ URI: "http://foo",
189+ },
190+ {
191+ ID: "foo2",
192+ Path: "/foo",
193+ URI: "http://foo",
194+ },
175195 },
176196 },
177197 errStrings: []string{multiplePathsMsg},
178198 }),
179199 Entry("when a static code is supplied without static", &validateUpstreamTableInput{
180200 upstreams: options.Upstreams{
181− {
182− ID: "foo",
183− Path: "/foo",
184− StaticCode: &staticCode200,
201+ Configs: []options.Upstream{
202+ {
203+ ID: "foo",
204+ Path: "/foo",
205+ StaticCode: &staticCode200,
206+ },
185207 },
186208 },
187209 errStrings: []string{emptyURIMsg, staticCodeMsg},