mirror of
https://github.com/replicatedhq/troubleshoot.git
synced 2026-04-15 07:16:34 +00:00
388 lines
9.4 KiB
Go
388 lines
9.4 KiB
Go
package supportbundle
|
|
|
|
import (
|
|
"archive/tar"
|
|
"compress/gzip"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
types "github.com/replicatedhq/troubleshoot/pkg/supportbundle/types"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
corev1 "k8s.io/api/core/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
)
|
|
|
|
func Test_getPodDetailsFromFiles(t *testing.T) {
|
|
podNamespace := "default"
|
|
podName := "hello-27436131-pxhk9"
|
|
|
|
podsFileContentOldFormat := `[
|
|
{
|
|
"kind": "Pod",
|
|
"apiVersion": "v1",
|
|
"metadata": {
|
|
"name": "hello-27436131-pxhk9",
|
|
"namespace": "default"
|
|
},
|
|
"spec": {
|
|
"initContainers": [
|
|
{
|
|
"name": "remove-lost-found"
|
|
}
|
|
],
|
|
"containers": [
|
|
{
|
|
"name": "hello"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]`
|
|
|
|
podsFileContentNewFormat := fmt.Sprintf(`{
|
|
"kind": "PodList",
|
|
"apiVersion": "v1",
|
|
"metadata": {
|
|
"resourceVersion": "5389414"
|
|
},
|
|
"items": %s
|
|
}`, podsFileContentOldFormat)
|
|
|
|
eventsFileContentOldFormat := `[
|
|
{
|
|
"kind": "Event",
|
|
"apiVersion": "v1",
|
|
"metadata": {
|
|
"name": "example-nginx.16d85cebe302a9b1",
|
|
"namespace": "default"
|
|
},
|
|
"involvedObject": {
|
|
"kind": "Deployment",
|
|
"namespace": "default",
|
|
"name": "example-nginx"
|
|
}
|
|
},
|
|
{
|
|
"kind": "Event",
|
|
"apiVersion": "v1",
|
|
"metadata": {
|
|
"name": "hello-27436131-pxhk9.16d85cf27380b4fa",
|
|
"namespace": "default"
|
|
},
|
|
"involvedObject": {
|
|
"kind": "Pod",
|
|
"namespace": "default",
|
|
"name": "hello-27436131-pxhk9"
|
|
}
|
|
}
|
|
]`
|
|
|
|
eventsFileContentNewFormat := fmt.Sprintf(`{
|
|
"kind": "EventList",
|
|
"apiVersion": "v1",
|
|
"metadata": {
|
|
"resourceVersion": "5389515"
|
|
},
|
|
"items": %s
|
|
}`, eventsFileContentOldFormat)
|
|
|
|
removeLostAndFoundInitContainerLogs := `some logs here`
|
|
helloContainerLogs := `Tue Mar 1 20:53:00 UTC 2022 Hello`
|
|
|
|
tests := []struct {
|
|
name string
|
|
files map[string][]byte
|
|
expect *types.PodDetails
|
|
}{
|
|
{
|
|
name: "old support bundle format",
|
|
files: map[string][]byte{
|
|
getPodsFilePath(podNamespace): []byte(podsFileContentOldFormat),
|
|
getEventsFilePath(podNamespace): []byte(eventsFileContentOldFormat),
|
|
getContainerLogsFilePath(podNamespace, podName, "remove-lost-found"): []byte(removeLostAndFoundInitContainerLogs),
|
|
getContainerLogsFilePath(podNamespace, podName, "hello"): []byte(helloContainerLogs),
|
|
},
|
|
expect: &types.PodDetails{
|
|
PodDefinition: corev1.Pod{
|
|
TypeMeta: metav1.TypeMeta{
|
|
APIVersion: "v1",
|
|
Kind: "Pod",
|
|
},
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: podName,
|
|
Namespace: podNamespace,
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
InitContainers: []corev1.Container{
|
|
{
|
|
Name: "remove-lost-found",
|
|
},
|
|
},
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: "hello",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
PodEvents: []corev1.Event{
|
|
{
|
|
TypeMeta: metav1.TypeMeta{
|
|
APIVersion: "v1",
|
|
Kind: "Event",
|
|
},
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "hello-27436131-pxhk9.16d85cf27380b4fa",
|
|
Namespace: podNamespace,
|
|
},
|
|
InvolvedObject: corev1.ObjectReference{
|
|
Kind: "Pod",
|
|
Namespace: podNamespace,
|
|
Name: podName,
|
|
},
|
|
},
|
|
},
|
|
PodContainers: []types.PodContainer{
|
|
{
|
|
Name: "remove-lost-found",
|
|
LogsFilePath: getContainerLogsFilePath(podNamespace, podName, "remove-lost-found"),
|
|
IsInitContainer: true,
|
|
},
|
|
{
|
|
Name: "hello",
|
|
LogsFilePath: getContainerLogsFilePath(podNamespace, podName, "hello"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "new support bundle format",
|
|
files: map[string][]byte{
|
|
getPodsFilePath(podNamespace): []byte(podsFileContentNewFormat),
|
|
getEventsFilePath(podNamespace): []byte(eventsFileContentNewFormat),
|
|
getContainerLogsFilePath(podNamespace, podName, "remove-lost-found"): []byte(removeLostAndFoundInitContainerLogs),
|
|
getContainerLogsFilePath(podNamespace, podName, "hello"): []byte(helloContainerLogs),
|
|
},
|
|
expect: &types.PodDetails{
|
|
PodDefinition: corev1.Pod{
|
|
TypeMeta: metav1.TypeMeta{
|
|
APIVersion: "v1",
|
|
Kind: "Pod",
|
|
},
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: podName,
|
|
Namespace: podNamespace,
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
InitContainers: []corev1.Container{
|
|
{
|
|
Name: "remove-lost-found",
|
|
},
|
|
},
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: "hello",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
PodEvents: []corev1.Event{
|
|
{
|
|
TypeMeta: metav1.TypeMeta{
|
|
APIVersion: "v1",
|
|
Kind: "Event",
|
|
},
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "hello-27436131-pxhk9.16d85cf27380b4fa",
|
|
Namespace: podNamespace,
|
|
},
|
|
InvolvedObject: corev1.ObjectReference{
|
|
Kind: "Pod",
|
|
Namespace: podNamespace,
|
|
Name: podName,
|
|
},
|
|
},
|
|
},
|
|
PodContainers: []types.PodContainer{
|
|
{
|
|
Name: "remove-lost-found",
|
|
LogsFilePath: getContainerLogsFilePath(podNamespace, podName, "remove-lost-found"),
|
|
IsInitContainer: true,
|
|
},
|
|
{
|
|
Name: "hello",
|
|
LogsFilePath: getContainerLogsFilePath(podNamespace, podName, "hello"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
req := require.New(t)
|
|
|
|
actual, err := getPodDetailsFromFiles(test.files, podNamespace, podName)
|
|
req.NoError(err)
|
|
|
|
assert.Equal(t, test.expect, actual)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetPodDetails(t *testing.T) {
|
|
req := require.New(t)
|
|
|
|
// Create a temporary directory for our test files
|
|
testDir, err := os.MkdirTemp("", "troubleshoot-test")
|
|
req.NoError(err)
|
|
defer os.RemoveAll(testDir)
|
|
|
|
// Set up test data
|
|
podNamespace := "default"
|
|
podName := "hello-27436131-pxhk9"
|
|
|
|
// Define our test files
|
|
podsFileContent := `[
|
|
{
|
|
"kind": "Pod",
|
|
"apiVersion": "v1",
|
|
"metadata": {
|
|
"name": "hello-27436131-pxhk9",
|
|
"namespace": "default"
|
|
},
|
|
"spec": {
|
|
"initContainers": [
|
|
{
|
|
"name": "remove-lost-found"
|
|
}
|
|
],
|
|
"containers": [
|
|
{
|
|
"name": "hello"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]`
|
|
|
|
eventsFileContent := `[
|
|
{
|
|
"kind": "Event",
|
|
"apiVersion": "v1",
|
|
"metadata": {
|
|
"name": "hello-27436131-pxhk9.16d85cf27380b4fa",
|
|
"namespace": "default"
|
|
},
|
|
"involvedObject": {
|
|
"kind": "Pod",
|
|
"namespace": "default",
|
|
"name": "hello-27436131-pxhk9"
|
|
}
|
|
}
|
|
]`
|
|
|
|
initContainerLogs := "some logs here"
|
|
containerLogs := "Tue Mar 1 20:53:00 UTC 2022 Hello"
|
|
|
|
// Create the directory structure for our test files
|
|
podsFilePath := getPodsFilePath(podNamespace)
|
|
eventsFilePath := getEventsFilePath(podNamespace)
|
|
initContainerLogsPath := getContainerLogsFilePath(podNamespace, podName, "remove-lost-found")
|
|
containerLogsPath := getContainerLogsFilePath(podNamespace, podName, "hello")
|
|
|
|
// Create the target file
|
|
archivePath := filepath.Join(testDir, "test-bundle.tar.gz")
|
|
file, err := os.Create(archivePath)
|
|
req.NoError(err)
|
|
|
|
// Create a gzip writer
|
|
gw := gzip.NewWriter(file)
|
|
|
|
// Create a tar writer
|
|
tw := tar.NewWriter(gw)
|
|
|
|
err = tw.WriteHeader(&tar.Header{
|
|
Name: podsFilePath,
|
|
Mode: 0644,
|
|
Size: int64(len(podsFileContent)),
|
|
})
|
|
req.NoError(err)
|
|
_, err = tw.Write([]byte(podsFileContent))
|
|
req.NoError(err)
|
|
|
|
err = tw.WriteHeader(&tar.Header{
|
|
Name: eventsFilePath,
|
|
Mode: 0644,
|
|
Size: int64(len(eventsFileContent)),
|
|
})
|
|
req.NoError(err)
|
|
_, err = tw.Write([]byte(eventsFileContent))
|
|
req.NoError(err)
|
|
|
|
err = tw.WriteHeader(&tar.Header{
|
|
Name: initContainerLogsPath,
|
|
Mode: 0644,
|
|
Size: int64(len(initContainerLogs)),
|
|
})
|
|
req.NoError(err)
|
|
_, err = tw.Write([]byte(initContainerLogs))
|
|
req.NoError(err)
|
|
|
|
err = tw.WriteHeader(&tar.Header{
|
|
Name: containerLogsPath,
|
|
Mode: 0644,
|
|
Size: int64(len(containerLogs)),
|
|
})
|
|
req.NoError(err)
|
|
_, err = tw.Write([]byte(containerLogs))
|
|
req.NoError(err)
|
|
|
|
req.NoError(tw.Close())
|
|
req.NoError(gw.Close())
|
|
req.NoError(file.Close())
|
|
|
|
// Call GetPodDetails and verify the results
|
|
podDetails, err := GetPodDetails(archivePath, podNamespace, podName)
|
|
req.NoError(err)
|
|
req.NotNil(podDetails)
|
|
|
|
// Verify pod definition
|
|
req.Equal(podName, podDetails.PodDefinition.Name)
|
|
req.Equal(podNamespace, podDetails.PodDefinition.Namespace)
|
|
|
|
// Verify init containers
|
|
req.Len(podDetails.PodDefinition.Spec.InitContainers, 1)
|
|
req.Equal("remove-lost-found", podDetails.PodDefinition.Spec.InitContainers[0].Name)
|
|
|
|
// Verify containers
|
|
req.Len(podDetails.PodDefinition.Spec.Containers, 1)
|
|
req.Equal("hello", podDetails.PodDefinition.Spec.Containers[0].Name)
|
|
|
|
// Verify events
|
|
req.Len(podDetails.PodEvents, 1)
|
|
req.Equal(podName, podDetails.PodEvents[0].InvolvedObject.Name)
|
|
|
|
// Verify pod containers
|
|
req.Len(podDetails.PodContainers, 2)
|
|
|
|
// One should be an init container
|
|
var initContainerFound, regularContainerFound bool
|
|
for _, container := range podDetails.PodContainers {
|
|
if container.Name == "remove-lost-found" {
|
|
req.True(container.IsInitContainer)
|
|
req.Equal(getContainerLogsFilePath(podNamespace, podName, "remove-lost-found"), container.LogsFilePath)
|
|
initContainerFound = true
|
|
} else if container.Name == "hello" {
|
|
req.False(container.IsInitContainer)
|
|
req.Equal(getContainerLogsFilePath(podNamespace, podName, "hello"), container.LogsFilePath)
|
|
regularContainerFound = true
|
|
}
|
|
}
|
|
req.True(initContainerFound)
|
|
req.True(regularContainerFound)
|
|
}
|