16
envoy_bootstrap_v3 "github.com/envoyproxy/go-control-plane/envoy/config/bootstrap/v3"
17
. "github.com/onsi/ginkgo/v2"
18
. "github.com/onsi/gomega"
20
"github.com/kumahq/kuma/app/kuma-dp/pkg/dataplane/envoy"
21
kuma_cmd "github.com/kumahq/kuma/pkg/cmd"
22
kumadp "github.com/kumahq/kuma/pkg/config/app/kuma-dp"
23
util_proto "github.com/kumahq/kuma/pkg/util/proto"
24
"github.com/kumahq/kuma/pkg/xds/bootstrap/types"
27
var _ = Describe("run", func() {
29
var ctx context.Context
30
opts := kuma_cmd.RunCmdOpts{
31
SetupSignalHandler: func() (context.Context, context.Context) {
39
ctx, cancel = context.WithCancel(context.Background())
41
tmpDir, err = os.MkdirTemp("", "")
42
Expect(err).ToNot(HaveOccurred())
47
err := os.RemoveAll(tmpDir)
49
Expect(err).ToNot(HaveOccurred())
53
var backupEnvVars []string
56
backupEnvVars = os.Environ()
60
for _, envVar := range backupEnvVars {
61
parts := strings.SplitN(envVar, "=", 2)
62
Expect(os.Setenv(parts[0], parts[1])).To(Succeed())
66
type testCase struct {
67
envVars map[string]string
71
DescribeTable("should be possible to start dataplane (Envoy) using `kuma-dp run`",
72
func(givenFunc func() testCase) {
76
envoyPidFile := filepath.Join(tmpDir, "envoy-mock.pid")
77
envoyCmdlineFile := filepath.Join(tmpDir, "envoy-mock.cmdline")
78
corednsPidFile := filepath.Join(tmpDir, "coredns-mock.pid")
79
corednsCmdlineFile := filepath.Join(tmpDir, "coredns-mock.cmdline")
83
env["ENVOY_MOCK_PID_FILE"] = envoyPidFile
84
env["ENVOY_MOCK_CMDLINE_FILE"] = envoyCmdlineFile
85
env["COREDNS_MOCK_PID_FILE"] = corednsPidFile
86
env["COREDNS_MOCK_CMDLINE_FILE"] = corednsCmdlineFile
87
for key, value := range env {
88
Expect(os.Setenv(key, value)).To(Succeed())
92
rootCtx := DefaultRootContext()
93
rootCtx.BootstrapGenerator = func(_ context.Context, _ string, cfg kumadp.Config, _ envoy.BootstrapParams) (*envoy_bootstrap_v3.Bootstrap, *types.KumaSidecarConfiguration, error) {
94
respBytes, err := os.ReadFile(filepath.Join("testdata", "bootstrap-config.golden.yaml"))
95
Expect(err).ToNot(HaveOccurred())
96
bootstrap := &envoy_bootstrap_v3.Bootstrap{}
97
if err := util_proto.FromYAML(respBytes, bootstrap); err != nil {
100
return bootstrap, &types.KumaSidecarConfiguration{}, nil
103
reader, writer := io.Pipe()
105
defer GinkgoRecover()
106
_, err := io.ReadAll(reader)
107
Expect(err).ToNot(HaveOccurred())
110
cmd := NewRootCmd(opts, rootCtx)
111
cmd.SetArgs(append([]string{"run"}, given.args...))
116
By("starting the Kuma DP")
117
errCh := make(chan error)
120
errCh <- cmd.Execute()
124
var actualConfigFile string
125
envoyPid := verifyComponentProcess("Envoy", envoyPidFile, envoyCmdlineFile, func(actualArgs []string) {
126
Expect(actualArgs[0]).To(Equal("--version"))
127
Expect(actualArgs[1]).To(Equal("--config-path"))
128
actualConfigFile = actualArgs[2]
129
Expect(actualConfigFile).To(BeARegularFile())
130
if given.expectedFile != "" {
131
Expect(actualArgs[2]).To(Equal(given.expectedFile))
135
corednsPid := verifyComponentProcess("coredns", corednsPidFile, corednsCmdlineFile, func(actualArgs []string) {
136
Expect(actualArgs).To(HaveLen(3))
137
Expect(actualArgs[0]).To(Equal("-conf"))
138
Expect(actualArgs[2]).To(Equal("-quiet"))
142
By("signaling the dataplane manager to stop")
144
Expect(writer.Close()).To(Succeed())
149
Expect(err).ToNot(HaveOccurred())
151
By("waiting for dataplane (Envoy) to get stopped")
152
Eventually(func() bool {
154
err := syscall.Kill(int(envoyPid), syscall.Signal(0))
157
}, "5s", "100ms").Should(BeTrue())
158
By("waiting for dataplane (coredns) to get stopped")
159
Eventually(func() bool {
161
err := syscall.Kill(int(corednsPid), syscall.Signal(0))
164
}, "5s", "100ms").Should(BeTrue())
166
By("verifying that temporary configuration dir gets removed")
167
if given.expectedFile == "" {
168
Expect(actualConfigFile).NotTo(BeAnExistingFile())
171
By("verifying that explicit configuration dir is not removed")
172
if given.expectedFile != "" {
173
Expect(given.expectedFile).To(BeAnExistingFile())
176
Entry("can be launched with env vars", func() testCase {
178
envVars: map[string]string{
179
"KUMA_CONTROL_PLANE_API_SERVER_URL": "http://localhost:1234",
180
"KUMA_DATAPLANE_NAME": "example",
181
"KUMA_DATAPLANE_MESH": "default",
182
"KUMA_DATAPLANE_RUNTIME_BINARY_PATH": filepath.Join("testdata", "envoy-mock.sleep.sh"),
184
"KUMA_DNS_CORE_DNS_BINARY_PATH": filepath.Join("testdata", "coredns-mock.sleep.sh"),
190
Entry("can be launched with env vars and given config dir", func() testCase {
192
envVars: map[string]string{
193
"KUMA_CONTROL_PLANE_API_SERVER_URL": "http://localhost:1234",
194
"KUMA_DATAPLANE_NAME": "example",
195
"KUMA_DATAPLANE_MESH": "default",
196
"KUMA_DATAPLANE_RUNTIME_BINARY_PATH": filepath.Join("testdata", "envoy-mock.sleep.sh"),
197
"KUMA_DATAPLANE_RUNTIME_CONFIG_DIR": tmpDir,
198
"KUMA_DNS_CORE_DNS_BINARY_PATH": filepath.Join("testdata", "coredns-mock.sleep.sh"),
201
expectedFile: filepath.Join(tmpDir, "bootstrap.yaml"),
204
Entry("can be launched with args", func() testCase {
206
envVars: map[string]string{},
208
"--cp-address", "http://localhost:1234",
211
"--binary-path", filepath.Join("testdata", "envoy-mock.sleep.sh"),
213
"--dns-coredns-path", filepath.Join("testdata", "coredns-mock.sleep.sh"),
218
Entry("can be launched with args and given config dir", func() testCase {
220
envVars: map[string]string{},
222
"--cp-address", "http://localhost:1234",
225
"--binary-path", filepath.Join("testdata", "envoy-mock.sleep.sh"),
226
"--config-dir", tmpDir,
227
"--dns-coredns-path", filepath.Join("testdata", "coredns-mock.sleep.sh"),
229
expectedFile: filepath.Join(tmpDir, "bootstrap.yaml"),
232
Entry("can be launched with args and dataplane token", func() testCase {
234
envVars: map[string]string{},
236
"--cp-address", "http://localhost:1234",
239
"--binary-path", filepath.Join("testdata", "envoy-mock.sleep.sh"),
240
"--dataplane-token-file", filepath.Join("testdata", "token"),
242
"--dns-coredns-path", filepath.Join("testdata", "coredns-mock.sleep.sh"),
247
Entry("can be launched without Envoy Admin API (env vars)", func() testCase {
249
envVars: map[string]string{
250
"KUMA_CONTROL_PLANE_API_SERVER_URL": "http://localhost:1234",
251
"KUMA_DATAPLANE_NAME": "example",
252
"KUMA_DATAPLANE_MESH": "default",
253
"KUMA_DATAPLANE_RUNTIME_BINARY_PATH": filepath.Join("testdata", "envoy-mock.sleep.sh"),
255
"KUMA_DNS_CORE_DNS_BINARY_PATH": filepath.Join("testdata", "coredns-mock.sleep.sh"),
261
Entry("can be launched without Envoy Admin API (command-line args)", func() testCase {
263
envVars: map[string]string{},
265
"--cp-address", "http://localhost:1234",
268
"--binary-path", filepath.Join("testdata", "envoy-mock.sleep.sh"),
270
"--dns-coredns-path", filepath.Join("testdata", "coredns-mock.sleep.sh"),
275
Entry("can be launched with dataplane template", func() testCase {
277
envVars: map[string]string{},
279
"--cp-address", "http://localhost:1234",
280
"--binary-path", filepath.Join("testdata", "envoy-mock.sleep.sh"),
281
"--dataplane-token-file", filepath.Join("testdata", "token"),
282
"--dataplane-file", filepath.Join("testdata", "dataplane_template.yaml"),
283
"--dataplane-var", "name=example",
284
"--dataplane-var", "address=127.0.0.1",
285
"--dns-coredns-path", filepath.Join("testdata", "coredns-mock.sleep.sh"),
290
Entry("can be launched with given coredns configuration path", func() testCase {
291
corefileTemplate := filepath.Join(tmpDir, "Corefile")
292
_ = os.WriteFile(corefileTemplate, []byte("abcd"), 0o600)
294
envVars: map[string]string{
295
"KUMA_CONTROL_PLANE_API_SERVER_URL": "http://localhost:1234",
296
"KUMA_DATAPLANE_NAME": "example",
297
"KUMA_DATAPLANE_MESH": "default",
298
"KUMA_DATAPLANE_RUNTIME_BINARY_PATH": filepath.Join("testdata", "envoy-mock.sleep.sh"),
299
"KUMA_DATAPLANE_RUNTIME_CONFIG_DIR": tmpDir,
300
"KUMA_DNS_CORE_DNS_BINARY_PATH": filepath.Join("testdata", "coredns-mock.sleep.sh"),
301
"KUMA_DNS_CORE_DNS_CONFIG_TEMPLATE_PATH": corefileTemplate,
304
expectedFile: filepath.Join(tmpDir, "bootstrap.yaml"),
309
It("should fail when name and mesh is provided with dataplane definition", func() {
311
cmd := NewRootCmd(opts, DefaultRootContext())
312
cmd.SetArgs([]string{
314
"--cp-address", "http://localhost:1234",
315
"--binary-path", filepath.Join("testdata", "envoy-mock.sleep.sh"),
316
"--dataplane-file", filepath.Join("testdata", "dataplane_template.yaml"),
317
"--dataplane-var", "name=example",
318
"--dataplane-var", "address=127.0.0.1",
321
"--dns-coredns-path", filepath.Join("testdata", "coredns-mock.sleep.sh"),
328
Expect(err).To(HaveOccurred())
329
Expect(err.Error()).To(ContainSubstring("--name and --mesh cannot be specified"))
332
It("should fail when the proxy type is unknown", func() {
334
cmd := NewRootCmd(opts, DefaultRootContext())
335
cmd.SetArgs([]string{
337
"--cp-address", "http://localhost:1234",
338
"--binary-path", filepath.Join("testdata", "envoy-mock.sleep.sh"),
339
"--dataplane-file", filepath.Join("testdata", "dataplane_template.yaml"),
340
"--dns-coredns-path", filepath.Join("testdata", "coredns-mock.sleep.sh"),
341
"--proxy-type", "phoney",
348
Expect(err).To(HaveOccurred())
349
Expect(err.Error()).To(ContainSubstring("invalid proxy type"))
353
func verifyComponentProcess(processDescription, pidfile string, cmdlinefile string, argsVerifier func(expectedArgs []string)) int64 {
355
By(fmt.Sprintf("waiting for dataplane (%s) to get started", processDescription))
356
Eventually(func() bool {
357
data, err := os.ReadFile(pidfile)
361
pid, err = strconv.ParseInt(strings.TrimSpace(string(data)), 10, 32)
363
}, "5s", "100ms").Should(BeTrue())
364
Expect(pid).ToNot(BeZero())
366
By(fmt.Sprintf("verifying the arguments %s was launched with", processDescription))
368
cmdline, err := os.ReadFile(cmdlinefile)
371
Expect(err).ToNot(HaveOccurred())
373
if argsVerifier != nil {
374
actualArgs := strings.FieldsFunc(string(cmdline), func(c rune) bool {
377
argsVerifier(actualArgs)