diff --git a/cmd/nginx/flags.go b/cmd/nginx/flags.go index 608ef5c9a..2029f4d78 100644 --- a/cmd/nginx/flags.go +++ b/cmd/nginx/flags.go @@ -122,6 +122,8 @@ func parseFlags() (bool, *controller.Configuration, error) { sslProxyPort = flags.Int("ssl-passtrough-proxy-port", 442, `Default port to use internally for SSL when SSL Passthgough is enabled`) defServerPort = flags.Int("default-server-port", 8181, `Default port to use for exposing the default server (catch all)`) healthzPort = flags.Int("healthz-port", 10254, "port for healthz endpoint.") + + annotationsPrefix = flags.String("annotations-prefix", "nginx.ingress.kubernetes.io", `Prefix of the ingress annotations.`) ) flag.Set("logtostderr", "true") @@ -177,6 +179,7 @@ func parseFlags() (bool, *controller.Configuration, error) { } config := &controller.Configuration{ + AnnotationsPrefix: *annotationsPrefix, APIServerHost: *apiserverHost, KubeConfigFile: *kubeConfigFile, UpdateStatus: *updateStatus, diff --git a/internal/ingress/annotations/alias/main.go b/internal/ingress/annotations/alias/main.go index 0194e72af..2fb81b2a4 100644 --- a/internal/ingress/annotations/alias/main.go +++ b/internal/ingress/annotations/alias/main.go @@ -20,22 +20,20 @@ import ( extensions "k8s.io/api/extensions/v1beta1" "k8s.io/ingress-nginx/internal/ingress/annotations/parser" -) - -const ( - annotation = "ingress.kubernetes.io/server-alias" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) type alias struct { + r resolver.Resolver } // NewParser creates a new Alias annotation parser -func NewParser() parser.IngressAnnotation { - return alias{} +func NewParser(r resolver.Resolver) parser.IngressAnnotation { + return alias{r} } // Parse parses the annotations contained in the ingress rule // used to add an alias to the provided hosts func (a alias) Parse(ing *extensions.Ingress) (interface{}, error) { - return parser.GetStringAnnotation(annotation, ing) + return parser.GetStringAnnotation("server-alias", ing, a.r) } diff --git a/internal/ingress/annotations/alias/main_test.go b/internal/ingress/annotations/alias/main_test.go index de4fe17f5..579ed83f4 100644 --- a/internal/ingress/annotations/alias/main_test.go +++ b/internal/ingress/annotations/alias/main_test.go @@ -22,10 +22,13 @@ import ( api "k8s.io/api/core/v1" extensions "k8s.io/api/extensions/v1beta1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) +const annotation = "nginx/server-alias" + func TestParse(t *testing.T) { - ap := NewParser() + ap := NewParser(&resolver.Mock{}) if ap == nil { t.Fatalf("expected a parser.IngressAnnotation but returned nil") } diff --git a/internal/ingress/annotations/annotations.go b/internal/ingress/annotations/annotations.go index ff888cf84..a12c2cc44 100644 --- a/internal/ingress/annotations/annotations.go +++ b/internal/ingress/annotations/annotations.go @@ -54,13 +54,6 @@ import ( // DeniedKeyName name of the key that contains the reason to deny a location const DeniedKeyName = "Denied" -type config interface { - resolver.AuthCertificate - resolver.DefaultBackend - resolver.Secret - resolver.Service -} - // Ingress defines the valid annotations present in one NGINX Ingress rule type Ingress struct { metav1.ObjectMeta @@ -91,37 +84,35 @@ type Ingress struct { // Extractor defines the annotation parsers to be used in the extraction of annotations type Extractor struct { - secretResolver resolver.Secret - annotations map[string]parser.IngressAnnotation + annotations map[string]parser.IngressAnnotation } // NewAnnotationExtractor creates a new annotations extractor -func NewAnnotationExtractor(cfg config) Extractor { +func NewAnnotationExtractor(cfg resolver.Resolver) Extractor { return Extractor{ - cfg, map[string]parser.IngressAnnotation{ - "Alias": alias.NewParser(), + "Alias": alias.NewParser(cfg), "BasicDigestAuth": auth.NewParser(auth.AuthDirectory, cfg), "CertificateAuth": authtls.NewParser(cfg), - "ClientBodyBufferSize": clientbodybuffersize.NewParser(), - "ConfigurationSnippet": snippet.NewParser(), - "CorsConfig": cors.NewParser(), + "ClientBodyBufferSize": clientbodybuffersize.NewParser(cfg), + "ConfigurationSnippet": snippet.NewParser(cfg), + "CorsConfig": cors.NewParser(cfg), "DefaultBackend": defaultbackend.NewParser(cfg), - "ExternalAuth": authreq.NewParser(), + "ExternalAuth": authreq.NewParser(cfg), "HealthCheck": healthcheck.NewParser(cfg), "Proxy": proxy.NewParser(cfg), "RateLimit": ratelimit.NewParser(cfg), - "Redirect": redirect.NewParser(), + "Redirect": redirect.NewParser(cfg), "Rewrite": rewrite.NewParser(cfg), "SecureUpstream": secureupstream.NewParser(cfg), - "ServerSnippet": serversnippet.NewParser(), - "ServiceUpstream": serviceupstream.NewParser(), - "SessionAffinity": sessionaffinity.NewParser(), - "SSLPassthrough": sslpassthrough.NewParser(), + "ServerSnippet": serversnippet.NewParser(cfg), + "ServiceUpstream": serviceupstream.NewParser(cfg), + "SessionAffinity": sessionaffinity.NewParser(cfg), + "SSLPassthrough": sslpassthrough.NewParser(cfg), "UsePortInRedirects": portinredirect.NewParser(cfg), - "UpstreamHashBy": upstreamhashby.NewParser(), - "UpstreamVhost": upstreamvhost.NewParser(), - "VtsFilterKey": vtsfilterkey.NewParser(), + "UpstreamHashBy": upstreamhashby.NewParser(cfg), + "UpstreamVhost": upstreamvhost.NewParser(cfg), + "VtsFilterKey": vtsfilterkey.NewParser(cfg), "Whitelist": ipwhitelist.NewParser(cfg), }, } diff --git a/internal/ingress/annotations/annotations_test.go b/internal/ingress/annotations/annotations_test.go index 114be2318..fd086d43d 100644 --- a/internal/ingress/annotations/annotations_test.go +++ b/internal/ingress/annotations/annotations_test.go @@ -29,25 +29,26 @@ import ( ) const ( - annotationSecureUpstream = "ingress.kubernetes.io/secure-backends" - annotationSecureVerifyCACert = "ingress.kubernetes.io/secure-verify-ca-secret" - annotationUpsMaxFails = "ingress.kubernetes.io/upstream-max-fails" - annotationUpsFailTimeout = "ingress.kubernetes.io/upstream-fail-timeout" - annotationPassthrough = "ingress.kubernetes.io/ssl-passthrough" - annotationAffinityType = "ingress.kubernetes.io/affinity" - annotationCorsEnabled = "ingress.kubernetes.io/enable-cors" - annotationCorsAllowOrigin = "ingress.kubernetes.io/cors-allow-origin" - annotationCorsAllowMethods = "ingress.kubernetes.io/cors-allow-methods" - annotationCorsAllowHeaders = "ingress.kubernetes.io/cors-allow-headers" - annotationCorsAllowCredentials = "ingress.kubernetes.io/cors-allow-credentials" + annotationSecureUpstream = "nginx/secure-backends" + annotationSecureVerifyCACert = "nginx/secure-verify-ca-secret" + annotationUpsMaxFails = "nginx/upstream-max-fails" + annotationUpsFailTimeout = "nginx/upstream-fail-timeout" + annotationPassthrough = "nginx/ssl-passthrough" + annotationAffinityType = "nginx/affinity" + annotationCorsEnabled = "nginx/enable-cors" + annotationCorsAllowOrigin = "nginx/cors-allow-origin" + annotationCorsAllowMethods = "nginx/cors-allow-methods" + annotationCorsAllowHeaders = "nginx/cors-allow-headers" + annotationCorsAllowCredentials = "nginx/cors-allow-credentials" defaultCorsMethods = "GET, PUT, POST, DELETE, PATCH, OPTIONS" defaultCorsHeaders = "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization" - annotationAffinityCookieName = "ingress.kubernetes.io/session-cookie-name" - annotationAffinityCookieHash = "ingress.kubernetes.io/session-cookie-hash" - annotationUpstreamHashBy = "ingress.kubernetes.io/upstream-hash-by" + annotationAffinityCookieName = "nginx/session-cookie-name" + annotationAffinityCookieHash = "nginx/session-cookie-hash" + annotationUpstreamHashBy = "nginx/upstream-hash-by" ) type mockCfg struct { + resolver.Mock MockSecrets map[string]*apiv1.Secret MockServices map[string]*apiv1.Service } diff --git a/internal/ingress/annotations/auth/main.go b/internal/ingress/annotations/auth/main.go index 606b225ed..0b2187368 100644 --- a/internal/ingress/annotations/auth/main.go +++ b/internal/ingress/annotations/auth/main.go @@ -33,12 +33,6 @@ import ( "k8s.io/ingress-nginx/internal/ingress/resolver" ) -const ( - authType = "ingress.kubernetes.io/auth-type" - authSecret = "ingress.kubernetes.io/auth-secret" - authRealm = "ingress.kubernetes.io/auth-realm" -) - var ( authTypeRegex = regexp.MustCompile(`basic|digest`) // AuthDirectory default directory used to store files @@ -83,12 +77,12 @@ func (bd1 *Config) Equal(bd2 *Config) bool { } type auth struct { - secretResolver resolver.Secret - authDirectory string + r resolver.Resolver + authDirectory string } // NewParser creates a new authentication annotation parser -func NewParser(authDirectory string, sr resolver.Secret) parser.IngressAnnotation { +func NewParser(authDirectory string, r resolver.Resolver) parser.IngressAnnotation { os.MkdirAll(authDirectory, 0755) currPath := authDirectory @@ -100,7 +94,7 @@ func NewParser(authDirectory string, sr resolver.Secret) parser.IngressAnnotatio } } - return auth{sr, authDirectory} + return auth{r, authDirectory} } // Parse parses the annotations contained in the ingress @@ -108,7 +102,7 @@ func NewParser(authDirectory string, sr resolver.Secret) parser.IngressAnnotatio // and generated an htpasswd compatible file to be used as source // during the authentication process func (a auth) Parse(ing *extensions.Ingress) (interface{}, error) { - at, err := parser.GetStringAnnotation(authType, ing) + at, err := parser.GetStringAnnotation("auth-type", ing, a.r) if err != nil { return nil, err } @@ -117,7 +111,7 @@ func (a auth) Parse(ing *extensions.Ingress) (interface{}, error) { return nil, ing_errors.NewLocationDenied("invalid authentication type") } - s, err := parser.GetStringAnnotation(authSecret, ing) + s, err := parser.GetStringAnnotation("auth-secret", ing, a.r) if err != nil { return nil, ing_errors.LocationDenied{ Reason: errors.Wrap(err, "error reading secret name from annotation"), @@ -125,14 +119,14 @@ func (a auth) Parse(ing *extensions.Ingress) (interface{}, error) { } name := fmt.Sprintf("%v/%v", ing.Namespace, s) - secret, err := a.secretResolver.GetSecret(name) + secret, err := a.r.GetSecret(name) if err != nil { return nil, ing_errors.LocationDenied{ Reason: errors.Wrapf(err, "unexpected error reading secret %v", name), } } - realm, _ := parser.GetStringAnnotation(authRealm, ing) + realm, _ := parser.GetStringAnnotation("auth-realm", ing, a.r) passFile := fmt.Sprintf("%v/%v-%v.passwd", a.authDirectory, ing.GetNamespace(), ing.GetName()) err = dumpSecret(passFile, secret) diff --git a/internal/ingress/annotations/auth/main_test.go b/internal/ingress/annotations/auth/main_test.go index ffb421719..c93dddb67 100644 --- a/internal/ingress/annotations/auth/main_test.go +++ b/internal/ingress/annotations/auth/main_test.go @@ -29,6 +29,7 @@ import ( extensions "k8s.io/api/extensions/v1beta1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) func buildIngress() *extensions.Ingress { @@ -67,6 +68,7 @@ func buildIngress() *extensions.Ingress { } type mockSecret struct { + resolver.Mock } func (m mockSecret) GetSecret(name string) (*api.Secret, error) { @@ -87,7 +89,7 @@ func TestIngressWithoutAuth(t *testing.T) { ing := buildIngress() _, dir, _ := dummySecretContent(t) defer os.RemoveAll(dir) - _, err := NewParser(dir, mockSecret{}).Parse(ing) + _, err := NewParser(dir, &mockSecret{}).Parse(ing) if err == nil { t.Error("Expected error with ingress without annotations") } @@ -97,15 +99,15 @@ func TestIngressAuth(t *testing.T) { ing := buildIngress() data := map[string]string{} - data[authType] = "basic" - data[authSecret] = "demo-secret" - data[authRealm] = "-realm-" + data["nginx/auth-type"] = "basic" + data["nginx/auth-secret"] = "demo-secret" + data["nginx/auth-realm"] = "-realm-" ing.SetAnnotations(data) _, dir, _ := dummySecretContent(t) defer os.RemoveAll(dir) - i, err := NewParser(dir, mockSecret{}).Parse(ing) + i, err := NewParser(dir, &mockSecret{}).Parse(ing) if err != nil { t.Errorf("Uxpected error with ingress: %v", err) } @@ -128,9 +130,9 @@ func TestIngressAuthWithoutSecret(t *testing.T) { ing := buildIngress() data := map[string]string{} - data[authType] = "basic" - data[authSecret] = "invalid-secret" - data[authRealm] = "-realm-" + data["nginx/auth-type"] = "basic" + data["nginx/auth-secret"] = "invalid-secret" + data["nginx/auth-realm"] = "-realm-" ing.SetAnnotations(data) _, dir, _ := dummySecretContent(t) diff --git a/internal/ingress/annotations/authreq/main.go b/internal/ingress/annotations/authreq/main.go index 17a997652..dbc9f51a2 100644 --- a/internal/ingress/annotations/authreq/main.go +++ b/internal/ingress/annotations/authreq/main.go @@ -25,17 +25,10 @@ import ( "k8s.io/ingress-nginx/internal/ingress/annotations/parser" ing_errors "k8s.io/ingress-nginx/internal/ingress/errors" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) -const ( - // external URL that provides the authentication - authURL = "ingress.kubernetes.io/auth-url" - authSigninURL = "ingress.kubernetes.io/auth-signin" - authMethod = "ingress.kubernetes.io/auth-method" - authHeaders = "ingress.kubernetes.io/auth-response-headers" -) - -// External returns external authentication configuration for an Ingress rule +// Config returns external authentication configuration for an Ingress rule type Config struct { URL string `json:"url"` // Host contains the hostname defined in the URL @@ -108,17 +101,18 @@ func validHeader(header string) bool { } type authReq struct { + r resolver.Resolver } // NewParser creates a new authentication request annotation parser -func NewParser() parser.IngressAnnotation { - return authReq{} +func NewParser(r resolver.Resolver) parser.IngressAnnotation { + return authReq{r} } // ParseAnnotations parses the annotations contained in the ingress // rule used to use an Config URL as source for authentication func (a authReq) Parse(ing *extensions.Ingress) (interface{}, error) { - str, err := parser.GetStringAnnotation(authURL, ing) + str, err := parser.GetStringAnnotation("auth-url", ing, a.r) if err != nil { return nil, err } @@ -127,7 +121,7 @@ func (a authReq) Parse(ing *extensions.Ingress) (interface{}, error) { return nil, ing_errors.NewLocationDenied("an empty string is not a valid URL") } - signin, _ := parser.GetStringAnnotation(authSigninURL, ing) + signin, _ := parser.GetStringAnnotation("auth-signin", ing, a.r) ur, err := url.Parse(str) if err != nil { @@ -144,13 +138,13 @@ func (a authReq) Parse(ing *extensions.Ingress) (interface{}, error) { return nil, ing_errors.NewLocationDenied("invalid url host") } - m, _ := parser.GetStringAnnotation(authMethod, ing) + m, _ := parser.GetStringAnnotation("auth-method", ing, a.r) if len(m) != 0 && !validMethod(m) { return nil, ing_errors.NewLocationDenied("invalid HTTP method") } h := []string{} - hstr, _ := parser.GetStringAnnotation(authHeaders, ing) + hstr, _ := parser.GetStringAnnotation("auth-response-headers", ing, a.r) if len(hstr) != 0 { harr := strings.Split(hstr, ",") diff --git a/internal/ingress/annotations/authreq/main_test.go b/internal/ingress/annotations/authreq/main_test.go index 8256302a7..2208cc24e 100644 --- a/internal/ingress/annotations/authreq/main_test.go +++ b/internal/ingress/annotations/authreq/main_test.go @@ -24,6 +24,7 @@ import ( api "k8s.io/api/core/v1" extensions "k8s.io/api/extensions/v1beta1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/ingress-nginx/internal/ingress/resolver" "k8s.io/apimachinery/pkg/util/intstr" ) @@ -86,11 +87,11 @@ func TestAnnotations(t *testing.T) { } for _, test := range tests { - data[authURL] = test.url - data[authSigninURL] = test.signinURL - data[authMethod] = fmt.Sprintf("%v", test.method) + data["nginx/auth-url"] = test.url + data["nginx/auth-signin"] = test.signinURL + data["nginx/auth-method"] = fmt.Sprintf("%v", test.method) - i, err := NewParser().Parse(ing) + i, err := NewParser(&resolver.Mock{}).Parse(ing) if test.expErr { if err == nil { t.Errorf("%v: expected error but retuned nil", test.title) @@ -136,11 +137,11 @@ func TestHeaderAnnotations(t *testing.T) { } for _, test := range tests { - data[authURL] = test.url - data[authHeaders] = test.headers - data[authMethod] = "GET" + data["nginx/auth-url"] = test.url + data["nginx/auth-response-headers"] = test.headers + data["nginx/auth-method"] = "GET" - i, err := NewParser().Parse(ing) + i, err := NewParser(&resolver.Mock{}).Parse(ing) if test.expErr { if err == nil { t.Errorf("%v: expected error but retuned nil", err.Error()) diff --git a/internal/ingress/annotations/authtls/main.go b/internal/ingress/annotations/authtls/main.go index 7fb5eac71..7fa511873 100644 --- a/internal/ingress/annotations/authtls/main.go +++ b/internal/ingress/annotations/authtls/main.go @@ -29,13 +29,8 @@ import ( ) const ( - // name of the secret - annotationAuthTLSSecret = "ingress.kubernetes.io/auth-tls-secret" - annotationAuthVerifyClient = "ingress.kubernetes.io/auth-tls-verify-client" - annotationAuthTLSDepth = "ingress.kubernetes.io/auth-tls-verify-depth" - annotationAuthTLSErrorPage = "ingress.kubernetes.io/auth-tls-error-page" - defaultAuthTLSDepth = 1 - defaultAuthVerifyClient = "on" + defaultAuthTLSDepth = 1 + defaultAuthVerifyClient = "on" ) var ( @@ -75,19 +70,19 @@ func (assl1 *Config) Equal(assl2 *Config) bool { } // NewParser creates a new TLS authentication annotation parser -func NewParser(resolver resolver.AuthCertificate) parser.IngressAnnotation { +func NewParser(resolver resolver.Resolver) parser.IngressAnnotation { return authTLS{resolver} } type authTLS struct { - certResolver resolver.AuthCertificate + r resolver.Resolver } // Parse parses the annotations contained in the ingress // rule used to use a Certificate as authentication method func (a authTLS) Parse(ing *extensions.Ingress) (interface{}, error) { - tlsauthsecret, err := parser.GetStringAnnotation(annotationAuthTLSSecret, ing) + tlsauthsecret, err := parser.GetStringAnnotation(a.r.GetAnnotationWithPrefix("auth-tls-secret"), ing, a.r) if err != nil { return &Config{}, err } @@ -101,24 +96,24 @@ func (a authTLS) Parse(ing *extensions.Ingress) (interface{}, error) { return &Config{}, ing_errors.NewLocationDenied(err.Error()) } - tlsVerifyClient, err := parser.GetStringAnnotation(annotationAuthVerifyClient, ing) + tlsVerifyClient, err := parser.GetStringAnnotation("auth-tls-verify-client", ing, a.r) if err != nil || !authVerifyClientRegex.MatchString(tlsVerifyClient) { tlsVerifyClient = defaultAuthVerifyClient } - tlsdepth, err := parser.GetIntAnnotation(annotationAuthTLSDepth, ing) + tlsdepth, err := parser.GetIntAnnotation("auth-tls-verify-depth", ing, a.r) if err != nil || tlsdepth == 0 { tlsdepth = defaultAuthTLSDepth } - authCert, err := a.certResolver.GetAuthCertificate(tlsauthsecret) + authCert, err := a.r.GetAuthCertificate(tlsauthsecret) if err != nil { return &Config{}, ing_errors.LocationDenied{ Reason: errors.Wrap(err, "error obtaining certificate"), } } - errorpage, err := parser.GetStringAnnotation(annotationAuthTLSErrorPage, ing) + errorpage, err := parser.GetStringAnnotation("auth-tls-error-page", ing, a.r) if err != nil || errorpage == "" { errorpage = "" } diff --git a/internal/ingress/annotations/class/main.go b/internal/ingress/annotations/class/main.go index 9c0db669b..33c7c7629 100644 --- a/internal/ingress/annotations/class/main.go +++ b/internal/ingress/annotations/class/main.go @@ -19,9 +19,6 @@ package class import ( "github.com/golang/glog" extensions "k8s.io/api/extensions/v1beta1" - - "k8s.io/ingress-nginx/internal/ingress/annotations/parser" - "k8s.io/ingress-nginx/internal/ingress/errors" ) const ( @@ -35,9 +32,9 @@ const ( // the ingress.class annotation, or it's set to the configured in the // ingress controller. func IsValid(ing *extensions.Ingress, controller, defClass string) bool { - ingress, err := parser.GetStringAnnotation(IngressKey, ing) - if err != nil && !errors.IsMissingAnnotations(err) { - glog.Warningf("unexpected error reading ingress annotation: %v", err) + ingress, ok := ing.GetAnnotations()[IngressKey] + if !ok { + glog.V(3).Infof("annotation %v is not present in ingress %v/%v", IngressKey, ing.Namespace, ing.Name) } // we have 2 valid combinations diff --git a/internal/ingress/annotations/clientbodybuffersize/main.go b/internal/ingress/annotations/clientbodybuffersize/main.go index c8abf2701..6ff3e070a 100644 --- a/internal/ingress/annotations/clientbodybuffersize/main.go +++ b/internal/ingress/annotations/clientbodybuffersize/main.go @@ -20,22 +20,20 @@ import ( extensions "k8s.io/api/extensions/v1beta1" "k8s.io/ingress-nginx/internal/ingress/annotations/parser" -) - -const ( - annotation = "ingress.kubernetes.io/client-body-buffer-size" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) type clientBodyBufferSize struct { + r resolver.Resolver } // NewParser creates a new clientBodyBufferSize annotation parser -func NewParser() parser.IngressAnnotation { - return clientBodyBufferSize{} +func NewParser(r resolver.Resolver) parser.IngressAnnotation { + return clientBodyBufferSize{r} } // Parse parses the annotations contained in the ingress rule // used to add an client-body-buffer-size to the provided locations -func (a clientBodyBufferSize) Parse(ing *extensions.Ingress) (interface{}, error) { - return parser.GetStringAnnotation(annotation, ing) +func (cbbs clientBodyBufferSize) Parse(ing *extensions.Ingress) (interface{}, error) { + return parser.GetStringAnnotation("client-body-buffer-size", ing, cbbs.r) } diff --git a/internal/ingress/annotations/clientbodybuffersize/main_test.go b/internal/ingress/annotations/clientbodybuffersize/main_test.go index 8ed6e0c38..b47231498 100644 --- a/internal/ingress/annotations/clientbodybuffersize/main_test.go +++ b/internal/ingress/annotations/clientbodybuffersize/main_test.go @@ -22,10 +22,12 @@ import ( api "k8s.io/api/core/v1" extensions "k8s.io/api/extensions/v1beta1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) func TestParse(t *testing.T) { - ap := NewParser() + annotation := "nginx/client-body-buffer-size" + ap := NewParser(&resolver.Mock{}) if ap == nil { t.Fatalf("expected a parser.IngressAnnotation but returned nil") } diff --git a/internal/ingress/annotations/cors/main.go b/internal/ingress/annotations/cors/main.go index aa03ce035..ac77c250a 100644 --- a/internal/ingress/annotations/cors/main.go +++ b/internal/ingress/annotations/cors/main.go @@ -22,14 +22,10 @@ import ( extensions "k8s.io/api/extensions/v1beta1" "k8s.io/ingress-nginx/internal/ingress/annotations/parser" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) const ( - annotationCorsEnabled = "ingress.kubernetes.io/enable-cors" - annotationCorsAllowOrigin = "ingress.kubernetes.io/cors-allow-origin" - annotationCorsAllowMethods = "ingress.kubernetes.io/cors-allow-methods" - annotationCorsAllowHeaders = "ingress.kubernetes.io/cors-allow-headers" - annotationCorsAllowCredentials = "ingress.kubernetes.io/cors-allow-credentials" // Default values defaultCorsMethods = "GET, PUT, POST, DELETE, PATCH, OPTIONS" defaultCorsHeaders = "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization" @@ -49,6 +45,7 @@ var ( ) type cors struct { + r resolver.Resolver } // Config contains the Cors configuration to be used in the Ingress @@ -61,8 +58,8 @@ type Config struct { } // NewParser creates a new CORS annotation parser -func NewParser() parser.IngressAnnotation { - return cors{} +func NewParser(r resolver.Resolver) parser.IngressAnnotation { + return cors{r} } // Equal tests for equality between two External types @@ -94,28 +91,28 @@ func (c1 *Config) Equal(c2 *Config) bool { // Parse parses the annotations contained in the ingress // rule used to indicate if the location/s should allows CORS -func (a cors) Parse(ing *extensions.Ingress) (interface{}, error) { - corsenabled, err := parser.GetBoolAnnotation(annotationCorsEnabled, ing) +func (c cors) Parse(ing *extensions.Ingress) (interface{}, error) { + corsenabled, err := parser.GetBoolAnnotation("enable-cors", ing, c.r) if err != nil { corsenabled = false } - corsalloworigin, err := parser.GetStringAnnotation(annotationCorsAllowOrigin, ing) + corsalloworigin, err := parser.GetStringAnnotation("cors-allow-origin", ing, c.r) if err != nil || corsalloworigin == "" || !corsOriginRegex.MatchString(corsalloworigin) { corsalloworigin = "*" } - corsallowheaders, err := parser.GetStringAnnotation(annotationCorsAllowHeaders, ing) + corsallowheaders, err := parser.GetStringAnnotation("cors-allow-headers", ing, c.r) if err != nil || corsallowheaders == "" || !corsHeadersRegex.MatchString(corsallowheaders) { corsallowheaders = defaultCorsHeaders } - corsallowmethods, err := parser.GetStringAnnotation(annotationCorsAllowMethods, ing) + corsallowmethods, err := parser.GetStringAnnotation("cors-allow-methods", ing, c.r) if err != nil || corsallowmethods == "" || !corsMethodsRegex.MatchString(corsallowmethods) { corsallowmethods = defaultCorsMethods } - corsallowcredentials, err := parser.GetBoolAnnotation(annotationCorsAllowCredentials, ing) + corsallowcredentials, err := parser.GetBoolAnnotation("cors-allow-credentials", ing, c.r) if err != nil { corsallowcredentials = true } diff --git a/internal/ingress/annotations/cors/main_test.go b/internal/ingress/annotations/cors/main_test.go index 101e26cbc..2eda3a0fa 100644 --- a/internal/ingress/annotations/cors/main_test.go +++ b/internal/ingress/annotations/cors/main_test.go @@ -23,6 +23,7 @@ import ( extensions "k8s.io/api/extensions/v1beta1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) func buildIngress() *extensions.Ingress { @@ -64,14 +65,14 @@ func TestIngressCorsConfig(t *testing.T) { ing := buildIngress() data := map[string]string{} - data[annotationCorsEnabled] = "true" - data[annotationCorsAllowHeaders] = "DNT,X-CustomHeader, Keep-Alive,User-Agent" - data[annotationCorsAllowCredentials] = "false" - data[annotationCorsAllowMethods] = "PUT, GET,OPTIONS, PATCH, $nginx_version" - data[annotationCorsAllowOrigin] = "https://origin123.test.com:4443" + data["nginx/enable-cors"] = "true" + data["nginx/cors-allow-headers"] = "DNT,X-CustomHeader, Keep-Alive,User-Agent" + data["nginx/cors-allow-credentials"] = "false" + data["nginx/cors-allow-methods"] = "PUT, GET,OPTIONS, PATCH, $nginx_version" + data["nginx/cors-allow-origin"] = "https://origin123.test.com:4443" ing.SetAnnotations(data) - corst, _ := NewParser().Parse(ing) + corst, _ := NewParser(&resolver.Mock{}).Parse(ing) nginxCors, ok := corst.(*Config) if !ok { t.Errorf("expected a Config type") diff --git a/internal/ingress/annotations/defaultbackend/main.go b/internal/ingress/annotations/defaultbackend/main.go index fa19a583d..1d4be720f 100644 --- a/internal/ingress/annotations/defaultbackend/main.go +++ b/internal/ingress/annotations/defaultbackend/main.go @@ -26,29 +26,25 @@ import ( "k8s.io/ingress-nginx/internal/ingress/resolver" ) -const ( - defaultBackend = "ingress.kubernetes.io/default-backend" -) - type backend struct { - serviceResolver resolver.Service + r resolver.Resolver } // NewParser creates a new default backend annotation parser -func NewParser(sr resolver.Service) parser.IngressAnnotation { - return backend{sr} +func NewParser(r resolver.Resolver) parser.IngressAnnotation { + return backend{r} } // Parse parses the annotations contained in the ingress to use // a custom default backend func (db backend) Parse(ing *extensions.Ingress) (interface{}, error) { - s, err := parser.GetStringAnnotation(defaultBackend, ing) + s, err := parser.GetStringAnnotation("default-backend", ing, db.r) if err != nil { return nil, err } name := fmt.Sprintf("%v/%v", ing.Namespace, s) - svc, err := db.serviceResolver.GetService(name) + svc, err := db.r.GetService(name) if err != nil { return nil, errors.Wrapf(err, "unexpected error reading service %v", name) } diff --git a/internal/ingress/annotations/healthcheck/main.go b/internal/ingress/annotations/healthcheck/main.go index ca386a296..44c5b3602 100644 --- a/internal/ingress/annotations/healthcheck/main.go +++ b/internal/ingress/annotations/healthcheck/main.go @@ -23,11 +23,6 @@ import ( "k8s.io/ingress-nginx/internal/ingress/resolver" ) -const ( - upsMaxFails = "ingress.kubernetes.io/upstream-max-fails" - upsFailTimeout = "ingress.kubernetes.io/upstream-fail-timeout" -) - // Config returns the URL and method to use check the status of // the upstream server/s type Config struct { @@ -36,28 +31,28 @@ type Config struct { } type healthCheck struct { - backendResolver resolver.DefaultBackend + r resolver.Resolver } // NewParser creates a new health check annotation parser -func NewParser(br resolver.DefaultBackend) parser.IngressAnnotation { - return healthCheck{br} +func NewParser(r resolver.Resolver) parser.IngressAnnotation { + return healthCheck{r} } // ParseAnnotations parses the annotations contained in the ingress // rule used to configure upstream check parameters -func (a healthCheck) Parse(ing *extensions.Ingress) (interface{}, error) { - defBackend := a.backendResolver.GetDefaultBackend() +func (hc healthCheck) Parse(ing *extensions.Ingress) (interface{}, error) { + defBackend := hc.r.GetDefaultBackend() if ing.GetAnnotations() == nil { return &Config{defBackend.UpstreamMaxFails, defBackend.UpstreamFailTimeout}, nil } - mf, err := parser.GetIntAnnotation(upsMaxFails, ing) + mf, err := parser.GetIntAnnotation("upstream-max-fails", ing, hc.r) if err != nil { mf = defBackend.UpstreamMaxFails } - ft, err := parser.GetIntAnnotation(upsFailTimeout, ing) + ft, err := parser.GetIntAnnotation("upstream-fail-timeout", ing, hc.r) if err != nil { ft = defBackend.UpstreamFailTimeout } diff --git a/internal/ingress/annotations/healthcheck/main_test.go b/internal/ingress/annotations/healthcheck/main_test.go index 31b43eb39..1654aa0c2 100644 --- a/internal/ingress/annotations/healthcheck/main_test.go +++ b/internal/ingress/annotations/healthcheck/main_test.go @@ -25,6 +25,7 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/ingress-nginx/internal/ingress/defaults" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) func buildIngress() *extensions.Ingress { @@ -63,6 +64,7 @@ func buildIngress() *extensions.Ingress { } type mockBackend struct { + resolver.Mock } func (m mockBackend) GetDefaultBackend() defaults.Backend { @@ -73,7 +75,7 @@ func TestIngressHealthCheck(t *testing.T) { ing := buildIngress() data := map[string]string{} - data[upsMaxFails] = "2" + data["nginx/upstream-max-fails"] = "2" ing.SetAnnotations(data) hzi, _ := NewParser(mockBackend{}).Parse(ing) diff --git a/internal/ingress/annotations/ipwhitelist/main.go b/internal/ingress/annotations/ipwhitelist/main.go index 2b4cd72aa..2681f7136 100644 --- a/internal/ingress/annotations/ipwhitelist/main.go +++ b/internal/ingress/annotations/ipwhitelist/main.go @@ -30,10 +30,6 @@ import ( "k8s.io/ingress-nginx/internal/ingress/resolver" ) -const ( - whitelist = "ingress.kubernetes.io/whitelist-source-range" -) - // SourceRange returns the CIDR type SourceRange struct { CIDR []string `json:"cidr,omitEmpty"` @@ -69,12 +65,12 @@ func (sr1 *SourceRange) Equal(sr2 *SourceRange) bool { } type ipwhitelist struct { - backendResolver resolver.DefaultBackend + r resolver.Resolver } // NewParser creates a new whitelist annotation parser -func NewParser(br resolver.DefaultBackend) parser.IngressAnnotation { - return ipwhitelist{br} +func NewParser(r resolver.Resolver) parser.IngressAnnotation { + return ipwhitelist{r} } // ParseAnnotations parses the annotations contained in the ingress @@ -82,10 +78,10 @@ func NewParser(br resolver.DefaultBackend) parser.IngressAnnotation { // Multiple ranges can specified using commas as separator // e.g. `18.0.0.0/8,56.0.0.0/8` func (a ipwhitelist) Parse(ing *extensions.Ingress) (interface{}, error) { - defBackend := a.backendResolver.GetDefaultBackend() + defBackend := a.r.GetDefaultBackend() sort.Strings(defBackend.WhitelistSourceRange) - val, err := parser.GetStringAnnotation(whitelist, ing) + val, err := parser.GetStringAnnotation("whitelist-source-range", ing, a.r) // A missing annotation is not a problem, just use the default if err == ing_errors.ErrMissingAnnotations { return &SourceRange{CIDR: defBackend.WhitelistSourceRange}, nil diff --git a/internal/ingress/annotations/ipwhitelist/main_test.go b/internal/ingress/annotations/ipwhitelist/main_test.go index a4e166608..2e7d54f5c 100644 --- a/internal/ingress/annotations/ipwhitelist/main_test.go +++ b/internal/ingress/annotations/ipwhitelist/main_test.go @@ -23,8 +23,8 @@ import ( extensions "k8s.io/api/extensions/v1beta1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" - "k8s.io/ingress-nginx/internal/ingress/defaults" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) func buildIngress() *extensions.Ingress { @@ -62,14 +62,6 @@ func buildIngress() *extensions.Ingress { } } -type mockBackend struct { - defaults.Backend -} - -func (m mockBackend) GetDefaultBackend() defaults.Backend { - return m.Backend -} - func TestParseAnnotations(t *testing.T) { ing := buildIngress() tests := map[string]struct { @@ -102,9 +94,9 @@ func TestParseAnnotations(t *testing.T) { for testName, test := range tests { data := map[string]string{} - data[whitelist] = test.net + data["nginx/whitelist-source-range"] = test.net ing.SetAnnotations(data) - p := NewParser(mockBackend{}) + p := NewParser(&resolver.Mock{}) i, err := p.Parse(ing) if err != nil && !test.expectErr { t.Errorf("%v:unexpected error: %v", testName, err) @@ -126,12 +118,24 @@ func TestParseAnnotations(t *testing.T) { } } +type mockBackend struct { + resolver.Mock +} + +// GetDefaultBackend returns the backend that must be used as default +func (m mockBackend) GetDefaultBackend() defaults.Backend { + return defaults.Backend{ + WhitelistSourceRange: []string{"4.4.4.0/24", "1.2.3.4/32"}, + } +} + // Test that when we have a whitelist set on the Backend that is used when we // don't have the annotation func TestParseAnnotationsWithDefaultConfig(t *testing.T) { ing := buildIngress() + mockBackend := mockBackend{} - mockBackend.Backend.WhitelistSourceRange = []string{"4.4.4.0/24", "1.2.3.4/32"} + tests := map[string]struct { net string expectCidr []string @@ -162,7 +166,7 @@ func TestParseAnnotationsWithDefaultConfig(t *testing.T) { for testName, test := range tests { data := map[string]string{} - data[whitelist] = test.net + data["nginx/whitelist-source-range"] = test.net ing.SetAnnotations(data) p := NewParser(mockBackend) i, err := p.Parse(ing) diff --git a/internal/ingress/annotations/parser/main.go b/internal/ingress/annotations/parser/main.go index cbec167a5..d0e8dca71 100644 --- a/internal/ingress/annotations/parser/main.go +++ b/internal/ingress/annotations/parser/main.go @@ -22,6 +22,7 @@ import ( extensions "k8s.io/api/extensions/v1beta1" "k8s.io/ingress-nginx/internal/ingress/errors" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) // IngressAnnotation has a method to parse annotations located in Ingress @@ -75,28 +76,31 @@ func checkAnnotation(name string, ing *extensions.Ingress) error { } // GetBoolAnnotation extracts a boolean from an Ingress annotation -func GetBoolAnnotation(name string, ing *extensions.Ingress) (bool, error) { - err := checkAnnotation(name, ing) +func GetBoolAnnotation(name string, ing *extensions.Ingress, r resolver.Resolver) (bool, error) { + v := r.GetAnnotationWithPrefix(name) + err := checkAnnotation(v, ing) if err != nil { return false, err } - return ingAnnotations(ing.GetAnnotations()).parseBool(name) + return ingAnnotations(ing.GetAnnotations()).parseBool(v) } // GetStringAnnotation extracts a string from an Ingress annotation -func GetStringAnnotation(name string, ing *extensions.Ingress) (string, error) { - err := checkAnnotation(name, ing) +func GetStringAnnotation(name string, ing *extensions.Ingress, r resolver.Resolver) (string, error) { + v := r.GetAnnotationWithPrefix(name) + err := checkAnnotation(v, ing) if err != nil { return "", err } - return ingAnnotations(ing.GetAnnotations()).parseString(name) + return ingAnnotations(ing.GetAnnotations()).parseString(v) } // GetIntAnnotation extracts an int from an Ingress annotation -func GetIntAnnotation(name string, ing *extensions.Ingress) (int, error) { - err := checkAnnotation(name, ing) +func GetIntAnnotation(name string, ing *extensions.Ingress, r resolver.Resolver) (int, error) { + v := r.GetAnnotationWithPrefix(name) + err := checkAnnotation(v, ing) if err != nil { return 0, err } - return ingAnnotations(ing.GetAnnotations()).parseInt(name) + return ingAnnotations(ing.GetAnnotations()).parseInt(v) } diff --git a/internal/ingress/annotations/parser/main_test.go b/internal/ingress/annotations/parser/main_test.go index 4bcc3188e..b04f0d722 100644 --- a/internal/ingress/annotations/parser/main_test.go +++ b/internal/ingress/annotations/parser/main_test.go @@ -17,11 +17,13 @@ limitations under the License. package parser import ( + "fmt" "testing" api "k8s.io/api/core/v1" extensions "k8s.io/api/extensions/v1beta1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) func buildIngress() *extensions.Ingress { @@ -35,9 +37,11 @@ func buildIngress() *extensions.Ingress { } func TestGetBoolAnnotation(t *testing.T) { + r := &resolver.Mock{} + ing := buildIngress() - _, err := GetBoolAnnotation("", nil) + _, err := GetBoolAnnotation("", nil, r) if err == nil { t.Errorf("expected error but retuned nil") } @@ -49,8 +53,6 @@ func TestGetBoolAnnotation(t *testing.T) { exp bool expErr bool }{ - {"empty - false", "", "false", false, true}, - {"empty - true", "", "true", false, true}, {"valid - false", "bool", "false", false, false}, {"valid - true", "bool", "true", true, false}, } @@ -59,9 +61,9 @@ func TestGetBoolAnnotation(t *testing.T) { ing.SetAnnotations(data) for _, test := range tests { - data[test.field] = test.value + data[fmt.Sprintf("nginx/%v", test.field)] = test.value - u, err := GetBoolAnnotation(test.field, ing) + u, err := GetBoolAnnotation(test.field, ing, r) if test.expErr { if err == nil { t.Errorf("%v: expected error but retuned nil", test.name) @@ -77,9 +79,11 @@ func TestGetBoolAnnotation(t *testing.T) { } func TestGetStringAnnotation(t *testing.T) { + r := &resolver.Mock{} + ing := buildIngress() - _, err := GetStringAnnotation("", nil) + _, err := GetStringAnnotation("", nil, r) if err == nil { t.Errorf("expected error but retuned nil") } @@ -91,8 +95,6 @@ func TestGetStringAnnotation(t *testing.T) { exp string expErr bool }{ - {"empty - A", "", "A", "", true}, - {"empty - B", "", "B", "", true}, {"valid - A", "string", "A", "A", false}, {"valid - B", "string", "B", "B", false}, } @@ -101,9 +103,9 @@ func TestGetStringAnnotation(t *testing.T) { ing.SetAnnotations(data) for _, test := range tests { - data[test.field] = test.value + data[fmt.Sprintf("nginx/%v", test.field)] = test.value - s, err := GetStringAnnotation(test.field, ing) + s, err := GetStringAnnotation(test.field, ing, r) if test.expErr { if err == nil { t.Errorf("%v: expected error but retuned nil", test.name) @@ -119,9 +121,11 @@ func TestGetStringAnnotation(t *testing.T) { } func TestGetIntAnnotation(t *testing.T) { + r := &resolver.Mock{} + ing := buildIngress() - _, err := GetIntAnnotation("", nil) + _, err := GetIntAnnotation("", nil, r) if err == nil { t.Errorf("expected error but retuned nil") } @@ -133,8 +137,6 @@ func TestGetIntAnnotation(t *testing.T) { exp int expErr bool }{ - {"empty - A", "", "1", 0, true}, - {"empty - B", "", "2", 0, true}, {"valid - A", "string", "1", 1, false}, {"valid - B", "string", "2", 2, false}, } @@ -143,9 +145,9 @@ func TestGetIntAnnotation(t *testing.T) { ing.SetAnnotations(data) for _, test := range tests { - data[test.field] = test.value + data[fmt.Sprintf("nginx/%v", test.field)] = test.value - s, err := GetIntAnnotation(test.field, ing) + s, err := GetIntAnnotation(test.field, ing, r) if test.expErr { if err == nil { t.Errorf("%v: expected error but retuned nil", test.name) diff --git a/internal/ingress/annotations/portinredirect/main.go b/internal/ingress/annotations/portinredirect/main.go index 093af7dde..459878069 100644 --- a/internal/ingress/annotations/portinredirect/main.go +++ b/internal/ingress/annotations/portinredirect/main.go @@ -23,25 +23,21 @@ import ( "k8s.io/ingress-nginx/internal/ingress/resolver" ) -const ( - annotation = "ingress.kubernetes.io/use-port-in-redirects" -) - type portInRedirect struct { - backendResolver resolver.DefaultBackend + r resolver.Resolver } // NewParser creates a new port in redirect annotation parser -func NewParser(db resolver.DefaultBackend) parser.IngressAnnotation { - return portInRedirect{db} +func NewParser(r resolver.Resolver) parser.IngressAnnotation { + return portInRedirect{r} } // Parse parses the annotations contained in the ingress // rule used to indicate if the redirects must func (a portInRedirect) Parse(ing *extensions.Ingress) (interface{}, error) { - up, err := parser.GetBoolAnnotation(annotation, ing) + up, err := parser.GetBoolAnnotation("use-port-in-redirects", ing, a.r) if err != nil { - return a.backendResolver.GetDefaultBackend().UsePortInRedirects, nil + return a.r.GetDefaultBackend().UsePortInRedirects, nil } return up, nil diff --git a/internal/ingress/annotations/portinredirect/main_test.go b/internal/ingress/annotations/portinredirect/main_test.go index a7454302a..9bd0e4f31 100644 --- a/internal/ingress/annotations/portinredirect/main_test.go +++ b/internal/ingress/annotations/portinredirect/main_test.go @@ -26,6 +26,7 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/ingress-nginx/internal/ingress/defaults" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) func buildIngress() *extensions.Ingress { @@ -64,6 +65,7 @@ func buildIngress() *extensions.Ingress { } type mockBackend struct { + resolver.Mock usePortInRedirects bool } @@ -90,11 +92,11 @@ func TestPortInRedirect(t *testing.T) { data := map[string]string{} if test.usePort != nil { - data[annotation] = fmt.Sprintf("%v", *test.usePort) + data["nginx/use-port-in-redirects"] = fmt.Sprintf("%v", *test.usePort) } ing.SetAnnotations(data) - i, err := NewParser(mockBackend{test.def}).Parse(ing) + i, err := NewParser(mockBackend{usePortInRedirects: test.def}).Parse(ing) if err != nil { t.Errorf("unexpected error parsing a valid") } diff --git a/internal/ingress/annotations/proxy/main.go b/internal/ingress/annotations/proxy/main.go index 8dee7ce07..e193312de 100644 --- a/internal/ingress/annotations/proxy/main.go +++ b/internal/ingress/annotations/proxy/main.go @@ -23,19 +23,6 @@ import ( "k8s.io/ingress-nginx/internal/ingress/resolver" ) -const ( - bodySize = "ingress.kubernetes.io/proxy-body-size" - connect = "ingress.kubernetes.io/proxy-connect-timeout" - send = "ingress.kubernetes.io/proxy-send-timeout" - read = "ingress.kubernetes.io/proxy-read-timeout" - bufferSize = "ingress.kubernetes.io/proxy-buffer-size" - cookiePath = "ingress.kubernetes.io/proxy-cookie-path" - cookieDomain = "ingress.kubernetes.io/proxy-cookie-domain" - nextUpstream = "ingress.kubernetes.io/proxy-next-upstream" - passParams = "ingress.kubernetes.io/proxy-pass-params" - requestBuffering = "ingress.kubernetes.io/proxy-request-buffering" -) - // Config returns the proxy timeout to use in the upstream server/s type Config struct { BodySize string `json:"bodySize"` @@ -94,64 +81,64 @@ func (l1 *Config) Equal(l2 *Config) bool { } type proxy struct { - backendResolver resolver.DefaultBackend + r resolver.Resolver } // NewParser creates a new reverse proxy configuration annotation parser -func NewParser(br resolver.DefaultBackend) parser.IngressAnnotation { - return proxy{br} +func NewParser(r resolver.Resolver) parser.IngressAnnotation { + return proxy{r} } // ParseAnnotations parses the annotations contained in the ingress // rule used to configure upstream check parameters func (a proxy) Parse(ing *extensions.Ingress) (interface{}, error) { - defBackend := a.backendResolver.GetDefaultBackend() - ct, err := parser.GetIntAnnotation(connect, ing) + defBackend := a.r.GetDefaultBackend() + ct, err := parser.GetIntAnnotation("proxy-connect-timeout", ing, a.r) if err != nil { ct = defBackend.ProxyConnectTimeout } - st, err := parser.GetIntAnnotation(send, ing) + st, err := parser.GetIntAnnotation("proxy-send-timeout", ing, a.r) if err != nil { st = defBackend.ProxySendTimeout } - rt, err := parser.GetIntAnnotation(read, ing) + rt, err := parser.GetIntAnnotation("proxy-read-timeout", ing, a.r) if err != nil { rt = defBackend.ProxyReadTimeout } - bufs, err := parser.GetStringAnnotation(bufferSize, ing) + bufs, err := parser.GetStringAnnotation("proxy-buffer-size", ing, a.r) if err != nil || bufs == "" { bufs = defBackend.ProxyBufferSize } - cp, err := parser.GetStringAnnotation(cookiePath, ing) + cp, err := parser.GetStringAnnotation("proxy-cookie-path", ing, a.r) if err != nil || cp == "" { cp = defBackend.ProxyCookiePath } - cd, err := parser.GetStringAnnotation(cookieDomain, ing) + cd, err := parser.GetStringAnnotation("proxy-cookie-domain", ing, a.r) if err != nil || cd == "" { cd = defBackend.ProxyCookieDomain } - bs, err := parser.GetStringAnnotation(bodySize, ing) + bs, err := parser.GetStringAnnotation("proxy-body-size", ing, a.r) if err != nil || bs == "" { bs = defBackend.ProxyBodySize } - nu, err := parser.GetStringAnnotation(nextUpstream, ing) + nu, err := parser.GetStringAnnotation("proxy-next-upstream", ing, a.r) if err != nil || nu == "" { nu = defBackend.ProxyNextUpstream } - pp, err := parser.GetStringAnnotation(passParams, ing) + pp, err := parser.GetStringAnnotation("proxy-pass-params", ing, a.r) if err != nil || pp == "" { pp = defBackend.ProxyPassParams } - rb, err := parser.GetStringAnnotation(requestBuffering, ing) + rb, err := parser.GetStringAnnotation("proxy-request-buffering", ing, a.r) if err != nil || rb == "" { rb = defBackend.ProxyRequestBuffering } diff --git a/internal/ingress/annotations/proxy/main_test.go b/internal/ingress/annotations/proxy/main_test.go index 749d28206..c83dc9ef1 100644 --- a/internal/ingress/annotations/proxy/main_test.go +++ b/internal/ingress/annotations/proxy/main_test.go @@ -25,6 +25,7 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/ingress-nginx/internal/ingress/defaults" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) func buildIngress() *extensions.Ingress { @@ -63,6 +64,7 @@ func buildIngress() *extensions.Ingress { } type mockBackend struct { + resolver.Mock } func (m mockBackend) GetDefaultBackend() defaults.Backend { @@ -83,14 +85,14 @@ func TestProxy(t *testing.T) { ing := buildIngress() data := map[string]string{} - data[connect] = "1" - data[send] = "2" - data[read] = "3" - data[bufferSize] = "1k" - data[bodySize] = "2k" - data[nextUpstream] = "off" - data[passParams] = "smax=5 max=10" - data[requestBuffering] = "off" + data["nginx/proxy-connect-timeout"] = "1" + data["nginx/proxy-send-timeout"] = "2" + data["nginx/proxy-read-timeout"] = "3" + data["nginx/proxy-buffer-size"] = "1k" + data["nginx/proxy-body-size"] = "2k" + data["nginx/proxy-next-upstream"] = "off" + data["nginx/proxy-pass-params"] = "smax=5 max=10" + data["nginx/proxy-request-buffering"] = "off" ing.SetAnnotations(data) i, err := NewParser(mockBackend{}).Parse(ing) diff --git a/internal/ingress/annotations/ratelimit/main.go b/internal/ingress/annotations/ratelimit/main.go index e2a21f240..624d4aefd 100644 --- a/internal/ingress/annotations/ratelimit/main.go +++ b/internal/ingress/annotations/ratelimit/main.go @@ -30,13 +30,6 @@ import ( ) const ( - limitIP = "ingress.kubernetes.io/limit-connections" - limitRPS = "ingress.kubernetes.io/limit-rps" - limitRPM = "ingress.kubernetes.io/limit-rpm" - limitRATE = "ingress.kubernetes.io/limit-rate" - limitRATEAFTER = "ingress.kubernetes.io/limit-rate-after" - limitWhitelist = "ingress.kubernetes.io/limit-whitelist" - // allow 5 times the specified limit as burst defBurst = 5 @@ -152,32 +145,32 @@ func (z1 *Zone) Equal(z2 *Zone) bool { } type ratelimit struct { - backendResolver resolver.DefaultBackend + r resolver.Resolver } // NewParser creates a new ratelimit annotation parser -func NewParser(br resolver.DefaultBackend) parser.IngressAnnotation { - return ratelimit{br} +func NewParser(r resolver.Resolver) parser.IngressAnnotation { + return ratelimit{r} } // ParseAnnotations parses the annotations contained in the ingress // rule used to rewrite the defined paths func (a ratelimit) Parse(ing *extensions.Ingress) (interface{}, error) { - defBackend := a.backendResolver.GetDefaultBackend() - lr, err := parser.GetIntAnnotation(limitRATE, ing) + defBackend := a.r.GetDefaultBackend() + lr, err := parser.GetIntAnnotation("limit-rate", ing, a.r) if err != nil { lr = defBackend.LimitRate } - lra, err := parser.GetIntAnnotation(limitRATEAFTER, ing) + lra, err := parser.GetIntAnnotation("limit-rate-after", ing, a.r) if err != nil { lra = defBackend.LimitRateAfter } - rpm, _ := parser.GetIntAnnotation(limitRPM, ing) - rps, _ := parser.GetIntAnnotation(limitRPS, ing) - conn, _ := parser.GetIntAnnotation(limitIP, ing) + rpm, _ := parser.GetIntAnnotation("limit-rpm", ing, a.r) + rps, _ := parser.GetIntAnnotation("limit-rps", ing, a.r) + conn, _ := parser.GetIntAnnotation("limit-connections", ing, a.r) - val, _ := parser.GetStringAnnotation(limitWhitelist, ing) + val, _ := parser.GetStringAnnotation("limit-whitelist", ing, a.r) cidrs, err := parseCIDRs(val) if err != nil { diff --git a/internal/ingress/annotations/ratelimit/main_test.go b/internal/ingress/annotations/ratelimit/main_test.go index 4437bea56..a470bbb47 100644 --- a/internal/ingress/annotations/ratelimit/main_test.go +++ b/internal/ingress/annotations/ratelimit/main_test.go @@ -25,6 +25,7 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/ingress-nginx/internal/ingress/defaults" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) func buildIngress() *extensions.Ingress { @@ -63,6 +64,7 @@ func buildIngress() *extensions.Ingress { } type mockBackend struct { + resolver.Mock } func (m mockBackend) GetDefaultBackend() defaults.Backend { @@ -84,9 +86,9 @@ func TestBadRateLimiting(t *testing.T) { ing := buildIngress() data := map[string]string{} - data[limitIP] = "0" - data[limitRPS] = "0" - data[limitRPM] = "0" + data["nginx/limit-connections"] = "0" + data["nginx/limit-rps"] = "0" + data["nginx/limit-rpm"] = "0" ing.SetAnnotations(data) _, err := NewParser(mockBackend{}).Parse(ing) @@ -95,11 +97,11 @@ func TestBadRateLimiting(t *testing.T) { } data = map[string]string{} - data[limitIP] = "5" - data[limitRPS] = "100" - data[limitRPM] = "10" - data[limitRATEAFTER] = "100" - data[limitRATE] = "10" + data["nginx/limit-connections"] = "5" + data["nginx/limit-rps"] = "100" + data["nginx/limit-rpm"] = "10" + data["nginx/limit-rate-after"] = "100" + data["nginx/limit-rate"] = "10" ing.SetAnnotations(data) diff --git a/internal/ingress/annotations/redirect/redirect.go b/internal/ingress/annotations/redirect/redirect.go index 6cd90d960..255763ef6 100644 --- a/internal/ingress/annotations/redirect/redirect.go +++ b/internal/ingress/annotations/redirect/redirect.go @@ -25,12 +25,7 @@ import ( "k8s.io/ingress-nginx/internal/ingress/annotations/parser" "k8s.io/ingress-nginx/internal/ingress/errors" -) - -const ( - permanent = "ingress.kubernetes.io/permanent-redirect" - temporal = "ingress.kubernetes.io/temporal-redirect" - www = "ingress.kubernetes.io/from-to-www-redirect" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) // Config returns the redirect configuration for an Ingress rule @@ -40,11 +35,13 @@ type Config struct { FromToWWW bool `json:"fromToWWW"` } -type redirect struct{} +type redirect struct { + r resolver.Resolver +} // NewParser creates a new redirect annotation parser -func NewParser() parser.IngressAnnotation { - return redirect{} +func NewParser(r resolver.Resolver) parser.IngressAnnotation { + return redirect{r} } // Parse parses the annotations contained in the ingress @@ -52,9 +49,9 @@ func NewParser() parser.IngressAnnotation { // If the Ingress contains both annotations the execution order is // temporal and then permanent func (a redirect) Parse(ing *extensions.Ingress) (interface{}, error) { - r3w, _ := parser.GetBoolAnnotation(www, ing) + r3w, _ := parser.GetBoolAnnotation("from-to-www-redirect", ing, a.r) - tr, err := parser.GetStringAnnotation(temporal, ing) + tr, err := parser.GetStringAnnotation("temporal-redirect", ing, a.r) if err != nil && !errors.IsMissingAnnotations(err) { return nil, err } @@ -71,7 +68,7 @@ func (a redirect) Parse(ing *extensions.Ingress) (interface{}, error) { }, nil } - pr, err := parser.GetStringAnnotation(permanent, ing) + pr, err := parser.GetStringAnnotation("permanent-redirect", ing, a.r) if err != nil && !errors.IsMissingAnnotations(err) { return nil, err } diff --git a/internal/ingress/annotations/rewrite/main.go b/internal/ingress/annotations/rewrite/main.go index 2b08fe323..227cba446 100644 --- a/internal/ingress/annotations/rewrite/main.go +++ b/internal/ingress/annotations/rewrite/main.go @@ -23,15 +23,6 @@ import ( "k8s.io/ingress-nginx/internal/ingress/resolver" ) -const ( - rewriteTo = "ingress.kubernetes.io/rewrite-target" - addBaseURL = "ingress.kubernetes.io/add-base-url" - baseURLScheme = "ingress.kubernetes.io/base-url-scheme" - sslRedirect = "ingress.kubernetes.io/ssl-redirect" - forceSSLRedirect = "ingress.kubernetes.io/force-ssl-redirect" - appRoot = "ingress.kubernetes.io/app-root" -) - // Config describes the per location redirect config type Config struct { // Target URI where the traffic must be redirected @@ -80,29 +71,30 @@ func (r1 *Config) Equal(r2 *Config) bool { } type rewrite struct { - backendResolver resolver.DefaultBackend + r resolver.Resolver } // NewParser creates a new reqrite annotation parser -func NewParser(br resolver.DefaultBackend) parser.IngressAnnotation { - return rewrite{br} +func NewParser(r resolver.Resolver) parser.IngressAnnotation { + return rewrite{r} } // ParseAnnotations parses the annotations contained in the ingress // rule used to rewrite the defined paths func (a rewrite) Parse(ing *extensions.Ingress) (interface{}, error) { - rt, _ := parser.GetStringAnnotation(rewriteTo, ing) - sslRe, err := parser.GetBoolAnnotation(sslRedirect, ing) + rt, _ := parser.GetStringAnnotation("rewrite-target", ing, a.r) + sslRe, err := parser.GetBoolAnnotation("ssl-redirect", ing, a.r) if err != nil { - sslRe = a.backendResolver.GetDefaultBackend().SSLRedirect + sslRe = a.r.GetDefaultBackend().SSLRedirect } - fSslRe, err := parser.GetBoolAnnotation(forceSSLRedirect, ing) + fSslRe, err := parser.GetBoolAnnotation("force-ssl-redirect", ing, a.r) if err != nil { - fSslRe = a.backendResolver.GetDefaultBackend().ForceSSLRedirect + fSslRe = a.r.GetDefaultBackend().ForceSSLRedirect } - abu, _ := parser.GetBoolAnnotation(addBaseURL, ing) - bus, _ := parser.GetStringAnnotation(baseURLScheme, ing) - ar, _ := parser.GetStringAnnotation(appRoot, ing) + abu, _ := parser.GetBoolAnnotation("add-base-url", ing, a.r) + bus, _ := parser.GetStringAnnotation("base-url-scheme", ing, a.r) + ar, _ := parser.GetStringAnnotation("app-root", ing, a.r) + return &Config{ Target: rt, AddBaseURL: abu, diff --git a/internal/ingress/annotations/rewrite/main_test.go b/internal/ingress/annotations/rewrite/main_test.go index 8e62ec49e..7b0f9c7c1 100644 --- a/internal/ingress/annotations/rewrite/main_test.go +++ b/internal/ingress/annotations/rewrite/main_test.go @@ -25,6 +25,7 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/ingress-nginx/internal/ingress/defaults" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) const ( @@ -67,6 +68,7 @@ func buildIngress() *extensions.Ingress { } type mockBackend struct { + resolver.Mock redirect bool } @@ -86,7 +88,7 @@ func TestRedirect(t *testing.T) { ing := buildIngress() data := map[string]string{} - data[rewriteTo] = defRoute + data["nginx/rewrite-target"] = defRoute ing.SetAnnotations(data) i, err := NewParser(mockBackend{}).Parse(ing) @@ -106,10 +108,10 @@ func TestSSLRedirect(t *testing.T) { ing := buildIngress() data := map[string]string{} - data[rewriteTo] = defRoute + data["nginx/rewrite-target"] = defRoute ing.SetAnnotations(data) - i, _ := NewParser(mockBackend{true}).Parse(ing) + i, _ := NewParser(mockBackend{redirect: true}).Parse(ing) redirect, ok := i.(*Config) if !ok { t.Errorf("expected a Redirect type") @@ -118,10 +120,10 @@ func TestSSLRedirect(t *testing.T) { t.Errorf("Expected true but returned false") } - data[sslRedirect] = "false" + data["nginx/ssl-redirect"] = "false" ing.SetAnnotations(data) - i, _ = NewParser(mockBackend{false}).Parse(ing) + i, _ = NewParser(mockBackend{redirect: false}).Parse(ing) redirect, ok = i.(*Config) if !ok { t.Errorf("expected a Redirect type") @@ -135,10 +137,10 @@ func TestForceSSLRedirect(t *testing.T) { ing := buildIngress() data := map[string]string{} - data[rewriteTo] = defRoute + data["nginx/rewrite-target"] = defRoute ing.SetAnnotations(data) - i, _ := NewParser(mockBackend{true}).Parse(ing) + i, _ := NewParser(mockBackend{redirect: true}).Parse(ing) redirect, ok := i.(*Config) if !ok { t.Errorf("expected a Redirect type") @@ -147,10 +149,10 @@ func TestForceSSLRedirect(t *testing.T) { t.Errorf("Expected false but returned true") } - data[forceSSLRedirect] = "true" + data["nginx/force-ssl-redirect"] = "true" ing.SetAnnotations(data) - i, _ = NewParser(mockBackend{false}).Parse(ing) + i, _ = NewParser(mockBackend{redirect: false}).Parse(ing) redirect, ok = i.(*Config) if !ok { t.Errorf("expected a Redirect type") @@ -163,10 +165,10 @@ func TestAppRoot(t *testing.T) { ing := buildIngress() data := map[string]string{} - data[appRoot] = "/app1" + data["nginx/app-root"] = "/app1" ing.SetAnnotations(data) - i, _ := NewParser(mockBackend{true}).Parse(ing) + i, _ := NewParser(mockBackend{redirect: true}).Parse(ing) redirect, ok := i.(*Config) if !ok { t.Errorf("expected a App Context") diff --git a/internal/ingress/annotations/secureupstream/main.go b/internal/ingress/annotations/secureupstream/main.go index 95439ba1a..c2d5082e7 100644 --- a/internal/ingress/annotations/secureupstream/main.go +++ b/internal/ingress/annotations/secureupstream/main.go @@ -26,11 +26,6 @@ import ( "k8s.io/ingress-nginx/internal/ingress/resolver" ) -const ( - secureUpstream = "ingress.kubernetes.io/secure-backends" - secureVerifyCASecret = "ingress.kubernetes.io/secure-verify-ca-secret" -) - // Config describes SSL backend configuration type Config struct { Secure bool `json:"secure"` @@ -38,21 +33,19 @@ type Config struct { } type su struct { - certResolver resolver.AuthCertificate + r resolver.Resolver } // NewParser creates a new secure upstream annotation parser -func NewParser(resolver resolver.AuthCertificate) parser.IngressAnnotation { - return su{ - certResolver: resolver, - } +func NewParser(r resolver.Resolver) parser.IngressAnnotation { + return su{r} } // Parse parses the annotations contained in the ingress // rule used to indicate if the upstream servers should use SSL func (a su) Parse(ing *extensions.Ingress) (interface{}, error) { - s, _ := parser.GetBoolAnnotation(secureUpstream, ing) - ca, _ := parser.GetStringAnnotation(secureVerifyCASecret, ing) + s, _ := parser.GetBoolAnnotation("secure-backends", ing, a.r) + ca, _ := parser.GetStringAnnotation("secure-verify-ca-secret", ing, a.r) secure := &Config{ Secure: s, CACert: resolver.AuthSSLCert{}, @@ -64,7 +57,7 @@ func (a su) Parse(ing *extensions.Ingress) (interface{}, error) { if ca == "" { return secure, nil } - caCert, err := a.certResolver.GetAuthCertificate(fmt.Sprintf("%v/%v", ing.Namespace, ca)) + caCert, err := a.r.GetAuthCertificate(fmt.Sprintf("%v/%v", ing.Namespace, ca)) if err != nil { return secure, errors.Wrap(err, "error obtaining certificate") } diff --git a/internal/ingress/annotations/secureupstream/main_test.go b/internal/ingress/annotations/secureupstream/main_test.go index 390b38485..6563c8c6e 100644 --- a/internal/ingress/annotations/secureupstream/main_test.go +++ b/internal/ingress/annotations/secureupstream/main_test.go @@ -64,6 +64,7 @@ func buildIngress() *extensions.Ingress { } type mockCfg struct { + resolver.Mock certs map[string]resolver.AuthSSLCert } @@ -77,8 +78,8 @@ func (cfg mockCfg) GetAuthCertificate(secret string) (*resolver.AuthSSLCert, err func TestAnnotations(t *testing.T) { ing := buildIngress() data := map[string]string{} - data[secureUpstream] = "true" - data[secureVerifyCASecret] = "secure-verify-ca" + data["nginx/secure-backends"] = "true" + data["nginx/secure-verify-ca-secret"] = "secure-verify-ca" ing.SetAnnotations(data) _, err := NewParser(mockCfg{ @@ -94,8 +95,8 @@ func TestAnnotations(t *testing.T) { func TestSecretNotFound(t *testing.T) { ing := buildIngress() data := map[string]string{} - data[secureUpstream] = "true" - data[secureVerifyCASecret] = "secure-verify-ca" + data["nginx/secure-backends"] = "true" + data["nginx/secure-verify-ca-secret"] = "secure-verify-ca" ing.SetAnnotations(data) _, err := NewParser(mockCfg{}).Parse(ing) if err == nil { @@ -106,8 +107,8 @@ func TestSecretNotFound(t *testing.T) { func TestSecretOnNonSecure(t *testing.T) { ing := buildIngress() data := map[string]string{} - data[secureUpstream] = "false" - data[secureVerifyCASecret] = "secure-verify-ca" + data["nginx/secure-backends"] = "false" + data["nginx/secure-verify-ca-secret"] = "secure-verify-ca" ing.SetAnnotations(data) _, err := NewParser(mockCfg{ certs: map[string]resolver.AuthSSLCert{ diff --git a/internal/ingress/annotations/serversnippet/main.go b/internal/ingress/annotations/serversnippet/main.go index 969c2eee5..d6830d8fe 100644 --- a/internal/ingress/annotations/serversnippet/main.go +++ b/internal/ingress/annotations/serversnippet/main.go @@ -20,23 +20,21 @@ import ( extensions "k8s.io/api/extensions/v1beta1" "k8s.io/ingress-nginx/internal/ingress/annotations/parser" -) - -const ( - annotation = "ingress.kubernetes.io/server-snippet" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) type serverSnippet struct { + r resolver.Resolver } // NewParser creates a new server snippet annotation parser -func NewParser() parser.IngressAnnotation { - return serverSnippet{} +func NewParser(r resolver.Resolver) parser.IngressAnnotation { + return serverSnippet{r} } // Parse parses the annotations contained in the ingress rule // used to indicate if the location/s contains a fragment of // configuration to be included inside the paths of the rules func (a serverSnippet) Parse(ing *extensions.Ingress) (interface{}, error) { - return parser.GetStringAnnotation(annotation, ing) + return parser.GetStringAnnotation("server-snippet", ing, a.r) } diff --git a/internal/ingress/annotations/serversnippet/main_test.go b/internal/ingress/annotations/serversnippet/main_test.go index 1a4d51bed..4d17e5e49 100644 --- a/internal/ingress/annotations/serversnippet/main_test.go +++ b/internal/ingress/annotations/serversnippet/main_test.go @@ -22,10 +22,13 @@ import ( api "k8s.io/api/core/v1" extensions "k8s.io/api/extensions/v1beta1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) func TestParse(t *testing.T) { - ap := NewParser() + annotation := "nginx/server-snippet" + + ap := NewParser(&resolver.Mock{}) if ap == nil { t.Fatalf("expected a parser.IngressAnnotation but returned nil") } diff --git a/internal/ingress/annotations/serviceupstream/main.go b/internal/ingress/annotations/serviceupstream/main.go index a1d9a5a9d..a8386edb6 100644 --- a/internal/ingress/annotations/serviceupstream/main.go +++ b/internal/ingress/annotations/serviceupstream/main.go @@ -18,21 +18,20 @@ package serviceupstream import ( extensions "k8s.io/api/extensions/v1beta1" - "k8s.io/ingress-nginx/internal/ingress/annotations/parser" -) -const ( - annotationServiceUpstream = "ingress.kubernetes.io/service-upstream" + "k8s.io/ingress-nginx/internal/ingress/annotations/parser" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) type serviceUpstream struct { + r resolver.Resolver } // NewParser creates a new serviceUpstream annotation parser -func NewParser() parser.IngressAnnotation { - return serviceUpstream{} +func NewParser(r resolver.Resolver) parser.IngressAnnotation { + return serviceUpstream{r} } func (s serviceUpstream) Parse(ing *extensions.Ingress) (interface{}, error) { - return parser.GetBoolAnnotation(annotationServiceUpstream, ing) + return parser.GetBoolAnnotation("service-upstream", ing, s.r) } diff --git a/internal/ingress/annotations/serviceupstream/main_test.go b/internal/ingress/annotations/serviceupstream/main_test.go index 9dcfdece6..0b196ca0f 100644 --- a/internal/ingress/annotations/serviceupstream/main_test.go +++ b/internal/ingress/annotations/serviceupstream/main_test.go @@ -23,6 +23,7 @@ import ( extensions "k8s.io/api/extensions/v1beta1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) func buildIngress() *extensions.Ingress { @@ -64,10 +65,10 @@ func TestIngressAnnotationServiceUpstreamEnabled(t *testing.T) { ing := buildIngress() data := map[string]string{} - data[annotationServiceUpstream] = "true" + data["nginx/service-upstream"] = "true" ing.SetAnnotations(data) - val, _ := NewParser().Parse(ing) + val, _ := NewParser(&resolver.Mock{}).Parse(ing) enabled, ok := val.(bool) if !ok { t.Errorf("expected a bool type") @@ -83,10 +84,10 @@ func TestIngressAnnotationServiceUpstreamSetFalse(t *testing.T) { // Test with explicitly set to false data := map[string]string{} - data[annotationServiceUpstream] = "false" + data["nginx/service-upstream"] = "false" ing.SetAnnotations(data) - val, _ := NewParser().Parse(ing) + val, _ := NewParser(&resolver.Mock{}).Parse(ing) enabled, ok := val.(bool) if !ok { t.Errorf("expected a bool type") @@ -100,7 +101,7 @@ func TestIngressAnnotationServiceUpstreamSetFalse(t *testing.T) { data = map[string]string{} ing.SetAnnotations(data) - val, _ = NewParser().Parse(ing) + val, _ = NewParser(&resolver.Mock{}).Parse(ing) enabled, ok = val.(bool) if !ok { t.Errorf("expected a bool type") diff --git a/internal/ingress/annotations/sessionaffinity/main.go b/internal/ingress/annotations/sessionaffinity/main.go index b32009f55..fd4bceeb4 100644 --- a/internal/ingress/annotations/sessionaffinity/main.go +++ b/internal/ingress/annotations/sessionaffinity/main.go @@ -24,17 +24,20 @@ import ( extensions "k8s.io/api/extensions/v1beta1" "k8s.io/ingress-nginx/internal/ingress/annotations/parser" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) const ( - annotationAffinityType = "ingress.kubernetes.io/affinity" + annotationAffinityType = "affinity" // If a cookie with this name exists, // its value is used as an index into the list of available backends. - annotationAffinityCookieName = "ingress.kubernetes.io/session-cookie-name" - defaultAffinityCookieName = "INGRESSCOOKIE" + annotationAffinityCookieName = "session-cookie-name" + + defaultAffinityCookieName = "INGRESSCOOKIE" + // This is the algorithm used by nginx to generate a value for the session cookie, if // one isn't supplied and affinity is set to "cookie". - annotationAffinityCookieHash = "ingress.kubernetes.io/session-cookie-hash" + annotationAffinityCookieHash = "session-cookie-hash" defaultAffinityCookieHash = "md5" ) @@ -59,16 +62,15 @@ type Cookie struct { // cookieAffinityParse gets the annotation values related to Cookie Affinity // It also sets default values when no value or incorrect value is found -func cookieAffinityParse(ing *extensions.Ingress) *Cookie { - - sn, err := parser.GetStringAnnotation(annotationAffinityCookieName, ing) +func (a affinity) cookieAffinityParse(ing *extensions.Ingress) *Cookie { + sn, err := parser.GetStringAnnotation(annotationAffinityCookieName, ing, a.r) if err != nil || sn == "" { glog.V(3).Infof("Ingress %v: No value found in annotation %v. Using the default %v", ing.Name, annotationAffinityCookieName, defaultAffinityCookieName) sn = defaultAffinityCookieName } - sh, err := parser.GetStringAnnotation(annotationAffinityCookieHash, ing) + sh, err := parser.GetStringAnnotation(annotationAffinityCookieHash, ing, a.r) if err != nil || !affinityCookieHashRegex.MatchString(sh) { glog.V(3).Infof("Invalid or no annotation value found in Ingress %v: %v. Setting it to default %v", ing.Name, annotationAffinityCookieHash, defaultAffinityCookieHash) @@ -82,11 +84,12 @@ func cookieAffinityParse(ing *extensions.Ingress) *Cookie { } // NewParser creates a new Affinity annotation parser -func NewParser() parser.IngressAnnotation { - return affinity{} +func NewParser(r resolver.Resolver) parser.IngressAnnotation { + return affinity{r} } type affinity struct { + r resolver.Resolver } // ParseAnnotations parses the annotations contained in the ingress @@ -94,14 +97,14 @@ type affinity struct { func (a affinity) Parse(ing *extensions.Ingress) (interface{}, error) { cookie := &Cookie{} // Check the type of affinity that will be used - at, err := parser.GetStringAnnotation(annotationAffinityType, ing) + at, err := parser.GetStringAnnotation(annotationAffinityType, ing, a.r) if err != nil { at = "" } switch at { case "cookie": - cookie = cookieAffinityParse(ing) + cookie = a.cookieAffinityParse(ing) default: glog.V(3).Infof("No default affinity was found for Ingress %v", ing.Name) diff --git a/internal/ingress/annotations/sessionaffinity/main_test.go b/internal/ingress/annotations/sessionaffinity/main_test.go index 625019827..464435117 100644 --- a/internal/ingress/annotations/sessionaffinity/main_test.go +++ b/internal/ingress/annotations/sessionaffinity/main_test.go @@ -17,12 +17,14 @@ limitations under the License. package sessionaffinity import ( + "fmt" "testing" api "k8s.io/api/core/v1" extensions "k8s.io/api/extensions/v1beta1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) func buildIngress() *extensions.Ingress { @@ -64,12 +66,12 @@ func TestIngressAffinityCookieConfig(t *testing.T) { ing := buildIngress() data := map[string]string{} - data[annotationAffinityType] = "cookie" - data[annotationAffinityCookieHash] = "sha123" - data[annotationAffinityCookieName] = "INGRESSCOOKIE" + data[fmt.Sprintf("nginx/%v", annotationAffinityType)] = "cookie" + data[fmt.Sprintf("nginx/%v", annotationAffinityCookieHash)] = "sha123" + data[fmt.Sprintf("nginx/%v", annotationAffinityCookieName)] = "INGRESSCOOKIE" ing.SetAnnotations(data) - affin, _ := NewParser().Parse(ing) + affin, _ := NewParser(&resolver.Mock{}).Parse(ing) nginxAffinity, ok := affin.(*Config) if !ok { t.Errorf("expected a Config type") diff --git a/internal/ingress/annotations/snippet/main.go b/internal/ingress/annotations/snippet/main.go index 954c13f6d..b93dbf63b 100644 --- a/internal/ingress/annotations/snippet/main.go +++ b/internal/ingress/annotations/snippet/main.go @@ -20,23 +20,21 @@ import ( extensions "k8s.io/api/extensions/v1beta1" "k8s.io/ingress-nginx/internal/ingress/annotations/parser" -) - -const ( - annotation = "ingress.kubernetes.io/configuration-snippet" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) type snippet struct { + r resolver.Resolver } // NewParser creates a new CORS annotation parser -func NewParser() parser.IngressAnnotation { - return snippet{} +func NewParser(r resolver.Resolver) parser.IngressAnnotation { + return snippet{r} } // Parse parses the annotations contained in the ingress rule // used to indicate if the location/s contains a fragment of // configuration to be included inside the paths of the rules func (a snippet) Parse(ing *extensions.Ingress) (interface{}, error) { - return parser.GetStringAnnotation(annotation, ing) + return parser.GetStringAnnotation("configuration-snippet", ing, a.r) } diff --git a/internal/ingress/annotations/snippet/main_test.go b/internal/ingress/annotations/snippet/main_test.go index b92abfc45..30943379f 100644 --- a/internal/ingress/annotations/snippet/main_test.go +++ b/internal/ingress/annotations/snippet/main_test.go @@ -22,10 +22,13 @@ import ( api "k8s.io/api/core/v1" extensions "k8s.io/api/extensions/v1beta1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) func TestParse(t *testing.T) { - ap := NewParser() + annotation := "nginx/configuration-snippet" + + ap := NewParser(&resolver.Mock{}) if ap == nil { t.Fatalf("expected a parser.IngressAnnotation but returned nil") } diff --git a/internal/ingress/annotations/sslpassthrough/main.go b/internal/ingress/annotations/sslpassthrough/main.go index c3752f8bd..82b69a170 100644 --- a/internal/ingress/annotations/sslpassthrough/main.go +++ b/internal/ingress/annotations/sslpassthrough/main.go @@ -21,18 +21,16 @@ import ( "k8s.io/ingress-nginx/internal/ingress/annotations/parser" ing_errors "k8s.io/ingress-nginx/internal/ingress/errors" -) - -const ( - passthrough = "ingress.kubernetes.io/ssl-passthrough" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) type sslpt struct { + r resolver.Resolver } // NewParser creates a new SSL passthrough annotation parser -func NewParser() parser.IngressAnnotation { - return sslpt{} +func NewParser(r resolver.Resolver) parser.IngressAnnotation { + return sslpt{r} } // ParseAnnotations parses the annotations contained in the ingress @@ -42,5 +40,5 @@ func (a sslpt) Parse(ing *extensions.Ingress) (interface{}, error) { return false, ing_errors.ErrMissingAnnotations } - return parser.GetBoolAnnotation(passthrough, ing) + return parser.GetBoolAnnotation("ssl-passthrough", ing, a.r) } diff --git a/internal/ingress/annotations/sslpassthrough/main_test.go b/internal/ingress/annotations/sslpassthrough/main_test.go index bf3e083d8..0320c007e 100644 --- a/internal/ingress/annotations/sslpassthrough/main_test.go +++ b/internal/ingress/annotations/sslpassthrough/main_test.go @@ -22,6 +22,7 @@ import ( api "k8s.io/api/core/v1" extensions "k8s.io/api/extensions/v1beta1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/ingress-nginx/internal/ingress/resolver" "k8s.io/apimachinery/pkg/util/intstr" ) @@ -44,16 +45,16 @@ func buildIngress() *extensions.Ingress { func TestParseAnnotations(t *testing.T) { ing := buildIngress() - _, err := NewParser().Parse(ing) + _, err := NewParser(&resolver.Mock{}).Parse(ing) if err == nil { t.Errorf("unexpected error: %v", err) } data := map[string]string{} - data[passthrough] = "true" + data["nginx/ssl-passthrough"] = "true" ing.SetAnnotations(data) // test ingress using the annotation without a TLS section - _, err = NewParser().Parse(ing) + _, err = NewParser(&resolver.Mock{}).Parse(ing) if err != nil { t.Errorf("unexpected error parsing ingress with sslpassthrough") } @@ -64,7 +65,7 @@ func TestParseAnnotations(t *testing.T) { Hosts: []string{"foo.bar.com"}, }, } - i, err := NewParser().Parse(ing) + i, err := NewParser(&resolver.Mock{}).Parse(ing) if err != nil { t.Errorf("expected error parsing ingress with sslpassthrough") } diff --git a/internal/ingress/annotations/upstreamhashby/main.go b/internal/ingress/annotations/upstreamhashby/main.go index c29f5cbbb..b543070a0 100644 --- a/internal/ingress/annotations/upstreamhashby/main.go +++ b/internal/ingress/annotations/upstreamhashby/main.go @@ -20,23 +20,21 @@ import ( extensions "k8s.io/api/extensions/v1beta1" "k8s.io/ingress-nginx/internal/ingress/annotations/parser" -) - -const ( - annotation = "ingress.kubernetes.io/upstream-hash-by" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) type upstreamhashby struct { + r resolver.Resolver } // NewParser creates a new CORS annotation parser -func NewParser() parser.IngressAnnotation { - return upstreamhashby{} +func NewParser(r resolver.Resolver) parser.IngressAnnotation { + return upstreamhashby{r} } // Parse parses the annotations contained in the ingress rule // used to indicate if the location/s contains a fragment of // configuration to be included inside the paths of the rules func (a upstreamhashby) Parse(ing *extensions.Ingress) (interface{}, error) { - return parser.GetStringAnnotation(annotation, ing) + return parser.GetStringAnnotation("upstream-hash-by", ing, a.r) } diff --git a/internal/ingress/annotations/upstreamhashby/main_test.go b/internal/ingress/annotations/upstreamhashby/main_test.go index ad5afafc8..5507a8c7f 100644 --- a/internal/ingress/annotations/upstreamhashby/main_test.go +++ b/internal/ingress/annotations/upstreamhashby/main_test.go @@ -22,10 +22,13 @@ import ( api "k8s.io/api/core/v1" extensions "k8s.io/api/extensions/v1beta1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) func TestParse(t *testing.T) { - ap := NewParser() + annotation := "nginx/upstream-hash-by" + + ap := NewParser(&resolver.Mock{}) if ap == nil { t.Fatalf("expected a parser.IngressAnnotation but returned nil") } diff --git a/internal/ingress/annotations/upstreamvhost/main.go b/internal/ingress/annotations/upstreamvhost/main.go index c702d621a..02c1e96cf 100644 --- a/internal/ingress/annotations/upstreamvhost/main.go +++ b/internal/ingress/annotations/upstreamvhost/main.go @@ -20,23 +20,21 @@ import ( extensions "k8s.io/api/extensions/v1beta1" "k8s.io/ingress-nginx/internal/ingress/annotations/parser" -) - -const ( - annotation = "ingress.kubernetes.io/upstream-vhost" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) type upstreamVhost struct { + r resolver.Resolver } // NewParser creates a new upstream VHost annotation parser -func NewParser() parser.IngressAnnotation { - return upstreamVhost{} +func NewParser(r resolver.Resolver) parser.IngressAnnotation { + return upstreamVhost{r} } // Parse parses the annotations contained in the ingress rule // used to indicate if the location/s contains a fragment of // configuration to be included inside the paths of the rules func (a upstreamVhost) Parse(ing *extensions.Ingress) (interface{}, error) { - return parser.GetStringAnnotation(annotation, ing) + return parser.GetStringAnnotation("upstream-vhost", ing, a.r) } diff --git a/internal/ingress/annotations/vtsfilterkey/main.go b/internal/ingress/annotations/vtsfilterkey/main.go index 809187fae..41288e291 100644 --- a/internal/ingress/annotations/vtsfilterkey/main.go +++ b/internal/ingress/annotations/vtsfilterkey/main.go @@ -20,23 +20,21 @@ import ( extensions "k8s.io/api/extensions/v1beta1" "k8s.io/ingress-nginx/internal/ingress/annotations/parser" -) - -const ( - annotation = "ingress.kubernetes.io/vts-filter-key" + "k8s.io/ingress-nginx/internal/ingress/resolver" ) type vtsFilterKey struct { + r resolver.Resolver } // NewParser creates a new vts filter key annotation parser -func NewParser() parser.IngressAnnotation { - return vtsFilterKey{} +func NewParser(r resolver.Resolver) parser.IngressAnnotation { + return vtsFilterKey{r} } // Parse parses the annotations contained in the ingress rule // used to indicate if the location/s contains a fragment of // configuration to be included inside the paths of the rules func (a vtsFilterKey) Parse(ing *extensions.Ingress) (interface{}, error) { - return parser.GetStringAnnotation(annotation, ing) + return parser.GetStringAnnotation("vts-filter-key", ing, a.r) } diff --git a/internal/ingress/controller/backend_ssl.go b/internal/ingress/controller/backend_ssl.go index a1e3b4f1e..272b24c37 100644 --- a/internal/ingress/controller/backend_ssl.go +++ b/internal/ingress/controller/backend_ssl.go @@ -92,7 +92,7 @@ func (ic *NGINXController) getPemCertificate(secretName string) (*ingress.SSLCer } // If 'ca.crt' is also present, it will allow this secret to be used in the - // 'ingress.kubernetes.io/auth-tls-secret' annotation + // 'nginx.ingress.kubernetes.io/auth-tls-secret' annotation s, err = ssl.AddOrUpdateCertAndKey(nsSecName, cert, key, ca) if err != nil { return nil, fmt.Errorf("unexpected error creating pem file: %v", err) @@ -145,7 +145,7 @@ func (ic *NGINXController) checkMissingSecrets() { } } - key, _ := parser.GetStringAnnotation("ingress.kubernetes.io/auth-tls-secret", ing) + key, _ := parser.GetStringAnnotation("auth-tls-secret", ing, ic) if key == "" { continue } diff --git a/internal/ingress/controller/controller.go b/internal/ingress/controller/controller.go index 2861f9f91..b22007f56 100644 --- a/internal/ingress/controller/controller.go +++ b/internal/ingress/controller/controller.go @@ -66,6 +66,8 @@ func init() { // Configuration contains all the settings required by an Ingress controller type Configuration struct { + AnnotationsPrefix string + APIServerHost string KubeConfigFile string Client clientset.Interface @@ -133,6 +135,11 @@ func (n NGINXController) GetService(name string) (*apiv1.Service, error) { return n.listers.Service.GetByName(name) } +// GetAnnotationWithPrefix returns the prefix of ingress annotations +func (n NGINXController) GetAnnotationWithPrefix(suffix string) string { + return fmt.Sprintf("%v/%v", n.cfg.AnnotationsPrefix, suffix) +} + // sync collects all the pieces required to assemble the configuration file and // then sends the content to the backend (OnUpdate) receiving the populated // template as response reloading the backend if is required. @@ -1156,7 +1163,7 @@ func (n *NGINXController) readSecrets(ing *extensions.Ingress) { n.syncSecret(key) } - key, _ := parser.GetStringAnnotation("ingress.kubernetes.io/auth-tls-secret", ing) + key, _ := parser.GetStringAnnotation("auth-tls-secret", ing, n) if key == "" { return } diff --git a/internal/ingress/controller/listers.go b/internal/ingress/controller/listers.go index bdfd5931b..8149891b4 100644 --- a/internal/ingress/controller/listers.go +++ b/internal/ingress/controller/listers.go @@ -66,7 +66,7 @@ func (n *NGINXController) createListers(stopCh chan struct{}) (*ingress.StoreLis AddFunc: func(obj interface{}) { addIng := obj.(*extensions.Ingress) if !class.IsValid(addIng, n.cfg.IngressClass, defIngressClass) { - a, _ := parser.GetStringAnnotation(class.IngressKey, addIng) + a, _ := parser.GetStringAnnotation(class.IngressKey, addIng, n) glog.Infof("ignoring add for ingress %v based on annotation %v with value %v", addIng.Name, class.IngressKey, a) return } diff --git a/internal/ingress/controller/nginx.go b/internal/ingress/controller/nginx.go index 7417e278b..b88002fec 100644 --- a/internal/ingress/controller/nginx.go +++ b/internal/ingress/controller/nginx.go @@ -246,7 +246,7 @@ func (n *NGINXController) Start() { ing := obj.(*extensions.Ingress) if !class.IsValid(ing, n.cfg.IngressClass, n.cfg.DefaultIngressClass) { - a, _ := parser.GetStringAnnotation(class.IngressKey, ing) + a, _ := parser.GetStringAnnotation(class.IngressKey, ing, n) glog.Infof("ignoring add for ingress %v based on annotation %v with value %v", ing.Name, class.IngressKey, a) continue } diff --git a/internal/ingress/controller/template/template.go b/internal/ingress/controller/template/template.go index 078a05a0e..b5cea55e6 100644 --- a/internal/ingress/controller/template/template.go +++ b/internal/ingress/controller/template/template.go @@ -193,7 +193,7 @@ func buildResolvers(input interface{}) string { } // buildLocation produces the location string, if the ingress has redirects -// (specified through the ingress.kubernetes.io/rewrite-to annotation) +// (specified through the nginx.ingress.kubernetes.io/rewrite-to annotation) func buildLocation(input interface{}) string { location, ok := input.(*ingress.Location) if !ok { @@ -268,8 +268,8 @@ func buildLogFormatUpstream(input interface{}) string { } // 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 +// (specified through the nginx.ingress.kubernetes.io/rewrite-to annotation) +// If the annotation nginx.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(host string, b interface{}, loc interface{}) string { backends, ok := b.([]*ingress.Backend) diff --git a/internal/ingress/resolver/main.go b/internal/ingress/resolver/main.go index 61f91518e..9fd43828f 100644 --- a/internal/ingress/resolver/main.go +++ b/internal/ingress/resolver/main.go @@ -22,29 +22,24 @@ import ( "k8s.io/ingress-nginx/internal/ingress/defaults" ) -// DefaultBackend has a method that returns the backend -// that must be used as default -type DefaultBackend interface { +// Resolver is an interface that knows how to extract information from a controller +type Resolver interface { + // GetDefaultBackend returns the backend that must be used as default GetDefaultBackend() defaults.Backend -} -// Secret has a method that searches for secrets contenating -// the namespace and name using a the character / -type Secret interface { + // GetSecret searches for secrets contenating the namespace and name using a the character / GetSecret(string) (*apiv1.Secret, error) -} -// AuthCertificate resolves a given secret name into an SSL certificate. -// The secret must contain 3 keys named: -// ca.crt: contains the certificate chain used for authentication -type AuthCertificate interface { + // GetAuthCertificate resolves a given secret name into an SSL certificate. + // The secret must contain 3 keys named: + // ca.crt: contains the certificate chain used for authentication GetAuthCertificate(string) (*AuthSSLCert, error) -} -// Service has a method that searches for services contenating -// the namespace and name using a the character / -type Service interface { + // GetService searches for services contenating the namespace and name using a the character / GetService(string) (*apiv1.Service, error) + + // GetAnnotationWithPrefix returns the prefix of the Ingress annotations + GetAnnotationWithPrefix(suffix string) string } // AuthSSLCert contains the necessary information to do certificate based diff --git a/internal/ingress/resolver/mock.go b/internal/ingress/resolver/mock.go new file mode 100644 index 000000000..7a11972b9 --- /dev/null +++ b/internal/ingress/resolver/mock.go @@ -0,0 +1,56 @@ +/* +Copyright 2017 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 resolver + +import ( + "fmt" + + apiv1 "k8s.io/api/core/v1" + + "k8s.io/ingress-nginx/internal/ingress/defaults" +) + +// Mock implements the Resolver interface +type Mock struct { +} + +// GetDefaultBackend returns the backend that must be used as default +func (m Mock) GetDefaultBackend() defaults.Backend { + return defaults.Backend{} +} + +// GetSecret searches for secrets contenating the namespace and name using a the character / +func (m Mock) GetSecret(string) (*apiv1.Secret, error) { + return nil, nil +} + +// GetAuthCertificate resolves a given secret name into an SSL certificate. +// The secret must contain 3 keys named: +// ca.crt: contains the certificate chain used for authentication +func (m Mock) GetAuthCertificate(string) (*AuthSSLCert, error) { + return nil, nil +} + +// GetService searches for services contenating the namespace and name using a the character / +func (m Mock) GetService(string) (*apiv1.Service, error) { + return nil, nil +} + +// GetAnnotationWithPrefix returns the prefix of the Ingress annotations +func (m Mock) GetAnnotationWithPrefix(name string) string { + return fmt.Sprintf("nginx/%v", name) +}