diff --git a/controllers/nginx/controller.go b/controllers/nginx/controller.go index d1fb498f8..84653bab9 100644 --- a/controllers/nginx/controller.go +++ b/controllers/nginx/controller.go @@ -48,7 +48,7 @@ import ( const ( defUpstreamName = "upstream-default-backend" defServerName = "_" - namedPortAnnotation = "kubernetes.io/ingress-named-ports" + namedPortAnnotation = "ingress.kubernetes.io/named-ports" podStoreSyncedPollPeriod = 1 * time.Second rootLocation = "/" ) diff --git a/controllers/nginx/examples/rewrite/README.md b/controllers/nginx/examples/rewrite/README.md new file mode 100644 index 000000000..507b4315a --- /dev/null +++ b/controllers/nginx/examples/rewrite/README.md @@ -0,0 +1,67 @@ + +Create an Ingress rule with a rewrite annotation: +``` +$ echo " +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + annotations: + ingress.kubernetes.io/rewrite-target: / + name: rewrite + namespace: default +spec: + rules: + - host: rewrite.bar.com + http: + paths: + - backend: + serviceName: echoheaders + servicePort: 80 + path: /something +" | kubectl create -f - +``` + +Check the rewrite is working + +``` +$ curl -v http://172.17.4.99/something -H 'Host: rewrite.bar.com' +* Trying 172.17.4.99... +* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0) +> GET /something HTTP/1.1 +> Host: rewrite.bar.com +> User-Agent: curl/7.43.0 +> Accept: */* +> +< HTTP/1.1 200 OK +< Server: nginx/1.11.0 +< Date: Tue, 31 May 2016 16:07:31 GMT +< Content-Type: text/plain +< Transfer-Encoding: chunked +< Connection: keep-alive +< +CLIENT VALUES: +client_address=10.2.56.9 +command=GET +real path=/ +query=nil +request_version=1.1 +request_uri=http://rewrite.bar.com:8080/ + +SERVER VALUES: +server_version=nginx: 1.9.11 - lua: 10001 + +HEADERS RECEIVED: +accept=*/* +connection=close +host=rewrite.bar.com +user-agent=curl/7.43.0 +x-forwarded-for=10.2.56.1 +x-forwarded-host=rewrite.bar.com +x-forwarded-port=80 +x-forwarded-proto=http +x-real-ip=10.2.56.1 +BODY: +* Connection #0 to host 172.17.4.99 left intact +-no body in request- +``` + diff --git a/controllers/nginx/nginx.tmpl b/controllers/nginx/nginx.tmpl index 812f7f438..68277d351 100644 --- a/controllers/nginx/nginx.tmpl +++ b/controllers/nginx/nginx.tmpl @@ -177,8 +177,10 @@ http { {{ if $cfg.enableVtsStatus }}vhost_traffic_status_filter_by_set_key $geoip_country_code country::$server_name;{{ end }} - {{ range $location := $server.Locations }} - location {{ $location.Path }} { + {{- range $location := $server.Locations }} + {{- $path := buildLocation $location }} + location {{ $path }} { + location {{ $path }} { proxy_set_header Host $host; # Pass Real IP @@ -202,7 +204,12 @@ http { proxy_http_version 1.1; - proxy_pass http://{{ $location.Upstream.Name }}; + {{/* rewrite only works if the content is not compressed */}} + {{ if $location.Redirect.AddBaseURL -}} + proxy_set_header Accept-Encoding ""; + {{- end }} + + {{- buildProxyPass $location }} } {{ end }} diff --git a/controllers/nginx/nginx/rewrite/main.go b/controllers/nginx/nginx/rewrite/main.go index f2726ad91..ed17f31a3 100644 --- a/controllers/nginx/nginx/rewrite/main.go +++ b/controllers/nginx/nginx/rewrite/main.go @@ -17,68 +17,57 @@ limitations under the License. package rewrite import ( + "errors" "strconv" "k8s.io/kubernetes/pkg/apis/extensions" ) const ( - rewrite = "ingress-nginx.kubernetes.io/rewrite-to" - fixUrls = "ingress-nginx.kubernetes.io/fix-urls" + rewriteTo = "ingress.kubernetes.io/rewrite-target" + addBaseURL = "ingress.kubernetes.io/add-base-url" ) -// ErrMissingAnnotations is returned when the ingress rule -// does not contains annotations related with redirect or strip prefix -type ErrMissingAnnotations struct { - msg string -} - -func (e ErrMissingAnnotations) Error() string { - return e.msg -} - // Redirect returns authentication configuration for an Ingress rule type Redirect struct { - // To URI where the traffic must be redirected - To string - // Rewrite indicates if is required to change the - // links in the response from the upstream servers - Rewrite bool + // Target URI where the traffic must be redirected + Target string + // AddBaseURL indicates if is required to add a base tag in the head + // of the responses from the upstream servers + AddBaseURL bool } type ingAnnotations map[string]string -func (a ingAnnotations) rewrite() string { - val, ok := a[rewrite] - if ok { - return val - } - - return "" -} - -func (a ingAnnotations) fixUrls() bool { - val, ok := a[fixUrls] +func (a ingAnnotations) addBaseURL() bool { + val, ok := a[addBaseURL] if ok { if b, err := strconv.ParseBool(val); err == nil { return b } } - return false } +func (a ingAnnotations) rewriteTo() string { + val, ok := a[rewriteTo] + if ok { + return val + } + return "" +} + // ParseAnnotations parses the annotations contained in the ingress // rule used to rewrite the defined paths func ParseAnnotations(ing *extensions.Ingress) (*Redirect, error) { if ing.GetAnnotations() == nil { - return &Redirect{}, ErrMissingAnnotations{"no annotations present"} + return &Redirect{}, errors.New("no annotations present") } - rt := ingAnnotations(ing.GetAnnotations()).rewrite() - rw := ingAnnotations(ing.GetAnnotations()).fixUrls() + rt := ingAnnotations(ing.GetAnnotations()).rewriteTo() + abu := ingAnnotations(ing.GetAnnotations()).addBaseURL() return &Redirect{ - To: rt, - Rewrite: rw, + Target: rt, + AddBaseURL: abu, }, nil } diff --git a/controllers/nginx/nginx/rewrite/main_test.go b/controllers/nginx/nginx/rewrite/main_test.go index 6fc500c0b..cd8cf843e 100644 --- a/controllers/nginx/nginx/rewrite/main_test.go +++ b/controllers/nginx/nginx/rewrite/main_test.go @@ -66,29 +66,29 @@ func buildIngress() *extensions.Ingress { func TestAnnotations(t *testing.T) { ing := buildIngress() - r := ingAnnotations(ing.GetAnnotations()).rewrite() + r := ingAnnotations(ing.GetAnnotations()).rewriteTo() if r != "" { t.Error("Expected no redirect") } - f := ingAnnotations(ing.GetAnnotations()).fixUrls() + f := ingAnnotations(ing.GetAnnotations()).addBaseURL() if f != false { - t.Error("Expected false as fix-urls but %v was returend", f) + t.Error("Expected false in add-base-url but %v was returend", f) } data := map[string]string{} - data[rewrite] = defRoute - data[fixUrls] = "true" + data[rewriteTo] = defRoute + data[addBaseURL] = "true" ing.SetAnnotations(data) - r = ingAnnotations(ing.GetAnnotations()).rewrite() + r = ingAnnotations(ing.GetAnnotations()).rewriteTo() if r != defRoute { - t.Error("Expected %v as rewrite but %v was returend", defRoute, r) + t.Error("Expected %v in rewrite but %v was returend", defRoute, r) } - f = ingAnnotations(ing.GetAnnotations()).fixUrls() + f = ingAnnotations(ing.GetAnnotations()).addBaseURL() if f != true { - t.Error("Expected true as fix-urls but %v was returend", f) + t.Error("Expected true in add-base-url but %v was returend", f) } } @@ -104,7 +104,7 @@ func TestRedirect(t *testing.T) { ing := buildIngress() data := map[string]string{} - data[rewrite] = defRoute + data[rewriteTo] = defRoute ing.SetAnnotations(data) redirect, err := ParseAnnotations(ing) @@ -112,7 +112,7 @@ func TestRedirect(t *testing.T) { t.Errorf("Uxpected error with ingress: %v", err) } - if redirect.To != defRoute { - t.Errorf("Expected %v as redirect but returned %s", defRoute, redirect.To) + if redirect.Target != defRoute { + t.Errorf("Expected %v as redirect but returned %s", defRoute, redirect.Target) } } diff --git a/controllers/nginx/nginx/template.go b/controllers/nginx/nginx/template.go index b1b0b1cfc..a844cb944 100644 --- a/controllers/nginx/nginx/template.go +++ b/controllers/nginx/nginx/template.go @@ -109,6 +109,8 @@ func toCamelCase(src string) string { return string(bytes.Join(chunks, nil)) } +// 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.(*Location) if !ok { @@ -116,16 +118,17 @@ func buildLocation(input interface{}) string { } path := location.Path - if len(location.Redirect.To) > 0 && location.Redirect.To != path { - // if path != slash && !strings.HasSuffix(path, slash) { - // path = fmt.Sprintf("%s/", path) - // } + if len(location.Redirect.Target) > 0 && location.Redirect.Target != path { return fmt.Sprintf("~* %s", path) } return path } +// 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.(*Location) if !ok { @@ -134,34 +137,46 @@ func buildProxyPass(input interface{}) string { path := location.Path - if path == location.Redirect.To { - return fmt.Sprintf("proxy_pass http://%s;", location.Upstream.Name) + // defProxyPass returns the default proxy_pass, just the name of the upstream + defProxyPass := fmt.Sprintf("proxy_pass http://%s;", 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.To) > 0 { - rc := "" - if location.Redirect.Rewrite { - rc = fmt.Sprintf(`sub_filter '
' '