Skip to content

Commit

Permalink
MEDIUM: new annotation cookie-persistence-no-dynamic
Browse files Browse the repository at this point in the history
This new annotation allows to set a cookie on the server line with the server name as value
  • Loading branch information
hdurand0710 committed Nov 22, 2024
1 parent 64fdab8 commit 7e0eefe
Show file tree
Hide file tree
Showing 8 changed files with 633 additions and 14 deletions.
67 changes: 67 additions & 0 deletions deploy/tests/e2e/cookie-persistence/config/deploy.yml.tmpl
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 deploy/tests/e2e/cookie-persistence/cookie-persistence_test.go
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)
}
Loading

0 comments on commit 7e0eefe

Please sign in to comment.