Split implementations from generic code
This commit is contained in:
parent
d1e8a629ca
commit
ed9a416b01
107 changed files with 5777 additions and 3546 deletions
122
controllers/nginx/pkg/template/configmap.go
Normal file
122
controllers/nginx/pkg/template/configmap.go
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package template
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/imdario/mergo"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
go_camelcase "github.com/segmentio/go-camelcase"
|
||||
|
||||
"k8s.io/ingress/controllers/nginx/pkg/config"
|
||||
"k8s.io/ingress/core/pkg/ingress/defaults"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
)
|
||||
|
||||
const (
|
||||
customHTTPErrors = "custom-http-errors"
|
||||
skipAccessLogUrls = "skip-access-log-urls"
|
||||
whitelistSourceRange = "whitelist-source-range"
|
||||
)
|
||||
|
||||
// StandarizeKeyNames ...
|
||||
func StandarizeKeyNames(data interface{}) map[string]interface{} {
|
||||
return fixKeyNames(structs.Map(data))
|
||||
}
|
||||
|
||||
// ReadConfig obtains the configuration defined by the user merged with the defaults.
|
||||
func ReadConfig(conf *api.ConfigMap) config.Configuration {
|
||||
if len(conf.Data) == 0 {
|
||||
return config.NewDefault()
|
||||
}
|
||||
|
||||
var errors []int
|
||||
var skipUrls []string
|
||||
var whitelist []string
|
||||
|
||||
if val, ok := conf.Data[customHTTPErrors]; ok {
|
||||
delete(conf.Data, customHTTPErrors)
|
||||
for _, i := range strings.Split(val, ",") {
|
||||
j, err := strconv.Atoi(i)
|
||||
if err != nil {
|
||||
glog.Warningf("%v is not a valid http code: %v", i, err)
|
||||
} else {
|
||||
errors = append(errors, j)
|
||||
}
|
||||
}
|
||||
}
|
||||
if val, ok := conf.Data[skipAccessLogUrls]; ok {
|
||||
delete(conf.Data, skipAccessLogUrls)
|
||||
skipUrls = strings.Split(val, ",")
|
||||
}
|
||||
if val, ok := conf.Data[whitelistSourceRange]; ok {
|
||||
delete(conf.Data, whitelistSourceRange)
|
||||
whitelist = append(whitelist, strings.Split(val, ",")...)
|
||||
}
|
||||
|
||||
to := config.Configuration{}
|
||||
to.Backend = defaults.Backend{
|
||||
CustomHTTPErrors: filterErrors(errors),
|
||||
SkipAccessLogURLs: skipUrls,
|
||||
WhitelistSourceRange: whitelist,
|
||||
}
|
||||
def := config.NewDefault()
|
||||
if err := mergo.Merge(&to, def); err != nil {
|
||||
glog.Warningf("unexpected error merging defaults: %v", err)
|
||||
}
|
||||
|
||||
metadata := &mapstructure.Metadata{}
|
||||
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
||||
TagName: "structs",
|
||||
Result: &to,
|
||||
WeaklyTypedInput: true,
|
||||
Metadata: metadata,
|
||||
})
|
||||
|
||||
err = decoder.Decode(conf.Data)
|
||||
if err != nil {
|
||||
glog.Infof("%v", err)
|
||||
}
|
||||
return to
|
||||
}
|
||||
|
||||
func filterErrors(codes []int) []int {
|
||||
var fa []int
|
||||
for _, code := range codes {
|
||||
if code > 299 && code < 600 {
|
||||
fa = append(fa, code)
|
||||
} else {
|
||||
glog.Warningf("error code %v is not valid for custom error pages", code)
|
||||
}
|
||||
}
|
||||
|
||||
return fa
|
||||
}
|
||||
|
||||
func fixKeyNames(data map[string]interface{}) map[string]interface{} {
|
||||
fixed := make(map[string]interface{})
|
||||
for k, v := range data {
|
||||
fixed[go_camelcase.Camelcase(k)] = v
|
||||
}
|
||||
return fixed
|
||||
}
|
||||
83
controllers/nginx/pkg/template/configmap_test.go
Normal file
83
controllers/nginx/pkg/template/configmap_test.go
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package template
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/ingress/controllers/nginx/pkg/config"
|
||||
)
|
||||
|
||||
func TestStandarizeKeyNames(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFilterErrors(t *testing.T) {
|
||||
e := filterErrors([]int{200, 300, 345, 500, 555, 999})
|
||||
if len(e) != 4 {
|
||||
t.Errorf("expected 4 elements but %v returned", len(e))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFixKeyNames(t *testing.T) {
|
||||
d := map[string]interface{}{
|
||||
"one": "one",
|
||||
"one-example": "oneExample",
|
||||
"aMore-complex_example": "aMoreComplexExample",
|
||||
"a": "a",
|
||||
}
|
||||
|
||||
fixed := fixKeyNames(d)
|
||||
for k, v := range fixed {
|
||||
if k != v {
|
||||
t.Errorf("expected %v but retuned %v", v, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type testStruct struct {
|
||||
ProxyReadTimeout int `structs:"proxy-read-timeout,omitempty"`
|
||||
ProxySendTimeout int `structs:"proxy-send-timeout,omitempty"`
|
||||
CustomHTTPErrors []int `structs:"custom-http-errors"`
|
||||
SkipAccessLogURLs []string `structs:"skip-access-log-urls,-"`
|
||||
NoTag string
|
||||
}
|
||||
|
||||
var decodedData = &testStruct{
|
||||
1,
|
||||
2,
|
||||
[]int{300, 400},
|
||||
[]string{"/log"},
|
||||
"",
|
||||
}
|
||||
|
||||
func TestMergeConfigMapToStruct(t *testing.T) {
|
||||
/*conf := &api.ConfigMap{
|
||||
Data: map[string]string{
|
||||
"custom-http-errors": "300,400",
|
||||
"proxy-read-timeout": "1",
|
||||
"proxy-send-timeout": "2",
|
||||
"skip-access-log-urls": "/log",
|
||||
},
|
||||
}*/
|
||||
def := config.NewDefault()
|
||||
def.CustomHTTPErrors = []int{300, 400}
|
||||
def.SkipAccessLogURLs = []string{"/log"}
|
||||
//to := ReadConfig(conf)
|
||||
//if !reflect.DeepEqual(def, to) {
|
||||
// t.Errorf("expected %v but retuned %v", def, to)
|
||||
//}
|
||||
}
|
||||
300
controllers/nginx/pkg/template/template.go
Normal file
300
controllers/nginx/pkg/template/template.go
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package template
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
text_template "text/template"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/ingress/core/pkg/ingress"
|
||||
"k8s.io/ingress/core/pkg/watch"
|
||||
)
|
||||
|
||||
const (
|
||||
slash = "/"
|
||||
defBufferSize = 65535
|
||||
)
|
||||
|
||||
// Template ...
|
||||
type Template struct {
|
||||
tmpl *text_template.Template
|
||||
fw watch.FileWatcher
|
||||
s int
|
||||
tmplBuf *bytes.Buffer
|
||||
outCmdBuf *bytes.Buffer
|
||||
}
|
||||
|
||||
//NewTemplate returns a new Template instance or an
|
||||
//error if the specified template file contains errors
|
||||
func NewTemplate(file string, onChange func()) (*Template, error) {
|
||||
tmpl, err := text_template.New("nginx.tmpl").Funcs(funcMap).ParseFiles(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fw, err := watch.NewFileWatcher(file, onChange)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Template{
|
||||
tmpl: tmpl,
|
||||
fw: fw,
|
||||
s: defBufferSize,
|
||||
tmplBuf: bytes.NewBuffer(make([]byte, 0, defBufferSize)),
|
||||
outCmdBuf: bytes.NewBuffer(make([]byte, 0, defBufferSize)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Close removes the file watcher
|
||||
func (t *Template) Close() {
|
||||
t.fw.Close()
|
||||
}
|
||||
|
||||
// Write populates a buffer using a template with NGINX configuration
|
||||
// and the servers and upstreams created by Ingress rules
|
||||
func (t *Template) Write(conf map[string]interface{},
|
||||
isValidTemplate func([]byte) error) ([]byte, error) {
|
||||
|
||||
defer t.tmplBuf.Reset()
|
||||
defer t.outCmdBuf.Reset()
|
||||
|
||||
if glog.V(3) {
|
||||
b, err := json.Marshal(conf)
|
||||
if err != nil {
|
||||
glog.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
glog.Infof("NGINX configuration: %v", string(b))
|
||||
}
|
||||
|
||||
err := t.tmpl.Execute(t.tmplBuf, conf)
|
||||
|
||||
if t.s < t.tmplBuf.Cap() {
|
||||
glog.V(2).Infof("adjusting template buffer size from %v to %v", t.s, t.tmplBuf.Cap())
|
||||
t.s = t.tmplBuf.Cap()
|
||||
t.tmplBuf = bytes.NewBuffer(make([]byte, 0, t.tmplBuf.Cap()))
|
||||
t.outCmdBuf = bytes.NewBuffer(make([]byte, 0, t.outCmdBuf.Cap()))
|
||||
}
|
||||
|
||||
// squeezes multiple adjacent empty lines to be single
|
||||
// spaced this is to avoid the use of regular expressions
|
||||
cmd := exec.Command("/ingress-controller/clean-nginx-conf.sh")
|
||||
cmd.Stdin = t.tmplBuf
|
||||
cmd.Stdout = t.outCmdBuf
|
||||
if err := cmd.Run(); err != nil {
|
||||
glog.Warningf("unexpected error cleaning template: %v", err)
|
||||
return t.tmplBuf.Bytes(), nil
|
||||
}
|
||||
|
||||
content := t.outCmdBuf.Bytes()
|
||||
err = isValidTemplate(content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return content, nil
|
||||
}
|
||||
|
||||
var (
|
||||
funcMap = text_template.FuncMap{
|
||||
"empty": func(input interface{}) bool {
|
||||
check, ok := input.(string)
|
||||
if ok {
|
||||
return len(check) == 0
|
||||
}
|
||||
return true
|
||||
},
|
||||
"buildLocation": buildLocation,
|
||||
"buildAuthLocation": buildAuthLocation,
|
||||
"buildProxyPass": buildProxyPass,
|
||||
"buildRateLimitZones": buildRateLimitZones,
|
||||
"buildRateLimit": buildRateLimit,
|
||||
"getSSPassthroughUpstream": getSSPassthroughUpstream,
|
||||
|
||||
"contains": strings.Contains,
|
||||
"hasPrefix": strings.HasPrefix,
|
||||
"hasSuffix": strings.HasSuffix,
|
||||
"toUpper": strings.ToUpper,
|
||||
"toLower": strings.ToLower,
|
||||
}
|
||||
)
|
||||
|
||||
func getSSPassthroughUpstream(input interface{}) string {
|
||||
s, ok := input.(*ingress.Server)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
return s.Name
|
||||
}
|
||||
|
||||
// buildLocation produces the location string, if the ingress has redirects
|
||||
// (specified through the ingress.kubernetes.io/rewrite-to annotation)
|
||||
func buildLocation(input interface{}) string {
|
||||
location, ok := input.(*ingress.Location)
|
||||
if !ok {
|
||||
return slash
|
||||
}
|
||||
|
||||
path := location.Path
|
||||
if len(location.Redirect.Target) > 0 && location.Redirect.Target != path {
|
||||
return fmt.Sprintf("~* %s", path)
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
func buildAuthLocation(input interface{}) string {
|
||||
location, ok := input.(*ingress.Location)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
if location.ExternalAuth.URL == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
str := base64.URLEncoding.EncodeToString([]byte(location.Path))
|
||||
// avoid locations containing the = char
|
||||
str = strings.Replace(str, "=", "", -1)
|
||||
return fmt.Sprintf("/_external-auth-%v", str)
|
||||
}
|
||||
|
||||
// buildProxyPass produces the proxy pass string, if the ingress has redirects
|
||||
// (specified through the ingress.kubernetes.io/rewrite-to annotation)
|
||||
// If the annotation ingress.kubernetes.io/add-base-url:"true" is specified it will
|
||||
// add a base tag in the head of the response from the service
|
||||
func buildProxyPass(input interface{}) string {
|
||||
location, ok := input.(*ingress.Location)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
path := location.Path
|
||||
|
||||
proto := "http"
|
||||
if location.SecureUpstream {
|
||||
proto = "https"
|
||||
}
|
||||
// defProxyPass returns the default proxy_pass, just the name of the upstream
|
||||
defProxyPass := fmt.Sprintf("proxy_pass %s://%s;", proto, location.Upstream.Name)
|
||||
// if the path in the ingress rule is equals to the target: no special rewrite
|
||||
if path == location.Redirect.Target {
|
||||
return defProxyPass
|
||||
}
|
||||
|
||||
if path != slash && !strings.HasSuffix(path, slash) {
|
||||
path = fmt.Sprintf("%s/", path)
|
||||
}
|
||||
|
||||
if len(location.Redirect.Target) > 0 {
|
||||
abu := ""
|
||||
if location.Redirect.AddBaseURL {
|
||||
bPath := location.Redirect.Target
|
||||
if !strings.HasSuffix(bPath, slash) {
|
||||
bPath = fmt.Sprintf("%s/", bPath)
|
||||
}
|
||||
|
||||
abu = fmt.Sprintf(`subs_filter '<head(.*)>' '<head$1><base href="$scheme://$server_name%v">' r;
|
||||
subs_filter '<HEAD(.*)>' '<HEAD$1><base href="$scheme://$server_name%v">' r;
|
||||
`, bPath, bPath)
|
||||
}
|
||||
|
||||
if location.Redirect.Target == slash {
|
||||
// special case redirect to /
|
||||
// ie /something to /
|
||||
return fmt.Sprintf(`
|
||||
rewrite %s(.*) /$1 break;
|
||||
rewrite %s / break;
|
||||
proxy_pass %s://%s;
|
||||
%v`, path, location.Path, proto, location.Upstream.Name, abu)
|
||||
}
|
||||
|
||||
return fmt.Sprintf(`
|
||||
rewrite %s(.*) %s/$1 break;
|
||||
proxy_pass %s://%s;
|
||||
%v`, path, location.Redirect.Target, proto, location.Upstream.Name, abu)
|
||||
}
|
||||
|
||||
// default proxy_pass
|
||||
return defProxyPass
|
||||
}
|
||||
|
||||
// buildRateLimitZones produces an array of limit_conn_zone in order to allow
|
||||
// rate limiting of request. Each Ingress rule could have up to two zones, one
|
||||
// for connection limit by IP address and other for limiting request per second
|
||||
func buildRateLimitZones(input interface{}) []string {
|
||||
zones := []string{}
|
||||
|
||||
servers, ok := input.([]*ingress.Server)
|
||||
if !ok {
|
||||
return zones
|
||||
}
|
||||
|
||||
for _, server := range servers {
|
||||
for _, loc := range server.Locations {
|
||||
|
||||
if loc.RateLimit.Connections.Limit > 0 {
|
||||
zone := fmt.Sprintf("limit_conn_zone $binary_remote_addr zone=%v:%vm;",
|
||||
loc.RateLimit.Connections.Name,
|
||||
loc.RateLimit.Connections.SharedSize)
|
||||
zones = append(zones, zone)
|
||||
}
|
||||
|
||||
if loc.RateLimit.RPS.Limit > 0 {
|
||||
zone := fmt.Sprintf("limit_conn_zone $binary_remote_addr zone=%v:%vm rate=%vr/s;",
|
||||
loc.RateLimit.Connections.Name,
|
||||
loc.RateLimit.Connections.SharedSize,
|
||||
loc.RateLimit.Connections.Limit)
|
||||
zones = append(zones, zone)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return zones
|
||||
}
|
||||
|
||||
// buildRateLimit produces an array of limit_req to be used inside the Path of
|
||||
// Ingress rules. The order: connections by IP first and RPS next.
|
||||
func buildRateLimit(input interface{}) []string {
|
||||
limits := []string{}
|
||||
|
||||
loc, ok := input.(*ingress.Location)
|
||||
if !ok {
|
||||
return limits
|
||||
}
|
||||
|
||||
if loc.RateLimit.Connections.Limit > 0 {
|
||||
limit := fmt.Sprintf("limit_conn %v %v;",
|
||||
loc.RateLimit.Connections.Name, loc.RateLimit.Connections.Limit)
|
||||
limits = append(limits, limit)
|
||||
}
|
||||
|
||||
if loc.RateLimit.RPS.Limit > 0 {
|
||||
limit := fmt.Sprintf("limit_req zone=%v burst=%v nodelay;",
|
||||
loc.RateLimit.Connections.Name, loc.RateLimit.Connections.Burst)
|
||||
limits = append(limits, limit)
|
||||
}
|
||||
|
||||
return limits
|
||||
}
|
||||
99
controllers/nginx/pkg/template/template_test.go
Normal file
99
controllers/nginx/pkg/template/template_test.go
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package template
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/ingress/core/pkg/ingress"
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/rewrite"
|
||||
)
|
||||
|
||||
var (
|
||||
tmplFuncTestcases = map[string]struct {
|
||||
Path string
|
||||
Target string
|
||||
Location string
|
||||
ProxyPass string
|
||||
AddBaseURL bool
|
||||
}{
|
||||
"invalid redirect / to /": {"/", "/", "/", "proxy_pass http://upstream-name;", false},
|
||||
"redirect / to /jenkins": {"/", "/jenkins", "~* /",
|
||||
`
|
||||
rewrite /(.*) /jenkins/$1 break;
|
||||
proxy_pass http://upstream-name;
|
||||
`, false},
|
||||
"redirect /something to /": {"/something", "/", "~* /something", `
|
||||
rewrite /something/(.*) /$1 break;
|
||||
rewrite /something / break;
|
||||
proxy_pass http://upstream-name;
|
||||
`, false},
|
||||
"redirect /something-complex to /not-root": {"/something-complex", "/not-root", "~* /something-complex", `
|
||||
rewrite /something-complex/(.*) /not-root/$1 break;
|
||||
proxy_pass http://upstream-name;
|
||||
`, false},
|
||||
"redirect / to /jenkins and rewrite": {"/", "/jenkins", "~* /", `
|
||||
rewrite /(.*) /jenkins/$1 break;
|
||||
proxy_pass http://upstream-name;
|
||||
subs_filter '<head(.*)>' '<head$1><base href="$scheme://$server_name/jenkins/">' r;
|
||||
subs_filter '<HEAD(.*)>' '<HEAD$1><base href="$scheme://$server_name/jenkins/">' r;
|
||||
`, true},
|
||||
"redirect /something to / and rewrite": {"/something", "/", "~* /something", `
|
||||
rewrite /something/(.*) /$1 break;
|
||||
rewrite /something / break;
|
||||
proxy_pass http://upstream-name;
|
||||
subs_filter '<head(.*)>' '<head$1><base href="$scheme://$server_name/">' r;
|
||||
subs_filter '<HEAD(.*)>' '<HEAD$1><base href="$scheme://$server_name/">' r;
|
||||
`, true},
|
||||
"redirect /something-complex to /not-root and rewrite": {"/something-complex", "/not-root", "~* /something-complex", `
|
||||
rewrite /something-complex/(.*) /not-root/$1 break;
|
||||
proxy_pass http://upstream-name;
|
||||
subs_filter '<head(.*)>' '<head$1><base href="$scheme://$server_name/not-root/">' r;
|
||||
subs_filter '<HEAD(.*)>' '<HEAD$1><base href="$scheme://$server_name/not-root/">' r;
|
||||
`, true},
|
||||
}
|
||||
)
|
||||
|
||||
func TestBuildLocation(t *testing.T) {
|
||||
for k, tc := range tmplFuncTestcases {
|
||||
loc := &ingress.Location{
|
||||
Path: tc.Path,
|
||||
Redirect: rewrite.Redirect{Target: tc.Target, AddBaseURL: tc.AddBaseURL},
|
||||
}
|
||||
|
||||
newLoc := buildLocation(loc)
|
||||
if tc.Location != newLoc {
|
||||
t.Errorf("%s: expected '%v' but returned %v", k, tc.Location, newLoc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildProxyPass(t *testing.T) {
|
||||
for k, tc := range tmplFuncTestcases {
|
||||
loc := &ingress.Location{
|
||||
Path: tc.Path,
|
||||
Redirect: rewrite.Redirect{Target: tc.Target, AddBaseURL: tc.AddBaseURL},
|
||||
Upstream: ingress.Upstream{Name: "upstream-name"},
|
||||
}
|
||||
|
||||
pp := buildProxyPass(loc)
|
||||
if !strings.EqualFold(tc.ProxyPass, pp) {
|
||||
t.Errorf("%s: expected \n'%v'\nbut returned \n'%v'", k, tc.ProxyPass, pp)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue