}
func (s *KindSuite) DeployPod(pod *Pod) {
+ pod.suite = s
s.CurrentlyRunning = append(s.CurrentlyRunning, pod.Name)
pod.CreatedPod = &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
}
}
- s.Log("IP: %s", pod.IpAddress)
+ s.Log("IP: %s\n", pod.IpAddress)
}
package hst_kind
-import corev1 "k8s.io/api/core/v1"
+import (
+ "bytes"
+ "context"
+ "os"
+ "os/exec"
+ "text/template"
+ "time"
+
+ . "fd.io/hs-test/infra/common"
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/client-go/tools/remotecommand"
+)
type Pod struct {
+ suite *KindSuite
Name string
Image string
ContainerName string
clientCont := "client"
serverCont := "server"
+ // TODO: load from file
s.images = append(s.images, vppImg, nginxLdpImg, abImg)
s.Namespace = "namespace" + s.Ppid
s.Pods.Nginx.Image = nginxLdpImg
s.Pods.Nginx.ContainerName = serverCont
s.Pods.Nginx.Worker = wrk2
+
+ s.Pods.NginxProxy = new(Pod)
+ s.Pods.NginxProxy.Name = "nginx-proxy" + s.Ppid
+ s.Pods.NginxProxy.Image = nginxLdpImg
+ s.Pods.NginxProxy.ContainerName = serverCont
+ s.Pods.NginxProxy.Worker = wrk2
+}
+
+func (pod *Pod) CopyToPod(namespace string, src string, dst string) {
+ cmd := exec.Command("kubectl", "--kubeconfig="+pod.suite.KubeconfigPath, "cp", src, namespace+"/"+pod.Name+":"+dst)
+ out, err := cmd.CombinedOutput()
+ pod.suite.AssertNil(err, string(out))
+}
+
+func (pod *Pod) Exec(command []string) (string, error) {
+ var stdout, stderr bytes.Buffer
+
+ // Prepare the request
+ req := pod.suite.ClientSet.CoreV1().RESTClient().Post().
+ Resource("pods").
+ Name(pod.Name).
+ Namespace(pod.suite.Namespace).
+ SubResource("exec").
+ Param("container", pod.ContainerName).
+ Param("stdout", "true").
+ Param("stderr", "true").
+ Param("tty", "true")
+
+ for _, cmd := range command {
+ req = req.Param("command", cmd)
+ }
+ pod.suite.Log("%s: %s\n", pod.Name, command)
+
+ executor, err := remotecommand.NewSPDYExecutor(pod.suite.Config, "POST", req.URL())
+ if err != nil {
+ pod.suite.Log("Error creating executor: %s", err.Error())
+ }
+
+ ctx, cancel := context.WithTimeout(context.Background(), 500*time.Second)
+ defer cancel()
+
+ err = executor.StreamWithContext(ctx, remotecommand.StreamOptions{
+ Stdout: &stdout,
+ Stderr: &stderr,
+ Tty: true,
+ })
+
+ output := stdout.String() + stderr.String()
+
+ if err != nil {
+ return output, err
+ }
+
+ return output, nil
+}
+
+func (pod *Pod) CreateConfigFromTemplate(targetConfigName string, templateName string, values any) {
+ template := template.Must(template.ParseFiles(templateName))
+
+ f, err := os.CreateTemp(LogDir, "hst-config")
+ pod.suite.AssertNil(err, err)
+ defer os.Remove(f.Name())
+
+ err = template.Execute(f, values)
+ pod.suite.AssertNil(err, err)
+
+ err = f.Close()
+ pod.suite.AssertNil(err, err)
+
+ pod.CopyToPod(pod.suite.Namespace, f.Name(), targetConfigName)
}
import (
"fmt"
- "os"
"reflect"
"regexp"
"runtime"
"strings"
- "text/template"
. "fd.io/hs-test/infra/common"
. "github.com/onsi/ginkgo/v2"
ServerGeneric *Pod
ClientGeneric *Pod
Nginx *Pod
+ NginxProxy *Pod
Ab *Pod
}
}
var kindTests = map[string][]func(s *KindSuite){}
+const VclConfIperf = "echo \"vcl {\n" +
+ "rx-fifo-size 4000000\n" +
+ "tx-fifo-size 4000000\n" +
+ "app-scope-local\n" +
+ "app-scope-global\n" +
+ "app-socket-api abstract:vpp/session\n" +
+ "}\" > /vcl.conf"
+
+const VclConfNginx = "echo \"vcl {\n" +
+ "heapsize 64M\n" +
+ "rx-fifo-size 4000000\n" +
+ "tx-fifo-size 4000000\n" +
+ "segment-size 4000000000\n" +
+ "add-segment-size 4000000000\n" +
+ "event-queue-size 100000\n" +
+ "use-mq-eventfd\n" +
+ "app-socket-api abstract:vpp/session\n" +
+ "}\" > /vcl.conf"
+
func RegisterKindTests(tests ...func(s *KindSuite)) {
kindTests[GetTestFilename()] = tests
}
func (s *KindSuite) TeardownTest() {
s.HstCommon.TeardownTest()
if len(s.CurrentlyRunning) != 0 {
+ s.Log("Removing:")
for _, pod := range s.CurrentlyRunning {
s.Log(" %s", pod)
s.deletePod(s.Namespace, pod)
func (s *KindSuite) TeardownSuite() {
s.HstCommon.TeardownSuite()
- s.Log(" %s", s.Namespace)
+ s.Log("Removing:\n %s", s.Namespace)
s.AssertNil(s.deleteNamespace(s.Namespace))
}
// and searches for the first version string, then creates symlinks.
func (s *KindSuite) FixVersionNumber(pods ...*Pod) {
regex := regexp.MustCompile(`lib.*\.so\.([0-9]+\.[0-9]+)`)
- o, _ := s.Exec(s.Pods.ServerGeneric, []string{"/bin/bash", "-c",
+ o, _ := s.Pods.ServerGeneric.Exec([]string{"/bin/bash", "-c",
"ldd /usr/lib/libvcl_ldpreload.so"})
match := regex.FindStringSubmatch(o)
"fi\n"+
"done", version)
for _, pod := range pods {
- s.Exec(pod, []string{"/bin/bash", "-c", cmd})
+ pod.Exec([]string{"/bin/bash", "-c", cmd})
}
} else {
}
}
-func (s *KindSuite) CreateConfigFromTemplate(targetConfigName string, templateName string, values any) {
- template := template.Must(template.ParseFiles(templateName))
-
- f, err := os.CreateTemp(LogDir, "hst-config")
- s.AssertNil(err, err)
- defer os.Remove(f.Name())
-
- err = template.Execute(f, values)
- s.AssertNil(err, err)
-
- err = f.Close()
- s.AssertNil(err, err)
-
- s.CopyToPod(s.Pods.Nginx.Name, s.Namespace, f.Name(), targetConfigName)
-}
-
-func (s *KindSuite) CreateNginxConfig() {
+func (s *KindSuite) CreateNginxConfig(pod *Pod) {
values := struct {
Workers uint8
Port uint16
Workers: 1,
Port: 8081,
}
- s.CreateConfigFromTemplate(
+ pod.CreateConfigFromTemplate(
"/nginx.conf",
"./resources/nginx/nginx.conf",
values,
)
}
+func (s *KindSuite) CreateNginxProxyConfig(pod *Pod) {
+ pod.Exec([]string{"/bin/bash", "-c", "mkdir -p /tmp/nginx"})
+ values := struct {
+ Workers uint8
+ LogPrefix string
+ Proxy string
+ Server string
+ Port uint16
+ Upstream1 string
+ Upstream2 string
+ Upstream3 string
+ }{
+ Workers: 1,
+ LogPrefix: s.Pods.NginxProxy.Name,
+ Proxy: s.Pods.NginxProxy.IpAddress,
+ Server: s.Pods.Nginx.IpAddress,
+ Port: 8080,
+ Upstream1: "8081",
+ Upstream2: "8081",
+ Upstream3: "8081",
+ }
+ pod.CreateConfigFromTemplate(
+ "/nginx.conf",
+ "./resources/nginx/nginx_proxy_mirroring.conf",
+ values,
+ )
+}
+
var _ = Describe("KindSuite", Ordered, ContinueOnFailure, Label("Perf"), func() {
var s KindSuite
BeforeAll(func() {
package hst_kind
-import (
- "bytes"
- "context"
- "os/exec"
- "time"
-
- "k8s.io/client-go/tools/remotecommand"
-)
-
-func (s *KindSuite) CopyToPod(podName string, namespace string, src string, dst string) {
- cmd := exec.Command("kubectl", "--kubeconfig="+s.KubeconfigPath, "cp", src, namespace+"/"+podName+":"+dst)
- out, err := cmd.CombinedOutput()
- s.AssertNil(err, string(out))
-}
-
-func (s *KindSuite) Exec(pod *Pod, command []string) (string, error) {
- var stdout, stderr bytes.Buffer
-
- // Prepare the request
- req := s.ClientSet.CoreV1().RESTClient().Post().
- Resource("pods").
- Name(pod.Name).
- Namespace(s.Namespace).
- SubResource("exec").
- Param("container", pod.ContainerName).
- Param("stdout", "true").
- Param("stderr", "true").
- Param("tty", "true")
-
- for _, cmd := range command {
- req = req.Param("command", cmd)
- }
- s.Log("%s: %s", pod.Name, command)
-
- executor, err := remotecommand.NewSPDYExecutor(s.Config, "POST", req.URL())
- if err != nil {
- s.Log("Error creating executor: %s", err.Error())
- }
-
- ctx, cancel := context.WithTimeout(context.Background(), 500*time.Second)
- defer cancel()
-
- err = executor.StreamWithContext(ctx, remotecommand.StreamOptions{
- Stdout: &stdout,
- Stderr: &stderr,
- Tty: true,
- })
-
- output := stdout.String() + stderr.String()
-
- if err != nil {
- return output, err
- }
-
- return output, nil
-}
-
func boolPtr(b bool) *bool {
return &b
}
)
func init() {
- RegisterKindTests(KindIperfVclTest, NginxRpsTest)
+ RegisterKindTests(KindIperfVclTest, NginxRpsTest, NginxProxyMirroringTest)
}
const vcl string = "VCL_CONFIG=/vcl.conf"
s.DeployPod(s.Pods.ClientGeneric)
s.DeployPod(s.Pods.ServerGeneric)
- vclConf := "echo \"vcl {\n" +
- "rx-fifo-size 4000000\n" +
- "tx-fifo-size 4000000\n" +
- "app-scope-local\n" +
- "app-scope-global\n" +
- "app-socket-api abstract:vpp/session\n" +
- "}\" > /vcl.conf"
-
- _, err := s.Exec(s.Pods.ClientGeneric, []string{"/bin/bash", "-c", vclConf})
+ _, err := s.Pods.ClientGeneric.Exec([]string{"/bin/bash", "-c", VclConfIperf})
s.AssertNil(err)
- _, err = s.Exec(s.Pods.ServerGeneric, []string{"/bin/bash", "-c", vclConf})
+ _, err = s.Pods.ServerGeneric.Exec([]string{"/bin/bash", "-c", VclConfIperf})
s.AssertNil(err)
s.FixVersionNumber(s.Pods.ClientGeneric, s.Pods.ServerGeneric)
- o, err := s.Exec(s.Pods.ServerGeneric, []string{"/bin/bash", "-c",
+ o, err := s.Pods.ServerGeneric.Exec([]string{"/bin/bash", "-c",
vcl + " " + ldp + " iperf3 -s -D -4"})
s.AssertNil(err, o)
- output, err := s.Exec(s.Pods.ClientGeneric, []string{"/bin/bash", "-c",
+ o, err = s.Pods.ClientGeneric.Exec([]string{"/bin/bash", "-c",
vcl + " " + ldp + " iperf3 -l 1460 -b 10g -c " + s.Pods.ServerGeneric.IpAddress})
- s.Log(output)
+ s.Log(o)
s.AssertNil(err)
}
func NginxRpsTest(s *KindSuite) {
s.DeployPod(s.Pods.Nginx)
s.DeployPod(s.Pods.Ab)
- s.CreateNginxConfig()
-
- vclConf := "echo \"vcl {\n" +
- "heapsize 64M\n" +
- "rx-fifo-size 4000000\n" +
- "tx-fifo-size 4000000\n" +
- "segment-size 4000000000\n" +
- "add-segment-size 4000000000\n" +
- "event-queue-size 100000\n" +
- "use-mq-eventfd\n" +
- "app-socket-api abstract:vpp/session\n" +
- "}\" > /vcl.conf"
-
- out, err := s.Exec(s.Pods.Nginx, []string{"/bin/bash", "-c", vclConf})
+ s.CreateNginxConfig(s.Pods.Nginx)
+
+ out, err := s.Pods.Nginx.Exec([]string{"/bin/bash", "-c", VclConfNginx})
+ s.AssertNil(err, out)
+
+ go func() {
+ defer GinkgoRecover()
+ out, err := s.Pods.Nginx.Exec([]string{"/bin/bash", "-c", ldp + " " + vcl + " nginx -c /nginx.conf"})
+ s.AssertNil(err, out)
+ }()
+
+ // wait for nginx to start up
+ time.Sleep(time.Second * 2)
+ out, err = s.Pods.Ab.Exec([]string{"ab", "-k", "-r", "-n", "1000000", "-c", "1000", "http://" + s.Pods.Nginx.IpAddress + ":8081/64B.json"})
+ s.Log(out)
+ s.AssertNil(err)
+}
+
+func NginxProxyMirroringTest(s *KindSuite) {
+ s.DeployPod(s.Pods.Nginx)
+ s.DeployPod(s.Pods.NginxProxy)
+ s.DeployPod(s.Pods.ClientGeneric)
+ s.CreateNginxConfig(s.Pods.Nginx)
+ s.CreateNginxProxyConfig(s.Pods.NginxProxy)
+
+ out, err := s.Pods.Nginx.Exec([]string{"/bin/bash", "-c", VclConfNginx})
s.AssertNil(err, out)
+ out, err = s.Pods.NginxProxy.Exec([]string{"/bin/bash", "-c", VclConfNginx})
+ s.AssertNil(err, out)
+
+ go func() {
+ defer GinkgoRecover()
+ out, err := s.Pods.Nginx.Exec([]string{"/bin/bash", "-c", ldp + " " + vcl + " nginx -c /nginx.conf"})
+ s.AssertNil(err, out)
+ }()
go func() {
defer GinkgoRecover()
- out, err := s.Exec(s.Pods.Nginx, []string{"/bin/bash", "-c", ldp + " " + vcl + " nginx -c /nginx.conf"})
+ out, err := s.Pods.NginxProxy.Exec([]string{"/bin/bash", "-c", "nginx -c /nginx.conf"})
s.AssertNil(err, out)
}()
// wait for nginx to start up
time.Sleep(time.Second * 2)
- out, err = s.Exec(s.Pods.Ab, []string{"ab", "-k", "-r", "-n", "1000000", "-c", "1000", "http://" + s.Pods.Nginx.IpAddress + ":8081/64B.json"})
+ out, err = s.Pods.ClientGeneric.Exec([]string{"curl", "-v", "--noproxy", "'*'", "--insecure", "http://" + s.Pods.NginxProxy.IpAddress + ":8080/64B.json"})
s.Log(out)
s.AssertNil(err)
}
make -C $CALICOVPP_DIR kind-new-cluster N_KIND_WORKERS=2
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.3/manifests/tigera-operator.yaml
make -C $CALICOVPP_DIR cherry-vpp FORCE=y BASE=origin/master VPP_DIR=$VPP_DIR
- make build-vpp-release
+ make -C $VPP_DIR/extras/hs-test build-vpp-release
make -C $CALICOVPP_DIR dev-kind
make -C $CALICOVPP_DIR load-kind
$CALICOVPP_DIR/yaml/overlays/dev/kustomize.sh up