Skip to content

Commit 2c44ee8

Browse files
Dipta Dastamalsaha
authored andcommitted
Implement snapshots for v1beta1 api (#749)
1 parent c88df7a commit 2c44ee8

File tree

8 files changed

+275
-83
lines changed

8 files changed

+275
-83
lines changed

cli/cli.go

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
package cli
22

33
import (
4+
"io/ioutil"
5+
"os"
46
"path/filepath"
57

68
cs "github.com/appscode/stash/client/clientset/versioned"
9+
"github.com/appscode/stash/pkg/cmds/docker"
710
docker_image "github.com/appscode/stash/pkg/docker"
11+
"github.com/appscode/stash/pkg/restic"
812
"github.com/spf13/cobra"
13+
core "k8s.io/api/core/v1"
914
"k8s.io/client-go/kubernetes"
1015
"k8s.io/client-go/rest"
1116
"k8s.io/client-go/util/homedir"
@@ -14,8 +19,8 @@ import (
1419
)
1520

1621
const (
17-
cliSecretDir = "/tmp/stash-cli/secret"
18-
cliConfigDir = "/tmp/stash-cli/config"
22+
secretDirName = "secret"
23+
configDirName = "config"
1924
)
2025

2126
type stashCLIController struct {
@@ -24,6 +29,12 @@ type stashCLIController struct {
2429
stashClient cs.Interface
2530
}
2631

32+
type cliLocalDirectories struct {
33+
secretDir string // temp dir
34+
configDir string // temp dir
35+
downloadDir string // user provided or, current working dir
36+
}
37+
2738
var (
2839
image = docker_image.Docker{
2940
Registry: docker_image.ACRegistry,
@@ -49,6 +60,7 @@ func NewCLICmd() *cobra.Command {
4960
cmd.AddCommand(NewTriggerBackupCmd())
5061
cmd.AddCommand(NewBackupPVCmd())
5162
cmd.AddCommand(NewDownloadCmd())
63+
cmd.AddCommand(NewDeleteSnapshotCmd())
5264

5365
return cmd
5466
}
@@ -72,3 +84,48 @@ func newStashCLIController(kubeConfig string) (*stashCLIController, error) {
7284
}
7385
return controller, nil
7486
}
87+
88+
func (localDirs *cliLocalDirectories) prepareSecretDir(tempDir string, secret *core.Secret) error {
89+
// write repository secrets in a sub-dir insider tempDir
90+
localDirs.secretDir = filepath.Join(tempDir, secretDirName)
91+
if err := os.MkdirAll(localDirs.secretDir, 0755); err != nil {
92+
return err
93+
}
94+
for key, value := range secret.Data {
95+
if err := ioutil.WriteFile(filepath.Join(localDirs.secretDir, key), value, 0755); err != nil {
96+
return err
97+
}
98+
}
99+
return nil
100+
}
101+
102+
func (localDirs *cliLocalDirectories) prepareConfigDir(tempDir string, setupOpt *restic.SetupOptions, restoreOpt *restic.RestoreOptions) error {
103+
// write restic options in a sub-dir insider tempDir
104+
localDirs.configDir = filepath.Join(tempDir, configDirName)
105+
if err := os.MkdirAll(localDirs.secretDir, 0755); err != nil {
106+
return err
107+
}
108+
if setupOpt != nil {
109+
err := docker.WriteSetupOptionToFile(setupOpt, filepath.Join(localDirs.configDir, docker.SetupOptionsFile))
110+
if err != nil {
111+
return err
112+
}
113+
}
114+
if restoreOpt != nil {
115+
err := docker.WriteRestoreOptionToFile(restoreOpt, filepath.Join(localDirs.configDir, docker.RestoreOptionsFile))
116+
if err != nil {
117+
return err
118+
}
119+
}
120+
return nil
121+
}
122+
123+
func (localDirs *cliLocalDirectories) prepareDownloadDir() (err error) {
124+
// if destination flag is not specified, restore in current directory
125+
if localDirs.downloadDir == "" {
126+
if localDirs.downloadDir, err = os.Getwd(); err != nil {
127+
return err
128+
}
129+
}
130+
return os.MkdirAll(localDirs.downloadDir, 0755)
131+
}

cli/delete_snapshot.go

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package cli
2+
3+
import (
4+
"fmt"
5+
"io/ioutil"
6+
"os"
7+
"os/exec"
8+
"os/user"
9+
10+
"github.com/appscode/go/log"
11+
"github.com/appscode/stash/pkg/cmds/docker"
12+
"github.com/appscode/stash/pkg/registry/snapshot"
13+
"github.com/appscode/stash/pkg/util"
14+
"github.com/spf13/cobra"
15+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
16+
)
17+
18+
func NewDeleteSnapshotCmd() *cobra.Command {
19+
var (
20+
kubeConfig string
21+
namespace string
22+
localDirs = &cliLocalDirectories{}
23+
)
24+
25+
var cmd = &cobra.Command{
26+
Use: "delete-snapshot",
27+
Short: `Delete a snapshot from repository backend`,
28+
Long: `Delete a snapshot from repository backend`,
29+
DisableAutoGenTag: true,
30+
RunE: func(cmd *cobra.Command, args []string) error {
31+
if len(args) == 0 {
32+
return fmt.Errorf("snapshot name not provided")
33+
}
34+
repoName, snapshotId, err := util.GetRepoNameAndSnapshotID(args[0])
35+
if err != nil {
36+
return err
37+
}
38+
39+
c, err := newStashCLIController(kubeConfig)
40+
if err != nil {
41+
return err
42+
}
43+
44+
// get source repository
45+
repository, err := c.stashClient.StashV1alpha1().Repositories(namespace).Get(repoName, metav1.GetOptions{})
46+
if err != nil {
47+
return err
48+
}
49+
// delete from local backend
50+
if repository.Spec.Backend.Local != nil {
51+
r := snapshot.NewREST(c.clientConfig)
52+
return r.ForgetVersionedSnapshots(repository, []string{snapshotId}, false)
53+
}
54+
55+
// get source repository secret
56+
secret, err := c.kubeClient.CoreV1().Secrets(namespace).Get(repository.Spec.Backend.StorageSecretName, metav1.GetOptions{})
57+
if err != nil {
58+
return err
59+
}
60+
61+
// configure restic wrapper
62+
extraOpt := util.ExtraOptions{
63+
SecretDir: docker.SecretDir,
64+
EnableCache: false,
65+
ScratchDir: docker.ScratchDir,
66+
}
67+
setupOpt, err := util.SetupOptionsForRepository(*repository, extraOpt)
68+
if err != nil {
69+
return fmt.Errorf("setup option for repository failed")
70+
}
71+
72+
// write secret and config in a temp dir
73+
// cleanup whole tempDir dir at the end
74+
tempDir, err := ioutil.TempDir("", "stash-cli")
75+
if err != nil {
76+
return err
77+
}
78+
defer os.RemoveAll(tempDir)
79+
80+
// prepare local dirs
81+
if err = localDirs.prepareSecretDir(tempDir, secret); err != nil {
82+
return err
83+
}
84+
if err = localDirs.prepareConfigDir(tempDir, &setupOpt, nil); err != nil {
85+
return err
86+
}
87+
88+
// run unlock inside docker
89+
if err = runDeleteSnapshotViaDocker(*localDirs, snapshotId); err != nil {
90+
return err
91+
}
92+
log.Infof("Snapshot %s deleted from repository %s/%s", snapshotId, namespace, repoName)
93+
return nil
94+
},
95+
}
96+
97+
cmd.Flags().StringVar(&kubeConfig, "kubeconfig", kubeConfig, "Path of the Kube config file.")
98+
cmd.Flags().StringVar(&namespace, "namespace", "default", "Namespace of the Repository.")
99+
100+
cmd.Flags().StringVar(&image.Registry, "docker-registry", image.Registry, "Docker image registry")
101+
cmd.Flags().StringVar(&image.Tag, "image-tag", image.Tag, "Stash image tag")
102+
103+
return cmd
104+
}
105+
106+
func runDeleteSnapshotViaDocker(localDirs cliLocalDirectories, snapshotId string) error {
107+
// get current user
108+
currentUser, err := user.Current()
109+
if err != nil {
110+
return err
111+
}
112+
args := []string{
113+
"run",
114+
"--rm",
115+
"-u", currentUser.Uid,
116+
"-v", localDirs.configDir + ":" + docker.ConfigDir,
117+
"-v", localDirs.secretDir + ":" + docker.SecretDir,
118+
image.ToContainerImage(),
119+
"docker",
120+
"delete-snapshot",
121+
"--snapshot", snapshotId,
122+
}
123+
log.Infoln("Running docker with args:", args)
124+
out, err := exec.Command("docker", args...).CombinedOutput()
125+
log.Infoln("Output:", string(out))
126+
return err
127+
}

cli/download.go

Lines changed: 29 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,23 @@ import (
66
"os"
77
"os/exec"
88
"os/user"
9-
"path/filepath"
109

1110
"github.com/appscode/go/flags"
1211
"github.com/appscode/go/log"
1312
"github.com/appscode/stash/pkg/cmds/docker"
1413
"github.com/appscode/stash/pkg/restic"
1514
"github.com/appscode/stash/pkg/util"
1615
"github.com/spf13/cobra"
17-
core "k8s.io/api/core/v1"
1816
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1917
)
2018

2119
func NewDownloadCmd() *cobra.Command {
2220
var (
23-
kubeConfig string
24-
repositoryName string
25-
namespace string
26-
localDestination string
27-
restoreOpt = restic.RestoreOptions{
21+
kubeConfig string
22+
repositoryName string
23+
namespace string
24+
localDirs = &cliLocalDirectories{}
25+
restoreOpt = restic.RestoreOptions{
2826
SourceHost: restic.DefaultHost,
2927
Destination: docker.DestinationDir,
3028
}
@@ -69,16 +67,27 @@ func NewDownloadCmd() *cobra.Command {
6967
return fmt.Errorf("setup option for repository failed")
7068
}
7169

72-
// write secret and config
73-
// cleanup whole config/secret dir at the end
74-
defer os.RemoveAll(cliSecretDir)
75-
defer os.RemoveAll(cliConfigDir)
76-
if err = prepareDockerVolumeForRestore(*secret, setupOpt, restoreOpt); err != nil {
70+
// write secret and config in a temp dir
71+
// cleanup whole tempDir dir at the end
72+
tempDir, err := ioutil.TempDir("", "stash-cli")
73+
if err != nil {
74+
return err
75+
}
76+
defer os.RemoveAll(tempDir)
77+
78+
// prepare local dirs
79+
if err = localDirs.prepareSecretDir(tempDir, secret); err != nil {
80+
return err
81+
}
82+
if err = localDirs.prepareConfigDir(tempDir, &setupOpt, &restoreOpt); err != nil {
83+
return err
84+
}
85+
if err = localDirs.prepareDownloadDir(); err != nil {
7786
return err
7887
}
7988

8089
// run restore inside docker
81-
if err = runRestoreViaDocker(localDestination); err != nil {
90+
if err = runRestoreViaDocker(*localDirs); err != nil {
8291
return err
8392
}
8493
log.Infof("Repository %s/%s restored in path %s", namespace, repositoryName, restoreOpt.Destination)
@@ -89,59 +98,31 @@ func NewDownloadCmd() *cobra.Command {
8998
cmd.Flags().StringVar(&kubeConfig, "kubeconfig", kubeConfig, "Path of the Kube config file.")
9099
cmd.Flags().StringVar(&repositoryName, "repository", repositoryName, "Name of the Repository.")
91100
cmd.Flags().StringVar(&namespace, "namespace", "default", "Namespace of the Repository.")
92-
cmd.Flags().StringVar(&localDestination, "destination", localDestination, "Destination path where snapshot will be restored.")
101+
cmd.Flags().StringVar(&localDirs.downloadDir, "destination", localDirs.downloadDir, "Destination path where snapshot will be restored.")
93102

94103
cmd.Flags().StringVar(&restoreOpt.SourceHost, "host", restoreOpt.SourceHost, "Name of the source host machine")
95104
cmd.Flags().StringSliceVar(&restoreOpt.RestoreDirs, "directories", restoreOpt.RestoreDirs, "List of directories to be restored")
96105
cmd.Flags().StringSliceVar(&restoreOpt.Snapshots, "snapshots", restoreOpt.Snapshots, "List of snapshots to be restored")
97106

98-
cmd.Flags().StringVar(&image.Registry, "docker-registry", image.Registry, "Docker image registry for unlock job")
99-
cmd.Flags().StringVar(&image.Tag, "image-tag", image.Tag, "Stash image tag for unlock job")
107+
cmd.Flags().StringVar(&image.Registry, "docker-registry", image.Registry, "Docker image registry")
108+
cmd.Flags().StringVar(&image.Tag, "image-tag", image.Tag, "Stash image tag")
100109

101110
return cmd
102111
}
103112

104-
func prepareDockerVolumeForRestore(secret core.Secret, setupOpt restic.SetupOptions, restoreOpt restic.RestoreOptions) error {
105-
// write repository secrets
106-
if err := os.MkdirAll(cliSecretDir, 0755); err != nil {
107-
return err
108-
}
109-
for key, value := range secret.Data {
110-
if err := ioutil.WriteFile(filepath.Join(cliSecretDir, key), value, 0755); err != nil {
111-
return err
112-
}
113-
}
114-
// write restic options
115-
err := docker.WriteSetupOptionToFile(&setupOpt, filepath.Join(cliConfigDir, docker.SetupOptionsFile))
116-
if err != nil {
117-
return err
118-
}
119-
return docker.WriteRestoreOptionToFile(&restoreOpt, filepath.Join(cliConfigDir, docker.RestoreOptionsFile))
120-
}
121-
122-
func runRestoreViaDocker(localDestination string) error {
113+
func runRestoreViaDocker(localDirs cliLocalDirectories) error {
123114
// get current user
124115
currentUser, err := user.Current()
125116
if err != nil {
126117
return err
127118
}
128-
// if destination flag is not specified, restore in current directory
129-
if localDestination == "" {
130-
if localDestination, err = os.Getwd(); err != nil {
131-
return err
132-
}
133-
}
134-
// create local destination dir
135-
if err := os.MkdirAll(localDestination, 0755); err != nil {
136-
return err
137-
}
138119
args := []string{
139120
"run",
140121
"--rm",
141122
"-u", currentUser.Uid,
142-
"-v", cliConfigDir + ":" + docker.ConfigDir,
143-
"-v", cliSecretDir + ":" + docker.SecretDir,
144-
"-v", localDestination + ":" + docker.DestinationDir,
123+
"-v", localDirs.configDir + ":" + docker.ConfigDir,
124+
"-v", localDirs.secretDir + ":" + docker.SecretDir,
125+
"-v", localDirs.downloadDir + ":" + docker.DestinationDir,
145126
image.ToContainerImage(),
146127
"docker",
147128
"download-snapshots",

0 commit comments

Comments
 (0)