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 16 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
52 changes: 50 additions & 2 deletions cmd/rootCmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,20 @@ var (
},
}

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,
csiCheckRunAsUser,
browseLocalPort,
)
},
}

blockMountRunAsUser int64
blockMountCleanup bool
blockMountCleanupOnly bool
Expand Down Expand Up @@ -178,16 +192,18 @@ func init() {
rootCmd.AddCommand(browseCmd)
browseCmd.Flags().StringVarP(&csiCheckVolumeSnapshotClass, "volumesnapshotclass", "v", "", "The name of a VolumeSnapshotClass. (Required)")
_ = browseCmd.MarkFlagRequired("volumesnapshotclass")
browseCmd.PersistentFlags().StringVarP(&namespace, "namespace", "n", fio.DefaultNS, "The namespace of the PersistentVolumeClaim.")
browseCmd.PersistentFlags().StringVarP(&namespace, "namespace", "n", fio.DefaultNS, "The namespace of the above resource.")
shlokc9 marked this conversation as resolved.
Show resolved Hide resolved
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.AddCommand(browsePvcCmd)
browsePvcCmd.Flags().StringVarP(&csiCheckVolumeSnapshotClass, "volumesnapshotclass", "v", "", "The name of a VolumeSnapshotClass. (Required)")
_ = browsePvcCmd.MarkFlagRequired("volumesnapshotclass")

browseCmd.AddCommand(browseSnapshotCmd)

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 @@ -373,6 +389,38 @@ func CsiPvcBrowse(ctx context.Context,
return err
}

func CsiSnapshotBrowse(ctx context.Context,
snapshotName string,
namespace 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,
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.

97 changes: 97 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