Enhance Backup to backup resources in specific order. (#2724)

Signed-off-by: Phuong Hoang <phuong.n.hoang@dell.com>

Co-authored-by: Phuong Hoang <phuong.n.hoang@dell.com>
This commit is contained in:
Phuong N. Hoang
2020-08-12 17:17:31 -07:00
committed by GitHub
co-authored by Phuong Hoang
parent dd2d040fcf
commit 14170b52a8
13 changed files with 219 additions and 5 deletions
+32
View File
@@ -19,6 +19,7 @@ package backup
import (
"context"
"fmt"
"strings"
"time"
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
@@ -96,6 +97,7 @@ type CreateOptions struct {
StorageLocation string
SnapshotLocations []string
FromSchedule string
OrderedResources string
client veleroclient.Interface
}
@@ -120,6 +122,7 @@ func (o *CreateOptions) BindFlags(flags *pflag.FlagSet) {
flags.StringVar(&o.StorageLocation, "storage-location", "", "Location in which to store the backup.")
flags.StringSliceVar(&o.SnapshotLocations, "volume-snapshot-locations", o.SnapshotLocations, "List of locations (at most one per provider) where volume snapshots should be stored.")
flags.VarP(&o.Selector, "selector", "l", "Only back up resources matching this label selector.")
flags.StringVar(&o.OrderedResources, "ordered-resources", "", "mapping Kinds to an ordered list of specific resources of that Kind. Resource names are separated by commas and their names are in format 'namespace/resourcename'. For cluster scope resource, simply use resource name. Key-value pairs in the mapping are separated by semi-colon. Example: 'pods=ns1/pod1,ns1/pod2;persistentvolumeclaims=ns1/pvc4,ns1/pvc8'. Optional.")
f := flags.VarPF(&o.SnapshotVolumes, "snapshot-volumes", "", "Take snapshots of PersistentVolumes as part of the backup.")
// this allows the user to just specify "--snapshot-volumes" as shorthand for "--snapshot-volumes=true"
// like a normal bool flag
@@ -281,6 +284,28 @@ func (o *CreateOptions) Run(c *cobra.Command, f client.Factory) error {
return nil
}
// parseOrderedResources converts to map of Kinds to an ordered list of specific resources of that Kind.
// Resource names in the list are in format 'namespace/resourcename' and separated by commas.
// Key-value pairs in the mapping are separated by semi-colon.
// Ex: 'pods=ns1/pod1,ns1/pod2;persistentvolumeclaims=ns1/pvc4,ns1/pvc8'.
func parseOrderedResources(orderMapStr string) (map[string]string, error) {
entries := strings.Split(orderMapStr, ";")
if len(entries) == 0 {
return nil, fmt.Errorf("Invalid OrderedResources '%s'.", orderMapStr)
}
orderedResources := make(map[string]string)
for _, entry := range entries {
kv := strings.Split(entry, "=")
if len(kv) != 2 {
return nil, fmt.Errorf("Invalid OrderedResources '%s'.", entry)
}
kind := strings.TrimSpace(kv[0])
order := strings.TrimSpace(kv[1])
orderedResources[kind] = order
}
return orderedResources, nil
}
func (o *CreateOptions) BuildBackup(namespace string) (*velerov1api.Backup, error) {
var backupBuilder *builder.BackupBuilder
@@ -304,6 +329,13 @@ func (o *CreateOptions) BuildBackup(namespace string) (*velerov1api.Backup, erro
TTL(o.TTL).
StorageLocation(o.StorageLocation).
VolumeSnapshotLocations(o.SnapshotLocations...)
if len(o.OrderedResources) > 0 {
orders, err := parseOrderedResources(o.OrderedResources)
if err != nil {
return nil, err
}
backupBuilder.OrderedResources(orders)
}
if o.SnapshotVolumes.Value != nil {
backupBuilder.SnapshotVolumes(*o.SnapshotVolumes.Value)
+33 -1
View File
@@ -1,5 +1,5 @@
/*
Copyright 2019 the Velero contributors.
Copyright 2020 the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -33,6 +33,9 @@ const testNamespace = "velero"
func TestCreateOptions_BuildBackup(t *testing.T) {
o := NewCreateOptions()
o.Labels.Set("velero.io/test=true")
o.OrderedResources = "pods=p1,p2;persistentvolumeclaims=pvc1,pvc2"
orders, err := parseOrderedResources(o.OrderedResources)
assert.NoError(t, err)
backup, err := o.BuildBackup(testNamespace)
assert.NoError(t, err)
@@ -42,11 +45,16 @@ func TestCreateOptions_BuildBackup(t *testing.T) {
IncludedNamespaces: []string(o.IncludeNamespaces),
SnapshotVolumes: o.SnapshotVolumes.Value,
IncludeClusterResources: o.IncludeClusterResources.Value,
OrderedResources: orders,
}, backup.Spec)
assert.Equal(t, map[string]string{
"velero.io/test": "true",
}, backup.GetLabels())
assert.Equal(t, map[string]string{
"pods": "p1,p2",
"persistentvolumeclaims": "pvc1,pvc2",
}, backup.Spec.OrderedResources)
}
func TestCreateOptions_BuildBackupFromSchedule(t *testing.T) {
@@ -87,3 +95,27 @@ func TestCreateOptions_BuildBackupFromSchedule(t *testing.T) {
}, backup.GetLabels())
})
}
func TestCreateOptions_OrderedResources(t *testing.T) {
orderedResources, err := parseOrderedResources("pods= ns1/p1; ns1/p2; persistentvolumeclaims=ns2/pvc1, ns2/pvc2")
assert.NotNil(t, err)
orderedResources, err = parseOrderedResources("pods= ns1/p1,ns1/p2 ; persistentvolumeclaims=ns2/pvc1,ns2/pvc2")
assert.NoError(t, err)
expectedResources := map[string]string{
"pods": "ns1/p1,ns1/p2",
"persistentvolumeclaims": "ns2/pvc1,ns2/pvc2",
}
assert.Equal(t, orderedResources, expectedResources)
orderedResources, err = parseOrderedResources("pods= ns1/p1,ns1/p2 ; persistentvolumes=pv1,pv2")
assert.NoError(t, err)
expectedMixedResources := map[string]string{
"pods": "ns1/p1,ns1/p2",
"persistentvolumes": "pv1,pv2",
}
assert.Equal(t, orderedResources, expectedMixedResources)
}