Merge pull request #1662 from aledbf/refactor-annotations

Refactor annotations
This commit is contained in:
Manuel Alejandro de Brito Fontes 2017-11-11 15:19:46 -03:00 committed by GitHub
commit 39c30853ae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
119 changed files with 1630 additions and 1201 deletions

View file

@ -27,9 +27,9 @@ import (
apiv1 "k8s.io/api/core/v1"
"k8s.io/ingress-nginx/pkg/ingress/controller"
ngx_config "k8s.io/ingress-nginx/pkg/ingress/controller/config"
ing_net "k8s.io/ingress-nginx/pkg/net"
"k8s.io/ingress-nginx/internal/ingress/controller"
ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
ing_net "k8s.io/ingress-nginx/internal/net"
)
const (
@ -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

@ -39,10 +39,10 @@ import (
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/ingress-nginx/pkg/ingress"
"k8s.io/ingress-nginx/pkg/ingress/controller"
"k8s.io/ingress-nginx/pkg/k8s"
"k8s.io/ingress-nginx/pkg/net/ssl"
"k8s.io/ingress-nginx/internal/ingress"
"k8s.io/ingress-nginx/internal/ingress/controller"
"k8s.io/ingress-nginx/internal/k8s"
"k8s.io/ingress-nginx/internal/net/ssl"
"k8s.io/ingress-nginx/version"
)

View file

@ -19,23 +19,21 @@ package alias
import (
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
)
const (
annotation = "ingress.kubernetes.io/server-alias"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"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

@ -0,0 +1,162 @@
/*
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/internal/ingress/annotations/alias"
"k8s.io/ingress-nginx/internal/ingress/annotations/auth"
"k8s.io/ingress-nginx/internal/ingress/annotations/authreq"
"k8s.io/ingress-nginx/internal/ingress/annotations/authtls"
"k8s.io/ingress-nginx/internal/ingress/annotations/clientbodybuffersize"
"k8s.io/ingress-nginx/internal/ingress/annotations/cors"
"k8s.io/ingress-nginx/internal/ingress/annotations/defaultbackend"
"k8s.io/ingress-nginx/internal/ingress/annotations/healthcheck"
"k8s.io/ingress-nginx/internal/ingress/annotations/ipwhitelist"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/annotations/portinredirect"
"k8s.io/ingress-nginx/internal/ingress/annotations/proxy"
"k8s.io/ingress-nginx/internal/ingress/annotations/ratelimit"
"k8s.io/ingress-nginx/internal/ingress/annotations/redirect"
"k8s.io/ingress-nginx/internal/ingress/annotations/rewrite"
"k8s.io/ingress-nginx/internal/ingress/annotations/secureupstream"
"k8s.io/ingress-nginx/internal/ingress/annotations/serversnippet"
"k8s.io/ingress-nginx/internal/ingress/annotations/serviceupstream"
"k8s.io/ingress-nginx/internal/ingress/annotations/sessionaffinity"
"k8s.io/ingress-nginx/internal/ingress/annotations/snippet"
"k8s.io/ingress-nginx/internal/ingress/annotations/sslpassthrough"
"k8s.io/ingress-nginx/internal/ingress/annotations/upstreamhashby"
"k8s.io/ingress-nginx/internal/ingress/annotations/upstreamvhost"
"k8s.io/ingress-nginx/internal/ingress/annotations/vtsfilterkey"
"k8s.io/ingress-nginx/internal/ingress/errors"
"k8s.io/ingress-nginx/internal/ingress/resolver"
)
// DeniedKeyName name of the key that contains the reason to deny a location
const DeniedKeyName = "Denied"
// 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
Denied error
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 {
annotations map[string]parser.IngressAnnotation
}
// NewAnnotationExtractor creates a new annotations extractor
func NewAnnotationExtractor(cfg resolver.Resolver) Extractor {
return Extractor{
map[string]parser.IngressAnnotation{
"Alias": alias.NewParser(cfg),
"BasicDigestAuth": auth.NewParser(auth.AuthDirectory, cfg),
"CertificateAuth": authtls.NewParser(cfg),
"ClientBodyBufferSize": clientbodybuffersize.NewParser(cfg),
"ConfigurationSnippet": snippet.NewParser(cfg),
"CorsConfig": cors.NewParser(cfg),
"DefaultBackend": defaultbackend.NewParser(cfg),
"ExternalAuth": authreq.NewParser(cfg),
"HealthCheck": healthcheck.NewParser(cfg),
"Proxy": proxy.NewParser(cfg),
"RateLimit": ratelimit.NewParser(cfg),
"Redirect": redirect.NewParser(cfg),
"Rewrite": rewrite.NewParser(cfg),
"SecureUpstream": secureupstream.NewParser(cfg),
"ServerSnippet": serversnippet.NewParser(cfg),
"ServiceUpstream": serviceupstream.NewParser(cfg),
"SessionAffinity": sessionaffinity.NewParser(cfg),
"SSLPassthrough": sslpassthrough.NewParser(cfg),
"UsePortInRedirects": portinredirect.NewParser(cfg),
"UpstreamHashBy": upstreamhashby.NewParser(cfg),
"UpstreamVhost": upstreamvhost.NewParser(cfg),
"VtsFilterKey": vtsfilterkey.NewParser(cfg),
"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

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
package annotations
import (
"testing"
@ -24,30 +24,31 @@ import (
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"
"k8s.io/ingress-nginx/internal/ingress/defaults"
"k8s.io/ingress-nginx/internal/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"
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
}
@ -75,20 +76,6 @@ func (m mockCfg) GetAuthCertificate(name string) (*resolver.AuthSSLCert, error)
return nil, nil
}
func TestAnnotationExtractor(t *testing.T) {
ec := newAnnotationExtractor(mockCfg{})
ing := buildIngress()
m := ec.Extract(ing)
// the map at least should contains HealthCheck and Proxy information (defaults)
if _, ok := m["HealthCheck"]; !ok {
t.Error("expected HealthCheck annotation")
}
if _, ok := m["Proxy"]; !ok {
t.Error("expected Proxy annotation")
}
}
func buildIngress() *extensions.Ingress {
defaultBackend := extensions.IngressBackend{
ServiceName: "default-backend",
@ -125,7 +112,7 @@ func buildIngress() *extensions.Ingress {
}
func TestSecureUpstream(t *testing.T) {
ec := newAnnotationExtractor(mockCfg{})
ec := NewAnnotationExtractor(mockCfg{})
ing := buildIngress()
fooAnns := []struct {
@ -141,7 +128,7 @@ func TestSecureUpstream(t *testing.T) {
for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations)
r := ec.SecureUpstream(ing)
r := ec.Extract(ing).SecureUpstream
if r.Secure != foo.er {
t.Errorf("Returned %v but expected %v", r, foo.er)
}
@ -149,7 +136,7 @@ func TestSecureUpstream(t *testing.T) {
}
func TestSecureVerifyCACert(t *testing.T) {
ec := newAnnotationExtractor(mockCfg{
ec := NewAnnotationExtractor(mockCfg{
MockSecrets: map[string]*apiv1.Secret{
"default/secure-verify-ca": {
ObjectMeta: metav1.ObjectMeta{
@ -176,15 +163,15 @@ func TestSecureVerifyCACert(t *testing.T) {
for _, ann := range anns {
ing := buildIngress()
ing.SetAnnotations(ann.annotations)
res := ec.SecureUpstream(ing)
if (res.CACert.CAFileName != "") != ann.exists {
su := ec.Extract(ing).SecureUpstream
if (su.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{})
ec := NewAnnotationExtractor(mockCfg{})
ing := buildIngress()
fooAnns := []struct {
@ -201,11 +188,7 @@ func TestHealthCheck(t *testing.T) {
for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations)
r := ec.HealthCheck(ing)
if r == nil {
t.Errorf("Returned nil but expected a healthcheck.Upstream")
continue
}
r := ec.Extract(ing).HealthCheck
if r.FailTimeout != foo.euft {
t.Errorf("Returned %d but expected %d for FailTimeout", r.FailTimeout, foo.euft)
@ -218,7 +201,7 @@ func TestHealthCheck(t *testing.T) {
}
func TestSSLPassthrough(t *testing.T) {
ec := newAnnotationExtractor(mockCfg{})
ec := NewAnnotationExtractor(mockCfg{})
ing := buildIngress()
fooAnns := []struct {
@ -234,7 +217,7 @@ func TestSSLPassthrough(t *testing.T) {
for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations)
r := ec.SSLPassthrough(ing)
r := ec.Extract(ing).SSLPassthrough
if r != foo.er {
t.Errorf("Returned %v but expected %v", r, foo.er)
}
@ -242,7 +225,7 @@ func TestSSLPassthrough(t *testing.T) {
}
func TestUpstreamHashBy(t *testing.T) {
ec := newAnnotationExtractor(mockCfg{})
ec := NewAnnotationExtractor(mockCfg{})
ing := buildIngress()
fooAnns := []struct {
@ -258,7 +241,7 @@ func TestUpstreamHashBy(t *testing.T) {
for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations)
r := ec.UpstreamHashBy(ing)
r := ec.Extract(ing).UpstreamHashBy
if r != foo.er {
t.Errorf("Returned %v but expected %v", r, foo.er)
}
@ -266,7 +249,7 @@ func TestUpstreamHashBy(t *testing.T) {
}
func TestAffinitySession(t *testing.T) {
ec := newAnnotationExtractor(mockCfg{})
ec := NewAnnotationExtractor(mockCfg{})
ing := buildIngress()
fooAnns := []struct {
@ -284,25 +267,21 @@ func TestAffinitySession(t *testing.T) {
for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations)
r := ec.SessionAffinity(ing)
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.CookieConfig.Hash != foo.hash {
t.Errorf("Returned %v but expected %v for Hash", r.CookieConfig.Hash, foo.hash)
}
if r.CookieConfig.Name != foo.name {
t.Errorf("Returned %v but expected %v for Name", r.CookieConfig.Name, foo.name)
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{})
ec := NewAnnotationExtractor(mockCfg{})
ing := buildIngress()
fooAnns := []struct {
@ -322,12 +301,8 @@ func TestCors(t *testing.T) {
for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations)
r := ec.Cors(ing)
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)
@ -351,3 +326,48 @@ func TestCors(t *testing.T) {
}
}
/*
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

@ -27,16 +27,10 @@ import (
api "k8s.io/api/core/v1"
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/ingress-nginx/pkg/file"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
ing_errors "k8s.io/ingress-nginx/pkg/ingress/errors"
"k8s.io/ingress-nginx/pkg/ingress/resolver"
)
const (
authType = "ingress.kubernetes.io/auth-type"
authSecret = "ingress.kubernetes.io/auth-secret"
authRealm = "ingress.kubernetes.io/auth-realm"
"k8s.io/ingress-nginx/internal/file"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
"k8s.io/ingress-nginx/internal/ingress/resolver"
)
var (
@ -46,8 +40,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 +49,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
}
@ -83,12 +77,12 @@ func (bd1 *BasicDigest) Equal(bd2 *BasicDigest) 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)
@ -140,7 +134,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

@ -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,19 +99,19 @@ 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)
}
auth, ok := i.(*BasicDigest)
auth, ok := i.(*Config)
if !ok {
t.Errorf("expected a BasicDigest type")
}
@ -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

@ -23,20 +23,13 @@ import (
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
ing_errors "k8s.io/ingress-nginx/pkg/ingress/errors"
"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
type External struct {
// Config returns external authentication configuration for an Ingress rule
type Config struct {
URL string `json:"url"`
// Host contains the hostname defined in the URL
Host string `json:"host"`
@ -45,8 +38,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
}
@ -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 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)
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, ",")
@ -165,7 +159,7 @@ func (a authReq) Parse(ing *extensions.Ingress) (interface{}, error) {
}
}
return &External{
return &Config{
URL: str,
Host: ur.Hostname(),
SigninURL: signin,

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,18 +87,18 @@ 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)
}
continue
}
u, ok := i.(*External)
u, ok := i.(*Config)
if !ok {
t.Errorf("%v: expected an External type", 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())
@ -149,7 +150,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,38 +20,34 @@ import (
"github.com/pkg/errors"
extensions "k8s.io/api/extensions/v1beta1"
"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"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
"k8s.io/ingress-nginx/internal/ingress/resolver"
"k8s.io/ingress-nginx/internal/k8s"
)
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 (
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
}
@ -74,55 +70,55 @@ func (assl1 *AuthSSLConfig) Equal(assl2 *AuthSSLConfig) 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 &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)
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 &AuthSSLConfig{}, ing_errors.LocationDenied{
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 = ""
}
return &AuthSSLConfig{
return &Config{
AuthSSLCert: *authCert,
VerifyClient: tlsVerifyClient,
ValidationDepth: tlsdepth,

View file

@ -19,9 +19,6 @@ package class
import (
"github.com/golang/glog"
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
"k8s.io/ingress-nginx/pkg/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

@ -19,23 +19,21 @@ package clientbodybuffersize
import (
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
)
const (
annotation = "ingress.kubernetes.io/client-body-buffer-size"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"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

@ -21,15 +21,11 @@ import (
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
"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,10 +45,11 @@ var (
)
type cors struct {
r resolver.Resolver
}
// 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"`
@ -61,12 +58,12 @@ type CorsConfig 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
func (c1 *CorsConfig) Equal(c2 *CorsConfig) bool {
func (c1 *Config) Equal(c2 *Config) bool {
if c1 == c2 {
return true
}
@ -94,33 +91,33 @@ func (c1 *CorsConfig) Equal(c2 *CorsConfig) 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
}
return &CorsConfig{
return &Config{
CorsEnabled: corsenabled,
CorsAllowOrigin: corsalloworigin,
CorsAllowHeaders: corsallowheaders,

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,15 +65,15 @@ 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)
nginxCors, ok := corst.(*CorsConfig)
corst, _ := NewParser(&resolver.Mock{}).Parse(ing)
nginxCors, ok := corst.(*Config)
if !ok {
t.Errorf("expected a Config type")
}

View file

@ -22,33 +22,29 @@ import (
"github.com/pkg/errors"
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
"k8s.io/ingress-nginx/pkg/ingress/resolver"
)
const (
defaultBackend = "ingress.kubernetes.io/default-backend"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/resolver"
)
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

@ -19,48 +19,43 @@ package healthcheck
import (
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
"k8s.io/ingress-nginx/pkg/ingress/resolver"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/resolver"
)
const (
upsMaxFails = "ingress.kubernetes.io/upstream-max-fails"
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"`
}
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 &Upstream{defBackend.UpstreamMaxFails, defBackend.UpstreamFailTimeout}, 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
}
return &Upstream{mf, ft}, nil
return &Config{mf, ft}, nil
}

View file

@ -24,7 +24,8 @@ import (
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/ingress-nginx/pkg/ingress/defaults"
"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,11 +75,11 @@ 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)
nginxHz, ok := hzi.(*Upstream)
nginxHz, ok := hzi.(*Config)
if !ok {
t.Errorf("expected a Upstream type")
}

View file

@ -23,15 +23,11 @@ import (
"github.com/pkg/errors"
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/ingress-nginx/pkg/net"
"k8s.io/ingress-nginx/internal/net"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
ing_errors "k8s.io/ingress-nginx/pkg/ingress/errors"
"k8s.io/ingress-nginx/pkg/ingress/resolver"
)
const (
whitelist = "ingress.kubernetes.io/whitelist-source-range"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
"k8s.io/ingress-nginx/internal/ingress/resolver"
)
// SourceRange returns the CIDR
@ -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/pkg/ingress/defaults"
"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

@ -21,7 +21,8 @@ import (
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/ingress-nginx/pkg/ingress/errors"
"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

@ -19,29 +19,25 @@ package portinredirect
import (
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
"k8s.io/ingress-nginx/pkg/ingress/resolver"
)
const (
annotation = "ingress.kubernetes.io/use-port-in-redirects"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/resolver"
)
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

@ -17,6 +17,7 @@ limitations under the License.
package portinredirect
import (
"fmt"
"testing"
api "k8s.io/api/core/v1"
@ -24,9 +25,8 @@ import (
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"fmt"
"k8s.io/ingress-nginx/pkg/ingress/defaults"
"k8s.io/ingress-nginx/internal/ingress/defaults"
"k8s.io/ingress-nginx/internal/ingress/resolver"
)
func buildIngress() *extensions.Ingress {
@ -65,6 +65,7 @@ func buildIngress() *extensions.Ingress {
}
type mockBackend struct {
resolver.Mock
usePortInRedirects bool
}
@ -91,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

@ -19,25 +19,12 @@ package proxy
import (
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
"k8s.io/ingress-nginx/pkg/ingress/resolver"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"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"
)
// 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 +38,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
}
@ -94,67 +81,67 @@ func (l1 *Configuration) Equal(l2 *Configuration) 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
}
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

@ -24,7 +24,8 @@ import (
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/ingress-nginx/pkg/ingress/defaults"
"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,23 +85,23 @@ 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)
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 +139,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

@ -24,19 +24,12 @@ import (
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
"k8s.io/ingress-nginx/pkg/ingress/resolver"
"k8s.io/ingress-nginx/pkg/net"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/resolver"
"k8s.io/ingress-nginx/internal/net"
)
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
@ -45,11 +38,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 +62,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
}
@ -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 {
@ -185,7 +178,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 +189,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

@ -24,7 +24,8 @@ import (
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/ingress-nginx/pkg/ingress/defaults"
"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)
@ -107,7 +109,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

@ -23,28 +23,25 @@ import (
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
"k8s.io/ingress-nginx/pkg/ingress/errors"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/errors"
"k8s.io/ingress-nginx/internal/ingress/resolver"
)
const (
permanent = "ingress.kubernetes.io/permanent-redirect"
temporal = "ingress.kubernetes.io/temporal-redirect"
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"`
}
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
}
@ -64,14 +61,14 @@ func (a redirect) Parse(ing *extensions.Ingress) (interface{}, error) {
return nil, err
}
return &Redirect{
return &Config{
URL: tr,
Code: http.StatusFound,
FromToWWW: r3w,
}, 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
}
@ -81,7 +78,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 +86,7 @@ func (a redirect) Parse(ing *extensions.Ingress) (interface{}, error) {
}
if r3w {
return &Redirect{
return &Config{
FromToWWW: r3w,
}, nil
}
@ -98,7 +95,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

@ -19,21 +19,12 @@ package rewrite
import (
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
"k8s.io/ingress-nginx/pkg/ingress/resolver"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"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"
)
// 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 +41,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
}
@ -80,30 +71,31 @@ func (r1 *Redirect) Equal(r2 *Redirect) 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)
return &Redirect{
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,
BaseURLScheme: bus,

View file

@ -24,7 +24,8 @@ import (
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/ingress-nginx/pkg/ingress/defaults"
"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,14 +88,14 @@ 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)
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")
}
@ -106,11 +108,11 @@ 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)
redirect, ok := i.(*Redirect)
i, _ := NewParser(mockBackend{redirect: true}).Parse(ing)
redirect, ok := i.(*Config)
if !ok {
t.Errorf("expected a Redirect type")
}
@ -118,11 +120,11 @@ 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)
redirect, ok = i.(*Redirect)
i, _ = NewParser(mockBackend{redirect: false}).Parse(ing)
redirect, ok = i.(*Config)
if !ok {
t.Errorf("expected a Redirect type")
}
@ -135,11 +137,11 @@ 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)
redirect, ok := i.(*Redirect)
i, _ := NewParser(mockBackend{redirect: true}).Parse(ing)
redirect, ok := i.(*Config)
if !ok {
t.Errorf("expected a Redirect type")
}
@ -147,11 +149,11 @@ 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)
redirect, ok = i.(*Redirect)
i, _ = NewParser(mockBackend{redirect: false}).Parse(ing)
redirect, ok = i.(*Config)
if !ok {
t.Errorf("expected a Redirect type")
}
@ -163,16 +165,15 @@ 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)
redirect, ok := i.(*Redirect)
i, _ := NewParser(mockBackend{redirect: true}).Parse(ing)
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

@ -22,38 +22,31 @@ import (
"github.com/pkg/errors"
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
"k8s.io/ingress-nginx/pkg/ingress/resolver"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/resolver"
)
const (
secureUpstream = "ingress.kubernetes.io/secure-backends"
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"`
}
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)
secure := &Secure{
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,14 +57,14 @@ 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")
}
if caCert == nil {
return secure, nil
}
return &Secure{
return &Config{
Secure: s,
CACert: *caCert,
}, nil

View file

@ -17,16 +17,15 @@ 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"
"k8s.io/ingress-nginx/internal/ingress/resolver"
)
func buildIngress() *extensions.Ingress {
@ -65,6 +64,7 @@ func buildIngress() *extensions.Ingress {
}
type mockCfg struct {
resolver.Mock
certs map[string]resolver.AuthSSLCert
}
@ -78,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{
@ -95,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 {
@ -107,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

@ -19,24 +19,22 @@ package serversnippet
import (
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
)
const (
annotation = "ingress.kubernetes.io/server-snippet"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"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/pkg/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

@ -23,18 +23,21 @@ import (
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
"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"
)
@ -42,74 +45,73 @@ 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 {
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)
sh = defaultAffinityCookieHash
}
return &CookieConfig{
return &Cookie{
Name: sn,
Hash: sh,
}
}
// 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
// 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)
at, err := parser.GetStringAnnotation(annotationAffinityType, ing, a.r)
if err != nil {
at = ""
}
switch at {
case "cookie":
cookieAffinityConfig = CookieAffinityParse(ing)
cookie = a.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

@ -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,26 +66,26 @@ 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)
nginxAffinity, ok := affin.(*AffinityConfig)
affin, _ := NewParser(&resolver.Mock{}).Parse(ing)
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)
}
}

View file

@ -19,24 +19,22 @@ package snippet
import (
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
)
const (
annotation = "ingress.kubernetes.io/configuration-snippet"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"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

@ -19,20 +19,18 @@ package sslpassthrough
import (
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
ing_errors "k8s.io/ingress-nginx/pkg/ingress/errors"
)
const (
passthrough = "ingress.kubernetes.io/ssl-passthrough"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
"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

@ -19,24 +19,22 @@ package upstreamhashby
import (
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
)
const (
annotation = "ingress.kubernetes.io/upstream-hash-by"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"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

@ -19,24 +19,22 @@ package upstreamvhost
import (
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
)
const (
annotation = "ingress.kubernetes.io/upstream-vhost"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"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

@ -19,24 +19,22 @@ package vtsfilterkey
import (
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
)
const (
annotation = "ingress.kubernetes.io/vts-filter-key"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"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

@ -25,12 +25,11 @@ import (
apiv1 "k8s.io/api/core/v1"
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/client-go/tools/cache"
"k8s.io/ingress-nginx/pkg/ingress"
"k8s.io/ingress-nginx/pkg/ingress/annotations/class"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
"k8s.io/ingress-nginx/pkg/net/ssl"
"k8s.io/ingress-nginx/internal/ingress"
"k8s.io/ingress-nginx/internal/ingress/annotations/class"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/net/ssl"
)
// syncSecret keeps in sync Secrets used by Ingress rules with the files on
@ -93,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)
@ -146,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
}
@ -156,18 +155,3 @@ func (ic *NGINXController) checkMissingSecrets() {
}
}
}
// sslCertTracker holds a store of referenced Secrets in Ingress rules
type sslCertTracker struct {
cache.ThreadSafeStore
}
func newSSLCertTracker() *sslCertTracker {
return &sslCertTracker{
cache.NewThreadSafeStore(cache.Indexers{}, cache.Indices{}),
}
}
func (s *sslCertTracker) DeleteAll(key string) {
s.Delete(key)
}

View file

@ -28,9 +28,9 @@ import (
cache_client "k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/flowcontrol"
"k8s.io/ingress-nginx/pkg/ingress"
"k8s.io/ingress-nginx/pkg/ingress/store"
"k8s.io/ingress-nginx/pkg/task"
"k8s.io/ingress-nginx/internal/ingress"
"k8s.io/ingress-nginx/internal/ingress/store"
"k8s.io/ingress-nginx/internal/task"
"k8s.io/kubernetes/pkg/api"
)
@ -110,7 +110,7 @@ func buildGenericControllerForBackendSSL() *NGINXController {
Client: buildSimpleClientSetForBackendSSL(),
},
listers: buildListers(),
sslCertTracker: newSSLCertTracker(),
sslCertTracker: store.NewSSLCertTracker(),
}
gc.syncQueue = task.NewTaskQueue(gc.syncIngress)

View file

@ -27,7 +27,7 @@ import (
"k8s.io/apiserver/pkg/server/healthz"
"k8s.io/kubernetes/pkg/util/filesystem"
ngx_config "k8s.io/ingress-nginx/pkg/ingress/controller/config"
ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
)
func TestNginxCheck(t *testing.T) {

View file

@ -25,8 +25,8 @@ import (
apiv1 "k8s.io/api/core/v1"
"k8s.io/ingress-nginx/pkg/ingress"
"k8s.io/ingress-nginx/pkg/ingress/defaults"
"k8s.io/ingress-nginx/internal/ingress"
"k8s.io/ingress-nginx/internal/ingress/defaults"
)
const (

View file

@ -36,16 +36,17 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
clientset "k8s.io/client-go/kubernetes"
"k8s.io/ingress-nginx/pkg/ingress"
"k8s.io/ingress-nginx/pkg/ingress/annotations/class"
"k8s.io/ingress-nginx/pkg/ingress/annotations/healthcheck"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
"k8s.io/ingress-nginx/pkg/ingress/annotations/proxy"
ngx_config "k8s.io/ingress-nginx/pkg/ingress/controller/config"
"k8s.io/ingress-nginx/pkg/ingress/defaults"
"k8s.io/ingress-nginx/pkg/ingress/resolver"
"k8s.io/ingress-nginx/pkg/k8s"
"k8s.io/ingress-nginx/pkg/task"
"k8s.io/ingress-nginx/internal/ingress"
"k8s.io/ingress-nginx/internal/ingress/annotations"
"k8s.io/ingress-nginx/internal/ingress/annotations/class"
"k8s.io/ingress-nginx/internal/ingress/annotations/healthcheck"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/annotations/proxy"
ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
"k8s.io/ingress-nginx/internal/ingress/defaults"
"k8s.io/ingress-nginx/internal/ingress/resolver"
"k8s.io/ingress-nginx/internal/k8s"
"k8s.io/ingress-nginx/internal/task"
)
const (
@ -65,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
@ -132,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.
@ -316,7 +324,7 @@ func (n *NGINXController) getStreamServices(configmapName string, proto apiv1.Pr
for _, sp := range svc.Spec.Ports {
if sp.Name == svcPort {
if sp.Protocol == proto {
endps = n.getEndpoints(svc, &sp, proto, &healthcheck.Upstream{})
endps = n.getEndpoints(svc, &sp, proto, &healthcheck.Config{})
break
}
}
@ -327,7 +335,7 @@ func (n *NGINXController) getStreamServices(configmapName string, proto apiv1.Pr
for _, sp := range svc.Spec.Ports {
if sp.Port == int32(targetPort) {
if sp.Protocol == proto {
endps = n.getEndpoints(svc, &sp, proto, &healthcheck.Upstream{})
endps = n.getEndpoints(svc, &sp, proto, &healthcheck.Config{})
break
}
}
@ -379,7 +387,7 @@ func (n *NGINXController) getDefaultUpstream() *ingress.Backend {
}
svc := svcObj.(*apiv1.Service)
endps := n.getEndpoints(svc, &svc.Spec.Ports[0], apiv1.ProtocolTCP, &healthcheck.Upstream{})
endps := n.getEndpoints(svc, &svc.Spec.Ports[0], apiv1.ProtocolTCP, &healthcheck.Config{})
if len(endps) == 0 {
glog.Warningf("service %v does not have any active endpoints", svcKey)
endps = []ingress.Endpoint{n.DefaultEndpoint()}
@ -398,8 +406,7 @@ func (n *NGINXController) getBackendServers(ingresses []*extensions.Ingress) ([]
servers := n.createServers(ingresses, upstreams, du)
for _, ing := range ingresses {
affinity := n.annotations.SessionAffinity(ing)
anns := n.annotations.Extract(ing)
anns := n.getIngressAnnotations(ing)
for _, rule := range ing.Spec.Rules {
host := rule.Host
@ -418,13 +425,11 @@ func (n *NGINXController) getBackendServers(ingresses []*extensions.Ingress) ([]
}
if server.CertificateAuth.CAFileName == "" {
ca := n.annotations.CertificateAuth(ing)
if ca != nil {
server.CertificateAuth = *ca
// It is possible that no CAFileName is found in the secret
if server.CertificateAuth.CAFileName == "" {
glog.V(3).Infof("secret %v does not contain 'ca.crt', mutual authentication not enabled - ingress rule %v/%v.", server.CertificateAuth.Secret, ing.Namespace, ing.Name)
}
server.CertificateAuth = anns.CertificateAuth
// It is possible that no CAFileName is found in the secret
if server.CertificateAuth.CAFileName == "" {
glog.V(3).Infof("secret %v does not contain 'ca.crt', mutual authentication not enabled - ingress rule %v/%v.", server.CertificateAuth.Secret, ing.Namespace, ing.Name)
}
} else {
glog.V(3).Infof("server %v already contains a mutual authentication configuration - ingress rule %v/%v", server.Hostname, ing.Namespace, ing.Name)
@ -461,7 +466,20 @@ func (n *NGINXController) getBackendServers(ingresses []*extensions.Ingress) ([]
loc.Port = ups.Port
loc.Service = ups.Service
loc.Ingress = ing
mergeLocationAnnotations(loc, anns)
loc.BasicDigestAuth = anns.BasicDigestAuth
loc.ClientBodyBufferSize = anns.ClientBodyBufferSize
loc.ConfigurationSnippet = anns.ConfigurationSnippet
loc.CorsConfig = anns.CorsConfig
loc.ExternalAuth = anns.ExternalAuth
loc.Proxy = anns.Proxy
loc.RateLimit = anns.RateLimit
loc.Redirect = anns.Redirect
loc.Rewrite = anns.Rewrite
loc.UpstreamVhost = anns.UpstreamVhost
loc.VtsFilterKey = anns.VtsFilterKey
loc.Whitelist = anns.Whitelist
loc.Denied = anns.Denied
if loc.Redirect.FromToWWW {
server.RedirectFromToWWW = true
}
@ -472,14 +490,27 @@ func (n *NGINXController) getBackendServers(ingresses []*extensions.Ingress) ([]
if addLoc {
glog.V(3).Infof("adding location %v in ingress rule %v/%v upstream %v", nginxPath, ing.Namespace, ing.Name, ups.Name)
loc := &ingress.Location{
Path: nginxPath,
Backend: ups.Name,
IsDefBackend: false,
Service: ups.Service,
Port: ups.Port,
Ingress: ing,
Path: nginxPath,
Backend: ups.Name,
IsDefBackend: false,
Service: ups.Service,
Port: ups.Port,
Ingress: ing,
BasicDigestAuth: anns.BasicDigestAuth,
ClientBodyBufferSize: anns.ClientBodyBufferSize,
ConfigurationSnippet: anns.ConfigurationSnippet,
CorsConfig: anns.CorsConfig,
ExternalAuth: anns.ExternalAuth,
Proxy: anns.Proxy,
RateLimit: anns.RateLimit,
Redirect: anns.Redirect,
Rewrite: anns.Rewrite,
UpstreamVhost: anns.UpstreamVhost,
VtsFilterKey: anns.VtsFilterKey,
Whitelist: anns.Whitelist,
Denied: anns.Denied,
}
mergeLocationAnnotations(loc, anns)
if loc.Redirect.FromToWWW {
server.RedirectFromToWWW = true
}
@ -487,12 +518,12 @@ func (n *NGINXController) getBackendServers(ingresses []*extensions.Ingress) ([]
}
if ups.SessionAffinity.AffinityType == "" {
ups.SessionAffinity.AffinityType = affinity.AffinityType
ups.SessionAffinity.AffinityType = anns.SessionAffinity.Type
}
if affinity.AffinityType == "cookie" {
ups.SessionAffinity.CookieSessionAffinity.Name = affinity.CookieConfig.Name
ups.SessionAffinity.CookieSessionAffinity.Hash = affinity.CookieConfig.Hash
if anns.SessionAffinity.Type == "cookie" {
ups.SessionAffinity.CookieSessionAffinity.Name = anns.SessionAffinity.Cookie.Name
ups.SessionAffinity.CookieSessionAffinity.Hash = anns.SessionAffinity.Cookie.Hash
locs := ups.SessionAffinity.CookieSessionAffinity.Locations
if _, ok := locs[host]; !ok {
@ -519,7 +550,7 @@ func (n *NGINXController) getBackendServers(ingresses []*extensions.Ingress) ([]
// check if the location contains endpoints and a custom default backend
if location.DefaultBackend != nil {
sp := location.DefaultBackend.Spec.Ports[0]
endps := n.getEndpoints(location.DefaultBackend, &sp, apiv1.ProtocolTCP, &healthcheck.Upstream{})
endps := n.getEndpoints(location.DefaultBackend, &sp, apiv1.ProtocolTCP, &healthcheck.Config{})
if len(endps) > 0 {
glog.V(3).Infof("using custom default backend in server %v location %v (service %v/%v)",
server.Hostname, location.Path, location.DefaultBackend.Namespace, location.DefaultBackend.Name)
@ -617,10 +648,7 @@ func (n *NGINXController) createUpstreams(data []*extensions.Ingress, du *ingres
upstreams[defUpstreamName] = du
for _, ing := range data {
secUpstream := n.annotations.SecureUpstream(ing)
hz := n.annotations.HealthCheck(ing)
serviceUpstream := n.annotations.ServiceUpstream(ing)
upstreamHashBy := n.annotations.UpstreamHashBy(ing)
anns := n.getIngressAnnotations(ing)
var defBackend string
if ing.Spec.Backend != nil {
@ -635,7 +663,7 @@ func (n *NGINXController) createUpstreams(data []*extensions.Ingress, du *ingres
// Add the service cluster endpoint as the upstream instead of individual endpoints
// if the serviceUpstream annotation is enabled
if serviceUpstream {
if anns.ServiceUpstream {
endpoint, err := n.getServiceClusterEndpoint(svcKey, ing.Spec.Backend)
if err != nil {
glog.Errorf("Failed to get service cluster endpoint for service %s: %v", svcKey, err)
@ -645,7 +673,7 @@ func (n *NGINXController) createUpstreams(data []*extensions.Ingress, du *ingres
}
if len(upstreams[defBackend].Endpoints) == 0 {
endps, err := n.serviceEndpoints(svcKey, ing.Spec.Backend.ServicePort.String(), hz)
endps, err := n.serviceEndpoints(svcKey, ing.Spec.Backend.ServicePort.String(), &anns.HealthCheck)
upstreams[defBackend].Endpoints = append(upstreams[defBackend].Endpoints, endps...)
if err != nil {
glog.Warningf("error creating upstream %v: %v", defBackend, err)
@ -674,22 +702,22 @@ func (n *NGINXController) createUpstreams(data []*extensions.Ingress, du *ingres
upstreams[name].Port = path.Backend.ServicePort
if !upstreams[name].Secure {
upstreams[name].Secure = secUpstream.Secure
upstreams[name].Secure = anns.SecureUpstream.Secure
}
if upstreams[name].SecureCACert.Secret == "" {
upstreams[name].SecureCACert = secUpstream.CACert
upstreams[name].SecureCACert = anns.SecureUpstream.CACert
}
if upstreams[name].UpstreamHashBy == "" {
upstreams[name].UpstreamHashBy = upstreamHashBy
upstreams[name].UpstreamHashBy = anns.UpstreamHashBy
}
svcKey := fmt.Sprintf("%v/%v", ing.GetNamespace(), path.Backend.ServiceName)
// Add the service cluster endpoint as the upstream instead of individual endpoints
// if the serviceUpstream annotation is enabled
if serviceUpstream {
if anns.ServiceUpstream {
endpoint, err := n.getServiceClusterEndpoint(svcKey, &path.Backend)
if err != nil {
glog.Errorf("failed to get service cluster endpoint for service %s: %v", svcKey, err)
@ -699,7 +727,7 @@ func (n *NGINXController) createUpstreams(data []*extensions.Ingress, du *ingres
}
if len(upstreams[name].Endpoints) == 0 {
endp, err := n.serviceEndpoints(svcKey, path.Backend.ServicePort.String(), hz)
endp, err := n.serviceEndpoints(svcKey, path.Backend.ServicePort.String(), &anns.HealthCheck)
if err != nil {
glog.Warningf("error obtaining service endpoints: %v", err)
continue
@ -759,7 +787,7 @@ func (n *NGINXController) getServiceClusterEndpoint(svcKey string, backend *exte
// serviceEndpoints returns the upstream servers (endpoints) associated
// to a service.
func (n *NGINXController) serviceEndpoints(svcKey, backendPort string,
hz *healthcheck.Upstream) ([]ingress.Endpoint, error) {
hz *healthcheck.Config) ([]ingress.Endpoint, error) {
svc, err := n.listers.Service.GetByName(svcKey)
var upstreams []ingress.Endpoint
@ -843,7 +871,7 @@ func (n *NGINXController) createServers(data []*extensions.Ingress,
aliases := make(map[string]string, len(data))
bdef := n.GetDefaultBackend()
ngxProxy := proxy.Configuration{
ngxProxy := proxy.Config{
BodySize: bdef.ProxyBodySize,
ConnectTimeout: bdef.ProxyConnectTimeout,
SendTimeout: bdef.ProxySendTimeout,
@ -884,9 +912,7 @@ func (n *NGINXController) createServers(data []*extensions.Ingress,
// initialize all the servers
for _, ing := range data {
// check if ssl passthrough is configured
sslpt := n.annotations.SSLPassthrough(ing)
anns := n.getIngressAnnotations(ing)
// default upstream server
un := du.Name
@ -930,16 +956,14 @@ func (n *NGINXController) createServers(data []*extensions.Ingress,
Service: &apiv1.Service{},
},
},
SSLPassthrough: sslpt,
SSLPassthrough: anns.SSLPassthrough,
}
}
}
// configure default location, alias, and SSL
for _, ing := range data {
// setup server-alias based on annotations
aliasAnnotation := n.annotations.Alias(ing)
srvsnippet := n.annotations.ServerSnippet(ing)
anns := n.getIngressAnnotations(ing)
for _, rule := range ing.Spec.Rules {
host := rule.Host
@ -948,11 +972,11 @@ func (n *NGINXController) createServers(data []*extensions.Ingress,
}
// setup server aliases
if aliasAnnotation != "" {
if anns.Alias != "" {
if servers[host].Alias == "" {
servers[host].Alias = aliasAnnotation
if _, ok := aliases[aliasAnnotation]; !ok {
aliases[aliasAnnotation] = host
servers[host].Alias = anns.Alias
if _, ok := aliases["Alias"]; !ok {
aliases["Alias"] = host
}
} else {
glog.Warningf("ingress %v/%v for host %v contains an Alias but one has already been configured.",
@ -961,14 +985,14 @@ func (n *NGINXController) createServers(data []*extensions.Ingress,
}
//notifying the user that it has already been configured.
if servers[host].ServerSnippet != "" && srvsnippet != "" {
if servers[host].ServerSnippet != "" && anns.ServerSnippet != "" {
glog.Warningf("ingress %v/%v for host %v contains a Server Snippet section that it has already been configured.",
ing.Namespace, ing.Name, host)
}
// only add a server snippet if the server does not have one previously configured
if servers[host].ServerSnippet == "" && srvsnippet != "" {
servers[host].ServerSnippet = srvsnippet
if servers[host].ServerSnippet == "" && anns.ServerSnippet != "" {
servers[host].ServerSnippet = anns.ServerSnippet
}
// only add a certificate if the server does not have one previously configured
@ -992,8 +1016,7 @@ func (n *NGINXController) createServers(data []*extensions.Ingress,
}
if !found {
glog.Warningf("ingress %v/%v for host %v contains a TLS section but none of the host match",
ing.Namespace, ing.Name, host)
// does not contains a TLS section but none of the host match
continue
}
@ -1044,7 +1067,7 @@ func (n *NGINXController) getEndpoints(
s *apiv1.Service,
servicePort *apiv1.ServicePort,
proto apiv1.Protocol,
hz *healthcheck.Upstream) []ingress.Endpoint {
hz *healthcheck.Config) []ingress.Endpoint {
upsServers := []ingress.Endpoint{}
@ -1141,7 +1164,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
}
@ -1152,6 +1175,7 @@ func (n *NGINXController) isForceReload() bool {
return atomic.LoadInt32(&n.forceReload) != 0
}
// SetForceReload sets if the ingress controller should be reloaded or not
func (n *NGINXController) SetForceReload(shouldReload bool) {
if shouldReload {
atomic.StoreInt32(&n.forceReload, 1)
@ -1160,3 +1184,24 @@ func (n *NGINXController) SetForceReload(shouldReload bool) {
atomic.StoreInt32(&n.forceReload, 0)
}
}
func (n *NGINXController) extractAnnotations(ing *extensions.Ingress) {
anns := n.annotations.Extract(ing)
glog.V(3).Infof("updating annotations information for ingres %v/%v", anns.Namespace, anns.Name)
n.listers.IngressAnnotation.Update(anns)
}
// getByIngress returns the parsed annotations from an Ingress
func (n *NGINXController) getIngressAnnotations(ing *extensions.Ingress) *annotations.Ingress {
key := fmt.Sprintf("%v/%v", ing.Namespace, ing.Name)
item, exists, err := n.listers.IngressAnnotation.GetByKey(key)
if err != nil {
glog.Errorf("unexpected error getting ingress annotation %v: %v", key, err)
return &annotations.Ingress{}
}
if !exists {
glog.Errorf("ingress annotation %v was not found", key)
return &annotations.Ingress{}
}
return item.(*annotations.Ingress)
}

View file

@ -27,10 +27,11 @@ import (
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/tools/cache"
cache_client "k8s.io/client-go/tools/cache"
"k8s.io/ingress-nginx/pkg/ingress"
"k8s.io/ingress-nginx/pkg/ingress/annotations/class"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress"
"k8s.io/ingress-nginx/internal/ingress/annotations/class"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
)
type cacheController struct {
@ -60,19 +61,17 @@ func (c *cacheController) Run(stopCh chan struct{}) {
}
}
func (n *NGINXController) createListers(stopCh chan struct{}) *ingress.StoreLister {
// from here to the end of the method all the code is just boilerplate
// required to watch Ingress, Secrets, ConfigMaps and Endoints.
// This is used to detect new content, updates or removals and act accordingly
func (n *NGINXController) createListers(stopCh chan struct{}) (*ingress.StoreLister, *cacheController) {
ingEventHandler := cache.ResourceEventHandlerFuncs{
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
}
n.extractAnnotations(addIng)
n.recorder.Eventf(addIng, apiv1.EventTypeNormal, "CREATE", fmt.Sprintf("Ingress %s/%s", addIng.Namespace, addIng.Name))
n.syncQueue.Enqueue(obj)
},
@ -96,6 +95,7 @@ func (n *NGINXController) createListers(stopCh chan struct{}) *ingress.StoreList
return
}
n.recorder.Eventf(delIng, apiv1.EventTypeNormal, "DELETE", fmt.Sprintf("Ingress %s/%s", delIng.Namespace, delIng.Name))
n.listers.IngressAnnotation.Delete(delIng)
n.syncQueue.Enqueue(obj)
},
UpdateFunc: func(old, cur interface{}) {
@ -113,6 +113,7 @@ func (n *NGINXController) createListers(stopCh chan struct{}) *ingress.StoreList
n.recorder.Eventf(curIng, apiv1.EventTypeNormal, "UPDATE", fmt.Sprintf("Ingress %s/%s", curIng.Namespace, curIng.Name))
}
n.extractAnnotations(curIng)
n.syncQueue.Enqueue(cur)
},
}
@ -141,7 +142,7 @@ func (n *NGINXController) createListers(stopCh chan struct{}) *ingress.StoreList
}
}
key := fmt.Sprintf("%v/%v", sec.Namespace, sec.Name)
n.sslCertTracker.DeleteAll(key)
n.sslCertTracker.Delete(key)
n.syncQueue.Enqueue(key)
},
}
@ -196,6 +197,7 @@ func (n *NGINXController) createListers(stopCh chan struct{}) *ingress.StoreList
}
lister := &ingress.StoreLister{}
lister.IngressAnnotation.Store = cache_client.NewStore(cache_client.DeletionHandlingMetaNamespaceKeyFunc)
controller := &cacheController{}
@ -219,7 +221,5 @@ func (n *NGINXController) createListers(stopCh chan struct{}) *ingress.StoreList
cache.NewListWatchFromClient(n.cfg.Client.CoreV1().RESTClient(), "services", n.cfg.Namespace, fields.Everything()),
&apiv1.Service{}, n.cfg.ResyncPeriod, cache.ResourceEventHandlerFuncs{})
controller.Run(n.stopCh)
return lister
return lister, controller
}

View file

@ -19,7 +19,7 @@ package controller
import (
"github.com/prometheus/client_golang/prometheus"
"k8s.io/ingress-nginx/pkg/ingress"
"k8s.io/ingress-nginx/internal/ingress"
)
const (

View file

@ -42,18 +42,20 @@ import (
"k8s.io/client-go/util/flowcontrol"
"k8s.io/kubernetes/pkg/util/filesystem"
"k8s.io/ingress-nginx/pkg/ingress"
"k8s.io/ingress-nginx/pkg/ingress/annotations/class"
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
ngx_config "k8s.io/ingress-nginx/pkg/ingress/controller/config"
"k8s.io/ingress-nginx/pkg/ingress/controller/process"
ngx_template "k8s.io/ingress-nginx/pkg/ingress/controller/template"
"k8s.io/ingress-nginx/pkg/ingress/defaults"
"k8s.io/ingress-nginx/pkg/ingress/status"
ing_net "k8s.io/ingress-nginx/pkg/net"
"k8s.io/ingress-nginx/pkg/net/dns"
"k8s.io/ingress-nginx/pkg/net/ssl"
"k8s.io/ingress-nginx/pkg/task"
"k8s.io/ingress-nginx/internal/ingress"
"k8s.io/ingress-nginx/internal/ingress/annotations"
"k8s.io/ingress-nginx/internal/ingress/annotations/class"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
"k8s.io/ingress-nginx/internal/ingress/controller/process"
ngx_template "k8s.io/ingress-nginx/internal/ingress/controller/template"
"k8s.io/ingress-nginx/internal/ingress/defaults"
"k8s.io/ingress-nginx/internal/ingress/status"
"k8s.io/ingress-nginx/internal/ingress/store"
ing_net "k8s.io/ingress-nginx/internal/net"
"k8s.io/ingress-nginx/internal/net/dns"
"k8s.io/ingress-nginx/internal/net/ssl"
"k8s.io/ingress-nginx/internal/task"
)
type statusModule string
@ -102,7 +104,7 @@ func NewNGINXController(config *Configuration) *NGINXController {
resolver: h,
cfg: config,
sslCertTracker: newSSLCertTracker(),
sslCertTracker: store.NewSSLCertTracker(),
syncRateLimiter: flowcontrol.NewTokenBucketRateLimiter(0.3, 1),
recorder: eventBroadcaster.NewRecorder(scheme.Scheme, apiv1.EventSource{
@ -115,11 +117,13 @@ func NewNGINXController(config *Configuration) *NGINXController {
fileSystem: filesystem.DefaultFs{},
}
n.listers, n.controllers = n.createListers(n.stopCh)
n.stats = newStatsCollector(config.Namespace, config.IngressClass, n.binary, n.cfg.ListenPorts.Status)
n.syncQueue = task.NewTaskQueue(n.syncIngress)
n.listers = n.createListers(n.stopCh)
n.annotations = annotations.NewAnnotationExtractor(n)
if config.UpdateStatus {
n.syncStatus = status.NewStatusSyncer(status.Config{
@ -135,7 +139,6 @@ func NewNGINXController(config *Configuration) *NGINXController {
} else {
glog.Warning("Update of ingress status is disabled (flag --update-status=false was specified)")
}
n.annotations = newAnnotationExtractor(n)
var onChange func()
onChange = func() {
@ -170,9 +173,10 @@ Error loading new template : %v
type NGINXController struct {
cfg *Configuration
listers *ingress.StoreLister
listers *ingress.StoreLister
controllers *cacheController
annotations annotationExtractor
annotations annotations.Extractor
recorder record.EventRecorder
@ -182,7 +186,7 @@ type NGINXController struct {
// local store of SSL certificates
// (only certificates used in ingress)
sslCertTracker *sslCertTracker
sslCertTracker *store.SSLCertTracker
syncRateLimiter flowcontrol.RateLimiter
@ -234,13 +238,15 @@ type NGINXController struct {
func (n *NGINXController) Start() {
glog.Infof("starting Ingress controller")
n.controllers.Run(n.stopCh)
// initial sync of secrets to avoid unnecessary reloads
glog.Info("running initial sync of secrets")
for _, obj := range n.listers.Ingress.List() {
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
}
@ -425,12 +431,12 @@ func (n *NGINXController) SetConfig(cmap *apiv1.ConfigMap) {
n.backendDefaults = c.Backend
}
// OnUpdate is called by syncQueue in https://github.com/kubernetes/ingress-nginx/blob/master/pkg/ingress/controller/controller.go#L426
// periodically to keep the configuration in sync.
// OnUpdate is called periodically by syncQueue to keep the configuration in sync.
//
// 1. converts configmap configuration to custom configuration object
// 2. write the custom template (the complexity depends on the implementation)
// 3. write the configuration file
//
// convert configmap to custom configuration object (different in each implementation)
// write the custom template (the complexity depends on the implementation)
// write the configuration file
// returning nill implies the backend will be reloaded.
// if an error is returned means requeue the update
func (n *NGINXController) OnUpdate(ingressCfg ingress.Configuration) error {

View file

@ -20,7 +20,7 @@ import (
"github.com/golang/glog"
"github.com/prometheus/client_golang/prometheus"
"k8s.io/ingress-nginx/pkg/ingress/controller/metric/collector"
"k8s.io/ingress-nginx/internal/ingress/controller/metric/collector"
)
const (

View file

@ -0,0 +1,51 @@
/*
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 template
import (
"bytes"
"sync"
)
// BufferPool defines a Pool of Buffers
type BufferPool struct {
sync.Pool
}
// NewBufferPool creates a new BufferPool with a custom buffer size
func NewBufferPool(s int) *BufferPool {
return &BufferPool{
Pool: sync.Pool{
New: func() interface{} {
b := bytes.NewBuffer(make([]byte, s))
b.Reset()
return b
},
},
}
}
// Get returns a Buffer from the pool
func (bp *BufferPool) Get() *bytes.Buffer {
return bp.Pool.Get().(*bytes.Buffer)
}
// Put resets ans returns a Buffer to the pool
func (bp *BufferPool) Put(b *bytes.Buffer) {
b.Reset()
bp.Pool.Put(b)
}

View file

@ -26,8 +26,8 @@ import (
"github.com/mitchellh/mapstructure"
"k8s.io/ingress-nginx/pkg/ingress/controller/config"
ing_net "k8s.io/ingress-nginx/pkg/net"
"k8s.io/ingress-nginx/internal/ingress/controller/config"
ing_net "k8s.io/ingress-nginx/internal/net"
)
const (

View file

@ -21,7 +21,7 @@ import (
"github.com/kylelemons/godebug/pretty"
"k8s.io/ingress-nginx/pkg/ingress/controller/config"
"k8s.io/ingress-nginx/internal/ingress/controller/config"
)
func TestFilterErrors(t *testing.T) {

View file

@ -17,7 +17,6 @@ limitations under the License.
package template
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
@ -35,11 +34,11 @@ import (
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/ingress-nginx/pkg/ingress"
"k8s.io/ingress-nginx/pkg/ingress/annotations/ratelimit"
"k8s.io/ingress-nginx/pkg/ingress/controller/config"
ing_net "k8s.io/ingress-nginx/pkg/net"
"k8s.io/ingress-nginx/pkg/watch"
"k8s.io/ingress-nginx/internal/ingress"
"k8s.io/ingress-nginx/internal/ingress/annotations/ratelimit"
"k8s.io/ingress-nginx/internal/ingress/controller/config"
ing_net "k8s.io/ingress-nginx/internal/net"
"k8s.io/ingress-nginx/internal/watch"
)
const (
@ -52,7 +51,7 @@ const (
type Template struct {
tmpl *text_template.Template
fw watch.FileWatcher
s int
bp *BufferPool
}
//NewTemplate returns a new Template instance or an
@ -70,7 +69,7 @@ func NewTemplate(file string, onChange func()) (*Template, error) {
return &Template{
tmpl: tmpl,
fw: fw,
s: defBufferSize,
bp: NewBufferPool(defBufferSize),
}, nil
}
@ -82,15 +81,11 @@ func (t *Template) Close() {
// Write populates a buffer using a template with NGINX configuration
// and the servers and upstreams created by Ingress rules
func (t *Template) Write(conf config.TemplateConfig) ([]byte, error) {
tmplBuf := bytes.NewBuffer(make([]byte, 0, t.s))
outCmdBuf := bytes.NewBuffer(make([]byte, 0, t.s))
tmplBuf := t.bp.Get()
defer t.bp.Put(tmplBuf)
defer func() {
if t.s < tmplBuf.Cap() {
glog.V(2).Infof("adjusting template buffer size from %v to %v", t.s, tmplBuf.Cap())
t.s = tmplBuf.Cap()
}
}()
outCmdBuf := t.bp.Get()
defer t.bp.Put(outCmdBuf)
if glog.V(3) {
b, err := json.Marshal(conf)
@ -198,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 {
@ -273,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)
@ -354,8 +349,8 @@ func buildProxyPass(host string, b interface{}, loc interface{}) string {
}
// TODO: Needs Unit Tests
func filterRateLimits(input interface{}) []ratelimit.RateLimit {
ratelimits := []ratelimit.RateLimit{}
func filterRateLimits(input interface{}) []ratelimit.Config {
ratelimits := []ratelimit.Config{}
found := sets.String{}
servers, ok := input.([]*ingress.Server)

View file

@ -26,10 +26,10 @@ import (
"strings"
"testing"
"k8s.io/ingress-nginx/pkg/ingress"
"k8s.io/ingress-nginx/pkg/ingress/annotations/authreq"
"k8s.io/ingress-nginx/pkg/ingress/annotations/rewrite"
"k8s.io/ingress-nginx/pkg/ingress/controller/config"
"k8s.io/ingress-nginx/internal/ingress"
"k8s.io/ingress-nginx/internal/ingress/annotations/authreq"
"k8s.io/ingress-nginx/internal/ingress/annotations/rewrite"
"k8s.io/ingress-nginx/internal/ingress/controller/config"
)
var (
@ -114,7 +114,7 @@ func TestBuildLocation(t *testing.T) {
for k, tc := range tmplFuncTestcases {
loc := &ingress.Location{
Path: tc.Path,
Rewrite: rewrite.Redirect{Target: tc.Target, AddBaseURL: tc.AddBaseURL},
Rewrite: rewrite.Config{Target: tc.Target, AddBaseURL: tc.AddBaseURL},
}
newLoc := buildLocation(loc)
@ -128,7 +128,7 @@ func TestBuildProxyPass(t *testing.T) {
for k, tc := range tmplFuncTestcases {
loc := &ingress.Location{
Path: tc.Path,
Rewrite: rewrite.Redirect{Target: tc.Target, AddBaseURL: tc.AddBaseURL, BaseURLScheme: tc.BaseURLScheme},
Rewrite: rewrite.Config{Target: tc.Target, AddBaseURL: tc.AddBaseURL, BaseURLScheme: tc.BaseURLScheme},
Backend: "upstream-name",
}
@ -141,7 +141,7 @@ func TestBuildProxyPass(t *testing.T) {
func TestBuildAuthResponseHeaders(t *testing.T) {
loc := &ingress.Location{
ExternalAuth: authreq.External{ResponseHeaders: []string{"h1", "H-With-Caps-And-Dashes"}},
ExternalAuth: authreq.Config{ResponseHeaders: []string{"h1", "H-With-Caps-And-Dashes"}},
}
headers := buildAuthResponseHeaders(loc)
expected := []string{

View file

@ -21,17 +21,12 @@ import (
"github.com/golang/glog"
"github.com/imdario/mergo"
api "k8s.io/api/core/v1"
"k8s.io/kubernetes/pkg/util/sysctl"
"k8s.io/ingress-nginx/pkg/ingress"
"k8s.io/ingress-nginx/internal/ingress"
)
// DeniedKeyName name of the key that contains the reason to deny a location
const DeniedKeyName = "Denied"
// newUpstream creates an upstream without servers.
func newUpstream(name string) *ingress.Backend {
return &ingress.Backend{
@ -46,17 +41,6 @@ func newUpstream(name string) *ingress.Backend {
}
}
func mergeLocationAnnotations(loc *ingress.Location, anns map[string]interface{}) {
if _, ok := anns[DeniedKeyName]; ok {
loc.Denied = anns[DeniedKeyName].(error)
}
delete(anns, DeniedKeyName)
err := mergo.Map(loc, anns)
if err != nil {
glog.Errorf("unexpected error merging extracted annotations in location type: %v", err)
}
}
// sysctlSomaxconn returns the value of net.core.somaxconn, i.e.
// maximum number of connections that can be queued for acceptance
// http://nginx.org/en/docs/http/ngx_http_core_module.html#listen

View file

@ -0,0 +1,61 @@
/*
Copyright 2015 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 controller
import (
"testing"
)
type fakeError struct{}
func (fe *fakeError) Error() string {
return "fakeError"
}
func TestIntInSlice(t *testing.T) {
fooTests := []struct {
i int
list []int
er bool
}{
{1, []int{1, 2}, true},
{3, []int{1, 2}, false},
{1, nil, false},
{0, nil, false},
}
for _, fooTest := range fooTests {
r := intInSlice(fooTest.i, fooTest.list)
if r != fooTest.er {
t.Errorf("returned %t but expected %t for s=%v & list=%v", r, fooTest.er, fooTest.i, fooTest.list)
}
}
}
func TestSysctlFSFileMax(t *testing.T) {
i := sysctlFSFileMax()
if i < 1 {
t.Errorf("returned %v but expected > 0", i)
}
}
func TestSysctlSomaxconn(t *testing.T) {
i := sysctlSomaxconn()
if i < 511 {
t.Errorf("returned %v but expected >= 511", i)
}
}

View file

@ -19,32 +19,27 @@ package resolver
import (
apiv1 "k8s.io/api/core/v1"
"k8s.io/ingress-nginx/pkg/ingress/defaults"
"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)
}

View file

@ -40,10 +40,10 @@ import (
"k8s.io/client-go/tools/record"
"k8s.io/kubernetes/pkg/kubelet/util/sliceutils"
"k8s.io/ingress-nginx/pkg/ingress/annotations/class"
"k8s.io/ingress-nginx/pkg/ingress/store"
"k8s.io/ingress-nginx/pkg/k8s"
"k8s.io/ingress-nginx/pkg/task"
"k8s.io/ingress-nginx/internal/ingress/annotations/class"
"k8s.io/ingress-nginx/internal/ingress/store"
"k8s.io/ingress-nginx/internal/k8s"
"k8s.io/ingress-nginx/internal/task"
)
const (

View file

@ -28,10 +28,10 @@ import (
"k8s.io/client-go/tools/cache"
"k8s.io/kubernetes/pkg/api"
"k8s.io/ingress-nginx/pkg/ingress/annotations/class"
"k8s.io/ingress-nginx/pkg/ingress/store"
"k8s.io/ingress-nginx/pkg/k8s"
"k8s.io/ingress-nginx/pkg/task"
"k8s.io/ingress-nginx/internal/ingress/annotations/class"
"k8s.io/ingress-nginx/internal/ingress/store"
"k8s.io/ingress-nginx/internal/k8s"
"k8s.io/ingress-nginx/internal/task"
)
func buildLoadBalancerIngressByIP() []apiv1.LoadBalancerIngress {

View file

@ -28,6 +28,11 @@ type IngressLister struct {
cache.Store
}
// IngressAnnotationsLister makes a Store that lists annotations in Ingress rules.
type IngressAnnotationsLister struct {
cache.Store
}
// SecretLister makes a Store that lists Secrets.
type SecretLister struct {
cache.Store
@ -94,3 +99,15 @@ func (s *EndpointLister) GetServiceEndpoints(svc *apiv1.Service) (*apiv1.Endpoin
}
return nil, fmt.Errorf("could not find endpoints for service: %v", svc.Name)
}
// SSLCertTracker holds a store of referenced Secrets in Ingress rules
type SSLCertTracker struct {
cache.ThreadSafeStore
}
// NewSSLCertTracker creates a new SSLCertTracker store
func NewSSLCertTracker() *SSLCertTracker {
return &SSLCertTracker{
cache.NewThreadSafeStore(cache.Indexers{}, cache.Indices{}),
}
}

View file

@ -23,17 +23,17 @@ import (
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/util/intstr"
"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/cors"
"k8s.io/ingress-nginx/pkg/ingress/annotations/ipwhitelist"
"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/resolver"
"k8s.io/ingress-nginx/pkg/ingress/store"
"k8s.io/ingress-nginx/internal/ingress/annotations/auth"
"k8s.io/ingress-nginx/internal/ingress/annotations/authreq"
"k8s.io/ingress-nginx/internal/ingress/annotations/authtls"
"k8s.io/ingress-nginx/internal/ingress/annotations/cors"
"k8s.io/ingress-nginx/internal/ingress/annotations/ipwhitelist"
"k8s.io/ingress-nginx/internal/ingress/annotations/proxy"
"k8s.io/ingress-nginx/internal/ingress/annotations/ratelimit"
"k8s.io/ingress-nginx/internal/ingress/annotations/redirect"
"k8s.io/ingress-nginx/internal/ingress/annotations/rewrite"
"k8s.io/ingress-nginx/internal/ingress/resolver"
"k8s.io/ingress-nginx/internal/ingress/store"
)
var (
@ -47,11 +47,12 @@ var (
// StoreLister returns the configured stores for ingresses, services,
// endpoints, secrets and configmaps.
type StoreLister struct {
Ingress store.IngressLister
Service store.ServiceLister
Endpoint store.EndpointLister
Secret store.SecretLister
ConfigMap store.ConfigMapLister
Ingress store.IngressLister
Service store.ServiceLister
Endpoint store.EndpointLister
Secret store.SecretLister
ConfigMap store.ConfigMapLister
IngressAnnotation store.IngressAnnotationsLister
}
// Configuration holds the definition of all the parts required to describe all
@ -165,7 +166,7 @@ type Server struct {
RedirectFromToWWW bool `json:"redirectFromToWWW,omitempty"`
// CertificateAuth indicates the this server requires mutual authentication
// +optional
CertificateAuth authtls.AuthSSLConfig `json:"certificateAuth"`
CertificateAuth authtls.Config `json:"certificateAuth"`
// ServerSnippet returns the snippet of server
// +optional
@ -211,28 +212,28 @@ type Location struct {
// BasicDigestAuth returns authentication configuration for
// an Ingress rule.
// +optional
BasicDigestAuth auth.BasicDigest `json:"basicDigestAuth,omitempty"`
BasicDigestAuth auth.Config `json:"basicDigestAuth,omitempty"`
// Denied returns an error when this location cannot not be allowed
// Requesting a denied location should return HTTP code 403.
Denied error `json:"denied,omitempty"`
// CorsConfig returns the Cors Configration for the ingress rule
// +optional
CorsConfig cors.CorsConfig `json:"corsConfig,omitempty"`
CorsConfig cors.Config `json:"corsConfig,omitempty"`
// ExternalAuth indicates the access to this location requires
// authentication using an external provider
// +optional
ExternalAuth authreq.External `json:"externalAuth,omitempty"`
ExternalAuth authreq.Config `json:"externalAuth,omitempty"`
// RateLimit describes a limit in the number of connections per IP
// address or connections per second.
// The Redirect annotation precedes RateLimit
// +optional
RateLimit ratelimit.RateLimit `json:"rateLimit,omitempty"`
RateLimit ratelimit.Config `json:"rateLimit,omitempty"`
// Redirect describes a temporal o permanent redirection this location.
// +optional
Redirect redirect.Redirect `json:"redirect,omitempty"`
Redirect redirect.Config `json:"redirect,omitempty"`
// Rewrite describes the redirection this location.
// +optional
Rewrite rewrite.Redirect `json:"rewrite,omitempty"`
Rewrite rewrite.Config `json:"rewrite,omitempty"`
// Whitelist indicates only connections from certain client
// addresses or networks are allowed.
// +optional
@ -240,7 +241,7 @@ type Location struct {
// Proxy contains information about timeouts and buffer sizes
// to be used in connections against endpoints
// +optional
Proxy proxy.Configuration `json:"proxy,omitempty"`
Proxy proxy.Config `json:"proxy,omitempty"`
// UsePortInRedirects indicates if redirects must specify the port
// +optional
UsePortInRedirects bool `json:"usePortInRedirects"`

Some files were not shown because too many files have changed in this diff Show more