Refactor annotations

This commit is contained in:
Manuel de Brito Fontes 2017-11-07 13:36:51 -03:00
parent f215828b1b
commit fb33c58d18
33 changed files with 370 additions and 401 deletions

View file

@ -0,0 +1,170 @@
/*
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 annotations
import (
"github.com/golang/glog"
"github.com/imdario/mergo"
extensions "k8s.io/api/extensions/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/ingress-nginx/pkg/ingress/annotations/alias"
"k8s.io/ingress-nginx/pkg/ingress/annotations/auth"
"k8s.io/ingress-nginx/pkg/ingress/annotations/authreq"
"k8s.io/ingress-nginx/pkg/ingress/annotations/authtls"
"k8s.io/ingress-nginx/pkg/ingress/annotations/clientbodybuffersize"
"k8s.io/ingress-nginx/pkg/ingress/annotations/cors"
"k8s.io/ingress-nginx/pkg/ingress/annotations/defaultbackend"
"k8s.io/ingress-nginx/pkg/ingress/annotations/healthcheck"
"k8s.io/ingress-nginx/pkg/ingress/annotations/ipwhitelist"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
"k8s.io/ingress-nginx/pkg/ingress/annotations/portinredirect"
"k8s.io/ingress-nginx/pkg/ingress/annotations/proxy"
"k8s.io/ingress-nginx/pkg/ingress/annotations/ratelimit"
"k8s.io/ingress-nginx/pkg/ingress/annotations/redirect"
"k8s.io/ingress-nginx/pkg/ingress/annotations/rewrite"
"k8s.io/ingress-nginx/pkg/ingress/annotations/secureupstream"
"k8s.io/ingress-nginx/pkg/ingress/annotations/serversnippet"
"k8s.io/ingress-nginx/pkg/ingress/annotations/serviceupstream"
"k8s.io/ingress-nginx/pkg/ingress/annotations/sessionaffinity"
"k8s.io/ingress-nginx/pkg/ingress/annotations/snippet"
"k8s.io/ingress-nginx/pkg/ingress/annotations/sslpassthrough"
"k8s.io/ingress-nginx/pkg/ingress/annotations/upstreamhashby"
"k8s.io/ingress-nginx/pkg/ingress/annotations/upstreamvhost"
"k8s.io/ingress-nginx/pkg/ingress/annotations/vtsfilterkey"
"k8s.io/ingress-nginx/pkg/ingress/errors"
"k8s.io/ingress-nginx/pkg/ingress/resolver"
)
// 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
Alias string
BasicDigestAuth auth.Config
CertificateAuth authtls.Config
ClientBodyBufferSize string
ConfigurationSnippet string
CorsConfig cors.Config
DefaultBackend string
ExternalAuth authreq.Config
HealthCheck healthcheck.Config
Proxy proxy.Config
RateLimit ratelimit.Config
Redirect redirect.Config
Rewrite rewrite.Config
SecureUpstream secureupstream.Config
ServerSnippet string
ServiceUpstream bool
SessionAffinity sessionaffinity.Config
SSLPassthrough bool
UsePortInRedirects bool
UpstreamHashBy string
UpstreamVhost string
VtsFilterKey string
Whitelist ipwhitelist.SourceRange
}
// Extractor defines the annotation parsers to be used in the extraction of annotations
type Extractor struct {
secretResolver resolver.Secret
annotations map[string]parser.IngressAnnotation
}
// NewAnnotationExtractor creates a new annotations extractor
func NewAnnotationExtractor(cfg config) Extractor {
return Extractor{
cfg,
map[string]parser.IngressAnnotation{
"Alias": alias.NewParser(),
"BasicDigestAuth": auth.NewParser(auth.AuthDirectory, cfg),
"CertificateAuth": authtls.NewParser(cfg),
"ClientBodyBufferSize": clientbodybuffersize.NewParser(),
"ConfigurationSnippet": snippet.NewParser(),
"CorsConfig": cors.NewParser(),
"DefaultBackend": defaultbackend.NewParser(cfg),
"ExternalAuth": authreq.NewParser(),
"HealthCheck": healthcheck.NewParser(cfg),
"Proxy": proxy.NewParser(cfg),
"RateLimit": ratelimit.NewParser(cfg),
"Redirect": redirect.NewParser(),
"Rewrite": rewrite.NewParser(cfg),
"SecureUpstream": secureupstream.NewParser(cfg),
"ServerSnippet": serversnippet.NewParser(),
"ServiceUpstream": serviceupstream.NewParser(),
"SessionAffinity": sessionaffinity.NewParser(),
"SSLPassthrough": sslpassthrough.NewParser(),
"UsePortInRedirects": portinredirect.NewParser(cfg),
"UpstreamHashBy": upstreamhashby.NewParser(),
"UpstreamVhost": upstreamvhost.NewParser(),
"VtsFilterKey": vtsfilterkey.NewParser(),
"Whitelist": ipwhitelist.NewParser(cfg),
},
}
}
// Extract extracts the annotations from an Ingress
func (e Extractor) Extract(ing *extensions.Ingress) *Ingress {
pia := &Ingress{
ObjectMeta: ing.ObjectMeta,
}
data := make(map[string]interface{})
for name, annotationParser := range e.annotations {
val, err := annotationParser.Parse(ing)
glog.V(5).Infof("annotation %v in Ingress %v/%v: %v", name, ing.GetNamespace(), ing.GetName(), val)
if err != nil {
if errors.IsMissingAnnotations(err) {
continue
}
if !errors.IsLocationDenied(err) {
continue
}
_, alreadyDenied := data[DeniedKeyName]
if !alreadyDenied {
data[DeniedKeyName] = err
glog.Errorf("error reading %v annotation in Ingress %v/%v: %v", name, ing.GetNamespace(), ing.GetName(), err)
continue
}
glog.V(5).Infof("error reading %v annotation in Ingress %v/%v: %v", name, ing.GetNamespace(), ing.GetName(), err)
}
if val != nil {
data[name] = val
}
}
err := mergo.Map(pia, data)
if err != nil {
glog.Errorf("unexpected error merging extracted annotations: %v", err)
}
return pia
}

View file

@ -0,0 +1,385 @@
/*
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 annotations
import (
"testing"
apiv1 "k8s.io/api/core/v1"
extensions "k8s.io/api/extensions/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/ingress-nginx/pkg/ingress/defaults"
"k8s.io/ingress-nginx/pkg/ingress/resolver"
)
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"
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"
)
type mockCfg struct {
MockSecrets map[string]*apiv1.Secret
MockServices map[string]*apiv1.Service
}
func (m mockCfg) GetDefaultBackend() defaults.Backend {
return defaults.Backend{}
}
func (m mockCfg) GetSecret(name string) (*apiv1.Secret, error) {
return m.MockSecrets[name], nil
}
func (m mockCfg) GetService(name string) (*apiv1.Service, error) {
return m.MockServices[name], nil
}
func (m mockCfg) GetAuthCertificate(name string) (*resolver.AuthSSLCert, error) {
if secret, _ := m.GetSecret(name); secret != nil {
return &resolver.AuthSSLCert{
Secret: name,
CAFileName: "/opt/ca.pem",
PemSHA: "123",
}, nil
}
return nil, nil
}
func buildIngress() *extensions.Ingress {
defaultBackend := extensions.IngressBackend{
ServiceName: "default-backend",
ServicePort: intstr.FromInt(80),
}
return &extensions.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
Namespace: apiv1.NamespaceDefault,
},
Spec: extensions.IngressSpec{
Backend: &extensions.IngressBackend{
ServiceName: "default-backend",
ServicePort: intstr.FromInt(80),
},
Rules: []extensions.IngressRule{
{
Host: "foo.bar.com",
IngressRuleValue: extensions.IngressRuleValue{
HTTP: &extensions.HTTPIngressRuleValue{
Paths: []extensions.HTTPIngressPath{
{
Path: "/foo",
Backend: defaultBackend,
},
},
},
},
},
},
},
}
}
func TestSecureUpstream(t *testing.T) {
ec := NewAnnotationExtractor(mockCfg{})
ing := buildIngress()
fooAnns := []struct {
annotations map[string]string
er bool
}{
{map[string]string{annotationSecureUpstream: "true"}, true},
{map[string]string{annotationSecureUpstream: "false"}, false},
{map[string]string{annotationSecureUpstream + "_no": "true"}, false},
{map[string]string{}, false},
{nil, false},
}
for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations)
r := ec.Extract(ing).SecureUpstream
if r.Secure != foo.er {
t.Errorf("Returned %v but expected %v", r, foo.er)
}
}
}
func TestSecureVerifyCACert(t *testing.T) {
ec := NewAnnotationExtractor(mockCfg{
MockSecrets: map[string]*apiv1.Secret{
"default/secure-verify-ca": {
ObjectMeta: metav1.ObjectMeta{
Name: "secure-verify-ca",
},
},
},
})
anns := []struct {
it int
annotations map[string]string
exists bool
}{
{1, map[string]string{annotationSecureUpstream: "true", annotationSecureVerifyCACert: "not"}, false},
{2, map[string]string{annotationSecureUpstream: "false", annotationSecureVerifyCACert: "secure-verify-ca"}, false},
{3, map[string]string{annotationSecureUpstream: "true", annotationSecureVerifyCACert: "secure-verify-ca"}, true},
{4, map[string]string{annotationSecureUpstream: "true", annotationSecureVerifyCACert + "_not": "secure-verify-ca"}, false},
{5, map[string]string{annotationSecureUpstream: "true"}, false},
{6, map[string]string{}, false},
{7, nil, false},
}
for _, ann := range anns {
ing := buildIngress()
ing.SetAnnotations(ann.annotations)
res := ec.Extract(ing).SecureUpstream
if (res != nil && res.CACert.CAFileName != "") != ann.exists {
t.Errorf("Expected exists was %v on iteration %v", ann.exists, ann.it)
}
}
}
func TestHealthCheck(t *testing.T) {
ec := NewAnnotationExtractor(mockCfg{})
ing := buildIngress()
fooAnns := []struct {
annotations map[string]string
eumf int
euft int
}{
{map[string]string{annotationUpsMaxFails: "3", annotationUpsFailTimeout: "10"}, 3, 10},
{map[string]string{annotationUpsMaxFails: "3"}, 3, 0},
{map[string]string{annotationUpsFailTimeout: "10"}, 0, 10},
{map[string]string{}, 0, 0},
{nil, 0, 0},
}
for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations)
r := ec.Extract(ing).HealthCheck
if r == nil {
t.Errorf("Returned nil but expected a healthcheck.Upstream")
continue
}
if r.FailTimeout != foo.euft {
t.Errorf("Returned %d but expected %d for FailTimeout", r.FailTimeout, foo.euft)
}
if r.MaxFails != foo.eumf {
t.Errorf("Returned %d but expected %d for MaxFails", r.MaxFails, foo.eumf)
}
}
}
func TestSSLPassthrough(t *testing.T) {
ec := NewAnnotationExtractor(mockCfg{})
ing := buildIngress()
fooAnns := []struct {
annotations map[string]string
er bool
}{
{map[string]string{annotationPassthrough: "true"}, true},
{map[string]string{annotationPassthrough: "false"}, false},
{map[string]string{annotationPassthrough + "_no": "true"}, false},
{map[string]string{}, false},
{nil, false},
}
for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations)
r := ec.Extract(ing).SSLPassthrough
if r != foo.er {
t.Errorf("Returned %v but expected %v", r, foo.er)
}
}
}
func TestUpstreamHashBy(t *testing.T) {
ec := NewAnnotationExtractor(mockCfg{})
ing := buildIngress()
fooAnns := []struct {
annotations map[string]string
er string
}{
{map[string]string{annotationUpstreamHashBy: "$request_uri"}, "$request_uri"},
{map[string]string{annotationUpstreamHashBy: "false"}, "false"},
{map[string]string{annotationUpstreamHashBy + "_no": "true"}, ""},
{map[string]string{}, ""},
{nil, ""},
}
for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations)
r := ec.Extract(ing).UpstreamHashBy
if r != foo.er {
t.Errorf("Returned %v but expected %v", r, foo.er)
}
}
}
func TestAffinitySession(t *testing.T) {
ec := NewAnnotationExtractor(mockCfg{})
ing := buildIngress()
fooAnns := []struct {
annotations map[string]string
affinitytype string
hash string
name string
}{
{map[string]string{annotationAffinityType: "cookie", annotationAffinityCookieHash: "md5", annotationAffinityCookieName: "route"}, "cookie", "md5", "route"},
{map[string]string{annotationAffinityType: "cookie", annotationAffinityCookieHash: "xpto", annotationAffinityCookieName: "route1"}, "cookie", "md5", "route1"},
{map[string]string{annotationAffinityType: "cookie", annotationAffinityCookieHash: "", annotationAffinityCookieName: ""}, "cookie", "md5", "INGRESSCOOKIE"},
{map[string]string{}, "", "", ""},
{nil, "", "", ""},
}
for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations)
r := ec.Extract(ing).SessionAffinity
t.Logf("Testing pass %v %v %v", foo.affinitytype, foo.hash, foo.name)
if r == nil {
t.Errorf("Returned nil but expected a SessionAffinity.AffinityConfig")
continue
}
if r.Cookie.Hash != foo.hash {
t.Errorf("Returned %v but expected %v for Hash", r.Cookie.Hash, foo.hash)
}
if r.Cookie.Name != foo.name {
t.Errorf("Returned %v but expected %v for Name", r.Cookie.Name, foo.name)
}
}
}
func TestCors(t *testing.T) {
ec := NewAnnotationExtractor(mockCfg{})
ing := buildIngress()
fooAnns := []struct {
annotations map[string]string
corsenabled bool
methods string
headers string
origin string
credentials bool
}{
{map[string]string{annotationCorsEnabled: "true"}, true, defaultCorsMethods, defaultCorsHeaders, "*", true},
{map[string]string{annotationCorsEnabled: "true", annotationCorsAllowMethods: "POST, GET, OPTIONS", annotationCorsAllowHeaders: "$nginx_version", annotationCorsAllowCredentials: "false"}, true, "POST, GET, OPTIONS", defaultCorsHeaders, "*", false},
{map[string]string{annotationCorsEnabled: "true", annotationCorsAllowCredentials: "false"}, true, defaultCorsMethods, defaultCorsHeaders, "*", false},
{map[string]string{}, false, defaultCorsMethods, defaultCorsHeaders, "*", true},
{nil, false, defaultCorsMethods, defaultCorsHeaders, "*", true},
}
for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations)
r := ec.Extract(ing).CorsConfig
t.Logf("Testing pass %v %v %v %v %v", foo.corsenabled, foo.methods, foo.headers, foo.origin, foo.credentials)
if r == nil {
t.Errorf("Returned nil but expected a Cors.CorsConfig")
continue
}
if r.CorsEnabled != foo.corsenabled {
t.Errorf("Returned %v but expected %v for Cors Enabled", r.CorsEnabled, foo.corsenabled)
}
if r.CorsAllowHeaders != foo.headers {
t.Errorf("Returned %v but expected %v for Cors Headers", r.CorsAllowHeaders, foo.headers)
}
if r.CorsAllowMethods != foo.methods {
t.Errorf("Returned %v but expected %v for Cors Methods", r.CorsAllowMethods, foo.methods)
}
if r.CorsAllowOrigin != foo.origin {
t.Errorf("Returned %v but expected %v for Cors Methods", r.CorsAllowOrigin, foo.origin)
}
if r.CorsAllowCredentials != foo.credentials {
t.Errorf("Returned %v but expected %v for Cors Methods", r.CorsAllowCredentials, foo.credentials)
}
}
}
/*
func TestMergeLocationAnnotations(t *testing.T) {
// initial parameters
keys := []string{"BasicDigestAuth", "CorsConfig", "ExternalAuth", "RateLimit", "Redirect", "Rewrite", "Whitelist", "Proxy", "UsePortInRedirects"}
loc := ingress.Location{}
annotations := &Ingress{
BasicDigestAuth: &auth.Config{},
CorsConfig: &cors.Config{},
ExternalAuth: &authreq.Config{},
RateLimit: &ratelimit.Config{},
Redirect: &redirect.Config{},
Rewrite: &rewrite.Config{},
Whitelist: &ipwhitelist.SourceRange{},
Proxy: &proxy.Config{},
UsePortInRedirects: true,
}
// create test table
type fooMergeLocationAnnotationsStruct struct {
fName string
er interface{}
}
fooTests := []fooMergeLocationAnnotationsStruct{}
for name, value := range keys {
fva := fooMergeLocationAnnotationsStruct{name, value}
fooTests = append(fooTests, fva)
}
// execute test
MergeWithLocation(&loc, annotations)
// check result
for _, foo := range fooTests {
fv := reflect.ValueOf(loc).FieldByName(foo.fName).Interface()
if !reflect.DeepEqual(fv, foo.er) {
t.Errorf("Returned %v but expected %v for the field %s", fv, foo.er, foo.fName)
}
}
if _, ok := annotations[DeniedKeyName]; ok {
t.Errorf("%s should be removed after mergeLocationAnnotations", DeniedKeyName)
}
}
*/

