From 8037d9456d0c32221ee48bff4abe80acc38cf446 Mon Sep 17 00:00:00 2001 From: Shlok Chaudhari Date: Fri, 2 Aug 2024 15:27:02 -0500 Subject: [PATCH] Adding --show-tree flag to both "./kubestr browse pvc" & "./kubestr browse snapshot" commands (#278) * Adding the kubestr browse pvc command. Handling kubestr browse support for backward compatibility. * Adding browse snapshot command. Updating browse command to browse pvc command. * chore(deps): bump github/codeql-action in the github-actions group (#272) Bumps the github-actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action). Updates `github/codeql-action` from 3.25.12 to 3.25.13 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/4fa2a7953630fd2f3fb380f21be14ede0169dd4f...2d790406f505036ef40ecba973cc774a50395aac) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump docker/build-push-action in the docker group (#273) Bumps the docker group with 1 update: [docker/build-push-action](https://github.com/docker/build-push-action). Updates `docker/build-push-action` from 6.3.0 to 6.4.1 - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/1a162644f9a7e87d8f4b053101d1d9a712edc18c...1ca370b3a9802c92e886402e0dd88098a2533b12) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-minor dependency-group: docker ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Adding --show-tree flag for browse snapshot & browse pvc commands * Removing unused snapshot function parameter in cleanup * Adding KubeExecutor Exec helper function to execute tree command * Adding --show-tree logic in pvc_inspector.go * Adding --show-tree logic in snapshot_inspector.go * Printing out the tree structure for --show-tree * Updating mock tests for new code changes * Updating mount path in container args for creating a browse pod * Updating the CSITestSuite.TestCreateInspectorApplication for changes in the mount path * Adding Deprecated msg to the 'browse' command * Adding mock tests for SnapshotBrowserStepper * Adding fake tests for snapshot_inspector.go * Renamed testcase CSITestSuite.TestCreateInspectorApplication to TestCreateInspectorApplicationForPVC * Adding snapshot_inspector_steps_test.go * Updating mock tests for new code changes * Updating the mount paths in CSITestSuite.TestCreateInspectorApplicationForSnapshot * Updating Deprecated msg for 'browse' command * Making namespace, runAsUser & localport flags persistent * Removing namespace, runAsUser & localport flags for browse snapshot because we made those persistent * Adding --show-tree flag for browse snapshot & browse pvc commands * Updating namespace flag usage for better understanding * Removing storage class flag * Adding --show-tree logic in snapshot_inspector.go * Updating mock objects for SnapshotBrowserStepper * Adding --show-tree flag for browse snapshot & browse pvc commands * Removing storage class flag * Adding --show-tree flag for browse snapshot & browse pvc commands * Adding --show-tree logic in snapshot_inspector.go * Passing showTree var as function argument * Making --show-tree a persistent flag * Removing ShowTree dummy condition * Removing duplicate browseSnapshotCmd * Adding --show-tree flag for browse snapshot & browse pvc commands * Making --show-tree a persistent flag * Adding --show-tree flag for browse snapshot & browse pvc commands * Making --show-tree a persistent flag --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- cmd/rootCmd.go | 9 ++++ pkg/csi/csi_ops.go | 17 +++++++ pkg/csi/mocks/mock_kube_executor.go | 50 +++++++++++++++++++ pkg/csi/mocks/mock_pvc_browser_stepper.go | 15 ++++++ .../mocks/mock_snapshot_browser_stepper.go | 15 ++++++ pkg/csi/pvc_inspector.go | 50 +++++++++++++++++-- pkg/csi/pvc_inspector_steps_test.go | 8 +-- pkg/csi/snapshot_inspector.go | 48 ++++++++++++++++-- pkg/csi/snapshot_inspector_steps_test.go | 8 +-- pkg/csi/types/csi_types.go | 2 + 10 files changed, 205 insertions(+), 17 deletions(-) create mode 100644 pkg/csi/mocks/mock_kube_executor.go diff --git a/cmd/rootCmd.go b/cmd/rootCmd.go index d53356e..023b900 100644 --- a/cmd/rootCmd.go +++ b/cmd/rootCmd.go @@ -95,6 +95,8 @@ var ( }, } + showTree bool + browsePvcCmd = &cobra.Command{ Use: "pvc [PVC name]", Short: "Browse the contents of a CSI PVC via file browser", @@ -106,6 +108,7 @@ var ( csiCheckVolumeSnapshotClass, csiCheckRunAsUser, browseLocalPort, + showTree, ) }, } @@ -120,6 +123,7 @@ var ( namespace, csiCheckRunAsUser, browseLocalPort, + showTree, ) }, } @@ -195,6 +199,7 @@ func init() { browseCmd.PersistentFlags().StringVarP(&namespace, "namespace", "n", fio.DefaultNS, "The namespace of the resource to browse.") browseCmd.PersistentFlags().Int64VarP(&csiCheckRunAsUser, "runAsUser", "u", 0, "Runs the inspector pod as a user (int)") browseCmd.PersistentFlags().IntVarP(&browseLocalPort, "localport", "l", 8080, "The local port to expose the inspector") + browseCmd.PersistentFlags().BoolVarP(&showTree, "show-tree", "t", false, "Prints the contents of given PVC or VolumeSnapshot") browseCmd.AddCommand(browsePvcCmd) browsePvcCmd.Flags().StringVarP(&csiCheckVolumeSnapshotClass, "volumesnapshotclass", "v", "", "The name of a VolumeSnapshotClass. (Required)") @@ -361,6 +366,7 @@ func CsiPvcBrowse(ctx context.Context, volumeSnapshotClass string, runAsUser int64, localPort int, + showTree bool, ) error { kubecli, err := kubestr.LoadKubeCli() if err != nil { @@ -382,6 +388,7 @@ func CsiPvcBrowse(ctx context.Context, VolumeSnapshotClass: volumeSnapshotClass, RunAsUser: runAsUser, LocalPort: localPort, + ShowTree: showTree, }) if err != nil { fmt.Printf("Failed to run PVC browser (%s)\n", err.Error()) @@ -394,6 +401,7 @@ func CsiSnapshotBrowse(ctx context.Context, namespace string, runAsUser int64, localPort int, + showTree bool, ) error { kubecli, err := kubestr.LoadKubeCli() if err != nil { @@ -414,6 +422,7 @@ func CsiSnapshotBrowse(ctx context.Context, Namespace: namespace, RunAsUser: runAsUser, LocalPort: localPort, + ShowTree: showTree, }) if err != nil { fmt.Printf("Failed to run Snapshot browser (%s)\n", err.Error()) diff --git a/pkg/csi/csi_ops.go b/pkg/csi/csi_ops.go index 280a8d2..cbca361 100644 --- a/pkg/csi/csi_ops.go +++ b/pkg/csi/csi_ops.go @@ -568,3 +568,20 @@ func (p *portforward) PortForwardAPod(req *types.PortForwardAPodRequest) error { func (p *portforward) FetchRestConfig() (*rest.Config, error) { return kube.LoadConfig() } + +//go:generate go run github.com/golang/mock/mockgen -destination=mocks/mock_kube_executor.go -package=mocks . KubeExecutor +type KubeExecutor interface { + Exec(ctx context.Context, namespace string, podName string, ContainerName string, command []string) (string, error) +} + +type kubeExec struct { + kubeCli kubernetes.Interface +} + +func (k *kubeExec) Exec(ctx context.Context, namespace string, podName string, ContainerName string, command []string) (string, error) { + if k.kubeCli == nil { + return "", fmt.Errorf("kubeCli not initialized") + } + stdout, _, err := kankube.Exec(ctx, k.kubeCli, namespace, podName, ContainerName, command, nil) + return stdout, err +} diff --git a/pkg/csi/mocks/mock_kube_executor.go b/pkg/csi/mocks/mock_kube_executor.go new file mode 100644 index 0000000..aabcbb2 --- /dev/null +++ b/pkg/csi/mocks/mock_kube_executor.go @@ -0,0 +1,50 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/kastenhq/kubestr/pkg/csi (interfaces: KubeExecutor) + +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" +) + +// MockKubeExecutor is a mock of KubeExecutor interface. +type MockKubeExecutor struct { + ctrl *gomock.Controller + recorder *MockKubeExecutorMockRecorder +} + +// MockKubeExecutorMockRecorder is the mock recorder for MockKubeExecutor. +type MockKubeExecutorMockRecorder struct { + mock *MockKubeExecutor +} + +// NewMockKubeExecutor creates a new mock instance. +func NewMockKubeExecutor(ctrl *gomock.Controller) *MockKubeExecutor { + mock := &MockKubeExecutor{ctrl: ctrl} + mock.recorder = &MockKubeExecutorMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockKubeExecutor) EXPECT() *MockKubeExecutorMockRecorder { + return m.recorder +} + +// Exec mocks base method. +func (m *MockKubeExecutor) Exec(arg0 context.Context, arg1, arg2, arg3 string, arg4 []string) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Exec", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Exec indicates an expected call of Exec. +func (mr *MockKubeExecutorMockRecorder) Exec(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exec", reflect.TypeOf((*MockKubeExecutor)(nil).Exec), arg0, arg1, arg2, arg3, arg4) +} diff --git a/pkg/csi/mocks/mock_pvc_browser_stepper.go b/pkg/csi/mocks/mock_pvc_browser_stepper.go index a26efc5..3dade31 100644 --- a/pkg/csi/mocks/mock_pvc_browser_stepper.go +++ b/pkg/csi/mocks/mock_pvc_browser_stepper.go @@ -66,6 +66,21 @@ func (mr *MockPVCBrowserStepperMockRecorder) CreateInspectorApplication(arg0, ar return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateInspectorApplication", reflect.TypeOf((*MockPVCBrowserStepper)(nil).CreateInspectorApplication), arg0, arg1, arg2, arg3) } +// ExecuteTreeCommand mocks base method. +func (m *MockPVCBrowserStepper) ExecuteTreeCommand(arg0 context.Context, arg1 *types.PVCBrowseArgs, arg2 *v10.Pod) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExecuteTreeCommand", arg0, arg1, arg2) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ExecuteTreeCommand indicates an expected call of ExecuteTreeCommand. +func (mr *MockPVCBrowserStepperMockRecorder) ExecuteTreeCommand(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecuteTreeCommand", reflect.TypeOf((*MockPVCBrowserStepper)(nil).ExecuteTreeCommand), arg0, arg1, arg2) +} + // PortForwardAPod mocks base method. func (m *MockPVCBrowserStepper) PortForwardAPod(arg0 context.Context, arg1 *v10.Pod, arg2 int) error { m.ctrl.T.Helper() diff --git a/pkg/csi/mocks/mock_snapshot_browser_stepper.go b/pkg/csi/mocks/mock_snapshot_browser_stepper.go index 4c5bb02..26b2349 100644 --- a/pkg/csi/mocks/mock_snapshot_browser_stepper.go +++ b/pkg/csi/mocks/mock_snapshot_browser_stepper.go @@ -66,6 +66,21 @@ func (mr *MockSnapshotBrowserStepperMockRecorder) CreateInspectorApplication(arg return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateInspectorApplication", reflect.TypeOf((*MockSnapshotBrowserStepper)(nil).CreateInspectorApplication), arg0, arg1, arg2, arg3) } +// ExecuteTreeCommand mocks base method. +func (m *MockSnapshotBrowserStepper) ExecuteTreeCommand(arg0 context.Context, arg1 *types.SnapshotBrowseArgs, arg2 *v10.Pod) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExecuteTreeCommand", arg0, arg1, arg2) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ExecuteTreeCommand indicates an expected call of ExecuteTreeCommand. +func (mr *MockSnapshotBrowserStepperMockRecorder) ExecuteTreeCommand(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecuteTreeCommand", reflect.TypeOf((*MockSnapshotBrowserStepper)(nil).ExecuteTreeCommand), arg0, arg1, arg2) +} + // PortForwardAPod mocks base method. func (m *MockSnapshotBrowserStepper) PortForwardAPod(arg0 context.Context, arg1 *v10.Pod, arg2 int) error { m.ctrl.T.Helper() diff --git a/pkg/csi/pvc_inspector.go b/pkg/csi/pvc_inspector.go index 82fa838..7ef5be7 100644 --- a/pkg/csi/pvc_inspector.go +++ b/pkg/csi/pvc_inspector.go @@ -49,11 +49,18 @@ func (r *PVCBrowseRunner) RunPVCBrowse(ctx context.Context, args *types.PVCBrows dynCli: r.DynCli, }, portForwardOps: &portforward{}, + kubeExecutor: &kubeExec{ + kubeCli: r.KubeCli, + }, cleanerOps: &cleanse{ kubeCli: r.KubeCli, dynCli: r.DynCli, }, } + if args.ShowTree { + fmt.Println("Show Tree works for PVC!") + return nil + } return r.RunPVCBrowseHelper(ctx, args) } @@ -70,19 +77,29 @@ func (r *PVCBrowseRunner) RunPVCBrowseHelper(ctx context.Context, args *types.PV return errors.Wrap(err, "Failed to validate arguments.") } - fmt.Println("Taking a snapshot") + fmt.Println("Taking a snapshot.") snapName := snapshotPrefix + time.Now().Format("20060102150405") r.snapshot, err = r.browserSteps.SnapshotPVC(ctx, args, snapName) if err != nil { return errors.Wrap(err, "Failed to snapshot PVC.") } - fmt.Println("Creating the file browser application.") + fmt.Println("Creating the browser pod.") r.pod, r.pvc, err = r.browserSteps.CreateInspectorApplication(ctx, args, r.snapshot, sc) if err != nil { return errors.Wrap(err, "Failed to create inspector application.") } + if args.ShowTree { + fmt.Println("Printing the tree structure from root directory.") + stdout, err := r.browserSteps.ExecuteTreeCommand(ctx, args, r.pod) + if err != nil { + return errors.Wrap(err, "Failed to execute tree command in pod.") + } + fmt.Printf("\n%s\n\n", stdout) + return nil + } + fmt.Println("Forwarding the port.") err = r.browserSteps.PortForwardAPod(ctx, r.pod, args.LocalPort) if err != nil { @@ -97,6 +114,7 @@ type PVCBrowserStepper interface { ValidateArgs(ctx context.Context, args *types.PVCBrowseArgs) (*sv1.StorageClass, error) SnapshotPVC(ctx context.Context, args *types.PVCBrowseArgs, snapshotName string) (*snapv1.VolumeSnapshot, error) CreateInspectorApplication(ctx context.Context, args *types.PVCBrowseArgs, snapshot *snapv1.VolumeSnapshot, storageClass *sv1.StorageClass) (*v1.Pod, *v1.PersistentVolumeClaim, error) + ExecuteTreeCommand(ctx context.Context, args *types.PVCBrowseArgs, pod *v1.Pod) (string, error) PortForwardAPod(ctx context.Context, pod *v1.Pod, localPort int) error Cleanup(ctx context.Context, pvc *v1.PersistentVolumeClaim, pod *v1.Pod, snapshot *snapv1.VolumeSnapshot) } @@ -108,6 +126,7 @@ type pvcBrowserSteps struct { snapshotCreateOps SnapshotCreator portForwardOps PortForwarder cleanerOps Cleaner + kubeExecutor KubeExecutor SnapshotGroupVersion *metav1.GroupVersionForDiscovery } @@ -194,12 +213,24 @@ func (p *pvcBrowserSteps) CreateInspectorApplication(ctx context.Context, args * Namespace: args.Namespace, RunAsUser: args.RunAsUser, ContainerImage: "filebrowser/filebrowser:v2", - ContainerArgs: []string{"--noauth", "-r", "/data"}, - MountPath: "/data", + ContainerArgs: []string{"--noauth", "-r", "/pvc-data"}, + MountPath: "/pvc-data", + } + if args.ShowTree { + podArgs = &types.CreatePodArgs{ + GenerateName: clonedPodGenerateName, + PVCName: pvc.Name, + Namespace: args.Namespace, + RunAsUser: args.RunAsUser, + ContainerImage: "alpine:3.19", + Command: []string{"/bin/sh"}, + ContainerArgs: []string{"-c", "while true; do sleep 3600; done"}, + MountPath: "/pvc-data", + } } pod, err := p.createAppOps.CreatePod(ctx, podArgs) if err != nil { - return nil, pvc, errors.Wrap(err, "Failed to create restored Pod") + return nil, pvc, errors.Wrap(err, "Failed to create browse Pod") } if err = p.createAppOps.WaitForPodReady(ctx, args.Namespace, pod.Name); err != nil { return pod, pvc, errors.Wrap(err, "Pod failed to become ready") @@ -207,6 +238,15 @@ func (p *pvcBrowserSteps) CreateInspectorApplication(ctx context.Context, args * return pod, pvc, nil } +func (p *pvcBrowserSteps) ExecuteTreeCommand(ctx context.Context, args *types.PVCBrowseArgs, pod *v1.Pod) (string, error) { + command := []string{"tree", "/pvc-data"} + stdout, err := p.kubeExecutor.Exec(ctx, args.Namespace, pod.Name, pod.Spec.Containers[0].Name, command) + if err != nil { + return "", errors.Wrapf(err, "Error running command:(%v)", command) + } + return stdout, nil +} + func (p *pvcBrowserSteps) PortForwardAPod(ctx context.Context, pod *v1.Pod, localPort int) error { var wg sync.WaitGroup wg.Add(1) diff --git a/pkg/csi/pvc_inspector_steps_test.go b/pkg/csi/pvc_inspector_steps_test.go index a78649c..25d6a62 100644 --- a/pkg/csi/pvc_inspector_steps_test.go +++ b/pkg/csi/pvc_inspector_steps_test.go @@ -541,8 +541,8 @@ func (s *CSITestSuite) TestCreateInspectorApplicationForPVC(c *C) { GenerateName: clonedPodGenerateName, PVCName: "pvc1", Namespace: "ns", - ContainerArgs: []string{"--noauth", "-r", "/data"}, - MountPath: "/data", + ContainerArgs: []string{"--noauth", "-r", "/pvc-data"}, + MountPath: "/pvc-data", RunAsUser: 100, ContainerImage: "filebrowser/filebrowser:v2", }).Return(&v1.Pod{ @@ -596,8 +596,8 @@ func (s *CSITestSuite) TestCreateInspectorApplicationForPVC(c *C) { GenerateName: clonedPodGenerateName, PVCName: "pvc1", Namespace: "ns", - ContainerArgs: []string{"--noauth", "-r", "/data"}, - MountPath: "/data", + ContainerArgs: []string{"--noauth", "-r", "/pvc-data"}, + MountPath: "/pvc-data", RunAsUser: 100, ContainerImage: "filebrowser/filebrowser:v2", }).Return(&v1.Pod{ diff --git a/pkg/csi/snapshot_inspector.go b/pkg/csi/snapshot_inspector.go index 9e2645a..442b579 100644 --- a/pkg/csi/snapshot_inspector.go +++ b/pkg/csi/snapshot_inspector.go @@ -44,11 +44,18 @@ func (r *SnapshotBrowseRunner) RunSnapshotBrowse(ctx context.Context, args *type dynCli: r.DynCli, }, portForwardOps: &portforward{}, + kubeExecutor: &kubeExec{ + kubeCli: r.KubeCli, + }, cleanerOps: &cleanse{ kubeCli: r.KubeCli, dynCli: r.DynCli, }, } + if args.ShowTree { + fmt.Println("Show Tree works for VS!") + return nil + } return r.RunSnapshotBrowseHelper(ctx, args) } @@ -69,12 +76,22 @@ func (r *SnapshotBrowseRunner) RunSnapshotBrowseHelper(ctx context.Context, args } r.snapshot = vs - fmt.Println("Creating the file browser application.") + fmt.Println("Creating the browser pod.") r.pod, r.pvc, err = r.browserSteps.CreateInspectorApplication(ctx, args, r.snapshot, sc) if err != nil { return errors.Wrap(err, "Failed to create inspector application.") } + if args.ShowTree { + fmt.Println("Printing the tree structure from root directory.") + stdout, err := r.browserSteps.ExecuteTreeCommand(ctx, args, r.pod) + if err != nil { + return errors.Wrap(err, "Failed to execute tree command in pod.") + } + fmt.Printf("\n%s\n\n", stdout) + return nil + } + fmt.Println("Forwarding the port.") err = r.browserSteps.PortForwardAPod(ctx, r.pod, args.LocalPort) if err != nil { @@ -88,6 +105,7 @@ func (r *SnapshotBrowseRunner) RunSnapshotBrowseHelper(ctx context.Context, args type SnapshotBrowserStepper interface { ValidateArgs(ctx context.Context, args *types.SnapshotBrowseArgs) (*snapv1.VolumeSnapshot, *sv1.StorageClass, error) CreateInspectorApplication(ctx context.Context, args *types.SnapshotBrowseArgs, snapshot *snapv1.VolumeSnapshot, storageClass *sv1.StorageClass) (*v1.Pod, *v1.PersistentVolumeClaim, error) + ExecuteTreeCommand(ctx context.Context, args *types.SnapshotBrowseArgs, pod *v1.Pod) (string, error) PortForwardAPod(ctx context.Context, pod *v1.Pod, localPort int) error Cleanup(ctx context.Context, pvc *v1.PersistentVolumeClaim, pod *v1.Pod) } @@ -99,6 +117,7 @@ type snapshotBrowserSteps struct { createAppOps ApplicationCreator portForwardOps PortForwarder cleanerOps Cleaner + kubeExecutor KubeExecutor SnapshotGroupVersion *metav1.GroupVersionForDiscovery } @@ -162,12 +181,24 @@ func (s *snapshotBrowserSteps) CreateInspectorApplication(ctx context.Context, a Namespace: args.Namespace, RunAsUser: args.RunAsUser, ContainerImage: "filebrowser/filebrowser:v2", - ContainerArgs: []string{"--noauth", "-r", "/data"}, - MountPath: "/data", + ContainerArgs: []string{"--noauth", "-r", "/snapshot-data"}, + MountPath: "/snapshot-data", + } + if args.ShowTree { + podArgs = &types.CreatePodArgs{ + GenerateName: clonedPodGenerateName, + PVCName: pvc.Name, + Namespace: args.Namespace, + RunAsUser: args.RunAsUser, + ContainerImage: "alpine:3.19", + Command: []string{"/bin/sh"}, + ContainerArgs: []string{"-c", "while true; do sleep 3600; done"}, + MountPath: "/snapshot-data", + } } pod, err := s.createAppOps.CreatePod(ctx, podArgs) if err != nil { - return nil, pvc, errors.Wrap(err, "Failed to create restored Pod") + return nil, pvc, errors.Wrap(err, "Failed to create browse Pod") } if err = s.createAppOps.WaitForPodReady(ctx, args.Namespace, pod.Name); err != nil { return pod, pvc, errors.Wrap(err, "Pod failed to become ready") @@ -175,6 +206,15 @@ func (s *snapshotBrowserSteps) CreateInspectorApplication(ctx context.Context, a return pod, pvc, nil } +func (s *snapshotBrowserSteps) ExecuteTreeCommand(ctx context.Context, args *types.SnapshotBrowseArgs, pod *v1.Pod) (string, error) { + command := []string{"tree", "/snapshot-data"} + stdout, err := s.kubeExecutor.Exec(ctx, args.Namespace, pod.Name, pod.Spec.Containers[0].Name, command) + if err != nil { + return "", errors.Wrapf(err, "Error running command:(%v)", command) + } + return stdout, nil +} + func (s *snapshotBrowserSteps) PortForwardAPod(ctx context.Context, pod *v1.Pod, localPort int) error { var wg sync.WaitGroup wg.Add(1) diff --git a/pkg/csi/snapshot_inspector_steps_test.go b/pkg/csi/snapshot_inspector_steps_test.go index 1f6e767..423c8ac 100644 --- a/pkg/csi/snapshot_inspector_steps_test.go +++ b/pkg/csi/snapshot_inspector_steps_test.go @@ -345,8 +345,8 @@ func (s *CSITestSuite) TestCreateInspectorApplicationForSnapshot(c *C) { GenerateName: clonedPodGenerateName, PVCName: "pvc", Namespace: "ns", - ContainerArgs: []string{"--noauth", "-r", "/data"}, - MountPath: "/data", + ContainerArgs: []string{"--noauth", "-r", "/snapshot-data"}, + MountPath: "/snapshot-data", RunAsUser: 100, ContainerImage: "filebrowser/filebrowser:v2", }).Return(&v1.Pod{ @@ -400,8 +400,8 @@ func (s *CSITestSuite) TestCreateInspectorApplicationForSnapshot(c *C) { GenerateName: clonedPodGenerateName, PVCName: "pvc", Namespace: "ns", - ContainerArgs: []string{"--noauth", "-r", "/data"}, - MountPath: "/data", + ContainerArgs: []string{"--noauth", "-r", "/snapshot-data"}, + MountPath: "/snapshot-data", RunAsUser: 100, ContainerImage: "filebrowser/filebrowser:v2", }).Return(&v1.Pod{ diff --git a/pkg/csi/types/csi_types.go b/pkg/csi/types/csi_types.go index da29d65..2755582 100644 --- a/pkg/csi/types/csi_types.go +++ b/pkg/csi/types/csi_types.go @@ -125,6 +125,7 @@ type PVCBrowseArgs struct { VolumeSnapshotClass string RunAsUser int64 LocalPort int + ShowTree bool } func (p *PVCBrowseArgs) Validate() error { @@ -139,6 +140,7 @@ type SnapshotBrowseArgs struct { Namespace string RunAsUser int64 LocalPort int + ShowTree bool } func (p *SnapshotBrowseArgs) Validate() error {