Add configuration and annotation for port_in_redirect
This commit is contained in:
parent
db17db812d
commit
3df139cb56
14 changed files with 249 additions and 72 deletions
|
@ -29,6 +29,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
|
||||||
"k8s.io/ingress/controllers/nginx/pkg/config"
|
"k8s.io/ingress/controllers/nginx/pkg/config"
|
||||||
|
@ -58,7 +60,10 @@ func newNGINXController() ingress.Controller {
|
||||||
if ngx == "" {
|
if ngx == "" {
|
||||||
ngx = binary
|
ngx = binary
|
||||||
}
|
}
|
||||||
n := NGINXController{binary: ngx}
|
n := NGINXController{
|
||||||
|
binary: ngx,
|
||||||
|
configmap: &api.ConfigMap{},
|
||||||
|
}
|
||||||
|
|
||||||
var onChange func()
|
var onChange func()
|
||||||
onChange = func() {
|
onChange = func() {
|
||||||
|
@ -87,13 +92,15 @@ Error loading new template : %v
|
||||||
|
|
||||||
go n.Start()
|
go n.Start()
|
||||||
|
|
||||||
return n
|
return ingress.Controller(&n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NGINXController ...
|
// NGINXController ...
|
||||||
type NGINXController struct {
|
type NGINXController struct {
|
||||||
t *ngx_template.Template
|
t *ngx_template.Template
|
||||||
|
|
||||||
|
configmap *api.ConfigMap
|
||||||
|
|
||||||
binary string
|
binary string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,11 +177,31 @@ func (n NGINXController) Reload(data []byte) ([]byte, bool, error) {
|
||||||
|
|
||||||
// BackendDefaults returns the nginx defaults
|
// BackendDefaults returns the nginx defaults
|
||||||
func (n NGINXController) BackendDefaults() defaults.Backend {
|
func (n NGINXController) BackendDefaults() defaults.Backend {
|
||||||
|
if n.configmap == nil {
|
||||||
|
d := config.NewDefault()
|
||||||
|
return d.Backend
|
||||||
|
}
|
||||||
|
|
||||||
|
return n.backendDefaults()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NGINXController) backendDefaults() defaults.Backend {
|
||||||
d := config.NewDefault()
|
d := config.NewDefault()
|
||||||
|
config := &mapstructure.DecoderConfig{
|
||||||
|
Metadata: nil,
|
||||||
|
WeaklyTypedInput: true,
|
||||||
|
Result: &d,
|
||||||
|
TagName: "json",
|
||||||
|
}
|
||||||
|
decoder, err := mapstructure.NewDecoder(config)
|
||||||
|
if err != nil {
|
||||||
|
glog.Warningf("unexpected error merging defaults: %v", err)
|
||||||
|
}
|
||||||
|
decoder.Decode(n.configmap.Data)
|
||||||
return d.Backend
|
return d.Backend
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsReloadRequired check if the new configuration file is different
|
// isReloadRequired check if the new configuration file is different
|
||||||
// from the current one.
|
// from the current one.
|
||||||
func (n NGINXController) isReloadRequired(data []byte) bool {
|
func (n NGINXController) isReloadRequired(data []byte) bool {
|
||||||
in, err := os.Open(cfgPath)
|
in, err := os.Open(cfgPath)
|
||||||
|
@ -249,6 +276,11 @@ Error: %v
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetConfig ...
|
||||||
|
func (n *NGINXController) SetConfig(cmap *api.ConfigMap) {
|
||||||
|
n.configmap = cmap
|
||||||
|
}
|
||||||
|
|
||||||
// OnUpdate is called by syncQueue in https://github.com/aledbf/ingress-controller/blob/master/pkg/ingress/controller/controller.go#L82
|
// OnUpdate is called by syncQueue in https://github.com/aledbf/ingress-controller/blob/master/pkg/ingress/controller/controller.go#L82
|
||||||
// periodically to keep the configuration in sync.
|
// periodically to keep the configuration in sync.
|
||||||
//
|
//
|
||||||
|
@ -257,7 +289,7 @@ Error: %v
|
||||||
// write the configuration file
|
// write the configuration file
|
||||||
// returning nill implies the backend will be reloaded.
|
// returning nill implies the backend will be reloaded.
|
||||||
// if an error is returned means requeue the update
|
// if an error is returned means requeue the update
|
||||||
func (n NGINXController) OnUpdate(cmap *api.ConfigMap, ingressCfg ingress.Configuration) ([]byte, error) {
|
func (n *NGINXController) OnUpdate(ingressCfg ingress.Configuration) ([]byte, error) {
|
||||||
var longestName int
|
var longestName int
|
||||||
var serverNames int
|
var serverNames int
|
||||||
for _, srv := range ingressCfg.Servers {
|
for _, srv := range ingressCfg.Servers {
|
||||||
|
@ -267,7 +299,7 @@ func (n NGINXController) OnUpdate(cmap *api.ConfigMap, ingressCfg ingress.Config
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := ngx_template.ReadConfig(cmap)
|
cfg := ngx_template.ReadConfig(n.configmap.Data)
|
||||||
|
|
||||||
// NGINX cannot resize the has tables used to store server names.
|
// NGINX cannot resize the has tables used to store server names.
|
||||||
// For this reason we check if the defined size defined is correct
|
// For this reason we check if the defined size defined is correct
|
||||||
|
|
|
@ -270,6 +270,7 @@ func NewDefault() Configuration {
|
||||||
CustomHTTPErrors: []int{},
|
CustomHTTPErrors: []int{},
|
||||||
WhitelistSourceRange: []string{},
|
WhitelistSourceRange: []string{},
|
||||||
SkipAccessLogURLs: []string{},
|
SkipAccessLogURLs: []string{},
|
||||||
|
UsePortInRedirects: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,6 @@ import (
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
|
||||||
|
|
||||||
"k8s.io/ingress/controllers/nginx/pkg/config"
|
"k8s.io/ingress/controllers/nginx/pkg/config"
|
||||||
"k8s.io/ingress/core/pkg/net/dns"
|
"k8s.io/ingress/core/pkg/net/dns"
|
||||||
)
|
)
|
||||||
|
@ -36,13 +34,21 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReadConfig obtains the configuration defined by the user merged with the defaults.
|
// ReadConfig obtains the configuration defined by the user merged with the defaults.
|
||||||
func ReadConfig(conf *api.ConfigMap) config.Configuration {
|
func ReadConfig(src map[string]string) config.Configuration {
|
||||||
|
conf := map[string]string{}
|
||||||
|
if src != nil {
|
||||||
|
// we need to copy the configmap data because the content is altered
|
||||||
|
for k, v := range src {
|
||||||
|
conf[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
errors := make([]int, 0)
|
errors := make([]int, 0)
|
||||||
skipUrls := make([]string, 0)
|
skipUrls := make([]string, 0)
|
||||||
whitelist := make([]string, 0)
|
whitelist := make([]string, 0)
|
||||||
|
|
||||||
if val, ok := conf.Data[customHTTPErrors]; ok {
|
if val, ok := conf[customHTTPErrors]; ok {
|
||||||
delete(conf.Data, customHTTPErrors)
|
delete(conf, customHTTPErrors)
|
||||||
for _, i := range strings.Split(val, ",") {
|
for _, i := range strings.Split(val, ",") {
|
||||||
j, err := strconv.Atoi(i)
|
j, err := strconv.Atoi(i)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -52,12 +58,12 @@ func ReadConfig(conf *api.ConfigMap) config.Configuration {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if val, ok := conf.Data[skipAccessLogUrls]; ok {
|
if val, ok := conf[skipAccessLogUrls]; ok {
|
||||||
delete(conf.Data, skipAccessLogUrls)
|
delete(conf, skipAccessLogUrls)
|
||||||
skipUrls = strings.Split(val, ",")
|
skipUrls = strings.Split(val, ",")
|
||||||
}
|
}
|
||||||
if val, ok := conf.Data[whitelistSourceRange]; ok {
|
if val, ok := conf[whitelistSourceRange]; ok {
|
||||||
delete(conf.Data, whitelistSourceRange)
|
delete(conf, whitelistSourceRange)
|
||||||
whitelist = append(whitelist, strings.Split(val, ",")...)
|
whitelist = append(whitelist, strings.Split(val, ",")...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +90,7 @@ func ReadConfig(conf *api.ConfigMap) config.Configuration {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Warningf("unexpected error merging defaults: %v", err)
|
glog.Warningf("unexpected error merging defaults: %v", err)
|
||||||
}
|
}
|
||||||
err = decoder.Decode(conf.Data)
|
err = decoder.Decode(conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Warningf("unexpected error merging defaults: %v", err)
|
glog.Warningf("unexpected error merging defaults: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ import (
|
||||||
|
|
||||||
"k8s.io/ingress/controllers/nginx/pkg/config"
|
"k8s.io/ingress/controllers/nginx/pkg/config"
|
||||||
"k8s.io/ingress/core/pkg/net/dns"
|
"k8s.io/ingress/core/pkg/net/dns"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFilterErrors(t *testing.T) {
|
func TestFilterErrors(t *testing.T) {
|
||||||
|
@ -34,17 +33,15 @@ func TestFilterErrors(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMergeConfigMapToStruct(t *testing.T) {
|
func TestMergeConfigMapToStruct(t *testing.T) {
|
||||||
conf := &api.ConfigMap{
|
conf := map[string]string{
|
||||||
Data: map[string]string{
|
"custom-http-errors": "300,400,demo",
|
||||||
"custom-http-errors": "300,400,demo",
|
"proxy-read-timeout": "1",
|
||||||
"proxy-read-timeout": "1",
|
"proxy-send-timeout": "2",
|
||||||
"proxy-send-timeout": "2",
|
"skip-access-log-urls": "/log,/demo,/test",
|
||||||
"skip-access-log-urls": "/log,/demo,/test",
|
"use-proxy-protocol": "true",
|
||||||
"use-proxy-protocol": "true",
|
"use-gzip": "true",
|
||||||
"use-gzip": "true",
|
"enable-dynamic-tls-records": "false",
|
||||||
"enable-dynamic-tls-records": "false",
|
"gzip-types": "text/html",
|
||||||
"gzip-types": "text/html",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
def := config.NewDefault()
|
def := config.NewDefault()
|
||||||
def.CustomHTTPErrors = []int{300, 400}
|
def.CustomHTTPErrors = []int{300, 400}
|
||||||
|
@ -68,7 +65,7 @@ func TestMergeConfigMapToStruct(t *testing.T) {
|
||||||
|
|
||||||
def = config.NewDefault()
|
def = config.NewDefault()
|
||||||
def.Resolver = h
|
def.Resolver = h
|
||||||
to = ReadConfig(&api.ConfigMap{})
|
to = ReadConfig(map[string]string{})
|
||||||
if diff := pretty.Compare(to, def); diff != "" {
|
if diff := pretty.Compare(to, def); diff != "" {
|
||||||
t.Errorf("unexpected diff: (-got +want)\n%s", diff)
|
t.Errorf("unexpected diff: (-got +want)\n%s", diff)
|
||||||
}
|
}
|
||||||
|
@ -76,10 +73,8 @@ func TestMergeConfigMapToStruct(t *testing.T) {
|
||||||
def = config.NewDefault()
|
def = config.NewDefault()
|
||||||
def.Resolver = h
|
def.Resolver = h
|
||||||
def.WhitelistSourceRange = []string{"1.1.1.1/32"}
|
def.WhitelistSourceRange = []string{"1.1.1.1/32"}
|
||||||
to = ReadConfig(&api.ConfigMap{
|
to = ReadConfig(map[string]string{
|
||||||
Data: map[string]string{
|
"whitelist-source-range": "1.1.1.1/32",
|
||||||
"whitelist-source-range": "1.1.1.1/32",
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if diff := pretty.Compare(to, def); diff != "" {
|
if diff := pretty.Compare(to, def); diff != "" {
|
||||||
|
|
|
@ -251,6 +251,8 @@ http {
|
||||||
deny all;
|
deny all;
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
|
port_in_redirect {{ if $location.UsePortInRedirects }}on{{ else }}off{{ end }};
|
||||||
|
|
||||||
{{ if not (empty $authPath) }}
|
{{ if not (empty $authPath) }}
|
||||||
# this location requires authentication
|
# this location requires authentication
|
||||||
auth_request {{ $authPath }};
|
auth_request {{ $authPath }};
|
||||||
|
|
|
@ -36,7 +36,7 @@ func (a ingAnnotations) parseBool(name string) (bool, error) {
|
||||||
if ok {
|
if ok {
|
||||||
b, err := strconv.ParseBool(val)
|
b, err := strconv.ParseBool(val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, errors.NewInvalidAnnotationContent(name)
|
return false, errors.NewInvalidAnnotationContent(name, val)
|
||||||
}
|
}
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ func (a ingAnnotations) parseInt(name string) (int, error) {
|
||||||
if ok {
|
if ok {
|
||||||
i, err := strconv.Atoi(val)
|
i, err := strconv.Atoi(val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, errors.NewInvalidAnnotationContent(name)
|
return 0, errors.NewInvalidAnnotationContent(name, val)
|
||||||
}
|
}
|
||||||
return i, nil
|
return i, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,28 +14,35 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package cors
|
package portinredirect
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
|
|
||||||
"k8s.io/ingress/core/pkg/ingress/annotations/parser"
|
"k8s.io/ingress/core/pkg/ingress/annotations/parser"
|
||||||
|
"k8s.io/ingress/core/pkg/ingress/resolver"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
annotation = "ingress.kubernetes.io/port-in-redirect"
|
annotation = "ingress.kubernetes.io/use-port-in-redirects"
|
||||||
)
|
)
|
||||||
|
|
||||||
type portInRedirect struct {
|
type portInRedirect struct {
|
||||||
|
backendResolver resolver.DefaultBackend
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewParser creates a new port in redirect annotation parser
|
// NewParser creates a new port in redirect annotation parser
|
||||||
func NewParser() parser.IngressAnnotation {
|
func NewParser(db resolver.DefaultBackend) parser.IngressAnnotation {
|
||||||
return portInRedirect{}
|
return portInRedirect{db}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse parses the annotations contained in the ingress
|
// Parse parses the annotations contained in the ingress
|
||||||
// rule used to indicate if the redirects must
|
// rule used to indicate if the redirects must
|
||||||
func (a portInRedirect) Parse(ing *extensions.Ingress) (interface{}, error) {
|
func (a portInRedirect) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||||
return parser.GetBoolAnnotation(annotation, ing)
|
up, err := parser.GetBoolAnnotation(annotation, ing)
|
||||||
|
if err != nil {
|
||||||
|
return a.backendResolver.GetDefaultBackend().UsePortInRedirects, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return up, nil
|
||||||
}
|
}
|
||||||
|
|
120
core/pkg/ingress/annotations/portinredirect/main_test.go
Normal file
120
core/pkg/ingress/annotations/portinredirect/main_test.go
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 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 portinredirect
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
|
"k8s.io/kubernetes/pkg/util/intstr"
|
||||||
|
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"k8s.io/ingress/core/pkg/ingress/defaults"
|
||||||
|
)
|
||||||
|
|
||||||
|
func buildIngress() *extensions.Ingress {
|
||||||
|
defaultBackend := extensions.IngressBackend{
|
||||||
|
ServiceName: "default-backend",
|
||||||
|
ServicePort: intstr.FromInt(80),
|
||||||
|
}
|
||||||
|
|
||||||
|
return &extensions.Ingress{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Namespace: api.NamespaceDefault,
|
||||||
|
},
|
||||||
|
Spec: extensions.IngressSpec{
|
||||||
|
Backend: &extensions.IngressBackend{
|
||||||
|
ServiceName: "default-backend",
|
||||||
|
ServicePort: intstr.FromInt(80),
|
||||||
|
},
|
||||||
|
Rules: []extensions.IngressRule{
|
||||||
|
{
|
||||||
|
Host: "foo.bar.com",
|
||||||
|
IngressRuleValue: extensions.IngressRuleValue{
|
||||||
|
HTTP: &extensions.HTTPIngressRuleValue{
|
||||||
|
Paths: []extensions.HTTPIngressPath{
|
||||||
|
{
|
||||||
|
Path: "/foo",
|
||||||
|
Backend: defaultBackend,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type mockBackend struct {
|
||||||
|
usePortInRedirects bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) GetDefaultBackend() defaults.Backend {
|
||||||
|
return defaults.Backend{UsePortInRedirects: m.usePortInRedirects}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPortInRedirect(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
title string
|
||||||
|
usePort *bool
|
||||||
|
def bool
|
||||||
|
exp bool
|
||||||
|
}{
|
||||||
|
{"false - default false", newFalse(), false, false},
|
||||||
|
{"false - default true", newFalse(), true, false},
|
||||||
|
{"no annotation - default false", nil, false, false},
|
||||||
|
{"no annotation - default true", nil, true, true},
|
||||||
|
{"true - default true", newTrue(), true, true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
ing := buildIngress()
|
||||||
|
|
||||||
|
data := map[string]string{}
|
||||||
|
if test.usePort != nil {
|
||||||
|
data[annotation] = fmt.Sprintf("%v", *test.usePort)
|
||||||
|
}
|
||||||
|
ing.SetAnnotations(data)
|
||||||
|
|
||||||
|
i, err := NewParser(mockBackend{test.def}).Parse(ing)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error parsing a valid")
|
||||||
|
}
|
||||||
|
p, ok := i.(bool)
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("expected a bool type")
|
||||||
|
}
|
||||||
|
|
||||||
|
if p != test.exp {
|
||||||
|
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.exp, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTrue() *bool {
|
||||||
|
b := true
|
||||||
|
return &b
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFalse() *bool {
|
||||||
|
b := false
|
||||||
|
return &b
|
||||||
|
}
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"k8s.io/ingress/core/pkg/ingress/annotations/healthcheck"
|
"k8s.io/ingress/core/pkg/ingress/annotations/healthcheck"
|
||||||
"k8s.io/ingress/core/pkg/ingress/annotations/ipwhitelist"
|
"k8s.io/ingress/core/pkg/ingress/annotations/ipwhitelist"
|
||||||
"k8s.io/ingress/core/pkg/ingress/annotations/parser"
|
"k8s.io/ingress/core/pkg/ingress/annotations/parser"
|
||||||
|
"k8s.io/ingress/core/pkg/ingress/annotations/portinredirect"
|
||||||
"k8s.io/ingress/core/pkg/ingress/annotations/proxy"
|
"k8s.io/ingress/core/pkg/ingress/annotations/proxy"
|
||||||
"k8s.io/ingress/core/pkg/ingress/annotations/ratelimit"
|
"k8s.io/ingress/core/pkg/ingress/annotations/ratelimit"
|
||||||
"k8s.io/ingress/core/pkg/ingress/annotations/rewrite"
|
"k8s.io/ingress/core/pkg/ingress/annotations/rewrite"
|
||||||
|
@ -50,17 +51,18 @@ type annotationExtractor struct {
|
||||||
func newAnnotationExtractor(cfg extractorConfig) annotationExtractor {
|
func newAnnotationExtractor(cfg extractorConfig) annotationExtractor {
|
||||||
return annotationExtractor{
|
return annotationExtractor{
|
||||||
map[string]parser.IngressAnnotation{
|
map[string]parser.IngressAnnotation{
|
||||||
"BasicDigestAuth": auth.NewParser(auth.AuthDirectory, cfg),
|
"BasicDigestAuth": auth.NewParser(auth.AuthDirectory, cfg),
|
||||||
"ExternalAuth": authreq.NewParser(),
|
"ExternalAuth": authreq.NewParser(),
|
||||||
"CertificateAuth": authtls.NewParser(cfg),
|
"CertificateAuth": authtls.NewParser(cfg),
|
||||||
"EnableCORS": cors.NewParser(),
|
"EnableCORS": cors.NewParser(),
|
||||||
"HealthCheck": healthcheck.NewParser(cfg),
|
"HealthCheck": healthcheck.NewParser(cfg),
|
||||||
"Whitelist": ipwhitelist.NewParser(cfg),
|
"Whitelist": ipwhitelist.NewParser(cfg),
|
||||||
"Proxy": proxy.NewParser(cfg),
|
"UsePortInRedirects": portinredirect.NewParser(cfg),
|
||||||
"RateLimit": ratelimit.NewParser(),
|
"Proxy": proxy.NewParser(cfg),
|
||||||
"Redirect": rewrite.NewParser(cfg),
|
"RateLimit": ratelimit.NewParser(),
|
||||||
"SecureUpstream": secureupstream.NewParser(),
|
"Redirect": rewrite.NewParser(cfg),
|
||||||
"SSLPassthrough": sslpassthrough.NewParser(),
|
"SecureUpstream": secureupstream.NewParser(),
|
||||||
|
"SSLPassthrough": sslpassthrough.NewParser(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,10 +223,22 @@ func newIngressController(config *Configuration) *GenericController {
|
||||||
}
|
}
|
||||||
|
|
||||||
mapEventHandler := cache.ResourceEventHandlerFuncs{
|
mapEventHandler := cache.ResourceEventHandlerFuncs{
|
||||||
|
AddFunc: func(obj interface{}) {
|
||||||
|
upCmap := obj.(*api.ConfigMap)
|
||||||
|
mapKey := fmt.Sprintf("%s/%s", upCmap.Namespace, upCmap.Name)
|
||||||
|
if mapKey == ic.cfg.ConfigMapName {
|
||||||
|
glog.V(2).Infof("adding configmap %v to backend", mapKey)
|
||||||
|
ic.cfg.Backend.SetConfig(upCmap)
|
||||||
|
}
|
||||||
|
},
|
||||||
UpdateFunc: func(old, cur interface{}) {
|
UpdateFunc: func(old, cur interface{}) {
|
||||||
if !reflect.DeepEqual(old, cur) {
|
if !reflect.DeepEqual(old, cur) {
|
||||||
upCmap := cur.(*api.ConfigMap)
|
upCmap := cur.(*api.ConfigMap)
|
||||||
mapKey := fmt.Sprintf("%s/%s", upCmap.Namespace, upCmap.Name)
|
mapKey := fmt.Sprintf("%s/%s", upCmap.Namespace, upCmap.Name)
|
||||||
|
if mapKey == ic.cfg.ConfigMapName {
|
||||||
|
glog.V(2).Infof("updating configmap backend (%v)", mapKey)
|
||||||
|
ic.cfg.Backend.SetConfig(upCmap)
|
||||||
|
}
|
||||||
// updates to configuration configmaps can trigger an update
|
// updates to configuration configmaps can trigger an update
|
||||||
if mapKey == ic.cfg.ConfigMapName || mapKey == ic.cfg.TCPConfigMapName || mapKey == ic.cfg.UDPConfigMapName {
|
if mapKey == ic.cfg.ConfigMapName || mapKey == ic.cfg.TCPConfigMapName || mapKey == ic.cfg.UDPConfigMapName {
|
||||||
ic.recorder.Eventf(upCmap, api.EventTypeNormal, "UPDATE", fmt.Sprintf("ConfigMap %v", mapKey))
|
ic.recorder.Eventf(upCmap, api.EventTypeNormal, "UPDATE", fmt.Sprintf("ConfigMap %v", mapKey))
|
||||||
|
@ -310,8 +322,14 @@ func (ic GenericController) GetSecret(name string) (*api.Secret, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ic *GenericController) getConfigMap(ns, name string) (*api.ConfigMap, error) {
|
func (ic *GenericController) getConfigMap(ns, name string) (*api.ConfigMap, error) {
|
||||||
// TODO: check why ic.mapLister.Store.GetByKey(mapKey) is not stable (random content)
|
s, exists, err := ic.mapLister.Store.GetByKey(fmt.Sprintf("%v/%v", ns, name))
|
||||||
return ic.cfg.Client.ConfigMaps(ns).Get(name)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
|
return nil, fmt.Errorf("configmap %v was not found", name)
|
||||||
|
}
|
||||||
|
return s.(*api.ConfigMap), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// sync collects all the pieces required to assemble the configuration file and
|
// sync collects all the pieces required to assemble the configuration file and
|
||||||
|
@ -329,20 +347,6 @@ func (ic *GenericController) sync(key interface{}) error {
|
||||||
return fmt.Errorf("deferring sync till endpoints controller has synced")
|
return fmt.Errorf("deferring sync till endpoints controller has synced")
|
||||||
}
|
}
|
||||||
|
|
||||||
// by default no custom configuration
|
|
||||||
cfg := &api.ConfigMap{}
|
|
||||||
|
|
||||||
if ic.cfg.ConfigMapName != "" {
|
|
||||||
// search for custom configmap (defined in main args)
|
|
||||||
var err error
|
|
||||||
ns, name, _ := k8s.ParseNameNS(ic.cfg.ConfigMapName)
|
|
||||||
cfg, err = ic.getConfigMap(ns, name)
|
|
||||||
if err != nil {
|
|
||||||
// requeue
|
|
||||||
return fmt.Errorf("unexpected error searching configmap %v: %v", ic.cfg.ConfigMapName, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
upstreams, servers := ic.getBackendServers()
|
upstreams, servers := ic.getBackendServers()
|
||||||
var passUpstreams []*ingress.SSLPassthroughBackend
|
var passUpstreams []*ingress.SSLPassthroughBackend
|
||||||
for _, server := range servers {
|
for _, server := range servers {
|
||||||
|
@ -362,7 +366,7 @@ func (ic *GenericController) sync(key interface{}) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := ic.cfg.Backend.OnUpdate(cfg, ingress.Configuration{
|
data, err := ic.cfg.Backend.OnUpdate(ingress.Configuration{
|
||||||
Backends: upstreams,
|
Backends: upstreams,
|
||||||
Servers: servers,
|
Servers: servers,
|
||||||
TCPEndpoints: ic.getTCPServices(),
|
TCPEndpoints: ic.getTCPServices(),
|
||||||
|
|
|
@ -49,6 +49,10 @@ type Backend struct {
|
||||||
// Enables or disables the redirect (301) to the HTTPS port
|
// Enables or disables the redirect (301) to the HTTPS port
|
||||||
SSLRedirect bool `json:"ssl-redirect"`
|
SSLRedirect bool `json:"ssl-redirect"`
|
||||||
|
|
||||||
|
// Enables or disables the specification of port in redirects
|
||||||
|
// Default: false
|
||||||
|
UsePortInRedirects bool `json:"use-port-in-redirects"`
|
||||||
|
|
||||||
// Number of unsuccessful attempts to communicate with the server that should happen in the
|
// Number of unsuccessful attempts to communicate with the server that should happen in the
|
||||||
// duration set by the fail_timeout parameter to consider the server unavailable
|
// duration set by the fail_timeout parameter to consider the server unavailable
|
||||||
// http://nginx.org/en/docs/http/ngx_http_upstream_module.html#upstream
|
// http://nginx.org/en/docs/http/ngx_http_upstream_module.html#upstream
|
||||||
|
|
|
@ -37,9 +37,9 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewInvalidAnnotationContent returns a new InvalidContent error
|
// NewInvalidAnnotationContent returns a new InvalidContent error
|
||||||
func NewInvalidAnnotationContent(name string) error {
|
func NewInvalidAnnotationContent(name string, val interface{}) error {
|
||||||
return InvalidContent{
|
return InvalidContent{
|
||||||
Name: fmt.Sprintf("the annotation %v does not contains a valid value", name),
|
Name: fmt.Sprintf("the annotation %v does not contains a valid value (%v)", name, val),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ func TestInvalidContent(t *testing.T) {
|
||||||
if IsInvalidContent(ErrMissingAnnotations) {
|
if IsInvalidContent(ErrMissingAnnotations) {
|
||||||
t.Error("expected false")
|
t.Error("expected false")
|
||||||
}
|
}
|
||||||
err := NewInvalidAnnotationContent("demo")
|
err := NewInvalidAnnotationContent("demo", "")
|
||||||
if !IsInvalidContent(err) {
|
if !IsInvalidContent(err) {
|
||||||
t.Error("expected true")
|
t.Error("expected true")
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,6 @@ type Controller interface {
|
||||||
// Notifications of type Add, Update and Delete:
|
// Notifications of type Add, Update and Delete:
|
||||||
// https://github.com/kubernetes/kubernetes/blob/master/pkg/client/cache/controller.go#L164
|
// https://github.com/kubernetes/kubernetes/blob/master/pkg/client/cache/controller.go#L164
|
||||||
//
|
//
|
||||||
// ConfigMap content of --configmap
|
|
||||||
// Configuration returns the translation from Ingress rules containing
|
// Configuration returns the translation from Ingress rules containing
|
||||||
// information about all the upstreams (service endpoints ) "virtual"
|
// information about all the upstreams (service endpoints ) "virtual"
|
||||||
// servers (FQDN) and all the locations inside each server. Each
|
// servers (FQDN) and all the locations inside each server. Each
|
||||||
|
@ -79,7 +78,9 @@ type Controller interface {
|
||||||
//
|
//
|
||||||
// The returned configuration is then passed to test, and then to reload
|
// The returned configuration is then passed to test, and then to reload
|
||||||
// if there is no errors.
|
// if there is no errors.
|
||||||
OnUpdate(*api.ConfigMap, Configuration) ([]byte, error)
|
OnUpdate(Configuration) ([]byte, error)
|
||||||
|
// ConfigMap content of --configmap
|
||||||
|
SetConfig(*api.ConfigMap)
|
||||||
// BackendDefaults returns the minimum settings required to configure the
|
// BackendDefaults returns the minimum settings required to configure the
|
||||||
// communication to endpoints
|
// communication to endpoints
|
||||||
BackendDefaults() defaults.Backend
|
BackendDefaults() defaults.Backend
|
||||||
|
@ -233,6 +234,9 @@ type Location struct {
|
||||||
// external authentication
|
// external authentication
|
||||||
// +optional
|
// +optional
|
||||||
CertificateAuth resolver.AuthSSLCert `json:"certificateAuth,omitempty"`
|
CertificateAuth resolver.AuthSSLCert `json:"certificateAuth,omitempty"`
|
||||||
|
// UsePortInRedirects indicates if redirects must specify the port
|
||||||
|
// +optional
|
||||||
|
UsePortInRedirects bool `json:"use-port-in-redirects"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SSLPassthroughBackend describes a SSL upstream server configured
|
// SSLPassthroughBackend describes a SSL upstream server configured
|
||||||
|
|
Loading…
Reference in a new issue