Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 45 additions & 38 deletions test/e2e/internal/framework/dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"fmt"
"io"
"os"
"path"
"strings"

. "github.com/onsi/ginkgo/v2"
Expand Down Expand Up @@ -58,14 +59,21 @@ func truncateTestName(s string, maxLen int) string {
func (f *Framework) saveTestCaseDump() {
ft := GetFormattedTestCaseFullText()
tmpDir := GetTMPDir()
dumpDir := path.Join(tmpDir, ft)

f.saveTestCaseResources(ft, tmpDir)
f.savePodAdditionalInfo(ft, tmpDir)
f.saveIntvirtvmDescriptions(ft, tmpDir)
f.saveIntvirtvmiDescriptions(ft, tmpDir)
f.saveNodeAdditionalInfo(ft, tmpDir)
f.saveEvents(ft, tmpDir)
f.saveClusterNetworkInfo(ft, tmpDir)
err := os.MkdirAll(dumpDir, 0o755)
if err != nil {
GinkgoWriter.Printf("Failed to create dump directory:\nDir: %s\nError: %v\n", dumpDir, err)
return
}

f.saveTestCaseResources(dumpDir)
f.savePodAdditionalInfo(dumpDir)
f.saveIntvirtvmDescriptions(dumpDir)
f.saveIntvirtvmiDescriptions(dumpDir)
f.saveNodeAdditionalInfo(dumpDir)
f.saveEvents(dumpDir)
f.saveClusterNetworkInfo(dumpDir)
}

// GetFormattedTestCaseFullText returns CurrentSpecReport().FullText(), formatted with the following rules:
Expand Down Expand Up @@ -104,8 +112,8 @@ func GetTMPDir() string {
return tmpDir
}

func (f *Framework) saveTestCaseResources(testCaseFullText, dumpPath string) {
resFileName := fmt.Sprintf("%s/e2e_failed__%s.yaml", dumpPath, testCaseFullText)
func (f *Framework) saveTestCaseResources(dumpDir string) {
resFileName := path.Join(dumpDir, "resources.yaml")

// TODO: Add CVI and VMC to the request when the environment is isolated.
result := f.Clients.Kubectl().Get("virtualization,intvirt,pod,volumesnapshot,pvc", kubectl.GetOptions{
Expand All @@ -125,7 +133,7 @@ func (f *Framework) saveTestCaseResources(testCaseFullText, dumpPath string) {
}
}

func (f *Framework) savePodAdditionalInfo(testCaseFullText, dumpPath string) {
func (f *Framework) savePodAdditionalInfo(dumpDir string) {
pods, err := f.Clients.kubeClient.CoreV1().Pods(f.Namespace().Name).List(context.Background(), metav1.ListOptions{})
if err != nil {
GinkgoWriter.Printf("Failed to get PodList:\n%s\n", err)
Expand All @@ -138,39 +146,39 @@ func (f *Framework) savePodAdditionalInfo(testCaseFullText, dumpPath string) {
}

for _, pod := range pods.Items {
f.writePodLogs(pod.Name, pod.Namespace, dumpPath, testCaseFullText)
f.writePodDescription(pod.Name, pod.Namespace, dumpPath, testCaseFullText)
f.writeVirtualMachineGuestInfo(pod, dumpPath, testCaseFullText)
f.writePodLogs(pod.Name, pod.Namespace, dumpDir)
f.writePodDescription(pod.Name, pod.Namespace, dumpDir)
f.writeVirtualMachineGuestInfo(pod, dumpDir)
}
}

func (f *Framework) saveIntvirtvmDescriptions(testCaseFullText, dumpPath string) {
func (f *Framework) saveIntvirtvmDescriptions(dumpDir string) {
describeCmd := f.Clients.Kubectl().RawCommand(fmt.Sprintf("describe intvirtvm --namespace %s", f.Namespace().Name), ShortTimeout)
if describeCmd.Error() != nil {
GinkgoWriter.Printf("Failed to describe InternalVirtualizationVirtualMachine:\nError: %s\n", describeCmd.StdErr())
}

fileName := fmt.Sprintf("%s/e2e_failed__%s__intvirtvm_describe", dumpPath, testCaseFullText)
fileName := path.Join(dumpDir, "intvirtvm_describe.log")
err := os.WriteFile(fileName, describeCmd.StdOutBytes(), 0o644)
if err != nil {
GinkgoWriter.Printf("Failed to save InternalVirtualizationVirtualMachine description:\nError: %s\n", err)
}
}

func (f *Framework) saveIntvirtvmiDescriptions(testCaseFullText, dumpPath string) {
func (f *Framework) saveIntvirtvmiDescriptions(dumpDir string) {
describeCmd := f.Clients.Kubectl().RawCommand(fmt.Sprintf("describe intvirtvmi --namespace %s", f.Namespace().Name), ShortTimeout)
if describeCmd.Error() != nil {
GinkgoWriter.Printf("Failed to describe InternalVirtualizationVirtualMachineInstance:\nError: %s\n", describeCmd.StdErr())
}

fileName := fmt.Sprintf("%s/e2e_failed__%s__intvirtvmi_describe", dumpPath, testCaseFullText)
fileName := path.Join(dumpDir, "intvirtvmi_describe.log")
err := os.WriteFile(fileName, describeCmd.StdOutBytes(), 0o644)
if err != nil {
GinkgoWriter.Printf("Failed to save InternalVirtualizationVirtualMachineInstance description:\nError: %s\n", err)
}
}

func (f *Framework) writePodLogs(name, namespace, filePath, testCaseFullText string) {
func (f *Framework) writePodLogs(name, namespace, dumpDir string) {
pod, err := f.Clients.kubeClient.CoreV1().Pods(namespace).Get(context.Background(), name, metav1.GetOptions{})
if err != nil {
GinkgoWriter.Printf("Failed to get pod:\nPodName: %s\nError: %v\n", name, err)
Expand All @@ -182,11 +190,11 @@ func (f *Framework) writePodLogs(name, namespace, filePath, testCaseFullText str
GinkgoWriter.Printf("Skipping container without d8v prefix:\nPodName: %s\nContainer: %s\n", pod.Name, container.Name)
continue
}
f.writePodContainerLogs(pod, container.Name, filePath, testCaseFullText)
f.writePodContainerLogs(pod, container.Name, dumpDir)
}
}

func (f *Framework) writePodContainerLogs(pod *corev1.Pod, containerName, filePath, testCaseFullText string) {
func (f *Framework) writePodContainerLogs(pod *corev1.Pod, containerName, dumpDir string) {
podLogs, err := f.Clients.KubeClient().CoreV1().Pods(pod.Namespace).GetLogs(pod.Name,
&corev1.PodLogOptions{
Container: containerName,
Expand All @@ -203,35 +211,35 @@ func (f *Framework) writePodContainerLogs(pod *corev1.Pod, containerName, filePa
return
}

fileName := fmt.Sprintf("%s/e2e_failed__%s__%s__%s__logs.json", filePath, testCaseFullText, pod.Name, containerName)
fileName := path.Join(dumpDir, fmt.Sprintf("pod_%s__%s_logs.json", pod.Name, containerName))
err = os.WriteFile(fileName, logs, 0o644)
if err != nil {
GinkgoWriter.Printf("Failed to save logs:\nPodName: %s\nContainer: %s\nError: %v\n", pod.Name, containerName, err)
}
}

func (f *Framework) writePodDescription(name, namespace, filePath, testCaseFullText string) {
func (f *Framework) writePodDescription(name, namespace, dumpDir string) {
describeCmd := f.Clients.Kubectl().RawCommand(fmt.Sprintf("describe pod %s --namespace %s", name, namespace), ShortTimeout)
if describeCmd.Error() != nil {
GinkgoWriter.Printf("Failed to describe pod:\nPodName: %s\nError: %s\n", name, describeCmd.StdErr())
}

fileName := fmt.Sprintf("%s/e2e_failed__%s__%s__describe", filePath, testCaseFullText, name)
fileName := path.Join(dumpDir, fmt.Sprintf("pod_%s_describe.log", name))
err := os.WriteFile(fileName, describeCmd.StdOutBytes(), 0o644)
if err != nil {
GinkgoWriter.Printf("Failed to save pod description:\nPodName: %s\nError: %v\n", name, err)
}
}

func (f *Framework) writeVirtualMachineGuestInfo(pod corev1.Pod, filePath, testCaseFullText string) {
func (f *Framework) writeVirtualMachineGuestInfo(pod corev1.Pod, dumpDir string) {
if pod.Labels != nil && pod.Status.Phase == corev1.PodRunning {
if value, ok := pod.Labels["kubevirt.internal.virtualization.deckhouse.io"]; ok && value == "virt-launcher" {
vlctlGuestInfoCmd := f.Clients.Kubectl().RawCommand(fmt.Sprintf("exec %s --namespace %s -- vlctl guest info", pod.Name, pod.Namespace), ShortTimeout)
if vlctlGuestInfoCmd.Error() != nil {
GinkgoWriter.Printf("Failed to get pod guest info:\nPodName: %s\nError: %s\n", pod.Name, vlctlGuestInfoCmd.StdErr())
}

fileName := fmt.Sprintf("%s/e2e_failed__%s__%s__vlctl_guest_info", filePath, testCaseFullText, pod.Name)
fileName := path.Join(dumpDir, fmt.Sprintf("pod_%s_vlctl_guest_info.log", pod.Name))
err := os.WriteFile(fileName, vlctlGuestInfoCmd.StdOutBytes(), 0o644)
if err != nil {
GinkgoWriter.Printf("Failed to save pod guest info:\nPodName: %s\nError: %v\n", pod.Name, err)
Expand All @@ -240,22 +248,22 @@ func (f *Framework) writeVirtualMachineGuestInfo(pod corev1.Pod, filePath, testC
}
}

func (f *Framework) saveNodeAdditionalInfo(testCaseFullText, dumpPath string) {
func (f *Framework) saveNodeAdditionalInfo(dumpDir string) {
GinkgoHelper()

f.writeNodeDescription(testCaseFullText, dumpPath)
f.writeNodeList(testCaseFullText, dumpPath)
f.writeNodeDescription(dumpDir)
f.writeNodeList(dumpDir)
}

func (f *Framework) writeNodeDescription(testCaseFullText, dumpPath string) {
func (f *Framework) writeNodeDescription(dumpDir string) {
GinkgoHelper()

cmd := f.Clients.Kubectl().RawCommand("describe nodes", ShortTimeout)
if cmd.Error() != nil {
GinkgoWriter.Printf("Failed to run 'kubectl describe nodes':\nCmdError: %v\nStderr: %s\n", cmd.Error(), cmd.StdErr())
}

fileName := fmt.Sprintf("%s/e2e_failed__%s__nodes_describe.log", dumpPath, testCaseFullText)
fileName := path.Join(dumpDir, "nodes_describe.log")
if len(cmd.StdOutBytes()) > 0 {
err := os.WriteFile(fileName, cmd.StdOutBytes(), 0o644)
if err != nil {
Expand All @@ -264,15 +272,15 @@ func (f *Framework) writeNodeDescription(testCaseFullText, dumpPath string) {
}
}

func (f *Framework) writeNodeList(testCaseFullText, dumpPath string) {
func (f *Framework) writeNodeList(dumpDir string) {
GinkgoHelper()

cmd := f.Clients.Kubectl().RawCommand("get nodes -o wide", ShortTimeout)
if cmd.Error() != nil {
GinkgoWriter.Printf("Failed to run 'kubectl get nodes -o wide':\nCmdError: %v\nStderr: %s\n", cmd.Error(), cmd.StdErr())
}

fileName := fmt.Sprintf("%s/e2e_failed__%s__nodes_owide.log", dumpPath, testCaseFullText)
fileName := path.Join(dumpDir, "nodes_owide.log")
if len(cmd.StdOutBytes()) > 0 {
err := os.WriteFile(fileName, cmd.StdOutBytes(), 0o644)
if err != nil {
Expand All @@ -281,7 +289,7 @@ func (f *Framework) writeNodeList(testCaseFullText, dumpPath string) {
}
}

func (f *Framework) saveEvents(testCaseFullText, dumpPath string) {
func (f *Framework) saveEvents(dumpDir string) {
GinkgoHelper()
namespace := f.Namespace().Name
events, err := f.Clients.kubeClient.CoreV1().Events(namespace).List(context.Background(), metav1.ListOptions{})
Expand All @@ -290,7 +298,7 @@ func (f *Framework) saveEvents(testCaseFullText, dumpPath string) {
return
}

fileName := fmt.Sprintf("%s/e2e_failed__%s__%s__events.yaml", dumpPath, testCaseFullText, namespace)
fileName := path.Join(dumpDir, fmt.Sprintf("events_%s.yaml", namespace))
if len(events.Items) > 0 {
data, err := yaml.Marshal(events)
if err != nil {
Expand All @@ -305,11 +313,10 @@ func (f *Framework) saveEvents(testCaseFullText, dumpPath string) {
}
}

func (f *Framework) saveClusterNetworkInfo(testCaseFullText, dumpPath string) {
func (f *Framework) saveClusterNetworkInfo(dumpDir string) {
GinkgoHelper()

// Only for tests that use additional networks.
// We use the original full text for checking because testCaseFullText may be truncated.
if !strings.Contains(CurrentSpecReport().FullText(), "VirtualMachineAdditionalNetworkInterfaces") {
return
}
Expand All @@ -320,7 +327,7 @@ func (f *Framework) saveClusterNetworkInfo(testCaseFullText, dumpPath string) {
GinkgoWriter.Printf("Failed to get clusternetwork:\nCmdError: %v\nStderr: %s\n", cmd.Error(), cmd.StdErr())
}

fileName := fmt.Sprintf("%s/e2e_failed__%s__clusternetwork.yaml", dumpPath, testCaseFullText)
fileName := path.Join(dumpDir, "clusternetwork.yaml")
if len(cmd.StdOutBytes()) > 0 {
err := os.WriteFile(fileName, cmd.StdOutBytes(), 0o644)
if err != nil {
Expand All @@ -334,7 +341,7 @@ func (f *Framework) saveClusterNetworkInfo(testCaseFullText, dumpPath string) {
GinkgoWriter.Printf("Failed to get cep:\nCmdError: %v\nStderr: %s\n", cepCmd.Error(), cepCmd.StdErr())
}

cepFileName := fmt.Sprintf("%s/e2e_failed__%s__cep.yaml", dumpPath, testCaseFullText)
cepFileName := path.Join(dumpDir, "cep.yaml")
if len(cepCmd.StdOutBytes()) > 0 {
err := os.WriteFile(cepFileName, cepCmd.StdOutBytes(), 0o644)
if err != nil {
Expand Down
Loading