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"
2019-06-09 22:49:59 +00:00
networking "k8s.io/api/networking/v1beta1"
2020-08-08 23:31:02 +00:00
"k8s.io/klog/v2"
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"
2019-08-30 09:40:29 +00:00
annotationAffinityMode = "affinity-mode"
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"
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"
2018-11-19 14:15:24 +00:00
// This is used to control the cookie path when use-regex is set to true
annotationAffinityCookiePath = "session-cookie-path"
2019-04-29 13:20:30 +00:00
2020-01-22 20:19:16 +00:00
// This is used to control the SameSite attribute of the cookie
annotationAffinityCookieSameSite = "session-cookie-samesite"
// This is used to control whether SameSite=None should be conditionally applied based on the User-Agent
annotationAffinityCookieConditionalSameSiteNone = "session-cookie-conditional-samesite-none"
2019-04-29 13:20:30 +00:00
// This is used to control the cookie change after request failure
annotationAffinityCookieChangeOnFailure = "session-cookie-change-on-failure"
2017-02-12 23:13:39 +00:00
)
var (
2019-06-06 15:02:51 +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" `
2019-08-30 09:40:29 +00:00
// The affinity mode, i.e. how sticky a session is
Mode string ` json:"mode" `
2017-11-07 16:36:51 +00:00
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" `
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" `
2018-11-19 14:15:24 +00:00
// The path that a cookie will be set on
Path string ` json:"path" `
2019-04-29 13:20:30 +00:00
// Flag that allows cookie regeneration on request failure
2019-06-06 15:02:51 +00:00
ChangeOnFailure bool ` json:"changeonfailure" `
2020-01-22 20:19:16 +00:00
// SameSite attribute value
SameSite string ` json:"samesite" `
// Flag that conditionally applies SameSite=None attribute on cookie if user agent accepts it.
ConditionalSameSiteNone bool ` json:"conditional-samesite-none" `
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
2019-06-09 22:49:59 +00:00
func ( a affinity ) cookieAffinityParse ( ing * networking . Ingress ) * Cookie {
2018-11-30 22:56:11 +00:00
var err error
2018-10-29 07:21:10 +00:00
cookie := & Cookie { }
2017-02-12 23:13:39 +00:00
2018-11-30 22:56:11 +00:00
cookie . Name , err = parser . GetStringAnnotation ( annotationAffinityCookieName , ing )
2018-12-02 18:35:12 +00:00
if err != nil {
2020-10-26 19:08:55 +00:00
klog . V ( 3 ) . InfoS ( "Invalid or no annotation value found. Ignoring" , "ingress" , klog . KObj ( ing ) , "annotation" , annotationAffinityCookieExpires , "default" , defaultAffinityCookieName )
2018-11-30 22:56:11 +00:00
cookie . Name = defaultAffinityCookieName
2017-02-12 23:13:39 +00:00
}
2018-11-30 22:56:11 +00:00
cookie . Expires , err = parser . GetStringAnnotation ( annotationAffinityCookieExpires , ing )
if err != nil || ! affinityCookieExpiresRegex . MatchString ( cookie . Expires ) {
2020-10-26 19:08:55 +00:00
klog . V ( 3 ) . InfoS ( "Invalid or no annotation value found. Ignoring" , "ingress" , klog . KObj ( ing ) , "annotation" , annotationAffinityCookieExpires )
2018-11-30 22:56:11 +00:00
cookie . Expires = ""
2018-10-29 07:21:10 +00:00
}
2017-02-12 23:13:39 +00:00
2018-11-30 22:56:11 +00:00
cookie . MaxAge , err = parser . GetStringAnnotation ( annotationAffinityCookieMaxAge , ing )
if err != nil || ! affinityCookieExpiresRegex . MatchString ( cookie . MaxAge ) {
2020-10-26 19:08:55 +00:00
klog . V ( 3 ) . InfoS ( "Invalid or no annotation value found. Ignoring" , "ingress" , klog . KObj ( ing ) , "annotation" , annotationAffinityCookieMaxAge )
2018-11-30 22:56:11 +00:00
cookie . MaxAge = ""
2017-02-12 23:13:39 +00:00
}
2018-11-19 14:15:24 +00:00
2018-11-30 22:56:11 +00:00
cookie . Path , err = parser . GetStringAnnotation ( annotationAffinityCookiePath , ing )
2018-12-02 18:35:12 +00:00
if err != nil {
2020-10-26 19:08:55 +00:00
klog . V ( 3 ) . InfoS ( "Invalid or no annotation value found. Ignoring" , "ingress" , klog . KObj ( ing ) , "annotation" , annotationAffinityCookieMaxAge )
2018-11-19 14:15:24 +00:00
}
2018-11-30 22:56:11 +00:00
2020-01-22 20:19:16 +00:00
cookie . SameSite , err = parser . GetStringAnnotation ( annotationAffinityCookieSameSite , ing )
if err != nil {
2020-10-26 19:08:55 +00:00
klog . V ( 3 ) . InfoS ( "Invalid or no annotation value found. Ignoring" , "ingress" , klog . KObj ( ing ) , "annotation" , annotationAffinityCookieSameSite )
2020-01-22 20:19:16 +00:00
}
cookie . ConditionalSameSiteNone , err = parser . GetBoolAnnotation ( annotationAffinityCookieConditionalSameSiteNone , ing )
if err != nil {
2020-10-26 19:08:55 +00:00
klog . V ( 3 ) . InfoS ( "Invalid or no annotation value found. Ignoring" , "ingress" , klog . KObj ( ing ) , "annotation" , annotationAffinityCookieConditionalSameSiteNone )
2020-01-22 20:19:16 +00:00
}
2019-06-09 22:49:59 +00:00
cookie . ChangeOnFailure , err = parser . GetBoolAnnotation ( annotationAffinityCookieChangeOnFailure , ing )
if err != nil {
2020-10-26 19:08:55 +00:00
klog . V ( 3 ) . InfoS ( "Invalid or no annotation value found. Ignoring" , "ingress" , klog . KObj ( ing ) , "annotation" , annotationAffinityCookieChangeOnFailure )
2019-06-09 22:49:59 +00:00
}
2018-10-29 07:21:10 +00:00
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
2019-06-09 22:49:59 +00:00
func ( a affinity ) Parse ( ing * networking . 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
2019-08-30 09:40:29 +00:00
// Check the afinity mode that will be used
am , err := parser . GetStringAnnotation ( annotationAffinityMode , ing )
if err != nil {
am = ""
}
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 :
2020-09-27 20:32:40 +00:00
klog . V ( 3 ) . InfoS ( "No default affinity found" , "ingress" , ing . Name )
2017-02-12 23:13:39 +00:00
}
2017-11-07 16:36:51 +00:00
return & Config {
Type : at ,
2019-08-30 09:40:29 +00:00
Mode : am ,
2017-11-07 16:36:51 +00:00
Cookie : * cookie ,
} , nil
2017-02-12 23:13:39 +00:00
}