Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding "./kubestr browse snapshot" command #277

Merged
merged 17 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
96 changes: 85 additions & 11 deletions cmd/rootCmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,20 @@ var (
},
}

pvcBrowseLocalPort int
pvcBrowseCmd = &cobra.Command{
Use: "browse [PVC name]",
browseLocalPort int
browseCmd = &cobra.Command{
Use: "browse",
Short: "Browse the contents of PVC or VolumeSnapshot",
Long: "Browse the contents of a CSI provisioned PVC or a CSI provisioned VolumeSnapshot.",
Deprecated: "we recommend you to use command 'browse pvc' instead. Command 'browse pvc' will support newer updates for browsing through the contents of a PVC.",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return browsePvcCmd.RunE(cmd, args)
},
}

browsePvcCmd = &cobra.Command{
Use: "pvc [PVC name]",
Short: "Browse the contents of a CSI PVC via file browser",
Long: "Browse the contents of a CSI provisioned PVC by cloning the volume and mounting it with a file browser.",
Args: cobra.ExactArgs(1),
Expand All @@ -94,7 +105,22 @@ var (
namespace,
csiCheckVolumeSnapshotClass,
csiCheckRunAsUser,
pvcBrowseLocalPort,
browseLocalPort,
)
},
}

browseSnapshotCmd = &cobra.Command{
Use: "snapshot [Snapshot name]",
Short: "Browse the contents of a CSI VolumeSnapshot via file browser",
Long: "Browse the contents of a CSI provisioned VolumeSnapshot by cloning the volume and mounting it with a file browser.",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return CsiSnapshotBrowse(context.Background(), args[0],
namespace,
storageClass,
csiCheckRunAsUser,
browseLocalPort,
)
},
}
Expand Down Expand Up @@ -164,15 +190,29 @@ func init() {
csiCheckCmd.Flags().Int64VarP(&csiCheckRunAsUser, "runAsUser", "u", 0, "Runs the CSI check pod with the specified user ID (int)")
csiCheckCmd.Flags().BoolVarP(&csiCheckSkipCFSCheck, "skipCFScheck", "k", false, "Use this flag to skip validating the ability to clone a snapshot.")

rootCmd.AddCommand(pvcBrowseCmd)
pvcBrowseCmd.Flags().StringVarP(&csiCheckVolumeSnapshotClass, "volumesnapshotclass", "v", "", "The name of a VolumeSnapshotClass. (Required)")
_ = pvcBrowseCmd.MarkFlagRequired("volumesnapshotclass")
pvcBrowseCmd.Flags().StringVarP(&namespace, "namespace", "n", fio.DefaultNS, "The namespace of the PersistentVolumeClaim.")
pvcBrowseCmd.Flags().Int64VarP(&csiCheckRunAsUser, "runAsUser", "u", 0, "Runs the inspector pod as a user (int)")
pvcBrowseCmd.Flags().IntVarP(&pvcBrowseLocalPort, "localport", "l", 8080, "The local port to expose the inspector")
rootCmd.AddCommand(browseCmd)
browseCmd.Flags().StringVarP(&csiCheckVolumeSnapshotClass, "volumesnapshotclass", "v", "", "The name of a VolumeSnapshotClass. (Required)")
_ = browseCmd.MarkFlagRequired("volumesnapshotclass")
browseCmd.Flags().StringVarP(&namespace, "namespace", "n", fio.DefaultNS, "The namespace of the PersistentVolumeClaim.")
browseCmd.Flags().Int64VarP(&csiCheckRunAsUser, "runAsUser", "u", 0, "Runs the inspector pod as a user (int)")
browseCmd.Flags().IntVarP(&browseLocalPort, "localport", "l", 8080, "The local port to expose the inspector")

browseCmd.AddCommand(browsePvcCmd)
browsePvcCmd.Flags().StringVarP(&csiCheckVolumeSnapshotClass, "volumesnapshotclass", "v", "", "The name of a VolumeSnapshotClass. (Required)")
_ = browsePvcCmd.MarkFlagRequired("volumesnapshotclass")
browsePvcCmd.Flags().StringVarP(&namespace, "namespace", "n", fio.DefaultNS, "The namespace of the PersistentVolumeClaim.")
browsePvcCmd.Flags().Int64VarP(&csiCheckRunAsUser, "runAsUser", "u", 0, "Runs the inspector pod as a user (int)")
browsePvcCmd.Flags().IntVarP(&browseLocalPort, "localport", "l", 8080, "The local port to expose the inspector")

browseCmd.AddCommand(browseSnapshotCmd)
browseSnapshotCmd.Flags().StringVarP(&storageClass, "storageclass", "s", "", "The name of a StorageClass. (Required)")
shlokc9 marked this conversation as resolved.
Show resolved Hide resolved
_ = browseSnapshotCmd.MarkFlagRequired("storageclass")
shlokc9 marked this conversation as resolved.
Show resolved Hide resolved
browseSnapshotCmd.Flags().StringVarP(&namespace, "namespace", "n", fio.DefaultNS, "The namespace of the VolumeSnapshot.")
browseSnapshotCmd.Flags().Int64VarP(&csiCheckRunAsUser, "runAsUser", "u", 0, "Runs the inspector pod as a user (int)")
browseSnapshotCmd.Flags().IntVarP(&browseLocalPort, "localport", "l", 8080, "The local port to expose the inspector")
shlokc9 marked this conversation as resolved.
Show resolved Hide resolved

rootCmd.AddCommand(blockMountCmd)
blockMountCmd.Flags().StringVarP(&storageClass, "storageclass", "s", "", "The name of a Storageclass. (Required)")
blockMountCmd.Flags().StringVarP(&storageClass, "storageclass", "s", "", "The name of a StorageClass. (Required)")
_ = blockMountCmd.MarkFlagRequired("storageclass")
blockMountCmd.Flags().StringVarP(&namespace, "namespace", "n", fio.DefaultNS, "The namespace used to run the check.")
blockMountCmd.Flags().StringVarP(&containerImage, "image", "i", "", "The container image used to create a pod.")
Expand Down Expand Up @@ -358,6 +398,40 @@ func CsiPvcBrowse(ctx context.Context,
return err
}

func CsiSnapshotBrowse(ctx context.Context,
snapshotName string,
namespace string,
storageClass string,
runAsUser int64,
localPort int,
) error {
kubecli, err := kubestr.LoadKubeCli()
if err != nil {
fmt.Printf("Failed to load kubeCli (%s)", err.Error())
return err
}
dyncli, err := kubestr.LoadDynCli()
if err != nil {
fmt.Printf("Failed to load dynCli (%s)", err.Error())
return err
}
browseRunner := &csi.SnapshotBrowseRunner{
KubeCli: kubecli,
DynCli: dyncli,
}
err = browseRunner.RunSnapshotBrowse(ctx, &csitypes.SnapshotBrowseArgs{
SnapshotName: snapshotName,
Namespace: namespace,
StorageClassName: storageClass,
RunAsUser: runAsUser,
LocalPort: localPort,
})
if err != nil {
fmt.Printf("Failed to run Snapshot browser (%s)\n", err.Error())
}
return err
}

func BlockMountCheck(ctx context.Context, output, outfile string, cleanupOnly bool, checkerArgs block.BlockMountCheckerArgs) error {
kubecli, err := kubestr.LoadKubeCli()
if err != nil {
Expand Down
49 changes: 49 additions & 0 deletions pkg/csi/csi_ops.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ package csi
import (
"context"
"fmt"
"k8s.io/apimachinery/pkg/runtime"
"log"
"net/http"
"net/url"
"strings"
Expand Down Expand Up @@ -44,6 +46,7 @@ type ArgumentValidator interface {
//Rename
ValidatePVC(ctx context.Context, pvcName, namespace string) (*v1.PersistentVolumeClaim, error)
FetchPV(ctx context.Context, pvName string) (*v1.PersistentVolume, error)
ValidateVolumeSnapshot(ctx context.Context, snapshotName, namespace string, groupVersion *metav1.GroupVersionForDiscovery) (*snapv1.VolumeSnapshot, error)
ValidateNamespace(ctx context.Context, namespace string) error
ValidateStorageClass(ctx context.Context, storageClass string) (*sv1.StorageClass, error)
ValidateVolumeSnapshotClass(ctx context.Context, volumeSnapshotClass string, groupVersion *metav1.GroupVersionForDiscovery) (*unstructured.Unstructured, error)
Expand All @@ -68,6 +71,17 @@ func (o *validateOperations) ValidatePVC(ctx context.Context, pvcName, namespace
return o.kubeCli.CoreV1().PersistentVolumeClaims(namespace).Get(ctx, pvcName, metav1.GetOptions{})
}

func (o *validateOperations) ValidateVolumeSnapshot(ctx context.Context, snapshotName, namespace string, groupVersion *metav1.GroupVersionForDiscovery) (*snapv1.VolumeSnapshot, error) {
VolSnapGVR := schema.GroupVersionResource{Group: snapv1.GroupName, Version: groupVersion.Version, Resource: common.VolumeSnapshotResourcePlural}
uVS, err := o.dynCli.Resource(VolSnapGVR).Namespace(namespace).Get(ctx, snapshotName, metav1.GetOptions{})
if err != nil {
log.Fatalf("Failed to get VolumeSnapshot: %v", err)
}
volumeSnapshot := &snapv1.VolumeSnapshot{}
err = runtime.DefaultUnstructuredConverter.FromUnstructured(uVS.UnstructuredContent(), volumeSnapshot)
return volumeSnapshot, err
}

func (o *validateOperations) FetchPV(ctx context.Context, pvName string) (*v1.PersistentVolume, error) {
if o.kubeCli == nil {
return nil, fmt.Errorf("kubeCli not initialized")
Expand Down Expand Up @@ -317,6 +331,41 @@ func (c *applicationCreate) getErrorFromEvents(ctx context.Context, namespace, n
return nil
}

//go:generate go run github.com/golang/mock/mockgen -destination=mocks/mock_snapshot_fetcher.go -package=mocks . SnapshotFetcher
type SnapshotFetcher interface {
NewSnapshotter() (kansnapshot.Snapshotter, error)
GetVolumeSnapshot(ctx context.Context, snapshotter kansnapshot.Snapshotter, args *types.FetchSnapshotArgs) (*snapv1.VolumeSnapshot, error)
}

type snapshotFetch struct {
kubeCli kubernetes.Interface
dynCli dynamic.Interface
}

func (f *snapshotFetch) NewSnapshotter() (kansnapshot.Snapshotter, error) {
if f.kubeCli == nil {
return nil, fmt.Errorf("kubeCli not initialized")
}
if f.dynCli == nil {
return nil, fmt.Errorf("dynCli not initialized")
}
return kansnapshot.NewSnapshotter(f.kubeCli, f.dynCli)
}

func (f *snapshotFetch) GetVolumeSnapshot(ctx context.Context, snapshotter kansnapshot.Snapshotter, args *types.FetchSnapshotArgs) (*snapv1.VolumeSnapshot, error) {
if snapshotter == nil || args == nil {
return nil, fmt.Errorf("snapshotter or args are empty")
}
if err := args.Validate(); err != nil {
return nil, err
}
snap, err := snapshotter.Get(ctx, args.SnapshotName, args.Namespace)
if err != nil {
return nil, errors.Wrapf(err, "Failed to get CSI snapshot (%s) in Namespace (%s)", args.SnapshotName, args.Namespace)
}
return snap, nil
}

//go:generate go run github.com/golang/mock/mockgen -destination=mocks/mock_snapshot_creator.go -package=mocks . SnapshotCreator
type SnapshotCreator interface {
NewSnapshotter() (kansnapshot.Snapshotter, error)
Expand Down
36 changes: 26 additions & 10 deletions pkg/csi/mocks/mock_argument_validator.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

111 changes: 111 additions & 0 deletions pkg/csi/mocks/mock_snapshot_browser_stepper.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading