Refactor annotations
This commit is contained in:
parent
f215828b1b
commit
fb33c58d18
33 changed files with 370 additions and 401 deletions
|
@ -14,12 +14,15 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
package annotations
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
"github.com/imdario/mergo"
|
||||
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/alias"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/auth"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/authreq"
|
||||
|
@ -48,51 +51,89 @@ import (
|
|||
"k8s.io/ingress-nginx/pkg/ingress/resolver"
|
||||
)
|
||||
|
||||
type extractorConfig interface {
|
||||
// DeniedKeyName name of the key that contains the reason to deny a location
|
||||
const DeniedKeyName = "Denied"
|
||||
|
||||
type config interface {
|
||||
resolver.AuthCertificate
|
||||
resolver.DefaultBackend
|
||||
resolver.Secret
|
||||
resolver.Service
|
||||
}
|
||||
|
||||
type annotationExtractor struct {
|
||||
// Ingress defines the valid annotations present in one NGINX Ingress rule
|
||||
type Ingress struct {
|
||||
metav1.ObjectMeta
|
||||
Alias string
|
||||
BasicDigestAuth auth.Config
|
||||
CertificateAuth authtls.Config
|
||||
ClientBodyBufferSize string
|
||||
ConfigurationSnippet string
|
||||
CorsConfig cors.Config
|
||||
DefaultBackend string
|
||||
ExternalAuth authreq.Config
|
||||
HealthCheck healthcheck.Config
|
||||
Proxy proxy.Config
|
||||
RateLimit ratelimit.Config
|
||||
Redirect redirect.Config
|
||||
Rewrite rewrite.Config
|
||||
SecureUpstream secureupstream.Config
|
||||
ServerSnippet string
|
||||
ServiceUpstream bool
|
||||
SessionAffinity sessionaffinity.Config
|
||||
SSLPassthrough bool
|
||||
UsePortInRedirects bool
|
||||
UpstreamHashBy string
|
||||
UpstreamVhost string
|
||||
VtsFilterKey string
|
||||
Whitelist ipwhitelist.SourceRange
|
||||
}
|
||||
|
||||
// Extractor defines the annotation parsers to be used in the extraction of annotations
|
||||
type Extractor struct {
|
||||
secretResolver resolver.Secret
|
||||
annotations map[string]parser.IngressAnnotation
|
||||
}
|
||||
|
||||
func newAnnotationExtractor(cfg extractorConfig) annotationExtractor {
|
||||
return annotationExtractor{
|
||||
// NewAnnotationExtractor creates a new annotations extractor
|
||||
func NewAnnotationExtractor(cfg config) Extractor {
|
||||
return Extractor{
|
||||
cfg,
|
||||
map[string]parser.IngressAnnotation{
|
||||
"Alias": alias.NewParser(),
|
||||
"BasicDigestAuth": auth.NewParser(auth.AuthDirectory, cfg),
|
||||
"ExternalAuth": authreq.NewParser(),
|
||||
"CertificateAuth": authtls.NewParser(cfg),
|
||||
"ClientBodyBufferSize": clientbodybuffersize.NewParser(),
|
||||
"ConfigurationSnippet": snippet.NewParser(),
|
||||
"CorsConfig": cors.NewParser(),
|
||||
"DefaultBackend": defaultbackend.NewParser(cfg),
|
||||
"ExternalAuth": authreq.NewParser(),
|
||||
"HealthCheck": healthcheck.NewParser(cfg),
|
||||
"Whitelist": ipwhitelist.NewParser(cfg),
|
||||
"UsePortInRedirects": portinredirect.NewParser(cfg),
|
||||
"Proxy": proxy.NewParser(cfg),
|
||||
"RateLimit": ratelimit.NewParser(cfg),
|
||||
"Redirect": redirect.NewParser(),
|
||||
"Rewrite": rewrite.NewParser(cfg),
|
||||
"SecureUpstream": secureupstream.NewParser(cfg),
|
||||
"ServerSnippet": serversnippet.NewParser(),
|
||||
"ServiceUpstream": serviceupstream.NewParser(),
|
||||
"SessionAffinity": sessionaffinity.NewParser(),
|
||||
"SSLPassthrough": sslpassthrough.NewParser(),
|
||||
"ConfigurationSnippet": snippet.NewParser(),
|
||||
"Alias": alias.NewParser(),
|
||||
"ClientBodyBufferSize": clientbodybuffersize.NewParser(),
|
||||
"DefaultBackend": defaultbackend.NewParser(cfg),
|
||||
"UsePortInRedirects": portinredirect.NewParser(cfg),
|
||||
"UpstreamHashBy": upstreamhashby.NewParser(),
|
||||
"UpstreamVhost": upstreamvhost.NewParser(),
|
||||
"VtsFilterKey": vtsfilterkey.NewParser(),
|
||||
"ServerSnippet": serversnippet.NewParser(),
|
||||
"Whitelist": ipwhitelist.NewParser(cfg),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (e *annotationExtractor) Extract(ing *extensions.Ingress) map[string]interface{} {
|
||||
anns := make(map[string]interface{})
|
||||
// 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)
|
||||
|
@ -105,9 +146,9 @@ func (e *annotationExtractor) Extract(ing *extensions.Ingress) map[string]interf
|
|||
continue
|
||||
}
|
||||
|
||||
_, alreadyDenied := anns[DeniedKeyName]
|
||||
_, alreadyDenied := data[DeniedKeyName]
|
||||
if !alreadyDenied {
|
||||
anns[DeniedKeyName] = err
|
||||
data[DeniedKeyName] = err
|
||||
glog.Errorf("error reading %v annotation in Ingress %v/%v: %v", name, ing.GetNamespace(), ing.GetName(), err)
|
||||
continue
|
||||
}
|
||||
|
@ -116,90 +157,14 @@ func (e *annotationExtractor) Extract(ing *extensions.Ingress) map[string]interf
|
|||
}
|
||||
|
||||
if val != nil {
|
||||
anns[name] = val
|
||||
data[name] = val
|
||||
}
|
||||
}
|
||||
|
||||
return anns
|
||||
}
|
||||
|
||||
const (
|
||||
secureUpstream = "SecureUpstream"
|
||||
healthCheck = "HealthCheck"
|
||||
sslPassthrough = "SSLPassthrough"
|
||||
sessionAffinity = "SessionAffinity"
|
||||
serviceUpstream = "ServiceUpstream"
|
||||
serverAlias = "Alias"
|
||||
corsConfig = "CorsConfig"
|
||||
clientBodyBufferSize = "ClientBodyBufferSize"
|
||||
certificateAuth = "CertificateAuth"
|
||||
serverSnippet = "ServerSnippet"
|
||||
upstreamHashBy = "UpstreamHashBy"
|
||||
)
|
||||
|
||||
func (e *annotationExtractor) ServiceUpstream(ing *extensions.Ingress) bool {
|
||||
val, _ := e.annotations[serviceUpstream].Parse(ing)
|
||||
return val.(bool)
|
||||
}
|
||||
|
||||
func (e *annotationExtractor) SecureUpstream(ing *extensions.Ingress) *secureupstream.Secure {
|
||||
val, err := e.annotations[secureUpstream].Parse(ing)
|
||||
err := mergo.Map(pia, data)
|
||||
if err != nil {
|
||||
glog.Errorf("error parsing secure upstream: %v", err)
|
||||
}
|
||||
secure := val.(*secureupstream.Secure)
|
||||
return secure
|
||||
}
|
||||
|
||||
func (e *annotationExtractor) HealthCheck(ing *extensions.Ingress) *healthcheck.Upstream {
|
||||
val, _ := e.annotations[healthCheck].Parse(ing)
|
||||
return val.(*healthcheck.Upstream)
|
||||
}
|
||||
|
||||
func (e *annotationExtractor) SSLPassthrough(ing *extensions.Ingress) bool {
|
||||
val, _ := e.annotations[sslPassthrough].Parse(ing)
|
||||
return val.(bool)
|
||||
}
|
||||
|
||||
func (e *annotationExtractor) Alias(ing *extensions.Ingress) string {
|
||||
val, _ := e.annotations[serverAlias].Parse(ing)
|
||||
return val.(string)
|
||||
}
|
||||
|
||||
func (e *annotationExtractor) ClientBodyBufferSize(ing *extensions.Ingress) string {
|
||||
val, _ := e.annotations[clientBodyBufferSize].Parse(ing)
|
||||
return val.(string)
|
||||
}
|
||||
|
||||
func (e *annotationExtractor) SessionAffinity(ing *extensions.Ingress) *sessionaffinity.AffinityConfig {
|
||||
val, _ := e.annotations[sessionAffinity].Parse(ing)
|
||||
return val.(*sessionaffinity.AffinityConfig)
|
||||
}
|
||||
|
||||
func (e *annotationExtractor) Cors(ing *extensions.Ingress) *cors.CorsConfig {
|
||||
val, _ := e.annotations[corsConfig].Parse(ing)
|
||||
return val.(*cors.CorsConfig)
|
||||
}
|
||||
|
||||
func (e *annotationExtractor) CertificateAuth(ing *extensions.Ingress) *authtls.AuthSSLConfig {
|
||||
val, err := e.annotations[certificateAuth].Parse(ing)
|
||||
if errors.IsMissingAnnotations(err) {
|
||||
return nil
|
||||
glog.Errorf("unexpected error merging extracted annotations: %v", err)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
glog.Errorf("error parsing certificate auth: %v", err)
|
||||
}
|
||||
secure := val.(*authtls.AuthSSLConfig)
|
||||
return secure
|
||||
}
|
||||
|
||||
func (e *annotationExtractor) ServerSnippet(ing *extensions.Ingress) string {
|
||||
val, _ := e.annotations[serverSnippet].Parse(ing)
|
||||
return val.(string)
|
||||
}
|
||||
|
||||
func (e *annotationExtractor) UpstreamHashBy(ing *extensions.Ingress) string {
|
||||
val, _ := e.annotations[upstreamHashBy].Parse(ing)
|
||||
return val.(string)
|
||||
return pia
|
||||
}
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
package annotations
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
@ -75,20 +75,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 +111,7 @@ func buildIngress() *extensions.Ingress {
|
|||
}
|
||||
|
||||
func TestSecureUpstream(t *testing.T) {
|
||||
ec := newAnnotationExtractor(mockCfg{})
|
||||
ec := NewAnnotationExtractor(mockCfg{})
|
||||
ing := buildIngress()
|
||||
|
||||
fooAnns := []struct {
|
||||
|
@ -141,7 +127,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 +135,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 +162,16 @@ 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 {
|
||||
res := ec.Extract(ing).SecureUpstream
|
||||
|
||||
if (res != nil && res.CACert.CAFileName != "") != ann.exists {
|
||||
t.Errorf("Expected exists was %v on iteration %v", ann.exists, ann.it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHealthCheck(t *testing.T) {
|
||||
ec := newAnnotationExtractor(mockCfg{})
|
||||
ec := NewAnnotationExtractor(mockCfg{})
|
||||
ing := buildIngress()
|
||||
|
||||
fooAnns := []struct {
|
||||
|
@ -201,7 +188,7 @@ func TestHealthCheck(t *testing.T) {
|
|||
|
||||
for _, foo := range fooAnns {
|
||||
ing.SetAnnotations(foo.annotations)
|
||||
r := ec.HealthCheck(ing)
|
||||
r := ec.Extract(ing).HealthCheck
|
||||
if r == nil {
|
||||
t.Errorf("Returned nil but expected a healthcheck.Upstream")
|
||||
continue
|
||||
|
@ -218,7 +205,7 @@ func TestHealthCheck(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSSLPassthrough(t *testing.T) {
|
||||
ec := newAnnotationExtractor(mockCfg{})
|
||||
ec := NewAnnotationExtractor(mockCfg{})
|
||||
ing := buildIngress()
|
||||
|
||||
fooAnns := []struct {
|
||||
|
@ -234,7 +221,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 +229,7 @@ func TestSSLPassthrough(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUpstreamHashBy(t *testing.T) {
|
||||
ec := newAnnotationExtractor(mockCfg{})
|
||||
ec := NewAnnotationExtractor(mockCfg{})
|
||||
ing := buildIngress()
|
||||
|
||||
fooAnns := []struct {
|
||||
|
@ -258,7 +245,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 +253,7 @@ func TestUpstreamHashBy(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAffinitySession(t *testing.T) {
|
||||
ec := newAnnotationExtractor(mockCfg{})
|
||||
ec := NewAnnotationExtractor(mockCfg{})
|
||||
ing := buildIngress()
|
||||
|
||||
fooAnns := []struct {
|
||||
|
@ -284,25 +271,25 @@ 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.CookieConfig.Hash != foo.hash {
|
||||
t.Errorf("Returned %v but expected %v for Hash", r.CookieConfig.Hash, foo.hash)
|
||||
if r.Cookie.Hash != foo.hash {
|
||||
t.Errorf("Returned %v but expected %v for Hash", r.Cookie.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,7 +309,7 @@ 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")
|
||||
|
@ -351,3 +338,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)
|
||||
}
|
||||
}
|
||||
*/
|
|
@ -46,8 +46,8 @@ var (
|
|||
AuthDirectory = "/etc/ingress-controller/auth"
|
||||
)
|
||||
|
||||
// BasicDigest returns authentication configuration for an Ingress rule
|
||||
type BasicDigest struct {
|
||||
// Config returns authentication configuration for an Ingress rule
|
||||
type Config struct {
|
||||
Type string `json:"type"`
|
||||
Realm string `json:"realm"`
|
||||
File string `json:"file"`
|
||||
|
@ -55,8 +55,8 @@ type BasicDigest struct {
|
|||
FileSHA string `json:"fileSha"`
|
||||
}
|
||||
|
||||
// Equal tests for equality between two BasicDigest types
|
||||
func (bd1 *BasicDigest) Equal(bd2 *BasicDigest) bool {
|
||||
// Equal tests for equality between two Config types
|
||||
func (bd1 *Config) Equal(bd2 *Config) bool {
|
||||
if bd1 == bd2 {
|
||||
return true
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ func (a auth) Parse(ing *extensions.Ingress) (interface{}, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return &BasicDigest{
|
||||
return &Config{
|
||||
Type: at,
|
||||
Realm: realm,
|
||||
File: passFile,
|
||||
|
|
|
@ -109,7 +109,7 @@ func TestIngressAuth(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Errorf("Uxpected error with ingress: %v", err)
|
||||
}
|
||||
auth, ok := i.(*BasicDigest)
|
||||
auth, ok := i.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("expected a BasicDigest type")
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ const (
|
|||
)
|
||||
|
||||
// External returns external authentication configuration for an Ingress rule
|
||||
type External struct {
|
||||
type Config struct {
|
||||
URL string `json:"url"`
|
||||
// Host contains the hostname defined in the URL
|
||||
Host string `json:"host"`
|
||||
|
@ -45,8 +45,8 @@ type External struct {
|
|||
ResponseHeaders []string `json:"responseHeaders,omitEmpty"`
|
||||
}
|
||||
|
||||
// Equal tests for equality between two External types
|
||||
func (e1 *External) Equal(e2 *External) bool {
|
||||
// Equal tests for equality between two Config types
|
||||
func (e1 *Config) Equal(e2 *Config) bool {
|
||||
if e1 == e2 {
|
||||
return true
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ func NewParser() parser.IngressAnnotation {
|
|||
}
|
||||
|
||||
// ParseAnnotations parses the annotations contained in the ingress
|
||||
// rule used to use an external URL as source for authentication
|
||||
// rule used to use an Config URL as source for authentication
|
||||
func (a authReq) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
str, err := parser.GetStringAnnotation(authURL, ing)
|
||||
if err != nil {
|
||||
|
@ -165,7 +165,7 @@ func (a authReq) Parse(ing *extensions.Ingress) (interface{}, error) {
|
|||
}
|
||||
}
|
||||
|
||||
return &External{
|
||||
return &Config{
|
||||
URL: str,
|
||||
Host: ur.Hostname(),
|
||||
SigninURL: signin,
|
||||
|
|
|
@ -97,7 +97,7 @@ func TestAnnotations(t *testing.T) {
|
|||
}
|
||||
continue
|
||||
}
|
||||
u, ok := i.(*External)
|
||||
u, ok := i.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("%v: expected an External type", test.title)
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ func TestHeaderAnnotations(t *testing.T) {
|
|||
}
|
||||
|
||||
t.Log(i)
|
||||
u, ok := i.(*External)
|
||||
u, ok := i.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("%v: expected an External type", test.title)
|
||||
continue
|
||||
|
|
|
@ -20,11 +20,12 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"regexp"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
ing_errors "k8s.io/ingress-nginx/pkg/ingress/errors"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/resolver"
|
||||
"k8s.io/ingress-nginx/pkg/k8s"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -41,17 +42,17 @@ var (
|
|||
authVerifyClientRegex = regexp.MustCompile(`on|off|optional|optional_no_ca`)
|
||||
)
|
||||
|
||||
// AuthSSLConfig contains the AuthSSLCert used for muthual autentication
|
||||
// Config contains the AuthSSLCert used for muthual autentication
|
||||
// and the configured ValidationDepth
|
||||
type AuthSSLConfig struct {
|
||||
type Config struct {
|
||||
resolver.AuthSSLCert
|
||||
VerifyClient string `json:"verify_client"`
|
||||
ValidationDepth int `json:"validationDepth"`
|
||||
ErrorPage string `json:"errorPage"`
|
||||
}
|
||||
|
||||
// Equal tests for equality between two AuthSSLConfig types
|
||||
func (assl1 *AuthSSLConfig) Equal(assl2 *AuthSSLConfig) bool {
|
||||
// Equal tests for equality between two Config types
|
||||
func (assl1 *Config) Equal(assl2 *Config) bool {
|
||||
if assl1 == assl2 {
|
||||
return true
|
||||
}
|
||||
|
@ -88,16 +89,16 @@ func (a authTLS) Parse(ing *extensions.Ingress) (interface{}, error) {
|
|||
|
||||
tlsauthsecret, err := parser.GetStringAnnotation(annotationAuthTLSSecret, ing)
|
||||
if err != nil {
|
||||
return &AuthSSLConfig{}, err
|
||||
return &Config{}, err
|
||||
}
|
||||
|
||||
if tlsauthsecret == "" {
|
||||
return &AuthSSLConfig{}, ing_errors.NewLocationDenied("an empty string is not a valid secret name")
|
||||
return &Config{}, ing_errors.NewLocationDenied("an empty string is not a valid secret name")
|
||||
}
|
||||
|
||||
_, _, err = k8s.ParseNameNS(tlsauthsecret)
|
||||
if err != nil {
|
||||
return &AuthSSLConfig{}, ing_errors.NewLocationDenied(err.Error())
|
||||
return &Config{}, ing_errors.NewLocationDenied(err.Error())
|
||||
}
|
||||
|
||||
tlsVerifyClient, err := parser.GetStringAnnotation(annotationAuthVerifyClient, ing)
|
||||
|
@ -112,7 +113,7 @@ func (a authTLS) Parse(ing *extensions.Ingress) (interface{}, error) {
|
|||
|
||||
authCert, err := a.certResolver.GetAuthCertificate(tlsauthsecret)
|
||||
if err != nil {
|
||||
return &AuthSSLConfig{}, ing_errors.LocationDenied{
|
||||
return &Config{}, ing_errors.LocationDenied{
|
||||
Reason: errors.Wrap(err, "error obtaining certificate"),
|
||||
}
|
||||
}
|
||||
|
@ -122,7 +123,7 @@ func (a authTLS) Parse(ing *extensions.Ingress) (interface{}, error) {
|
|||
errorpage = ""
|
||||
}
|
||||
|
||||
return &AuthSSLConfig{
|
||||
return &Config{
|
||||
AuthSSLCert: *authCert,
|
||||
VerifyClient: tlsVerifyClient,
|
||||
ValidationDepth: tlsdepth,
|
||||
|
|
|
@ -51,8 +51,8 @@ var (
|
|||
type cors struct {
|
||||
}
|
||||
|
||||
// CorsConfig contains the Cors configuration to be used in the Ingress
|
||||
type CorsConfig struct {
|
||||
// Config contains the Cors configuration to be used in the Ingress
|
||||
type Config struct {
|
||||
CorsEnabled bool `json:"corsEnabled"`
|
||||
CorsAllowOrigin string `json:"corsAllowOrigin"`
|
||||
CorsAllowMethods string `json:"corsAllowMethods"`
|
||||
|
@ -66,7 +66,7 @@ func NewParser() parser.IngressAnnotation {
|
|||
}
|
||||
|
||||
// Equal tests for equality between two External types
|
||||
func (c1 *CorsConfig) Equal(c2 *CorsConfig) bool {
|
||||
func (c1 *Config) Equal(c2 *Config) bool {
|
||||
if c1 == c2 {
|
||||
return true
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ func (a cors) Parse(ing *extensions.Ingress) (interface{}, error) {
|
|||
corsallowcredentials = true
|
||||
}
|
||||
|
||||
return &CorsConfig{
|
||||
return &Config{
|
||||
CorsEnabled: corsenabled,
|
||||
CorsAllowOrigin: corsalloworigin,
|
||||
CorsAllowHeaders: corsallowheaders,
|
||||
|
|
|
@ -72,7 +72,7 @@ func TestIngressCorsConfig(t *testing.T) {
|
|||
ing.SetAnnotations(data)
|
||||
|
||||
corst, _ := NewParser().Parse(ing)
|
||||
nginxCors, ok := corst.(*CorsConfig)
|
||||
nginxCors, ok := corst.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("expected a Config type")
|
||||
}
|
||||
|
|
|
@ -28,9 +28,9 @@ const (
|
|||
upsFailTimeout = "ingress.kubernetes.io/upstream-fail-timeout"
|
||||
)
|
||||
|
||||
// Upstream returns the URL and method to use check the status of
|
||||
// Config returns the URL and method to use check the status of
|
||||
// the upstream server/s
|
||||
type Upstream struct {
|
||||
type Config struct {
|
||||
MaxFails int `json:"maxFails"`
|
||||
FailTimeout int `json:"failTimeout"`
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ func NewParser(br resolver.DefaultBackend) parser.IngressAnnotation {
|
|||
func (a healthCheck) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
defBackend := a.backendResolver.GetDefaultBackend()
|
||||
if ing.GetAnnotations() == nil {
|
||||
return &Upstream{defBackend.UpstreamMaxFails, defBackend.UpstreamFailTimeout}, nil
|
||||
return &Config{defBackend.UpstreamMaxFails, defBackend.UpstreamFailTimeout}, nil
|
||||
}
|
||||
|
||||
mf, err := parser.GetIntAnnotation(upsMaxFails, ing)
|
||||
|
@ -62,5 +62,5 @@ func (a healthCheck) Parse(ing *extensions.Ingress) (interface{}, error) {
|
|||
ft = defBackend.UpstreamFailTimeout
|
||||
}
|
||||
|
||||
return &Upstream{mf, ft}, nil
|
||||
return &Config{mf, ft}, nil
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ func TestIngressHealthCheck(t *testing.T) {
|
|||
ing.SetAnnotations(data)
|
||||
|
||||
hzi, _ := NewParser(mockBackend{}).Parse(ing)
|
||||
nginxHz, ok := hzi.(*Upstream)
|
||||
nginxHz, ok := hzi.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("expected a Upstream type")
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||
package portinredirect
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
|
@ -24,8 +25,6 @@ import (
|
|||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
|
||||
"fmt"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/defaults"
|
||||
)
|
||||
|
||||
|
|
|
@ -36,8 +36,8 @@ const (
|
|||
requestBuffering = "ingress.kubernetes.io/proxy-request-buffering"
|
||||
)
|
||||
|
||||
// Configuration returns the proxy timeout to use in the upstream server/s
|
||||
type Configuration struct {
|
||||
// Config returns the proxy timeout to use in the upstream server/s
|
||||
type Config struct {
|
||||
BodySize string `json:"bodySize"`
|
||||
ConnectTimeout int `json:"connectTimeout"`
|
||||
SendTimeout int `json:"sendTimeout"`
|
||||
|
@ -51,7 +51,7 @@ type Configuration struct {
|
|||
}
|
||||
|
||||
// Equal tests for equality between two Configuration types
|
||||
func (l1 *Configuration) Equal(l2 *Configuration) bool {
|
||||
func (l1 *Config) Equal(l2 *Config) bool {
|
||||
if l1 == l2 {
|
||||
return true
|
||||
}
|
||||
|
@ -156,5 +156,5 @@ func (a proxy) Parse(ing *extensions.Ingress) (interface{}, error) {
|
|||
rb = defBackend.ProxyRequestBuffering
|
||||
}
|
||||
|
||||
return &Configuration{bs, ct, st, rt, bufs, cd, cp, nu, pp, rb}, nil
|
||||
return &Config{bs, ct, st, rt, bufs, cd, cp, nu, pp, rb}, nil
|
||||
}
|
||||
|
|
|
@ -97,9 +97,9 @@ func TestProxy(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("unexpected error parsing a valid")
|
||||
}
|
||||
p, ok := i.(*Configuration)
|
||||
p, ok := i.(*Config)
|
||||
if !ok {
|
||||
t.Fatalf("expected a Configuration type")
|
||||
t.Fatalf("expected a Config type")
|
||||
}
|
||||
if p.ConnectTimeout != 1 {
|
||||
t.Errorf("expected 1 as connect-timeout but returned %v", p.ConnectTimeout)
|
||||
|
@ -137,9 +137,9 @@ func TestProxyWithNoAnnotation(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("unexpected error parsing a valid")
|
||||
}
|
||||
p, ok := i.(*Configuration)
|
||||
p, ok := i.(*Config)
|
||||
if !ok {
|
||||
t.Fatalf("expected a Configuration type")
|
||||
t.Fatalf("expected a Config type")
|
||||
}
|
||||
if p.ConnectTimeout != 10 {
|
||||
t.Errorf("expected 10 as connect-timeout but returned %v", p.ConnectTimeout)
|
||||
|
|
|
@ -45,11 +45,11 @@ const (
|
|||
defSharedSize = 5
|
||||
)
|
||||
|
||||
// RateLimit returns rate limit configuration for an Ingress rule limiting the
|
||||
// Config returns rate limit configuration for an Ingress rule limiting the
|
||||
// number of connections per IP address and/or connections per second.
|
||||
// If you both annotations are specified in a single Ingress rule, RPS limits
|
||||
// takes precedence
|
||||
type RateLimit struct {
|
||||
type Config struct {
|
||||
// Connections indicates a limit with the number of connections per IP address
|
||||
Connections Zone `json:"connections"`
|
||||
// RPS indicates a limit with the number of connections per second
|
||||
|
@ -69,7 +69,7 @@ type RateLimit struct {
|
|||
}
|
||||
|
||||
// Equal tests for equality between two RateLimit types
|
||||
func (rt1 *RateLimit) Equal(rt2 *RateLimit) bool {
|
||||
func (rt1 *Config) Equal(rt2 *Config) bool {
|
||||
if rt1 == rt2 {
|
||||
return true
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ func (a ratelimit) Parse(ing *extensions.Ingress) (interface{}, error) {
|
|||
}
|
||||
|
||||
if rpm == 0 && rps == 0 && conn == 0 {
|
||||
return &RateLimit{
|
||||
return &Config{
|
||||
Connections: Zone{},
|
||||
RPS: Zone{},
|
||||
RPM: Zone{},
|
||||
|
@ -196,7 +196,7 @@ func (a ratelimit) Parse(ing *extensions.Ingress) (interface{}, error) {
|
|||
|
||||
zoneName := fmt.Sprintf("%v_%v", ing.GetNamespace(), ing.GetName())
|
||||
|
||||
return &RateLimit{
|
||||
return &Config{
|
||||
Connections: Zone{
|
||||
Name: fmt.Sprintf("%v_conn", zoneName),
|
||||
Limit: conn,
|
||||
|
|
|
@ -107,7 +107,7 @@ func TestBadRateLimiting(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
rateLimit, ok := i.(*RateLimit)
|
||||
rateLimit, ok := i.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("expected a RateLimit type")
|
||||
}
|
||||
|
|
|
@ -33,8 +33,8 @@ const (
|
|||
www = "ingress.kubernetes.io/from-to-www-redirect"
|
||||
)
|
||||
|
||||
// Redirect returns the redirect configuration for an Ingress rule
|
||||
type Redirect struct {
|
||||
// Config returns the redirect configuration for an Ingress rule
|
||||
type Config struct {
|
||||
URL string `json:"url"`
|
||||
Code int `json:"code"`
|
||||
FromToWWW bool `json:"fromToWWW"`
|
||||
|
@ -64,7 +64,7 @@ func (a redirect) Parse(ing *extensions.Ingress) (interface{}, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return &Redirect{
|
||||
return &Config{
|
||||
URL: tr,
|
||||
Code: http.StatusFound,
|
||||
FromToWWW: r3w,
|
||||
|
@ -81,7 +81,7 @@ func (a redirect) Parse(ing *extensions.Ingress) (interface{}, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return &Redirect{
|
||||
return &Config{
|
||||
URL: pr,
|
||||
Code: http.StatusMovedPermanently,
|
||||
FromToWWW: r3w,
|
||||
|
@ -89,7 +89,7 @@ func (a redirect) Parse(ing *extensions.Ingress) (interface{}, error) {
|
|||
}
|
||||
|
||||
if r3w {
|
||||
return &Redirect{
|
||||
return &Config{
|
||||
FromToWWW: r3w,
|
||||
}, nil
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ func (a redirect) Parse(ing *extensions.Ingress) (interface{}, error) {
|
|||
}
|
||||
|
||||
// Equal tests for equality between two Redirect types
|
||||
func (r1 *Redirect) Equal(r2 *Redirect) bool {
|
||||
func (r1 *Config) Equal(r2 *Config) bool {
|
||||
if r1 == r2 {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -32,8 +32,8 @@ const (
|
|||
appRoot = "ingress.kubernetes.io/app-root"
|
||||
)
|
||||
|
||||
// Redirect describes the per location redirect config
|
||||
type Redirect struct {
|
||||
// Config describes the per location redirect config
|
||||
type Config struct {
|
||||
// Target URI where the traffic must be redirected
|
||||
Target string `json:"target"`
|
||||
// AddBaseURL indicates if is required to add a base tag in the head
|
||||
|
@ -50,7 +50,7 @@ type Redirect struct {
|
|||
}
|
||||
|
||||
// Equal tests for equality between two Redirect types
|
||||
func (r1 *Redirect) Equal(r2 *Redirect) bool {
|
||||
func (r1 *Config) Equal(r2 *Config) bool {
|
||||
if r1 == r2 {
|
||||
return true
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ func (a rewrite) Parse(ing *extensions.Ingress) (interface{}, error) {
|
|||
abu, _ := parser.GetBoolAnnotation(addBaseURL, ing)
|
||||
bus, _ := parser.GetStringAnnotation(baseURLScheme, ing)
|
||||
ar, _ := parser.GetStringAnnotation(appRoot, ing)
|
||||
return &Redirect{
|
||||
return &Config{
|
||||
Target: rt,
|
||||
AddBaseURL: abu,
|
||||
BaseURLScheme: bus,
|
||||
|
|
|
@ -93,7 +93,7 @@ func TestRedirect(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Errorf("Unexpected error with ingress: %v", err)
|
||||
}
|
||||
redirect, ok := i.(*Redirect)
|
||||
redirect, ok := i.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("expected a Redirect type")
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ func TestSSLRedirect(t *testing.T) {
|
|||
ing.SetAnnotations(data)
|
||||
|
||||
i, _ := NewParser(mockBackend{true}).Parse(ing)
|
||||
redirect, ok := i.(*Redirect)
|
||||
redirect, ok := i.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("expected a Redirect type")
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ func TestSSLRedirect(t *testing.T) {
|
|||
ing.SetAnnotations(data)
|
||||
|
||||
i, _ = NewParser(mockBackend{false}).Parse(ing)
|
||||
redirect, ok = i.(*Redirect)
|
||||
redirect, ok = i.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("expected a Redirect type")
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ func TestForceSSLRedirect(t *testing.T) {
|
|||
ing.SetAnnotations(data)
|
||||
|
||||
i, _ := NewParser(mockBackend{true}).Parse(ing)
|
||||
redirect, ok := i.(*Redirect)
|
||||
redirect, ok := i.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("expected a Redirect type")
|
||||
}
|
||||
|
@ -151,7 +151,7 @@ func TestForceSSLRedirect(t *testing.T) {
|
|||
ing.SetAnnotations(data)
|
||||
|
||||
i, _ = NewParser(mockBackend{false}).Parse(ing)
|
||||
redirect, ok = i.(*Redirect)
|
||||
redirect, ok = i.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("expected a Redirect type")
|
||||
}
|
||||
|
@ -167,12 +167,11 @@ func TestAppRoot(t *testing.T) {
|
|||
ing.SetAnnotations(data)
|
||||
|
||||
i, _ := NewParser(mockBackend{true}).Parse(ing)
|
||||
redirect, ok := i.(*Redirect)
|
||||
redirect, ok := i.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("expected a App Context")
|
||||
}
|
||||
if redirect.AppRoot != "/app1" {
|
||||
t.Errorf("Unexpected value got in AppRoot")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,8 +31,8 @@ const (
|
|||
secureVerifyCASecret = "ingress.kubernetes.io/secure-verify-ca-secret"
|
||||
)
|
||||
|
||||
// Secure describes SSL backend configuration
|
||||
type Secure struct {
|
||||
// Config describes SSL backend configuration
|
||||
type Config struct {
|
||||
Secure bool `json:"secure"`
|
||||
CACert resolver.AuthSSLCert `json:"caCert"`
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ func NewParser(resolver resolver.AuthCertificate) parser.IngressAnnotation {
|
|||
func (a su) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
s, _ := parser.GetBoolAnnotation(secureUpstream, ing)
|
||||
ca, _ := parser.GetStringAnnotation(secureVerifyCASecret, ing)
|
||||
secure := &Secure{
|
||||
secure := &Config{
|
||||
Secure: s,
|
||||
CACert: resolver.AuthSSLCert{},
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ func (a su) Parse(ing *extensions.Ingress) (interface{}, error) {
|
|||
if caCert == nil {
|
||||
return secure, nil
|
||||
}
|
||||
return &Secure{
|
||||
return &Config{
|
||||
Secure: s,
|
||||
CACert: *caCert,
|
||||
}, nil
|
||||
|
|
|
@ -17,14 +17,13 @@ limitations under the License.
|
|||
package secureupstream
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/resolver"
|
||||
)
|
||||
|
|
|
@ -42,24 +42,24 @@ var (
|
|||
affinityCookieHashRegex = regexp.MustCompile(`^(index|md5|sha1)$`)
|
||||
)
|
||||
|
||||
// AffinityConfig describes the per ingress session affinity config
|
||||
type AffinityConfig struct {
|
||||
// Config describes the per ingress session affinity config
|
||||
type Config struct {
|
||||
// The type of affinity that will be used
|
||||
AffinityType string `json:"type"`
|
||||
CookieConfig
|
||||
Type string `json:"type"`
|
||||
Cookie
|
||||
}
|
||||
|
||||
// CookieConfig describes the Config of cookie type affinity
|
||||
type CookieConfig struct {
|
||||
// Cookie describes the Config of cookie type affinity
|
||||
type Cookie struct {
|
||||
// The name of the cookie that will be used in case of cookie affinity type.
|
||||
Name string `json:"name"`
|
||||
// The hash that will be used to encode the cookie in case of cookie affinity type
|
||||
Hash string `json:"hash"`
|
||||
}
|
||||
|
||||
// CookieAffinityParse gets the annotation values related to Cookie Affinity
|
||||
// cookieAffinityParse gets the annotation values related to Cookie Affinity
|
||||
// It also sets default values when no value or incorrect value is found
|
||||
func CookieAffinityParse(ing *extensions.Ingress) *CookieConfig {
|
||||
func cookieAffinityParse(ing *extensions.Ingress) *Cookie {
|
||||
|
||||
sn, err := parser.GetStringAnnotation(annotationAffinityCookieName, ing)
|
||||
|
||||
|
@ -75,7 +75,7 @@ func CookieAffinityParse(ing *extensions.Ingress) *CookieConfig {
|
|||
sh = defaultAffinityCookieHash
|
||||
}
|
||||
|
||||
return &CookieConfig{
|
||||
return &Cookie{
|
||||
Name: sn,
|
||||
Hash: sh,
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ type affinity struct {
|
|||
// ParseAnnotations parses the annotations contained in the ingress
|
||||
// rule used to configure the affinity directives
|
||||
func (a affinity) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
cookieAffinityConfig := &CookieConfig{}
|
||||
cookie := &Cookie{}
|
||||
// Check the type of affinity that will be used
|
||||
at, err := parser.GetStringAnnotation(annotationAffinityType, ing)
|
||||
if err != nil {
|
||||
|
@ -101,15 +101,14 @@ func (a affinity) Parse(ing *extensions.Ingress) (interface{}, error) {
|
|||
|
||||
switch at {
|
||||
case "cookie":
|
||||
cookieAffinityConfig = CookieAffinityParse(ing)
|
||||
|
||||
cookie = cookieAffinityParse(ing)
|
||||
default:
|
||||
glog.V(3).Infof("No default affinity was found for Ingress %v", ing.Name)
|
||||
|
||||
}
|
||||
return &AffinityConfig{
|
||||
AffinityType: at,
|
||||
CookieConfig: *cookieAffinityConfig,
|
||||
}, nil
|
||||
|
||||
return &Config{
|
||||
Type: at,
|
||||
Cookie: *cookie,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -70,20 +70,20 @@ func TestIngressAffinityCookieConfig(t *testing.T) {
|
|||
ing.SetAnnotations(data)
|
||||
|
||||
affin, _ := NewParser().Parse(ing)
|
||||
nginxAffinity, ok := affin.(*AffinityConfig)
|
||||
nginxAffinity, ok := affin.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("expected a Config type")
|
||||
}
|
||||
|
||||
if nginxAffinity.AffinityType != "cookie" {
|
||||
t.Errorf("expected cookie as sticky-type but returned %v", nginxAffinity.AffinityType)
|
||||
if nginxAffinity.Type != "cookie" {
|
||||
t.Errorf("expected cookie as sticky-type but returned %v", nginxAffinity.Type)
|
||||
}
|
||||
|
||||
if nginxAffinity.CookieConfig.Hash != "md5" {
|
||||
t.Errorf("expected md5 as sticky-hash but returned %v", nginxAffinity.CookieConfig.Hash)
|
||||
if nginxAffinity.Cookie.Hash != "md5" {
|
||||
t.Errorf("expected md5 as sticky-hash but returned %v", nginxAffinity.Cookie.Hash)
|
||||
}
|
||||
|
||||
if nginxAffinity.CookieConfig.Name != "INGRESSCOOKIE" {
|
||||
t.Errorf("expected route as sticky-name but returned %v", nginxAffinity.CookieConfig.Name)
|
||||
if nginxAffinity.Cookie.Name != "INGRESSCOOKIE" {
|
||||
t.Errorf("expected route as sticky-name but returned %v", nginxAffinity.Cookie.Name)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ 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"
|
||||
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ import (
|
|||
clientset "k8s.io/client-go/kubernetes"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/class"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/healthcheck"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
|
@ -316,7 +317,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 +328,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 +380,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 +399,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 +418,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 +459,19 @@ 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
|
||||
|
||||
if loc.Redirect.FromToWWW {
|
||||
server.RedirectFromToWWW = true
|
||||
}
|
||||
|
@ -472,14 +482,26 @@ 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,
|
||||
}
|
||||
mergeLocationAnnotations(loc, anns)
|
||||
|
||||
if loc.Redirect.FromToWWW {
|
||||
server.RedirectFromToWWW = true
|
||||
}
|
||||
|
@ -487,12 +509,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 +541,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 +639,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 +654,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 +664,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 +693,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 +718,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 +778,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 +862,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 +903,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 +947,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 +963,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 +976,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
|
||||
|
@ -1044,7 +1059,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{}
|
||||
|
||||
|
@ -1152,6 +1167,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 +1176,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)
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ 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"
|
||||
|
@ -60,7 +61,7 @@ func (c *cacheController) Run(stopCh chan struct{}) {
|
|||
}
|
||||
}
|
||||
|
||||
func (n *NGINXController) createListers(stopCh chan struct{}) *ingress.StoreLister {
|
||||
func (n *NGINXController) createListers(stopCh chan struct{}) (*ingress.StoreLister, *cacheController) {
|
||||
// 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
|
||||
|
@ -73,6 +74,7 @@ func (n *NGINXController) createListers(stopCh chan struct{}) *ingress.StoreList
|
|||
return
|
||||
}
|
||||
|
||||
n.extractAnnotations(addIng)
|
||||
n.recorder.Eventf(addIng, apiv1.EventTypeNormal, "CREATE", fmt.Sprintf("Ingress %s/%s", addIng.Namespace, addIng.Name))
|
||||
n.syncQueue.Enqueue(obj)
|
||||
},
|
||||
|
@ -113,6 +115,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 +144,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 +199,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 +223,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
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/util/filesystem"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations"
|
||||
"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"
|
||||
|
@ -50,6 +51,7 @@ import (
|
|||
ngx_template "k8s.io/ingress-nginx/pkg/ingress/controller/template"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/defaults"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/status"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/store"
|
||||
ing_net "k8s.io/ingress-nginx/pkg/net"
|
||||
"k8s.io/ingress-nginx/pkg/net/dns"
|
||||
"k8s.io/ingress-nginx/pkg/net/ssl"
|
||||
|
@ -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,6 +238,8 @@ 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() {
|
||||
|
@ -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 {
|
||||
|
|
|
@ -354,8 +354,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)
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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"
|
||||
)
|
||||
|
||||
// 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
|
||||
|
|
|
@ -17,18 +17,7 @@ limitations under the License.
|
|||
package controller
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/auth"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/authreq"
|
||||
"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"
|
||||
)
|
||||
|
||||
type fakeError struct{}
|
||||
|
@ -37,51 +26,6 @@ func (fe *fakeError) Error() string {
|
|||
return "fakeError"
|
||||
}
|
||||
|
||||
func TestMergeLocationAnnotations(t *testing.T) {
|
||||
// initial parameters
|
||||
loc := ingress.Location{}
|
||||
annotations := map[string]interface{}{
|
||||
"Path": "/checkpath",
|
||||
"IsDefBackend": true,
|
||||
"Backend": "foo_backend",
|
||||
"BasicDigestAuth": auth.BasicDigest{},
|
||||
DeniedKeyName: &fakeError{},
|
||||
"CorsConfig": cors.CorsConfig{},
|
||||
"ExternalAuth": authreq.External{},
|
||||
"RateLimit": ratelimit.RateLimit{},
|
||||
"Redirect": redirect.Redirect{},
|
||||
"Rewrite": rewrite.Redirect{},
|
||||
"Whitelist": ipwhitelist.SourceRange{},
|
||||
"Proxy": proxy.Configuration{},
|
||||
"UsePortInRedirects": true,
|
||||
}
|
||||
|
||||
// create test table
|
||||
type fooMergeLocationAnnotationsStruct struct {
|
||||
fName string
|
||||
er interface{}
|
||||
}
|
||||
fooTests := []fooMergeLocationAnnotationsStruct{}
|
||||
for name, value := range annotations {
|
||||
fva := fooMergeLocationAnnotationsStruct{name, value}
|
||||
fooTests = append(fooTests, fva)
|
||||
}
|
||||
|
||||
// execute test
|
||||
mergeLocationAnnotations(&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)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntInSlice(t *testing.T) {
|
||||
fooTests := []struct {
|
||||
i int
|
||||
|
|
|
@ -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{}),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"`
|
||||
|
|
Loading…
Reference in a new issue