mirror of
https://github.com/kastenhq/kubestr.git
synced 2024-12-14 11:57:56 +00:00
Adding "./kubestr file-restore" command (#287)
* 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](4fa2a79536...2d790406f5
) --- 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] <support@github.com> 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](1a162644f9...1ca370b3a9
) --- 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] <support@github.com> 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 * 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 * Adding "./kubestr browse snapshot" command (#277) * 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](4fa2a79536...2d790406f5
) --- 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] <support@github.com> 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](1a162644f9...1ca370b3a9
) --- 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] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Removing unused snapshot function parameter in cleanup * Adding mock tests for SnapshotBrowserStepper * Adding Deprecated msg to the 'browse' command * Adding fake tests for snapshot_inspector.go * Renamed testcase CSITestSuite.TestCreateInspectorApplication to TestCreateInspectorApplicationForPVC * Adding snapshot_inspector_steps_test.go * 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 * Removing storage class flag * Update cmd/rootCmd.go Co-authored-by: Sirish Bathina <sirish@kasten.io> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Sirish Bathina <sirish@kasten.io> * 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](4fa2a79536...2d790406f5
) --- 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] <support@github.com> 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](1a162644f9...1ca370b3a9
) --- 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] <support@github.com> 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] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Removing dummy ShowTree arg test * 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](4fa2a79536...2d790406f5
) --- 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] <support@github.com> 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](1a162644f9...1ca370b3a9
) --- 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] <support@github.com> 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] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump the github-actions group across 1 directory with 2 updates (#282) Bumps the github-actions group with 2 updates in the / directory: [github/codeql-action](https://github.com/github/codeql-action) and [actions/upload-artifact](https://github.com/actions/upload-artifact). Updates `github/codeql-action` from 3.25.13 to 3.25.15 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](2d790406f5...afb54ba388
) Updates `actions/upload-artifact` from 4.3.4 to 4.3.5 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](0b2256b8c0...89ef406dd8
) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump the docker group across 1 directory with 4 updates (#283) Bumps the docker group with 4 updates in the / directory: [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action), [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action), [docker/login-action](https://github.com/docker/login-action) and [docker/build-push-action](https://github.com/docker/build-push-action). Updates `docker/setup-qemu-action` from 3.1.0 to 3.2.0 - [Release notes](https://github.com/docker/setup-qemu-action/releases) - [Commits](5927c834f5...49b3bc8e6b
) Updates `docker/setup-buildx-action` from 3.4.0 to 3.6.1 - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](4fd812986e...988b5a0280
) Updates `docker/login-action` from 3.2.0 to 3.3.0 - [Release notes](https://github.com/docker/login-action/releases) - [Commits](0d4c9c5ea7...9780b0c442
) Updates `docker/build-push-action` from 6.4.1 to 6.5.0 - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](1ca370b3a9...5176d81f87
) --- updated-dependencies: - dependency-name: docker/setup-qemu-action dependency-type: direct:production update-type: version-update:semver-minor dependency-group: docker - dependency-name: docker/setup-buildx-action dependency-type: direct:production update-type: version-update:semver-minor dependency-group: docker - dependency-name: docker/login-action dependency-type: direct:production update-type: version-update:semver-minor dependency-group: docker - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-minor dependency-group: docker ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump ossf/scorecard-action from 2.3.3 to 2.4.0 (#281) Bumps [ossf/scorecard-action](https://github.com/ossf/scorecard-action) from 2.3.3 to 2.4.0. - [Release notes](https://github.com/ossf/scorecard-action/releases) - [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md) - [Commits](dc50aa9510...62b2cac7ed
) --- updated-dependencies: - dependency-name: ossf/scorecard-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * K10-23320: Fix function definition for Create and CreateFromSource (#274) * fix function definition for Create and CreateFromSource * update go mod * update go mod * update fakesnapshotter * update create and createFromSource method * change snapshot and content meta struct type * sync kanister dependency * Renamed struct * Sync kanister dependency * Sync kanister dependency * Sync kanister dependency * Sync kanister dependency to merge master commit * Updating CreatePodArgs to consume PVC args in []string{} format instead of string (#285) * Updating the PVCName, MountPath, DevicePath signature in CreatePodArgs * Refactoring PVCName, MountPath, DevicePath variables into a single PVCMap with path definitions * Removing unused PVCName variable from CreatePodArgs * Updating DevicePath and MountPath error messages * Removing placeholder test for browse snapshot and browse pvc * Removing unused snapshotFetchOps from snapshotBrowserSteps * Adding File restore command * Adding mock objects and fake tests for file restore command * Renaming file_restore_inspector.go * Removing unused SnapshotFetcher interface * Adding check for source PVC in Snapshot and supported accessModes in source PVC * Adding --toPVC flag * Fixing seg fault occurred because of the invalid error thrown in accessmodes check * Removing check for ReadWriteOnce accessmode * Update cmd/rootCmd.go Co-authored-by: Sirish Bathina <sirish@kasten.io> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Sirish Bathina <sirish@kasten.io> Co-authored-by: saima sultana <sultanasaima506@gmail.com>
This commit is contained in:
parent
474d444699
commit
0d37899f0f
9 changed files with 1279 additions and 112 deletions
|
@ -128,6 +128,25 @@ var (
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fromSnapshot string
|
||||||
|
toPVC string
|
||||||
|
path string
|
||||||
|
restoreFileCmd = &cobra.Command{
|
||||||
|
Use: "file-restore",
|
||||||
|
Short: "Restore file(s) from a VolumeSnapshot to it's source PVC",
|
||||||
|
Long: "Restore file(s) from a given CSI provisioned VolumeSnapshot to a PVC.",
|
||||||
|
Args: cobra.ExactArgs(0),
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
return FileRestore(context.Background(),
|
||||||
|
fromSnapshot,
|
||||||
|
toPVC,
|
||||||
|
namespace,
|
||||||
|
csiCheckRunAsUser,
|
||||||
|
browseLocalPort,
|
||||||
|
path)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
blockMountRunAsUser int64
|
blockMountRunAsUser int64
|
||||||
blockMountCleanup bool
|
blockMountCleanup bool
|
||||||
blockMountCleanupOnly bool
|
blockMountCleanupOnly bool
|
||||||
|
@ -207,6 +226,15 @@ func init() {
|
||||||
|
|
||||||
browseCmd.AddCommand(browseSnapshotCmd)
|
browseCmd.AddCommand(browseSnapshotCmd)
|
||||||
|
|
||||||
|
rootCmd.AddCommand(restoreFileCmd)
|
||||||
|
restoreFileCmd.Flags().StringVarP(&fromSnapshot, "fromSnapshot", "f", "", "The name of a VolumeSnapshot. (Required)")
|
||||||
|
_ = restoreFileCmd.MarkFlagRequired("fromSnapshot")
|
||||||
|
restoreFileCmd.Flags().StringVarP(&toPVC, "toPVC", "t", "", "The name of a PersistentVolumeClaim.")
|
||||||
|
restoreFileCmd.Flags().StringVarP(&namespace, "namespace", "n", fio.DefaultNS, "The namespace of both the given PVC & VS.")
|
||||||
|
restoreFileCmd.Flags().Int64VarP(&csiCheckRunAsUser, "runAsUser", "u", 0, "Runs the inspector pod as a user (int)")
|
||||||
|
restoreFileCmd.Flags().IntVarP(&browseLocalPort, "localport", "l", 8080, "The local port to expose the inspector")
|
||||||
|
restoreFileCmd.Flags().StringVarP(&path, "path", "p", "", "Path of a file or directory that needs to be restored")
|
||||||
|
|
||||||
rootCmd.AddCommand(blockMountCmd)
|
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.MarkFlagRequired("storageclass")
|
||||||
|
@ -430,6 +458,42 @@ func CsiSnapshotBrowse(ctx context.Context,
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FileRestore(ctx context.Context,
|
||||||
|
snapshotName string,
|
||||||
|
pvcName string,
|
||||||
|
namespace string,
|
||||||
|
runAsUser int64,
|
||||||
|
localPort int,
|
||||||
|
path string,
|
||||||
|
) 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
|
||||||
|
}
|
||||||
|
fileRestoreRunner := &csi.FileRestoreRunner{
|
||||||
|
KubeCli: kubecli,
|
||||||
|
DynCli: dyncli,
|
||||||
|
}
|
||||||
|
err = fileRestoreRunner.RunFileRestore(ctx, &csitypes.FileRestoreArgs{
|
||||||
|
SnapshotName: snapshotName,
|
||||||
|
PVCName: pvcName,
|
||||||
|
Namespace: namespace,
|
||||||
|
RunAsUser: runAsUser,
|
||||||
|
LocalPort: localPort,
|
||||||
|
Path: path,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to run file-restore (%s)\n", err.Error())
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func BlockMountCheck(ctx context.Context, output, outfile string, cleanupOnly bool, checkerArgs block.BlockMountCheckerArgs) error {
|
func BlockMountCheck(ctx context.Context, output, outfile string, cleanupOnly bool, checkerArgs block.BlockMountCheckerArgs) error {
|
||||||
kubecli, err := kubestr.LoadKubeCli()
|
kubecli, err := kubestr.LoadKubeCli()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -332,41 +332,6 @@ func (c *applicationCreate) getErrorFromEvents(ctx context.Context, namespace, n
|
||||||
return nil
|
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
|
//go:generate go run github.com/golang/mock/mockgen -destination=mocks/mock_snapshot_creator.go -package=mocks . SnapshotCreator
|
||||||
type SnapshotCreator interface {
|
type SnapshotCreator interface {
|
||||||
NewSnapshotter() (kansnapshot.Snapshotter, error)
|
NewSnapshotter() (kansnapshot.Snapshotter, error)
|
||||||
|
|
300
pkg/csi/file_restore_inspector.go
Normal file
300
pkg/csi/file_restore_inspector.go
Normal file
|
@ -0,0 +1,300 @@
|
||||||
|
package csi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/kastenhq/kubestr/pkg/csi/types"
|
||||||
|
snapv1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
sv1 "k8s.io/api/storage/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/client-go/dynamic"
|
||||||
|
"k8s.io/client-go/kubernetes"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FileRestoreRunner struct {
|
||||||
|
KubeCli kubernetes.Interface
|
||||||
|
DynCli dynamic.Interface
|
||||||
|
restoreSteps FileRestoreStepper
|
||||||
|
restorePVC *v1.PersistentVolumeClaim
|
||||||
|
pod *v1.Pod
|
||||||
|
snapshot *snapv1.VolumeSnapshot
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileRestoreRunner) RunFileRestore(ctx context.Context, args *types.FileRestoreArgs) error {
|
||||||
|
f.restoreSteps = &fileRestoreSteps{
|
||||||
|
validateOps: &validateOperations{
|
||||||
|
kubeCli: f.KubeCli,
|
||||||
|
dynCli: f.DynCli,
|
||||||
|
},
|
||||||
|
versionFetchOps: &apiVersionFetch{
|
||||||
|
kubeCli: f.KubeCli,
|
||||||
|
},
|
||||||
|
createAppOps: &applicationCreate{
|
||||||
|
kubeCli: f.KubeCli,
|
||||||
|
},
|
||||||
|
portForwardOps: &portforward{},
|
||||||
|
kubeExecutor: &kubeExec{
|
||||||
|
kubeCli: f.KubeCli,
|
||||||
|
},
|
||||||
|
cleanerOps: &cleanse{
|
||||||
|
kubeCli: f.KubeCli,
|
||||||
|
dynCli: f.DynCli,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return f.RunFileRestoreHelper(ctx, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileRestoreRunner) RunFileRestoreHelper(ctx context.Context, args *types.FileRestoreArgs) error {
|
||||||
|
defer func() {
|
||||||
|
fmt.Println("Cleaning up browser pod & restored PVC.")
|
||||||
|
f.restoreSteps.Cleanup(ctx, f.restorePVC, f.pod)
|
||||||
|
}()
|
||||||
|
|
||||||
|
if f.KubeCli == nil || f.DynCli == nil {
|
||||||
|
return fmt.Errorf("cli uninitialized")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Fetching the snapshot.")
|
||||||
|
vs, sourcePVC, sc, err := f.restoreSteps.ValidateArgs(ctx, args)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Failed to validate arguments.")
|
||||||
|
}
|
||||||
|
f.snapshot = vs
|
||||||
|
|
||||||
|
fmt.Println("Creating the restored PVC & browser Pod.")
|
||||||
|
f.pod, f.restorePVC, err = f.restoreSteps.CreateInspectorApplication(ctx, args, f.snapshot, sourcePVC, sc)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Failed to create inspector application.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if args.Path != "" {
|
||||||
|
fmt.Printf("Restoring the file %s\n", args.Path)
|
||||||
|
_, err := f.restoreSteps.ExecuteCopyCommand(ctx, args, f.pod)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Failed to execute cp command in pod.")
|
||||||
|
}
|
||||||
|
fmt.Printf("File restored from VolumeSnapshot %s to Source PVC %s.\n", f.snapshot.Name, sourcePVC.Name)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Forwarding the port.")
|
||||||
|
err = f.restoreSteps.PortForwardAPod(f.pod, args.LocalPort)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Failed to port forward Pod.")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:generate go run github.com/golang/mock/mockgen -destination=mocks/mock_file_restore_stepper.go -package=mocks . FileRestoreStepper
|
||||||
|
type FileRestoreStepper interface {
|
||||||
|
ValidateArgs(ctx context.Context, args *types.FileRestoreArgs) (*snapv1.VolumeSnapshot, *v1.PersistentVolumeClaim, *sv1.StorageClass, error)
|
||||||
|
CreateInspectorApplication(ctx context.Context, args *types.FileRestoreArgs, snapshot *snapv1.VolumeSnapshot, sourcePVC *v1.PersistentVolumeClaim, storageClass *sv1.StorageClass) (*v1.Pod, *v1.PersistentVolumeClaim, error)
|
||||||
|
ExecuteCopyCommand(ctx context.Context, args *types.FileRestoreArgs, pod *v1.Pod) (string, error)
|
||||||
|
PortForwardAPod(pod *v1.Pod, localPort int) error
|
||||||
|
Cleanup(ctx context.Context, restorePVC *v1.PersistentVolumeClaim, pod *v1.Pod)
|
||||||
|
}
|
||||||
|
|
||||||
|
type fileRestoreSteps struct {
|
||||||
|
validateOps ArgumentValidator
|
||||||
|
versionFetchOps ApiVersionFetcher
|
||||||
|
createAppOps ApplicationCreator
|
||||||
|
portForwardOps PortForwarder
|
||||||
|
cleanerOps Cleaner
|
||||||
|
kubeExecutor KubeExecutor
|
||||||
|
SnapshotGroupVersion *metav1.GroupVersionForDiscovery
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fileRestoreSteps) ValidateArgs(ctx context.Context, args *types.FileRestoreArgs) (*snapv1.VolumeSnapshot, *v1.PersistentVolumeClaim, *sv1.StorageClass, error) {
|
||||||
|
if err := args.Validate(); err != nil {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "Failed to validate input arguments")
|
||||||
|
}
|
||||||
|
if err := f.validateOps.ValidateNamespace(ctx, args.Namespace); err != nil {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "Failed to validate Namespace")
|
||||||
|
}
|
||||||
|
groupVersion, err := f.versionFetchOps.GetCSISnapshotGroupVersion()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "Failed to fetch groupVersion")
|
||||||
|
}
|
||||||
|
f.SnapshotGroupVersion = groupVersion
|
||||||
|
snapshot, err := f.validateOps.ValidateVolumeSnapshot(ctx, args.SnapshotName, args.Namespace, groupVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "Failed to validate VolumeSnapshot")
|
||||||
|
}
|
||||||
|
var sourcePVC *v1.PersistentVolumeClaim
|
||||||
|
if args.PVCName == "" {
|
||||||
|
fmt.Println("Fetching the source PVC from snapshot.")
|
||||||
|
if *snapshot.Spec.Source.PersistentVolumeClaimName == "" {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "Failed to fetch source PVC. VolumeSnapshot does not have a PVC as it's source")
|
||||||
|
}
|
||||||
|
sourcePVC, err = f.validateOps.ValidatePVC(ctx, *snapshot.Spec.Source.PersistentVolumeClaimName, args.Namespace)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "Failed to validate source PVC")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println("Fetching the source PVC.")
|
||||||
|
sourcePVC, err = f.validateOps.ValidatePVC(ctx, args.PVCName, args.Namespace)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "Failed to validate source PVC")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, sourceAccessMode := range sourcePVC.Spec.AccessModes {
|
||||||
|
if sourceAccessMode == v1.ReadWriteOncePod {
|
||||||
|
return nil, nil, nil, fmt.Errorf("Unsupported %s AccessMode found in source PVC. Supported AccessModes are ReadOnlyMany & ReadWriteMany", sourceAccessMode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sc, err := f.validateOps.ValidateStorageClass(ctx, *sourcePVC.Spec.StorageClassName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "Failed to validate StorageClass")
|
||||||
|
}
|
||||||
|
uVSC, err := f.validateOps.ValidateVolumeSnapshotClass(ctx, *snapshot.Spec.VolumeSnapshotClassName, groupVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "Failed to validate VolumeSnapshotClass")
|
||||||
|
}
|
||||||
|
vscDriver := getDriverNameFromUVSC(*uVSC, groupVersion.GroupVersion)
|
||||||
|
if sc.Provisioner != vscDriver {
|
||||||
|
return nil, nil, nil, fmt.Errorf("StorageClass provisioner (%s) and VolumeSnapshotClass driver (%s) are different.", sc.Provisioner, vscDriver)
|
||||||
|
}
|
||||||
|
return snapshot, sourcePVC, sc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fileRestoreSteps) CreateInspectorApplication(ctx context.Context, args *types.FileRestoreArgs, snapshot *snapv1.VolumeSnapshot, sourcePVC *v1.PersistentVolumeClaim, storageClass *sv1.StorageClass) (*v1.Pod, *v1.PersistentVolumeClaim, error) {
|
||||||
|
snapshotAPIGroup := "snapshot.storage.k8s.io"
|
||||||
|
snapshotKind := "VolumeSnapshot"
|
||||||
|
dataSource := &v1.TypedLocalObjectReference{
|
||||||
|
APIGroup: &snapshotAPIGroup,
|
||||||
|
Kind: snapshotKind,
|
||||||
|
Name: snapshot.Name,
|
||||||
|
}
|
||||||
|
pvcArgs := &types.CreatePVCArgs{
|
||||||
|
GenerateName: clonedPVCGenerateName,
|
||||||
|
StorageClass: storageClass.Name,
|
||||||
|
Namespace: args.Namespace,
|
||||||
|
DataSource: dataSource,
|
||||||
|
RestoreSize: snapshot.Status.RestoreSize,
|
||||||
|
}
|
||||||
|
restorePVC, err := f.createAppOps.CreatePVC(ctx, pvcArgs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errors.Wrap(err, "Failed to restore PVC")
|
||||||
|
}
|
||||||
|
podArgs := &types.CreatePodArgs{
|
||||||
|
GenerateName: clonedPodGenerateName,
|
||||||
|
Namespace: args.Namespace,
|
||||||
|
RunAsUser: args.RunAsUser,
|
||||||
|
ContainerImage: "filebrowser/filebrowser:v2",
|
||||||
|
ContainerArgs: []string{"--noauth"},
|
||||||
|
PVCMap: map[string]types.VolumePath{
|
||||||
|
restorePVC.Name: {
|
||||||
|
MountPath: "/srv/snapshot-data",
|
||||||
|
},
|
||||||
|
sourcePVC.Name: {
|
||||||
|
MountPath: "/srv/source-data",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if args.Path != "" {
|
||||||
|
podArgs = &types.CreatePodArgs{
|
||||||
|
GenerateName: clonedPodGenerateName,
|
||||||
|
Namespace: args.Namespace,
|
||||||
|
RunAsUser: args.RunAsUser,
|
||||||
|
ContainerImage: "alpine:3.19",
|
||||||
|
Command: []string{"/bin/sh"},
|
||||||
|
ContainerArgs: []string{"-c", "while true; do sleep 3600; done"},
|
||||||
|
PVCMap: map[string]types.VolumePath{
|
||||||
|
restorePVC.Name: {
|
||||||
|
MountPath: "/snapshot-data",
|
||||||
|
},
|
||||||
|
sourcePVC.Name: {
|
||||||
|
MountPath: "/source-data",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pod, err := f.createAppOps.CreatePod(ctx, podArgs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, restorePVC, errors.Wrap(err, "Failed to create browse Pod")
|
||||||
|
}
|
||||||
|
if err = f.createAppOps.WaitForPodReady(ctx, args.Namespace, pod.Name); err != nil {
|
||||||
|
return pod, restorePVC, errors.Wrap(err, "Pod failed to become ready")
|
||||||
|
}
|
||||||
|
return pod, restorePVC, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fileRestoreSteps) ExecuteCopyCommand(ctx context.Context, args *types.FileRestoreArgs, pod *v1.Pod) (string, error) {
|
||||||
|
command := []string{"cp", "-rf", fmt.Sprintf("/snapshot-data%s", args.Path), fmt.Sprintf("/source-data%s", args.Path)}
|
||||||
|
stdout, err := f.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 (f *fileRestoreSteps) PortForwardAPod(pod *v1.Pod, localPort int) error {
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(1)
|
||||||
|
stopChan, readyChan, errChan := make(chan struct{}, 1), make(chan struct{}, 1), make(chan string)
|
||||||
|
out, errOut := new(bytes.Buffer), new(bytes.Buffer)
|
||||||
|
cfg, err := f.portForwardOps.FetchRestConfig()
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("Failed to fetch rest config")
|
||||||
|
}
|
||||||
|
sigs := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
go func() {
|
||||||
|
<-sigs
|
||||||
|
fmt.Println("\nStopping port forward.")
|
||||||
|
close(stopChan)
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
pfArgs := &types.PortForwardAPodRequest{
|
||||||
|
RestConfig: cfg,
|
||||||
|
Pod: pod,
|
||||||
|
LocalPort: localPort,
|
||||||
|
PodPort: 80,
|
||||||
|
OutStream: bytes.Buffer(*out),
|
||||||
|
ErrOutStream: bytes.Buffer(*errOut),
|
||||||
|
StopCh: stopChan,
|
||||||
|
ReadyCh: readyChan,
|
||||||
|
}
|
||||||
|
err = f.portForwardOps.PortForwardAPod(pfArgs)
|
||||||
|
if err != nil {
|
||||||
|
errChan <- fmt.Sprintf("Failed to port forward (%s)", err.Error())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-readyChan:
|
||||||
|
url := fmt.Sprintf("http://localhost:%d/", localPort)
|
||||||
|
fmt.Printf("Port forwarding is ready to get traffic. visit %s\n", url)
|
||||||
|
openbrowser(url)
|
||||||
|
wg.Wait()
|
||||||
|
case msg := <-errChan:
|
||||||
|
return errors.New(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fileRestoreSteps) Cleanup(ctx context.Context, restorePVC *v1.PersistentVolumeClaim, pod *v1.Pod) {
|
||||||
|
if restorePVC != nil {
|
||||||
|
err := f.cleanerOps.DeletePVC(ctx, restorePVC.Name, restorePVC.Namespace)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Failed to delete restore PVC", restorePVC)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if pod != nil {
|
||||||
|
err := f.cleanerOps.DeletePod(ctx, pod.Name, pod.Namespace)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Failed to delete Pod", pod)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
594
pkg/csi/file_restore_inspector_steps_test.go
Normal file
594
pkg/csi/file_restore_inspector_steps_test.go
Normal file
|
@ -0,0 +1,594 @@
|
||||||
|
package csi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
|
"github.com/kastenhq/kubestr/pkg/common"
|
||||||
|
"github.com/kastenhq/kubestr/pkg/csi/mocks"
|
||||||
|
"github.com/kastenhq/kubestr/pkg/csi/types"
|
||||||
|
snapv1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
||||||
|
. "gopkg.in/check.v1"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
sv1 "k8s.io/api/storage/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *CSITestSuite) TestFileRestoreValidateArgs(c *C) {
|
||||||
|
ctx := context.Background()
|
||||||
|
scName := "sc"
|
||||||
|
vscName := "vsc"
|
||||||
|
pvcName := "pvc"
|
||||||
|
type fields struct {
|
||||||
|
validateOps *mocks.MockArgumentValidator
|
||||||
|
versionOps *mocks.MockApiVersionFetcher
|
||||||
|
}
|
||||||
|
for _, tc := range []struct {
|
||||||
|
args *types.FileRestoreArgs
|
||||||
|
prepare func(f *fields)
|
||||||
|
errChecker Checker
|
||||||
|
}{
|
||||||
|
{ // valid args
|
||||||
|
args: &types.FileRestoreArgs{
|
||||||
|
SnapshotName: "vs",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
prepare: func(f *fields) {
|
||||||
|
gomock.InOrder(
|
||||||
|
f.validateOps.EXPECT().ValidateNamespace(gomock.Any(), "ns").Return(nil),
|
||||||
|
f.versionOps.EXPECT().GetCSISnapshotGroupVersion().Return(
|
||||||
|
&metav1.GroupVersionForDiscovery{
|
||||||
|
GroupVersion: common.SnapshotAlphaVersion,
|
||||||
|
}, nil),
|
||||||
|
f.validateOps.EXPECT().ValidateVolumeSnapshot(gomock.Any(), "vs", "ns", gomock.Any()).Return(
|
||||||
|
&snapv1.VolumeSnapshot{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "vs",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
Spec: snapv1.VolumeSnapshotSpec{
|
||||||
|
Source: snapv1.VolumeSnapshotSource{
|
||||||
|
PersistentVolumeClaimName: &pvcName,
|
||||||
|
},
|
||||||
|
VolumeSnapshotClassName: &vscName,
|
||||||
|
},
|
||||||
|
}, nil,
|
||||||
|
),
|
||||||
|
f.validateOps.EXPECT().ValidatePVC(gomock.Any(), "pvc", "ns").Return(
|
||||||
|
&v1.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "pvc",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
Spec: v1.PersistentVolumeClaimSpec{
|
||||||
|
VolumeName: "vol",
|
||||||
|
StorageClassName: &scName,
|
||||||
|
},
|
||||||
|
}, nil,
|
||||||
|
),
|
||||||
|
f.validateOps.EXPECT().ValidateStorageClass(gomock.Any(), scName).Return(
|
||||||
|
&sv1.StorageClass{
|
||||||
|
Provisioner: "p1",
|
||||||
|
}, nil),
|
||||||
|
f.validateOps.EXPECT().ValidateVolumeSnapshotClass(gomock.Any(), "vsc", &metav1.GroupVersionForDiscovery{
|
||||||
|
GroupVersion: common.SnapshotAlphaVersion,
|
||||||
|
}).Return(&unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
common.VolSnapClassAlphaDriverKey: "p1",
|
||||||
|
},
|
||||||
|
}, nil),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
errChecker: IsNil,
|
||||||
|
},
|
||||||
|
{ // driver mismatch
|
||||||
|
args: &types.FileRestoreArgs{
|
||||||
|
SnapshotName: "vs",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
prepare: func(f *fields) {
|
||||||
|
gomock.InOrder(
|
||||||
|
f.validateOps.EXPECT().ValidateNamespace(gomock.Any(), "ns").Return(nil),
|
||||||
|
f.versionOps.EXPECT().GetCSISnapshotGroupVersion().Return(
|
||||||
|
&metav1.GroupVersionForDiscovery{
|
||||||
|
GroupVersion: common.SnapshotAlphaVersion,
|
||||||
|
}, nil),
|
||||||
|
f.validateOps.EXPECT().ValidateVolumeSnapshot(gomock.Any(), "vs", "ns", gomock.Any()).Return(
|
||||||
|
&snapv1.VolumeSnapshot{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "vs",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
Spec: snapv1.VolumeSnapshotSpec{
|
||||||
|
Source: snapv1.VolumeSnapshotSource{
|
||||||
|
PersistentVolumeClaimName: &pvcName,
|
||||||
|
},
|
||||||
|
VolumeSnapshotClassName: &vscName,
|
||||||
|
},
|
||||||
|
}, nil,
|
||||||
|
),
|
||||||
|
f.validateOps.EXPECT().ValidatePVC(gomock.Any(), "pvc", "ns").Return(
|
||||||
|
&v1.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "pvc",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
Spec: v1.PersistentVolumeClaimSpec{
|
||||||
|
VolumeName: "vol",
|
||||||
|
StorageClassName: &scName,
|
||||||
|
},
|
||||||
|
}, nil,
|
||||||
|
),
|
||||||
|
f.validateOps.EXPECT().ValidateStorageClass(gomock.Any(), gomock.Any()).Return(
|
||||||
|
&sv1.StorageClass{
|
||||||
|
Provisioner: "p1",
|
||||||
|
}, nil),
|
||||||
|
f.validateOps.EXPECT().ValidateVolumeSnapshotClass(gomock.Any(), "vsc", &metav1.GroupVersionForDiscovery{
|
||||||
|
GroupVersion: common.SnapshotAlphaVersion,
|
||||||
|
}).Return(&unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
common.VolSnapClassAlphaDriverKey: "p2",
|
||||||
|
},
|
||||||
|
}, nil),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
errChecker: NotNil,
|
||||||
|
},
|
||||||
|
{ // vsc error
|
||||||
|
args: &types.FileRestoreArgs{
|
||||||
|
SnapshotName: "vs",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
prepare: func(f *fields) {
|
||||||
|
gomock.InOrder(
|
||||||
|
f.validateOps.EXPECT().ValidateNamespace(gomock.Any(), "ns").Return(nil),
|
||||||
|
f.versionOps.EXPECT().GetCSISnapshotGroupVersion().Return(nil, nil),
|
||||||
|
f.validateOps.EXPECT().ValidateVolumeSnapshot(gomock.Any(), "vs", "ns", gomock.Any()).Return(
|
||||||
|
&snapv1.VolumeSnapshot{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "vs",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
Spec: snapv1.VolumeSnapshotSpec{
|
||||||
|
Source: snapv1.VolumeSnapshotSource{
|
||||||
|
PersistentVolumeClaimName: &pvcName,
|
||||||
|
},
|
||||||
|
VolumeSnapshotClassName: &vscName,
|
||||||
|
},
|
||||||
|
}, nil,
|
||||||
|
),
|
||||||
|
f.validateOps.EXPECT().ValidatePVC(gomock.Any(), "pvc", "ns").Return(
|
||||||
|
&v1.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "pvc",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
Spec: v1.PersistentVolumeClaimSpec{
|
||||||
|
VolumeName: "vol",
|
||||||
|
StorageClassName: &scName,
|
||||||
|
},
|
||||||
|
}, nil,
|
||||||
|
),
|
||||||
|
f.validateOps.EXPECT().ValidateStorageClass(gomock.Any(), gomock.Any()).Return(nil, nil),
|
||||||
|
f.validateOps.EXPECT().ValidateVolumeSnapshotClass(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("vsc error")),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
errChecker: NotNil,
|
||||||
|
},
|
||||||
|
{ // get driver versionn error
|
||||||
|
args: &types.FileRestoreArgs{
|
||||||
|
SnapshotName: "vs",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
prepare: func(f *fields) {
|
||||||
|
gomock.InOrder(
|
||||||
|
f.validateOps.EXPECT().ValidateNamespace(gomock.Any(), "ns").Return(nil),
|
||||||
|
f.versionOps.EXPECT().GetCSISnapshotGroupVersion().Return(nil, fmt.Errorf("driver version error")),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
errChecker: NotNil,
|
||||||
|
},
|
||||||
|
{ // sc error
|
||||||
|
args: &types.FileRestoreArgs{
|
||||||
|
SnapshotName: "vs",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
prepare: func(f *fields) {
|
||||||
|
gomock.InOrder(
|
||||||
|
f.validateOps.EXPECT().ValidateNamespace(gomock.Any(), "ns").Return(nil),
|
||||||
|
f.versionOps.EXPECT().GetCSISnapshotGroupVersion().Return(nil, nil),
|
||||||
|
f.validateOps.EXPECT().ValidateVolumeSnapshot(gomock.Any(), "vs", "ns", gomock.Any()).Return(
|
||||||
|
&snapv1.VolumeSnapshot{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "vs",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
Spec: snapv1.VolumeSnapshotSpec{
|
||||||
|
Source: snapv1.VolumeSnapshotSource{
|
||||||
|
PersistentVolumeClaimName: &pvcName,
|
||||||
|
},
|
||||||
|
VolumeSnapshotClassName: &vscName,
|
||||||
|
},
|
||||||
|
}, nil,
|
||||||
|
),
|
||||||
|
f.validateOps.EXPECT().ValidatePVC(gomock.Any(), "pvc", "ns").Return(
|
||||||
|
&v1.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "pvc",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
Spec: v1.PersistentVolumeClaimSpec{
|
||||||
|
VolumeName: "vol",
|
||||||
|
StorageClassName: &scName,
|
||||||
|
},
|
||||||
|
}, nil,
|
||||||
|
),
|
||||||
|
f.validateOps.EXPECT().ValidateStorageClass(gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("sc error")),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
errChecker: NotNil,
|
||||||
|
},
|
||||||
|
{ // validate vs error
|
||||||
|
args: &types.FileRestoreArgs{
|
||||||
|
SnapshotName: "vs",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
prepare: func(f *fields) {
|
||||||
|
gomock.InOrder(
|
||||||
|
f.validateOps.EXPECT().ValidateNamespace(gomock.Any(), "ns").Return(nil),
|
||||||
|
f.versionOps.EXPECT().GetCSISnapshotGroupVersion().Return(nil, nil),
|
||||||
|
f.validateOps.EXPECT().ValidateVolumeSnapshot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("validate vs error")),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
errChecker: NotNil,
|
||||||
|
},
|
||||||
|
{ // validate ns error
|
||||||
|
args: &types.FileRestoreArgs{
|
||||||
|
SnapshotName: "vs",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
prepare: func(f *fields) {
|
||||||
|
gomock.InOrder(
|
||||||
|
f.validateOps.EXPECT().ValidateNamespace(gomock.Any(), "ns").Return(fmt.Errorf("validate ns error")),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
errChecker: NotNil,
|
||||||
|
},
|
||||||
|
{ // validate vs error
|
||||||
|
args: &types.FileRestoreArgs{
|
||||||
|
SnapshotName: "",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
errChecker: NotNil,
|
||||||
|
},
|
||||||
|
{ // validate ns error
|
||||||
|
args: &types.FileRestoreArgs{
|
||||||
|
SnapshotName: "dfd",
|
||||||
|
Namespace: "",
|
||||||
|
},
|
||||||
|
errChecker: NotNil,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
ctrl := gomock.NewController(c)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
f := fields{
|
||||||
|
validateOps: mocks.NewMockArgumentValidator(ctrl),
|
||||||
|
versionOps: mocks.NewMockApiVersionFetcher(ctrl),
|
||||||
|
}
|
||||||
|
if tc.prepare != nil {
|
||||||
|
tc.prepare(&f)
|
||||||
|
}
|
||||||
|
stepper := &fileRestoreSteps{
|
||||||
|
validateOps: f.validateOps,
|
||||||
|
versionFetchOps: f.versionOps,
|
||||||
|
}
|
||||||
|
_, _, _, err := stepper.ValidateArgs(ctx, tc.args)
|
||||||
|
c.Check(err, tc.errChecker)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *CSITestSuite) TestCreateInspectorApplicationForFileRestore(c *C) {
|
||||||
|
ctx := context.Background()
|
||||||
|
resourceQuantity := resource.MustParse("1Gi")
|
||||||
|
snapshotAPIGroup := "snapshot.storage.k8s.io"
|
||||||
|
type fields struct {
|
||||||
|
createAppOps *mocks.MockApplicationCreator
|
||||||
|
}
|
||||||
|
for _, tc := range []struct {
|
||||||
|
args *types.FileRestoreArgs
|
||||||
|
snapshot *snapv1.VolumeSnapshot
|
||||||
|
sc *sv1.StorageClass
|
||||||
|
prepare func(f *fields)
|
||||||
|
errChecker Checker
|
||||||
|
podChecker Checker
|
||||||
|
pvcChecker Checker
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
args: &types.FileRestoreArgs{
|
||||||
|
Namespace: "ns",
|
||||||
|
RunAsUser: 100,
|
||||||
|
},
|
||||||
|
sc: &sv1.StorageClass{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "sc",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
snapshot: &snapv1.VolumeSnapshot{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "vs",
|
||||||
|
},
|
||||||
|
Status: &snapv1.VolumeSnapshotStatus{
|
||||||
|
RestoreSize: &resourceQuantity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
prepare: func(f *fields) {
|
||||||
|
gomock.InOrder(
|
||||||
|
f.createAppOps.EXPECT().CreatePVC(gomock.Any(), &types.CreatePVCArgs{
|
||||||
|
GenerateName: clonedPVCGenerateName,
|
||||||
|
StorageClass: "sc",
|
||||||
|
Namespace: "ns",
|
||||||
|
DataSource: &v1.TypedLocalObjectReference{
|
||||||
|
APIGroup: &snapshotAPIGroup,
|
||||||
|
Kind: "VolumeSnapshot",
|
||||||
|
Name: "vs",
|
||||||
|
},
|
||||||
|
RestoreSize: &resourceQuantity,
|
||||||
|
}).Return(&v1.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "restorePVC",
|
||||||
|
},
|
||||||
|
}, nil),
|
||||||
|
f.createAppOps.EXPECT().CreatePod(gomock.Any(), &types.CreatePodArgs{
|
||||||
|
GenerateName: clonedPodGenerateName,
|
||||||
|
Namespace: "ns",
|
||||||
|
ContainerArgs: []string{"--noauth"},
|
||||||
|
RunAsUser: 100,
|
||||||
|
ContainerImage: "filebrowser/filebrowser:v2",
|
||||||
|
PVCMap: map[string]types.VolumePath{
|
||||||
|
"restorePVC": {
|
||||||
|
MountPath: "/srv/snapshot-data",
|
||||||
|
},
|
||||||
|
"sourcePVC": {
|
||||||
|
MountPath: "/srv/source-data",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}).Return(&v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "pod",
|
||||||
|
},
|
||||||
|
}, nil),
|
||||||
|
f.createAppOps.EXPECT().WaitForPodReady(gomock.Any(), "ns", "pod").Return(nil),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
errChecker: IsNil,
|
||||||
|
podChecker: NotNil,
|
||||||
|
pvcChecker: NotNil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: &types.FileRestoreArgs{
|
||||||
|
Namespace: "ns",
|
||||||
|
RunAsUser: 100,
|
||||||
|
},
|
||||||
|
sc: &sv1.StorageClass{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "sc",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
snapshot: &snapv1.VolumeSnapshot{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "vs",
|
||||||
|
},
|
||||||
|
Status: &snapv1.VolumeSnapshotStatus{
|
||||||
|
RestoreSize: &resourceQuantity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
prepare: func(f *fields) {
|
||||||
|
gomock.InOrder(
|
||||||
|
f.createAppOps.EXPECT().CreatePVC(gomock.Any(), &types.CreatePVCArgs{
|
||||||
|
GenerateName: clonedPVCGenerateName,
|
||||||
|
StorageClass: "sc",
|
||||||
|
Namespace: "ns",
|
||||||
|
DataSource: &v1.TypedLocalObjectReference{
|
||||||
|
APIGroup: &snapshotAPIGroup,
|
||||||
|
Kind: "VolumeSnapshot",
|
||||||
|
Name: "vs",
|
||||||
|
},
|
||||||
|
RestoreSize: &resourceQuantity,
|
||||||
|
}).Return(&v1.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "restorePVC",
|
||||||
|
},
|
||||||
|
}, nil),
|
||||||
|
f.createAppOps.EXPECT().CreatePod(gomock.Any(), &types.CreatePodArgs{
|
||||||
|
GenerateName: clonedPodGenerateName,
|
||||||
|
Namespace: "ns",
|
||||||
|
ContainerArgs: []string{"--noauth"},
|
||||||
|
RunAsUser: 100,
|
||||||
|
ContainerImage: "filebrowser/filebrowser:v2",
|
||||||
|
PVCMap: map[string]types.VolumePath{
|
||||||
|
"restorePVC": {
|
||||||
|
MountPath: "/srv/snapshot-data",
|
||||||
|
},
|
||||||
|
"sourcePVC": {
|
||||||
|
MountPath: "/srv/source-data",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}).Return(&v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "pod",
|
||||||
|
},
|
||||||
|
}, nil),
|
||||||
|
f.createAppOps.EXPECT().WaitForPodReady(gomock.Any(), "ns", "pod").Return(fmt.Errorf("pod ready error")),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
errChecker: NotNil,
|
||||||
|
podChecker: NotNil,
|
||||||
|
pvcChecker: NotNil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: &types.FileRestoreArgs{
|
||||||
|
Namespace: "ns",
|
||||||
|
RunAsUser: 100,
|
||||||
|
},
|
||||||
|
sc: &sv1.StorageClass{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "sc",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
snapshot: &snapv1.VolumeSnapshot{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "vs",
|
||||||
|
},
|
||||||
|
Status: &snapv1.VolumeSnapshotStatus{
|
||||||
|
RestoreSize: &resourceQuantity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
prepare: func(f *fields) {
|
||||||
|
gomock.InOrder(
|
||||||
|
f.createAppOps.EXPECT().CreatePVC(gomock.Any(), gomock.Any()).Return(&v1.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "restorePVC",
|
||||||
|
},
|
||||||
|
}, nil),
|
||||||
|
f.createAppOps.EXPECT().CreatePod(gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("pod error")),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
errChecker: NotNil,
|
||||||
|
podChecker: IsNil,
|
||||||
|
pvcChecker: NotNil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: &types.FileRestoreArgs{
|
||||||
|
Namespace: "ns",
|
||||||
|
RunAsUser: 100,
|
||||||
|
},
|
||||||
|
sc: &sv1.StorageClass{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "sc",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
snapshot: &snapv1.VolumeSnapshot{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "vs",
|
||||||
|
},
|
||||||
|
Status: &snapv1.VolumeSnapshotStatus{
|
||||||
|
RestoreSize: &resourceQuantity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
prepare: func(f *fields) {
|
||||||
|
gomock.InOrder(
|
||||||
|
f.createAppOps.EXPECT().CreatePVC(gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("error")),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
errChecker: NotNil,
|
||||||
|
podChecker: IsNil,
|
||||||
|
pvcChecker: IsNil,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
ctrl := gomock.NewController(c)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
f := fields{
|
||||||
|
createAppOps: mocks.NewMockApplicationCreator(ctrl),
|
||||||
|
}
|
||||||
|
if tc.prepare != nil {
|
||||||
|
tc.prepare(&f)
|
||||||
|
}
|
||||||
|
stepper := &fileRestoreSteps{
|
||||||
|
createAppOps: f.createAppOps,
|
||||||
|
}
|
||||||
|
sourcePVC := v1.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "sourcePVC",
|
||||||
|
Namespace: tc.args.Namespace,
|
||||||
|
},
|
||||||
|
Spec: v1.PersistentVolumeClaimSpec{
|
||||||
|
AccessModes: []v1.PersistentVolumeAccessMode{
|
||||||
|
v1.ReadWriteOnce,
|
||||||
|
},
|
||||||
|
Resources: v1.VolumeResourceRequirements{
|
||||||
|
Requests: v1.ResourceList{
|
||||||
|
v1.ResourceStorage: resource.MustParse("1Gi"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
pod, pvc, err := stepper.CreateInspectorApplication(ctx, tc.args, tc.snapshot, &sourcePVC, tc.sc)
|
||||||
|
c.Check(err, tc.errChecker)
|
||||||
|
c.Check(pod, tc.podChecker)
|
||||||
|
c.Check(pvc, tc.pvcChecker)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *CSITestSuite) TestFileRestoreCleanup(c *C) {
|
||||||
|
ctx := context.Background()
|
||||||
|
groupversion := &metav1.GroupVersionForDiscovery{
|
||||||
|
GroupVersion: "gv",
|
||||||
|
Version: "v",
|
||||||
|
}
|
||||||
|
type fields struct {
|
||||||
|
cleanerOps *mocks.MockCleaner
|
||||||
|
}
|
||||||
|
for _, tc := range []struct {
|
||||||
|
restorePVC *v1.PersistentVolumeClaim
|
||||||
|
pod *v1.Pod
|
||||||
|
prepare func(f *fields)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
restorePVC: &v1.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "restorePVC",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pod: &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "pod",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
prepare: func(f *fields) {
|
||||||
|
gomock.InOrder(
|
||||||
|
f.cleanerOps.EXPECT().DeletePVC(ctx, "restorePVC", "ns").Return(nil),
|
||||||
|
f.cleanerOps.EXPECT().DeletePod(ctx, "pod", "ns").Return(nil),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
restorePVC: &v1.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "restorePVC",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pod: &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "pod",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
prepare: func(f *fields) {
|
||||||
|
gomock.InOrder(
|
||||||
|
f.cleanerOps.EXPECT().DeletePVC(ctx, "restorePVC", "ns").Return(fmt.Errorf("err")),
|
||||||
|
f.cleanerOps.EXPECT().DeletePod(ctx, "pod", "ns").Return(fmt.Errorf("err")),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
ctrl := gomock.NewController(c)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
f := fields{
|
||||||
|
cleanerOps: mocks.NewMockCleaner(ctrl),
|
||||||
|
}
|
||||||
|
if tc.prepare != nil {
|
||||||
|
tc.prepare(&f)
|
||||||
|
}
|
||||||
|
stepper := &fileRestoreSteps{
|
||||||
|
cleanerOps: f.cleanerOps,
|
||||||
|
SnapshotGroupVersion: groupversion,
|
||||||
|
}
|
||||||
|
stepper.Cleanup(ctx, tc.restorePVC, tc.pod)
|
||||||
|
}
|
||||||
|
}
|
192
pkg/csi/file_restore_inspector_test.go
Normal file
192
pkg/csi/file_restore_inspector_test.go
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
package csi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
|
"github.com/kastenhq/kubestr/pkg/csi/mocks"
|
||||||
|
"github.com/kastenhq/kubestr/pkg/csi/types"
|
||||||
|
snapv1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
||||||
|
. "gopkg.in/check.v1"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
sv1 "k8s.io/api/storage/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/client-go/dynamic"
|
||||||
|
fakedynamic "k8s.io/client-go/dynamic/fake"
|
||||||
|
"k8s.io/client-go/kubernetes"
|
||||||
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *CSITestSuite) TestRunFileRestoreHelper(c *C) {
|
||||||
|
ctx := context.Background()
|
||||||
|
type fields struct {
|
||||||
|
stepperOps *mocks.MockFileRestoreStepper
|
||||||
|
}
|
||||||
|
for _, tc := range []struct {
|
||||||
|
kubeCli kubernetes.Interface
|
||||||
|
dynCli dynamic.Interface
|
||||||
|
args *types.FileRestoreArgs
|
||||||
|
prepare func(f *fields)
|
||||||
|
errChecker Checker
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
// success
|
||||||
|
kubeCli: fake.NewSimpleClientset(),
|
||||||
|
dynCli: fakedynamic.NewSimpleDynamicClient(runtime.NewScheme()),
|
||||||
|
args: &types.FileRestoreArgs{},
|
||||||
|
prepare: func(f *fields) {
|
||||||
|
gomock.InOrder(
|
||||||
|
f.stepperOps.EXPECT().ValidateArgs(gomock.Any(), gomock.Any()).Return(
|
||||||
|
&snapv1.VolumeSnapshot{}, &v1.PersistentVolumeClaim{}, &sv1.StorageClass{}, nil,
|
||||||
|
),
|
||||||
|
f.stepperOps.EXPECT().CreateInspectorApplication(gomock.Any(), gomock.Any(),
|
||||||
|
&snapv1.VolumeSnapshot{}, &v1.PersistentVolumeClaim{}, &sv1.StorageClass{},
|
||||||
|
).Return(
|
||||||
|
&v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "pod1",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&v1.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "pvc1",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
f.stepperOps.EXPECT().PortForwardAPod(
|
||||||
|
&v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "pod1",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
}, gomock.Any(),
|
||||||
|
).Return(nil),
|
||||||
|
f.stepperOps.EXPECT().Cleanup(gomock.Any(),
|
||||||
|
&v1.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "pvc1",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "pod1",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
errChecker: IsNil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// portforward failure
|
||||||
|
kubeCli: fake.NewSimpleClientset(),
|
||||||
|
dynCli: fakedynamic.NewSimpleDynamicClient(runtime.NewScheme()),
|
||||||
|
args: &types.FileRestoreArgs{},
|
||||||
|
prepare: func(f *fields) {
|
||||||
|
gomock.InOrder(
|
||||||
|
f.stepperOps.EXPECT().ValidateArgs(gomock.Any(), gomock.Any()).Return(nil, nil, nil, nil),
|
||||||
|
f.stepperOps.EXPECT().CreateInspectorApplication(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil, nil),
|
||||||
|
f.stepperOps.EXPECT().PortForwardAPod(gomock.Any(), gomock.Any()).Return(fmt.Errorf("portforward error")),
|
||||||
|
f.stepperOps.EXPECT().Cleanup(gomock.Any(), gomock.Any(), gomock.Any()),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
errChecker: NotNil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// createapp failure
|
||||||
|
kubeCli: fake.NewSimpleClientset(),
|
||||||
|
dynCli: fakedynamic.NewSimpleDynamicClient(runtime.NewScheme()),
|
||||||
|
args: &types.FileRestoreArgs{},
|
||||||
|
prepare: func(f *fields) {
|
||||||
|
gomock.InOrder(
|
||||||
|
f.stepperOps.EXPECT().ValidateArgs(gomock.Any(), gomock.Any()).Return(nil, nil, nil, nil),
|
||||||
|
f.stepperOps.EXPECT().CreateInspectorApplication(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil, fmt.Errorf("createapp error")),
|
||||||
|
f.stepperOps.EXPECT().Cleanup(gomock.Any(), gomock.Any(), gomock.Any()),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
errChecker: NotNil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// fetch snapshot failure
|
||||||
|
kubeCli: fake.NewSimpleClientset(),
|
||||||
|
dynCli: fakedynamic.NewSimpleDynamicClient(runtime.NewScheme()),
|
||||||
|
args: &types.FileRestoreArgs{},
|
||||||
|
prepare: func(f *fields) {
|
||||||
|
gomock.InOrder(
|
||||||
|
f.stepperOps.EXPECT().ValidateArgs(gomock.Any(), gomock.Any()).Return(nil, nil, nil, fmt.Errorf("snapshot error")),
|
||||||
|
f.stepperOps.EXPECT().Cleanup(gomock.Any(), gomock.Any(), gomock.Any()),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
errChecker: NotNil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// validate failure
|
||||||
|
kubeCli: fake.NewSimpleClientset(),
|
||||||
|
dynCli: fakedynamic.NewSimpleDynamicClient(runtime.NewScheme()),
|
||||||
|
args: &types.FileRestoreArgs{},
|
||||||
|
prepare: func(f *fields) {
|
||||||
|
gomock.InOrder(
|
||||||
|
f.stepperOps.EXPECT().ValidateArgs(gomock.Any(), gomock.Any()).Return(nil, nil, nil, fmt.Errorf("validate error")),
|
||||||
|
f.stepperOps.EXPECT().Cleanup(gomock.Any(), gomock.Any(), gomock.Any()),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
errChecker: NotNil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// emptycli failure
|
||||||
|
kubeCli: nil,
|
||||||
|
dynCli: fakedynamic.NewSimpleDynamicClient(runtime.NewScheme()),
|
||||||
|
args: &types.FileRestoreArgs{},
|
||||||
|
prepare: func(f *fields) {
|
||||||
|
gomock.InOrder(
|
||||||
|
f.stepperOps.EXPECT().Cleanup(gomock.Any(), gomock.Any(), gomock.Any()),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
errChecker: NotNil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// emptydyncli failure
|
||||||
|
kubeCli: fake.NewSimpleClientset(),
|
||||||
|
dynCli: nil,
|
||||||
|
args: &types.FileRestoreArgs{},
|
||||||
|
prepare: func(f *fields) {
|
||||||
|
gomock.InOrder(
|
||||||
|
f.stepperOps.EXPECT().Cleanup(gomock.Any(), gomock.Any(), gomock.Any()),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
errChecker: NotNil,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
ctrl := gomock.NewController(c)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
f := fields{
|
||||||
|
stepperOps: mocks.NewMockFileRestoreStepper(ctrl),
|
||||||
|
}
|
||||||
|
if tc.prepare != nil {
|
||||||
|
tc.prepare(&f)
|
||||||
|
}
|
||||||
|
runner := &FileRestoreRunner{
|
||||||
|
KubeCli: tc.kubeCli,
|
||||||
|
DynCli: tc.dynCli,
|
||||||
|
restoreSteps: f.stepperOps,
|
||||||
|
}
|
||||||
|
err := runner.RunFileRestoreHelper(ctx, tc.args)
|
||||||
|
c.Check(err, tc.errChecker)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *CSITestSuite) TestFileRestoreRunner(c *C) {
|
||||||
|
ctx := context.Background()
|
||||||
|
r := &FileRestoreRunner{
|
||||||
|
restoreSteps: &fileRestoreSteps{},
|
||||||
|
}
|
||||||
|
err := r.RunFileRestoreHelper(ctx, nil)
|
||||||
|
c.Check(err, NotNil)
|
||||||
|
}
|
113
pkg/csi/mocks/mock_file_restore_stepper.go
Normal file
113
pkg/csi/mocks/mock_file_restore_stepper.go
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
// Code generated by MockGen. DO NOT EDIT.
|
||||||
|
// Source: github.com/kastenhq/kubestr/pkg/csi (interfaces: FileRestoreStepper)
|
||||||
|
|
||||||
|
// Package mocks is a generated GoMock package.
|
||||||
|
package mocks
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
reflect "reflect"
|
||||||
|
|
||||||
|
gomock "github.com/golang/mock/gomock"
|
||||||
|
types "github.com/kastenhq/kubestr/pkg/csi/types"
|
||||||
|
v1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
||||||
|
v10 "k8s.io/api/core/v1"
|
||||||
|
v11 "k8s.io/api/storage/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockFileRestoreStepper is a mock of FileRestoreStepper interface.
|
||||||
|
type MockFileRestoreStepper struct {
|
||||||
|
ctrl *gomock.Controller
|
||||||
|
recorder *MockFileRestoreStepperMockRecorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockFileRestoreStepperMockRecorder is the mock recorder for MockFileRestoreStepper.
|
||||||
|
type MockFileRestoreStepperMockRecorder struct {
|
||||||
|
mock *MockFileRestoreStepper
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMockFileRestoreStepper creates a new mock instance.
|
||||||
|
func NewMockFileRestoreStepper(ctrl *gomock.Controller) *MockFileRestoreStepper {
|
||||||
|
mock := &MockFileRestoreStepper{ctrl: ctrl}
|
||||||
|
mock.recorder = &MockFileRestoreStepperMockRecorder{mock}
|
||||||
|
return mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||||
|
func (m *MockFileRestoreStepper) EXPECT() *MockFileRestoreStepperMockRecorder {
|
||||||
|
return m.recorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup mocks base method.
|
||||||
|
func (m *MockFileRestoreStepper) Cleanup(arg0 context.Context, arg1 *v10.PersistentVolumeClaim, arg2 *v10.Pod) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
m.ctrl.Call(m, "Cleanup", arg0, arg1, arg2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup indicates an expected call of Cleanup.
|
||||||
|
func (mr *MockFileRestoreStepperMockRecorder) Cleanup(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Cleanup", reflect.TypeOf((*MockFileRestoreStepper)(nil).Cleanup), arg0, arg1, arg2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateInspectorApplication mocks base method.
|
||||||
|
func (m *MockFileRestoreStepper) CreateInspectorApplication(arg0 context.Context, arg1 *types.FileRestoreArgs, arg2 *v1.VolumeSnapshot, arg3 *v10.PersistentVolumeClaim, arg4 *v11.StorageClass) (*v10.Pod, *v10.PersistentVolumeClaim, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "CreateInspectorApplication", arg0, arg1, arg2, arg3, arg4)
|
||||||
|
ret0, _ := ret[0].(*v10.Pod)
|
||||||
|
ret1, _ := ret[1].(*v10.PersistentVolumeClaim)
|
||||||
|
ret2, _ := ret[2].(error)
|
||||||
|
return ret0, ret1, ret2
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateInspectorApplication indicates an expected call of CreateInspectorApplication.
|
||||||
|
func (mr *MockFileRestoreStepperMockRecorder) CreateInspectorApplication(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateInspectorApplication", reflect.TypeOf((*MockFileRestoreStepper)(nil).CreateInspectorApplication), arg0, arg1, arg2, arg3, arg4)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecuteCopyCommand mocks base method.
|
||||||
|
func (m *MockFileRestoreStepper) ExecuteCopyCommand(arg0 context.Context, arg1 *types.FileRestoreArgs, arg2 *v10.Pod) (string, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "ExecuteCopyCommand", arg0, arg1, arg2)
|
||||||
|
ret0, _ := ret[0].(string)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecuteCopyCommand indicates an expected call of ExecuteCopyCommand.
|
||||||
|
func (mr *MockFileRestoreStepperMockRecorder) ExecuteCopyCommand(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecuteCopyCommand", reflect.TypeOf((*MockFileRestoreStepper)(nil).ExecuteCopyCommand), arg0, arg1, arg2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PortForwardAPod mocks base method.
|
||||||
|
func (m *MockFileRestoreStepper) PortForwardAPod(arg0 *v10.Pod, arg1 int) error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "PortForwardAPod", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// PortForwardAPod indicates an expected call of PortForwardAPod.
|
||||||
|
func (mr *MockFileRestoreStepperMockRecorder) PortForwardAPod(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PortForwardAPod", reflect.TypeOf((*MockFileRestoreStepper)(nil).PortForwardAPod), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateArgs mocks base method.
|
||||||
|
func (m *MockFileRestoreStepper) ValidateArgs(arg0 context.Context, arg1 *types.FileRestoreArgs) (*v1.VolumeSnapshot, *v10.PersistentVolumeClaim, *v11.StorageClass, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "ValidateArgs", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].(*v1.VolumeSnapshot)
|
||||||
|
ret1, _ := ret[1].(*v10.PersistentVolumeClaim)
|
||||||
|
ret2, _ := ret[2].(*v11.StorageClass)
|
||||||
|
ret3, _ := ret[3].(error)
|
||||||
|
return ret0, ret1, ret2, ret3
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateArgs indicates an expected call of ValidateArgs.
|
||||||
|
func (mr *MockFileRestoreStepperMockRecorder) ValidateArgs(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateArgs", reflect.TypeOf((*MockFileRestoreStepper)(nil).ValidateArgs), arg0, arg1)
|
||||||
|
}
|
|
@ -1,68 +0,0 @@
|
||||||
// Code generated by MockGen. DO NOT EDIT.
|
|
||||||
// Source: github.com/kastenhq/kubestr/pkg/csi (interfaces: SnapshotFetcher)
|
|
||||||
|
|
||||||
// Package mocks is a generated GoMock package.
|
|
||||||
package mocks
|
|
||||||
|
|
||||||
import (
|
|
||||||
context "context"
|
|
||||||
reflect "reflect"
|
|
||||||
|
|
||||||
gomock "github.com/golang/mock/gomock"
|
|
||||||
snapshot "github.com/kanisterio/kanister/pkg/kube/snapshot"
|
|
||||||
types "github.com/kastenhq/kubestr/pkg/csi/types"
|
|
||||||
v1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MockSnapshotFetcher is a mock of SnapshotFetcher interface.
|
|
||||||
type MockSnapshotFetcher struct {
|
|
||||||
ctrl *gomock.Controller
|
|
||||||
recorder *MockSnapshotFetcherMockRecorder
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockSnapshotFetcherMockRecorder is the mock recorder for MockSnapshotFetcher.
|
|
||||||
type MockSnapshotFetcherMockRecorder struct {
|
|
||||||
mock *MockSnapshotFetcher
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMockSnapshotFetcher creates a new mock instance.
|
|
||||||
func NewMockSnapshotFetcher(ctrl *gomock.Controller) *MockSnapshotFetcher {
|
|
||||||
mock := &MockSnapshotFetcher{ctrl: ctrl}
|
|
||||||
mock.recorder = &MockSnapshotFetcherMockRecorder{mock}
|
|
||||||
return mock
|
|
||||||
}
|
|
||||||
|
|
||||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
|
||||||
func (m *MockSnapshotFetcher) EXPECT() *MockSnapshotFetcherMockRecorder {
|
|
||||||
return m.recorder
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetVolumeSnapshot mocks base method.
|
|
||||||
func (m *MockSnapshotFetcher) GetVolumeSnapshot(arg0 context.Context, arg1 snapshot.Snapshotter, arg2 *types.FetchSnapshotArgs) (*v1.VolumeSnapshot, error) {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "GetVolumeSnapshot", arg0, arg1, arg2)
|
|
||||||
ret0, _ := ret[0].(*v1.VolumeSnapshot)
|
|
||||||
ret1, _ := ret[1].(error)
|
|
||||||
return ret0, ret1
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetVolumeSnapshot indicates an expected call of GetVolumeSnapshot.
|
|
||||||
func (mr *MockSnapshotFetcherMockRecorder) GetVolumeSnapshot(arg0, arg1, arg2 interface{}) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVolumeSnapshot", reflect.TypeOf((*MockSnapshotFetcher)(nil).GetVolumeSnapshot), arg0, arg1, arg2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSnapshotter mocks base method.
|
|
||||||
func (m *MockSnapshotFetcher) NewSnapshotter() (snapshot.Snapshotter, error) {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "NewSnapshotter")
|
|
||||||
ret0, _ := ret[0].(snapshot.Snapshotter)
|
|
||||||
ret1, _ := ret[1].(error)
|
|
||||||
return ret0, ret1
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSnapshotter indicates an expected call of NewSnapshotter.
|
|
||||||
func (mr *MockSnapshotFetcherMockRecorder) NewSnapshotter() *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewSnapshotter", reflect.TypeOf((*MockSnapshotFetcher)(nil).NewSnapshotter))
|
|
||||||
}
|
|
|
@ -39,10 +39,6 @@ func (r *SnapshotBrowseRunner) RunSnapshotBrowse(ctx context.Context, args *type
|
||||||
createAppOps: &applicationCreate{
|
createAppOps: &applicationCreate{
|
||||||
kubeCli: r.KubeCli,
|
kubeCli: r.KubeCli,
|
||||||
},
|
},
|
||||||
snapshotFetchOps: &snapshotFetch{
|
|
||||||
kubeCli: r.KubeCli,
|
|
||||||
dynCli: r.DynCli,
|
|
||||||
},
|
|
||||||
portForwardOps: &portforward{},
|
portForwardOps: &portforward{},
|
||||||
kubeExecutor: &kubeExec{
|
kubeExecutor: &kubeExec{
|
||||||
kubeCli: r.KubeCli,
|
kubeCli: r.KubeCli,
|
||||||
|
@ -52,10 +48,6 @@ func (r *SnapshotBrowseRunner) RunSnapshotBrowse(ctx context.Context, args *type
|
||||||
dynCli: r.DynCli,
|
dynCli: r.DynCli,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if args.ShowTree {
|
|
||||||
fmt.Println("Show Tree works for VS!")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return r.RunSnapshotBrowseHelper(ctx, args)
|
return r.RunSnapshotBrowseHelper(ctx, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +105,6 @@ type SnapshotBrowserStepper interface {
|
||||||
type snapshotBrowserSteps struct {
|
type snapshotBrowserSteps struct {
|
||||||
validateOps ArgumentValidator
|
validateOps ArgumentValidator
|
||||||
versionFetchOps ApiVersionFetcher
|
versionFetchOps ApiVersionFetcher
|
||||||
snapshotFetchOps SnapshotFetcher
|
|
||||||
createAppOps ApplicationCreator
|
createAppOps ApplicationCreator
|
||||||
portForwardOps PortForwarder
|
portForwardOps PortForwarder
|
||||||
cleanerOps Cleaner
|
cleanerOps Cleaner
|
||||||
|
|
|
@ -162,6 +162,22 @@ func (p *SnapshotBrowseArgs) Validate() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FileRestoreArgs struct {
|
||||||
|
SnapshotName string
|
||||||
|
PVCName string
|
||||||
|
Namespace string
|
||||||
|
RunAsUser int64
|
||||||
|
LocalPort int
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileRestoreArgs) Validate() error {
|
||||||
|
if f.SnapshotName == "" || f.Namespace == "" {
|
||||||
|
return fmt.Errorf("Invalid FileRestoreArgs (%v)", f)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type PortForwardAPodRequest struct {
|
type PortForwardAPodRequest struct {
|
||||||
// RestConfig is the kubernetes config
|
// RestConfig is the kubernetes config
|
||||||
RestConfig *rest.Config
|
RestConfig *rest.Config
|
||||||
|
|
Loading…
Reference in a new issue