Skip to content

Commit

Permalink
Add a CheckRepository func (#382)
Browse files Browse the repository at this point in the history
* Add checkRepo func

* Add tests

* Address review comments
  • Loading branch information
DeepikaDixit authored and mergify[bot] committed Nov 6, 2019
1 parent 2123c79 commit d80360a
Show file tree
Hide file tree
Showing 2 changed files with 195 additions and 0 deletions.
125 changes: 125 additions & 0 deletions pkg/function/checkRepository.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package function

import (
"context"
"strings"

"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"

kanister "github.com/kanisterio/kanister/pkg"
crv1alpha1 "github.com/kanisterio/kanister/pkg/apis/cr/v1alpha1"
"github.com/kanisterio/kanister/pkg/kube"
"github.com/kanisterio/kanister/pkg/param"
"github.com/kanisterio/kanister/pkg/restic"
)

const (
// CheckRepositoryArtifactPrefixArg provides the path to restore backed up data
CheckRepositoryArtifactPrefixArg = "backupArtifactPrefix"
// CheckRepositoryEncryptionKeyArg provides the encryption key to be used for deletes
CheckRepositoryEncryptionKeyArg = "encryptionKey"
// CheckRepositoryPodOverrideArg contains pod specs to override default pod specs
CheckRepositoryPodOverrideArg = "podOverride"
CheckRepositoryJobPrefix = "check-repository-"
CheckRepositoryPasswordIncorrect = "passwordIncorrect"
CheckRepositoryRepoDoesNotExist = "repoUnavailable"
)

func init() {
kanister.Register(&CheckRepositoryFunc{})
}

var _ kanister.Func = (*CheckRepositoryFunc)(nil)

type CheckRepositoryFunc struct{}

func (*CheckRepositoryFunc) Name() string {
return "CheckRepository"
}

func CheckRepository(ctx context.Context, cli kubernetes.Interface, tp param.TemplateParams, encryptionKey, targetPaths, jobPrefix string, podOverride crv1alpha1.JSONMap) (map[string]interface{}, error) {
namespace, err := kube.GetControllerNamespace()
if err != nil {
return nil, errors.Wrapf(err, "Failed to get controller namespace")
}
options := &kube.PodOptions{
Namespace: namespace,
GenerateName: jobPrefix,
Image: kanisterToolsImage,
Command: []string{"sh", "-c", "tail -f /dev/null"},
PodOverride: podOverride,
}
pr := kube.NewPodRunner(cli, options)
podFunc := CheckRepositoryPodFunc(cli, tp, namespace, encryptionKey, targetPaths)
return pr.Run(ctx, podFunc)
}

func CheckRepositoryPodFunc(cli kubernetes.Interface, tp param.TemplateParams, namespace, encryptionKey, targetPath string) func(ctx context.Context, pod *v1.Pod) (map[string]interface{}, error) {
return func(ctx context.Context, pod *v1.Pod) (map[string]interface{}, error) {
// Wait for pod to reach running state
if err := kube.WaitForPodReady(ctx, cli, pod.Namespace, pod.Name); err != nil {
return nil, errors.Wrapf(err, "Failed while waiting for Pod %s to be ready", pod.Name)
}
pw, err := GetPodWriter(cli, ctx, pod.Namespace, pod.Name, pod.Spec.Containers[0].Name, tp.Profile)
if err != nil {
return nil, err
}
defer CleanUpCredsFile(ctx, pw, pod.Namespace, pod.Name, pod.Spec.Containers[0].Name)
err = restic.CheckIfRepoIsReachable(tp.Profile, targetPath, encryptionKey, cli, namespace, pod.Name, pod.Spec.Containers[0].Name)
switch {
case err == nil:
break
case strings.Contains(err.Error(), restic.PasswordIncorrect):
return map[string]interface{}{
CheckRepositoryPasswordIncorrect: "true",
CheckRepositoryRepoDoesNotExist: "false",
},
nil

case strings.Contains(err.Error(), restic.RepoDoesNotExist):
return map[string]interface{}{

CheckRepositoryPasswordIncorrect: "false",
CheckRepositoryRepoDoesNotExist: "true",
},
nil
default:
return nil, err

}
return map[string]interface{}{
CheckRepositoryPasswordIncorrect: "false",
CheckRepositoryRepoDoesNotExist: "false",
},
nil
}
}

func (*CheckRepositoryFunc) Exec(ctx context.Context, tp param.TemplateParams, args map[string]interface{}) (map[string]interface{}, error) {
var getCheckRepositoryArtifactPrefix, encryptionKey string
if err := Arg(args, CheckRepositoryArtifactPrefixArg, &getCheckRepositoryArtifactPrefix); err != nil {
return nil, err
}
if err := OptArg(args, CheckRepositoryEncryptionKeyArg, &encryptionKey, restic.GeneratePassword()); err != nil {
return nil, err
}
podOverride, err := GetPodSpecOverride(tp, args, CheckRepositoryPodOverrideArg)
if err != nil {
return nil, err
}

if err = ValidateProfile(tp.Profile); err != nil {
return nil, err
}
cli, err := kube.NewClient()
if err != nil {
return nil, errors.Wrapf(err, "Failed to create Kubernetes client")
}
return CheckRepository(ctx, cli, tp, encryptionKey, getCheckRepositoryArtifactPrefix, CheckRepositoryJobPrefix, podOverride)
}

func (*CheckRepositoryFunc) RequiredArgs() []string {
return []string{CheckRepositoryArtifactPrefixArg}
}
70 changes: 70 additions & 0 deletions pkg/function/data_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,26 @@ func newDescribeBackupsBlueprint() *crv1alpha1.Blueprint {
}
}

