Skip to content

Commit 67cdb35

Browse files
authored
[NPM-4170] Add e2e test for cilium conntracker (#34398)
1 parent a430c85 commit 67cdb35

File tree

8 files changed

+300
-31
lines changed

8 files changed

+300
-31
lines changed

.gitlab/e2e/e2e.yml

+14
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,20 @@ new-e2e-npm-eks:
344344
E2E_PRE_INITIALIZED: "true"
345345
ON_NIGHTLY_FIPS: "true"
346346

347+
new-e2e-npm:
348+
extends: .new_e2e_template
349+
rules:
350+
- !reference [.on_npm_or_e2e_changes]
351+
- !reference [.manual]
352+
needs:
353+
- !reference [.needs_new_e2e_template]
354+
- qa_agent
355+
- qa_dca
356+
variables:
357+
TARGETS: ./tests/npm
358+
TEAM: network-performance-monitoring
359+
EXTRA_PARAMS: --run TestCiliumLBConntracker
360+
347361
new-e2e-amp:
348362
extends: .new_e2e_template
349363
needs:

test/new-e2e/pkg/provisioners/aws/kubernetes/kind.go

+29-11
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,17 @@ package awskubernetes
99
import (
1010
"context"
1111
"fmt"
12-
"github.com/DataDog/test-infra-definitions/common/utils"
13-
"github.com/DataDog/test-infra-definitions/components/datadog/agent"
14-
"github.com/DataDog/test-infra-definitions/components/datadog/agentwithoperatorparams"
15-
"github.com/DataDog/test-infra-definitions/components/datadog/operator"
16-
"github.com/DataDog/test-infra-definitions/components/datadog/operatorparams"
12+
13+
"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes"
14+
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
1715

1816
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/environments"
1917
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/provisioners"
2018
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/utils/optional"
21-
19+
"github.com/DataDog/test-infra-definitions/common/utils"
20+
"github.com/DataDog/test-infra-definitions/components/datadog/agent"
2221
"github.com/DataDog/test-infra-definitions/components/datadog/agent/helm"
22+
"github.com/DataDog/test-infra-definitions/components/datadog/agentwithoperatorparams"
2323
"github.com/DataDog/test-infra-definitions/components/datadog/apps/cpustress"
2424
"github.com/DataDog/test-infra-definitions/components/datadog/apps/dogstatsd"
2525
"github.com/DataDog/test-infra-definitions/components/datadog/apps/mutatedbyadmissioncontroller"
@@ -30,15 +30,14 @@ import (
3030
dogstatsdstandalone "github.com/DataDog/test-infra-definitions/components/datadog/dogstatsd-standalone"
3131
fakeintakeComp "github.com/DataDog/test-infra-definitions/components/datadog/fakeintake"
3232
"github.com/DataDog/test-infra-definitions/components/datadog/kubernetesagentparams"
33+
"github.com/DataDog/test-infra-definitions/components/datadog/operator"
34+
"github.com/DataDog/test-infra-definitions/components/datadog/operatorparams"
3335
kubeComp "github.com/DataDog/test-infra-definitions/components/kubernetes"
36+
"github.com/DataDog/test-infra-definitions/components/kubernetes/cilium"
3437
"github.com/DataDog/test-infra-definitions/components/kubernetes/vpa"
3538
"github.com/DataDog/test-infra-definitions/resources/aws"
3639
"github.com/DataDog/test-infra-definitions/scenarios/aws/ec2"
3740
"github.com/DataDog/test-infra-definitions/scenarios/aws/fakeintake"
38-
39-
"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes"
40-
41-
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
4241
)
4342

4443
const (
@@ -92,7 +91,13 @@ func KindRunFunc(ctx *pulumi.Context, env *environments.Kubernetes, params *Prov
9291
return err
9392
}
9493

95-
kindCluster, err := kubeComp.NewKindCluster(&awsEnv, host, params.name, awsEnv.KubernetesVersion(), utils.PulumiDependsOn(installEcrCredsHelperCmd))
94+
var kindCluster *kubeComp.Cluster
95+
if len(params.ciliumOptions) > 0 {
96+
kindCluster, err = cilium.NewKindCluster(&awsEnv, host, params.name, awsEnv.KubernetesVersion(), params.ciliumOptions, utils.PulumiDependsOn(installEcrCredsHelperCmd))
97+
} else {
98+
kindCluster, err = kubeComp.NewKindCluster(&awsEnv, host, params.name, awsEnv.KubernetesVersion(), utils.PulumiDependsOn(installEcrCredsHelperCmd))
99+
}
100+
96101
if err != nil {
97102
return err
98103
}
@@ -116,6 +121,19 @@ func KindRunFunc(ctx *pulumi.Context, env *environments.Kubernetes, params *Prov
116121
}
117122
dependsOnVPA := utils.PulumiDependsOn(vpaCrd)
118123

124+
if len(params.ciliumOptions) > 0 {
125+
// deploy cilium
126+
ciliumParams, err := cilium.NewParams(params.ciliumOptions...)
127+
if err != nil {
128+
return err
129+
}
130+
131+
_, err = cilium.NewHelmInstallation(&awsEnv, kindCluster, ciliumParams, pulumi.Provider(kubeProvider))
132+
if err != nil {
133+
return err
134+
}
135+
}
136+
119137
var fakeIntake *fakeintakeComp.Fakeintake
120138
if params.fakeintakeOptions != nil {
121139
fakeintakeOpts := []fakeintake.Option{fakeintake.WithLoadBalancer()}

test/new-e2e/pkg/provisioners/aws/kubernetes/params.go

+14-5
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,21 @@ package awskubernetes
88

99
import (
1010
"fmt"
11-
"github.com/DataDog/test-infra-definitions/components/datadog/agentwithoperatorparams"
12-
"github.com/DataDog/test-infra-definitions/components/datadog/operatorparams"
11+
12+
"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes"
1313

1414
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/runner"
1515
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/utils/optional"
16-
1716
"github.com/DataDog/test-infra-definitions/common/config"
17+
"github.com/DataDog/test-infra-definitions/components/datadog/agentwithoperatorparams"
1818
"github.com/DataDog/test-infra-definitions/components/datadog/kubernetesagentparams"
19+
"github.com/DataDog/test-infra-definitions/components/datadog/operatorparams"
1920
kubeComp "github.com/DataDog/test-infra-definitions/components/kubernetes"
21+
"github.com/DataDog/test-infra-definitions/components/kubernetes/cilium"
2022
"github.com/DataDog/test-infra-definitions/resources/aws"
2123
"github.com/DataDog/test-infra-definitions/scenarios/aws/ec2"
2224
"github.com/DataDog/test-infra-definitions/scenarios/aws/eks"
2325
"github.com/DataDog/test-infra-definitions/scenarios/aws/fakeintake"
24-
25-
"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes"
2626
)
2727

2828
// ProvisionerParams contains all the parameters needed to create the environment
@@ -36,6 +36,7 @@ type ProvisionerParams struct {
3636
workloadAppFuncs []WorkloadAppFunc
3737
operatorOptions []operatorparams.Option
3838
operatorDDAOptions []agentwithoperatorparams.Option
39+
ciliumOptions []cilium.Option
3940

4041
eksLinuxNodeGroup bool
4142
eksLinuxARMNodeGroup bool
@@ -212,3 +213,11 @@ func WithoutDDA() ProvisionerOption {
212213
return nil
213214
}
214215
}
216+
217+
// WithCiliumOptions adds a cilium installation option
218+
func WithCiliumOptions(opts ...cilium.Option) ProvisionerOption {
219+
return func(params *ProvisionerParams) error {
220+
params.ciliumOptions = opts
221+
return nil
222+
}
223+
}

test/new-e2e/pkg/provisioners/local/kubernetes/kind.go

+4-6
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,20 @@ package localkubernetes
99
import (
1010
"fmt"
1111

12+
"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes"
13+
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
14+
1215
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/environments"
1316
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/provisioners"
1417
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/runner"
1518
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/utils/optional"
16-
1719
"github.com/DataDog/test-infra-definitions/common/config"
1820
"github.com/DataDog/test-infra-definitions/components/datadog/agent/helm"
19-
"github.com/DataDog/test-infra-definitions/resources/local"
20-
2121
fakeintakeComp "github.com/DataDog/test-infra-definitions/components/datadog/fakeintake"
2222
"github.com/DataDog/test-infra-definitions/components/datadog/kubernetesagentparams"
2323
kubeComp "github.com/DataDog/test-infra-definitions/components/kubernetes"
24+
"github.com/DataDog/test-infra-definitions/resources/local"
2425
"github.com/DataDog/test-infra-definitions/scenarios/aws/fakeintake"
25-
26-
"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes"
27-
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
2826
)
2927

3028
const (
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
// Unless explicitly stated otherwise all files in this repository are licensed
2+
// under the Apache License Version 2.0.
3+
// This product includes software developed at Datadog (https://www.datadoghq.com/).
4+
// Copyright 2016-present Datadog, Inc.
5+
6+
package npm
7+
8+
import (
9+
"context"
10+
"encoding/json"
11+
"fmt"
12+
"strings"
13+
"testing"
14+
"time"
15+
16+
"github.com/DataDog/agent-payload/v5/process"
17+
"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes"
18+
corev1 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/core/v1"
19+
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
20+
"github.com/stretchr/testify/assert"
21+
"github.com/stretchr/testify/require"
22+
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23+
24+
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/e2e"
25+
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/environments"
26+
awskubernetes "github.com/DataDog/datadog-agent/test/new-e2e/pkg/provisioners/aws/kubernetes"
27+
"github.com/DataDog/test-infra-definitions/common/config"
28+
npmtools "github.com/DataDog/test-infra-definitions/components/datadog/apps/npm-tools"
29+
"github.com/DataDog/test-infra-definitions/components/datadog/kubernetesagentparams"
30+
kubeComp "github.com/DataDog/test-infra-definitions/components/kubernetes"
31+
"github.com/DataDog/test-infra-definitions/components/kubernetes/cilium"
32+
"github.com/DataDog/test-infra-definitions/components/kubernetes/istio"
33+
)
34+
35+
type ciliumLBConntrackerTestSuite struct {
36+
e2e.BaseSuite[environments.Kubernetes]
37+
38+
httpBinService *corev1.Service
39+
}
40+
41+
func TestCiliumLBConntracker(t *testing.T) {
42+
// TODO: find a way to update this list dynamically
43+
versionsToTest := []string{"1.15.14", "1.16.7", "1.17.1"}
44+
for _, v := range versionsToTest {
45+
t.Run(fmt.Sprintf("version %s", v), func(_t *testing.T) {
46+
_t.Parallel()
47+
48+
testCiliumLBConntracker(t, v)
49+
})
50+
}
51+
}
52+
53+
func testCiliumLBConntracker(t *testing.T, ciliumVersion string) {
54+
t.Helper()
55+
56+
suite := &ciliumLBConntrackerTestSuite{}
57+
58+
httpBinServiceInstall := func(e config.Env, kubeProvider *kubernetes.Provider) (*kubeComp.Workload, error) {
59+
var err error
60+
suite.httpBinService, err = istio.NewHttpbinServiceInstallation(e, pulumi.Provider(kubeProvider))
61+
return &kubeComp.Workload{}, err
62+
}
63+
64+
npmToolsWorkload := func(e config.Env, kubeProvider *kubernetes.Provider) (*kubeComp.Workload, error) {
65+
// NPM tools Workload
66+
return npmtools.K8sAppDefinition(e, kubeProvider, "npmtools", "http://httpbin.default.svc.cluster.local:8000")
67+
}
68+
69+
ciliumHelmValues := map[string]pulumi.Input{
70+
"kubeProxyReplacement": pulumi.BoolPtr(true),
71+
"ipam": pulumi.Map{
72+
"method": pulumi.StringPtr("kubernetes"),
73+
},
74+
"socketLB": pulumi.Map{
75+
"hostNamespaceOnly": pulumi.BoolPtr(true),
76+
},
77+
"image": pulumi.Map{
78+
"tag": pulumi.StringPtr(ciliumVersion),
79+
},
80+
}
81+
82+
name := strings.ReplaceAll(fmt.Sprintf("cilium-lb-%s", ciliumVersion), ".", "-")
83+
e2e.Run(t, suite,
84+
e2e.WithStackName(fmt.Sprintf("stack-%s", name)),
85+
e2e.WithProvisioner(
86+
awskubernetes.KindProvisioner(
87+
awskubernetes.WithName(name),
88+
awskubernetes.WithCiliumOptions(cilium.WithHelmValues(ciliumHelmValues), cilium.WithVersion(ciliumVersion)),
89+
awskubernetes.WithAgentOptions(kubernetesagentparams.WithHelmValues(systemProbeConfigWithCiliumLB)),
90+
awskubernetes.WithWorkloadApp(httpBinServiceInstall),
91+
awskubernetes.WithWorkloadApp(npmToolsWorkload),
92+
),
93+
),
94+
)
95+
}
96+
97+
// BeforeTest will be called before each test
98+
func (suite *ciliumLBConntrackerTestSuite) BeforeTest(suiteName, testName string) {
99+
suite.BaseSuite.BeforeTest(suiteName, testName)
100+
// default is to reset the current state of the fakeintake aggregators
101+
if !suite.BaseSuite.IsDevMode() {
102+
suite.Env().FakeIntake.Client().FlushServerAndResetAggregators()
103+
}
104+
}
105+
106+
// AfterTest will be called after each test
107+
func (suite *ciliumLBConntrackerTestSuite) AfterTest(suiteName, testName string) {
108+
test1HostFakeIntakeNPMDumpInfo(suite.T(), suite.Env().FakeIntake)
109+
110+
suite.BaseSuite.AfterTest(suiteName, testName)
111+
}
112+
113+
func (suite *ciliumLBConntrackerTestSuite) TestCiliumConntracker() {
114+
fakeIntake := suite.Env().FakeIntake
115+
116+
var hostname string
117+
suite.Require().EventuallyWithT(func(collect *assert.CollectT) {
118+
names, err := fakeIntake.Client().GetConnectionsNames()
119+
if assert.NoError(collect, err, "error getting connection names") &&
120+
assert.NotEmpty(collect, names) {
121+
hostname = names[0]
122+
}
123+
}, time.Minute, time.Second, "timed out getting connection names")
124+
125+
var svcConns []*process.Connection
126+
suite.Require().EventuallyWithT(func(collect *assert.CollectT) {
127+
cnx, err := fakeIntake.Client().GetConnections()
128+
require.NoError(collect, err, "error getting connections")
129+
payloads := cnx.GetPayloadsByName(hostname)
130+
// only look at the last two payloads
131+
require.Greater(collect, len(payloads), 1, "at least 2 payloads not present")
132+
133+
svcConns = nil
134+
for _, c := range append(payloads[len(payloads)-2].Connections, payloads[len(payloads)-1].Connections...) {
135+
if c.Raddr.Port != 8000 {
136+
return
137+
}
138+
139+
if !assert.NotNil(collect, c.IpTranslation, "ip translation is nil for service connection") {
140+
return
141+
}
142+
143+
svcConns = append(svcConns, c)
144+
}
145+
146+
assert.NotEmpty(collect, svcConns, "no connections for service found")
147+
}, time.Minute, time.Second, "could not find connections for service")
148+
149+
backends, frontendIP := suite.httpBinCiliumService()
150+
for _, c := range svcConns {
151+
suite.Assert().Equalf(frontendIP, c.Raddr.Ip, "front end address not equal to connection raddr")
152+
suite.Assert().Conditionf(func() bool {
153+
for _, be := range backends {
154+
if be.ip == c.IpTranslation.ReplSrcIP && be.port == uint16(c.IpTranslation.ReplSrcPort) {
155+
return true
156+
}
157+
}
158+
159+
return false
160+
}, "")
161+
}
162+
}
163+
164+
type ciliumBackend struct {
165+
ip string
166+
port uint16
167+
}
168+
169+
func (suite *ciliumLBConntrackerTestSuite) httpBinCiliumService() (backends []ciliumBackend, frontendIP string) {
170+
t := suite.T()
171+
t.Helper()
172+
173+
var stdout string
174+
require.EventuallyWithT(t, func(collect *assert.CollectT) {
175+
ciliumPods, err := suite.Env().KubernetesCluster.Client().CoreV1().Pods("kube-system").List(context.Background(), v1.ListOptions{
176+
LabelSelector: "k8s-app=cilium",
177+
})
178+
require.NoError(collect, err, "could no get cilium pods")
179+
require.NotNil(collect, ciliumPods, "cilium pods object is nil")
180+
require.NotEmpty(collect, ciliumPods.Items, "no cilium pods found")
181+
182+
pod := ciliumPods.Items[0]
183+
var stderr string
184+
stdout, stderr, err = suite.Env().KubernetesCluster.KubernetesClient.PodExec("kube-system", pod.Name, "cilium-agent", []string{"cilium-dbg", "service", "list", "-o", "json"})
185+
require.NoError(collect, err, "error getting cilium service list")
186+
require.Empty(collect, stderr, "got output on stderr from cilium service list command", stderr)
187+
require.NotEmpty(collect, stdout, "empty output from cilium-dbg service list command")
188+
}, 20*time.Second, time.Second, "could not get cilium-agent pod")
189+
190+
var services []interface{}
191+
err := json.Unmarshal([]byte(stdout), &services)
192+
suite.Require().NoError(err, "error deserializing output of cilium-dbg service list command")
193+
for _, svc := range services {
194+
spec := svc.(map[string]interface{})["spec"].(map[string]interface{})
195+
frontendAddr := spec["frontend-address"].(map[string]interface{})
196+
if frontendAddrPort := frontendAddr["port"].(float64); frontendAddrPort != 8000 {
197+
continue
198+
}
199+
if frontendAddrProto, ok := frontendAddr["protocol"]; ok && frontendAddrProto.(string) != "TCP" {
200+
continue
201+
}
202+
203+
frontendIP = frontendAddr["ip"].(string)
204+
_backendAddrs := spec["backend-addresses"].([]interface{})
205+
for _, be := range _backendAddrs {
206+
be := be.(map[string]interface{})
207+
backends = append(backends, ciliumBackend{
208+
ip: be["ip"].(string),
209+
port: uint16(be["port"].(float64)),
210+
})
211+
}
212+
213+
break
214+
}
215+
216+
return backends, frontendIP
217+
218+
}

0 commit comments

Comments
 (0)