Add prefix nginx to annotations

This commit is contained in:
Manuel de Brito Fontes 2017-11-08 17:58:57 -03:00
parent 97577c07a5
commit 8f1ff15a6e
54 changed files with 445 additions and 441 deletions

View file

@ -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,

View file

@ -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)
}

View file

@ -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")
}

View file

@ -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),
},
}

View file

@ -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
}

View file

@ -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)

View file

@ -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)

View file

@ -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, ",")

View file

@ -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())

View file

@ -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 = ""
}

View file

@ -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

View file

@ -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)
}

View file

@ -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")
}

View file

@ -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
}

View file

@ -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")

View file

@ -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)
}

View file

@ -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
}

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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)
}

View file

@ -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)

View file

@ -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

View file

@ -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")
}

View file

@ -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
}

View file

@ -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)

View file

@ -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 {

View file

@ -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)

View file

@ -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
}

View file

@ -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,

View file

@ -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")

View file

@ -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")
}

View file

@ -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{

View file

@ -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)
}

View file

@ -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")
}

View file

@ -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)
}

View file

@ -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")

View file

@ -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)

View file

@ -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")

View file

@ -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)
}

View file

@ -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")
}

View file

@ -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)
}

View file

@ -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")
}

View file

@ -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)
}

View file

@ -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")
}

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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)

View file

@ -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

View file

@ -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)
}