func newCheckRepositoryBlueprint() *crv1alpha1.Blueprint {
return &crv1alpha1.Blueprint{
Actions: map[string]*crv1alpha1.BlueprintAction{
"checkRepository": &crv1alpha1.BlueprintAction{
Kind: param.StatefulSetKind,
Phases: []crv1alpha1.BlueprintPhase{
crv1alpha1.BlueprintPhase{
Name: "testCheckRepository",
Func: "CheckRepository",
Args: map[string]interface{}{
CheckRepositoryArtifactPrefixArg: "{{ .Profile.Location.Bucket }}/{{ .Profile.Location.Prefix }}",
CheckRepositoryEncryptionKeyArg: "{{ .Secrets.backupKey.Data.password | toString }}",
},
},
},
},
},
}
}

func newLocationDeleteBlueprint() *crv1alpha1.Blueprint {
return &crv1alpha1.Blueprint{
Actions: map[string]*crv1alpha1.BlueprintAction{
Expand Down Expand Up @@ -614,3 +634,53 @@ func (s *DataSuite) TestDescribeBackupsRepoNotAvailable(c *C) {
out2 := runAction(c, bp2, "describeBackups", tp)
c.Assert(out2[DescribeBackupsRepoDoesNotExist].(string), Equals, "true")
}

func (s *DataSuite) TestCheckRepository(c *C) {
tp, _ := s.getTemplateParamsAndPVCName(c, 1)

// Test backup
bp := *newBackupDataBlueprint()
out := runAction(c, bp, "backup", tp)
c.Assert(out[BackupDataOutputBackupID].(string), Not(Equals), "")
c.Assert(out[BackupDataOutputBackupTag].(string), Not(Equals), "")

// Test CheckRepository
bp2 := *newCheckRepositoryBlueprint()
out2 := runAction(c, bp2, "checkRepository", tp)
c.Assert(out2[CheckRepositoryPasswordIncorrect].(string), Equals, "false")
c.Assert(out2[CheckRepositoryRepoDoesNotExist].(string), Equals, "false")
}

func (s *DataSuite) TestCheckRepositoryWrongPassword(c *C) {
tp, _ := s.getTemplateParamsAndPVCName(c, 1)

// Test backup
bp := *newBackupDataBlueprint()
bp.Actions["backup"].Phases[0].Args[BackupDataBackupArtifactPrefixArg] = fmt.Sprintf("%s/%s", bp.Actions["backup"].Phases[0].Args[BackupDataBackupArtifactPrefixArg], "abcdef")
bp.Actions["backup"].Phases[0].Args[BackupDataEncryptionKeyArg] = "foobar"
out := runAction(c, bp, "backup", tp)
c.Assert(out[BackupDataOutputBackupID].(string), Not(Equals), "")
c.Assert(out[BackupDataOutputBackupTag].(string), Not(Equals), "")

// Test CheckRepository
bp2 := *newCheckRepositoryBlueprint()
bp2.Actions["checkRepository"].Phases[0].Args[CheckRepositoryArtifactPrefixArg] = fmt.Sprintf("%s/%s", bp2.Actions["checkRepository"].Phases[0].Args[CheckRepositoryArtifactPrefixArg], "abcdef")
out2 := runAction(c, bp2, "checkRepository", tp)
c.Assert(out2[CheckRepositoryPasswordIncorrect].(string), Equals, "true")
}

func (s *DataSuite) TestCheckRepositoryRepoNotAvailable(c *C) {
tp, _ := s.getTemplateParamsAndPVCName(c, 1)

// Test backup
bp := *newBackupDataBlueprint()
out := runAction(c, bp, "backup", tp)
c.Assert(out[BackupDataOutputBackupID].(string), Not(Equals), "")
c.Assert(out[BackupDataOutputBackupTag].(string), Not(Equals), "")

// Test CheckRepository
bp2 := *newCheckRepositoryBlueprint()
bp2.Actions["checkRepository"].Phases[0].Args[CheckRepositoryArtifactPrefixArg] = fmt.Sprintf("%s/%s", bp2.Actions["checkRepository"].Phases[0].Args[CheckRepositoryArtifactPrefixArg], c.TestName())
out2 := runAction(c, bp2, "checkRepository", tp)
c.Assert(out2[CheckRepositoryRepoDoesNotExist].(string), Equals, "true")
}

0 comments on commit d80360a

Please sign in to comment.