Skip to content

Commit 96996cd

Browse files
feat: dump pod logs when TestKubernetesAgentStandalone fails (elastic#5176)
1 parent acfed19 commit 96996cd

File tree

3 files changed

+88
-3
lines changed

3 files changed

+88
-3
lines changed

.buildkite/pipeline.yml

+1
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ steps:
205205
KIND_VERSION: "v0.20.0"
206206
command: ".buildkite/scripts/steps/k8s-extended-tests.sh"
207207
artifact_paths:
208+
- "build/k8s-logs*/*"
208209
- "build/TEST-**"
209210
- "build/diagnostics/*"
210211
agents:

pkg/testing/runner/kubernetes.go

+15-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package runner
66

77
import (
88
"context"
9+
"errors"
910
"fmt"
1011
"os"
1112
"path/filepath"
@@ -63,6 +64,19 @@ func (KubernetesRunner) Run(ctx context.Context, verbose bool, sshClient SSHClie
6364
env["AGENT_VERSION"] = agentVersion
6465
env["TEST_DEFINE_PREFIX"] = testPrefix
6566

67+
buildFolderAbsPath, err := filepath.Abs("build")
68+
if err != nil {
69+
return OSRunnerResult{}, err
70+
}
71+
72+
podLogsPath := filepath.Join(buildFolderAbsPath, fmt.Sprintf("k8s-logs-%s", testPrefix))
73+
err = os.Mkdir(podLogsPath, 0755)
74+
if err != nil && !errors.Is(err, os.ErrExist) {
75+
return OSRunnerResult{}, err
76+
}
77+
78+
env["K8S_TESTS_POD_LOGS_BASE"] = podLogsPath
79+
6680
params := devtools.GoTestArgs{
6781
LogName: testName,
6882
OutputFile: fileName + ".out",
@@ -72,7 +86,7 @@ func (KubernetesRunner) Run(ctx context.Context, verbose bool, sshClient SSHClie
7286
ExtraFlags: extraFlags,
7387
Env: env,
7488
}
75-
err := devtools.GoTest(ctx, params)
89+
err = devtools.GoTest(ctx, params)
7690
if err != nil {
7791
return OSRunnerResult{}, err
7892
}

testing/integration/kubernetes_agent_standalone_test.go

+72-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"fmt"
1313
"io"
1414
"os"
15+
"path/filepath"
1516
"testing"
1617
"time"
1718

@@ -26,6 +27,8 @@ import (
2627
"k8s.io/apimachinery/pkg/runtime"
2728
"k8s.io/apimachinery/pkg/runtime/serializer"
2829
"k8s.io/apimachinery/pkg/util/yaml"
30+
"k8s.io/client-go/kubernetes"
31+
"sigs.k8s.io/e2e-framework/klient"
2932
"sigs.k8s.io/e2e-framework/klient/k8s"
3033
"sigs.k8s.io/kustomize/api/krusty"
3134
"sigs.k8s.io/kustomize/kyaml/filesys"
@@ -51,6 +54,9 @@ func TestKubernetesAgentStandalone(t *testing.T) {
5154
require.NoError(t, err)
5255
require.NotNil(t, client)
5356

57+
testLogsBasePath := os.Getenv("K8S_TESTS_POD_LOGS_BASE")
58+
require.NotEmpty(t, testLogsBasePath)
59+
5460
ctx := context.Background()
5561

5662
namespace := info.Namespace
@@ -79,6 +85,9 @@ func TestKubernetesAgentStandalone(t *testing.T) {
7985
},
8086
}
8187
t.Cleanup(func() {
88+
if t.Failed() {
89+
dumpLogs(t, ctx, client, namespace, testLogsBasePath)
90+
}
8291
_ = client.Resources().Delete(ctx, k8sNamespaceObj)
8392
for _, obj := range objects {
8493
_ = client.Resources(namespace).Delete(ctx, obj)
@@ -129,6 +138,12 @@ func TestKubernetesAgentStandalone(t *testing.T) {
129138
require.NoError(t, err)
130139

131140
for _, pod := range podList.Items {
141+
for _, containerStatus := range pod.Status.ContainerStatuses {
142+
if containerStatus.RestartCount > 0 {
143+
return false
144+
}
145+
}
146+
132147
for _, cond := range pod.Status.Conditions {
133148
if cond.Type != corev1.PodReady {
134149
continue
@@ -141,8 +156,63 @@ func TestKubernetesAgentStandalone(t *testing.T) {
141156
}
142157

143158
return true
144-
}, time.Second*100, time.Second*1)
145-
require.NoError(t, err)
159+
}, time.Second*100, time.Second*1, "Timed out waiting for pods to be ready")
160+
}
161+
162+
func dumpLogs(t *testing.T, ctx context.Context, client klient.Client, namespace string, targetDir string) {
163+
164+
podList := &corev1.PodList{}
165+
166+
clientset, err := kubernetes.NewForConfig(client.RESTConfig())
167+
if err != nil {
168+
t.Logf("Error creating clientset: %v\n", err)
169+
return
170+
}
171+
172+
err = client.Resources(namespace).List(ctx, podList)
173+
if err != nil {
174+
t.Logf("Error listing pods: %v\n", err)
175+
return
176+
}
177+
178+
for _, pod := range podList.Items {
179+
180+
previous := false
181+
for _, containerStatus := range pod.Status.ContainerStatuses {
182+
if containerStatus.RestartCount > 0 {
183+
previous = true
184+
break
185+
}
186+
}
187+
188+
for _, container := range pod.Spec.Containers {
189+
logFilePath := filepath.Join(targetDir, fmt.Sprintf("%s-%s-%s.log", t.Name(), pod.Name, container.Name))
190+
logFile, err := os.Create(logFilePath)
191+
if err != nil {
192+
t.Logf("Error creating log file: %v\n", err)
193+
continue
194+
}
195+
196+
req := clientset.CoreV1().Pods(namespace).GetLogs(pod.Name, &corev1.PodLogOptions{
197+
Container: container.Name,
198+
Previous: previous,
199+
})
200+
podLogsStream, err := req.Stream(context.TODO())
201+
if err != nil {
202+
t.Logf("Error getting container %s of pod %s logs: %v\n", container.Name, pod.Name, err)
203+
continue
204+
}
205+
206+
_, err = io.Copy(logFile, podLogsStream)
207+
if err != nil {
208+
t.Logf("Error writing container %s of pod %s logs: %v\n", container.Name, pod.Name, err)
209+
} else {
210+
t.Logf("Wrote container %s of pod %s logs to %s\n", container.Name, pod.Name, logFilePath)
211+
}
212+
213+
_ = podLogsStream.Close()
214+
}
215+
}
146216
}
147217

148218
// YAMLDecoder converts YAML bytes into test.Builder instances.

0 commit comments

Comments
 (0)