diff --git a/pkg/restore.go b/pkg/restore.go index d9f0c7f3f..24c9d4d00 100644 --- a/pkg/restore.go +++ b/pkg/restore.go @@ -35,6 +35,7 @@ import ( license "go.bytebuilders.dev/license-verifier/kubernetes" "gomodules.xyz/flags" "gomodules.xyz/pointer" + go_str "gomodules.xyz/x/strings" core "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -228,9 +229,10 @@ func (opt *mongoOptions) restoreMongoDB(targetRef api_v1beta1.TargetRef) (*resti opt.totalHosts = 1 // For sharded MongoDB, parameter.ConfigServer will not be empty + var restoreSession *api_v1beta1.RestoreSession if parameters.ConfigServer != "" { opt.totalHosts = len(parameters.ReplicaSets) + 1 // for each shard there will be one key in parameters.ReplicaSet - restoreSession, err := opt.stashClient.StashV1beta1().RestoreSessions(opt.namespace).Get(context.TODO(), opt.restoreSessionName, metav1.GetOptions{}) + restoreSession, err = opt.stashClient.StashV1beta1().RestoreSessions(opt.namespace).Get(context.TODO(), opt.restoreSessionName, metav1.GetOptions{}) if err != nil { return nil, err } @@ -311,9 +313,8 @@ func (opt *mongoOptions) restoreMongoDB(targetRef api_v1beta1.TargetRef) (*resti Host: hostKey, SourceHost: hostKey, FileName: opt.defaultDumpOptions.FileName, - Snapshot: opt.defaultDumpOptions.Snapshot, + Snapshot: opt.getSnapshotForHost(hostKey, restoreSession.Spec.Target.Rules), } - // setup pipe command restoreCmd := restic.Command{ Name: MongoRestoreCMD, @@ -426,3 +427,19 @@ func (opt *mongoOptions) getHostRestoreStats(err error) []api_v1beta1.HostRestor return restoreStats } + +func (opt *mongoOptions) getSnapshotForHost(hostname string, rules []api_v1beta1.Rule) string { + var hostSnapshot string + for _, rule := range rules { + if len(rule.TargetHosts) == 0 || go_str.Contains(rule.TargetHosts, hostname) { + hostSnapshot = rule.Snapshots[0] + // if rule has empty targetHost then check further rules to see if any other rule with non-empty targetHost matches + if len(rule.TargetHosts) == 0 { + continue + } else { + return hostSnapshot + } + } + } + return hostSnapshot +} diff --git a/vendor/gomodules.xyz/x/strings/fmt.go b/vendor/gomodules.xyz/x/strings/fmt.go new file mode 100644 index 000000000..20474bcb9 --- /dev/null +++ b/vendor/gomodules.xyz/x/strings/fmt.go @@ -0,0 +1,60 @@ +package strings + +import ( + "strings" +) + +func Fmt(s string) string { + stripper := &Stripe{ + Result: "", + } + stripper.Write(s) + return stripper.Result +} + +// Striplines wraps an output stream, stripping runs of consecutive empty lines. +// You must call Flush before the output stream will be complete. +// Implements io.WriteCloser, Writer, Closer. +type Stripe struct { + Result string + lastLine []byte + currentLine []byte +} + +func (w *Stripe) Write(p string) (int, error) { + totalN := 0 + s := string(p) + if !strings.Contains(s, "\n") { + w.currentLine = append(w.currentLine, p...) + return 0, nil + } + cur := string(append(w.currentLine, p...)) + lastN := strings.LastIndex(cur, "\n") + s = cur[:lastN] + for _, line := range strings.Split(s, "\n") { + n, err := w.writeLn(line + "\n") + w.lastLine = []byte(line) + if err != nil { + return totalN, err + } + totalN += n + } + rem := cur[(lastN + 1):] + w.currentLine = []byte(rem) + return totalN, nil +} + +// Close flushes the last of the output into the underlying writer. +func (w *Stripe) Close() error { + _, err := w.writeLn(string(w.currentLine)) + return err +} + +func (w *Stripe) writeLn(line string) (n int, err error) { + if strings.TrimSpace(string(w.lastLine)) == "" && strings.TrimSpace(line) == "" { + return 0, nil + } else { + w.Result = w.Result + line + return len(line), nil + } +} diff --git a/vendor/gomodules.xyz/x/strings/optionals.go b/vendor/gomodules.xyz/x/strings/optionals.go new file mode 100644 index 000000000..68e9dad08 --- /dev/null +++ b/vendor/gomodules.xyz/x/strings/optionals.go @@ -0,0 +1,14 @@ +package strings + +import "log" + +func VString(def string, args ...string) string { + v := def + if len(args) == 1 { + v = args[0] + } else if len(args) > 1 { + v = args[0] + log.Printf("Found more than 1 argument when expected 1 %v", args) + } + return v +} diff --git a/vendor/gomodules.xyz/x/strings/preconditions.go b/vendor/gomodules.xyz/x/strings/preconditions.go new file mode 100644 index 000000000..36b290fb6 --- /dev/null +++ b/vendor/gomodules.xyz/x/strings/preconditions.go @@ -0,0 +1,11 @@ +package strings + +import "strings" + +func Val(v string, def string) string { + trimmed := strings.TrimSpace(v) + if trimmed == "" { + return def + } + return trimmed +} diff --git a/vendor/gomodules.xyz/x/strings/strings.go b/vendor/gomodules.xyz/x/strings/strings.go new file mode 100644 index 000000000..71a0f79b4 --- /dev/null +++ b/vendor/gomodules.xyz/x/strings/strings.go @@ -0,0 +1,112 @@ +package strings + +import ( + "sort" + "strings" + "unicode/utf8" +) + +// Benchmark 19246 ns/op. +func Reverse(s string) string { + size := len(s) + buf := make([]byte, size) + for start := 0; start < size; { + r, n := utf8.DecodeRuneInString(s[start:]) + start += n + utf8.EncodeRune(buf[size-start:], r) + } + return string(buf) +} + +func PrefixFold(s, prefix string) bool { + return len(s) >= len(prefix) && strings.EqualFold(prefix, s[:len(prefix)]) +} + +func IsEmpty(s *string) bool { + return s == nil || *s == "" +} + +func IsBothAlphaNum(a string) bool { + alpha := false + num := false + for _, c := range a { + if (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') { + alpha = true + } else if c >= '0' && c <= '9' { + num = true + } + if alpha && num { + return true + } + } + return false +} + +func Contains(a []string, e string) bool { + for _, s := range a { + if s == e { + return true + } + } + return false +} + +// Allowed char: [a-z0-9]([a-z0-9-]*[a-z0-9])? +// Makes it safe as a subdomain +func DomainForm(s string) string { + runes := make([]rune, len(s)) + for i, r := range strings.ToLower(s) { + if (r >= '0' && r <= '9') || (r >= 'a' && r <= 'z') || (r == '-') || (r == '.') { + runes[i] = r + } else if r == '_' { + runes[i] = '-' // _ --> - + } + } + return strings.Trim(string(runes), "-") +} + +func Filter(s []string, f func(string) bool) []string { + ret := make([]string, 0) + for _, elm := range s { + if !f(elm) { + ret = append(ret, elm) + } + } + return ret +} + +func Join(a []*string, sep string) string { + b := make([]string, len(a)) + for i, s := range a { + b[i] = *s + } + return strings.Join(b, sep) +} + +func EqualSlice(a, b []string) bool { + if a == nil && b == nil { + return true + } + + if a == nil || b == nil { + return false + } + + if len(a) != len(b) { + return false + } + + // Copy slices + aCopy := append([]string(nil), a...) + bCopy := append([]string(nil), b...) + + sort.Strings(aCopy) + sort.Strings(bCopy) + + for i := range aCopy { + if aCopy[i] != bCopy[i] { + return false + } + } + return true +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 30c0b45bd..b3d773501 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -257,6 +257,7 @@ gomodules.xyz/wait # gomodules.xyz/x v0.0.15 ## explicit; go 1.18 gomodules.xyz/x/arrays +gomodules.xyz/x/strings gomodules.xyz/x/version # google.golang.org/appengine v1.6.7 ## explicit; go 1.11