2017-02-12 23:13:39 +00:00
/ *
Copyright 2016 The Kubernetes Authors .
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
package sessionaffinity
import (
"regexp"
"github.com/golang/glog"
2017-07-16 19:19:59 +00:00
extensions "k8s.io/api/extensions/v1beta1"
2017-02-12 23:13:39 +00:00
2017-11-07 22:02:12 +00:00
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
2017-11-08 20:58:57 +00:00
"k8s.io/ingress-nginx/internal/ingress/resolver"
2017-02-12 23:13:39 +00:00
)
const (
2017-11-08 20:58:57 +00:00
annotationAffinityType = "affinity"
2017-02-12 23:13:39 +00:00
// If a cookie with this name exists,
// its value is used as an index into the list of available backends.
2017-11-08 20:58:57 +00:00
annotationAffinityCookieName = "session-cookie-name"
defaultAffinityCookieName = "INGRESSCOOKIE"
2017-02-12 23:13:39 +00:00
// This is the algorithm used by nginx to generate a value for the session cookie, if
2017-02-23 13:59:09 +00:00
// one isn't supplied and affinity is set to "cookie".
2017-11-08 20:58:57 +00:00
annotationAffinityCookieHash = "session-cookie-hash"
2017-02-12 23:13:39 +00:00
defaultAffinityCookieHash = "md5"
2018-10-29 07:21:10 +00:00
2018-11-02 09:05:38 +00:00
// This is used to control the cookie expires, its value is a number of seconds until the
// cookie expires
2018-10-29 07:21:10 +00:00
annotationAffinityCookieExpires = "session-cookie-expires"
// This is used to control the cookie expires, its value is a number of seconds until the
// cookie expires
annotationAffinityCookieMaxAge = "session-cookie-max-age"
2017-02-12 23:13:39 +00:00
)
var (
2018-10-29 07:21:10 +00:00
affinityCookieHashRegex = regexp . MustCompile ( ` ^(index|md5|sha1)$ ` )
2018-11-02 09:05:38 +00:00
affinityCookieExpiresRegex = regexp . MustCompile ( ` (^0|-?[1-9]\d*$) ` )
2017-02-12 23:13:39 +00:00
)
2017-11-07 16:36:51 +00:00
// Config describes the per ingress session affinity config
type Config struct {
2017-02-12 23:13:39 +00:00
// The type of affinity that will be used
2017-11-07 16:36:51 +00:00
Type string ` json:"type" `
Cookie
2017-02-12 23:13:39 +00:00
}
2017-11-07 16:36:51 +00:00
// Cookie describes the Config of cookie type affinity
type Cookie struct {
2017-02-12 23:13:39 +00:00
// 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" `
2018-11-02 09:05:38 +00:00
// The time duration to control cookie expires
2018-10-29 07:21:10 +00:00
Expires string ` json:"expires" `
// The number of seconds until the cookie expires
MaxAge string ` json:"maxage" `
2017-02-12 23:13:39 +00:00
}
2017-11-07 16:36:51 +00:00
// cookieAffinityParse gets the annotation values related to Cookie Affinity
2017-02-12 23:13:39 +00:00
// It also sets default values when no value or incorrect value is found
2017-11-08 20:58:57 +00:00
func ( a affinity ) cookieAffinityParse ( ing * extensions . Ingress ) * Cookie {
2018-10-29 07:21:10 +00:00
cookie := & Cookie { }
2017-11-23 16:46:23 +00:00
sn , err := parser . GetStringAnnotation ( annotationAffinityCookieName , ing )
2017-02-12 23:13:39 +00:00
if err != nil || sn == "" {
glog . V ( 3 ) . Infof ( "Ingress %v: No value found in annotation %v. Using the default %v" , ing . Name , annotationAffinityCookieName , defaultAffinityCookieName )
sn = defaultAffinityCookieName
}
2018-10-29 07:21:10 +00:00
cookie . Name = sn
2017-02-12 23:13:39 +00:00
2017-11-23 16:46:23 +00:00
sh , err := parser . GetStringAnnotation ( annotationAffinityCookieHash , ing )
2017-02-12 23:13:39 +00:00
if err != nil || ! affinityCookieHashRegex . MatchString ( sh ) {
glog . V ( 3 ) . Infof ( "Invalid or no annotation value found in Ingress %v: %v. Setting it to default %v" , ing . Name , annotationAffinityCookieHash , defaultAffinityCookieHash )
sh = defaultAffinityCookieHash
}
2018-10-29 07:21:10 +00:00
cookie . Hash = sh
se , err := parser . GetStringAnnotation ( annotationAffinityCookieExpires , ing )
2018-11-02 09:05:38 +00:00
if err != nil || ! affinityCookieExpiresRegex . MatchString ( se ) {
2018-10-29 07:21:10 +00:00
glog . V ( 3 ) . Infof ( "Invalid or no annotation value found in Ingress %v: %v. Ignoring it" , ing . Name , annotationAffinityCookieExpires )
se = ""
}
cookie . Expires = se
2017-02-12 23:13:39 +00:00
2018-10-29 07:21:10 +00:00
sm , err := parser . GetStringAnnotation ( annotationAffinityCookieMaxAge , ing )
2018-11-02 09:05:38 +00:00
if err != nil || ! affinityCookieExpiresRegex . MatchString ( sm ) {
2018-10-29 07:21:10 +00:00
glog . V ( 3 ) . Infof ( "Invalid or no annotation value found in Ingress %v: %v. Ignoring it" , ing . Name , annotationAffinityCookieMaxAge )
sm = ""
2017-02-12 23:13:39 +00:00
}
2018-10-29 07:21:10 +00:00
cookie . MaxAge = sm
return cookie
2017-02-12 23:13:39 +00:00
}
// NewParser creates a new Affinity annotation parser
2017-11-08 20:58:57 +00:00
func NewParser ( r resolver . Resolver ) parser . IngressAnnotation {
return affinity { r }
2017-02-12 23:13:39 +00:00
}
2017-02-14 10:49:10 +00:00
type affinity struct {
2017-11-08 20:58:57 +00:00
r resolver . Resolver
2017-02-14 10:49:10 +00:00
}
2017-02-12 23:13:39 +00:00
// ParseAnnotations parses the annotations contained in the ingress
// rule used to configure the affinity directives
func ( a affinity ) Parse ( ing * extensions . Ingress ) ( interface { } , error ) {
2017-11-07 16:36:51 +00:00
cookie := & Cookie { }
2017-02-12 23:13:39 +00:00
// Check the type of affinity that will be used
2017-11-23 16:46:23 +00:00
at , err := parser . GetStringAnnotation ( annotationAffinityType , ing )
2017-02-12 23:13:39 +00:00
if err != nil {
at = ""
}
2017-02-14 10:49:10 +00:00
2017-02-12 23:13:39 +00:00
switch at {
case "cookie" :
2017-11-08 20:58:57 +00:00
cookie = a . cookieAffinityParse ( ing )
2017-02-12 23:13:39 +00:00
default :
glog . V ( 3 ) . Infof ( "No default affinity was found for Ingress %v" , ing . Name )
}
2017-11-07 16:36:51 +00:00
return & Config {
Type : at ,
Cookie : * cookie ,
} , nil
2017-02-12 23:13:39 +00:00
}