View file

@ -46,8 +46,8 @@ var (
AuthDirectory = "/etc/ingress-controller/auth"
)
// BasicDigest returns authentication configuration for an Ingress rule
type BasicDigest struct {
// Config returns authentication configuration for an Ingress rule
type Config struct {
Type string `json:"type"`
Realm string `json:"realm"`
File string `json:"file"`
@ -55,8 +55,8 @@ type BasicDigest struct {
FileSHA string `json:"fileSha"`
}
// Equal tests for equality between two BasicDigest types
func (bd1 *BasicDigest) Equal(bd2 *BasicDigest) bool {
// Equal tests for equality between two Config types
func (bd1 *Config) Equal(bd2 *Config) bool {
if bd1 == bd2 {
return true
}
@ -140,7 +140,7 @@ func (a auth) Parse(ing *extensions.Ingress) (interface{}, error) {
return nil, err
}
return &BasicDigest{
return &Config{
Type: at,
Realm: realm,
File: passFile,

View file

@ -109,7 +109,7 @@ func TestIngressAuth(t *testing.T) {
if err != nil {
t.Errorf("Uxpected error with ingress: %v", err)
}
auth, ok := i.(*BasicDigest)
auth, ok := i.(*Config)
if !ok {
t.Errorf("expected a BasicDigest type")
}

View file

@ -36,7 +36,7 @@ const (
)
// External returns external authentication configuration for an Ingress rule
type External struct {
type Config struct {
URL string `json:"url"`
// Host contains the hostname defined in the URL
Host string `json:"host"`
@ -45,8 +45,8 @@ type External struct {
ResponseHeaders []string `json:"responseHeaders,omitEmpty"`
}
// Equal tests for equality between two External types
func (e1 *External) Equal(e2 *External) bool {
// Equal tests for equality between two Config types
func (e1 *Config) Equal(e2 *Config) bool {
if e1 == e2 {
return true
}
@ -116,7 +116,7 @@ func NewParser() parser.IngressAnnotation {
}
// ParseAnnotations parses the annotations contained in the ingress
// rule used to use an external URL as source for authentication
// 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)
if err != nil {
@ -165,7 +165,7 @@ func (a authReq) Parse(ing *extensions.Ingress) (interface{}, error) {
}
}
return &External{
return &Config{
URL: str,
Host: ur.Hostname(),
SigninURL: signin,

View file

@ -97,7 +97,7 @@ func TestAnnotations(t *testing.T) {
}
continue
}
u, ok := i.(*External)
u, ok := i.(*Config)
if !ok {
t.Errorf("%v: expected an External type", test.title)
}
@ -149,7 +149,7 @@ func TestHeaderAnnotations(t *testing.T) {
}
t.Log(i)
u, ok := i.(*External)
u, ok := i.(*Config)
if !ok {
t.Errorf("%v: expected an External type", test.title)
continue

View file

@ -20,11 +20,12 @@ import (
"github.com/pkg/errors"
extensions "k8s.io/api/extensions/v1beta1"
"regexp"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
ing_errors "k8s.io/ingress-nginx/pkg/ingress/errors"
"k8s.io/ingress-nginx/pkg/ingress/resolver"
"k8s.io/ingress-nginx/pkg/k8s"
"regexp"
)
const (
@ -41,17 +42,17 @@ var (
authVerifyClientRegex = regexp.MustCompile(`on|off|optional|optional_no_ca`)
)
// AuthSSLConfig contains the AuthSSLCert used for muthual autentication
// Config contains the AuthSSLCert used for muthual autentication
// and the configured ValidationDepth
type AuthSSLConfig struct {
type Config struct {
resolver.AuthSSLCert
VerifyClient string `json:"verify_client"`
ValidationDepth int `json:"validationDepth"`
ErrorPage string `json:"errorPage"`
}
// Equal tests for equality between two AuthSSLConfig types
func (assl1 *AuthSSLConfig) Equal(assl2 *AuthSSLConfig) bool {
// Equal tests for equality between two Config types
func (assl1 *Config) Equal(assl2 *Config) bool {
if assl1 == assl2 {
return true
}
@ -88,16 +89,16 @@ func (a authTLS) Parse(ing *extensions.Ingress) (interface{}, error) {
tlsauthsecret, err := parser.GetStringAnnotation(annotationAuthTLSSecret, ing)
if err != nil {
return &AuthSSLConfig{}, err
return &Config{}, err
}
if tlsauthsecret == "" {
return &AuthSSLConfig{}, ing_errors.NewLocationDenied("an empty string is not a valid secret name")
return &Config{}, ing_errors.NewLocationDenied("an empty string is not a valid secret name")
}
_, _, err = k8s.ParseNameNS(tlsauthsecret)
if err != nil {
return &AuthSSLConfig{}, ing_errors.NewLocationDenied(err.Error())
return &Config{}, ing_errors.NewLocationDenied(err.Error())
}
tlsVerifyClient, err := parser.GetStringAnnotation(annotationAuthVerifyClient, ing)
@ -112,7 +113,7 @@ func (a authTLS) Parse(ing *extensions.Ingress) (interface{}, error) {
authCert, err := a.certResolver.GetAuthCertificate(tlsauthsecret)
if err != nil {
return &AuthSSLConfig{}, ing_errors.LocationDenied{
return &Config{}, ing_errors.LocationDenied{
Reason: errors.Wrap(err, "error obtaining certificate"),
}
}
@ -122,7 +123,7 @@ func (a authTLS) Parse(ing *extensions.Ingress) (interface{}, error) {
errorpage = ""
}
return &AuthSSLConfig{
return &Config{
AuthSSLCert: *authCert,
VerifyClient: tlsVerifyClient,
ValidationDepth: tlsdepth,

View file

@ -51,8 +51,8 @@ var (
type cors struct {
}
// CorsConfig contains the Cors configuration to be used in the Ingress
type CorsConfig struct {
// Config contains the Cors configuration to be used in the Ingress
type Config struct {
CorsEnabled bool `json:"corsEnabled"`
CorsAllowOrigin string `json:"corsAllowOrigin"`
CorsAllowMethods string `json:"corsAllowMethods"`
@ -66,7 +66,7 @@ func NewParser() parser.IngressAnnotation {
}
// Equal tests for equality between two External types
func (c1 *CorsConfig) Equal(c2 *CorsConfig) bool {
func (c1 *Config) Equal(c2 *Config) bool {
if c1 == c2 {
return true
}
@ -120,7 +120,7 @@ func (a cors) Parse(ing *extensions.Ingress) (interface{}, error) {
corsallowcredentials = true
}
return &CorsConfig{
return &Config{
CorsEnabled: corsenabled,
CorsAllowOrigin: corsalloworigin,
CorsAllowHeaders: corsallowheaders,

View file

@ -72,7 +72,7 @@ func TestIngressCorsConfig(t *testing.T) {
ing.SetAnnotations(data)
corst, _ := NewParser().Parse(ing)
nginxCors, ok := corst.(*CorsConfig)
nginxCors, ok := corst.(*Config)
if !ok {
t.Errorf("expected a Config type")
}

View file

@ -28,9 +28,9 @@ const (
upsFailTimeout = "ingress.kubernetes.io/upstream-fail-timeout"
)
// Upstream returns the URL and method to use check the status of
// Config returns the URL and method to use check the status of
// the upstream server/s
type Upstream struct {
type Config struct {
MaxFails int `json:"maxFails"`
FailTimeout int `json:"failTimeout"`
}
@ -49,7 +49,7 @@ func NewParser(br resolver.DefaultBackend) parser.IngressAnnotation {
func (a healthCheck) Parse(ing *extensions.Ingress) (interface{}, error) {
defBackend := a.backendResolver.GetDefaultBackend()
if ing.GetAnnotations() == nil {
return &Upstream{defBackend.UpstreamMaxFails, defBackend.UpstreamFailTimeout}, nil
return &Config{defBackend.UpstreamMaxFails, defBackend.UpstreamFailTimeout}, nil
}
mf, err := parser.GetIntAnnotation(upsMaxFails, ing)
@ -62,5 +62,5 @@ func (a healthCheck) Parse(ing *extensions.Ingress) (interface{}, error) {
ft = defBackend.UpstreamFailTimeout
}
return &Upstream{mf, ft}, nil
return &Config{mf, ft}, nil
}

View file

@ -77,7 +77,7 @@ func TestIngressHealthCheck(t *testing.T) {
ing.SetAnnotations(data)
hzi, _ := NewParser(mockBackend{}).Parse(ing)
nginxHz, ok := hzi.(*Upstream)
nginxHz, ok := hzi.(*Config)
if !ok {
t.Errorf("expected a Upstream type")
}

View file

@ -17,6 +17,7 @@ limitations under the License.
package portinredirect
import (
"fmt"
"testing"
api "k8s.io/api/core/v1"
@ -24,8 +25,6 @@ import (
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"fmt"
"k8s.io/ingress-nginx/pkg/ingress/defaults"
)

View file

@ -36,8 +36,8 @@ const (
requestBuffering = "ingress.kubernetes.io/proxy-request-buffering"
)
// Configuration returns the proxy timeout to use in the upstream server/s
type Configuration struct {
// Config returns the proxy timeout to use in the upstream server/s
type Config struct {
BodySize string `json:"bodySize"`
ConnectTimeout int `json:"connectTimeout"`
SendTimeout int `json:"sendTimeout"`
@ -51,7 +51,7 @@ type Configuration struct {
}
// Equal tests for equality between two Configuration types
func (l1 *Configuration) Equal(l2 *Configuration) bool {
func (l1 *Config) Equal(l2 *Config) bool {
if l1 == l2 {
return true
}
@ -156,5 +156,5 @@ func (a proxy) Parse(ing *extensions.Ingress) (interface{}, error) {
rb = defBackend.ProxyRequestBuffering
}
return &Configuration{bs, ct, st, rt, bufs, cd, cp, nu, pp, rb}, nil
return &Config{bs, ct, st, rt, bufs, cd, cp, nu, pp, rb}, nil
}

View file

@ -97,9 +97,9 @@ func TestProxy(t *testing.T) {
if err != nil {
t.Fatalf("unexpected error parsing a valid")
}
p, ok := i.(*Configuration)
p, ok := i.(*Config)
if !ok {
t.Fatalf("expected a Configuration type")
t.Fatalf("expected a Config type")
}
if p.ConnectTimeout != 1 {
t.Errorf("expected 1 as connect-timeout but returned %v", p.ConnectTimeout)
@ -137,9 +137,9 @@ func TestProxyWithNoAnnotation(t *testing.T) {
if err != nil {
t.Fatalf("unexpected error parsing a valid")
}
p, ok := i.(*Configuration)
p, ok := i.(*Config)
if !ok {
t.Fatalf("expected a Configuration type")
t.Fatalf("expected a Config type")
}
if p.ConnectTimeout != 10 {
t.Errorf("expected 10 as connect-timeout but returned %v", p.ConnectTimeout)

View file

@ -45,11 +45,11 @@ const (
defSharedSize = 5
)
// RateLimit returns rate limit configuration for an Ingress rule limiting the
// Config returns rate limit configuration for an Ingress rule limiting the
// number of connections per IP address and/or connections per second.
// If you both annotations are specified in a single Ingress rule, RPS limits
// takes precedence
type RateLimit struct {
type Config struct {
// Connections indicates a limit with the number of connections per IP address
Connections Zone `json:"connections"`
// RPS indicates a limit with the number of connections per second
@ -69,7 +69,7 @@ type RateLimit struct {
}
// Equal tests for equality between two RateLimit types
func (rt1 *RateLimit) Equal(rt2 *RateLimit) bool {
func (rt1 *Config) Equal(rt2 *Config) bool {
if rt1 == rt2 {
return true
}
@ -185,7 +185,7 @@ func (a ratelimit) Parse(ing *extensions.Ingress) (interface{}, error) {
}
if rpm == 0 && rps == 0 && conn == 0 {
return &RateLimit{
return &Config{
Connections: Zone{},
RPS: Zone{},
RPM: Zone{},
@ -196,7 +196,7 @@ func (a ratelimit) Parse(ing *extensions.Ingress) (interface{}, error) {
zoneName := fmt.Sprintf("%v_%v", ing.GetNamespace(), ing.GetName())
return &RateLimit{
return &Config{
Connections: Zone{
Name: fmt.Sprintf("%v_conn", zoneName),
Limit: conn,

View file

@ -107,7 +107,7 @@ func TestBadRateLimiting(t *testing.T) {
if err != nil {
t.Errorf("unexpected error: %v", err)
}
rateLimit, ok := i.(*RateLimit)
rateLimit, ok := i.(*Config)
if !ok {
t.Errorf("expected a RateLimit type")
}

View file

@ -33,8 +33,8 @@ const (
www = "ingress.kubernetes.io/from-to-www-redirect"
)
// Redirect returns the redirect configuration for an Ingress rule
type Redirect struct {
// Config returns the redirect configuration for an Ingress rule
type Config struct {
URL string `json:"url"`
Code int `json:"code"`
FromToWWW bool `json:"fromToWWW"`
@ -64,7 +64,7 @@ func (a redirect) Parse(ing *extensions.Ingress) (interface{}, error) {
return nil, err
}
return &Redirect{
return &Config{
URL: tr,
Code: http.StatusFound,
FromToWWW: r3w,
@ -81,7 +81,7 @@ func (a redirect) Parse(ing *extensions.Ingress) (interface{}, error) {
return nil, err
}
return &Redirect{
return &Config{
URL: pr,
Code: http.StatusMovedPermanently,
FromToWWW: r3w,
@ -89,7 +89,7 @@ func (a redirect) Parse(ing *extensions.Ingress) (interface{}, error) {
}
if r3w {
return &Redirect{
return &Config{
FromToWWW: r3w,
}, nil
}
@ -98,7 +98,7 @@ func (a redirect) Parse(ing *extensions.Ingress) (interface{}, error) {
}
// Equal tests for equality between two Redirect types
func (r1 *Redirect) Equal(r2 *Redirect) bool {
func (r1 *Config) Equal(r2 *Config) bool {
if r1 == r2 {
return true
}

View file

@ -32,8 +32,8 @@ const (
appRoot = "ingress.kubernetes.io/app-root"
)
// Redirect describes the per location redirect config
type Redirect struct {
// Config describes the per location redirect config
type Config struct {
// Target URI where the traffic must be redirected
Target string `json:"target"`
// AddBaseURL indicates if is required to add a base tag in the head
@ -50,7 +50,7 @@ type Redirect struct {
}
// Equal tests for equality between two Redirect types
func (r1 *Redirect) Equal(r2 *Redirect) bool {
func (r1 *Config) Equal(r2 *Config) bool {
if r1 == r2 {
return true
}
@ -103,7 +103,7 @@ func (a rewrite) Parse(ing *extensions.Ingress) (interface{}, error) {
abu, _ := parser.GetBoolAnnotation(addBaseURL, ing)
bus, _ := parser.GetStringAnnotation(baseURLScheme, ing)
ar, _ := parser.GetStringAnnotation(appRoot, ing)
return &Redirect{
return &Config{
Target: rt,
AddBaseURL: abu,
BaseURLScheme: bus,

View file

@ -93,7 +93,7 @@ func TestRedirect(t *testing.T) {
if err != nil {
t.Errorf("Unexpected error with ingress: %v", err)
}
redirect, ok := i.(*Redirect)
redirect, ok := i.(*Config)
if !ok {
t.Errorf("expected a Redirect type")
}
@ -110,7 +110,7 @@ func TestSSLRedirect(t *testing.T) {
ing.SetAnnotations(data)
i, _ := NewParser(mockBackend{true}).Parse(ing)
redirect, ok := i.(*Redirect)
redirect, ok := i.(*Config)
if !ok {
t.Errorf("expected a Redirect type")
}
@ -122,7 +122,7 @@ func TestSSLRedirect(t *testing.T) {
ing.SetAnnotations(data)
i, _ = NewParser(mockBackend{false}).Parse(ing)
redirect, ok = i.(*Redirect)
redirect, ok = i.(*Config)
if !ok {
t.Errorf("expected a Redirect type")
}
@ -139,7 +139,7 @@ func TestForceSSLRedirect(t *testing.T) {
ing.SetAnnotations(data)
i, _ := NewParser(mockBackend{true}).Parse(ing)
redirect, ok := i.(*Redirect)
redirect, ok := i.(*Config)
if !ok {
t.Errorf("expected a Redirect type")
}
@ -151,7 +151,7 @@ func TestForceSSLRedirect(t *testing.T) {
ing.SetAnnotations(data)
i, _ = NewParser(mockBackend{false}).Parse(ing)
redirect, ok = i.(*Redirect)
redirect, ok = i.(*Config)
if !ok {
t.Errorf("expected a Redirect type")
}
@ -167,12 +167,11 @@ func TestAppRoot(t *testing.T) {
ing.SetAnnotations(data)
i, _ := NewParser(mockBackend{true}).Parse(ing)
redirect, ok := i.(*Redirect)
redirect, ok := i.(*Config)
if !ok {
t.Errorf("expected a App Context")
}
if redirect.AppRoot != "/app1" {
t.Errorf("Unexpected value got in AppRoot")
}
}

View file

@ -31,8 +31,8 @@ const (
secureVerifyCASecret = "ingress.kubernetes.io/secure-verify-ca-secret"
)
// Secure describes SSL backend configuration
type Secure struct {
// Config describes SSL backend configuration
type Config struct {
Secure bool `json:"secure"`
CACert resolver.AuthSSLCert `json:"caCert"`
}
@ -53,7 +53,7 @@ func NewParser(resolver resolver.AuthCertificate) parser.IngressAnnotation {
func (a su) Parse(ing *extensions.Ingress) (interface{}, error) {
s, _ := parser.GetBoolAnnotation(secureUpstream, ing)
ca, _ := parser.GetStringAnnotation(secureVerifyCASecret, ing)
secure := &Secure{
secure := &Config{
Secure: s,
CACert: resolver.AuthSSLCert{},
}
@ -71,7 +71,7 @@ func (a su) Parse(ing *extensions.Ingress) (interface{}, error) {
if caCert == nil {
return secure, nil
}
return &Secure{
return &Config{
Secure: s,
CACert: *caCert,
}, nil

View file

@ -17,14 +17,13 @@ limitations under the License.
package secureupstream
import (
"fmt"
"testing"
api "k8s.io/api/core/v1"
extensions "k8s.io/api/extensions/v1beta1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"fmt"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/ingress-nginx/pkg/ingress/resolver"
)

View file

@ -42,24 +42,24 @@ var (
affinityCookieHashRegex = regexp.MustCompile(`^(index|md5|sha1)$`)
)
// AffinityConfig describes the per ingress session affinity config
type AffinityConfig struct {
// Config describes the per ingress session affinity config
type Config struct {
// The type of affinity that will be used
AffinityType string `json:"type"`
CookieConfig
Type string `json:"type"`
Cookie
}
// CookieConfig describes the Config of cookie type affinity
type CookieConfig struct {
// Cookie describes the Config of cookie type affinity
type Cookie struct {
// The name of the cookie that will be used in case of cookie affinity type.
Name string `json:"name"`
// The hash that will be used to encode the cookie in case of cookie affinity type
Hash string `json:"hash"`
}
// CookieAffinityParse gets the annotation values related to Cookie Affinity
// 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) *CookieConfig {
func cookieAffinityParse(ing *extensions.Ingress) *Cookie {
sn, err := parser.GetStringAnnotation(annotationAffinityCookieName, ing)
@ -75,7 +75,7 @@ func CookieAffinityParse(ing *extensions.Ingress) *CookieConfig {
sh = defaultAffinityCookieHash
}
return &CookieConfig{
return &Cookie{
Name: sn,
Hash: sh,
}
@ -92,7 +92,7 @@ type affinity struct {
// ParseAnnotations parses the annotations contained in the ingress
// rule used to configure the affinity directives
func (a affinity) Parse(ing *extensions.Ingress) (interface{}, error) {
cookieAffinityConfig := &CookieConfig{}
cookie := &Cookie{}
// Check the type of affinity that will be used
at, err := parser.GetStringAnnotation(annotationAffinityType, ing)
if err != nil {
@ -101,15 +101,14 @@ func (a affinity) Parse(ing *extensions.Ingress) (interface{}, error) {
switch at {
case "cookie":
cookieAffinityConfig = CookieAffinityParse(ing)
cookie = cookieAffinityParse(ing)
default:
glog.V(3).Infof("No default affinity was found for Ingress %v", ing.Name)
}
return &AffinityConfig{
AffinityType: at,
CookieConfig: *cookieAffinityConfig,
}, nil
return &Config{
Type: at,
Cookie: *cookie,
}, nil
}

View file

@ -70,20 +70,20 @@ func TestIngressAffinityCookieConfig(t *testing.T) {
ing.SetAnnotations(data)
affin, _ := NewParser().Parse(ing)
nginxAffinity, ok := affin.(*AffinityConfig)
nginxAffinity, ok := affin.(*Config)
if !ok {
t.Errorf("expected a Config type")
}
if nginxAffinity.AffinityType != "cookie" {
t.Errorf("expected cookie as sticky-type but returned %v", nginxAffinity.AffinityType)
if nginxAffinity.Type != "cookie" {
t.Errorf("expected cookie as sticky-type but returned %v", nginxAffinity.Type)
}
if nginxAffinity.CookieConfig.Hash != "md5" {
t.Errorf("expected md5 as sticky-hash but returned %v", nginxAffinity.CookieConfig.Hash)
if nginxAffinity.Cookie.Hash != "md5" {
t.Errorf("expected md5 as sticky-hash but returned %v", nginxAffinity.Cookie.Hash)
}
if nginxAffinity.CookieConfig.Name != "INGRESSCOOKIE" {
t.Errorf("expected route as sticky-name but returned %v", nginxAffinity.CookieConfig.Name)
if nginxAffinity.Cookie.Name != "INGRESSCOOKIE" {
t.Errorf("expected route as sticky-name but returned %v", nginxAffinity.Cookie.Name)
}
}