From d99a268da569053dae4871b21e5144f8c203d778 Mon Sep 17 00:00:00 2001 From: Harsha Narayana Date: Wed, 17 Jul 2024 20:30:11 +0530 Subject: [PATCH] runtimes: enable log export feature --- pkg/runtimes/docker/docker.go | 21 +++++++++++++++ pkg/runtimes/docker/node.go | 3 +++ pkg/runtimes/docker/util.go | 49 +++++++++++++++++++++++++++++++++-- 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/pkg/runtimes/docker/docker.go b/pkg/runtimes/docker/docker.go index 4c812d7b4..01534f330 100644 --- a/pkg/runtimes/docker/docker.go +++ b/pkg/runtimes/docker/docker.go @@ -43,11 +43,32 @@ func (d Docker) ID() string { return "docker" } +type commandInfo struct { + Command []string + FileName string +} + var roleBasedExportPath = map[k3d.Role][]string{ k3d.ServerRole: {"/var/log", "/var/lib/rancher/k3s/agent/containerd/containerd.log"}, k3d.AgentRole: {"/var/log", "/var/lib/rancher/k3s/agent/containerd/containerd.log"}, } +var roleBasedCommandsToExecute = map[k3d.Role][]commandInfo{ + k3d.ServerRole: { + {Command: []string{"crictl", "images"}, FileName: "crictl-images.log"}, + {Command: []string{"crictl", "ps", "-a"}, FileName: "crictl-ps.log"}, + {Command: []string{"kubectl", "cluster-info"}, FileName: "cluster-info.log"}, + {Command: []string{"kubectl", "version"}, FileName: "kubectl-version.log"}, + {Command: []string{"kubectl", "get", "node", "-o", "yaml"}, FileName: "kubectl-get-node.yaml"}, + {Command: []string{"ps", "-aef"}, FileName: "ps-aef.log"}, + }, + k3d.AgentRole: { + {Command: []string{"crictl", "images"}, FileName: "crictl-images.log"}, + {Command: []string{"crictl", "ps", "-a"}, FileName: "crictl-ps.log"}, + {Command: []string{"ps", "-aef"}, FileName: "ps-aef.log"}, + }, +} + // GetHost returns the docker daemon host func (d Docker) GetHost() string { // a) docker-machine diff --git a/pkg/runtimes/docker/node.go b/pkg/runtimes/docker/node.go index 0e66d113e..4e2240da0 100644 --- a/pkg/runtimes/docker/node.go +++ b/pkg/runtimes/docker/node.go @@ -535,5 +535,8 @@ func (d Docker) ExportLogsFromNode(ctx context.Context, node *k3d.Node, dstPath return fmt.Errorf("failed to untar files from container '%s': %w", c.ID, err) } } + for _, command := range roleBasedCommandsToExecute[node.Role] { + d.executeCommandInContainer(ctx, docker, c.ID, command.Command, filepath.Join(destinationPath, command.FileName)) + } return nil } diff --git a/pkg/runtimes/docker/util.go b/pkg/runtimes/docker/util.go index d427ee86e..9b7bf7b0d 100644 --- a/pkg/runtimes/docker/util.go +++ b/pkg/runtimes/docker/util.go @@ -23,6 +23,7 @@ package docker import ( "archive/tar" + "bufio" "bytes" "context" "fmt" @@ -37,6 +38,7 @@ import ( "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/flags" "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/api/types/strslice" "github.com/docker/docker/client" "github.com/docker/docker/pkg/archive" l "github.com/k3d-io/k3d/v5/pkg/logger" @@ -181,6 +183,51 @@ func (d Docker) ReadFromNode(ctx context.Context, path string, node *k3d.Node) ( return reader, err } +func (d Docker) executeCommandInContainer(ctx context.Context, cli client.APIClient, containerID string, command []string, outputFilePath string) error { + execConfig := container.ExecOptions{ + Cmd: strslice.StrSlice(command), + AttachStdout: true, + AttachStderr: true, + Tty: false, + } + + execIDResp, err := cli.ContainerExecCreate(ctx, containerID, execConfig) + if err != nil { + return fmt.Errorf("error creating exec instance: %v", err) + } + + resp, err := cli.ContainerExecAttach(ctx, execIDResp.ID, container.ExecStartOptions{Tty: false}) + if err != nil { + return fmt.Errorf("error attaching to exec instance: %v", err) + } + defer resp.Close() + + outputFile, err := os.Create(outputFilePath) + if err != nil { + return fmt.Errorf("error creating output file: %v", err) + } + defer outputFile.Close() + + writer := bufio.NewWriter(outputFile) + + var stdoutBuf bytes.Buffer + + _, err = io.Copy(&stdoutBuf, resp.Reader) + if err != nil { + return fmt.Errorf("Error copying stdout: %v", err) + } + + if _, err := writer.WriteString(stdoutBuf.String()); err != nil { + return fmt.Errorf("Error writing stdout to file: %v", err) + } + + if err := writer.Flush(); err != nil { + return fmt.Errorf("Error flushing writer: %v", err) + } + + return nil +} + // GetDockerClient returns a docker client func GetDockerClient() (client.APIClient, error) { dockerCli, err := command.NewDockerCli(command.WithStandardStreams()) @@ -258,7 +305,6 @@ func copyOriginalContent(cli client.APIClient, ctx context.Context, containerID, return err } } else if header.Typeflag == tar.TypeDir { - // If the link target is a directory, recursively copy its contents if err := untarReader(ctx, cli, containerID, reader, target); err != nil { return err } @@ -293,7 +339,6 @@ func untarReader(ctx context.Context, cli client.APIClient, containerID string, return err } case tar.TypeSymlink: - // Resolve the symlink and copy the original content linkTarget := header.Linkname if err := copyOriginalContent(cli, ctx, containerID, linkTarget, target); err != nil { return err