-
Notifications
You must be signed in to change notification settings - Fork 203
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MEDIUM: new annotation cookie-persistence-no-dynamic
This new annotation allows to set a cookie on the server line with the server name as value
- Loading branch information
1 parent
64fdab8
commit 7e0eefe
Showing
8 changed files
with
633 additions
and
14 deletions.
There are no files selected for viewing
67 changes: 67 additions & 0 deletions
67
deploy/tests/e2e/cookie-persistence/config/deploy.yml.tmpl
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
kind: Deployment | ||
apiVersion: apps/v1 | ||
metadata: | ||
name: http-echo | ||
spec: | ||
replicas: 1 | ||
selector: | ||
matchLabels: | ||
app: http-echo | ||
template: | ||
metadata: | ||
labels: | ||
app: http-echo | ||
spec: | ||
containers: | ||
- name: http-echo | ||
image: "haproxytech/http-echo:latest" | ||
imagePullPolicy: Never | ||
ports: | ||
- name: http | ||
containerPort: 8888 | ||
protocol: TCP | ||
- name: https | ||
containerPort: 8443 | ||
protocol: TCP | ||
--- | ||
kind: Service | ||
apiVersion: v1 | ||
metadata: | ||
name: http-echo | ||
spec: | ||
ports: | ||
- name: http | ||
protocol: TCP | ||
port: 80 | ||
targetPort: http | ||
- name: https | ||
protocol: TCP | ||
port: 443 | ||
targetPort: https | ||
selector: | ||
app: http-echo | ||
--- | ||
kind: Ingress | ||
apiVersion: networking.k8s.io/v1 | ||
metadata: | ||
name: http-echo | ||
annotations: | ||
ingress.class: haproxy | ||
{{ if .CookiePersistenceDynamic }} | ||
cookie-persistence: "mycookie" | ||
{{ else if .CookiePersistenceNoDynamic }} | ||
cookie-persistence-no-dynamic: "mycookie" | ||
{{ end }} | ||
|
||
spec: | ||
rules: | ||
- host: {{ .Host }} | ||
http: | ||
paths: | ||
- path: / | ||
pathType: Prefix | ||
backend: | ||
service: | ||
name: http-echo | ||
port: | ||
name: http |
331 changes: 331 additions & 0 deletions
331
deploy/tests/e2e/cookie-persistence/cookie-persistence_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,331 @@ | ||
// Copyright 2019 HAProxy Technologies LLC | ||
// | ||
// 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. | ||
|
||
//go:build e2e_parallel | ||
|
||
package cookiepersistence | ||
|
||
import ( | ||
"net/http" | ||
"strings" | ||
"testing" | ||
|
||
parser "github.com/haproxytech/client-native/v5/config-parser" | ||
"github.com/haproxytech/client-native/v5/config-parser/options" | ||
|
||
"github.com/haproxytech/kubernetes-ingress/deploy/tests/e2e" | ||
"github.com/stretchr/testify/suite" | ||
) | ||
|
||
// Adding CookiePersistenceTest, just to be able to debug directly here and not from CRDTCPSuite | ||
type CookiePersistenceTestSuite struct { | ||
CookiePersistenceSuite | ||
} | ||
|
||
func TestCookiePersistenceTestSuite(t *testing.T) { | ||
suite.Run(t, new(CookiePersistenceTestSuite)) | ||
} | ||
|
||
// Expected backend | ||
// backend e2e-tests-cookie-persistence_http-echo_http | ||
// ... | ||
// cookie mycookie dynamic indirect nocache insert | ||
// dynamic-cookie-key ohph7OoGhong | ||
// server SRV_1 10.244.0.9:8888 enabled | ||
// ... | ||
|
||
func (suite *CookiePersistenceTestSuite) Test_CookiePersistence_Dynamic() { | ||
//------------------------ | ||
// First step : Dynamic | ||
suite.tmplData.CookiePersistenceDynamic = true | ||
suite.tmplData.CookiePersistenceNoDynamic = false | ||
suite.Require().NoError(suite.test.Apply("config/deploy.yml.tmpl", suite.test.GetNS(), suite.tmplData)) | ||
// Check that curl backend return 200 and "Set-Cookie ""mycookie=f8f1bc84b3d0d5c0; path=/" | ||
suite.Eventually(func() bool { | ||
res, cls, err := suite.client.Do() | ||
if res == nil { | ||
suite.T().Log(err) | ||
return false | ||
} | ||
defer cls() | ||
cookies := res.Header["Set-Cookie"] | ||
cookieOK := false | ||
if len(cookies) != 0 { | ||
for _, cookie := range cookies { | ||
if strings.Contains(cookie, "mycookie") { | ||
cookieOK = true | ||
break | ||
} | ||
} | ||
} | ||
|
||
return res.StatusCode == http.StatusOK && cookieOK | ||
}, e2e.WaitDuration, e2e.TickDuration) | ||
|
||
// Also check configuration | ||
cfg, err := suite.test.GetIngressControllerFile("/etc/haproxy/haproxy.cfg") | ||
suite.Require().NoError(err, "Could not get Haproxy config") | ||
|
||
suite.Require().Contains(cfg, "cookie mycookie dynamic indirect nocache insert") | ||
suite.Require().Contains(cfg, "dynamic-cookie-key") | ||
|
||
// Check that the server line does not contain "cookie" param | ||
reader := strings.NewReader(cfg) | ||
p, err := parser.New(options.Reader(reader)) | ||
suite.Require().NoError(err, "Could not get Haproxy config parser") | ||
beName := suite.test.GetNS() + "_http-echo_http" | ||
serverName := "SRV_1" | ||
|
||
suite.checkServerNoCookie(p, beName, serverName) | ||
|
||
// ------------------------ | ||
// Second step : remove annotation | ||
suite.tmplData.CookiePersistenceDynamic = false | ||
suite.tmplData.CookiePersistenceNoDynamic = false | ||
suite.Require().NoError(suite.test.Apply("config/deploy.yml.tmpl", suite.test.GetNS(), suite.tmplData)) | ||
// Check that curl backend return 200 and "Set-Cookie ""mycookie=f8f1bc84b3d0d5c0; path=/" | ||
suite.Eventually(func() bool { | ||
res, cls, err := suite.client.Do() | ||
if res == nil { | ||
suite.T().Log(err) | ||
return false | ||
} | ||
defer cls() | ||
_, cookieOK := res.Header["Set-Cookie"] | ||
|
||
return res.StatusCode == http.StatusOK && !cookieOK | ||
}, e2e.WaitDuration, e2e.TickDuration) | ||
|
||
// Also check configuration | ||
cfg, err = suite.test.GetIngressControllerFile("/etc/haproxy/haproxy.cfg") | ||
suite.Require().NoError(err, "Could not get Haproxy config") | ||
|
||
suite.Require().NotContains(cfg, "cookie mycookie dynamic indirect nocache insert") | ||
suite.Require().NotContains(cfg, "dynamic-cookie-key") | ||
// Check that the server line does not contain "cookie" param | ||
reader = strings.NewReader(cfg) | ||
p, err = parser.New(options.Reader(reader)) | ||
suite.Require().NoError(err, "Could not get Haproxy config parser") | ||
|
||
suite.checkServerNoCookie(p, beName, serverName) | ||
} | ||
|
||
// Expected backend | ||
// backend e2e-tests-cookie-persistence_http-echo_http | ||
// ... | ||
// cookie mycookie indirect nocache insert | ||
// server SRV_1 10.244.0.13:8888 enabled cookie SRV_1 | ||
// ... | ||
|
||
func (suite *CookiePersistenceTestSuite) Test_CookiePersistence_No_Dynamic() { | ||
suite.tmplData.CookiePersistenceNoDynamic = true | ||
suite.tmplData.CookiePersistenceDynamic = false | ||
suite.Require().NoError(suite.test.Apply("config/deploy.yml.tmpl", suite.test.GetNS(), suite.tmplData)) | ||
// Check that curl backend return 200 and "Set-Cookie ""mycookie=<SRV_NAME>; path=/" | ||
suite.Eventually(func() bool { | ||
res, cls, err := suite.client.Do() | ||
if res == nil { | ||
suite.T().Log(err) | ||
return false | ||
} | ||
defer cls() | ||
cookies := res.Header["Set-Cookie"] | ||
cookieOK := false | ||
if len(cookies) != 0 { | ||
for _, cookie := range cookies { | ||
if strings.Contains(cookie, "mycookie") && strings.Contains(cookie, "SRV_1") { | ||
cookieOK = true | ||
break | ||
} | ||
} | ||
} | ||
|
||
return res.StatusCode == http.StatusOK && cookieOK | ||
}, e2e.WaitDuration, e2e.TickDuration) | ||
|
||
// Also check configuration | ||
cfg, err := suite.test.GetIngressControllerFile("/etc/haproxy/haproxy.cfg") | ||
suite.Require().NoError(err, "Could not get Haproxy config") | ||
|
||
suite.Require().Contains(cfg, "cookie mycookie indirect nocache insert") // NOTE that it does not contains dynamic | ||
suite.Require().NotContains(cfg, "dynamic-cookie-key") | ||
|
||
reader := strings.NewReader(cfg) | ||
p, err := parser.New(options.Reader(reader)) | ||
suite.Require().NoError(err, "Could not get Haproxy config parser") | ||
|
||
// Check that the server line | ||
beName := suite.test.GetNS() + "_http-echo_http" | ||
serverName := "SRV_1" | ||
|
||
suite.checkServerCookie(p, beName, serverName) | ||
|
||
// ------------------------ | ||
// Second step : remove annotation | ||
suite.tmplData.CookiePersistenceDynamic = false | ||
suite.tmplData.CookiePersistenceNoDynamic = false | ||
suite.Require().NoError(suite.test.Apply("config/deploy.yml.tmpl", suite.test.GetNS(), suite.tmplData)) | ||
// Check that curl backend return 200 and "Set-Cookie ""mycookie=f8f1bc84b3d0d5c0; path=/" | ||
suite.Eventually(func() bool { | ||
res, cls, err := suite.client.Do() | ||
if res == nil { | ||
suite.T().Log(err) | ||
return false | ||
} | ||
defer cls() | ||
_, cookieOK := res.Header["Set-Cookie"] | ||
|
||
return res.StatusCode == http.StatusOK && !cookieOK | ||
}, e2e.WaitDuration, e2e.TickDuration) | ||
|
||
// Also check configuration | ||
cfg, err = suite.test.GetIngressControllerFile("/etc/haproxy/haproxy.cfg") | ||
suite.Require().NoError(err, "Could not get Haproxy config") | ||
|
||
suite.Require().NotContains(cfg, "cookie mycookie dynamic indirect nocache insert") | ||
suite.Require().NotContains(cfg, "dynamic-cookie-key") | ||
// Check that the server line does not contain "cookie" param | ||
reader = strings.NewReader(cfg) | ||
p, err = parser.New(options.Reader(reader)) | ||
suite.Require().NoError(err, "Could not get Haproxy config parser") | ||
|
||
suite.checkServerNoCookie(p, beName, serverName) | ||
} | ||
|
||
func (suite *CookiePersistenceTestSuite) Test_CookiePersistence_Switch() { | ||
//--------------------------- | ||
// Step 1 : Dynamic | ||
suite.tmplData.CookiePersistenceDynamic = true | ||
suite.tmplData.CookiePersistenceNoDynamic = false | ||
suite.Require().NoError(suite.test.Apply("config/deploy.yml.tmpl", suite.test.GetNS(), suite.tmplData)) | ||
// Check that curl backend return 200 and "Set-Cookie ""mycookie=f8f1bc84b3d0d5c0; path=/" | ||
suite.Eventually(func() bool { | ||
res, cls, err := suite.client.Do() | ||
if res == nil { | ||
suite.T().Log(err) | ||
return false | ||
} | ||
defer cls() | ||
cookies := res.Header["Set-Cookie"] | ||
cookieOK := false | ||
if len(cookies) != 0 { | ||
for _, cookie := range cookies { | ||
if strings.Contains(cookie, "mycookie") { | ||
cookieOK = true | ||
break | ||
} | ||
} | ||
} | ||
|
||
return res.StatusCode == http.StatusOK && cookieOK | ||
}, e2e.WaitDuration, e2e.TickDuration) | ||
|
||
// Also check configuration | ||
cfg, err := suite.test.GetIngressControllerFile("/etc/haproxy/haproxy.cfg") | ||
suite.Require().NoError(err, "Could not get Haproxy config") | ||
|
||
suite.Require().Contains(cfg, "cookie mycookie dynamic indirect nocache insert") | ||
suite.Require().Contains(cfg, "dynamic-cookie-key") | ||
|
||
// Check that the server line does not contain "cookie" param | ||
reader := strings.NewReader(cfg) | ||
p, err := parser.New(options.Reader(reader)) | ||
suite.Require().NoError(err, "Could not get Haproxy config parser") | ||
beName := suite.test.GetNS() + "_http-echo_http" | ||
serverName := "SRV_1" | ||
|
||
suite.checkServerNoCookie(p, beName, serverName) | ||
|
||
//---------------------- | ||
// Step 2: not dynamic | ||
suite.tmplData.CookiePersistenceNoDynamic = true | ||
suite.tmplData.CookiePersistenceDynamic = false | ||
suite.Require().NoError(suite.test.Apply("config/deploy.yml.tmpl", suite.test.GetNS(), suite.tmplData)) | ||
// Check that curl backend return 200 and "Set-Cookie ""mycookie=<SRV_NAME>; path=/" | ||
suite.Eventually(func() bool { | ||
res, cls, err := suite.client.Do() | ||
if res == nil { | ||
suite.T().Log(err) | ||
return false | ||
} | ||
defer cls() | ||
cookies := res.Header["Set-Cookie"] | ||
cookieOK := false | ||
if len(cookies) != 0 { | ||
for _, cookie := range cookies { | ||
if strings.Contains(cookie, "mycookie") && strings.Contains(cookie, "SRV_1") { | ||
cookieOK = true | ||
break | ||
} | ||
} | ||
} | ||
|
||
return res.StatusCode == http.StatusOK && cookieOK | ||
}, e2e.WaitDuration, e2e.TickDuration) | ||
|
||
// Also check configuration | ||
cfg, err = suite.test.GetIngressControllerFile("/etc/haproxy/haproxy.cfg") | ||
suite.Require().NoError(err, "Could not get Haproxy config") | ||
|
||
suite.Require().Contains(cfg, "cookie mycookie indirect nocache insert") // NOTE that it does not contains dynamic | ||
suite.Require().NotContains(cfg, "dynamic-cookie-key") | ||
|
||
reader = strings.NewReader(cfg) | ||
p, err = parser.New(options.Reader(reader)) | ||
suite.Require().NoError(err, "Could not get Haproxy config parser") | ||
|
||
// Check that the server line | ||
suite.checkServerCookie(p, beName, serverName) | ||
|
||
//------------------------ | ||
// Step 3: and back: Dynamic | ||
suite.tmplData.CookiePersistenceDynamic = true | ||
suite.tmplData.CookiePersistenceNoDynamic = false | ||
suite.Require().NoError(suite.test.Apply("config/deploy.yml.tmpl", suite.test.GetNS(), suite.tmplData)) | ||
// Check that curl backend return 200 and "Set-Cookie ""mycookie=f8f1bc84b3d0d5c0; path=/" | ||
suite.Eventually(func() bool { | ||
res, cls, err := suite.client.Do() | ||
if res == nil { | ||
suite.T().Log(err) | ||
return false | ||
} | ||
defer cls() | ||
cookies := res.Header["Set-Cookie"] | ||
cookieOK := false | ||
if len(cookies) != 0 { | ||
for _, cookie := range cookies { | ||
if strings.Contains(cookie, "mycookie") { | ||
cookieOK = true | ||
break | ||
} | ||
} | ||
} | ||
|
||
return res.StatusCode == http.StatusOK && cookieOK | ||
}, e2e.WaitDuration, e2e.TickDuration) | ||
|
||
// Also check configuration | ||
cfg, err = suite.test.GetIngressControllerFile("/etc/haproxy/haproxy.cfg") | ||
suite.Require().NoError(err, "Could not get Haproxy config") | ||
|
||
suite.Require().Contains(cfg, "cookie mycookie dynamic indirect nocache insert") | ||
suite.Require().Contains(cfg, "dynamic-cookie-key") | ||
|
||
// Check that the server line does not contain "cookie" param | ||
reader = strings.NewReader(cfg) | ||
p, err = parser.New(options.Reader(reader)) | ||
suite.Require().NoError(err, "Could not get Haproxy config parser") | ||
|
||
suite.checkServerNoCookie(p, beName, serverName) | ||
} |
Oops, something went wrong.