Merge pull request #533 from skriss/fix-init-repo-key-data
ark restic init-repository: use key data if providedpull/537/head
commit
c0cf61912d
|
@ -18,11 +18,11 @@ package restic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"io/ioutil"
|
|
||||||
|
|
||||||
"github.com/heptio/ark/pkg/client"
|
"github.com/heptio/ark/pkg/client"
|
||||||
"github.com/heptio/ark/pkg/cmd"
|
"github.com/heptio/ark/pkg/cmd"
|
||||||
"github.com/heptio/ark/pkg/restic"
|
"github.com/heptio/ark/pkg/restic"
|
||||||
|
"github.com/heptio/ark/pkg/util/filesystem"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
|
@ -55,6 +55,7 @@ type InitRepositoryOptions struct {
|
||||||
KeyData string
|
KeyData string
|
||||||
KeySize int
|
KeySize int
|
||||||
|
|
||||||
|
fileSystem filesystem.Interface
|
||||||
kubeClient kclientset.Interface
|
kubeClient kclientset.Interface
|
||||||
keyBytes []byte
|
keyBytes []byte
|
||||||
}
|
}
|
||||||
|
@ -62,9 +63,15 @@ type InitRepositoryOptions struct {
|
||||||
func NewInitRepositoryOptions() *InitRepositoryOptions {
|
func NewInitRepositoryOptions() *InitRepositoryOptions {
|
||||||
return &InitRepositoryOptions{
|
return &InitRepositoryOptions{
|
||||||
KeySize: 1024,
|
KeySize: 1024,
|
||||||
|
fileSystem: filesystem.NewFileSystem(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errKeyFileAndKeyDataProvided = errors.Errorf("only one of --key-file and --key-data may be specified")
|
||||||
|
errKeySizeTooSmall = errors.Errorf("--key-size must be at least 1")
|
||||||
|
)
|
||||||
|
|
||||||
func (o *InitRepositoryOptions) BindFlags(flags *pflag.FlagSet) {
|
func (o *InitRepositoryOptions) BindFlags(flags *pflag.FlagSet) {
|
||||||
flags.StringVar(&o.KeyFile, "key-file", o.KeyFile, "Path to file containing the encryption key for the restic repository. Optional; if unset, Ark will generate a random key for you.")
|
flags.StringVar(&o.KeyFile, "key-file", o.KeyFile, "Path to file containing the encryption key for the restic repository. Optional; if unset, Ark will generate a random key for you.")
|
||||||
flags.StringVar(&o.KeyData, "key-data", o.KeyData, "Encryption key for the restic repository. Optional; if unset, Ark will generate a random key for you.")
|
flags.StringVar(&o.KeyData, "key-data", o.KeyData, "Encryption key for the restic repository. Optional; if unset, Ark will generate a random key for you.")
|
||||||
|
@ -73,27 +80,28 @@ func (o *InitRepositoryOptions) BindFlags(flags *pflag.FlagSet) {
|
||||||
|
|
||||||
func (o *InitRepositoryOptions) Complete(f client.Factory) error {
|
func (o *InitRepositoryOptions) Complete(f client.Factory) error {
|
||||||
if o.KeyFile != "" && o.KeyData != "" {
|
if o.KeyFile != "" && o.KeyData != "" {
|
||||||
return errors.Errorf("only one of --key-file and --key-data may be specified")
|
return errKeyFileAndKeyDataProvided
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.KeyFile == "" && o.KeyData == "" && o.KeySize < 1 {
|
if o.KeyFile == "" && o.KeyData == "" && o.KeySize < 1 {
|
||||||
return errors.Errorf("--key-size must be at least 1")
|
return errKeySizeTooSmall
|
||||||
}
|
}
|
||||||
|
|
||||||
o.Namespace = f.Namespace()
|
o.Namespace = f.Namespace()
|
||||||
|
|
||||||
if o.KeyFile != "" {
|
switch {
|
||||||
data, err := ioutil.ReadFile(o.KeyFile)
|
case o.KeyFile != "":
|
||||||
|
data, err := o.fileSystem.ReadFile(o.KeyFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
o.keyBytes = data
|
o.keyBytes = data
|
||||||
}
|
case o.KeyData != "":
|
||||||
|
o.keyBytes = []byte(o.KeyData)
|
||||||
if len(o.KeyData) == 0 {
|
case o.KeySize > 0:
|
||||||
o.keyBytes = make([]byte, o.KeySize)
|
o.keyBytes = make([]byte, o.KeySize)
|
||||||
// rand.Reader always returns a nil error
|
// rand.Reader always returns a nil error
|
||||||
_, _ = rand.Read(o.keyBytes)
|
rand.Read(o.keyBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
package restic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"k8s.io/client-go/kubernetes"
|
||||||
|
|
||||||
|
"github.com/heptio/ark/pkg/client"
|
||||||
|
clientset "github.com/heptio/ark/pkg/generated/clientset/versioned"
|
||||||
|
arktest "github.com/heptio/ark/pkg/util/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
type fakeFactory struct{}
|
||||||
|
|
||||||
|
var _ client.Factory = &fakeFactory{}
|
||||||
|
|
||||||
|
func (f *fakeFactory) BindFlags(flags *pflag.FlagSet) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakeFactory) Client() (clientset.Interface, error) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakeFactory) KubeClient() (kubernetes.Interface, error) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakeFactory) Namespace() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestComplete(t *testing.T) {
|
||||||
|
// no key options provided should error
|
||||||
|
o := &InitRepositoryOptions{}
|
||||||
|
err := o.Complete(&fakeFactory{})
|
||||||
|
assert.EqualError(t, err, errKeySizeTooSmall.Error())
|
||||||
|
|
||||||
|
// both KeyFile and KeyData provided should error
|
||||||
|
o = &InitRepositoryOptions{
|
||||||
|
KeyFile: "/foo",
|
||||||
|
KeyData: "bar",
|
||||||
|
}
|
||||||
|
err = o.Complete(&fakeFactory{})
|
||||||
|
assert.EqualError(t, err, errKeyFileAndKeyDataProvided.Error())
|
||||||
|
|
||||||
|
// if KeyFile is provided, its contents are used
|
||||||
|
fileContents := []byte("bar")
|
||||||
|
o = &InitRepositoryOptions{
|
||||||
|
KeyFile: "/foo",
|
||||||
|
fileSystem: arktest.NewFakeFileSystem().WithFile("/foo", fileContents),
|
||||||
|
}
|
||||||
|
assert.NoError(t, o.Complete(&fakeFactory{}))
|
||||||
|
assert.Equal(t, fileContents, o.keyBytes)
|
||||||
|
|
||||||
|
// if KeyData is provided, it's used
|
||||||
|
o = &InitRepositoryOptions{
|
||||||
|
KeyData: "bar",
|
||||||
|
}
|
||||||
|
assert.NoError(t, o.Complete(&fakeFactory{}))
|
||||||
|
assert.Equal(t, []byte(o.KeyData), o.keyBytes)
|
||||||
|
|
||||||
|
// if KeySize is provided, a random key is generated
|
||||||
|
o = &InitRepositoryOptions{
|
||||||
|
KeySize: 10,
|
||||||
|
}
|
||||||
|
assert.NoError(t, o.Complete(&fakeFactory{}))
|
||||||
|
assert.Equal(t, o.KeySize, len(o.keyBytes))
|
||||||
|
}
|
|
@ -18,12 +18,9 @@ package restore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/afero"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
@ -120,7 +117,7 @@ func TestPrioritizeResources(t *testing.T) {
|
||||||
func TestRestoreNamespaceFiltering(t *testing.T) {
|
func TestRestoreNamespaceFiltering(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
fileSystem *fakeFileSystem
|
fileSystem *arktest.FakeFileSystem
|
||||||
baseDir string
|
baseDir string
|
||||||
restore *api.Restore
|
restore *api.Restore
|
||||||
expectedReadDirs []string
|
expectedReadDirs []string
|
||||||
|
@ -128,7 +125,7 @@ func TestRestoreNamespaceFiltering(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "namespacesToRestore having * restores all namespaces",
|
name: "namespacesToRestore having * restores all namespaces",
|
||||||
fileSystem: newFakeFileSystem().WithDirectories("bak/resources/nodes/cluster", "bak/resources/secrets/namespaces/a", "bak/resources/secrets/namespaces/b", "bak/resources/secrets/namespaces/c"),
|
fileSystem: arktest.NewFakeFileSystem().WithDirectories("bak/resources/nodes/cluster", "bak/resources/secrets/namespaces/a", "bak/resources/secrets/namespaces/b", "bak/resources/secrets/namespaces/c"),
|
||||||
baseDir: "bak",
|
baseDir: "bak",
|
||||||
restore: &api.Restore{Spec: api.RestoreSpec{IncludedNamespaces: []string{"*"}}},
|
restore: &api.Restore{Spec: api.RestoreSpec{IncludedNamespaces: []string{"*"}}},
|
||||||
expectedReadDirs: []string{"bak/resources", "bak/resources/nodes/cluster", "bak/resources/secrets/namespaces", "bak/resources/secrets/namespaces/a", "bak/resources/secrets/namespaces/b", "bak/resources/secrets/namespaces/c"},
|
expectedReadDirs: []string{"bak/resources", "bak/resources/nodes/cluster", "bak/resources/secrets/namespaces", "bak/resources/secrets/namespaces/a", "bak/resources/secrets/namespaces/b", "bak/resources/secrets/namespaces/c"},
|
||||||
|
@ -139,7 +136,7 @@ func TestRestoreNamespaceFiltering(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "namespacesToRestore properly filters",
|
name: "namespacesToRestore properly filters",
|
||||||
fileSystem: newFakeFileSystem().WithDirectories("bak/resources/nodes/cluster", "bak/resources/secrets/namespaces/a", "bak/resources/secrets/namespaces/b", "bak/resources/secrets/namespaces/c"),
|
fileSystem: arktest.NewFakeFileSystem().WithDirectories("bak/resources/nodes/cluster", "bak/resources/secrets/namespaces/a", "bak/resources/secrets/namespaces/b", "bak/resources/secrets/namespaces/c"),
|
||||||
baseDir: "bak",
|
baseDir: "bak",
|
||||||
restore: &api.Restore{Spec: api.RestoreSpec{IncludedNamespaces: []string{"b", "c"}}},
|
restore: &api.Restore{Spec: api.RestoreSpec{IncludedNamespaces: []string{"b", "c"}}},
|
||||||
expectedReadDirs: []string{"bak/resources", "bak/resources/nodes/cluster", "bak/resources/secrets/namespaces", "bak/resources/secrets/namespaces/b", "bak/resources/secrets/namespaces/c"},
|
expectedReadDirs: []string{"bak/resources", "bak/resources/nodes/cluster", "bak/resources/secrets/namespaces", "bak/resources/secrets/namespaces/b", "bak/resources/secrets/namespaces/c"},
|
||||||
|
@ -150,7 +147,7 @@ func TestRestoreNamespaceFiltering(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "namespacesToRestore properly filters with exclusion filter",
|
name: "namespacesToRestore properly filters with exclusion filter",
|
||||||
fileSystem: newFakeFileSystem().WithDirectories("bak/resources/nodes/cluster", "bak/resources/secrets/namespaces/a", "bak/resources/secrets/namespaces/b", "bak/resources/secrets/namespaces/c"),
|
fileSystem: arktest.NewFakeFileSystem().WithDirectories("bak/resources/nodes/cluster", "bak/resources/secrets/namespaces/a", "bak/resources/secrets/namespaces/b", "bak/resources/secrets/namespaces/c"),
|
||||||
baseDir: "bak",
|
baseDir: "bak",
|
||||||
restore: &api.Restore{Spec: api.RestoreSpec{IncludedNamespaces: []string{"*"}, ExcludedNamespaces: []string{"a"}}},
|
restore: &api.Restore{Spec: api.RestoreSpec{IncludedNamespaces: []string{"*"}, ExcludedNamespaces: []string{"a"}}},
|
||||||
expectedReadDirs: []string{"bak/resources", "bak/resources/nodes/cluster", "bak/resources/secrets/namespaces", "bak/resources/secrets/namespaces/b", "bak/resources/secrets/namespaces/c"},
|
expectedReadDirs: []string{"bak/resources", "bak/resources/nodes/cluster", "bak/resources/secrets/namespaces", "bak/resources/secrets/namespaces/b", "bak/resources/secrets/namespaces/c"},
|
||||||
|
@ -161,7 +158,7 @@ func TestRestoreNamespaceFiltering(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "namespacesToRestore properly filters with inclusion & exclusion filters",
|
name: "namespacesToRestore properly filters with inclusion & exclusion filters",
|
||||||
fileSystem: newFakeFileSystem().WithDirectories("bak/resources/nodes/cluster", "bak/resources/secrets/namespaces/a", "bak/resources/secrets/namespaces/b", "bak/resources/secrets/namespaces/c"),
|
fileSystem: arktest.NewFakeFileSystem().WithDirectories("bak/resources/nodes/cluster", "bak/resources/secrets/namespaces/a", "bak/resources/secrets/namespaces/b", "bak/resources/secrets/namespaces/c"),
|
||||||
baseDir: "bak",
|
baseDir: "bak",
|
||||||
restore: &api.Restore{
|
restore: &api.Restore{
|
||||||
Spec: api.RestoreSpec{
|
Spec: api.RestoreSpec{
|
||||||
|
@ -197,7 +194,7 @@ func TestRestoreNamespaceFiltering(t *testing.T) {
|
||||||
assert.Empty(t, errors.Ark)
|
assert.Empty(t, errors.Ark)
|
||||||
assert.Empty(t, errors.Cluster)
|
assert.Empty(t, errors.Cluster)
|
||||||
assert.Empty(t, errors.Namespaces)
|
assert.Empty(t, errors.Namespaces)
|
||||||
assert.Equal(t, test.expectedReadDirs, test.fileSystem.readDirCalls)
|
assert.Equal(t, test.expectedReadDirs, test.fileSystem.ReadDirCalls)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,7 +202,7 @@ func TestRestoreNamespaceFiltering(t *testing.T) {
|
||||||
func TestRestorePriority(t *testing.T) {
|
func TestRestorePriority(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
fileSystem *fakeFileSystem
|
fileSystem *arktest.FakeFileSystem
|
||||||
restore *api.Restore
|
restore *api.Restore
|
||||||
baseDir string
|
baseDir string
|
||||||
prioritizedResources []schema.GroupResource
|
prioritizedResources []schema.GroupResource
|
||||||
|
@ -214,7 +211,7 @@ func TestRestorePriority(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "cluster test",
|
name: "cluster test",
|
||||||
fileSystem: newFakeFileSystem().WithDirectory("bak/resources/a/cluster").WithDirectory("bak/resources/c/cluster"),
|
fileSystem: arktest.NewFakeFileSystem().WithDirectory("bak/resources/a/cluster").WithDirectory("bak/resources/c/cluster"),
|
||||||
baseDir: "bak",
|
baseDir: "bak",
|
||||||
restore: &api.Restore{Spec: api.RestoreSpec{IncludedNamespaces: []string{"*"}}},
|
restore: &api.Restore{Spec: api.RestoreSpec{IncludedNamespaces: []string{"*"}}},
|
||||||
prioritizedResources: []schema.GroupResource{
|
prioritizedResources: []schema.GroupResource{
|
||||||
|
@ -226,7 +223,7 @@ func TestRestorePriority(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "resource priorities are applied",
|
name: "resource priorities are applied",
|
||||||
fileSystem: newFakeFileSystem().WithDirectory("bak/resources/a/cluster").WithDirectory("bak/resources/c/cluster"),
|
fileSystem: arktest.NewFakeFileSystem().WithDirectory("bak/resources/a/cluster").WithDirectory("bak/resources/c/cluster"),
|
||||||
restore: &api.Restore{Spec: api.RestoreSpec{IncludedNamespaces: []string{"*"}}},
|
restore: &api.Restore{Spec: api.RestoreSpec{IncludedNamespaces: []string{"*"}}},
|
||||||
baseDir: "bak",
|
baseDir: "bak",
|
||||||
prioritizedResources: []schema.GroupResource{
|
prioritizedResources: []schema.GroupResource{
|
||||||
|
@ -238,7 +235,7 @@ func TestRestorePriority(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "basic namespace",
|
name: "basic namespace",
|
||||||
fileSystem: newFakeFileSystem().WithDirectory("bak/resources/a/namespaces/ns-1").WithDirectory("bak/resources/c/namespaces/ns-1"),
|
fileSystem: arktest.NewFakeFileSystem().WithDirectory("bak/resources/a/namespaces/ns-1").WithDirectory("bak/resources/c/namespaces/ns-1"),
|
||||||
restore: &api.Restore{Spec: api.RestoreSpec{IncludedNamespaces: []string{"*"}}},
|
restore: &api.Restore{Spec: api.RestoreSpec{IncludedNamespaces: []string{"*"}}},
|
||||||
baseDir: "bak",
|
baseDir: "bak",
|
||||||
prioritizedResources: []schema.GroupResource{
|
prioritizedResources: []schema.GroupResource{
|
||||||
|
@ -250,7 +247,7 @@ func TestRestorePriority(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "error in a single resource doesn't terminate restore immediately, but is returned",
|
name: "error in a single resource doesn't terminate restore immediately, but is returned",
|
||||||
fileSystem: newFakeFileSystem().
|
fileSystem: arktest.NewFakeFileSystem().
|
||||||
WithFile("bak/resources/a/namespaces/ns-1/invalid-json.json", []byte("invalid json")).
|
WithFile("bak/resources/a/namespaces/ns-1/invalid-json.json", []byte("invalid json")).
|
||||||
WithDirectory("bak/resources/c/namespaces/ns-1"),
|
WithDirectory("bak/resources/c/namespaces/ns-1"),
|
||||||
restore: &api.Restore{Spec: api.RestoreSpec{IncludedNamespaces: []string{"*"}}},
|
restore: &api.Restore{Spec: api.RestoreSpec{IncludedNamespaces: []string{"*"}}},
|
||||||
|
@ -288,7 +285,7 @@ func TestRestorePriority(t *testing.T) {
|
||||||
assert.Empty(t, warnings.Namespaces)
|
assert.Empty(t, warnings.Namespaces)
|
||||||
assert.Equal(t, test.expectedErrors, errors)
|
assert.Equal(t, test.expectedErrors, errors)
|
||||||
|
|
||||||
assert.Equal(t, test.expectedReadDirs, test.fileSystem.readDirCalls)
|
assert.Equal(t, test.expectedReadDirs, test.fileSystem.ReadDirCalls)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -299,7 +296,7 @@ func TestNamespaceRemapping(t *testing.T) {
|
||||||
restore = &api.Restore{Spec: api.RestoreSpec{IncludedNamespaces: []string{"*"}, NamespaceMapping: map[string]string{"ns-1": "ns-2"}}}
|
restore = &api.Restore{Spec: api.RestoreSpec{IncludedNamespaces: []string{"*"}, NamespaceMapping: map[string]string{"ns-1": "ns-2"}}}
|
||||||
prioritizedResources = []schema.GroupResource{{Resource: "namespaces"}, {Resource: "configmaps"}}
|
prioritizedResources = []schema.GroupResource{{Resource: "namespaces"}, {Resource: "configmaps"}}
|
||||||
labelSelector = labels.NewSelector()
|
labelSelector = labels.NewSelector()
|
||||||
fileSystem = newFakeFileSystem().
|
fileSystem = arktest.NewFakeFileSystem().
|
||||||
WithFile("bak/resources/configmaps/namespaces/ns-1/cm-1.json", newTestConfigMap().WithNamespace("ns-1").ToJSON()).
|
WithFile("bak/resources/configmaps/namespaces/ns-1/cm-1.json", newTestConfigMap().WithNamespace("ns-1").ToJSON()).
|
||||||
WithFile("bak/resources/namespaces/cluster/ns-1.json", newTestNamespace("ns-1").ToJSON())
|
WithFile("bak/resources/namespaces/cluster/ns-1.json", newTestNamespace("ns-1").ToJSON())
|
||||||
expectedNS = "ns-2"
|
expectedNS = "ns-2"
|
||||||
|
@ -363,7 +360,7 @@ func TestRestoreResourceForNamespace(t *testing.T) {
|
||||||
resourcePath string
|
resourcePath string
|
||||||
labelSelector labels.Selector
|
labelSelector labels.Selector
|
||||||
includeClusterResources *bool
|
includeClusterResources *bool
|
||||||
fileSystem *fakeFileSystem
|
fileSystem *arktest.FakeFileSystem
|
||||||
actions []resolvedAction
|
actions []resolvedAction
|
||||||
expectedErrors api.RestoreResult
|
expectedErrors api.RestoreResult
|
||||||
expectedObjs []unstructured.Unstructured
|
expectedObjs []unstructured.Unstructured
|
||||||
|
@ -373,7 +370,7 @@ func TestRestoreResourceForNamespace(t *testing.T) {
|
||||||
namespace: "ns-1",
|
namespace: "ns-1",
|
||||||
resourcePath: "configmaps",
|
resourcePath: "configmaps",
|
||||||
labelSelector: labels.NewSelector(),
|
labelSelector: labels.NewSelector(),
|
||||||
fileSystem: newFakeFileSystem().
|
fileSystem: arktest.NewFakeFileSystem().
|
||||||
WithFile("configmaps/cm-1.json", newNamedTestConfigMap("cm-1").ToJSON()).
|
WithFile("configmaps/cm-1.json", newNamedTestConfigMap("cm-1").ToJSON()).
|
||||||
WithFile("configmaps/cm-2.json", newNamedTestConfigMap("cm-2").ToJSON()),
|
WithFile("configmaps/cm-2.json", newNamedTestConfigMap("cm-2").ToJSON()),
|
||||||
expectedObjs: toUnstructured(
|
expectedObjs: toUnstructured(
|
||||||
|
@ -385,7 +382,7 @@ func TestRestoreResourceForNamespace(t *testing.T) {
|
||||||
name: "no such directory causes error",
|
name: "no such directory causes error",
|
||||||
namespace: "ns-1",
|
namespace: "ns-1",
|
||||||
resourcePath: "configmaps",
|
resourcePath: "configmaps",
|
||||||
fileSystem: newFakeFileSystem(),
|
fileSystem: arktest.NewFakeFileSystem(),
|
||||||
expectedErrors: api.RestoreResult{
|
expectedErrors: api.RestoreResult{
|
||||||
Namespaces: map[string][]string{
|
Namespaces: map[string][]string{
|
||||||
"ns-1": {"error reading \"configmaps\" resource directory: open configmaps: file does not exist"},
|
"ns-1": {"error reading \"configmaps\" resource directory: open configmaps: file does not exist"},
|
||||||
|
@ -396,14 +393,14 @@ func TestRestoreResourceForNamespace(t *testing.T) {
|
||||||
name: "empty directory is no-op",
|
name: "empty directory is no-op",
|
||||||
namespace: "ns-1",
|
namespace: "ns-1",
|
||||||
resourcePath: "configmaps",
|
resourcePath: "configmaps",
|
||||||
fileSystem: newFakeFileSystem().WithDirectory("configmaps"),
|
fileSystem: arktest.NewFakeFileSystem().WithDirectory("configmaps"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "unmarshall failure does not cause immediate return",
|
name: "unmarshall failure does not cause immediate return",
|
||||||
namespace: "ns-1",
|
namespace: "ns-1",
|
||||||
resourcePath: "configmaps",
|
resourcePath: "configmaps",
|
||||||
labelSelector: labels.NewSelector(),
|
labelSelector: labels.NewSelector(),
|
||||||
fileSystem: newFakeFileSystem().
|
fileSystem: arktest.NewFakeFileSystem().
|
||||||
WithFile("configmaps/cm-1-invalid.json", []byte("this is not valid json")).
|
WithFile("configmaps/cm-1-invalid.json", []byte("this is not valid json")).
|
||||||
WithFile("configmaps/cm-2.json", newNamedTestConfigMap("cm-2").ToJSON()),
|
WithFile("configmaps/cm-2.json", newNamedTestConfigMap("cm-2").ToJSON()),
|
||||||
expectedErrors: api.RestoreResult{
|
expectedErrors: api.RestoreResult{
|
||||||
|
@ -418,7 +415,7 @@ func TestRestoreResourceForNamespace(t *testing.T) {
|
||||||
namespace: "ns-1",
|
namespace: "ns-1",
|
||||||
resourcePath: "configmaps",
|
resourcePath: "configmaps",
|
||||||
labelSelector: labels.SelectorFromSet(labels.Set(map[string]string{"foo": "bar"})),
|
labelSelector: labels.SelectorFromSet(labels.Set(map[string]string{"foo": "bar"})),
|
||||||
fileSystem: newFakeFileSystem().WithFile("configmaps/cm-1.json", newTestConfigMap().WithLabels(map[string]string{"foo": "bar"}).ToJSON()),
|
fileSystem: arktest.NewFakeFileSystem().WithFile("configmaps/cm-1.json", newTestConfigMap().WithLabels(map[string]string{"foo": "bar"}).ToJSON()),
|
||||||
expectedObjs: toUnstructured(newTestConfigMap().WithLabels(map[string]string{"foo": "bar"}).WithArkLabel("my-restore").ConfigMap),
|
expectedObjs: toUnstructured(newTestConfigMap().WithLabels(map[string]string{"foo": "bar"}).WithArkLabel("my-restore").ConfigMap),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -426,14 +423,14 @@ func TestRestoreResourceForNamespace(t *testing.T) {
|
||||||
namespace: "ns-1",
|
namespace: "ns-1",
|
||||||
resourcePath: "configmaps",
|
resourcePath: "configmaps",
|
||||||
labelSelector: labels.SelectorFromSet(labels.Set(map[string]string{"foo": "not-bar"})),
|
labelSelector: labels.SelectorFromSet(labels.Set(map[string]string{"foo": "not-bar"})),
|
||||||
fileSystem: newFakeFileSystem().WithFile("configmaps/cm-1.json", newTestConfigMap().WithLabels(map[string]string{"foo": "bar"}).ToJSON()),
|
fileSystem: arktest.NewFakeFileSystem().WithFile("configmaps/cm-1.json", newTestConfigMap().WithLabels(map[string]string{"foo": "bar"}).ToJSON()),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "items with controller owner are skipped",
|
name: "items with controller owner are skipped",
|
||||||
namespace: "ns-1",
|
namespace: "ns-1",
|
||||||
resourcePath: "configmaps",
|
resourcePath: "configmaps",
|
||||||
labelSelector: labels.NewSelector(),
|
labelSelector: labels.NewSelector(),
|
||||||
fileSystem: newFakeFileSystem().
|
fileSystem: arktest.NewFakeFileSystem().
|
||||||
WithFile("configmaps/cm-1.json", newTestConfigMap().WithControllerOwner().ToJSON()).
|
WithFile("configmaps/cm-1.json", newTestConfigMap().WithControllerOwner().ToJSON()).
|
||||||
WithFile("configmaps/cm-2.json", newNamedTestConfigMap("cm-2").ToJSON()),
|
WithFile("configmaps/cm-2.json", newNamedTestConfigMap("cm-2").ToJSON()),
|
||||||
expectedObjs: toUnstructured(newNamedTestConfigMap("cm-2").WithArkLabel("my-restore").ConfigMap),
|
expectedObjs: toUnstructured(newNamedTestConfigMap("cm-2").WithArkLabel("my-restore").ConfigMap),
|
||||||
|
@ -443,7 +440,7 @@ func TestRestoreResourceForNamespace(t *testing.T) {
|
||||||
namespace: "ns-2",
|
namespace: "ns-2",
|
||||||
resourcePath: "configmaps",
|
resourcePath: "configmaps",
|
||||||
labelSelector: labels.NewSelector(),
|
labelSelector: labels.NewSelector(),
|
||||||
fileSystem: newFakeFileSystem().WithFile("configmaps/cm-1.json", newTestConfigMap().WithNamespace("ns-1").ToJSON()),
|
fileSystem: arktest.NewFakeFileSystem().WithFile("configmaps/cm-1.json", newTestConfigMap().WithNamespace("ns-1").ToJSON()),
|
||||||
expectedObjs: toUnstructured(newTestConfigMap().WithNamespace("ns-2").WithArkLabel("my-restore").ConfigMap),
|
expectedObjs: toUnstructured(newTestConfigMap().WithNamespace("ns-2").WithArkLabel("my-restore").ConfigMap),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -451,7 +448,7 @@ func TestRestoreResourceForNamespace(t *testing.T) {
|
||||||
namespace: "ns-1",
|
namespace: "ns-1",
|
||||||
resourcePath: "configmaps",
|
resourcePath: "configmaps",
|
||||||
labelSelector: labels.NewSelector(),
|
labelSelector: labels.NewSelector(),
|
||||||
fileSystem: newFakeFileSystem().WithFile("configmaps/cm-1.json", newTestConfigMap().ToJSON()),
|
fileSystem: arktest.NewFakeFileSystem().WithFile("configmaps/cm-1.json", newTestConfigMap().ToJSON()),
|
||||||
actions: []resolvedAction{
|
actions: []resolvedAction{
|
||||||
{
|
{
|
||||||
ItemAction: newFakeAction("configmaps"),
|
ItemAction: newFakeAction("configmaps"),
|
||||||
|
@ -467,7 +464,7 @@ func TestRestoreResourceForNamespace(t *testing.T) {
|
||||||
namespace: "ns-1",
|
namespace: "ns-1",
|
||||||
resourcePath: "configmaps",
|
resourcePath: "configmaps",
|
||||||
labelSelector: labels.NewSelector(),
|
labelSelector: labels.NewSelector(),
|
||||||
fileSystem: newFakeFileSystem().WithFile("configmaps/cm-1.json", newTestConfigMap().ToJSON()),
|
fileSystem: arktest.NewFakeFileSystem().WithFile("configmaps/cm-1.json", newTestConfigMap().ToJSON()),
|
||||||
actions: []resolvedAction{
|
actions: []resolvedAction{
|
||||||
{
|
{
|
||||||
ItemAction: newFakeAction("foo-resource"),
|
ItemAction: newFakeAction("foo-resource"),
|
||||||
|
@ -484,7 +481,7 @@ func TestRestoreResourceForNamespace(t *testing.T) {
|
||||||
resourcePath: "persistentvolumes",
|
resourcePath: "persistentvolumes",
|
||||||
labelSelector: labels.NewSelector(),
|
labelSelector: labels.NewSelector(),
|
||||||
includeClusterResources: falsePtr,
|
includeClusterResources: falsePtr,
|
||||||
fileSystem: newFakeFileSystem().WithFile("persistentvolumes/pv-1.json", newTestPV().ToJSON()),
|
fileSystem: arktest.NewFakeFileSystem().WithFile("persistentvolumes/pv-1.json", newTestPV().ToJSON()),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "namespaced resources are not skipped when IncludeClusterResources=false",
|
name: "namespaced resources are not skipped when IncludeClusterResources=false",
|
||||||
|
@ -492,7 +489,7 @@ func TestRestoreResourceForNamespace(t *testing.T) {
|
||||||
resourcePath: "configmaps",
|
resourcePath: "configmaps",
|
||||||
labelSelector: labels.NewSelector(),
|
labelSelector: labels.NewSelector(),
|
||||||
includeClusterResources: falsePtr,
|
includeClusterResources: falsePtr,
|
||||||
fileSystem: newFakeFileSystem().WithFile("configmaps/cm-1.json", newTestConfigMap().ToJSON()),
|
fileSystem: arktest.NewFakeFileSystem().WithFile("configmaps/cm-1.json", newTestConfigMap().ToJSON()),
|
||||||
expectedObjs: toUnstructured(newTestConfigMap().WithArkLabel("my-restore").ConfigMap),
|
expectedObjs: toUnstructured(newTestConfigMap().WithArkLabel("my-restore").ConfigMap),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -501,7 +498,7 @@ func TestRestoreResourceForNamespace(t *testing.T) {
|
||||||
resourcePath: "persistentvolumes",
|
resourcePath: "persistentvolumes",
|
||||||
labelSelector: labels.NewSelector(),
|
labelSelector: labels.NewSelector(),
|
||||||
includeClusterResources: truePtr,
|
includeClusterResources: truePtr,
|
||||||
fileSystem: newFakeFileSystem().WithFile("persistentvolumes/pv-1.json", newTestPV().ToJSON()),
|
fileSystem: arktest.NewFakeFileSystem().WithFile("persistentvolumes/pv-1.json", newTestPV().ToJSON()),
|
||||||
expectedObjs: toUnstructured(newTestPV().WithArkLabel("my-restore").PersistentVolume),
|
expectedObjs: toUnstructured(newTestPV().WithArkLabel("my-restore").PersistentVolume),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -510,7 +507,7 @@ func TestRestoreResourceForNamespace(t *testing.T) {
|
||||||
resourcePath: "configmaps",
|
resourcePath: "configmaps",
|
||||||
labelSelector: labels.NewSelector(),
|
labelSelector: labels.NewSelector(),
|
||||||
includeClusterResources: truePtr,
|
includeClusterResources: truePtr,
|
||||||
fileSystem: newFakeFileSystem().WithFile("configmaps/cm-1.json", newTestConfigMap().ToJSON()),
|
fileSystem: arktest.NewFakeFileSystem().WithFile("configmaps/cm-1.json", newTestConfigMap().ToJSON()),
|
||||||
expectedObjs: toUnstructured(newTestConfigMap().WithArkLabel("my-restore").ConfigMap),
|
expectedObjs: toUnstructured(newTestConfigMap().WithArkLabel("my-restore").ConfigMap),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -519,7 +516,7 @@ func TestRestoreResourceForNamespace(t *testing.T) {
|
||||||
resourcePath: "persistentvolumes",
|
resourcePath: "persistentvolumes",
|
||||||
labelSelector: labels.NewSelector(),
|
labelSelector: labels.NewSelector(),
|
||||||
includeClusterResources: nil,
|
includeClusterResources: nil,
|
||||||
fileSystem: newFakeFileSystem().WithFile("persistentvolumes/pv-1.json", newTestPV().ToJSON()),
|
fileSystem: arktest.NewFakeFileSystem().WithFile("persistentvolumes/pv-1.json", newTestPV().ToJSON()),
|
||||||
expectedObjs: toUnstructured(newTestPV().WithArkLabel("my-restore").PersistentVolume),
|
expectedObjs: toUnstructured(newTestPV().WithArkLabel("my-restore").PersistentVolume),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -528,7 +525,7 @@ func TestRestoreResourceForNamespace(t *testing.T) {
|
||||||
resourcePath: "configmaps",
|
resourcePath: "configmaps",
|
||||||
labelSelector: labels.NewSelector(),
|
labelSelector: labels.NewSelector(),
|
||||||
includeClusterResources: nil,
|
includeClusterResources: nil,
|
||||||
fileSystem: newFakeFileSystem().WithFile("configmaps/cm-1.json", newTestConfigMap().ToJSON()),
|
fileSystem: arktest.NewFakeFileSystem().WithFile("configmaps/cm-1.json", newTestConfigMap().ToJSON()),
|
||||||
expectedObjs: toUnstructured(newTestConfigMap().WithArkLabel("my-restore").ConfigMap),
|
expectedObjs: toUnstructured(newTestConfigMap().WithArkLabel("my-restore").ConfigMap),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1210,68 +1207,6 @@ func (cm *testConfigMap) ToJSON() []byte {
|
||||||
return bytes
|
return bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
type fakeFileSystem struct {
|
|
||||||
fs afero.Fs
|
|
||||||
|
|
||||||
readDirCalls []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func newFakeFileSystem() *fakeFileSystem {
|
|
||||||
return &fakeFileSystem{
|
|
||||||
fs: afero.NewMemMapFs(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fs *fakeFileSystem) WithFile(path string, data []byte) *fakeFileSystem {
|
|
||||||
file, _ := fs.fs.Create(path)
|
|
||||||
file.Write(data)
|
|
||||||
file.Close()
|
|
||||||
|
|
||||||
return fs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fs *fakeFileSystem) WithDirectory(path string) *fakeFileSystem {
|
|
||||||
fs.fs.MkdirAll(path, 0755)
|
|
||||||
return fs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fs *fakeFileSystem) WithDirectories(path ...string) *fakeFileSystem {
|
|
||||||
for _, dir := range path {
|
|
||||||
fs = fs.WithDirectory(dir)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fs *fakeFileSystem) TempDir(dir, prefix string) (string, error) {
|
|
||||||
return afero.TempDir(fs.fs, dir, prefix)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fs *fakeFileSystem) MkdirAll(path string, perm os.FileMode) error {
|
|
||||||
return fs.fs.MkdirAll(path, perm)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fs *fakeFileSystem) Create(name string) (io.WriteCloser, error) {
|
|
||||||
return fs.fs.Create(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fs *fakeFileSystem) RemoveAll(path string) error {
|
|
||||||
return fs.fs.RemoveAll(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fs *fakeFileSystem) ReadDir(dirname string) ([]os.FileInfo, error) {
|
|
||||||
fs.readDirCalls = append(fs.readDirCalls, dirname)
|
|
||||||
return afero.ReadDir(fs.fs, dirname)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fs *fakeFileSystem) ReadFile(filename string) ([]byte, error) {
|
|
||||||
return afero.ReadFile(fs.fs, filename)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fs *fakeFileSystem) DirExists(path string) (bool, error) {
|
|
||||||
return afero.DirExists(fs.fs, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
type fakeAction struct {
|
type fakeAction struct {
|
||||||
resource string
|
resource string
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
Copyright 2017 the Heptio Ark contributors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package filesystem
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Interface defines methods for interacting with an
|
||||||
|
// underlying file system.
|
||||||
|
type Interface interface {
|
||||||
|
TempDir(dir, prefix string) (string, error)
|
||||||
|
MkdirAll(path string, perm os.FileMode) error
|
||||||
|
Create(name string) (io.WriteCloser, error)
|
||||||
|
RemoveAll(path string) error
|
||||||
|
ReadDir(dirname string) ([]os.FileInfo, error)
|
||||||
|
ReadFile(filename string) ([]byte, error)
|
||||||
|
DirExists(path string) (bool, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFileSystem() Interface {
|
||||||
|
return &osFileSystem{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type osFileSystem struct{}
|
||||||
|
|
||||||
|
func (fs *osFileSystem) TempDir(dir, prefix string) (string, error) {
|
||||||
|
return ioutil.TempDir(dir, prefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *osFileSystem) MkdirAll(path string, perm os.FileMode) error {
|
||||||
|
return os.MkdirAll(path, perm)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *osFileSystem) Create(name string) (io.WriteCloser, error) {
|
||||||
|
return os.Create(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *osFileSystem) RemoveAll(path string) error {
|
||||||
|
return os.RemoveAll(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *osFileSystem) ReadDir(dirname string) ([]os.FileInfo, error) {
|
||||||
|
return ioutil.ReadDir(dirname)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *osFileSystem) ReadFile(filename string) ([]byte, error) {
|
||||||
|
return ioutil.ReadFile(filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *osFileSystem) DirExists(path string) (bool, error) {
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
if err == nil {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return false, err
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/spf13/afero"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FakeFileSystem struct {
|
||||||
|
fs afero.Fs
|
||||||
|
|
||||||
|
ReadDirCalls []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFakeFileSystem() *FakeFileSystem {
|
||||||
|
return &FakeFileSystem{
|
||||||
|
fs: afero.NewMemMapFs(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *FakeFileSystem) TempDir(dir, prefix string) (string, error) {
|
||||||
|
return afero.TempDir(fs.fs, dir, prefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *FakeFileSystem) MkdirAll(path string, perm os.FileMode) error {
|
||||||
|
return fs.fs.MkdirAll(path, perm)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *FakeFileSystem) Create(name string) (io.WriteCloser, error) {
|
||||||
|
return fs.fs.Create(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *FakeFileSystem) RemoveAll(path string) error {
|
||||||
|
return fs.fs.RemoveAll(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *FakeFileSystem) ReadDir(dirname string) ([]os.FileInfo, error) {
|
||||||
|
fs.ReadDirCalls = append(fs.ReadDirCalls, dirname)
|
||||||
|
return afero.ReadDir(fs.fs, dirname)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *FakeFileSystem) ReadFile(filename string) ([]byte, error) {
|
||||||
|
return afero.ReadFile(fs.fs, filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *FakeFileSystem) DirExists(path string) (bool, error) {
|
||||||
|
return afero.DirExists(fs.fs, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *FakeFileSystem) WithFile(path string, data []byte) *FakeFileSystem {
|
||||||
|
file, _ := fs.fs.Create(path)
|
||||||
|
file.Write(data)
|
||||||
|
file.Close()
|
||||||
|
|
||||||
|
return fs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *FakeFileSystem) WithDirectory(path string) *FakeFileSystem {
|
||||||
|
fs.fs.MkdirAll(path, 0755)
|
||||||
|
return fs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *FakeFileSystem) WithDirectories(path ...string) *FakeFileSystem {
|
||||||
|
for _, dir := range path {
|
||||||
|
fs = fs.WithDirectory(dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fs
|
||||||
|
}
|
Loading…
Reference in New Issue