commit
b5619cc978
6 changed files with 91 additions and 7 deletions
|
@ -39,10 +39,19 @@ const (
|
|||
// one isn't supplied and affinity is set to "cookie".
|
||||
annotationAffinityCookieHash = "session-cookie-hash"
|
||||
defaultAffinityCookieHash = "md5"
|
||||
|
||||
// This is used to control the cookie expires, its value is a number of seconds until the
|
||||
// cookie expires
|
||||
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"
|
||||
)
|
||||
|
||||
var (
|
||||
affinityCookieHashRegex = regexp.MustCompile(`^(index|md5|sha1)$`)
|
||||
affinityCookieExpiresRegex = regexp.MustCompile(`(^0|-?[1-9]\d*$)`)
|
||||
)
|
||||
|
||||
// Config describes the per ingress session affinity config
|
||||
|
@ -58,17 +67,23 @@ type Cookie struct {
|
|||
Name string `json:"name"`
|
||||
// The hash that will be used to encode the cookie in case of cookie affinity type
|
||||
Hash string `json:"hash"`
|
||||
// The time duration to control cookie expires
|
||||
Expires string `json:"expires"`
|
||||
// The number of seconds until the cookie expires
|
||||
MaxAge string `json:"maxage"`
|
||||
}
|
||||
|
||||
// cookieAffinityParse gets the annotation values related to Cookie Affinity
|
||||
// It also sets default values when no value or incorrect value is found
|
||||
func (a affinity) cookieAffinityParse(ing *extensions.Ingress) *Cookie {
|
||||
cookie := &Cookie{}
|
||||
sn, err := parser.GetStringAnnotation(annotationAffinityCookieName, ing)
|
||||
|
||||
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
|
||||
}
|
||||
cookie.Name = sn
|
||||
|
||||
sh, err := parser.GetStringAnnotation(annotationAffinityCookieHash, ing)
|
||||
|
||||
|
@ -76,11 +91,22 @@ func (a affinity) cookieAffinityParse(ing *extensions.Ingress) *Cookie {
|
|||
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 = sh
|
||||
|
||||
return &Cookie{
|
||||
Name: sn,
|
||||
Hash: sh,
|
||||
se, err := parser.GetStringAnnotation(annotationAffinityCookieExpires, ing)
|
||||
if err != nil || !affinityCookieExpiresRegex.MatchString(se) {
|
||||
glog.V(3).Infof("Invalid or no annotation value found in Ingress %v: %v. Ignoring it", ing.Name, annotationAffinityCookieExpires)
|
||||
se = ""
|
||||
}
|
||||
cookie.Expires = se
|
||||
|
||||
sm, err := parser.GetStringAnnotation(annotationAffinityCookieMaxAge, ing)
|
||||
if err != nil || !affinityCookieExpiresRegex.MatchString(sm) {
|
||||
glog.V(3).Infof("Invalid or no annotation value found in Ingress %v: %v. Ignoring it", ing.Name, annotationAffinityCookieMaxAge)
|
||||
sm = ""
|
||||
}
|
||||
cookie.MaxAge = sm
|
||||
return cookie
|
||||
}
|
||||
|
||||
// NewParser creates a new Affinity annotation parser
|
||||
|
|
|
@ -69,6 +69,8 @@ func TestIngressAffinityCookieConfig(t *testing.T) {
|
|||
data[parser.GetAnnotationWithPrefix(annotationAffinityType)] = "cookie"
|
||||
data[parser.GetAnnotationWithPrefix(annotationAffinityCookieHash)] = "sha123"
|
||||
data[parser.GetAnnotationWithPrefix(annotationAffinityCookieName)] = "INGRESSCOOKIE"
|
||||
data[parser.GetAnnotationWithPrefix(annotationAffinityCookieExpires)] = "4500"
|
||||
data[parser.GetAnnotationWithPrefix(annotationAffinityCookieMaxAge)] = "3000"
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
affin, _ := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
|
@ -88,4 +90,12 @@ func TestIngressAffinityCookieConfig(t *testing.T) {
|
|||
if nginxAffinity.Cookie.Name != "INGRESSCOOKIE" {
|
||||
t.Errorf("expected route as sticky-name but returned %v", nginxAffinity.Cookie.Name)
|
||||
}
|
||||
|
||||
if nginxAffinity.Cookie.Expires != "4500" {
|
||||
t.Errorf("expected 1h as sticky-expires but returned %v", nginxAffinity.Cookie.Expires)
|
||||
}
|
||||
|
||||
if nginxAffinity.Cookie.MaxAge != "3000" {
|
||||
t.Errorf("expected 3000 as sticky-max-age but returned %v", nginxAffinity.Cookie.MaxAge)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -406,6 +406,8 @@ func (n *NGINXController) getBackendServers(ingresses []*extensions.Ingress) ([]
|
|||
if anns.SessionAffinity.Type == "cookie" {
|
||||
ups.SessionAffinity.CookieSessionAffinity.Name = anns.SessionAffinity.Cookie.Name
|
||||
ups.SessionAffinity.CookieSessionAffinity.Hash = anns.SessionAffinity.Cookie.Hash
|
||||
ups.SessionAffinity.CookieSessionAffinity.Expires = anns.SessionAffinity.Cookie.Expires
|
||||
ups.SessionAffinity.CookieSessionAffinity.MaxAge = anns.SessionAffinity.Cookie.MaxAge
|
||||
|
||||
locs := ups.SessionAffinity.CookieSessionAffinity.Locations
|
||||
if _, ok := locs[host]; !ok {
|
||||
|
|
|
@ -109,6 +109,8 @@ type SessionAffinityConfig struct {
|
|||
type CookieSessionAffinity struct {
|
||||
Name string `json:"name"`
|
||||
Hash string `json:"hash"`
|
||||
Expires string `json:"expires,omitempty"`
|
||||
MaxAge string `json:"maxage,omitempty"`
|
||||
Locations map[string][]string `json:"locations,omitempty"`
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@ function _M.new(self, backend)
|
|||
local o = {
|
||||
instance = self.factory:new(nodes),
|
||||
cookie_name = backend["sessionAffinityConfig"]["cookieSessionAffinity"]["name"] or "route",
|
||||
cookie_expires = backend["sessionAffinityConfig"]["cookieSessionAffinity"]["expires"],
|
||||
cookie_max_age = backend["sessionAffinityConfig"]["cookieSessionAffinity"]["maxage"],
|
||||
digest_func = digest_func,
|
||||
}
|
||||
setmetatable(o, self)
|
||||
|
@ -37,14 +39,24 @@ local function set_cookie(self, value)
|
|||
ngx.log(ngx.ERR, err)
|
||||
end
|
||||
|
||||
local ok
|
||||
ok, err = cookie:set({
|
||||
local cookie_data = {
|
||||
key = self.cookie_name,
|
||||
value = value,
|
||||
path = ngx.var.location_path,
|
||||
domain = ngx.var.host,
|
||||
httponly = true,
|
||||
})
|
||||
}
|
||||
|
||||
if self.cookie_expires and self.cookie_expires ~= "" then
|
||||
cookie_data.expires = ngx.cookie_time(tonumber(self.cookie_expires))
|
||||
end
|
||||
|
||||
if self.cookie_max_age and self.cookie_max_age ~= "" then
|
||||
cookie_data.max_age = tonumber(self.cookie_max_age)
|
||||
end
|
||||
|
||||
local ok
|
||||
ok, err = cookie:set(cookie_data)
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR, err)
|
||||
end
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
@ -191,4 +192,35 @@ var _ = framework.IngressNginxDescribe("Annotations - Affinity/Sticky Sessions",
|
|||
Expect(resp.StatusCode).Should(Equal(http.StatusOK))
|
||||
Expect(resp.Header.Get("Set-Cookie")).Should(ContainSubstring("Path=/somewhereelese;"))
|
||||
})
|
||||
|
||||
It("should set cookie with expires", func() {
|
||||
host := "cookie.foo.com"
|
||||
annotations := map[string]string{
|
||||
"nginx.ingress.kubernetes.io/affinity": "cookie",
|
||||
"nginx.ingress.kubernetes.io/session-cookie-name": "ExpiresCookie",
|
||||
"nginx.ingress.kubernetes.io/session-cookie-expires": "172800",
|
||||
"nginx.ingress.kubernetes.io/session-cookie-max-age": "259200",
|
||||
}
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/", host, f.IngressController.Namespace, "http-svc", 80, &annotations)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.WaitForNginxServer(host,
|
||||
func(server string) bool {
|
||||
return strings.Contains(server, fmt.Sprintf("server_name %s ;", host))
|
||||
})
|
||||
|
||||
resp, _, errs := gorequest.New().
|
||||
Get(f.IngressController.HTTPURL).
|
||||
Set("Host", host).
|
||||
End()
|
||||
|
||||
Expect(len(errs)).Should(BeNumerically("==", 0))
|
||||
Expect(resp.StatusCode).Should(Equal(http.StatusOK))
|
||||
local, _ := time.LoadLocation("GMT")
|
||||
duration, _ := time.ParseDuration("48h")
|
||||
expected := time.Date(1970, time.January, 1, 0, 0, 0, 0, local).Add(duration).Format("Mon, 02-Jan-06 15:04:05 MST")
|
||||
Expect(resp.Header.Get("Set-Cookie")).Should(ContainSubstring(fmt.Sprintf("Expires=%s", expected)))
|
||||
Expect(resp.Header.Get("Set-Cookie")).Should(ContainSubstring("Max-Age=259200"))
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue