Merge pull request #3474 from aledbf/improve-parsing
Improve parsing of annotations and use of Ingress wrapper
This commit is contained in:
commit
c4ba23832a
18 changed files with 302 additions and 354 deletions
|
@ -123,9 +123,6 @@ func (a authReq) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if urlString == "" {
|
|
||||||
return nil, ing_errors.NewLocationDenied("an empty string is not a valid URL")
|
|
||||||
}
|
|
||||||
|
|
||||||
authURL, err := url.Parse(urlString)
|
authURL, err := url.Parse(urlString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -105,6 +105,10 @@ func TestAnnotations(t *testing.T) {
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%v: unexpected error: %v", test.title, err)
|
||||||
|
}
|
||||||
|
|
||||||
u, ok := i.(*Config)
|
u, ok := i.(*Config)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("%v: expected an External type", test.title)
|
t.Errorf("%v: expected an External type", test.title)
|
||||||
|
|
|
@ -87,52 +87,45 @@ type authTLS struct {
|
||||||
// Parse parses the annotations contained in the ingress
|
// Parse parses the annotations contained in the ingress
|
||||||
// rule used to use a Certificate as authentication method
|
// rule used to use a Certificate as authentication method
|
||||||
func (a authTLS) Parse(ing *extensions.Ingress) (interface{}, error) {
|
func (a authTLS) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||||
|
var err error
|
||||||
|
config := &Config{}
|
||||||
|
|
||||||
tlsauthsecret, err := parser.GetStringAnnotation("auth-tls-secret", ing)
|
tlsauthsecret, err := parser.GetStringAnnotation("auth-tls-secret", ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &Config{}, err
|
return &Config{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if tlsauthsecret == "" {
|
|
||||||
return &Config{}, ing_errors.NewLocationDenied("an empty string is not a valid secret name")
|
|
||||||
}
|
|
||||||
|
|
||||||
_, _, err = k8s.ParseNameNS(tlsauthsecret)
|
_, _, err = k8s.ParseNameNS(tlsauthsecret)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &Config{}, ing_errors.NewLocationDenied(err.Error())
|
return &Config{}, ing_errors.NewLocationDenied(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsVerifyClient, err := parser.GetStringAnnotation("auth-tls-verify-client", ing)
|
|
||||||
if err != nil || !authVerifyClientRegex.MatchString(tlsVerifyClient) {
|
|
||||||
tlsVerifyClient = defaultAuthVerifyClient
|
|
||||||
}
|
|
||||||
|
|
||||||
tlsdepth, err := parser.GetIntAnnotation("auth-tls-verify-depth", ing)
|
|
||||||
if err != nil || tlsdepth == 0 {
|
|
||||||
tlsdepth = defaultAuthTLSDepth
|
|
||||||
}
|
|
||||||
|
|
||||||
authCert, err := a.r.GetAuthCertificate(tlsauthsecret)
|
authCert, err := a.r.GetAuthCertificate(tlsauthsecret)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e := errors.Wrap(err, "error obtaining certificate")
|
e := errors.Wrap(err, "error obtaining certificate")
|
||||||
return &Config{}, ing_errors.LocationDenied{Reason: e}
|
return &Config{}, ing_errors.LocationDenied{Reason: e}
|
||||||
}
|
}
|
||||||
|
config.AuthSSLCert = *authCert
|
||||||
|
|
||||||
errorpage, err := parser.GetStringAnnotation("auth-tls-error-page", ing)
|
config.VerifyClient, err = parser.GetStringAnnotation("auth-tls-verify-client", ing)
|
||||||
if err != nil || errorpage == "" {
|
if err != nil || !authVerifyClientRegex.MatchString(config.VerifyClient) {
|
||||||
errorpage = ""
|
config.VerifyClient = defaultAuthVerifyClient
|
||||||
}
|
}
|
||||||
|
|
||||||
passCert, err := parser.GetBoolAnnotation("auth-tls-pass-certificate-to-upstream", ing)
|
config.ValidationDepth, err = parser.GetIntAnnotation("auth-tls-verify-depth", ing)
|
||||||
|
if err != nil || config.ValidationDepth == 0 {
|
||||||
|
config.ValidationDepth = defaultAuthTLSDepth
|
||||||
|
}
|
||||||
|
|
||||||
|
config.ErrorPage, err = parser.GetStringAnnotation("auth-tls-error-page", ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
passCert = false
|
config.ErrorPage = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Config{
|
config.PassCertToUpstream, err = parser.GetBoolAnnotation("auth-tls-pass-certificate-to-upstream", ing)
|
||||||
AuthSSLCert: *authCert,
|
if err != nil {
|
||||||
VerifyClient: tlsVerifyClient,
|
config.PassCertToUpstream = false
|
||||||
ValidationDepth: tlsdepth,
|
}
|
||||||
ErrorPage: errorpage,
|
|
||||||
PassCertToUpstream: passCert,
|
return config, nil
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,6 @@ func TestParse(t *testing.T) {
|
||||||
annotations map[string]string
|
annotations map[string]string
|
||||||
expected *Config
|
expected *Config
|
||||||
}{
|
}{
|
||||||
{map[string]string{annotation: ""}, &Config{Enabled: true, Header: ""}},
|
|
||||||
{map[string]string{annotation: "keep-alive"}, &Config{Enabled: true, Header: "keep-alive"}},
|
{map[string]string{annotation: "keep-alive"}, &Config{Enabled: true, Header: "keep-alive"}},
|
||||||
{map[string]string{}, &Config{Enabled: false}},
|
{map[string]string{}, &Config{Enabled: false}},
|
||||||
{nil, &Config{Enabled: false}},
|
{nil, &Config{Enabled: false}},
|
||||||
|
|
|
@ -97,43 +97,39 @@ func (c1 *Config) Equal(c2 *Config) bool {
|
||||||
// Parse parses the annotations contained in the ingress
|
// Parse parses the annotations contained in the ingress
|
||||||
// rule used to indicate if the location/s should allows CORS
|
// rule used to indicate if the location/s should allows CORS
|
||||||
func (c cors) Parse(ing *extensions.Ingress) (interface{}, error) {
|
func (c cors) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||||
corsenabled, err := parser.GetBoolAnnotation("enable-cors", ing)
|
var err error
|
||||||
|
config := &Config{}
|
||||||
|
|
||||||
|
config.CorsEnabled, err = parser.GetBoolAnnotation("enable-cors", ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
corsenabled = false
|
config.CorsEnabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
corsalloworigin, err := parser.GetStringAnnotation("cors-allow-origin", ing)
|
config.CorsAllowOrigin, err = parser.GetStringAnnotation("cors-allow-origin", ing)
|
||||||
if err != nil || corsalloworigin == "" || !corsOriginRegex.MatchString(corsalloworigin) {
|
if err != nil || !corsOriginRegex.MatchString(config.CorsAllowOrigin) {
|
||||||
corsalloworigin = "*"
|
config.CorsAllowOrigin = "*"
|
||||||
}
|
}
|
||||||
|
|
||||||
corsallowheaders, err := parser.GetStringAnnotation("cors-allow-headers", ing)
|
config.CorsAllowHeaders, err = parser.GetStringAnnotation("cors-allow-headers", ing)
|
||||||
if err != nil || corsallowheaders == "" || !corsHeadersRegex.MatchString(corsallowheaders) {
|
if err != nil || !corsHeadersRegex.MatchString(config.CorsAllowHeaders) {
|
||||||
corsallowheaders = defaultCorsHeaders
|
config.CorsAllowHeaders = defaultCorsHeaders
|
||||||
}
|
}
|
||||||
|
|
||||||
corsallowmethods, err := parser.GetStringAnnotation("cors-allow-methods", ing)
|
config.CorsAllowMethods, err = parser.GetStringAnnotation("cors-allow-methods", ing)
|
||||||
if err != nil || corsallowmethods == "" || !corsMethodsRegex.MatchString(corsallowmethods) {
|
if err != nil || !corsMethodsRegex.MatchString(config.CorsAllowMethods) {
|
||||||
corsallowmethods = defaultCorsMethods
|
config.CorsAllowMethods = defaultCorsMethods
|
||||||
}
|
}
|
||||||
|
|
||||||
corsallowcredentials, err := parser.GetBoolAnnotation("cors-allow-credentials", ing)
|
config.CorsAllowCredentials, err = parser.GetBoolAnnotation("cors-allow-credentials", ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
corsallowcredentials = true
|
config.CorsAllowCredentials = true
|
||||||
}
|
}
|
||||||
|
|
||||||
corsmaxage, err := parser.GetIntAnnotation("cors-max-age", ing)
|
config.CorsMaxAge, err = parser.GetIntAnnotation("cors-max-age", ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
corsmaxage = defaultCorsMaxAge
|
config.CorsMaxAge = defaultCorsMaxAge
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Config{
|
return config, nil
|
||||||
CorsEnabled: corsenabled,
|
|
||||||
CorsAllowOrigin: corsalloworigin,
|
|
||||||
CorsAllowHeaders: corsallowheaders,
|
|
||||||
CorsAllowMethods: corsallowmethods,
|
|
||||||
CorsAllowCredentials: corsallowcredentials,
|
|
||||||
CorsMaxAge: corsmaxage,
|
|
||||||
}, nil
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,40 +43,37 @@ func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
||||||
|
|
||||||
// Parse parses the annotations to look for InfluxDB configurations
|
// Parse parses the annotations to look for InfluxDB configurations
|
||||||
func (c influxdb) Parse(ing *extensions.Ingress) (interface{}, error) {
|
func (c influxdb) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||||
influxdbEnabled, err := parser.GetBoolAnnotation("enable-influxdb", ing)
|
var err error
|
||||||
|
config := &Config{}
|
||||||
|
|
||||||
|
config.InfluxDBEnabled, err = parser.GetBoolAnnotation("enable-influxdb", ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
influxdbEnabled = false
|
config.InfluxDBEnabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
influxdbMeasurement, err := parser.GetStringAnnotation("influxdb-measurement", ing)
|
config.InfluxDBMeasurement, err = parser.GetStringAnnotation("influxdb-measurement", ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
influxdbMeasurement = "default"
|
config.InfluxDBMeasurement = "default"
|
||||||
}
|
}
|
||||||
|
|
||||||
influxdbPort, err := parser.GetStringAnnotation("influxdb-port", ing)
|
config.InfluxDBPort, err = parser.GetStringAnnotation("influxdb-port", ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// This is not the default 8086 port but the port usually used to expose
|
// This is not the default 8086 port but the port usually used to expose
|
||||||
// influxdb in UDP, the module uses UDP to talk to influx via the line protocol.
|
// influxdb in UDP, the module uses UDP to talk to influx via the line protocol.
|
||||||
influxdbPort = "8089"
|
config.InfluxDBPort = "8089"
|
||||||
}
|
}
|
||||||
|
|
||||||
influxdbHost, err := parser.GetStringAnnotation("influxdb-host", ing)
|
config.InfluxDBHost, err = parser.GetStringAnnotation("influxdb-host", ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
influxdbHost = "127.0.0.1"
|
config.InfluxDBHost = "127.0.0.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
influxdbServerName, err := parser.GetStringAnnotation("influxdb-server-name", ing)
|
config.InfluxDBServerName, err = parser.GetStringAnnotation("influxdb-server-name", ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
influxdbServerName = "nginx-ingress"
|
config.InfluxDBServerName = "nginx-ingress"
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Config{
|
return config, nil
|
||||||
InfluxDBEnabled: influxdbEnabled,
|
|
||||||
InfluxDBMeasurement: influxdbMeasurement,
|
|
||||||
InfluxDBPort: influxdbPort,
|
|
||||||
InfluxDBHost: influxdbHost,
|
|
||||||
InfluxDBServerName: influxdbServerName,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Equal tests for equality between two Config types
|
// Equal tests for equality between two Config types
|
||||||
|
|
|
@ -54,15 +54,18 @@ func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
||||||
// Parse parses the annotations contained in the ingress
|
// Parse parses the annotations contained in the ingress
|
||||||
// rule used to indicate if the location/s should enable logs
|
// rule used to indicate if the location/s should enable logs
|
||||||
func (l log) Parse(ing *extensions.Ingress) (interface{}, error) {
|
func (l log) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||||
accessEnabled, err := parser.GetBoolAnnotation("enable-access-log", ing)
|
var err error
|
||||||
|
config := &Config{}
|
||||||
|
|
||||||
|
config.Access, err = parser.GetBoolAnnotation("enable-access-log", ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
accessEnabled = true
|
config.Access = true
|
||||||
}
|
}
|
||||||
|
|
||||||
rewriteEnabled, err := parser.GetBoolAnnotation("enable-rewrite-log", ing)
|
config.Rewrite, err = parser.GetBoolAnnotation("enable-rewrite-log", ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rewriteEnabled = false
|
config.Rewrite = false
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Config{Access: accessEnabled, Rewrite: rewriteEnabled}, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,43 +86,38 @@ func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
||||||
// used to indicate if the location/s contains a fragment of
|
// used to indicate if the location/s contains a fragment of
|
||||||
// configuration to be included inside the paths of the rules
|
// configuration to be included inside the paths of the rules
|
||||||
func (a luarestywaf) Parse(ing *extensions.Ingress) (interface{}, error) {
|
func (a luarestywaf) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||||
|
var err error
|
||||||
|
config := &Config{}
|
||||||
|
|
||||||
mode, err := parser.GetStringAnnotation("lua-resty-waf", ing)
|
mode, err := parser.GetStringAnnotation("lua-resty-waf", ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &Config{}, err
|
return &Config{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mode = strings.ToUpper(mode)
|
config.Mode = strings.ToUpper(mode)
|
||||||
if _, ok := luaRestyWAFModes[mode]; !ok {
|
if _, ok := luaRestyWAFModes[config.Mode]; !ok {
|
||||||
return &Config{}, errors.NewInvalidAnnotationContent("lua-resty-waf", mode)
|
return &Config{}, errors.NewInvalidAnnotationContent("lua-resty-waf", mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
debug, _ := parser.GetBoolAnnotation("lua-resty-waf-debug", ing)
|
config.Debug, _ = parser.GetBoolAnnotation("lua-resty-waf-debug", ing)
|
||||||
|
|
||||||
ignoredRuleSetsStr, _ := parser.GetStringAnnotation("lua-resty-waf-ignore-rulesets", ing)
|
ignoredRuleSetsStr, _ := parser.GetStringAnnotation("lua-resty-waf-ignore-rulesets", ing)
|
||||||
ignoredRuleSets := strings.FieldsFunc(ignoredRuleSetsStr, func(c rune) bool {
|
config.IgnoredRuleSets = strings.FieldsFunc(ignoredRuleSetsStr, func(c rune) bool {
|
||||||
strC := string(c)
|
strC := string(c)
|
||||||
return strC == "," || strC == " "
|
return strC == "," || strC == " "
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO(elvinefendi) maybe validate the ruleset string here
|
// TODO(elvinefendi) maybe validate the ruleset string here
|
||||||
extraRulesetString, _ := parser.GetStringAnnotation("lua-resty-waf-extra-rules", ing)
|
config.ExtraRulesetString, _ = parser.GetStringAnnotation("lua-resty-waf-extra-rules", ing)
|
||||||
|
|
||||||
scoreThreshold, _ := parser.GetIntAnnotation("lua-resty-waf-score-threshold", ing)
|
config.ScoreThreshold, _ = parser.GetIntAnnotation("lua-resty-waf-score-threshold", ing)
|
||||||
|
|
||||||
allowUnknownContentTypes, _ := parser.GetBoolAnnotation("lua-resty-waf-allow-unknown-content-types", ing)
|
config.AllowUnknownContentTypes, _ = parser.GetBoolAnnotation("lua-resty-waf-allow-unknown-content-types", ing)
|
||||||
|
|
||||||
processMultipartBody, err := parser.GetBoolAnnotation("lua-resty-waf-process-multipart-body", ing)
|
config.ProcessMultipartBody, err = parser.GetBoolAnnotation("lua-resty-waf-process-multipart-body", ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
processMultipartBody = true
|
config.ProcessMultipartBody = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Config{
|
return config, nil
|
||||||
Mode: mode,
|
|
||||||
Debug: debug,
|
|
||||||
IgnoredRuleSets: ignoredRuleSets,
|
|
||||||
ExtraRulesetString: extraRulesetString,
|
|
||||||
ScoreThreshold: scoreThreshold,
|
|
||||||
AllowUnknownContentTypes: allowUnknownContentTypes,
|
|
||||||
ProcessMultipartBody: processMultipartBody,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,31 +66,28 @@ type modSecurity struct {
|
||||||
// Parse parses the annotations contained in the ingress
|
// Parse parses the annotations contained in the ingress
|
||||||
// rule used to enable ModSecurity in a particular location
|
// rule used to enable ModSecurity in a particular location
|
||||||
func (a modSecurity) Parse(ing *extensions.Ingress) (interface{}, error) {
|
func (a modSecurity) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||||
|
var err error
|
||||||
|
config := &Config{}
|
||||||
|
|
||||||
enableModSecurity, err := parser.GetBoolAnnotation("enable-modsecurity", ing)
|
config.Enable, err = parser.GetBoolAnnotation("enable-modsecurity", ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
enableModSecurity = false
|
config.Enable = false
|
||||||
}
|
}
|
||||||
|
|
||||||
owaspRules, err := parser.GetBoolAnnotation("enable-owasp-core-rules", ing)
|
config.OWASPRules, err = parser.GetBoolAnnotation("enable-owasp-core-rules", ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
owaspRules = false
|
config.OWASPRules = false
|
||||||
}
|
}
|
||||||
|
|
||||||
transactionID, err := parser.GetStringAnnotation("modsecurity-transaction-id", ing)
|
config.TransactionID, err = parser.GetStringAnnotation("modsecurity-transaction-id", ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
transactionID = ""
|
config.TransactionID = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
snippet, err := parser.GetStringAnnotation("modsecurity-snippet", ing)
|
config.Snippet, err = parser.GetStringAnnotation("modsecurity-snippet", ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
snippet = ""
|
config.Snippet = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return Config{
|
return config, nil
|
||||||
Enable: enableModSecurity,
|
|
||||||
OWASPRules: owaspRules,
|
|
||||||
TransactionID: transactionID,
|
|
||||||
Snippet: snippet,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,8 @@ func TestParse(t *testing.T) {
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
ing.SetAnnotations(testCase.annotations)
|
ing.SetAnnotations(testCase.annotations)
|
||||||
result, _ := ap.Parse(ing)
|
result, _ := ap.Parse(ing)
|
||||||
if result != testCase.expected {
|
config := result.(*Config)
|
||||||
|
if !config.Equal(&testCase.expected) {
|
||||||
t.Errorf("expected %v but returned %v, annotations: %s", testCase.expected, result, testCase.annotations)
|
t.Errorf("expected %v but returned %v, annotations: %s", testCase.expected, result, testCase.annotations)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,10 @@ func (a ingAnnotations) parseBool(name string) (bool, error) {
|
||||||
func (a ingAnnotations) parseString(name string) (string, error) {
|
func (a ingAnnotations) parseString(name string) (string, error) {
|
||||||
val, ok := a[name]
|
val, ok := a[name]
|
||||||
if ok {
|
if ok {
|
||||||
|
if len(val) == 0 {
|
||||||
|
return "", errors.NewInvalidAnnotationContent(name, val)
|
||||||
|
}
|
||||||
|
|
||||||
return val, nil
|
return val, nil
|
||||||
}
|
}
|
||||||
return "", errors.ErrMissingAnnotations
|
return "", errors.ErrMissingAnnotations
|
||||||
|
@ -97,6 +101,7 @@ func GetStringAnnotation(name string, ing *extensions.Ingress) (string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return ingAnnotations(ing.GetAnnotations()).parseString(v)
|
return ingAnnotations(ing.GetAnnotations()).parseString(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,7 @@ func TestGetStringAnnotation(t *testing.T) {
|
||||||
|
|
||||||
_, err := GetStringAnnotation("", nil)
|
_, err := GetStringAnnotation("", nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("expected error but retuned nil")
|
t.Errorf("expected error but none returned")
|
||||||
}
|
}
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
@ -91,6 +91,7 @@ func TestGetStringAnnotation(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{"valid - A", "string", "A", "A", false},
|
{"valid - A", "string", "A", "A", false},
|
||||||
{"valid - B", "string", "B", "B", false},
|
{"valid - B", "string", "B", "B", false},
|
||||||
|
{"empty", "string", "", "", true},
|
||||||
}
|
}
|
||||||
|
|
||||||
data := map[string]string{}
|
data := map[string]string{}
|
||||||
|
@ -102,7 +103,7 @@ func TestGetStringAnnotation(t *testing.T) {
|
||||||
s, err := GetStringAnnotation(test.field, ing)
|
s, err := GetStringAnnotation(test.field, ing)
|
||||||
if test.expErr {
|
if test.expErr {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("%v: expected error but retuned nil", test.name)
|
t.Errorf("%v: expected error but none returned", test.name)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,72 +103,75 @@ func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
||||||
// ParseAnnotations parses the annotations contained in the ingress
|
// ParseAnnotations parses the annotations contained in the ingress
|
||||||
// rule used to configure upstream check parameters
|
// rule used to configure upstream check parameters
|
||||||
func (a proxy) Parse(ing *extensions.Ingress) (interface{}, error) {
|
func (a proxy) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||||
|
|
||||||
defBackend := a.r.GetDefaultBackend()
|
defBackend := a.r.GetDefaultBackend()
|
||||||
ct, err := parser.GetIntAnnotation("proxy-connect-timeout", ing)
|
config := &Config{}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
config.ConnectTimeout, err = parser.GetIntAnnotation("proxy-connect-timeout", ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ct = defBackend.ProxyConnectTimeout
|
config.ConnectTimeout = defBackend.ProxyConnectTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
st, err := parser.GetIntAnnotation("proxy-send-timeout", ing)
|
config.SendTimeout, err = parser.GetIntAnnotation("proxy-send-timeout", ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
st = defBackend.ProxySendTimeout
|
config.SendTimeout = defBackend.ProxySendTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
rt, err := parser.GetIntAnnotation("proxy-read-timeout", ing)
|
config.ReadTimeout, err = parser.GetIntAnnotation("proxy-read-timeout", ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rt = defBackend.ProxyReadTimeout
|
config.ReadTimeout = defBackend.ProxyReadTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
bufs, err := parser.GetStringAnnotation("proxy-buffer-size", ing)
|
config.BufferSize, err = parser.GetStringAnnotation("proxy-buffer-size", ing)
|
||||||
if err != nil || bufs == "" {
|
|
||||||
bufs = defBackend.ProxyBufferSize
|
|
||||||
}
|
|
||||||
|
|
||||||
cp, err := parser.GetStringAnnotation("proxy-cookie-path", ing)
|
|
||||||
if err != nil || cp == "" {
|
|
||||||
cp = defBackend.ProxyCookiePath
|
|
||||||
}
|
|
||||||
|
|
||||||
cd, err := parser.GetStringAnnotation("proxy-cookie-domain", ing)
|
|
||||||
if err != nil || cd == "" {
|
|
||||||
cd = defBackend.ProxyCookieDomain
|
|
||||||
}
|
|
||||||
|
|
||||||
bs, err := parser.GetStringAnnotation("proxy-body-size", ing)
|
|
||||||
if err != nil || bs == "" {
|
|
||||||
bs = defBackend.ProxyBodySize
|
|
||||||
}
|
|
||||||
|
|
||||||
nu, err := parser.GetStringAnnotation("proxy-next-upstream", ing)
|
|
||||||
if err != nil || nu == "" {
|
|
||||||
nu = defBackend.ProxyNextUpstream
|
|
||||||
}
|
|
||||||
|
|
||||||
nut, err := parser.GetIntAnnotation("proxy-next-upstream-tries", ing)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
nut = defBackend.ProxyNextUpstreamTries
|
config.BufferSize = defBackend.ProxyBufferSize
|
||||||
}
|
}
|
||||||
|
|
||||||
rb, err := parser.GetStringAnnotation("proxy-request-buffering", ing)
|
config.CookiePath, err = parser.GetStringAnnotation("proxy-cookie-path", ing)
|
||||||
if err != nil || rb == "" {
|
if err != nil {
|
||||||
rb = defBackend.ProxyRequestBuffering
|
config.CookiePath = defBackend.ProxyCookiePath
|
||||||
}
|
}
|
||||||
|
|
||||||
prf, err := parser.GetStringAnnotation("proxy-redirect-from", ing)
|
config.CookieDomain, err = parser.GetStringAnnotation("proxy-cookie-domain", ing)
|
||||||
if err != nil || prf == "" {
|
if err != nil {
|
||||||
prf = defBackend.ProxyRedirectFrom
|
config.CookieDomain = defBackend.ProxyCookieDomain
|
||||||
}
|
}
|
||||||
|
|
||||||
prt, err := parser.GetStringAnnotation("proxy-redirect-to", ing)
|
config.BodySize, err = parser.GetStringAnnotation("proxy-body-size", ing)
|
||||||
if err != nil || rb == "" {
|
if err != nil {
|
||||||
prt = defBackend.ProxyRedirectTo
|
config.BodySize = defBackend.ProxyBodySize
|
||||||
}
|
}
|
||||||
|
|
||||||
pb, err := parser.GetStringAnnotation("proxy-buffering", ing)
|
config.NextUpstream, err = parser.GetStringAnnotation("proxy-next-upstream", ing)
|
||||||
if err != nil || pb == "" {
|
if err != nil {
|
||||||
pb = defBackend.ProxyBuffering
|
config.NextUpstream = defBackend.ProxyNextUpstream
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Config{bs, ct, st, rt, bufs, cd, cp, nu, nut, prf, prt, rb, pb}, nil
|
config.NextUpstreamTries, err = parser.GetIntAnnotation("proxy-next-upstream-tries", ing)
|
||||||
|
if err != nil {
|
||||||
|
config.NextUpstreamTries = defBackend.ProxyNextUpstreamTries
|
||||||
|
}
|
||||||
|
|
||||||
|
config.RequestBuffering, err = parser.GetStringAnnotation("proxy-request-buffering", ing)
|
||||||
|
if err != nil {
|
||||||
|
config.RequestBuffering = defBackend.ProxyRequestBuffering
|
||||||
|
}
|
||||||
|
|
||||||
|
config.ProxyRedirectFrom, err = parser.GetStringAnnotation("proxy-redirect-from", ing)
|
||||||
|
if err != nil {
|
||||||
|
config.ProxyRedirectFrom = defBackend.ProxyRedirectFrom
|
||||||
|
}
|
||||||
|
|
||||||
|
config.ProxyRedirectTo, err = parser.GetStringAnnotation("proxy-redirect-to", ing)
|
||||||
|
if err != nil {
|
||||||
|
config.ProxyRedirectTo = defBackend.ProxyRedirectTo
|
||||||
|
}
|
||||||
|
|
||||||
|
config.ProxyBuffering, err = parser.GetStringAnnotation("proxy-buffering", ing)
|
||||||
|
if err != nil {
|
||||||
|
config.ProxyBuffering = defBackend.ProxyBuffering
|
||||||
|
}
|
||||||
|
|
||||||
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,27 +87,24 @@ func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
||||||
// ParseAnnotations parses the annotations contained in the ingress
|
// ParseAnnotations parses the annotations contained in the ingress
|
||||||
// rule used to rewrite the defined paths
|
// rule used to rewrite the defined paths
|
||||||
func (a rewrite) Parse(ing *extensions.Ingress) (interface{}, error) {
|
func (a rewrite) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||||
rt, _ := parser.GetStringAnnotation("rewrite-target", ing)
|
var err error
|
||||||
sslRe, err := parser.GetBoolAnnotation("ssl-redirect", ing)
|
config := &Config{}
|
||||||
if err != nil {
|
|
||||||
sslRe = a.r.GetDefaultBackend().SSLRedirect
|
|
||||||
}
|
|
||||||
fSslRe, err := parser.GetBoolAnnotation("force-ssl-redirect", ing)
|
|
||||||
if err != nil {
|
|
||||||
fSslRe = a.r.GetDefaultBackend().ForceSSLRedirect
|
|
||||||
}
|
|
||||||
abu, _ := parser.GetBoolAnnotation("add-base-url", ing)
|
|
||||||
bus, _ := parser.GetStringAnnotation("base-url-scheme", ing)
|
|
||||||
ar, _ := parser.GetStringAnnotation("app-root", ing)
|
|
||||||
ur, _ := parser.GetBoolAnnotation("use-regex", ing)
|
|
||||||
|
|
||||||
return &Config{
|
config.Target, _ = parser.GetStringAnnotation("rewrite-target", ing)
|
||||||
Target: rt,
|
config.SSLRedirect, err = parser.GetBoolAnnotation("ssl-redirect", ing)
|
||||||
AddBaseURL: abu,
|
if err != nil {
|
||||||
BaseURLScheme: bus,
|
config.SSLRedirect = a.r.GetDefaultBackend().SSLRedirect
|
||||||
SSLRedirect: sslRe,
|
}
|
||||||
ForceSSLRedirect: fSslRe,
|
|
||||||
AppRoot: ar,
|
config.ForceSSLRedirect, err = parser.GetBoolAnnotation("force-ssl-redirect", ing)
|
||||||
UseRegex: ur,
|
if err != nil {
|
||||||
}, nil
|
config.ForceSSLRedirect = a.r.GetDefaultBackend().ForceSSLRedirect
|
||||||
|
}
|
||||||
|
|
||||||
|
config.AddBaseURL, _ = parser.GetBoolAnnotation("add-base-url", ing)
|
||||||
|
config.BaseURLScheme, _ = parser.GetStringAnnotation("base-url-scheme", ing)
|
||||||
|
config.AppRoot, _ = parser.GetStringAnnotation("app-root", ing)
|
||||||
|
config.UseRegex, _ = parser.GetBoolAnnotation("use-regex", ing)
|
||||||
|
|
||||||
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,42 +81,39 @@ type Cookie struct {
|
||||||
// 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
|
// It also sets default values when no value or incorrect value is found
|
||||||
func (a affinity) cookieAffinityParse(ing *extensions.Ingress) *Cookie {
|
func (a affinity) cookieAffinityParse(ing *extensions.Ingress) *Cookie {
|
||||||
|
var err error
|
||||||
|
|
||||||
cookie := &Cookie{}
|
cookie := &Cookie{}
|
||||||
sn, err := parser.GetStringAnnotation(annotationAffinityCookieName, ing)
|
|
||||||
|
|
||||||
if err != nil || sn == "" {
|
cookie.Name, err = parser.GetStringAnnotation(annotationAffinityCookieName, ing)
|
||||||
|
if err != nil {
|
||||||
glog.V(3).Infof("Ingress %v: No value found in annotation %v. Using the default %v", ing.Name, annotationAffinityCookieName, defaultAffinityCookieName)
|
glog.V(3).Infof("Ingress %v: No value found in annotation %v. Using the default %v", ing.Name, annotationAffinityCookieName, defaultAffinityCookieName)
|
||||||
sn = defaultAffinityCookieName
|
cookie.Name = defaultAffinityCookieName
|
||||||
}
|
}
|
||||||
cookie.Name = sn
|
|
||||||
|
|
||||||
sh, err := parser.GetStringAnnotation(annotationAffinityCookieHash, ing)
|
cookie.Hash, err = parser.GetStringAnnotation(annotationAffinityCookieHash, ing)
|
||||||
|
if err != nil || !affinityCookieHashRegex.MatchString(cookie.Hash) {
|
||||||
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)
|
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
|
cookie.Hash = defaultAffinityCookieHash
|
||||||
}
|
}
|
||||||
cookie.Hash = sh
|
|
||||||
|
|
||||||
se, err := parser.GetStringAnnotation(annotationAffinityCookieExpires, ing)
|
cookie.Expires, err = parser.GetStringAnnotation(annotationAffinityCookieExpires, ing)
|
||||||
if err != nil || !affinityCookieExpiresRegex.MatchString(se) {
|
if err != nil || !affinityCookieExpiresRegex.MatchString(cookie.Expires) {
|
||||||
glog.V(3).Infof("Invalid or no annotation value found in Ingress %v: %v. Ignoring it", ing.Name, annotationAffinityCookieExpires)
|
glog.V(3).Infof("Invalid or no annotation value found in Ingress %v: %v. Ignoring it", ing.Name, annotationAffinityCookieExpires)
|
||||||
se = ""
|
cookie.Expires = ""
|
||||||
}
|
}
|
||||||
cookie.Expires = se
|
|
||||||
|
|
||||||
sm, err := parser.GetStringAnnotation(annotationAffinityCookieMaxAge, ing)
|
cookie.MaxAge, err = parser.GetStringAnnotation(annotationAffinityCookieMaxAge, ing)
|
||||||
if err != nil || !affinityCookieExpiresRegex.MatchString(sm) {
|
if err != nil || !affinityCookieExpiresRegex.MatchString(cookie.MaxAge) {
|
||||||
glog.V(3).Infof("Invalid or no annotation value found in Ingress %v: %v. Ignoring it", ing.Name, annotationAffinityCookieMaxAge)
|
glog.V(3).Infof("Invalid or no annotation value found in Ingress %v: %v. Ignoring it", ing.Name, annotationAffinityCookieMaxAge)
|
||||||
sm = ""
|
cookie.MaxAge = ""
|
||||||
}
|
}
|
||||||
cookie.MaxAge = sm
|
|
||||||
|
|
||||||
sp, err := parser.GetStringAnnotation(annotationAffinityCookiePath, ing)
|
cookie.Path, err = parser.GetStringAnnotation(annotationAffinityCookiePath, ing)
|
||||||
if err != nil || sp == "" {
|
if err != nil {
|
||||||
glog.V(3).Infof("Invalid or no annotation value found in Ingress %v: %v. Ignoring it", ing.Name, annotationAffinityCookieMaxAge)
|
glog.V(3).Infof("Invalid or no annotation value found in Ingress %v: %v. Ignoring it", ing.Name, annotationAffinityCookieMaxAge)
|
||||||
}
|
}
|
||||||
cookie.Path = sp
|
|
||||||
return cookie
|
return cookie
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,16 +18,16 @@ package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/client-go/tools/cache"
|
"k8s.io/client-go/tools/cache"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations"
|
"k8s.io/ingress-nginx/internal/ingress"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IngressAnnotationsLister makes a Store that lists annotations in Ingress rules.
|
// IngressWithAnnotationsLister makes a Store that lists Ingress rules with annotations already parsed
|
||||||
type IngressAnnotationsLister struct {
|
type IngressWithAnnotationsLister struct {
|
||||||
cache.Store
|
cache.Store
|
||||||
}
|
}
|
||||||
|
|
||||||
// ByKey returns the Ingress annotations matching key in the local Ingress annotations Store.
|
// ByKey returns the Ingress with annotations matching key in the local store or an error
|
||||||
func (il IngressAnnotationsLister) ByKey(key string) (*annotations.Ingress, error) {
|
func (il IngressWithAnnotationsLister) ByKey(key string) (*ingress.Ingress, error) {
|
||||||
i, exists, err := il.GetByKey(key)
|
i, exists, err := il.GetByKey(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -35,5 +35,5 @@ func (il IngressAnnotationsLister) ByKey(key string) (*annotations.Ingress, erro
|
||||||
if !exists {
|
if !exists {
|
||||||
return nil, NotExistsError(key)
|
return nil, NotExistsError(key)
|
||||||
}
|
}
|
||||||
return i.(*annotations.Ingress), nil
|
return i.(*ingress.Ingress), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,9 +73,6 @@ type Storer interface {
|
||||||
// GetServiceEndpoints returns the Endpoints of a Service matching key.
|
// GetServiceEndpoints returns the Endpoints of a Service matching key.
|
||||||
GetServiceEndpoints(key string) (*corev1.Endpoints, error)
|
GetServiceEndpoints(key string) (*corev1.Endpoints, error)
|
||||||
|
|
||||||
// GetIngress returns the Ingress matching key.
|
|
||||||
GetIngress(key string) (*extensions.Ingress, error)
|
|
||||||
|
|
||||||
// ListIngresses returns a list of all Ingresses in the store.
|
// ListIngresses returns a list of all Ingresses in the store.
|
||||||
ListIngresses() []*ingress.Ingress
|
ListIngresses() []*ingress.Ingress
|
||||||
|
|
||||||
|
@ -137,7 +134,7 @@ type Lister struct {
|
||||||
Endpoint EndpointLister
|
Endpoint EndpointLister
|
||||||
Secret SecretLister
|
Secret SecretLister
|
||||||
ConfigMap ConfigMapLister
|
ConfigMap ConfigMapLister
|
||||||
IngressAnnotation IngressAnnotationsLister
|
IngressWithAnnotation IngressWithAnnotationsLister
|
||||||
Pod PodLister
|
Pod PodLister
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +258,7 @@ func New(checkOCSP bool,
|
||||||
// k8sStore fulfills resolver.Resolver interface
|
// k8sStore fulfills resolver.Resolver interface
|
||||||
store.annotations = annotations.NewAnnotationExtractor(store)
|
store.annotations = annotations.NewAnnotationExtractor(store)
|
||||||
|
|
||||||
store.listers.IngressAnnotation.Store = cache.NewStore(cache.DeletionHandlingMetaNamespaceKeyFunc)
|
store.listers.IngressWithAnnotation.Store = cache.NewStore(cache.DeletionHandlingMetaNamespaceKeyFunc)
|
||||||
|
|
||||||
// create informers factory, enable and assign required informers
|
// create informers factory, enable and assign required informers
|
||||||
infFactory := informers.NewSharedInformerFactoryWithOptions(client, resyncPeriod,
|
infFactory := informers.NewSharedInformerFactoryWithOptions(client, resyncPeriod,
|
||||||
|
@ -313,7 +310,7 @@ func New(checkOCSP bool,
|
||||||
}
|
}
|
||||||
recorder.Eventf(ing, corev1.EventTypeNormal, "CREATE", fmt.Sprintf("Ingress %s/%s", ing.Namespace, ing.Name))
|
recorder.Eventf(ing, corev1.EventTypeNormal, "CREATE", fmt.Sprintf("Ingress %s/%s", ing.Namespace, ing.Name))
|
||||||
|
|
||||||
store.extractAnnotations(ing)
|
store.syncIngress(ing)
|
||||||
store.updateSecretIngressMap(ing)
|
store.updateSecretIngressMap(ing)
|
||||||
store.syncSecrets(ing)
|
store.syncSecrets(ing)
|
||||||
|
|
||||||
|
@ -343,7 +340,7 @@ func New(checkOCSP bool,
|
||||||
}
|
}
|
||||||
recorder.Eventf(ing, corev1.EventTypeNormal, "DELETE", fmt.Sprintf("Ingress %s/%s", ing.Namespace, ing.Name))
|
recorder.Eventf(ing, corev1.EventTypeNormal, "DELETE", fmt.Sprintf("Ingress %s/%s", ing.Namespace, ing.Name))
|
||||||
|
|
||||||
store.listers.IngressAnnotation.Delete(ing)
|
store.listers.IngressWithAnnotation.Delete(ing)
|
||||||
|
|
||||||
key := k8s.MetaNamespaceKey(ing)
|
key := k8s.MetaNamespaceKey(ing)
|
||||||
store.secretIngressMap.Delete(key)
|
store.secretIngressMap.Delete(key)
|
||||||
|
@ -368,7 +365,7 @@ func New(checkOCSP bool,
|
||||||
recorder.Eventf(curIng, corev1.EventTypeNormal, "UPDATE", fmt.Sprintf("Ingress %s/%s", curIng.Namespace, curIng.Name))
|
recorder.Eventf(curIng, corev1.EventTypeNormal, "UPDATE", fmt.Sprintf("Ingress %s/%s", curIng.Namespace, curIng.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
store.extractAnnotations(curIng)
|
store.syncIngress(curIng)
|
||||||
store.updateSecretIngressMap(curIng)
|
store.updateSecretIngressMap(curIng)
|
||||||
store.syncSecrets(curIng)
|
store.syncSecrets(curIng)
|
||||||
|
|
||||||
|
@ -392,12 +389,12 @@ func New(checkOCSP bool,
|
||||||
if ings := store.secretIngressMap.Reference(key); len(ings) > 0 {
|
if ings := store.secretIngressMap.Reference(key); len(ings) > 0 {
|
||||||
glog.Infof("secret %v was added and it is used in ingress annotations. Parsing...", key)
|
glog.Infof("secret %v was added and it is used in ingress annotations. Parsing...", key)
|
||||||
for _, ingKey := range ings {
|
for _, ingKey := range ings {
|
||||||
ing, err := store.GetIngress(ingKey)
|
ing, err := store.getIngress(ingKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("could not find Ingress %v in local store", ingKey)
|
glog.Errorf("could not find Ingress %v in local store", ingKey)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
store.extractAnnotations(ing)
|
store.syncIngress(ing)
|
||||||
store.syncSecrets(ing)
|
store.syncSecrets(ing)
|
||||||
}
|
}
|
||||||
updateCh.In() <- Event{
|
updateCh.In() <- Event{
|
||||||
|
@ -419,12 +416,12 @@ func New(checkOCSP bool,
|
||||||
if ings := store.secretIngressMap.Reference(key); len(ings) > 0 {
|
if ings := store.secretIngressMap.Reference(key); len(ings) > 0 {
|
||||||
glog.Infof("secret %v was updated and it is used in ingress annotations. Parsing...", key)
|
glog.Infof("secret %v was updated and it is used in ingress annotations. Parsing...", key)
|
||||||
for _, ingKey := range ings {
|
for _, ingKey := range ings {
|
||||||
ing, err := store.GetIngress(ingKey)
|
ing, err := store.getIngress(ingKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("could not find Ingress %v in local store", ingKey)
|
glog.Errorf("could not find Ingress %v in local store", ingKey)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
store.extractAnnotations(ing)
|
store.syncIngress(ing)
|
||||||
store.syncSecrets(ing)
|
store.syncSecrets(ing)
|
||||||
}
|
}
|
||||||
updateCh.In() <- Event{
|
updateCh.In() <- Event{
|
||||||
|
@ -458,12 +455,12 @@ func New(checkOCSP bool,
|
||||||
if ings := store.secretIngressMap.Reference(key); len(ings) > 0 {
|
if ings := store.secretIngressMap.Reference(key); len(ings) > 0 {
|
||||||
glog.Infof("secret %v was deleted and it is used in ingress annotations. Parsing...", key)
|
glog.Infof("secret %v was deleted and it is used in ingress annotations. Parsing...", key)
|
||||||
for _, ingKey := range ings {
|
for _, ingKey := range ings {
|
||||||
ing, err := store.GetIngress(ingKey)
|
ing, err := store.getIngress(ingKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("could not find Ingress %v in local store", ingKey)
|
glog.Errorf("could not find Ingress %v in local store", ingKey)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
store.extractAnnotations(ing)
|
store.syncIngress(ing)
|
||||||
}
|
}
|
||||||
updateCh.In() <- Event{
|
updateCh.In() <- Event{
|
||||||
Type: DeleteEvent,
|
Type: DeleteEvent,
|
||||||
|
@ -525,15 +522,15 @@ func New(checkOCSP bool,
|
||||||
store.setConfig(cm)
|
store.setConfig(cm)
|
||||||
}
|
}
|
||||||
|
|
||||||
ings := store.listers.IngressAnnotation.List()
|
ings := store.listers.IngressWithAnnotation.List()
|
||||||
for _, ingKey := range ings {
|
for _, ingKey := range ings {
|
||||||
key := k8s.MetaNamespaceKey(ingKey)
|
key := k8s.MetaNamespaceKey(ingKey)
|
||||||
ing, err := store.GetIngress(key)
|
ing, err := store.getIngress(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("could not find Ingress %v in local store: %v", key, err)
|
glog.Errorf("could not find Ingress %v in local store: %v", key, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
store.extractAnnotations(ing)
|
store.syncIngress(ing)
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCh.In() <- Event{
|
updateCh.In() <- Event{
|
||||||
|
@ -591,15 +588,32 @@ func New(checkOCSP bool,
|
||||||
return store
|
return store
|
||||||
}
|
}
|
||||||
|
|
||||||
// extractAnnotations parses ingress annotations converting the value of the
|
// syncIngress parses ingress annotations converting the value of the
|
||||||
// annotation to a go struct and also information about the referenced secrets
|
// annotation to a go struct
|
||||||
func (s *k8sStore) extractAnnotations(ing *extensions.Ingress) {
|
func (s *k8sStore) syncIngress(ing *extensions.Ingress) {
|
||||||
key := k8s.MetaNamespaceKey(ing)
|
key := k8s.MetaNamespaceKey(ing)
|
||||||
glog.V(3).Infof("updating annotations information for ingress %v", key)
|
glog.V(3).Infof("updating annotations information for ingress %v", key)
|
||||||
|
|
||||||
anns := s.annotations.Extract(ing)
|
copyIng := &extensions.Ingress{}
|
||||||
|
ing.ObjectMeta.DeepCopyInto(©Ing.ObjectMeta)
|
||||||
|
ing.Spec.DeepCopyInto(©Ing.Spec)
|
||||||
|
|
||||||
err := s.listers.IngressAnnotation.Update(anns)
|
for ri, rule := range copyIng.Spec.Rules {
|
||||||
|
if rule.HTTP == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for pi, path := range rule.HTTP.Paths {
|
||||||
|
if path.Path == "" {
|
||||||
|
copyIng.Spec.Rules[ri].HTTP.Paths[pi].Path = "/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.listers.IngressWithAnnotation.Update(&ingress.Ingress{
|
||||||
|
Ingress: *copyIng,
|
||||||
|
ParsedAnnotations: s.annotations.Extract(ing),
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Error(err)
|
glog.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -651,7 +665,7 @@ func (s *k8sStore) updateSecretIngressMap(ing *extensions.Ingress) {
|
||||||
// 'namespace/name' key from the given annotation name.
|
// 'namespace/name' key from the given annotation name.
|
||||||
func objectRefAnnotationNsKey(ann string, ing *extensions.Ingress) (string, error) {
|
func objectRefAnnotationNsKey(ann string, ing *extensions.Ingress) (string, error) {
|
||||||
annValue, err := parser.GetStringAnnotation(ann, ing)
|
annValue, err := parser.GetStringAnnotation(ann, ing)
|
||||||
if annValue == "" {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -697,59 +711,28 @@ func (s k8sStore) GetService(key string) (*corev1.Service, error) {
|
||||||
return s.listers.Service.ByKey(key)
|
return s.listers.Service.ByKey(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIngress returns the Ingress matching key.
|
// getIngress returns the Ingress matching key.
|
||||||
func (s k8sStore) GetIngress(key string) (*extensions.Ingress, error) {
|
func (s k8sStore) getIngress(key string) (*extensions.Ingress, error) {
|
||||||
return s.listers.Ingress.ByKey(key)
|
ing, err := s.listers.IngressWithAnnotation.ByKey(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ing.Ingress, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListIngresses returns the list of Ingresses
|
// ListIngresses returns the list of Ingresses
|
||||||
func (s k8sStore) ListIngresses() []*ingress.Ingress {
|
func (s k8sStore) ListIngresses() []*ingress.Ingress {
|
||||||
// filter ingress rules
|
// filter ingress rules
|
||||||
var ingresses []*ingress.Ingress
|
ingresses := make([]*ingress.Ingress, 0)
|
||||||
for _, item := range s.listers.Ingress.List() {
|
for _, item := range s.listers.IngressWithAnnotation.List() {
|
||||||
ing := item.(*extensions.Ingress)
|
ing := item.(*ingress.Ingress)
|
||||||
if !class.IsValid(ing) {
|
ingresses = append(ingresses, ing)
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
ingKey := k8s.MetaNamespaceKey(ing)
|
|
||||||
anns, err := s.getIngressAnnotations(ingKey)
|
|
||||||
if err != nil {
|
|
||||||
glog.Errorf("Error getting Ingress annotations %q: %v", ingKey, err)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
for ri, rule := range ing.Spec.Rules {
|
|
||||||
if rule.HTTP == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for pi, path := range rule.HTTP.Paths {
|
|
||||||
if path.Path == "" {
|
|
||||||
ing.Spec.Rules[ri].HTTP.Paths[pi].Path = "/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ingresses = append(ingresses, &ingress.Ingress{
|
|
||||||
Ingress: *ing,
|
|
||||||
ParsedAnnotations: anns,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ingresses
|
return ingresses
|
||||||
}
|
}
|
||||||
|
|
||||||
// getIngressAnnotations returns the parsed annotations of an Ingress matching key.
|
|
||||||
func (s k8sStore) getIngressAnnotations(key string) (*annotations.Ingress, error) {
|
|
||||||
ia, err := s.listers.IngressAnnotation.ByKey(key)
|
|
||||||
if err != nil {
|
|
||||||
return &annotations.Ingress{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ia, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLocalSSLCert returns the local copy of a SSLCert
|
// GetLocalSSLCert returns the local copy of a SSLCert
|
||||||
func (s k8sStore) GetLocalSSLCert(key string) (*ingress.SSLCert, error) {
|
func (s k8sStore) GetLocalSSLCert(key string) (*ingress.SSLCert, error) {
|
||||||
return s.sslStore.ByKey(key)
|
return s.sslStore.ByKey(key)
|
||||||
|
|
|
@ -38,6 +38,7 @@ import (
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/client-go/kubernetes/fake"
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
"k8s.io/ingress-nginx/internal/file"
|
"k8s.io/ingress-nginx/internal/file"
|
||||||
|
"k8s.io/ingress-nginx/internal/ingress"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||||
"k8s.io/ingress-nginx/internal/k8s"
|
"k8s.io/ingress-nginx/internal/k8s"
|
||||||
"k8s.io/ingress-nginx/test/e2e/framework"
|
"k8s.io/ingress-nginx/test/e2e/framework"
|
||||||
|
@ -86,14 +87,6 @@ func TestStore(t *testing.T) {
|
||||||
storer.Run(stopCh)
|
storer.Run(stopCh)
|
||||||
|
|
||||||
key := fmt.Sprintf("%v/anything", ns)
|
key := fmt.Sprintf("%v/anything", ns)
|
||||||
ing, err := storer.GetIngress(key)
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("expected an error but none returned")
|
|
||||||
}
|
|
||||||
if ing != nil {
|
|
||||||
t.Errorf("expected an Ingres but none returned")
|
|
||||||
}
|
|
||||||
|
|
||||||
ls, err := storer.GetLocalSSLCert(key)
|
ls, err := storer.GetLocalSSLCert(key)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("expected an error but none returned")
|
t.Errorf("expected an error but none returned")
|
||||||
|
@ -754,7 +747,7 @@ func newStore(t *testing.T) *k8sStore {
|
||||||
listers: &Lister{
|
listers: &Lister{
|
||||||
// add more listers if needed
|
// add more listers if needed
|
||||||
Ingress: IngressLister{cache.NewStore(cache.MetaNamespaceKeyFunc)},
|
Ingress: IngressLister{cache.NewStore(cache.MetaNamespaceKeyFunc)},
|
||||||
IngressAnnotation: IngressAnnotationsLister{cache.NewStore(cache.DeletionHandlingMetaNamespaceKeyFunc)},
|
IngressWithAnnotation: IngressWithAnnotationsLister{cache.NewStore(cache.DeletionHandlingMetaNamespaceKeyFunc)},
|
||||||
Pod: PodLister{cache.NewStore(cache.MetaNamespaceKeyFunc)},
|
Pod: PodLister{cache.NewStore(cache.MetaNamespaceKeyFunc)},
|
||||||
},
|
},
|
||||||
sslStore: NewSSLCertTracker(),
|
sslStore: NewSSLCertTracker(),
|
||||||
|
@ -833,26 +826,8 @@ func TestUpdateSecretIngressMap(t *testing.T) {
|
||||||
func TestListIngresses(t *testing.T) {
|
func TestListIngresses(t *testing.T) {
|
||||||
s := newStore(t)
|
s := newStore(t)
|
||||||
|
|
||||||
ingEmptyClass := &extensions.Ingress{
|
ingressToIgnore := &ingress.Ingress{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
Ingress: extensions.Ingress{
|
||||||
Name: "test-1",
|
|
||||||
Namespace: "testns",
|
|
||||||
},
|
|
||||||
Spec: extensions.IngressSpec{
|
|
||||||
Backend: &extensions.IngressBackend{
|
|
||||||
ServiceName: "demo",
|
|
||||||
ServicePort: intstr.FromInt(80),
|
|
||||||
},
|
|
||||||
Rules: []extensions.IngressRule{
|
|
||||||
{
|
|
||||||
Host: "foo.bar",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
s.listers.Ingress.Add(ingEmptyClass)
|
|
||||||
|
|
||||||
ingressToIgnore := &extensions.Ingress{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "test-2",
|
Name: "test-2",
|
||||||
Namespace: "testns",
|
Namespace: "testns",
|
||||||
|
@ -866,10 +841,12 @@ func TestListIngresses(t *testing.T) {
|
||||||
ServicePort: intstr.FromInt(80),
|
ServicePort: intstr.FromInt(80),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
s.listers.Ingress.Add(ingressToIgnore)
|
s.listers.IngressWithAnnotation.Add(ingressToIgnore)
|
||||||
|
|
||||||
ingressWithoutPath := &extensions.Ingress{
|
ingressWithoutPath := &ingress.Ingress{
|
||||||
|
Ingress: extensions.Ingress{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "test-3",
|
Name: "test-3",
|
||||||
Namespace: "testns",
|
Namespace: "testns",
|
||||||
|
@ -893,10 +870,12 @@ func TestListIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
s.listers.Ingress.Add(ingressWithoutPath)
|
s.listers.IngressWithAnnotation.Add(ingressWithoutPath)
|
||||||
|
|
||||||
ingressWithNginxClass := &extensions.Ingress{
|
ingressWithNginxClass := &ingress.Ingress{
|
||||||
|
Ingress: extensions.Ingress{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "test-4",
|
Name: "test-4",
|
||||||
Namespace: "testns",
|
Namespace: "testns",
|
||||||
|
@ -924,8 +903,9 @@ func TestListIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
s.listers.Ingress.Add(ingressWithNginxClass)
|
s.listers.IngressWithAnnotation.Add(ingressWithNginxClass)
|
||||||
|
|
||||||
ingresses := s.ListIngresses()
|
ingresses := s.ListIngresses()
|
||||||
if s := len(ingresses); s != 3 {
|
if s := len(ingresses); s != 3 {
|
||||||
|
|
Loading…
Reference in a new issue