Skip to content

Commit 1d0a016

Browse files
Improve debugging experience for k0s inttests
Implements an optional, heavier debug image with delve and strace, a way to replace the command in the BootlooseSuite for a debugging command and documents it. Signed-off-by: Juan-Luis de Sousa-Valadas Castaño <[email protected]>
1 parent 6457d0a commit 1d0a016

File tree

5 files changed

+99
-20
lines changed

5 files changed

+99
-20
lines changed

README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,3 +181,39 @@ To run a basic smoke test after build:
181181
```shell
182182
make check-basic
183183
```
184+
185+
### Debugging smoke tests
186+
187+
Every smoke test can be executed independently, the complete list of smoke tests is
188+
available in `inttest/Makefile.variables``
189+
190+
It's possible to attach a debugger to a smoke test but it requires some modifications:
191+
192+
1. k0s must be compiled with symbols: `DEBUG=true make k0s`
193+
2. The source code must be present in `go/src/github.com/k0sproject/` and
194+
the go cache in `/run/k0s-build/go`
195+
196+
```shell
197+
sudo mkdir -p /go/src/github.com/k0sproject/ /run/k0s-build/
198+
sudo chown -R $(whoami):$(whoami) /go/src/github.com/k0sproject/ /run/k0s-build/
199+
ln -s <K0s source dir> /go/src/github.com/k0sproject/k0s
200+
ln -s <K0s source dir>/build/cache/go /run/k0s-build/go
201+
```
202+
203+
3. Modify the inttest to include to run the command that you want to run:
204+
205+
```go
206+
// SetK0sCommand is only evaluated when Controllers or Workers are initialized
207+
// feel free to call it where it's appropriate and change the position.
208+
// This example enables the debugger for the controllers but not the workers
209+
s.SetK0sCommand("PATH=/usr/local/go/bin:$PATH /go/bin/dlv exec --headless --listen :4040 -- /usr/local/bin/k0s")
210+
s.Require().NoError(s.InitController(0, controllerArgs...))
211+
s.SetK0sCommand("/usr/local/bin/k0s")
212+
s.Require().NoError(s.RunWorkers())
213+
```
214+
215+
4. Launch the tests with `K0S_DEBUG_TEST=true` so that it uses the correct image:
216+
`K0S_KEEP_AFTER_TESTS=always DEBUG=true K0S_DEBUG_TESTS=true make check-<test name>`
217+
218+
5. Connect to the remote debugger using the correct container IP
219+
`dlv -connect <container ip address>:4040`

inttest/Makefile

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,25 @@ bin/sonobuoy: | bin
2020
$(curl) $(sonobuoy_url) | tar -C bin/ -zxv $(notdir $@)
2121

2222
bootloose_alpine_build_cmdline := \
23-
--build-arg GOLANG_IMAGE=$(golang_buildimage) \
24-
--build-arg ALPINE_VERSION=$(alpine_patch_version) \
2523
--build-arg ETCD_VERSION=$(etcd_version) \
2624
--build-arg HELM_VERSION=$(helm_version) \
27-
-t bootloose-alpine \
25+
--build-arg TARGETARCH=$(ARCH) \
2826
-f bootloose-alpine/Dockerfile \
2927
bootloose-alpine
3028

3129
.bootloose-alpine.stamp: $(shell find bootloose-alpine -type f)
32-
docker build --progress=plain --build-arg TARGETARCH=$(ARCH) $(bootloose_alpine_build_cmdline)
30+
docker build --progress=plain \
31+
--build-arg BOOTLOOSE_BASE=docker.io/library/alpine:$(alpine_patch_version) \
32+
-t bootloose-alpine \
33+
$(bootloose_alpine_build_cmdline)
34+
touch $@
35+
36+
.bootloose-debug.stamp: $(shell find bootloose-alpine -type f)
37+
docker build --progress=plain \
38+
-t bootloose-debug \
39+
--build-arg INCLUDE_DEBUG_TOOLS=true \
40+
--build-arg BOOTLOOSE_BASE=$(golang_buildimage) \
41+
$(bootloose_alpine_build_cmdline)
3342
touch $@
3443

3544
# This is a special target to test the bootloose alpine image locally for all supported platforms.
@@ -133,15 +142,25 @@ check-nllb: TIMEOUT=15m
133142
.PHONY: $(smoketests)
134143
include Makefile.variables
135144

145+
# Determine the bootloose stamp dependency based on K0S_DEBUG
146+
# Default to .bootloose-alpine.stamp (the "otherwise" case from the request)
147+
BOOTLOOSE_STAMP_DEP := .bootloose-alpine.stamp
148+
ifeq ($(K0S_DEBUG_TESTS),true)
149+
BOOTLOOSE_STAMP_DEP := .bootloose-debug.stamp
150+
BOOTLOOSE_IMAGE ?= bootloose-debug
151+
else
152+
endif
153+
136154
$(smoketests): K0S_PATH ?= $(realpath ../k0s)
137155
$(smoketests): K0S_IMAGES_BUNDLE ?= $(realpath ../airgap-image-bundle-linux-$(ARCH).tar)
138-
$(smoketests): .bootloose-alpine.stamp
156+
$(smoketests): $(BOOTLOOSE_STAMP_DEP)
139157
$(smoketests): TEST_PACKAGE ?= $(subst check-,,$@)
140158
$(smoketests):
141159
K0S_PATH='$(K0S_PATH)' \
142160
K0S_UPDATE_FROM_PATH='$(K0S_UPDATE_FROM_PATH)' \
143161
K0S_IMAGES_BUNDLE='$(K0S_IMAGES_BUNDLE)' \
144162
K0S_UPDATE_TO_VERSION='$(K0S_UPDATE_TO_VERSION)' \
163+
$(if $(BOOTLOOSE_IMAGE),BOOTLOOSE_IMAGE='$(BOOTLOOSE_IMAGE)') \
145164
go test -count=1 -v -timeout $(TIMEOUT) github.com/k0sproject/k0s/inttest/$(TEST_PACKAGE)
146165
.PHONY: clean
147166

inttest/bootloose-alpine/Dockerfile

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
ARG ALPINE_VERSION
2-
ARG GOLANG_IMAGE
1+
ARG BOOTLOOSE_BASE
32

4-
FROM docker.io/library/alpine:$ALPINE_VERSION
3+
FROM $BOOTLOOSE_BASE
54

65
ARG TARGETARCH
76
ARG CRI_DOCKERD_VERSION=0.3.16
87
ARG ETCD_VERSION
98
ARG TROUBLESHOOT_VERSION=v0.115.1
109
ARG HELM_VERSION
10+
ARG INCLUDE_DEBUG_TOOLS=false
1111

1212
# Apply our changes to the image
1313
COPY root/ /
@@ -50,22 +50,27 @@ RUN curl --proto '=https' --tlsv1.2 -L https://get.helm.sh/helm-v$HELM_VERSION-l
5050
# Install etcd for smoke tests with external etcd
5151
# No arm or riscv64 binaries available (check-externaletcd won't work on ARMv7 or RISC-V)
5252
RUN if [ "$TARGETARCH" != arm ] && [ "$TARGETARCH" != riscv64 ]; then \
53-
curl --proto '=https' --tlsv1.2 -L https://github.com/etcd-io/etcd/releases/download/v$ETCD_VERSION/etcd-v$ETCD_VERSION-linux-$TARGETARCH.tar.gz \
54-
| tar xz -C /opt --strip-components=1; \
53+
curl --proto '=https' --tlsv1.2 -L https://github.com/etcd-io/etcd/releases/download/v$ETCD_VERSION/etcd-v$ETCD_VERSION-linux-$TARGETARCH.tar.gz \
54+
| tar xz -C /opt --strip-components=1; \
5555
fi
5656

5757
# Install cri-dockerd shim for custom CRI testing
5858
# No arm or riscv64 binaries available (check-byocri won't work on ARMv7 or RISC-V)
5959
RUN if [ "$TARGETARCH" != arm ] && [ "$TARGETARCH" != riscv64 ]; then \
60-
curl --proto '=https' --tlsv1.2 --retry 5 --retry-all-errors -sSLfo /tmp/cri-dockerd.tgz https://github.com/Mirantis/cri-dockerd/releases/download/v$CRI_DOCKERD_VERSION/cri-dockerd-$CRI_DOCKERD_VERSION.$TARGETARCH.tgz \
61-
&& tar xf /tmp/cri-dockerd.tgz --directory /tmp/ \
62-
&& mv /tmp/cri-dockerd/cri-dockerd /usr/local/bin/cri-dockerd \
63-
&& rm -rf /tmp/cri-dockerd \
64-
&& chmod 755 /usr/local/bin/cri-dockerd; \
60+
curl --proto '=https' --tlsv1.2 --retry 5 --retry-all-errors -sSLfo /tmp/cri-dockerd.tgz https://github.com/Mirantis/cri-dockerd/releases/download/v$CRI_DOCKERD_VERSION/cri-dockerd-$CRI_DOCKERD_VERSION.$TARGETARCH.tgz \
61+
&& tar xf /tmp/cri-dockerd.tgz --directory /tmp/ \
62+
&& mv /tmp/cri-dockerd/cri-dockerd /usr/local/bin/cri-dockerd \
63+
&& rm -rf /tmp/cri-dockerd \
64+
&& chmod 755 /usr/local/bin/cri-dockerd; \
6565
fi
6666

6767
RUN for u in etcd kube-apiserver kube-scheduler konnectivity-server; do \
68-
adduser --system --shell /sbin/nologin --no-create-home --home /var/lib/k0s --disabled-password --gecos '' "$u"; \
68+
adduser --system --shell /sbin/nologin --no-create-home --home /var/lib/k0s --disabled-password --gecos '' "$u"; \
6969
done
7070

71+
RUN if [ "$INCLUDE_DEBUG_TOOLS" = "true" ]; then \
72+
apk add --no-cache strace \
73+
&& go install github.com/go-delve/delve/cmd/dlv@latest; \
74+
fi
75+
7176
ADD cri-dockerd.sh /etc/init.d/cri-dockerd

inttest/common/bootloosesuite.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,12 @@ func (s *BootlooseSuite) InitController(idx int, k0sArgs ...string) error {
642642
return s.WaitForKubeAPI(controllerNode, dataDirOpt)
643643
}
644644

645+
// SetK0sCommand allows to set the command used to launch k0s, so that it
646+
// can be launched with some debugging tools such as strace or delve
647+
func (s *BootlooseSuite) SetK0sCommand(command string) {
648+
s.Require().NoError(s.launchDelegate.SetK0sCommand(command))
649+
}
650+
645651
// GetJoinToken generates join token for the asked role
646652
func (s *BootlooseSuite) GetJoinToken(role string, extraArgs ...string) (string, error) {
647653
// assume we have main on node 0 always

inttest/common/launchdelegate.go

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,13 @@ type launchDelegate interface {
4343
StartWorker(ctx context.Context, conn *SSHConnection) error
4444
StopWorker(ctx context.Context, conn *SSHConnection) error
4545
ReadK0sLogs(ctx context.Context, conn *SSHConnection, out, err io.Writer) error
46+
SetK0sCommand(prefix string) error
4647
}
4748

4849
// standaloneLaunchDelegate is a launchDelegate that starts controllers and
4950
// workers in "standalone" mode, i.e. not via some service manager.
5051
type standaloneLaunchDelegate struct {
51-
k0sFullPath string
52+
k0sCommand string
5253
controllerUmask int
5354
}
5455

@@ -64,7 +65,7 @@ func (s *standaloneLaunchDelegate) InitController(ctx context.Context, conn *SSH
6465
fmt.Fprintf(&script, "umask %d\n", s.controllerUmask)
6566
}
6667
fmt.Fprintf(&script, "export ETCD_UNSUPPORTED_ARCH='%s'\n", runtime.GOARCH)
67-
fmt.Fprintf(&script, "%s controller --debug %s </dev/null >>/tmp/k0s-controller.log 2>&1 &\n", s.k0sFullPath, strings.Join(k0sArgs, " "))
68+
fmt.Fprintf(&script, "%s controller --debug %s </dev/null >>/tmp/k0s-controller.log 2>&1 &\n", s.k0sCommand, strings.Join(k0sArgs, " "))
6869
fmt.Fprintln(&script, "disown %1")
6970

7071
if err := conn.Exec(ctx, "cat >/tmp/start-k0s && chmod +x /tmp/start-k0s", SSHStreams{
@@ -76,6 +77,13 @@ func (s *standaloneLaunchDelegate) InitController(ctx context.Context, conn *SSH
7677
return s.StartController(ctx, conn)
7778
}
7879

80+
// SetControllerPrefixCmd allows to set some command before k0s so that it can
81+
// be launched with some debugging tools such as strace or delve
82+
func (s *standaloneLaunchDelegate) SetK0sCommand(command string) error {
83+
s.k0sCommand = command
84+
return nil
85+
}
86+
7987
// StartController starts a k0s controller that was initialized in "standalone" mode.
8088
func (s *standaloneLaunchDelegate) StartController(ctx context.Context, conn *SSHConnection) error {
8189
const cmd = "/tmp/start-k0s"
@@ -100,7 +108,7 @@ func (s *standaloneLaunchDelegate) InitWorker(ctx context.Context, conn *SSHConn
100108
var script strings.Builder
101109
fmt.Fprintln(&script, "#!/usr/bin/env bash")
102110
fmt.Fprintln(&script, "set -eu")
103-
fmt.Fprintf(&script, "%s worker --debug %s \"$@\" </dev/null >>/tmp/k0s-worker.log 2>&1 &\n", s.k0sFullPath, strings.Join(k0sArgs, " "))
111+
fmt.Fprintf(&script, "%s worker --debug %s \"$@\" </dev/null >>/tmp/k0s-worker.log 2>&1 &\n", s.k0sCommand, strings.Join(k0sArgs, " "))
104112
fmt.Fprintln(&script, "disown %1")
105113

106114
if err := conn.Exec(ctx, "cat >/tmp/start-k0s-worker && chmod +x /tmp/start-k0s-worker", SSHStreams{
@@ -134,7 +142,7 @@ func (s *standaloneLaunchDelegate) ReadK0sLogs(ctx context.Context, conn *SSHCon
134142
}
135143

136144
func (s *standaloneLaunchDelegate) killK0s(ctx context.Context, conn *SSHConnection) error {
137-
stopCommand := fmt.Sprintf("kill $(pidof %s | tr \" \" \"\\n\" | sort -n | head -n1) && while pidof %s; do sleep 0.1s; done", s.k0sFullPath, s.k0sFullPath)
145+
stopCommand := fmt.Sprintf("kill $(pidof %s | tr \" \" \"\\n\" | sort -n | head -n1) && while pidof %s; do sleep 0.1s; done", s.k0sCommand, s.k0sCommand)
138146
if err := conn.Exec(ctx, stopCommand, SSHStreams{}); err != nil {
139147
return fmt.Errorf("unable to execute %q: %w", stopCommand, err)
140148
}
@@ -171,6 +179,11 @@ func (o *openRCLaunchDelegate) InitController(ctx context.Context, conn *SSHConn
171179
return o.StartController(ctx, conn)
172180
}
173181

182+
// SetK0sCommand isn't implemented in "OpenRC" mode
183+
func (o *openRCLaunchDelegate) SetK0sCommand(_ string) error {
184+
return errors.New("openRCLaunchDelegate.SetK0sCommand isn't implemented")
185+
}
186+
174187
// StartController starts a k0s controller that was started using OpenRC.
175188
func (o *openRCLaunchDelegate) StartController(ctx context.Context, conn *SSHConnection) error {
176189
const cmd = "/etc/init.d/k0scontroller start"

0 commit comments

Comments
 (0)