Update tests to use object builders in pkg/builder (#1707)
* add pkg/builder with BackupBuilder and ObjectMeta functional options Signed-off-by: Steve Kriss <krisss@vmware.com>pull/1694/head
parent
22eca22ac8
commit
4543258970
pkg
builder
cmd/cli
serverstatusrequest
test
|
@ -1,178 +0,0 @@
|
|||
/*
|
||||
Copyright 2019 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.
|
||||
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 backup
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
velerov1api "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
)
|
||||
|
||||
// Builder is a helper for concisely constructing Backup API objects.
|
||||
type Builder struct {
|
||||
backup velerov1api.Backup
|
||||
}
|
||||
|
||||
// NewBuilder returns a Builder for a Backup with no namespace/name.
|
||||
func NewBuilder() *Builder {
|
||||
return NewNamedBackupBuilder("", "")
|
||||
}
|
||||
|
||||
// NewNamedBackupBuilder returns a Builder for a Backup with the specified namespace
|
||||
// and name.
|
||||
func NewNamedBackupBuilder(namespace, name string) *Builder {
|
||||
return &Builder{
|
||||
backup: velerov1api.Backup{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: velerov1api.SchemeGroupVersion.String(),
|
||||
Kind: "Backup",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Backup returns the built Backup API object.
|
||||
func (b *Builder) Backup() *velerov1api.Backup {
|
||||
return &b.backup
|
||||
}
|
||||
|
||||
// Namespace sets the Backup's namespace.
|
||||
func (b *Builder) Namespace(namespace string) *Builder {
|
||||
b.backup.Namespace = namespace
|
||||
return b
|
||||
}
|
||||
|
||||
// Name sets the Backup's name.
|
||||
func (b *Builder) Name(name string) *Builder {
|
||||
b.backup.Name = name
|
||||
return b
|
||||
}
|
||||
|
||||
// Labels sets the Backup's labels.
|
||||
func (b *Builder) Labels(vals ...string) *Builder {
|
||||
if b.backup.Labels == nil {
|
||||
b.backup.Labels = map[string]string{}
|
||||
}
|
||||
|
||||
// if we don't have an even number of values, e.g. a key and a value
|
||||
// for each pair, add an empty-string value at the end to serve as
|
||||
// the default value for the last key.
|
||||
if len(vals)%2 != 0 {
|
||||
vals = append(vals, "")
|
||||
}
|
||||
|
||||
for i := 0; i < len(vals); i += 2 {
|
||||
b.backup.Labels[vals[i]] = vals[i+1]
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// IncludedNamespaces sets the Backup's included namespaces.
|
||||
func (b *Builder) IncludedNamespaces(namespaces ...string) *Builder {
|
||||
b.backup.Spec.IncludedNamespaces = namespaces
|
||||
return b
|
||||
}
|
||||
|
||||
// ExcludedNamespaces sets the Backup's excluded namespaces.
|
||||
func (b *Builder) ExcludedNamespaces(namespaces ...string) *Builder {
|
||||
b.backup.Spec.ExcludedNamespaces = namespaces
|
||||
return b
|
||||
}
|
||||
|
||||
// IncludedResources sets the Backup's included resources.
|
||||
func (b *Builder) IncludedResources(resources ...string) *Builder {
|
||||
b.backup.Spec.IncludedResources = resources
|
||||
return b
|
||||
}
|
||||
|
||||
// ExcludedResources sets the Backup's excluded resources.
|
||||
func (b *Builder) ExcludedResources(resources ...string) *Builder {
|
||||
b.backup.Spec.ExcludedResources = resources
|
||||
return b
|
||||
}
|
||||
|
||||
// IncludeClusterResources sets the Backup's "include cluster resources" flag.
|
||||
func (b *Builder) IncludeClusterResources(val bool) *Builder {
|
||||
b.backup.Spec.IncludeClusterResources = &val
|
||||
return b
|
||||
}
|
||||
|
||||
// LabelSelector sets the Backup's label selector.
|
||||
func (b *Builder) LabelSelector(selector *metav1.LabelSelector) *Builder {
|
||||
b.backup.Spec.LabelSelector = selector
|
||||
return b
|
||||
}
|
||||
|
||||
// SnapshotVolumes sets the Backup's "snapshot volumes" flag.
|
||||
func (b *Builder) SnapshotVolumes(val bool) *Builder {
|
||||
b.backup.Spec.SnapshotVolumes = &val
|
||||
return b
|
||||
}
|
||||
|
||||
// Phase sets the Backup's phase.
|
||||
func (b *Builder) Phase(phase velerov1api.BackupPhase) *Builder {
|
||||
b.backup.Status.Phase = phase
|
||||
return b
|
||||
}
|
||||
|
||||
// StorageLocation sets the Backup's storage location.
|
||||
func (b *Builder) StorageLocation(location string) *Builder {
|
||||
b.backup.Spec.StorageLocation = location
|
||||
return b
|
||||
}
|
||||
|
||||
// VolumeSnapshotLocations sets the Backup's volume snapshot locations.
|
||||
func (b *Builder) VolumeSnapshotLocations(locations ...string) *Builder {
|
||||
b.backup.Spec.VolumeSnapshotLocations = locations
|
||||
return b
|
||||
}
|
||||
|
||||
// TTL sets the Backup's TTL.
|
||||
func (b *Builder) TTL(ttl time.Duration) *Builder {
|
||||
b.backup.Spec.TTL.Duration = ttl
|
||||
return b
|
||||
}
|
||||
|
||||
// Expiration sets the Backup's expiration.
|
||||
func (b *Builder) Expiration(val time.Time) *Builder {
|
||||
b.backup.Status.Expiration.Time = val
|
||||
return b
|
||||
}
|
||||
|
||||
// StartTimestamp sets the Backup's start timestamp.
|
||||
func (b *Builder) StartTimestamp(val time.Time) *Builder {
|
||||
b.backup.Status.StartTimestamp.Time = val
|
||||
return b
|
||||
}
|
||||
|
||||
// NoTypeMeta removes the type meta from the Backup.
|
||||
func (b *Builder) NoTypeMeta() *Builder {
|
||||
b.backup.TypeMeta = metav1.TypeMeta{}
|
||||
return b
|
||||
}
|
||||
|
||||
// Hooks sets the Backup's hooks.
|
||||
func (b *Builder) Hooks(hooks velerov1api.BackupHooks) *Builder {
|
||||
b.backup.Spec.Hooks = hooks
|
||||
return b
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
Copyright 2019 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.
|
||||
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 backup
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
velerov1api "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
)
|
||||
|
||||
// PodVolumeBackupBuilder is a helper for concisely constructing PodVolumeBackup API objects.
|
||||
type PodVolumeBackupBuilder struct {
|
||||
podVolumeBackup velerov1api.PodVolumeBackup
|
||||
}
|
||||
|
||||
// NewPodVolumeBackupBuilder returns a PodVolumeBackupBuilder for a PodVolumeBackup with no namespace/name.
|
||||
func NewPodVolumeBackupBuilder() *PodVolumeBackupBuilder {
|
||||
return NewNamedPodVolumeBackupBuilder("", "")
|
||||
}
|
||||
|
||||
// NewNamedPodVolumeBackupBuilder returns a PodVolumeBackupBuilder for a Backup with the specified namespace
|
||||
// and name.
|
||||
func NewNamedPodVolumeBackupBuilder(namespace, name string) *PodVolumeBackupBuilder {
|
||||
return &PodVolumeBackupBuilder{
|
||||
podVolumeBackup: velerov1api.PodVolumeBackup{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: velerov1api.SchemeGroupVersion.String(),
|
||||
Kind: "PodVolumeBackup",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// PodVolumeBackup returns the built PodVolumeBackup API object.
|
||||
func (p *PodVolumeBackupBuilder) PodVolumeBackup() *velerov1api.PodVolumeBackup {
|
||||
return &p.podVolumeBackup
|
||||
}
|
||||
|
||||
// Namespace sets the PodVolumeBackup's namespace.
|
||||
func (p *PodVolumeBackupBuilder) Namespace(namespace string) *PodVolumeBackupBuilder {
|
||||
p.podVolumeBackup.Namespace = namespace
|
||||
return p
|
||||
}
|
||||
|
||||
// Name sets the PodVolumeBackup's name.
|
||||
func (p *PodVolumeBackupBuilder) Name(name string) *PodVolumeBackupBuilder {
|
||||
p.podVolumeBackup.Name = name
|
||||
return p
|
||||
}
|
||||
|
||||
// Labels sets the PodVolumeBackup's labels.
|
||||
func (p *PodVolumeBackupBuilder) Labels(vals ...string) *PodVolumeBackupBuilder {
|
||||
if p.podVolumeBackup.Labels == nil {
|
||||
p.podVolumeBackup.Labels = map[string]string{}
|
||||
}
|
||||
|
||||
// if we don't have an even number of values, e.g. a key and a value
|
||||
// for each pair, add an empty-string value at the end to serve as
|
||||
// the default value for the last key.
|
||||
if len(vals)%2 != 0 {
|
||||
vals = append(vals, "")
|
||||
}
|
||||
|
||||
for i := 0; i < len(vals); i += 2 {
|
||||
p.podVolumeBackup.Labels[vals[i]] = vals[i+1]
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Phase sets the PodVolumeBackup's phase.
|
||||
func (p *PodVolumeBackupBuilder) Phase(phase velerov1api.PodVolumeBackupPhase) *PodVolumeBackupBuilder {
|
||||
p.podVolumeBackup.Status.Phase = phase
|
||||
return p
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
Copyright 2019 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.
|
||||
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 builder
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
velerov1api "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
)
|
||||
|
||||
/*
|
||||
|
||||
Example usage:
|
||||
|
||||
var backup = builder.ForBackup("velero", "backup-1").
|
||||
ObjectMeta(
|
||||
builder.WithLabels("foo", "bar"),
|
||||
builder.WithClusterName("cluster-1"),
|
||||
).
|
||||
SnapshotVolumes(true).
|
||||
Result()
|
||||
|
||||
*/
|
||||
|
||||
// BackupBuilder builds Backup objects.
|
||||
type BackupBuilder struct {
|
||||
object *velerov1api.Backup
|
||||
}
|
||||
|
||||
// ForBackup is the constructor for a BackupBuilder.
|
||||
func ForBackup(ns, name string) *BackupBuilder {
|
||||
return &BackupBuilder{
|
||||
object: &velerov1api.Backup{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: velerov1api.SchemeGroupVersion.String(),
|
||||
Kind: "Backup",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Result returns the built Backup.
|
||||
func (b *BackupBuilder) Result() *velerov1api.Backup {
|
||||
return b.object
|
||||
}
|
||||
|
||||
// ObjectMeta applies functional options to the Backup's ObjectMeta.
|
||||
func (b *BackupBuilder) ObjectMeta(opts ...ObjectMetaOpt) *BackupBuilder {
|
||||
for _, opt := range opts {
|
||||
opt(b.object)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// IncludedNamespaces sets the Backup's included namespaces.
|
||||
func (b *BackupBuilder) IncludedNamespaces(namespaces ...string) *BackupBuilder {
|
||||
b.object.Spec.IncludedNamespaces = namespaces
|
||||
return b
|
||||
}
|
||||
|
||||
// ExcludedNamespaces sets the Backup's excluded namespaces.
|
||||
func (b *BackupBuilder) ExcludedNamespaces(namespaces ...string) *BackupBuilder {
|
||||
b.object.Spec.ExcludedNamespaces = namespaces
|
||||
return b
|
||||
}
|
||||
|
||||
// IncludedResources sets the Backup's included resources.
|
||||
func (b *BackupBuilder) IncludedResources(resources ...string) *BackupBuilder {
|
||||
b.object.Spec.IncludedResources = resources
|
||||
return b
|
||||
}
|
||||
|
||||
// ExcludedResources sets the Backup's excluded resources.
|
||||
func (b *BackupBuilder) ExcludedResources(resources ...string) *BackupBuilder {
|
||||
b.object.Spec.ExcludedResources = resources
|
||||
return b
|
||||
}
|
||||
|
||||
// IncludeClusterResources sets the Backup's "include cluster resources" flag.
|
||||
func (b *BackupBuilder) IncludeClusterResources(val bool) *BackupBuilder {
|
||||
b.object.Spec.IncludeClusterResources = &val
|
||||
return b
|
||||
}
|
||||
|
||||
// LabelSelector sets the Backup's label selector.
|
||||
func (b *BackupBuilder) LabelSelector(selector *metav1.LabelSelector) *BackupBuilder {
|
||||
b.object.Spec.LabelSelector = selector
|
||||
return b
|
||||
}
|
||||
|
||||
// SnapshotVolumes sets the Backup's "snapshot volumes" flag.
|
||||
func (b *BackupBuilder) SnapshotVolumes(val bool) *BackupBuilder {
|
||||
b.object.Spec.SnapshotVolumes = &val
|
||||
return b
|
||||
}
|
||||
|
||||
// Phase sets the Backup's phase.
|
||||
func (b *BackupBuilder) Phase(phase velerov1api.BackupPhase) *BackupBuilder {
|
||||
b.object.Status.Phase = phase
|
||||
return b
|
||||
}
|
||||
|
||||
// StorageLocation sets the Backup's storage location.
|
||||
func (b *BackupBuilder) StorageLocation(location string) *BackupBuilder {
|
||||
b.object.Spec.StorageLocation = location
|
||||
return b
|
||||
}
|
||||
|
||||
// VolumeSnapshotLocations sets the Backup's volume snapshot locations.
|
||||
func (b *BackupBuilder) VolumeSnapshotLocations(locations ...string) *BackupBuilder {
|
||||
b.object.Spec.VolumeSnapshotLocations = locations
|
||||
return b
|
||||
}
|
||||
|
||||
// TTL sets the Backup's TTL.
|
||||
func (b *BackupBuilder) TTL(ttl time.Duration) *BackupBuilder {
|
||||
b.object.Spec.TTL.Duration = ttl
|
||||
return b
|
||||
}
|
||||
|
||||
// Expiration sets the Backup's expiration.
|
||||
func (b *BackupBuilder) Expiration(val time.Time) *BackupBuilder {
|
||||
b.object.Status.Expiration.Time = val
|
||||
return b
|
||||
}
|
||||
|
||||
// StartTimestamp sets the Backup's start timestamp.
|
||||
func (b *BackupBuilder) StartTimestamp(val time.Time) *BackupBuilder {
|
||||
b.object.Status.StartTimestamp.Time = val
|
||||
return b
|
||||
}
|
||||
|
||||
// NoTypeMeta removes the type meta from the Backup.
|
||||
func (b *BackupBuilder) NoTypeMeta() *BackupBuilder {
|
||||
b.object.TypeMeta = metav1.TypeMeta{}
|
||||
return b
|
||||
}
|
||||
|
||||
// Hooks sets the Backup's hooks.
|
||||
func (b *BackupBuilder) Hooks(hooks velerov1api.BackupHooks) *BackupBuilder {
|
||||
b.object.Spec.Hooks = hooks
|
||||
return b
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
Copyright 2017, 2019 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.
|
||||
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 builder
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
velerov1api "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
)
|
||||
|
||||
// BackupStorageLocationBuilder builds BackupStorageLocation objects.
|
||||
type BackupStorageLocationBuilder struct {
|
||||
object *velerov1api.BackupStorageLocation
|
||||
}
|
||||
|
||||
// ForBackupStorageLocation is the constructor for a BackupStorageLocationBuilder.
|
||||
func ForBackupStorageLocation(ns, name string) *BackupStorageLocationBuilder {
|
||||
return &BackupStorageLocationBuilder{
|
||||
object: &velerov1api.BackupStorageLocation{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: velerov1api.SchemeGroupVersion.String(),
|
||||
Kind: "BackupStorageLocation",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Result returns the built BackupStorageLocation.
|
||||
func (b *BackupStorageLocationBuilder) Result() *velerov1api.BackupStorageLocation {
|
||||
return b.object
|
||||
}
|
||||
|
||||
// ObjectMeta applies functional options to the BackupStorageLocation's ObjectMeta.
|
||||
func (b *BackupStorageLocationBuilder) ObjectMeta(opts ...ObjectMetaOpt) *BackupStorageLocationBuilder {
|
||||
for _, opt := range opts {
|
||||
opt(b.object)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// Provider sets the BackupStorageLocation's provider.
|
||||
func (b *BackupStorageLocationBuilder) Provider(name string) *BackupStorageLocationBuilder {
|
||||
b.object.Spec.Provider = name
|
||||
return b
|
||||
}
|
||||
|
||||
// ObjectStorage sets the BackupStorageLocation's object storage.
|
||||
func (b *BackupStorageLocationBuilder) ObjectStorage(bucketName string) *BackupStorageLocationBuilder {
|
||||
if b.object.Spec.StorageType.ObjectStorage == nil {
|
||||
b.object.Spec.StorageType.ObjectStorage = new(velerov1api.ObjectStorageLocation)
|
||||
}
|
||||
b.object.Spec.ObjectStorage.Bucket = bucketName
|
||||
return b
|
||||
}
|
||||
|
||||
// AccessMode sets the BackupStorageLocation's access mode.
|
||||
func (b *BackupStorageLocationBuilder) AccessMode(accessMode velerov1api.BackupStorageLocationAccessMode) *BackupStorageLocationBuilder {
|
||||
b.object.Spec.AccessMode = accessMode
|
||||
return b
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
Copyright 2019 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.
|
||||
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 builder
|
||||
|
||||
import (
|
||||
corev1api "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// ConfigMapBuilder builds ConfigMap objects.
|
||||
type ConfigMapBuilder struct {
|
||||
object *corev1api.ConfigMap
|
||||
}
|
||||
|
||||
// ForConfigMap is the constructor for a ConfigMapBuilder.
|
||||
func ForConfigMap(ns, name string) *ConfigMapBuilder {
|
||||
return &ConfigMapBuilder{
|
||||
object: &corev1api.ConfigMap{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: corev1api.SchemeGroupVersion.String(),
|
||||
Kind: "ConfigMap",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Result returns the built ConfigMap.
|
||||
func (b *ConfigMapBuilder) Result() *corev1api.ConfigMap {
|
||||
return b.object
|
||||
}
|
||||
|
||||
// ObjectMeta applies functional options to the ConfigMap's ObjectMeta.
|
||||
func (b *ConfigMapBuilder) ObjectMeta(opts ...ObjectMetaOpt) *ConfigMapBuilder {
|
||||
for _, opt := range opts {
|
||||
opt(b.object)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// Data set's the ConfigMap's data.
|
||||
func (b *ConfigMapBuilder) Data(vals ...string) *ConfigMapBuilder {
|
||||
b.object.Data = setMapEntries(b.object.Data, vals...)
|
||||
return b
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
Copyright 2019 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.
|
||||
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 builder
|
||||
|
||||
import (
|
||||
appsv1api "k8s.io/api/apps/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// DeploymentBuilder builds Deployment objects.
|
||||
type DeploymentBuilder struct {
|
||||
object *appsv1api.Deployment
|
||||
}
|
||||
|
||||
// ForDeployment is the constructor for a DeploymentBuilder.
|
||||
func ForDeployment(ns, name string) *DeploymentBuilder {
|
||||
return &DeploymentBuilder{
|
||||
object: &appsv1api.Deployment{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: appsv1api.SchemeGroupVersion.String(),
|
||||
Kind: "Deployment",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Result returns the built Deployment.
|
||||
func (b *DeploymentBuilder) Result() *appsv1api.Deployment {
|
||||
return b.object
|
||||
}
|
||||
|
||||
// ObjectMeta applies functional options to the Deployment's ObjectMeta.
|
||||
func (b *DeploymentBuilder) ObjectMeta(opts ...ObjectMetaOpt) *DeploymentBuilder {
|
||||
for _, opt := range opts {
|
||||
opt(b.object)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
Copyright 2019 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.
|
||||
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 builder
|
||||
|
||||
import (
|
||||
corev1api "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// NamespaceBuilder builds Namespace objects.
|
||||
type NamespaceBuilder struct {
|
||||
object *corev1api.Namespace
|
||||
}
|
||||
|
||||
// ForNamespace is the constructor for a NamespaceBuilder.
|
||||
func ForNamespace(name string) *NamespaceBuilder {
|
||||
return &NamespaceBuilder{
|
||||
object: &corev1api.Namespace{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: corev1api.SchemeGroupVersion.String(),
|
||||
Kind: "Namespace",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Result returns the built Namespace.
|
||||
func (b *NamespaceBuilder) Result() *corev1api.Namespace {
|
||||
return b.object
|
||||
}
|
||||
|
||||
// ObjectMeta applies functional options to the Namespace's ObjectMeta.
|
||||
func (b *NamespaceBuilder) ObjectMeta(opts ...ObjectMetaOpt) *NamespaceBuilder {
|
||||
for _, opt := range opts {
|
||||
opt(b.object)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// Phase sets the namespace's phase
|
||||
func (b *NamespaceBuilder) Phase(val corev1api.NamespacePhase) *NamespaceBuilder {
|
||||
b.object.Status.Phase = val
|
||||
return b
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
Copyright 2019 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.
|
||||
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 builder
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
// ObjectMetaOpt is a functional option for ObjectMeta.
|
||||
type ObjectMetaOpt func(metav1.Object)
|
||||
|
||||
// WithName is a functional option that applies the specified
|
||||
// name to an object.
|
||||
func WithName(val string) func(obj metav1.Object) {
|
||||
return func(obj metav1.Object) {
|
||||
obj.SetName(val)
|
||||
}
|
||||
}
|
||||
|
||||
// WithLabels is a functional option that applies the specified
|
||||
// label keys/values to an object.
|
||||
func WithLabels(vals ...string) func(obj metav1.Object) {
|
||||
return func(obj metav1.Object) {
|
||||
obj.SetLabels(setMapEntries(obj.GetLabels(), vals...))
|
||||
}
|
||||
}
|
||||
|
||||
// WithAnnotations is a functional option that applies the specified
|
||||
// annotation keys/values to an object.
|
||||
func WithAnnotations(vals ...string) func(obj metav1.Object) {
|
||||
return func(obj metav1.Object) {
|
||||
obj.SetAnnotations(setMapEntries(obj.GetAnnotations(), vals...))
|
||||
}
|
||||
}
|
||||
|
||||
func setMapEntries(m map[string]string, vals ...string) map[string]string {
|
||||
if m == nil {
|
||||
m = make(map[string]string)
|
||||
}
|
||||
|
||||
// if we don't have a value for every key, add an empty
|
||||
// string at the end to serve as the value for the last
|
||||
// key.
|
||||
if len(vals)%2 != 0 {
|
||||
vals = append(vals, "")
|
||||
}
|
||||
|
||||
for i := 0; i < len(vals); i += 2 {
|
||||
key := vals[i]
|
||||
val := vals[i+1]
|
||||
|
||||
m[key] = val
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// WithClusterName is a functional option that applies the specified
|
||||
// cluster name to an object.
|
||||
func WithClusterName(val string) func(obj metav1.Object) {
|
||||
return func(obj metav1.Object) {
|
||||
obj.SetClusterName(val)
|
||||
}
|
||||
}
|
||||
|
||||
// WithFinalizers is a functional option that applies the specified
|
||||
// finalizers to an object.
|
||||
func WithFinalizers(vals ...string) func(obj metav1.Object) {
|
||||
return func(obj metav1.Object) {
|
||||
obj.SetFinalizers(vals)
|
||||
}
|
||||
}
|
||||
|
||||
// WithDeletionTimestamp is a functional option that applies the specified
|
||||
// deletion timestamp to an object.
|
||||
func WithDeletionTimestamp(val time.Time) func(obj metav1.Object) {
|
||||
return func(obj metav1.Object) {
|
||||
obj.SetDeletionTimestamp(&metav1.Time{Time: val})
|
||||
}
|
||||
}
|
||||
|
||||
// WithUID is a functional option that applies the specified UID to an object.
|
||||
func WithUID(val string) func(obj metav1.Object) {
|
||||
return func(obj metav1.Object) {
|
||||
obj.SetUID(types.UID(val))
|
||||
}
|
||||
}
|
||||
|
||||
// WithGenerateName is a functional option that applies the specified generate name to an object.
|
||||
func WithGenerateName(val string) func(obj metav1.Object) {
|
||||
return func(obj metav1.Object) {
|
||||
obj.SetGenerateName(val)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
Copyright 2019 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.
|
||||
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 builder
|
||||
|
||||
import (
|
||||
corev1api "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// PersistentVolumeBuilder builds PersistentVolume objects.
|
||||
type PersistentVolumeBuilder struct {
|
||||
object *corev1api.PersistentVolume
|
||||
}
|
||||
|
||||
// ForPersistentVolume is the constructor for a PersistentVolumeBuilder.
|
||||
func ForPersistentVolume(name string) *PersistentVolumeBuilder {
|
||||
return &PersistentVolumeBuilder{
|
||||
object: &corev1api.PersistentVolume{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: corev1api.SchemeGroupVersion.String(),
|
||||
Kind: "PersistentVolume",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Result returns the built PersistentVolume.
|
||||
func (b *PersistentVolumeBuilder) Result() *corev1api.PersistentVolume {
|
||||
return b.object
|
||||
}
|
||||
|
||||
// ObjectMeta applies functional options to the PersistentVolume's ObjectMeta.
|
||||
func (b *PersistentVolumeBuilder) ObjectMeta(opts ...ObjectMetaOpt) *PersistentVolumeBuilder {
|
||||
for _, opt := range opts {
|
||||
opt(b.object)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// ReclaimPolicy sets the PersistentVolume's reclaim policy.
|
||||
func (b *PersistentVolumeBuilder) ReclaimPolicy(policy corev1api.PersistentVolumeReclaimPolicy) *PersistentVolumeBuilder {
|
||||
b.object.Spec.PersistentVolumeReclaimPolicy = policy
|
||||
return b
|
||||
}
|
||||
|
||||
// ClaimRef sets the PersistentVolume's claim ref.
|
||||
func (b *PersistentVolumeBuilder) ClaimRef(ns, name string) *PersistentVolumeBuilder {
|
||||
b.object.Spec.ClaimRef = &corev1api.ObjectReference{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// AWSEBSVolumeID sets the PersistentVolume's AWSElasticBlockStore volume ID.
|
||||
func (b *PersistentVolumeBuilder) AWSEBSVolumeID(volumeID string) *PersistentVolumeBuilder {
|
||||
if b.object.Spec.AWSElasticBlockStore == nil {
|
||||
b.object.Spec.AWSElasticBlockStore = new(corev1api.AWSElasticBlockStoreVolumeSource)
|
||||
}
|
||||
b.object.Spec.AWSElasticBlockStore.VolumeID = volumeID
|
||||
return b
|
||||
}
|
||||
|
||||
// CSI sets the PersistentVolume's CSI.
|
||||
func (b *PersistentVolumeBuilder) CSI(driver, volumeHandle string) *PersistentVolumeBuilder {
|
||||
if b.object.Spec.CSI == nil {
|
||||
b.object.Spec.CSI = new(corev1api.CSIPersistentVolumeSource)
|
||||
}
|
||||
b.object.Spec.CSI.Driver = driver
|
||||
b.object.Spec.CSI.VolumeHandle = volumeHandle
|
||||
return b
|
||||
}
|
||||
|
||||
// StorageClass sets the PersistentVolume's storage class name.
|
||||
func (b *PersistentVolumeBuilder) StorageClass(name string) *PersistentVolumeBuilder {
|
||||
b.object.Spec.StorageClassName = name
|
||||
return b
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
Copyright 2019 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.
|
||||
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 builder
|
||||
|
||||
import (
|
||||
corev1api "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// PersistentVolumeClaimBuilder builds PersistentVolumeClaim objects.
|
||||
type PersistentVolumeClaimBuilder struct {
|
||||
object *corev1api.PersistentVolumeClaim
|
||||
}
|
||||
|
||||
// ForPersistentVolumeClaim is the constructor for a PersistentVolumeClaimBuilder.
|
||||
func ForPersistentVolumeClaim(ns, name string) *PersistentVolumeClaimBuilder {
|
||||
return &PersistentVolumeClaimBuilder{
|
||||
object: &corev1api.PersistentVolumeClaim{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: corev1api.SchemeGroupVersion.String(),
|
||||
Kind: "PersistentVolumeClaim",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Result returns the built PersistentVolumeClaim.
|
||||
func (b *PersistentVolumeClaimBuilder) Result() *corev1api.PersistentVolumeClaim {
|
||||
return b.object
|
||||
}
|
||||
|
||||
// ObjectMeta applies functional options to the PersistentVolumeClaim's ObjectMeta.
|
||||
func (b *PersistentVolumeClaimBuilder) ObjectMeta(opts ...ObjectMetaOpt) *PersistentVolumeClaimBuilder {
|
||||
for _, opt := range opts {
|
||||
opt(b.object)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// VolumeName sets the PersistentVolumeClaim's volume name.
|
||||
func (b *PersistentVolumeClaimBuilder) VolumeName(name string) *PersistentVolumeClaimBuilder {
|
||||
b.object.Spec.VolumeName = name
|
||||
return b
|
||||
}
|
||||
|
||||
// StorageClass sets the PersistentVolumeClaim's storage class name.
|
||||
func (b *PersistentVolumeClaimBuilder) StorageClass(name string) *PersistentVolumeClaimBuilder {
|
||||
b.object.Spec.StorageClassName = &name
|
||||
return b
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
Copyright 2019 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.
|
||||
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 builder
|
||||
|
||||
import (
|
||||
corev1api "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// PodBuilder builds Pod objects.
|
||||
type PodBuilder struct {
|
||||
object *corev1api.Pod
|
||||
}
|
||||
|
||||
// ForPod is the constructor for a PodBuilder.
|
||||
func ForPod(ns, name string) *PodBuilder {
|
||||
return &PodBuilder{
|
||||
object: &corev1api.Pod{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: corev1api.SchemeGroupVersion.String(),
|
||||
Kind: "Pod",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Result returns the built Pod.
|
||||
func (b *PodBuilder) Result() *corev1api.Pod {
|
||||
return b.object
|
||||
}
|
||||
|
||||
// ObjectMeta applies functional options to the Pod's ObjectMeta.
|
||||
func (b *PodBuilder) ObjectMeta(opts ...ObjectMetaOpt) *PodBuilder {
|
||||
for _, opt := range opts {
|
||||
opt(b.object)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// Volumes appends to the pod's volumes
|
||||
func (b *PodBuilder) Volumes(volumes ...*corev1api.Volume) *PodBuilder {
|
||||
for _, v := range volumes {
|
||||
b.object.Spec.Volumes = append(b.object.Spec.Volumes, *v)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// NodeName sets the pod's node name
|
||||
func (b *PodBuilder) NodeName(val string) *PodBuilder {
|
||||
b.object.Spec.NodeName = val
|
||||
return b
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
Copyright 2019 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.
|
||||
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 builder
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
velerov1api "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
)
|
||||
|
||||
// PodVolumeBackupBuilder builds PodVolumeBackup objects
|
||||
type PodVolumeBackupBuilder struct {
|
||||
object *velerov1api.PodVolumeBackup
|
||||
}
|
||||
|
||||
// ForPodVolumeBackup is the constructor for a PodVolumeBackupBuilder.
|
||||
func ForPodVolumeBackup(ns, name string) *PodVolumeBackupBuilder {
|
||||
return &PodVolumeBackupBuilder{
|
||||
object: &velerov1api.PodVolumeBackup{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: velerov1api.SchemeGroupVersion.String(),
|
||||
Kind: "PodVolumeBackup",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Result returns the built PodVolumeBackup.
|
||||
func (b *PodVolumeBackupBuilder) Result() *velerov1api.PodVolumeBackup {
|
||||
return b.object
|
||||
}
|
||||
|
||||
// ObjectMeta applies functional options to the PodVolumeBackup's ObjectMeta.
|
||||
func (b *PodVolumeBackupBuilder) ObjectMeta(opts ...ObjectMetaOpt) *PodVolumeBackupBuilder {
|
||||
for _, opt := range opts {
|
||||
opt(b.object)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// Phase sets the PodVolumeBackup's phase.
|
||||
func (b *PodVolumeBackupBuilder) Phase(phase velerov1api.PodVolumeBackupPhase) *PodVolumeBackupBuilder {
|
||||
b.object.Status.Phase = phase
|
||||
return b
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
Copyright 2019 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.
|
||||
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 builder
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
velerov1api "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
)
|
||||
|
||||
// RestoreBuilder builds Restore objects.
|
||||
type RestoreBuilder struct {
|
||||
object *velerov1api.Restore
|
||||
}
|
||||
|
||||
// ForRestore is the constructor for a RestoreBuilder.
|
||||
func ForRestore(ns, name string) *RestoreBuilder {
|
||||
return &RestoreBuilder{
|
||||
object: &velerov1api.Restore{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: velerov1api.SchemeGroupVersion.String(),
|
||||
Kind: "Restore",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Result returns the built Restore.
|
||||
func (b *RestoreBuilder) Result() *velerov1api.Restore {
|
||||
return b.object
|
||||
}
|
||||
|
||||
// ObjectMeta applies functional options to the Restore's ObjectMeta.
|
||||
func (b *RestoreBuilder) ObjectMeta(opts ...ObjectMetaOpt) *RestoreBuilder {
|
||||
for _, opt := range opts {
|
||||
opt(b.object)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// Backup sets the Restore's backup name.
|
||||
func (b *RestoreBuilder) Backup(name string) *RestoreBuilder {
|
||||
b.object.Spec.BackupName = name
|
||||
return b
|
||||
}
|
||||
|
||||
// Schedule sets the Restore's schedule name.
|
||||
func (b *RestoreBuilder) Schedule(name string) *RestoreBuilder {
|
||||
b.object.Spec.ScheduleName = name
|
||||
return b
|
||||
}
|
||||
|
||||
// IncludedNamespaces appends to the Restore's included namespaces.
|
||||
func (b *RestoreBuilder) IncludedNamespaces(namespaces ...string) *RestoreBuilder {
|
||||
b.object.Spec.IncludedNamespaces = append(b.object.Spec.IncludedNamespaces, namespaces...)
|
||||
return b
|
||||
}
|
||||
|
||||
// ExcludedNamespaces appends to the Restore's excluded namespaces.
|
||||
func (b *RestoreBuilder) ExcludedNamespaces(namespaces ...string) *RestoreBuilder {
|
||||
b.object.Spec.ExcludedNamespaces = append(b.object.Spec.ExcludedNamespaces, namespaces...)
|
||||
return b
|
||||
}
|
||||
|
||||
// IncludedResources appends to the Restore's included resources.
|
||||
func (b *RestoreBuilder) IncludedResources(resources ...string) *RestoreBuilder {
|
||||
b.object.Spec.IncludedResources = append(b.object.Spec.IncludedResources, resources...)
|
||||
return b
|
||||
}
|
||||
|
||||
// ExcludedResources appends to the Restore's excluded resources.
|
||||
func (b *RestoreBuilder) ExcludedResources(resources ...string) *RestoreBuilder {
|
||||
b.object.Spec.ExcludedResources = append(b.object.Spec.ExcludedResources, resources...)
|
||||
return b
|
||||
}
|
||||
|
||||
// IncludeClusterResources sets the Restore's "include cluster resources" flag.
|
||||
func (b *RestoreBuilder) IncludeClusterResources(val bool) *RestoreBuilder {
|
||||
b.object.Spec.IncludeClusterResources = &val
|
||||
return b
|
||||
}
|
||||
|
||||
// LabelSelector sets the Restore's label selector.
|
||||
func (b *RestoreBuilder) LabelSelector(selector *metav1.LabelSelector) *RestoreBuilder {
|
||||
b.object.Spec.LabelSelector = selector
|
||||
return b
|
||||
}
|
||||
|
||||
// NamespaceMappings sets the Restore's namespace mappings.
|
||||
func (b *RestoreBuilder) NamespaceMappings(mapping ...string) *RestoreBuilder {
|
||||
if b.object.Spec.NamespaceMapping == nil {
|
||||
b.object.Spec.NamespaceMapping = make(map[string]string)
|
||||
}
|
||||
|
||||
if len(mapping)%2 != 0 {
|
||||
panic("mapping must contain an even number of values")
|
||||
}
|
||||
|
||||
for i := 0; i < len(mapping); i += 2 {
|
||||
b.object.Spec.NamespaceMapping[mapping[i]] = mapping[i+1]
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// Phase sets the Restore's phase.
|
||||
func (b *RestoreBuilder) Phase(phase velerov1api.RestorePhase) *RestoreBuilder {
|
||||
b.object.Status.Phase = phase
|
||||
return b
|
||||
}
|
||||
|
||||
// RestorePVs sets the Restore's restore PVs.
|
||||
func (b *RestoreBuilder) RestorePVs(val bool) *RestoreBuilder {
|
||||
b.object.Spec.RestorePVs = &val
|
||||
return b
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
Copyright 2019 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.
|
||||
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 builder
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
velerov1api "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
)
|
||||
|
||||
// ScheduleBuilder builds Schedule objects.
|
||||
type ScheduleBuilder struct {
|
||||
object *velerov1api.Schedule
|
||||
}
|
||||
|
||||
// ForSchedule is the constructor for a ScheduleBuilder.
|
||||
func ForSchedule(ns, name string) *ScheduleBuilder {
|
||||
return &ScheduleBuilder{
|
||||
object: &velerov1api.Schedule{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: velerov1api.SchemeGroupVersion.String(),
|
||||
Kind: "Schedule",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Result returns the built Schedule.
|
||||
func (b *ScheduleBuilder) Result() *velerov1api.Schedule {
|
||||
return b.object
|
||||
}
|
||||
|
||||
// ObjectMeta applies functional options to the Schedule's ObjectMeta.
|
||||
func (b *ScheduleBuilder) ObjectMeta(opts ...ObjectMetaOpt) *ScheduleBuilder {
|
||||
for _, opt := range opts {
|
||||
opt(b.object)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// Phase sets the Schedule's phase.
|
||||
func (b *ScheduleBuilder) Phase(phase velerov1api.SchedulePhase) *ScheduleBuilder {
|
||||
b.object.Status.Phase = phase
|
||||
return b
|
||||
}
|
||||
|
||||
// ValidationError appends to the Schedule's validation errors.
|
||||
func (b *ScheduleBuilder) ValidationError(err string) *ScheduleBuilder {
|
||||
b.object.Status.ValidationErrors = append(b.object.Status.ValidationErrors, err)
|
||||
return b
|
||||
}
|
||||
|
||||
// CronSchedule sets the Schedule's cron schedule.
|
||||
func (b *ScheduleBuilder) CronSchedule(expression string) *ScheduleBuilder {
|
||||
b.object.Spec.Schedule = expression
|
||||
return b
|
||||
}
|
||||
|
||||
// LastBackupTime sets the Schedule's last backup time.
|
||||
func (b *ScheduleBuilder) LastBackupTime(val string) *ScheduleBuilder {
|
||||
t, _ := time.Parse("2006-01-02 15:04:05", val)
|
||||
b.object.Status.LastBackup.Time = t
|
||||
return b
|
||||
}
|
||||
|
||||
// Template sets the Schedule's template.
|
||||
func (b *ScheduleBuilder) Template(spec velerov1api.BackupSpec) *ScheduleBuilder {
|
||||
b.object.Spec.Template = spec
|
||||
return b
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
Copyright 2019 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.
|
||||
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 builder
|
||||
|
||||
import (
|
||||
corev1api "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// SecretBuilder builds Secret objects.
|
||||
type SecretBuilder struct {
|
||||
object *corev1api.Secret
|
||||
}
|
||||
|
||||
// ForSecret is the constructor for a SecretBuilder.
|
||||
func ForSecret(ns, name string) *SecretBuilder {
|
||||
return &SecretBuilder{
|
||||
object: &corev1api.Secret{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: corev1api.SchemeGroupVersion.String(),
|
||||
Kind: "Secret",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Result returns the built Secret.
|
||||
func (b *SecretBuilder) Result() *corev1api.Secret {
|
||||
return b.object
|
||||
}
|
||||
|
||||
// ObjectMeta applies functional options to the Secret's ObjectMeta.
|
||||
func (b *SecretBuilder) ObjectMeta(opts ...ObjectMetaOpt) *SecretBuilder {
|
||||
for _, opt := range opts {
|
||||
opt(b.object)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
Copyright 2018 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.
|
||||
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 builder
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
velerov1api "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
)
|
||||
|
||||
// ServerStatusRequestBuilder builds ServerStatusRequest objects.
|
||||
type ServerStatusRequestBuilder struct {
|
||||
object *velerov1api.ServerStatusRequest
|
||||
}
|
||||
|
||||
// ForServerStatusRequest is the constructor for for a ServerStatusRequestBuilder.
|
||||
func ForServerStatusRequest(ns, name string) *ServerStatusRequestBuilder {
|
||||
return &ServerStatusRequestBuilder{
|
||||
object: &velerov1api.ServerStatusRequest{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: velerov1api.SchemeGroupVersion.String(),
|
||||
Kind: "ServerStatusRequest",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Result returns the built ServerStatusRequest.
|
||||
func (b *ServerStatusRequestBuilder) Result() *velerov1api.ServerStatusRequest {
|
||||
return b.object
|
||||
}
|
||||
|
||||
// ObjectMeta applies functional options to the ServerStatusRequest's ObjectMeta.
|
||||
func (b *ServerStatusRequestBuilder) ObjectMeta(opts ...ObjectMetaOpt) *ServerStatusRequestBuilder {
|
||||
for _, opt := range opts {
|
||||
opt(b.object)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// Phase sets the ServerStatusRequest's phase.
|
||||
func (b *ServerStatusRequestBuilder) Phase(phase velerov1api.ServerStatusRequestPhase) *ServerStatusRequestBuilder {
|
||||
b.object.Status.Phase = phase
|
||||
return b
|
||||
}
|
||||
|
||||
// ProcessedTimestamp sets the ServerStatusRequest's processed timestamp.
|
||||
func (b *ServerStatusRequestBuilder) ProcessedTimestamp(time time.Time) *ServerStatusRequestBuilder {
|
||||
b.object.Status.ProcessedTimestamp.Time = time
|
||||
return b
|
||||
}
|
||||
|
||||
// ServerVersion sets the ServerStatusRequest's server version.
|
||||
func (b *ServerStatusRequestBuilder) ServerVersion(version string) *ServerStatusRequestBuilder {
|
||||
b.object.Status.ServerVersion = version
|
||||
return b
|
||||
}
|
||||
|
||||
// Plugins sets the ServerStatusRequest's plugins.
|
||||
func (b *ServerStatusRequestBuilder) Plugins(plugins []velerov1api.PluginInfo) *ServerStatusRequestBuilder {
|
||||
b.object.Status.Plugins = plugins
|
||||
return b
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
Copyright 2019 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.
|
||||
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 builder
|
||||
|
||||
import (
|
||||
corev1api "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// ServiceAccountBuilder builds ServiceAccount objects.
|
||||
type ServiceAccountBuilder struct {
|
||||
object *corev1api.ServiceAccount
|
||||
}
|
||||
|
||||
// ForServiceAccount is the constructor for a ServiceAccountBuilder.
|
||||
func ForServiceAccount(ns, name string) *ServiceAccountBuilder {
|
||||
return &ServiceAccountBuilder{
|
||||
object: &corev1api.ServiceAccount{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: corev1api.SchemeGroupVersion.String(),
|
||||
Kind: "ServiceAccount",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Result returns the built ServiceAccount.
|
||||
func (b *ServiceAccountBuilder) Result() *corev1api.ServiceAccount {
|
||||
return b.object
|
||||
}
|
||||
|
||||
// ObjectMeta applies functional options to the ServiceAccount's ObjectMeta.
|
||||
func (b *ServiceAccountBuilder) ObjectMeta(opts ...ObjectMetaOpt) *ServiceAccountBuilder {
|
||||
for _, opt := range opts {
|
||||
opt(b.object)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
Copyright 2019 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.
|
||||
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 builder
|
||||
|
||||
import (
|
||||
storagev1api "k8s.io/api/storage/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// StorageClassBuilder builds StorageClass objects.
|
||||
type StorageClassBuilder struct {
|
||||
object *storagev1api.StorageClass
|
||||
}
|
||||
|
||||
// ForStorageClass is the constructor for a StorageClassBuilder.
|
||||
func ForStorageClass(name string) *StorageClassBuilder {
|
||||
return &StorageClassBuilder{
|
||||
object: &storagev1api.StorageClass{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: storagev1api.SchemeGroupVersion.String(),
|
||||
Kind: "StorageClass",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Result returns the built StorageClass.
|
||||
func (b *StorageClassBuilder) Result() *storagev1api.StorageClass {
|
||||
return b.object
|
||||
}
|
||||
|
||||
// ObjectMeta applies functional options to the StorageClass's ObjectMeta.
|
||||
func (b *StorageClassBuilder) ObjectMeta(opts ...ObjectMetaOpt) *StorageClassBuilder {
|
||||
for _, opt := range opts {
|
||||
opt(b.object)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
Copyright 2019 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.
|
||||
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 builder
|
||||
|
||||
import (
|
||||
corev1api "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
// VolumeBuilder builds Volume objects.
|
||||
type VolumeBuilder struct {
|
||||
object *corev1api.Volume
|
||||
}
|
||||
|
||||
// ForVolume is the constructor for a VolumeBuilder.
|
||||
func ForVolume(name string) *VolumeBuilder {
|
||||
return &VolumeBuilder{
|
||||
object: &corev1api.Volume{
|
||||
Name: name,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Result returns the built Volume.
|
||||
func (b *VolumeBuilder) Result() *corev1api.Volume {
|
||||
return b.object
|
||||
}
|
||||
|
||||
// PersistentVolumeClaimSource sets the Volume's persistent volume claim source.
|
||||
func (b *VolumeBuilder) PersistentVolumeClaimSource(claimName string) *VolumeBuilder {
|
||||
b.object.PersistentVolumeClaim = &corev1api.PersistentVolumeClaimVolumeSource{
|
||||
ClaimName: claimName,
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// CSISource sets the Volume's CSI source.
|
||||
func (b *VolumeBuilder) CSISource(driver string) *VolumeBuilder {
|
||||
b.object.CSI = &corev1api.CSIVolumeSource{
|
||||
Driver: driver,
|
||||
}
|
||||
return b
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
Copyright 2019 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.
|
||||
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 builder
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
velerov1api "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
)
|
||||
|
||||
// VolumeSnapshotLocationBuilder builds VolumeSnapshotLocation objects.
|
||||
type VolumeSnapshotLocationBuilder struct {
|
||||
object *velerov1api.VolumeSnapshotLocation
|
||||
}
|
||||
|
||||
// ForVolumeSnapshotLocation is the constructor for a VolumeSnapshotLocationBuilder.
|
||||
func ForVolumeSnapshotLocation(ns, name string) *VolumeSnapshotLocationBuilder {
|
||||
return &VolumeSnapshotLocationBuilder{
|
||||
object: &velerov1api.VolumeSnapshotLocation{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: velerov1api.SchemeGroupVersion.String(),
|
||||
Kind: "VolumeSnapshotLocation",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Result returns the built VolumeSnapshotLocation.
|
||||
func (b *VolumeSnapshotLocationBuilder) Result() *velerov1api.VolumeSnapshotLocation {
|
||||
return b.object
|
||||
}
|
||||
|
||||
// ObjectMeta applies functional options to the VolumeSnapshotLocation's ObjectMeta.
|
||||
func (b *VolumeSnapshotLocationBuilder) ObjectMeta(opts ...ObjectMetaOpt) *VolumeSnapshotLocationBuilder {
|
||||
for _, opt := range opts {
|
||||
opt(b.object)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// Provider sets the VolumeSnapshotLocation's provider.
|
||||
func (b *VolumeSnapshotLocationBuilder) Provider(name string) *VolumeSnapshotLocationBuilder {
|
||||
b.object.Spec.Provider = name
|
||||
return b
|
||||
}
|
|
@ -25,7 +25,7 @@ import (
|
|||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
|
||||
"github.com/heptio/velero/pkg/test"
|
||||
"github.com/heptio/velero/pkg/builder"
|
||||
testutil "github.com/heptio/velero/pkg/util/test"
|
||||
)
|
||||
|
||||
|
@ -39,8 +39,8 @@ func Test_validatePodVolumesHostPath(t *testing.T) {
|
|||
{
|
||||
name: "no error when pod volumes are present",
|
||||
pods: []*corev1.Pod{
|
||||
test.NewPod("foo", "bar", test.WithUID("foo")),
|
||||
test.NewPod("zoo", "raz", test.WithUID("zoo")),
|
||||
builder.ForPod("foo", "bar").ObjectMeta(builder.WithUID("foo")).Result(),
|
||||
builder.ForPod("zoo", "raz").ObjectMeta(builder.WithUID("zoo")).Result(),
|
||||
},
|
||||
dirs: []string{"foo", "zoo"},
|
||||
wantErr: false,
|
||||
|
@ -48,8 +48,8 @@ func Test_validatePodVolumesHostPath(t *testing.T) {
|
|||
{
|
||||
name: "no error when pod volumes are present and there are mirror pods",
|
||||
pods: []*corev1.Pod{
|
||||
test.NewPod("foo", "bar", test.WithUID("foo")),
|
||||
test.NewPod("zoo", "raz", test.WithUID("zoo"), test.WithAnnotations(v1.MirrorPodAnnotationKey, "baz")),
|
||||
builder.ForPod("foo", "bar").ObjectMeta(builder.WithUID("foo")).Result(),
|
||||
builder.ForPod("zoo", "raz").ObjectMeta(builder.WithUID("zoo"), builder.WithAnnotations(v1.MirrorPodAnnotationKey, "baz")).Result(),
|
||||
},
|
||||
dirs: []string{"foo", "baz"},
|
||||
wantErr: false,
|
||||
|
@ -57,8 +57,8 @@ func Test_validatePodVolumesHostPath(t *testing.T) {
|
|||
{
|
||||
name: "error when all pod volumes missing",
|
||||
pods: []*corev1.Pod{
|
||||
test.NewPod("foo", "bar", test.WithUID("foo")),
|
||||
test.NewPod("zoo", "raz", test.WithUID("zoo")),
|
||||
builder.ForPod("foo", "bar").ObjectMeta(builder.WithUID("foo")).Result(),
|
||||
builder.ForPod("zoo", "raz").ObjectMeta(builder.WithUID("zoo")).Result(),
|
||||
},
|
||||
dirs: []string{"unexpected-dir"},
|
||||
wantErr: true,
|
||||
|
@ -66,8 +66,8 @@ func Test_validatePodVolumesHostPath(t *testing.T) {
|
|||
{
|
||||
name: "error when some pod volumes missing",
|
||||
pods: []*corev1.Pod{
|
||||
test.NewPod("foo", "bar", test.WithUID("foo")),
|
||||
test.NewPod("zoo", "raz", test.WithUID("zoo")),
|
||||
builder.ForPod("foo", "bar").ObjectMeta(builder.WithUID("foo")).Result(),
|
||||
builder.ForPod("zoo", "raz").ObjectMeta(builder.WithUID("zoo")).Result(),
|
||||
},
|
||||
dirs: []string{"foo"},
|
||||
wantErr: true,
|
||||
|
|
|
@ -24,8 +24,8 @@ import (
|
|||
"k8s.io/apimachinery/pkg/watch"
|
||||
|
||||
velerov1api "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
"github.com/heptio/velero/pkg/builder"
|
||||
velerov1client "github.com/heptio/velero/pkg/generated/clientset/versioned/typed/velero/v1"
|
||||
"github.com/heptio/velero/pkg/serverstatusrequest"
|
||||
)
|
||||
|
||||
type ServerStatusGetter interface {
|
||||
|
@ -38,7 +38,10 @@ type DefaultServerStatusGetter struct {
|
|||
}
|
||||
|
||||
func (g *DefaultServerStatusGetter) GetServerStatus(client velerov1client.ServerStatusRequestsGetter) (*velerov1api.ServerStatusRequest, error) {
|
||||
req := serverstatusrequest.NewBuilder().Namespace(g.Namespace).GenerateName("velero-cli-").ServerStatusRequest()
|
||||
req := builder.ForServerStatusRequest(g.Namespace, "").
|
||||
ObjectMeta(
|
||||
builder.WithGenerateName("velero-cli-"),
|
||||
).Result()
|
||||
|
||||
created, err := client.ServerStatusRequests(g.Namespace).Create(req)
|
||||
if err != nil {
|
||||
|
|
|
@ -26,10 +26,10 @@ import (
|
|||
"github.com/stretchr/testify/mock"
|
||||
|
||||
velerov1 "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
"github.com/heptio/velero/pkg/builder"
|
||||
"github.com/heptio/velero/pkg/buildinfo"
|
||||
"github.com/heptio/velero/pkg/generated/clientset/versioned/fake"
|
||||
v1 "github.com/heptio/velero/pkg/generated/clientset/versioned/typed/velero/v1"
|
||||
"github.com/heptio/velero/pkg/serverstatusrequest"
|
||||
)
|
||||
|
||||
func TestPrintVersion(t *testing.T) {
|
||||
|
@ -73,7 +73,7 @@ func TestPrintVersion(t *testing.T) {
|
|||
{
|
||||
name: "server status getter returns normally",
|
||||
clientOnly: false,
|
||||
serverStatusRequest: serverstatusrequest.NewBuilder().ServerVersion("v1.0.1").ServerStatusRequest(),
|
||||
serverStatusRequest: builder.ForServerStatusRequest("velero", "ssr-1").ServerVersion("v1.0.1").Result(),
|
||||
getterError: nil,
|
||||
want: clientVersion + "Server:\n\tVersion: v1.0.1\n",
|
||||
},
|
||||
|
|
|
@ -35,6 +35,7 @@ import (
|
|||
|
||||
velerov1api "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
pkgbackup "github.com/heptio/velero/pkg/backup"
|
||||
"github.com/heptio/velero/pkg/builder"
|
||||
"github.com/heptio/velero/pkg/generated/clientset/versioned/fake"
|
||||
informers "github.com/heptio/velero/pkg/generated/informers/externalversions"
|
||||
"github.com/heptio/velero/pkg/metrics"
|
||||
|
@ -44,7 +45,6 @@ import (
|
|||
pluginmocks "github.com/heptio/velero/pkg/plugin/mocks"
|
||||
"github.com/heptio/velero/pkg/plugin/velero"
|
||||
"github.com/heptio/velero/pkg/util/logging"
|
||||
velerotest "github.com/heptio/velero/pkg/util/test"
|
||||
)
|
||||
|
||||
type fakeBackupper struct {
|
||||
|
@ -56,8 +56,8 @@ func (b *fakeBackupper) Backup(logger logrus.FieldLogger, backup *pkgbackup.Requ
|
|||
return args.Error(0)
|
||||
}
|
||||
|
||||
func defaultBackup() *pkgbackup.Builder {
|
||||
return pkgbackup.NewNamedBackupBuilder(velerov1api.DefaultNamespace, "backup-1")
|
||||
func defaultBackup() *builder.BackupBuilder {
|
||||
return builder.ForBackup(velerov1api.DefaultNamespace, "backup-1")
|
||||
}
|
||||
|
||||
func TestProcessBackupNonProcessedItems(t *testing.T) {
|
||||
|
@ -77,22 +77,22 @@ func TestProcessBackupNonProcessedItems(t *testing.T) {
|
|||
{
|
||||
name: "FailedValidation backup is not processed",
|
||||
key: "velero/backup-1",
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseFailedValidation).Backup(),
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseFailedValidation).Result(),
|
||||
},
|
||||
{
|
||||
name: "InProgress backup is not processed",
|
||||
key: "velero/backup-1",
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseInProgress).Backup(),
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseInProgress).Result(),
|
||||
},
|
||||
{
|
||||
name: "Completed backup is not processed",
|
||||
key: "velero/backup-1",
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseCompleted).Backup(),
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseCompleted).Result(),
|
||||
},
|
||||
{
|
||||
name: "Failed backup is not processed",
|
||||
key: "velero/backup-1",
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseFailed).Backup(),
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseFailed).Result(),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -126,7 +126,7 @@ func TestProcessBackupNonProcessedItems(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestProcessBackupValidationFailures(t *testing.T) {
|
||||
defaultBackupLocation := velerotest.NewTestBackupStorageLocation().WithName("loc-1").BackupStorageLocation
|
||||
defaultBackupLocation := builder.ForBackupStorageLocation("velero", "loc-1").Result()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
|
@ -136,25 +136,25 @@ func TestProcessBackupValidationFailures(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
name: "invalid included/excluded resources fails validation",
|
||||
backup: defaultBackup().IncludedResources("foo").ExcludedResources("foo").Backup(),
|
||||
backup: defaultBackup().IncludedResources("foo").ExcludedResources("foo").Result(),
|
||||
backupLocation: defaultBackupLocation,
|
||||
expectedErrs: []string{"Invalid included/excluded resource lists: excludes list cannot contain an item in the includes list: foo"},
|
||||
},
|
||||
{
|
||||
name: "invalid included/excluded namespaces fails validation",
|
||||
backup: defaultBackup().IncludedNamespaces("foo").ExcludedNamespaces("foo").Backup(),
|
||||
backup: defaultBackup().IncludedNamespaces("foo").ExcludedNamespaces("foo").Result(),
|
||||
backupLocation: defaultBackupLocation,
|
||||
expectedErrs: []string{"Invalid included/excluded namespace lists: excludes list cannot contain an item in the includes list: foo"},
|
||||
},
|
||||
{
|
||||
name: "non-existent backup location fails validation",
|
||||
backup: defaultBackup().StorageLocation("nonexistent").Backup(),
|
||||
backup: defaultBackup().StorageLocation("nonexistent").Result(),
|
||||
expectedErrs: []string{"a BackupStorageLocation CRD with the name specified in the backup spec needs to be created before this backup can be executed. Error: backupstoragelocation.velero.io \"nonexistent\" not found"},
|
||||
},
|
||||
{
|
||||
name: "backup for read-only backup location fails validation",
|
||||
backup: defaultBackup().StorageLocation("read-only").Backup(),
|
||||
backupLocation: velerotest.NewTestBackupStorageLocation().WithName("read-only").WithAccessMode(velerov1api.BackupStorageLocationAccessModeReadOnly).BackupStorageLocation,
|
||||
backup: defaultBackup().StorageLocation("read-only").Result(),
|
||||
backupLocation: builder.ForBackupStorageLocation("velero", "read-only").AccessMode(velerov1api.BackupStorageLocationAccessModeReadOnly).Result(),
|
||||
expectedErrs: []string{"backup can't be created because backup storage location read-only is currently in read-only mode"},
|
||||
},
|
||||
}
|
||||
|
@ -214,15 +214,14 @@ func TestBackupLocationLabel(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
name: "valid backup location name should be used as a label",
|
||||
backup: defaultBackup().Backup(),
|
||||
backupLocation: velerotest.NewTestBackupStorageLocation().WithName("loc-1").BackupStorageLocation,
|
||||
backup: defaultBackup().Result(),
|
||||
backupLocation: builder.ForBackupStorageLocation("velero", "loc-1").Result(),
|
||||
expectedBackupLocation: "loc-1",
|
||||
},
|
||||
{
|
||||
name: "invalid storage location name should be handled while creating label",
|
||||
backup: defaultBackup().Backup(),
|
||||
backupLocation: velerotest.NewTestBackupStorageLocation().
|
||||
WithName("defaultdefaultdefaultdefaultdefaultdefaultdefaultdefaultdefaultdefault").BackupStorageLocation,
|
||||
name: "invalid storage location name should be handled while creating label",
|
||||
backup: defaultBackup().Result(),
|
||||
backupLocation: builder.ForBackupStorageLocation("velero", "defaultdefaultdefaultdefaultdefaultdefaultdefaultdefaultdefaultdefault").Result(),
|
||||
expectedBackupLocation: "defaultdefaultdefaultdefaultdefaultdefaultdefaultdefaultd58343f",
|
||||
},
|
||||
}
|
||||
|
@ -273,13 +272,13 @@ func TestDefaultBackupTTL(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
name: "backup with no TTL specified",
|
||||
backup: defaultBackup().Backup(),
|
||||
backup: defaultBackup().Result(),
|
||||
expectedTTL: defaultBackupTTL,
|
||||
expectedExpiration: metav1.NewTime(now.Add(defaultBackupTTL.Duration)),
|
||||
},
|
||||
{
|
||||
name: "backup with TTL specified",
|
||||
backup: defaultBackup().TTL(time.Hour).Backup(),
|
||||
backup: defaultBackup().TTL(time.Hour).Result(),
|
||||
expectedTTL: metav1.Duration{Duration: 1 * time.Hour},
|
||||
expectedExpiration: metav1.NewTime(now.Add(1 * time.Hour)),
|
||||
},
|
||||
|
@ -312,7 +311,7 @@ func TestDefaultBackupTTL(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestProcessBackupCompletions(t *testing.T) {
|
||||
defaultBackupLocation := velerotest.NewTestBackupStorageLocation().WithName("loc-1").WithObjectStorage("store-1").BackupStorageLocation
|
||||
defaultBackupLocation := builder.ForBackupStorageLocation("velero", "loc-1").ObjectStorage("store-1").Result()
|
||||
|
||||
now, err := time.Parse(time.RFC1123Z, time.RFC1123Z)
|
||||
require.NoError(t, err)
|
||||
|
@ -329,7 +328,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||
// Completed
|
||||
{
|
||||
name: "backup with no backup location gets the default",
|
||||
backup: defaultBackup().Backup(),
|
||||
backup: defaultBackup().Result(),
|
||||
backupLocation: defaultBackupLocation,
|
||||
expectedResult: &velerov1api.Backup{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
|
@ -357,8 +356,8 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "backup with a specific backup location keeps it",
|
||||
backup: defaultBackup().StorageLocation("alt-loc").Backup(),
|
||||
backupLocation: velerotest.NewTestBackupStorageLocation().WithName("alt-loc").WithObjectStorage("store-1").BackupStorageLocation,
|
||||
backup: defaultBackup().StorageLocation("alt-loc").Result(),
|
||||
backupLocation: builder.ForBackupStorageLocation("velero", "alt-loc").ObjectStorage("store-1").Result(),
|
||||
expectedResult: &velerov1api.Backup{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Backup",
|
||||
|
@ -385,12 +384,11 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "backup for a location with ReadWrite access mode gets processed",
|
||||
backup: defaultBackup().StorageLocation("read-write").Backup(),
|
||||
backupLocation: velerotest.NewTestBackupStorageLocation().
|
||||
WithName("read-write").
|
||||
WithObjectStorage("store-1").
|
||||
WithAccessMode(velerov1api.BackupStorageLocationAccessModeReadWrite).
|
||||
BackupStorageLocation,
|
||||
backup: defaultBackup().StorageLocation("read-write").Result(),
|
||||
backupLocation: builder.ForBackupStorageLocation("velero", "read-write").
|
||||
ObjectStorage("store-1").
|
||||
AccessMode(velerov1api.BackupStorageLocationAccessModeReadWrite).
|
||||
Result(),
|
||||
expectedResult: &velerov1api.Backup{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Backup",
|
||||
|
@ -417,7 +415,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "backup with a TTL has expiration set",
|
||||
backup: defaultBackup().TTL(10 * time.Minute).Backup(),
|
||||
backup: defaultBackup().TTL(10 * time.Minute).Result(),
|
||||
backupLocation: defaultBackupLocation,
|
||||
expectedResult: &velerov1api.Backup{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
|
@ -447,7 +445,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||
{
|
||||
name: "backup without an existing backup will succeed",
|
||||
backupExists: false,
|
||||
backup: defaultBackup().Backup(),
|
||||
backup: defaultBackup().Result(),
|
||||
backupLocation: defaultBackupLocation,
|
||||
expectedResult: &velerov1api.Backup{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
|
@ -478,7 +476,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||
{
|
||||
name: "backup with existing backup will fail",
|
||||
backupExists: true,
|
||||
backup: defaultBackup().Backup(),
|
||||
backup: defaultBackup().Result(),
|
||||
backupLocation: defaultBackupLocation,
|
||||
expectedResult: &velerov1api.Backup{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
|
@ -506,7 +504,7 @@ func TestProcessBackupCompletions(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "error when checking if backup exists will cause backup to fail",
|
||||
backup: defaultBackup().Backup(),
|
||||
backup: defaultBackup().Result(),
|
||||
existenceCheckError: errors.New("Backup already exists in object storage"),
|
||||
backupLocation: defaultBackupLocation,
|
||||
expectedResult: &velerov1api.Backup{
|
||||
|
@ -613,7 +611,7 @@ func TestValidateAndGetSnapshotLocations(t *testing.T) {
|
|||
tests := []struct {
|
||||
name string
|
||||
backup *velerov1api.Backup
|
||||
locations []*velerotest.TestVolumeSnapshotLocation
|
||||
locations []*velerov1api.VolumeSnapshotLocation
|
||||
defaultLocations map[string]string
|
||||
expectedVolumeSnapshotLocationNames []string // adding these in the expected order will allow to test with better msgs in case of a test failure
|
||||
expectedErrors string
|
||||
|
@ -621,76 +619,76 @@ func TestValidateAndGetSnapshotLocations(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
name: "location name does not correspond to any existing location",
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseNew).VolumeSnapshotLocations("random-name").Backup(),
|
||||
locations: []*velerotest.TestVolumeSnapshotLocation{
|
||||
velerotest.NewTestVolumeSnapshotLocation().WithProvider("aws").WithName("aws-us-east-1"),
|
||||
velerotest.NewTestVolumeSnapshotLocation().WithProvider("aws").WithName("aws-us-west-1"),
|
||||
velerotest.NewTestVolumeSnapshotLocation().WithProvider("fake-provider").WithName("some-name"),
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseNew).VolumeSnapshotLocations("random-name").Result(),
|
||||
locations: []*velerov1api.VolumeSnapshotLocation{
|
||||
builder.ForVolumeSnapshotLocation(velerov1api.DefaultNamespace, "aws-us-east-1").Provider("aws").Result(),
|
||||
builder.ForVolumeSnapshotLocation(velerov1api.DefaultNamespace, "aws-us-west-1").Provider("aws").Result(),
|
||||
builder.ForVolumeSnapshotLocation(velerov1api.DefaultNamespace, "some-name").Provider("fake-provider").Result(),
|
||||
},
|
||||
expectedErrors: "a VolumeSnapshotLocation CRD for the location random-name with the name specified in the backup spec needs to be created before this snapshot can be executed. Error: volumesnapshotlocation.velero.io \"random-name\" not found", expectedSuccess: false,
|
||||
},
|
||||
{
|
||||
name: "duplicate locationName per provider: should filter out dups",
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseNew).VolumeSnapshotLocations("aws-us-west-1", "aws-us-west-1").Backup(),
|
||||
locations: []*velerotest.TestVolumeSnapshotLocation{
|
||||
velerotest.NewTestVolumeSnapshotLocation().WithProvider("aws").WithName("aws-us-east-1"),
|
||||
velerotest.NewTestVolumeSnapshotLocation().WithProvider("aws").WithName("aws-us-west-1"),
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseNew).VolumeSnapshotLocations("aws-us-west-1", "aws-us-west-1").Result(),
|
||||
locations: []*velerov1api.VolumeSnapshotLocation{
|
||||
builder.ForVolumeSnapshotLocation(velerov1api.DefaultNamespace, "aws-us-east-1").Provider("aws").Result(),
|
||||
builder.ForVolumeSnapshotLocation(velerov1api.DefaultNamespace, "aws-us-west-1").Provider("aws").Result(),
|
||||
},
|
||||
expectedVolumeSnapshotLocationNames: []string{"aws-us-west-1"},
|
||||
expectedSuccess: true,
|
||||
},
|
||||
{
|
||||
name: "multiple non-dupe location names per provider should error",
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseNew).VolumeSnapshotLocations("aws-us-east-1", "aws-us-west-1").Backup(),
|
||||
locations: []*velerotest.TestVolumeSnapshotLocation{
|
||||
velerotest.NewTestVolumeSnapshotLocation().WithProvider("aws").WithName("aws-us-east-1"),
|
||||
velerotest.NewTestVolumeSnapshotLocation().WithProvider("aws").WithName("aws-us-west-1"),
|
||||
velerotest.NewTestVolumeSnapshotLocation().WithProvider("fake-provider").WithName("some-name"),
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseNew).VolumeSnapshotLocations("aws-us-east-1", "aws-us-west-1").Result(),
|
||||
locations: []*velerov1api.VolumeSnapshotLocation{
|
||||
builder.ForVolumeSnapshotLocation(velerov1api.DefaultNamespace, "aws-us-east-1").Provider("aws").Result(),
|
||||
builder.ForVolumeSnapshotLocation(velerov1api.DefaultNamespace, "aws-us-west-1").Provider("aws").Result(),
|
||||
builder.ForVolumeSnapshotLocation(velerov1api.DefaultNamespace, "some-name").Provider("fake-provider").Result(),
|
||||
},
|
||||
expectedErrors: "more than one VolumeSnapshotLocation name specified for provider aws: aws-us-west-1; unexpected name was aws-us-east-1",
|
||||
expectedSuccess: false,
|
||||
},
|
||||
{
|
||||
name: "no location name for the provider exists, only one VSL for the provider: use it",
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseNew).Backup(),
|
||||
locations: []*velerotest.TestVolumeSnapshotLocation{
|
||||
velerotest.NewTestVolumeSnapshotLocation().WithProvider("aws").WithName("aws-us-east-1"),
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseNew).Result(),
|
||||
locations: []*velerov1api.VolumeSnapshotLocation{
|
||||
builder.ForVolumeSnapshotLocation(velerov1api.DefaultNamespace, "aws-us-east-1").Provider("aws").Result(),
|
||||
},
|
||||
expectedVolumeSnapshotLocationNames: []string{"aws-us-east-1"},
|
||||
expectedSuccess: true,
|
||||
},
|
||||
{
|
||||
name: "no location name for the provider exists, no default, more than one VSL for the provider: error",
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseNew).Backup(),
|
||||
locations: []*velerotest.TestVolumeSnapshotLocation{
|
||||
velerotest.NewTestVolumeSnapshotLocation().WithProvider("aws").WithName("aws-us-east-1"),
|
||||
velerotest.NewTestVolumeSnapshotLocation().WithProvider("aws").WithName("aws-us-west-1"),
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseNew).Result(),
|
||||
locations: []*velerov1api.VolumeSnapshotLocation{
|
||||
builder.ForVolumeSnapshotLocation(velerov1api.DefaultNamespace, "aws-us-east-1").Provider("aws").Result(),
|
||||
builder.ForVolumeSnapshotLocation(velerov1api.DefaultNamespace, "aws-us-west-1").Provider("aws").Result(),
|
||||
},
|
||||
expectedErrors: "provider aws has more than one possible volume snapshot location, and none were specified explicitly or as a default",
|
||||
},
|
||||
{
|
||||
name: "no location name for the provider exists, more than one VSL for the provider: the provider's default should be added",
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseNew).Backup(),
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseNew).Result(),
|
||||
defaultLocations: map[string]string{"aws": "aws-us-east-1"},
|
||||
locations: []*velerotest.TestVolumeSnapshotLocation{
|
||||
velerotest.NewTestVolumeSnapshotLocation().WithName("aws-us-east-1").WithProvider("aws"),
|
||||
velerotest.NewTestVolumeSnapshotLocation().WithName("aws-us-west-1").WithProvider("aws"),
|
||||
locations: []*velerov1api.VolumeSnapshotLocation{
|
||||
builder.ForVolumeSnapshotLocation(velerov1api.DefaultNamespace, "aws-us-east-1").Provider("aws").Result(),
|
||||
builder.ForVolumeSnapshotLocation(velerov1api.DefaultNamespace, "aws-us-west-1").Provider("aws").Result(),
|
||||
},
|
||||
expectedVolumeSnapshotLocationNames: []string{"aws-us-east-1"},
|
||||
expectedSuccess: true,
|
||||
},
|
||||
{
|
||||
name: "no existing location name and no default location name given",
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseNew).Backup(),
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseNew).Result(),
|
||||
expectedSuccess: true,
|
||||
},
|
||||
{
|
||||
name: "multiple location names for a provider, default location name for another provider",
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseNew).VolumeSnapshotLocations("aws-us-west-1", "aws-us-west-1").Backup(),
|
||||
backup: defaultBackup().Phase(velerov1api.BackupPhaseNew).VolumeSnapshotLocations("aws-us-west-1", "aws-us-west-1").Result(),
|
||||
defaultLocations: map[string]string{"fake-provider": "some-name"},
|
||||
locations: []*velerotest.TestVolumeSnapshotLocation{
|
||||
velerotest.NewTestVolumeSnapshotLocation().WithProvider("aws").WithName("aws-us-west-1"),
|
||||
velerotest.NewTestVolumeSnapshotLocation().WithProvider("fake-provider").WithName("some-name"),
|
||||
locations: []*velerov1api.VolumeSnapshotLocation{
|
||||
builder.ForVolumeSnapshotLocation(velerov1api.DefaultNamespace, "aws-us-west-1").Provider("aws").Result(),
|
||||
builder.ForVolumeSnapshotLocation(velerov1api.DefaultNamespace, "some-name").Provider("fake-provider").Result(),
|
||||
},
|
||||
expectedVolumeSnapshotLocationNames: []string{"aws-us-west-1", "some-name"},
|
||||
expectedSuccess: true,
|
||||
|
@ -713,7 +711,7 @@ func TestValidateAndGetSnapshotLocations(t *testing.T) {
|
|||
backup := test.backup.DeepCopy()
|
||||
backup.Spec.VolumeSnapshotLocations = test.backup.Spec.VolumeSnapshotLocations
|
||||
for _, location := range test.locations {
|
||||
require.NoError(t, sharedInformers.Velero().V1().VolumeSnapshotLocations().Informer().GetStore().Add(location.VolumeSnapshotLocation))
|
||||
require.NoError(t, sharedInformers.Velero().V1().VolumeSnapshotLocations().Informer().GetStore().Add(location))
|
||||
}
|
||||
|
||||
providerLocations, errs := c.validateAndGetSnapshotLocations(backup)
|
||||
|
|
|
@ -34,6 +34,7 @@ import (
|
|||
|
||||
v1 "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
pkgbackup "github.com/heptio/velero/pkg/backup"
|
||||
"github.com/heptio/velero/pkg/builder"
|
||||
"github.com/heptio/velero/pkg/generated/clientset/versioned/fake"
|
||||
informers "github.com/heptio/velero/pkg/generated/informers/externalversions"
|
||||
"github.com/heptio/velero/pkg/metrics"
|
||||
|
@ -266,8 +267,8 @@ func TestBackupDeletionControllerProcessRequest(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("patching to InProgress fails", func(t *testing.T) {
|
||||
backup := defaultBackup().Name("foo").StorageLocation("default").Backup()
|
||||
location := velerotest.NewTestBackupStorageLocation().WithName("default").BackupStorageLocation
|
||||
backup := builder.ForBackup(v1.DefaultNamespace, "foo").StorageLocation("default").Result()
|
||||
location := builder.ForBackupStorageLocation("velero", "default").Result()
|
||||
|
||||
td := setupBackupDeletionControllerTest(backup)
|
||||
|
||||
|
@ -298,8 +299,8 @@ func TestBackupDeletionControllerProcessRequest(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("patching backup to Deleting fails", func(t *testing.T) {
|
||||
backup := defaultBackup().Name("foo").StorageLocation("default").Backup()
|
||||
location := velerotest.NewTestBackupStorageLocation().WithName("default").BackupStorageLocation
|
||||
backup := builder.ForBackup(v1.DefaultNamespace, "foo").StorageLocation("default").Result()
|
||||
location := builder.ForBackupStorageLocation("velero", "default").Result()
|
||||
|
||||
td := setupBackupDeletionControllerTest(backup)
|
||||
|
||||
|
@ -364,7 +365,7 @@ func TestBackupDeletionControllerProcessRequest(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("unable to find backup storage location", func(t *testing.T) {
|
||||
backup := defaultBackup().Name("foo").StorageLocation("default").Backup()
|
||||
backup := builder.ForBackup(v1.DefaultNamespace, "foo").StorageLocation("default").Result()
|
||||
|
||||
td := setupBackupDeletionControllerTest(backup)
|
||||
|
||||
|
@ -390,8 +391,8 @@ func TestBackupDeletionControllerProcessRequest(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("backup storage location is in read-only mode", func(t *testing.T) {
|
||||
backup := defaultBackup().Name("foo").StorageLocation("default").Backup()
|
||||
location := velerotest.NewTestBackupStorageLocation().WithName("default").WithAccessMode(v1.BackupStorageLocationAccessModeReadOnly).BackupStorageLocation
|
||||
backup := builder.ForBackup(v1.DefaultNamespace, "foo").StorageLocation("default").Result()
|
||||
location := builder.ForBackupStorageLocation("velero", "default").AccessMode(v1.BackupStorageLocationAccessModeReadOnly).Result()
|
||||
|
||||
td := setupBackupDeletionControllerTest(backup)
|
||||
|
||||
|
@ -419,13 +420,13 @@ func TestBackupDeletionControllerProcessRequest(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("full delete, no errors", func(t *testing.T) {
|
||||
backup := defaultBackup().Name("foo").Backup()
|
||||
backup := builder.ForBackup(v1.DefaultNamespace, "foo").Result()
|
||||
backup.UID = "uid"
|
||||
backup.Spec.StorageLocation = "primary"
|
||||
|
||||
restore1 := velerotest.NewTestRestore("velero", "restore-1", v1.RestorePhaseCompleted).WithBackup("foo").Restore
|
||||
restore2 := velerotest.NewTestRestore("velero", "restore-2", v1.RestorePhaseCompleted).WithBackup("foo").Restore
|
||||
restore3 := velerotest.NewTestRestore("velero", "restore-3", v1.RestorePhaseCompleted).WithBackup("some-other-backup").Restore
|
||||
restore1 := builder.ForRestore("velero", "restore-1").Phase(v1.RestorePhaseCompleted).Backup("foo").Result()
|
||||
restore2 := builder.ForRestore("velero", "restore-2").Phase(v1.RestorePhaseCompleted).Backup("foo").Result()
|
||||
restore3 := builder.ForRestore("velero", "restore-3").Phase(v1.RestorePhaseCompleted).Backup("some-other-backup").Result()
|
||||
|
||||
td := setupBackupDeletionControllerTest(backup, restore1, restore2, restore3)
|
||||
|
||||
|
@ -565,16 +566,26 @@ func TestBackupDeletionControllerProcessRequest(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("full delete, no errors, with backup name greater than 63 chars", func(t *testing.T) {
|
||||
backup := defaultBackup().Name("the-really-long-backup-name-that-is-much-more-than-63-characters").Backup()
|
||||
backup := defaultBackup().
|
||||
ObjectMeta(
|
||||
builder.WithName("the-really-long-backup-name-that-is-much-more-than-63-characters"),
|
||||
).
|
||||
Result()
|
||||
backup.UID = "uid"
|
||||
backup.Spec.StorageLocation = "primary"
|
||||
|
||||
restore1 := velerotest.NewTestRestore("velero", "restore-1", v1.RestorePhaseCompleted).
|
||||
WithBackup("the-really-long-backup-name-that-is-much-more-than-63-characters").Restore
|
||||
restore2 := velerotest.NewTestRestore("velero", "restore-2", v1.RestorePhaseCompleted).
|
||||
WithBackup("the-really-long-backup-name-that-is-much-more-than-63-characters").Restore
|
||||
restore3 := velerotest.NewTestRestore("velero", "restore-3", v1.RestorePhaseCompleted).
|
||||
WithBackup("some-other-backup").Restore
|
||||
restore1 := builder.ForRestore("velero", "restore-1").
|
||||
Phase(v1.RestorePhaseCompleted).
|
||||
Backup("the-really-long-backup-name-that-is-much-more-than-63-characters").
|
||||
Result()
|
||||
restore2 := builder.ForRestore("velero", "restore-2").
|
||||
Phase(v1.RestorePhaseCompleted).
|
||||
Backup("the-really-long-backup-name-that-is-much-more-than-63-characters").
|
||||
Result()
|
||||
restore3 := builder.ForRestore("velero", "restore-3").
|
||||
Phase(v1.RestorePhaseCompleted).
|
||||
Backup("some-other-backup").
|
||||
Result()
|
||||
|
||||
td := setupBackupDeletionControllerTest(backup, restore1, restore2, restore3)
|
||||
td.req = pkgbackup.NewDeleteBackupRequest(backup.Name, string(backup.UID))
|
||||
|
|
|
@ -32,7 +32,7 @@ import (
|
|||
core "k8s.io/client-go/testing"
|
||||
|
||||
velerov1api "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
pkgbackup "github.com/heptio/velero/pkg/backup"
|
||||
"github.com/heptio/velero/pkg/builder"
|
||||
"github.com/heptio/velero/pkg/generated/clientset/versioned/fake"
|
||||
informers "github.com/heptio/velero/pkg/generated/informers/externalversions"
|
||||
"github.com/heptio/velero/pkg/label"
|
||||
|
@ -43,10 +43,6 @@ import (
|
|||
velerotest "github.com/heptio/velero/pkg/util/test"
|
||||
)
|
||||
|
||||
func defaultPodVolumeBackup() *pkgbackup.PodVolumeBackupBuilder {
|
||||
return pkgbackup.NewNamedPodVolumeBackupBuilder(velerov1api.DefaultNamespace, "pvb-1")
|
||||
}
|
||||
|
||||
func defaultLocationsList(namespace string) []*velerov1api.BackupStorageLocation {
|
||||
return []*velerov1api.BackupStorageLocation{
|
||||
{
|
||||
|
@ -138,15 +134,15 @@ func TestBackupSyncControllerRun(t *testing.T) {
|
|||
cloudBuckets: map[string][]*cloudBackupData{
|
||||
"bucket-1": {
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-1").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-1").Result(),
|
||||
},
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-2").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-2").Result(),
|
||||
},
|
||||
},
|
||||
"bucket-2": {
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-3").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-3").Result(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -158,18 +154,18 @@ func TestBackupSyncControllerRun(t *testing.T) {
|
|||
cloudBuckets: map[string][]*cloudBackupData{
|
||||
"bucket-1": {
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-1").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-1").Result(),
|
||||
},
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-2").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-2").Result(),
|
||||
},
|
||||
},
|
||||
"bucket-2": {
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-2").Name("backup-3").Backup(),
|
||||
backup: builder.ForBackup("ns-2", "backup-3").Result(),
|
||||
},
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("velero").Name("backup-4").Backup(),
|
||||
backup: builder.ForBackup("velero", "backup-4").Result(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -181,26 +177,26 @@ func TestBackupSyncControllerRun(t *testing.T) {
|
|||
cloudBuckets: map[string][]*cloudBackupData{
|
||||
"bucket-1": {
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-1").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-1").Result(),
|
||||
},
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-2").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-2").Result(),
|
||||
},
|
||||
},
|
||||
"bucket-2": {
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-3").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-3").Result(),
|
||||
},
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-4").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-4").Result(),
|
||||
},
|
||||
},
|
||||
},
|
||||
existingBackups: []*velerov1api.Backup{
|
||||
// add a label to each existing backup so we can differentiate it from the cloud
|
||||
// backup during verification
|
||||
defaultBackup().Namespace("ns-1").Name("backup-1").Labels("i-exist", "true").StorageLocation("location-1").Backup(),
|
||||
defaultBackup().Namespace("ns-1").Name("backup-3").Labels("i-exist", "true").StorageLocation("location-2").Backup(),
|
||||
builder.ForBackup("ns-1", "backup-1").StorageLocation("location-1").ObjectMeta(builder.WithLabels("i-exist", "true")).Result(),
|
||||
builder.ForBackup("ns-1", "backup-3").StorageLocation("location-2").ObjectMeta(builder.WithLabels("i-exist", "true")).Result(),
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -210,14 +206,14 @@ func TestBackupSyncControllerRun(t *testing.T) {
|
|||
cloudBuckets: map[string][]*cloudBackupData{
|
||||
"bucket-1": {
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-1").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-1").Result(),
|
||||
},
|
||||
},
|
||||
},
|
||||
existingBackups: []*velerov1api.Backup{
|
||||
// add a label to each existing backup so we can differentiate it from the cloud
|
||||
// backup during verification
|
||||
defaultBackup().Namespace("ns-1").Name("backup-1").Labels("i-exist", "true").StorageLocation("location-1").Backup(),
|
||||
builder.ForBackup("ns-1", "backup-1").ObjectMeta(builder.WithLabels("i-exist", "true")).StorageLocation("location-1").Result(),
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -227,15 +223,15 @@ func TestBackupSyncControllerRun(t *testing.T) {
|
|||
cloudBuckets: map[string][]*cloudBackupData{
|
||||
"bucket-1": {
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-1").StorageLocation("foo").Labels(velerov1api.StorageLocationLabel, "foo").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-1").StorageLocation("foo").ObjectMeta(builder.WithLabels(velerov1api.StorageLocationLabel, "foo")).Result(),
|
||||
},
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-2").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-2").Result(),
|
||||
},
|
||||
},
|
||||
"bucket-2": {
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-3").StorageLocation("bar").Labels(velerov1api.StorageLocationLabel, "bar").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-3").StorageLocation("bar").ObjectMeta(builder.WithLabels(velerov1api.StorageLocationLabel, "bar")).Result(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -248,15 +244,15 @@ func TestBackupSyncControllerRun(t *testing.T) {
|
|||
cloudBuckets: map[string][]*cloudBackupData{
|
||||
"bucket-1": {
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-1").StorageLocation("foo").Labels(velerov1api.StorageLocationLabel, "foo").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-1").StorageLocation("foo").ObjectMeta(builder.WithLabels(velerov1api.StorageLocationLabel, "foo")).Result(),
|
||||
},
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-2").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-2").Result(),
|
||||
},
|
||||
},
|
||||
"bucket-2": {
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-3").StorageLocation("bar").Labels(velerov1api.StorageLocationLabel, "bar").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-3").StorageLocation("bar").ObjectMeta(builder.WithLabels(velerov1api.StorageLocationLabel, "bar")).Result(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -268,28 +264,28 @@ func TestBackupSyncControllerRun(t *testing.T) {
|
|||
cloudBuckets: map[string][]*cloudBackupData{
|
||||
"bucket-1": {
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-1").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-1").Result(),
|
||||
podVolumeBackups: []*velerov1api.PodVolumeBackup{
|
||||
defaultPodVolumeBackup().Namespace("ns-1").Name("pvb-1").PodVolumeBackup(),
|
||||
builder.ForPodVolumeBackup("ns-1", "pvb-1").Result(),
|
||||
},
|
||||
},
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-2").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-2").Result(),
|
||||
podVolumeBackups: []*velerov1api.PodVolumeBackup{
|
||||
defaultPodVolumeBackup().Namespace("ns-1").Name("pvb-2").PodVolumeBackup(),
|
||||
builder.ForPodVolumeBackup("ns-1", "pvb-2").Result(),
|
||||
},
|
||||
},
|
||||
},
|
||||
"bucket-2": {
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-3").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-3").Result(),
|
||||
},
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-4").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-4").Result(),
|
||||
podVolumeBackups: []*velerov1api.PodVolumeBackup{
|
||||
defaultPodVolumeBackup().Namespace("ns-1").Name("pvb-1").PodVolumeBackup(),
|
||||
defaultPodVolumeBackup().Namespace("ns-1").Name("pvb-2").PodVolumeBackup(),
|
||||
defaultPodVolumeBackup().Namespace("ns-1").Name("pvb-3").PodVolumeBackup(),
|
||||
builder.ForPodVolumeBackup("ns-1", "pvb-1").Result(),
|
||||
builder.ForPodVolumeBackup("ns-1", "pvb-2").Result(),
|
||||
builder.ForPodVolumeBackup("ns-1", "pvb-3").Result(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -302,35 +298,35 @@ func TestBackupSyncControllerRun(t *testing.T) {
|
|||
cloudBuckets: map[string][]*cloudBackupData{
|
||||
"bucket-1": {
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-1").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-1").Result(),
|
||||
podVolumeBackups: []*velerov1api.PodVolumeBackup{
|
||||
defaultPodVolumeBackup().Namespace("ns-1").Name("pvb-1").PodVolumeBackup(),
|
||||
builder.ForPodVolumeBackup("ns-1", "pvb-1").Result(),
|
||||
},
|
||||
},
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-2").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-2").Result(),
|
||||
podVolumeBackups: []*velerov1api.PodVolumeBackup{
|
||||
defaultPodVolumeBackup().Namespace("ns-1").Name("pvb-3").PodVolumeBackup(),
|
||||
builder.ForPodVolumeBackup("ns-1", "pvb-3").Result(),
|
||||
},
|
||||
},
|
||||
},
|
||||
"bucket-2": {
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-3").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-3").Result(),
|
||||
},
|
||||
&cloudBackupData{
|
||||
backup: defaultBackup().Namespace("ns-1").Name("backup-4").Backup(),
|
||||
backup: builder.ForBackup("ns-1", "backup-4").Result(),
|
||||
podVolumeBackups: []*velerov1api.PodVolumeBackup{
|
||||
defaultPodVolumeBackup().Namespace("ns-1").Name("pvb-1").PodVolumeBackup(),
|
||||
defaultPodVolumeBackup().Namespace("ns-1").Name("pvb-5").PodVolumeBackup(),
|
||||
defaultPodVolumeBackup().Namespace("ns-1").Name("pvb-6").PodVolumeBackup(),
|
||||
builder.ForPodVolumeBackup("ns-1", "pvb-1").Result(),
|
||||
builder.ForPodVolumeBackup("ns-1", "pvb-5").Result(),
|
||||
builder.ForPodVolumeBackup("ns-1", "pvb-6").Result(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
existingPodVolumeBackups: []*velerov1api.PodVolumeBackup{
|
||||
defaultPodVolumeBackup().Namespace("ns-1").Name("pvb-1").PodVolumeBackup(),
|
||||
defaultPodVolumeBackup().Namespace("ns-1").Name("pvb-2").PodVolumeBackup(),
|
||||
builder.ForPodVolumeBackup("ns-1", "pvb-1").Result(),
|
||||
builder.ForPodVolumeBackup("ns-1", "pvb-2").Result(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -477,6 +473,10 @@ func TestBackupSyncControllerRun(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDeleteOrphanedBackups(t *testing.T) {
|
||||
baseBuilder := func(name string) *builder.BackupBuilder {
|
||||
return builder.ForBackup("ns-1", name).ObjectMeta(builder.WithLabels(velerov1api.StorageLocationLabel, "default"))
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
cloudBackups sets.String
|
||||
|
@ -489,9 +489,9 @@ func TestDeleteOrphanedBackups(t *testing.T) {
|
|||
namespace: "ns-1",
|
||||
cloudBackups: sets.NewString("backup-1", "backup-2", "backup-3"),
|
||||
k8sBackups: []*velerov1api.Backup{
|
||||
defaultBackup().Namespace("ns-1").Name("backupA").Labels(velerov1api.StorageLocationLabel, "default").Phase(velerov1api.BackupPhaseCompleted).Backup(),
|
||||
defaultBackup().Namespace("ns-1").Name("backupB").Labels(velerov1api.StorageLocationLabel, "default").Phase(velerov1api.BackupPhaseCompleted).Backup(),
|
||||
defaultBackup().Namespace("ns-1").Name("backupC").Labels(velerov1api.StorageLocationLabel, "default").Phase(velerov1api.BackupPhaseCompleted).Backup(),
|
||||
baseBuilder("backupA").Phase(velerov1api.BackupPhaseCompleted).Result(),
|
||||
baseBuilder("backupB").Phase(velerov1api.BackupPhaseCompleted).Result(),
|
||||
baseBuilder("backupC").Phase(velerov1api.BackupPhaseCompleted).Result(),
|
||||
},
|
||||
expectedDeletes: sets.NewString("backupA", "backupB", "backupC"),
|
||||
},
|
||||
|
@ -500,9 +500,9 @@ func TestDeleteOrphanedBackups(t *testing.T) {
|
|||
namespace: "ns-1",
|
||||
cloudBackups: sets.NewString("backup-1", "backup-2", "backup-3"),
|
||||
k8sBackups: []*velerov1api.Backup{
|
||||
defaultBackup().Namespace("ns-1").Name("backup-1").Labels(velerov1api.StorageLocationLabel, "default").Phase(velerov1api.BackupPhaseCompleted).Backup(),
|
||||
defaultBackup().Namespace("ns-1").Name("backup-2").Labels(velerov1api.StorageLocationLabel, "default").Phase(velerov1api.BackupPhaseCompleted).Backup(),
|
||||
defaultBackup().Namespace("ns-1").Name("backup-C").Labels(velerov1api.StorageLocationLabel, "default").Phase(velerov1api.BackupPhaseCompleted).Backup(),
|
||||
baseBuilder("backup-1").Phase(velerov1api.BackupPhaseCompleted).Result(),
|
||||
baseBuilder("backup-2").Phase(velerov1api.BackupPhaseCompleted).Result(),
|
||||
baseBuilder("backup-C").Phase(velerov1api.BackupPhaseCompleted).Result(),
|
||||
},
|
||||
expectedDeletes: sets.NewString("backup-C"),
|
||||
},
|
||||
|
@ -511,9 +511,9 @@ func TestDeleteOrphanedBackups(t *testing.T) {
|
|||
namespace: "ns-1",
|
||||
cloudBackups: sets.NewString("backup-1", "backup-2", "backup-3"),
|
||||
k8sBackups: []*velerov1api.Backup{
|
||||
defaultBackup().Namespace("ns-1").Name("backup-1").Labels(velerov1api.StorageLocationLabel, "default").Phase(velerov1api.BackupPhaseCompleted).Backup(),
|
||||
defaultBackup().Namespace("ns-1").Name("backup-2").Labels(velerov1api.StorageLocationLabel, "default").Phase(velerov1api.BackupPhaseCompleted).Backup(),
|
||||
defaultBackup().Namespace("ns-1").Name("backup-3").Labels(velerov1api.StorageLocationLabel, "default").Phase(velerov1api.BackupPhaseCompleted).Backup(),
|
||||
baseBuilder("backup-1").Phase(velerov1api.BackupPhaseCompleted).Result(),
|
||||
baseBuilder("backup-2").Phase(velerov1api.BackupPhaseCompleted).Result(),
|
||||
baseBuilder("backup-3").Phase(velerov1api.BackupPhaseCompleted).Result(),
|
||||
},
|
||||
expectedDeletes: sets.NewString(),
|
||||
},
|
||||
|
@ -522,12 +522,12 @@ func TestDeleteOrphanedBackups(t *testing.T) {
|
|||
namespace: "ns-1",
|
||||
cloudBackups: sets.NewString("backup-1", "backup-2", "backup-3"),
|
||||
k8sBackups: []*velerov1api.Backup{
|
||||
defaultBackup().Namespace("ns-1").Name("backupA").Labels(velerov1api.StorageLocationLabel, "default").Phase(velerov1api.BackupPhaseCompleted).Backup(),
|
||||
defaultBackup().Namespace("ns-1").Name("Deleting").Labels(velerov1api.StorageLocationLabel, "default").Phase(velerov1api.BackupPhaseDeleting).Backup(),
|
||||
defaultBackup().Namespace("ns-1").Name("Failed").Labels(velerov1api.StorageLocationLabel, "default").Phase(velerov1api.BackupPhaseFailed).Backup(),
|
||||
defaultBackup().Namespace("ns-1").Name("FailedValidation").Labels(velerov1api.StorageLocationLabel, "default").Phase(velerov1api.BackupPhaseFailedValidation).Backup(),
|
||||
defaultBackup().Namespace("ns-1").Name("InProgress").Labels(velerov1api.StorageLocationLabel, "default").Phase(velerov1api.BackupPhaseInProgress).Backup(),
|
||||
defaultBackup().Namespace("ns-1").Name("New").Labels(velerov1api.StorageLocationLabel, "default").Phase(velerov1api.BackupPhaseNew).Backup(),
|
||||
baseBuilder("backupA").Phase(velerov1api.BackupPhaseCompleted).Result(),
|
||||
baseBuilder("Deleting").Phase(velerov1api.BackupPhaseDeleting).Result(),
|
||||
baseBuilder("Failed").Phase(velerov1api.BackupPhaseFailed).Result(),
|
||||
baseBuilder("FailedValidation").Phase(velerov1api.BackupPhaseFailedValidation).Result(),
|
||||
baseBuilder("InProgress").Phase(velerov1api.BackupPhaseInProgress).Result(),
|
||||
baseBuilder("New").Phase(velerov1api.BackupPhaseNew).Result(),
|
||||
},
|
||||
expectedDeletes: sets.NewString("backupA"),
|
||||
},
|
||||
|
@ -536,9 +536,9 @@ func TestDeleteOrphanedBackups(t *testing.T) {
|
|||
namespace: "ns-1",
|
||||
cloudBackups: sets.NewString("backup-1", "backup-2", "backup-3"),
|
||||
k8sBackups: []*velerov1api.Backup{
|
||||
defaultBackup().Namespace("ns-1").Name("backup-1").Labels(velerov1api.StorageLocationLabel, "default").Phase(velerov1api.BackupPhaseFailed).Backup(),
|
||||
defaultBackup().Namespace("ns-1").Name("backup-2").Labels(velerov1api.StorageLocationLabel, "default").Phase(velerov1api.BackupPhaseFailedValidation).Backup(),
|
||||
defaultBackup().Namespace("ns-1").Name("backup-3").Labels(velerov1api.StorageLocationLabel, "default").Phase(velerov1api.BackupPhaseInProgress).Backup(),
|
||||
baseBuilder("backup-1").Phase(velerov1api.BackupPhaseFailed).Result(),
|
||||
baseBuilder("backup-2").Phase(velerov1api.BackupPhaseFailedValidation).Result(),
|
||||
baseBuilder("backup-3").Phase(velerov1api.BackupPhaseInProgress).Result(),
|
||||
},
|
||||
expectedDeletes: sets.NewString(),
|
||||
},
|
||||
|
@ -547,13 +547,13 @@ func TestDeleteOrphanedBackups(t *testing.T) {
|
|||
namespace: "ns-1",
|
||||
cloudBackups: sets.NewString("backup-1", "backup-2", "backup-3"),
|
||||
k8sBackups: []*velerov1api.Backup{
|
||||
defaultBackup().Namespace("ns-1").Name("backup-1").Labels(velerov1api.StorageLocationLabel, "default").Phase(velerov1api.BackupPhaseCompleted).Backup(),
|
||||
defaultBackup().Namespace("ns-1").Name("backup-2").Labels(velerov1api.StorageLocationLabel, "default").Phase(velerov1api.BackupPhaseCompleted).Backup(),
|
||||
defaultBackup().Namespace("ns-1").Name("backup-C").Labels(velerov1api.StorageLocationLabel, "default").Phase(velerov1api.BackupPhaseCompleted).Backup(),
|
||||
baseBuilder("backup-1").Phase(velerov1api.BackupPhaseCompleted).Result(),
|
||||
baseBuilder("backup-2").Phase(velerov1api.BackupPhaseCompleted).Result(),
|
||||
baseBuilder("backup-C").Phase(velerov1api.BackupPhaseCompleted).Result(),
|
||||
|
||||
defaultBackup().Namespace("ns-1").Name("backup-4").Labels(velerov1api.StorageLocationLabel, "alternate").Phase(velerov1api.BackupPhaseCompleted).Backup(),
|
||||
defaultBackup().Namespace("ns-1").Name("backup-5").Labels(velerov1api.StorageLocationLabel, "alternate").Phase(velerov1api.BackupPhaseCompleted).Backup(),
|
||||
defaultBackup().Namespace("ns-1").Name("backup-6").Labels(velerov1api.StorageLocationLabel, "alternate").Phase(velerov1api.BackupPhaseCompleted).Backup(),
|
||||
baseBuilder("backup-4").ObjectMeta(builder.WithLabels(velerov1api.StorageLocationLabel, "alternate")).Phase(velerov1api.BackupPhaseCompleted).Result(),
|
||||
baseBuilder("backup-5").ObjectMeta(builder.WithLabels(velerov1api.StorageLocationLabel, "alternate")).Phase(velerov1api.BackupPhaseCompleted).Result(),
|
||||
baseBuilder("backup-6").ObjectMeta(builder.WithLabels(velerov1api.StorageLocationLabel, "alternate")).Phase(velerov1api.BackupPhaseCompleted).Result(),
|
||||
},
|
||||
expectedDeletes: sets.NewString("backup-C"),
|
||||
},
|
||||
|
@ -628,12 +628,24 @@ func TestStorageLabelsInDeleteOrphanedBackups(t *testing.T) {
|
|||
namespace: "ns-1",
|
||||
cloudBackups: sets.NewString("backup-1", "backup-2", "backup-3"),
|
||||
k8sBackups: []*velerov1api.Backup{
|
||||
defaultBackup().Namespace("ns-1").Name("backup-1").
|
||||
Labels(velerov1api.StorageLocationLabel, "the-really-long-location-name-that-is-much-more-than-63-c69e779").Phase(velerov1api.BackupPhaseCompleted).Backup(),
|
||||
defaultBackup().Namespace("ns-1").Name("backup-2").
|
||||
Labels(velerov1api.StorageLocationLabel, "the-really-long-location-name-that-is-much-more-than-63-c69e779").Phase(velerov1api.BackupPhaseCompleted).Backup(),
|
||||
defaultBackup().Namespace("ns-1").Name("backup-C").
|
||||
Labels(velerov1api.StorageLocationLabel, "the-really-long-location-name-that-is-much-more-than-63-c69e779").Phase(velerov1api.BackupPhaseCompleted).Backup(),
|
||||
builder.ForBackup("ns-1", "backup-1").
|
||||
ObjectMeta(
|
||||
builder.WithLabels(velerov1api.StorageLocationLabel, "the-really-long-location-name-that-is-much-more-than-63-c69e779"),
|
||||
).
|
||||
Phase(velerov1api.BackupPhaseCompleted).
|
||||
Result(),
|
||||
builder.ForBackup("ns-1", "backup-2").
|
||||
ObjectMeta(
|
||||
builder.WithLabels(velerov1api.StorageLocationLabel, "the-really-long-location-name-that-is-much-more-than-63-c69e779"),
|
||||
).
|
||||
Phase(velerov1api.BackupPhaseCompleted).
|
||||
Result(),
|
||||
builder.ForBackup("ns-1", "backup-C").
|
||||
ObjectMeta(
|
||||
builder.WithLabels(velerov1api.StorageLocationLabel, "the-really-long-location-name-that-is-much-more-than-63-c69e779"),
|
||||
).
|
||||
Phase(velerov1api.BackupPhaseCompleted).
|
||||
Result(),
|
||||
},
|
||||
expectedDeletes: sets.NewString("backup-C"),
|
||||
},
|
||||
|
|
|
@ -28,6 +28,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
|
||||
v1 "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
"github.com/heptio/velero/pkg/builder"
|
||||
"github.com/heptio/velero/pkg/generated/clientset/versioned/fake"
|
||||
informers "github.com/heptio/velero/pkg/generated/informers/externalversions"
|
||||
"github.com/heptio/velero/pkg/persistence"
|
||||
|
@ -119,6 +120,10 @@ func newBackupLocation(name, provider, bucket string) *v1.BackupStorageLocation
|
|||
}
|
||||
|
||||
func TestProcessDownloadRequest(t *testing.T) {
|
||||
defaultBackup := func() *v1.Backup {
|
||||
return builder.ForBackup(v1.DefaultNamespace, "a-backup").StorageLocation("a-location").Result()
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
key string
|
||||
|
@ -145,94 +150,94 @@ func TestProcessDownloadRequest(t *testing.T) {
|
|||
{
|
||||
name: "backup contents request for nonexistent backup returns an error",
|
||||
downloadRequest: newDownloadRequest("", v1.DownloadTargetKindBackupContents, "a-backup"),
|
||||
backup: defaultBackup().Name("non-matching-backup").StorageLocation("a-location").Backup(),
|
||||
backup: builder.ForBackup(v1.DefaultNamespace, "non-matching-backup").StorageLocation("a-location").Result(),
|
||||
backupLocation: newBackupLocation("a-location", "a-provider", "a-bucket"),
|
||||
expectedErr: "backup.velero.io \"a-backup\" not found",
|
||||
},
|
||||
{
|
||||
name: "restore log request for nonexistent restore returns an error",
|
||||
downloadRequest: newDownloadRequest("", v1.DownloadTargetKindRestoreLog, "a-backup-20170912150214"),
|
||||
restore: velerotest.NewTestRestore(v1.DefaultNamespace, "non-matching-restore", v1.RestorePhaseCompleted).WithBackup("a-backup").Restore,
|
||||
backup: defaultBackup().Name("a-backup").StorageLocation("a-location").Backup(),
|
||||
restore: builder.ForRestore(v1.DefaultNamespace, "non-matching-restore").Phase(v1.RestorePhaseCompleted).Backup("a-backup").Result(),
|
||||
backup: defaultBackup(),
|
||||
backupLocation: newBackupLocation("a-location", "a-provider", "a-bucket"),
|
||||
expectedErr: "error getting Restore: restore.velero.io \"a-backup-20170912150214\" not found",
|
||||
},
|
||||
{
|
||||
name: "backup contents request for backup with nonexistent location returns an error",
|
||||
downloadRequest: newDownloadRequest("", v1.DownloadTargetKindBackupContents, "a-backup"),
|
||||
backup: defaultBackup().Name("a-backup").StorageLocation("a-location").Backup(),
|
||||
backup: defaultBackup(),
|
||||
backupLocation: newBackupLocation("non-matching-location", "a-provider", "a-bucket"),
|
||||
expectedErr: "backupstoragelocation.velero.io \"a-location\" not found",
|
||||
},
|
||||
{
|
||||
name: "backup contents request with phase '' gets a url",
|
||||
downloadRequest: newDownloadRequest("", v1.DownloadTargetKindBackupContents, "a-backup"),
|
||||
backup: defaultBackup().Name("a-backup").StorageLocation("a-location").Backup(),
|
||||
backup: defaultBackup(),
|
||||
backupLocation: newBackupLocation("a-location", "a-provider", "a-bucket"),
|
||||
expectGetsURL: true,
|
||||
},
|
||||
{
|
||||
name: "backup contents request with phase 'New' gets a url",
|
||||
downloadRequest: newDownloadRequest(v1.DownloadRequestPhaseNew, v1.DownloadTargetKindBackupContents, "a-backup"),
|
||||
backup: defaultBackup().Name("a-backup").StorageLocation("a-location").Backup(),
|
||||
backup: defaultBackup(),
|
||||
backupLocation: newBackupLocation("a-location", "a-provider", "a-bucket"),
|
||||
expectGetsURL: true,
|
||||
},
|
||||
{
|
||||
name: "backup log request with phase '' gets a url",
|
||||
downloadRequest: newDownloadRequest("", v1.DownloadTargetKindBackupLog, "a-backup"),
|
||||
backup: defaultBackup().Name("a-backup").StorageLocation("a-location").Backup(),
|
||||
backup: defaultBackup(),
|
||||
backupLocation: newBackupLocation("a-location", "a-provider", "a-bucket"),
|
||||
expectGetsURL: true,
|
||||
},
|
||||
{
|
||||
name: "backup log request with phase 'New' gets a url",
|
||||
downloadRequest: newDownloadRequest(v1.DownloadRequestPhaseNew, v1.DownloadTargetKindBackupLog, "a-backup"),
|
||||
backup: defaultBackup().Name("a-backup").StorageLocation("a-location").Backup(),
|
||||
backup: defaultBackup(),
|
||||
backupLocation: newBackupLocation("a-location", "a-provider", "a-bucket"),
|
||||
expectGetsURL: true,
|
||||
},
|
||||
{
|
||||
name: "restore log request with phase '' gets a url",
|
||||
downloadRequest: newDownloadRequest("", v1.DownloadTargetKindRestoreLog, "a-backup-20170912150214"),
|
||||
restore: velerotest.NewTestRestore(v1.DefaultNamespace, "a-backup-20170912150214", v1.RestorePhaseCompleted).WithBackup("a-backup").Restore,
|
||||
backup: defaultBackup().Name("a-backup").StorageLocation("a-location").Backup(),
|
||||
restore: builder.ForRestore(v1.DefaultNamespace, "a-backup-20170912150214").Phase(v1.RestorePhaseCompleted).Backup("a-backup").Result(),
|
||||
backup: defaultBackup(),
|
||||
backupLocation: newBackupLocation("a-location", "a-provider", "a-bucket"),
|
||||
expectGetsURL: true,
|
||||
},
|
||||
{
|
||||
name: "restore log request with phase 'New' gets a url",
|
||||
downloadRequest: newDownloadRequest(v1.DownloadRequestPhaseNew, v1.DownloadTargetKindRestoreLog, "a-backup-20170912150214"),
|
||||
restore: velerotest.NewTestRestore(v1.DefaultNamespace, "a-backup-20170912150214", v1.RestorePhaseCompleted).WithBackup("a-backup").Restore,
|
||||
backup: defaultBackup().Name("a-backup").StorageLocation("a-location").Backup(),
|
||||
restore: builder.ForRestore(v1.DefaultNamespace, "a-backup-20170912150214").Phase(v1.RestorePhaseCompleted).Backup("a-backup").Result(),
|
||||
backup: defaultBackup(),
|
||||
backupLocation: newBackupLocation("a-location", "a-provider", "a-bucket"),
|
||||
expectGetsURL: true,
|
||||
},
|
||||
{
|
||||
name: "restore results request with phase '' gets a url",
|
||||
downloadRequest: newDownloadRequest("", v1.DownloadTargetKindRestoreResults, "a-backup-20170912150214"),
|
||||
restore: velerotest.NewTestRestore(v1.DefaultNamespace, "a-backup-20170912150214", v1.RestorePhaseCompleted).WithBackup("a-backup").Restore,
|
||||
backup: defaultBackup().Name("a-backup").StorageLocation("a-location").Backup(),
|
||||
restore: builder.ForRestore(v1.DefaultNamespace, "a-backup-20170912150214").Phase(v1.RestorePhaseCompleted).Backup("a-backup").Result(),
|
||||
backup: defaultBackup(),
|
||||
backupLocation: newBackupLocation("a-location", "a-provider", "a-bucket"),
|
||||
expectGetsURL: true,
|
||||
},
|
||||
{
|
||||
name: "restore results request with phase 'New' gets a url",
|
||||
downloadRequest: newDownloadRequest(v1.DownloadRequestPhaseNew, v1.DownloadTargetKindRestoreResults, "a-backup-20170912150214"),
|
||||
restore: velerotest.NewTestRestore(v1.DefaultNamespace, "a-backup-20170912150214", v1.RestorePhaseCompleted).WithBackup("a-backup").Restore,
|
||||
backup: defaultBackup().Name("a-backup").StorageLocation("a-location").Backup(),
|
||||
restore: builder.ForRestore(v1.DefaultNamespace, "a-backup-20170912150214").Phase(v1.RestorePhaseCompleted).Backup("a-backup").Result(),
|
||||
backup: defaultBackup(),
|
||||
backupLocation: newBackupLocation("a-location", "a-provider", "a-bucket"),
|
||||
expectGetsURL: true,
|
||||
},
|
||||
{
|
||||
name: "request with phase 'Processed' is not deleted if not expired",
|
||||
downloadRequest: newDownloadRequest(v1.DownloadRequestPhaseProcessed, v1.DownloadTargetKindBackupLog, "a-backup-20170912150214"),
|
||||
backup: defaultBackup().Name("a-backup").StorageLocation("a-location").Backup(),
|
||||
backup: defaultBackup(),
|
||||
},
|
||||
{
|
||||
name: "request with phase 'Processed' is deleted if expired",
|
||||
downloadRequest: newDownloadRequest(v1.DownloadRequestPhaseProcessed, v1.DownloadTargetKindBackupLog, "a-backup-20170912150214"),
|
||||
backup: defaultBackup().Name("a-backup").StorageLocation("a-location").Backup(),
|
||||
backup: defaultBackup(),
|
||||
expired: true,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import (
|
|||
core "k8s.io/client-go/testing"
|
||||
|
||||
api "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
"github.com/heptio/velero/pkg/builder"
|
||||
"github.com/heptio/velero/pkg/generated/clientset/versioned/fake"
|
||||
informers "github.com/heptio/velero/pkg/generated/informers/externalversions"
|
||||
"github.com/heptio/velero/pkg/util/kube"
|
||||
|
@ -66,7 +67,7 @@ func TestGCControllerEnqueueAllBackups(t *testing.T) {
|
|||
var expected []string
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
backup := defaultBackup().Name(fmt.Sprintf("backup-%d", i)).Backup()
|
||||
backup := builder.ForBackup(api.DefaultNamespace, fmt.Sprintf("backup-%d", i)).Result()
|
||||
sharedInformers.Velero().V1().Backups().Informer().GetStore().Add(backup)
|
||||
expected = append(expected, kube.NamespaceAndName(backup))
|
||||
}
|
||||
|
@ -97,7 +98,7 @@ Loop:
|
|||
}
|
||||
|
||||
func TestGCControllerHasUpdateFunc(t *testing.T) {
|
||||
backup := defaultBackup().Backup()
|
||||
backup := defaultBackup().Result()
|
||||
expected := kube.NamespaceAndName(backup)
|
||||
|
||||
client := fake.NewSimpleClientset(backup)
|
||||
|
@ -151,7 +152,7 @@ func TestGCControllerHasUpdateFunc(t *testing.T) {
|
|||
|
||||
func TestGCControllerProcessQueueItem(t *testing.T) {
|
||||
fakeClock := clock.NewFakeClock(time.Now())
|
||||
defaultBackupLocation := velerotest.NewTestBackupStorageLocation().WithName("default").BackupStorageLocation
|
||||
defaultBackupLocation := builder.ForBackupStorageLocation("velero", "default").Result()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
|
@ -167,31 +168,31 @@ func TestGCControllerProcessQueueItem(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "unexpired backup is not deleted",
|
||||
backup: defaultBackup().Expiration(fakeClock.Now().Add(time.Minute)).StorageLocation("default").Backup(),
|
||||
backup: defaultBackup().Expiration(fakeClock.Now().Add(time.Minute)).StorageLocation("default").Result(),
|
||||
backupLocation: defaultBackupLocation,
|
||||
expectDeletion: false,
|
||||
},
|
||||
{
|
||||
name: "expired backup in read-only storage location is not deleted",
|
||||
backup: defaultBackup().Expiration(fakeClock.Now().Add(-time.Minute)).StorageLocation("read-only").Backup(),
|
||||
backupLocation: velerotest.NewTestBackupStorageLocation().WithName("read-only").WithAccessMode(api.BackupStorageLocationAccessModeReadOnly).BackupStorageLocation,
|
||||
backup: defaultBackup().Expiration(fakeClock.Now().Add(-time.Minute)).StorageLocation("read-only").Result(),
|
||||
backupLocation: builder.ForBackupStorageLocation("velero", "read-only").AccessMode(api.BackupStorageLocationAccessModeReadOnly).Result(),
|
||||
expectDeletion: false,
|
||||
},
|
||||
{
|
||||
name: "expired backup in read-write storage location is deleted",
|
||||
backup: defaultBackup().Expiration(fakeClock.Now().Add(-time.Minute)).StorageLocation("read-write").Backup(),
|
||||
backupLocation: velerotest.NewTestBackupStorageLocation().WithName("read-write").WithAccessMode(api.BackupStorageLocationAccessModeReadWrite).BackupStorageLocation,
|
||||
backup: defaultBackup().Expiration(fakeClock.Now().Add(-time.Minute)).StorageLocation("read-write").Result(),
|
||||
backupLocation: builder.ForBackupStorageLocation("velero", "read-write").AccessMode(api.BackupStorageLocationAccessModeReadWrite).Result(),
|
||||
expectDeletion: true,
|
||||
},
|
||||
{
|
||||
name: "expired backup with no pending deletion requests is deleted",
|
||||
backup: defaultBackup().Expiration(fakeClock.Now().Add(-time.Second)).StorageLocation("default").Backup(),
|
||||
backup: defaultBackup().Expiration(fakeClock.Now().Add(-time.Second)).StorageLocation("default").Result(),
|
||||
backupLocation: defaultBackupLocation,
|
||||
expectDeletion: true,
|
||||
},
|
||||
{
|
||||
name: "expired backup with a pending deletion request is not deleted",
|
||||
backup: defaultBackup().Expiration(fakeClock.Now().Add(-time.Second)).StorageLocation("default").Backup(),
|
||||
backup: defaultBackup().Expiration(fakeClock.Now().Add(-time.Second)).StorageLocation("default").Result(),
|
||||
backupLocation: defaultBackupLocation,
|
||||
deleteBackupRequests: []*api.DeleteBackupRequest{
|
||||
{
|
||||
|
@ -212,7 +213,7 @@ func TestGCControllerProcessQueueItem(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "expired backup with only processed deletion requests is deleted",
|
||||
backup: defaultBackup().Expiration(fakeClock.Now().Add(-time.Second)).StorageLocation("default").Backup(),
|
||||
backup: defaultBackup().Expiration(fakeClock.Now().Add(-time.Second)).StorageLocation("default").Result(),
|
||||
backupLocation: defaultBackupLocation,
|
||||
deleteBackupRequests: []*api.DeleteBackupRequest{
|
||||
{
|
||||
|
@ -233,7 +234,7 @@ func TestGCControllerProcessQueueItem(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "create DeleteBackupRequest error returns an error",
|
||||
backup: defaultBackup().Expiration(fakeClock.Now().Add(-time.Second)).StorageLocation("default").Backup(),
|
||||
backup: defaultBackup().Expiration(fakeClock.Now().Add(-time.Second)).StorageLocation("default").Result(),
|
||||
backupLocation: defaultBackupLocation,
|
||||
expectDeletion: true,
|
||||
createDeleteBackupRequestError: true,
|
||||
|
|
|
@ -36,7 +36,7 @@ import (
|
|||
"k8s.io/client-go/tools/cache"
|
||||
|
||||
api "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
velerov1api "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
"github.com/heptio/velero/pkg/builder"
|
||||
"github.com/heptio/velero/pkg/generated/clientset/versioned/fake"
|
||||
informers "github.com/heptio/velero/pkg/generated/informers/externalversions"
|
||||
listers "github.com/heptio/velero/pkg/generated/listers/velero/v1"
|
||||
|
@ -66,17 +66,17 @@ func TestFetchBackupInfo(t *testing.T) {
|
|||
{
|
||||
name: "lister has backup",
|
||||
backupName: "backup-1",
|
||||
informerLocations: []*api.BackupStorageLocation{velerotest.NewTestBackupStorageLocation().WithName("default").WithProvider("myCloud").WithObjectStorage("bucket").BackupStorageLocation},
|
||||
informerBackups: []*api.Backup{defaultBackup().StorageLocation("default").Backup()},
|
||||
expectedRes: defaultBackup().StorageLocation("default").Backup(),
|
||||
informerLocations: []*api.BackupStorageLocation{builder.ForBackupStorageLocation("velero", "default").Provider("myCloud").ObjectStorage("bucket").Result()},
|
||||
informerBackups: []*api.Backup{defaultBackup().StorageLocation("default").Result()},
|
||||
expectedRes: defaultBackup().StorageLocation("default").Result(),
|
||||
},
|
||||
{
|
||||
name: "lister does not have a backup, but backupSvc does",
|
||||
backupName: "backup-1",
|
||||
backupStoreBackup: defaultBackup().StorageLocation("default").Backup(),
|
||||
informerLocations: []*api.BackupStorageLocation{velerotest.NewTestBackupStorageLocation().WithName("default").WithProvider("myCloud").WithObjectStorage("bucket").BackupStorageLocation},
|
||||
informerBackups: []*api.Backup{defaultBackup().StorageLocation("default").Backup()},
|
||||
expectedRes: defaultBackup().StorageLocation("default").Backup(),
|
||||
backupStoreBackup: defaultBackup().StorageLocation("default").Result(),
|
||||
informerLocations: []*api.BackupStorageLocation{builder.ForBackupStorageLocation("velero", "default").Provider("myCloud").ObjectStorage("bucket").Result()},
|
||||
informerBackups: []*api.Backup{defaultBackup().StorageLocation("default").Result()},
|
||||
expectedRes: defaultBackup().StorageLocation("default").Result(),
|
||||
},
|
||||
{
|
||||
name: "no backup",
|
||||
|
@ -173,17 +173,17 @@ func TestProcessQueueItemSkips(t *testing.T) {
|
|||
{
|
||||
name: "restore with phase InProgress does not get processed",
|
||||
restoreKey: "foo/bar",
|
||||
restore: velerotest.NewTestRestore("foo", "bar", api.RestorePhaseInProgress).Restore,
|
||||
restore: builder.ForRestore("foo", "bar").Phase(api.RestorePhaseInProgress).Result(),
|
||||
},
|
||||
{
|
||||
name: "restore with phase Completed does not get processed",
|
||||
restoreKey: "foo/bar",
|
||||
restore: velerotest.NewTestRestore("foo", "bar", api.RestorePhaseCompleted).Restore,
|
||||
restore: builder.ForRestore("foo", "bar").Phase(api.RestorePhaseCompleted).Result(),
|
||||
},
|
||||
{
|
||||
name: "restore with phase FailedValidation does not get processed",
|
||||
restoreKey: "foo/bar",
|
||||
restore: velerotest.NewTestRestore("foo", "bar", api.RestorePhaseFailedValidation).Restore,
|
||||
restore: builder.ForRestore("foo", "bar").Phase(api.RestorePhaseFailedValidation).Result(),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -227,6 +227,8 @@ func TestProcessQueueItemSkips(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestProcessQueueItem(t *testing.T) {
|
||||
defaultStorageLocation := builder.ForBackupStorageLocation("velero", "default").Provider("myCloud").ObjectStorage("bucket").Result()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
restoreKey string
|
||||
|
@ -246,48 +248,48 @@ func TestProcessQueueItem(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
name: "restore with both namespace in both includedNamespaces and excludedNamespaces fails validation",
|
||||
location: velerotest.NewTestBackupStorageLocation().WithName("default").WithProvider("myCloud").WithObjectStorage("bucket").BackupStorageLocation,
|
||||
restore: NewRestore("foo", "bar", "backup-1", "another-1", "*", api.RestorePhaseNew).WithExcludedNamespace("another-1").Restore,
|
||||
backup: defaultBackup().StorageLocation("default").Backup(),
|
||||
location: defaultStorageLocation,
|
||||
restore: NewRestore("foo", "bar", "backup-1", "another-1", "*", api.RestorePhaseNew).ExcludedNamespaces("another-1").Result(),
|
||||
backup: defaultBackup().StorageLocation("default").Result(),
|
||||
expectedErr: false,
|
||||
expectedPhase: string(api.RestorePhaseFailedValidation),
|
||||
expectedValidationErrors: []string{"Invalid included/excluded namespace lists: excludes list cannot contain an item in the includes list: another-1"},
|
||||
},
|
||||
{
|
||||
name: "restore with resource in both includedResources and excludedResources fails validation",
|
||||
location: velerotest.NewTestBackupStorageLocation().WithName("default").WithProvider("myCloud").WithObjectStorage("bucket").BackupStorageLocation,
|
||||
restore: NewRestore("foo", "bar", "backup-1", "*", "a-resource", api.RestorePhaseNew).WithExcludedResource("a-resource").Restore,
|
||||
backup: defaultBackup().StorageLocation("default").Backup(),
|
||||
location: defaultStorageLocation,
|
||||
restore: NewRestore("foo", "bar", "backup-1", "*", "a-resource", api.RestorePhaseNew).ExcludedResources("a-resource").Result(),
|
||||
backup: defaultBackup().StorageLocation("default").Result(),
|
||||
expectedErr: false,
|
||||
expectedPhase: string(api.RestorePhaseFailedValidation),
|
||||
expectedValidationErrors: []string{"Invalid included/excluded resource lists: excludes list cannot contain an item in the includes list: a-resource"},
|
||||
},
|
||||
{
|
||||
name: "new restore with empty backup and schedule names fails validation",
|
||||
restore: NewRestore("foo", "bar", "", "ns-1", "", api.RestorePhaseNew).Restore,
|
||||
restore: NewRestore("foo", "bar", "", "ns-1", "", api.RestorePhaseNew).Result(),
|
||||
expectedErr: false,
|
||||
expectedPhase: string(api.RestorePhaseFailedValidation),
|
||||
expectedValidationErrors: []string{"Either a backup or schedule must be specified as a source for the restore, but not both"},
|
||||
},
|
||||
{
|
||||
name: "new restore with backup and schedule names provided fails validation",
|
||||
restore: NewRestore("foo", "bar", "backup-1", "ns-1", "", api.RestorePhaseNew).WithSchedule("sched-1").Restore,
|
||||
restore: NewRestore("foo", "bar", "backup-1", "ns-1", "", api.RestorePhaseNew).Schedule("sched-1").Result(),
|
||||
expectedErr: false,
|
||||
expectedPhase: string(api.RestorePhaseFailedValidation),
|
||||
expectedValidationErrors: []string{"Either a backup or schedule must be specified as a source for the restore, but not both"},
|
||||
},
|
||||
{
|
||||
name: "valid restore with schedule name gets executed",
|
||||
location: velerotest.NewTestBackupStorageLocation().WithName("default").WithProvider("myCloud").WithObjectStorage("bucket").BackupStorageLocation,
|
||||
restore: NewRestore("foo", "bar", "", "ns-1", "", api.RestorePhaseNew).WithSchedule("sched-1").Restore,
|
||||
backup: defaultBackup().StorageLocation("default").Labels(velerov1api.ScheduleNameLabel, "sched-1").Phase(api.BackupPhaseCompleted).Backup(),
|
||||
location: defaultStorageLocation,
|
||||
restore: NewRestore("foo", "bar", "", "ns-1", "", api.RestorePhaseNew).Schedule("sched-1").Result(),
|
||||
backup: defaultBackup().StorageLocation("default").ObjectMeta(builder.WithLabels(api.ScheduleNameLabel, "sched-1")).Phase(api.BackupPhaseCompleted).Result(),
|
||||
expectedErr: false,
|
||||
expectedPhase: string(api.RestorePhaseInProgress),
|
||||
expectedRestorerCall: NewRestore("foo", "bar", "backup-1", "ns-1", "", api.RestorePhaseInProgress).WithSchedule("sched-1").Restore,
|
||||
expectedRestorerCall: NewRestore("foo", "bar", "backup-1", "ns-1", "", api.RestorePhaseInProgress).Schedule("sched-1").Result(),
|
||||
},
|
||||
{
|
||||
name: "restore with non-existent backup name fails",
|
||||
restore: NewRestore("foo", "bar", "backup-1", "ns-1", "*", api.RestorePhaseNew).Restore,
|
||||
restore: NewRestore("foo", "bar", "backup-1", "ns-1", "*", api.RestorePhaseNew).Result(),
|
||||
expectedErr: false,
|
||||
expectedPhase: string(api.RestorePhaseFailedValidation),
|
||||
expectedValidationErrors: []string{"Error retrieving backup: backup.velero.io \"backup-1\" not found"},
|
||||
|
@ -295,30 +297,30 @@ func TestProcessQueueItem(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "restorer throwing an error causes the restore to fail",
|
||||
location: velerotest.NewTestBackupStorageLocation().WithName("default").WithProvider("myCloud").WithObjectStorage("bucket").BackupStorageLocation,
|
||||
restore: NewRestore("foo", "bar", "backup-1", "ns-1", "", api.RestorePhaseNew).Restore,
|
||||
backup: defaultBackup().StorageLocation("default").Backup(),
|
||||
location: defaultStorageLocation,
|
||||
restore: NewRestore("foo", "bar", "backup-1", "ns-1", "", api.RestorePhaseNew).Result(),
|
||||
backup: defaultBackup().StorageLocation("default").Result(),
|
||||
restorerError: errors.New("blarg"),
|
||||
expectedErr: false,
|
||||
expectedPhase: string(api.RestorePhaseInProgress),
|
||||
expectedFinalPhase: string(api.RestorePhasePartiallyFailed),
|
||||
expectedRestoreErrors: 1,
|
||||
expectedRestorerCall: NewRestore("foo", "bar", "backup-1", "ns-1", "", api.RestorePhaseInProgress).Restore,
|
||||
expectedRestorerCall: NewRestore("foo", "bar", "backup-1", "ns-1", "", api.RestorePhaseInProgress).Result(),
|
||||
},
|
||||
{
|
||||
name: "valid restore gets executed",
|
||||
location: velerotest.NewTestBackupStorageLocation().WithName("default").WithProvider("myCloud").WithObjectStorage("bucket").BackupStorageLocation,
|
||||
restore: NewRestore("foo", "bar", "backup-1", "ns-1", "", api.RestorePhaseNew).Restore,
|
||||
backup: defaultBackup().StorageLocation("default").Backup(),
|
||||
location: defaultStorageLocation,
|
||||
restore: NewRestore("foo", "bar", "backup-1", "ns-1", "", api.RestorePhaseNew).Result(),
|
||||
backup: defaultBackup().StorageLocation("default").Result(),
|
||||
expectedErr: false,
|
||||
expectedPhase: string(api.RestorePhaseInProgress),
|
||||
expectedRestorerCall: NewRestore("foo", "bar", "backup-1", "ns-1", "", api.RestorePhaseInProgress).Restore,
|
||||
expectedRestorerCall: NewRestore("foo", "bar", "backup-1", "ns-1", "", api.RestorePhaseInProgress).Result(),
|
||||
},
|
||||
{
|
||||
name: "restoration of nodes is not supported",
|
||||
location: velerotest.NewTestBackupStorageLocation().WithName("default").WithProvider("myCloud").WithObjectStorage("bucket").BackupStorageLocation,
|
||||
restore: NewRestore("foo", "bar", "backup-1", "ns-1", "nodes", api.RestorePhaseNew).Restore,
|
||||
backup: defaultBackup().StorageLocation("default").Backup(),
|
||||
location: defaultStorageLocation,
|
||||
restore: NewRestore("foo", "bar", "backup-1", "ns-1", "nodes", api.RestorePhaseNew).Result(),
|
||||
backup: defaultBackup().StorageLocation("default").Result(),
|
||||
expectedErr: false,
|
||||
expectedPhase: string(api.RestorePhaseFailedValidation),
|
||||
expectedValidationErrors: []string{
|
||||
|
@ -328,9 +330,9 @@ func TestProcessQueueItem(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "restoration of events is not supported",
|
||||
location: velerotest.NewTestBackupStorageLocation().WithName("default").WithProvider("myCloud").WithObjectStorage("bucket").BackupStorageLocation,
|
||||
restore: NewRestore("foo", "bar", "backup-1", "ns-1", "events", api.RestorePhaseNew).Restore,
|
||||
backup: defaultBackup().StorageLocation("default").Backup(),
|
||||
location: defaultStorageLocation,
|
||||
restore: NewRestore("foo", "bar", "backup-1", "ns-1", "events", api.RestorePhaseNew).Result(),
|
||||
backup: defaultBackup().StorageLocation("default").Result(),
|
||||
expectedErr: false,
|
||||
expectedPhase: string(api.RestorePhaseFailedValidation),
|
||||
expectedValidationErrors: []string{
|
||||
|
@ -340,9 +342,9 @@ func TestProcessQueueItem(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "restoration of events.events.k8s.io is not supported",
|
||||
location: velerotest.NewTestBackupStorageLocation().WithName("default").WithProvider("myCloud").WithObjectStorage("bucket").BackupStorageLocation,
|
||||
restore: NewRestore("foo", "bar", "backup-1", "ns-1", "events.events.k8s.io", api.RestorePhaseNew).Restore,
|
||||
backup: defaultBackup().StorageLocation("default").Backup(),
|
||||
location: defaultStorageLocation,
|
||||
restore: NewRestore("foo", "bar", "backup-1", "ns-1", "events.events.k8s.io", api.RestorePhaseNew).Result(),
|
||||
backup: defaultBackup().StorageLocation("default").Result(),
|
||||
expectedErr: false,
|
||||
expectedPhase: string(api.RestorePhaseFailedValidation),
|
||||
expectedValidationErrors: []string{
|
||||
|
@ -352,9 +354,9 @@ func TestProcessQueueItem(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "restoration of backups.velero.io is not supported",
|
||||
location: velerotest.NewTestBackupStorageLocation().WithName("default").WithProvider("myCloud").WithObjectStorage("bucket").BackupStorageLocation,
|
||||
restore: NewRestore("foo", "bar", "backup-1", "ns-1", "backups.velero.io", api.RestorePhaseNew).Restore,
|
||||
backup: defaultBackup().StorageLocation("default").Backup(),
|
||||
location: defaultStorageLocation,
|
||||
restore: NewRestore("foo", "bar", "backup-1", "ns-1", "backups.velero.io", api.RestorePhaseNew).Result(),
|
||||
backup: defaultBackup().StorageLocation("default").Result(),
|
||||
expectedErr: false,
|
||||
expectedPhase: string(api.RestorePhaseFailedValidation),
|
||||
expectedValidationErrors: []string{
|
||||
|
@ -364,9 +366,9 @@ func TestProcessQueueItem(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "restoration of restores.velero.io is not supported",
|
||||
location: velerotest.NewTestBackupStorageLocation().WithName("default").WithProvider("myCloud").WithObjectStorage("bucket").BackupStorageLocation,
|
||||
restore: NewRestore("foo", "bar", "backup-1", "ns-1", "restores.velero.io", api.RestorePhaseNew).Restore,
|
||||
backup: defaultBackup().StorageLocation("default").Backup(),
|
||||
location: defaultStorageLocation,
|
||||
restore: NewRestore("foo", "bar", "backup-1", "ns-1", "restores.velero.io", api.RestorePhaseNew).Result(),
|
||||
backup: defaultBackup().StorageLocation("default").Result(),
|
||||
expectedErr: false,
|
||||
expectedPhase: string(api.RestorePhaseFailedValidation),
|
||||
expectedValidationErrors: []string{
|
||||
|
@ -376,12 +378,12 @@ func TestProcessQueueItem(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "backup download error results in failed restore",
|
||||
location: velerotest.NewTestBackupStorageLocation().WithName("default").WithProvider("myCloud").WithObjectStorage("bucket").BackupStorageLocation,
|
||||
restore: NewRestore(api.DefaultNamespace, "bar", "backup-1", "ns-1", "", api.RestorePhaseNew).Restore,
|
||||
location: defaultStorageLocation,
|
||||
restore: NewRestore(api.DefaultNamespace, "bar", "backup-1", "ns-1", "", api.RestorePhaseNew).Result(),
|
||||
expectedPhase: string(api.RestorePhaseInProgress),
|
||||
expectedFinalPhase: string(api.RestorePhaseFailed),
|
||||
backupStoreGetBackupContentsErr: errors.New("Couldn't download backup"),
|
||||
backup: defaultBackup().StorageLocation("default").Backup(),
|
||||
backup: defaultBackup().StorageLocation("default").Result(),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -656,9 +658,9 @@ func TestvalidateAndCompleteWhenScheduleNameSpecified(t *testing.T) {
|
|||
// no backups created from the schedule: fail validation
|
||||
require.NoError(t, sharedInformers.Velero().V1().Backups().Informer().GetStore().Add(
|
||||
defaultBackup().
|
||||
Labels(velerov1api.ScheduleNameLabel, "non-matching-schedule").
|
||||
Phase(velerov1api.BackupPhaseCompleted).
|
||||
Backup(),
|
||||
ObjectMeta(builder.WithLabels(api.ScheduleNameLabel, "non-matching-schedule")).
|
||||
Phase(api.BackupPhaseCompleted).
|
||||
Result(),
|
||||
))
|
||||
|
||||
errs := c.validateAndComplete(restore, pluginManager)
|
||||
|
@ -668,10 +670,12 @@ func TestvalidateAndCompleteWhenScheduleNameSpecified(t *testing.T) {
|
|||
// no completed backups created from the schedule: fail validation
|
||||
require.NoError(t, sharedInformers.Velero().V1().Backups().Informer().GetStore().Add(
|
||||
defaultBackup().
|
||||
Name("backup-2").
|
||||
Labels(velerov1api.ScheduleNameLabel, "schedule-1").
|
||||
Phase(velerov1api.BackupPhaseInProgress).
|
||||
Backup(),
|
||||
ObjectMeta(
|
||||
builder.WithName("backup-2"),
|
||||
builder.WithLabels(api.ScheduleNameLabel, "schedule-1"),
|
||||
).
|
||||
Phase(api.BackupPhaseInProgress).
|
||||
Result(),
|
||||
))
|
||||
|
||||
errs = c.validateAndComplete(restore, pluginManager)
|
||||
|
@ -683,19 +687,23 @@ func TestvalidateAndCompleteWhenScheduleNameSpecified(t *testing.T) {
|
|||
|
||||
require.NoError(t, sharedInformers.Velero().V1().Backups().Informer().GetStore().Add(
|
||||
defaultBackup().
|
||||
Name("foo").
|
||||
Labels(velerov1api.ScheduleNameLabel, "schedule-1").
|
||||
Phase(velerov1api.BackupPhaseCompleted).
|
||||
ObjectMeta(
|
||||
builder.WithName("foo"),
|
||||
builder.WithLabels(api.ScheduleNameLabel, "schedule-1"),
|
||||
).
|
||||
Phase(api.BackupPhaseCompleted).
|
||||
StartTimestamp(now).
|
||||
Backup(),
|
||||
Result(),
|
||||
))
|
||||
require.NoError(t, sharedInformers.Velero().V1().Backups().Informer().GetStore().Add(
|
||||
defaultBackup().
|
||||
Name("foo").
|
||||
Labels(velerov1api.ScheduleNameLabel, "schedule-1").
|
||||
Phase(velerov1api.BackupPhaseCompleted).
|
||||
ObjectMeta(
|
||||
builder.WithName("foo"),
|
||||
builder.WithLabels(api.ScheduleNameLabel, "schedule-1"),
|
||||
).
|
||||
Phase(api.BackupPhaseCompleted).
|
||||
StartTimestamp(now.Add(time.Second)).
|
||||
Backup(),
|
||||
Result(),
|
||||
))
|
||||
|
||||
errs = c.validateAndComplete(restore, pluginManager)
|
||||
|
@ -792,20 +800,18 @@ func TestMostRecentCompletedBackup(t *testing.T) {
|
|||
assert.Equal(t, expected, mostRecentCompletedBackup(backups))
|
||||
}
|
||||
|
||||
func NewRestore(ns, name, backup, includeNS, includeResource string, phase api.RestorePhase) *velerotest.TestRestore {
|
||||
restore := velerotest.NewTestRestore(ns, name, phase).WithBackup(backup)
|
||||
func NewRestore(ns, name, backup, includeNS, includeResource string, phase api.RestorePhase) *builder.RestoreBuilder {
|
||||
restore := builder.ForRestore(ns, name).Phase(phase).Backup(backup)
|
||||
|
||||
if includeNS != "" {
|
||||
restore = restore.WithIncludedNamespace(includeNS)
|
||||
restore = restore.IncludedNamespaces(includeNS)
|
||||
}
|
||||
|
||||
if includeResource != "" {
|
||||
restore = restore.WithIncludedResource(includeResource)
|
||||
restore = restore.IncludedResources(includeResource)
|
||||
}
|
||||
|
||||
for _, n := range nonRestorableResources {
|
||||
restore = restore.WithExcludedResource(n)
|
||||
}
|
||||
restore.ExcludedResources(nonRestorableResources...)
|
||||
|
||||
return restore
|
||||
}
|
||||
|
|
|
@ -31,8 +31,8 @@ import (
|
|||
core "k8s.io/client-go/testing"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
|
||||
api "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
velerov1api "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
"github.com/heptio/velero/pkg/builder"
|
||||
"github.com/heptio/velero/pkg/generated/clientset/versioned/fake"
|
||||
informers "github.com/heptio/velero/pkg/generated/informers/externalversions"
|
||||
"github.com/heptio/velero/pkg/metrics"
|
||||
|
@ -40,15 +40,19 @@ import (
|
|||
)
|
||||
|
||||
func TestProcessSchedule(t *testing.T) {
|
||||
newScheduleBuilder := func(phase velerov1api.SchedulePhase) *builder.ScheduleBuilder {
|
||||
return builder.ForSchedule("ns", "name").Phase(phase)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
scheduleKey string
|
||||
schedule *api.Schedule
|
||||
schedule *velerov1api.Schedule
|
||||
fakeClockTime string
|
||||
expectedErr bool
|
||||
expectedPhase string
|
||||
expectedValidationErrors []string
|
||||
expectedBackupCreate *api.Backup
|
||||
expectedBackupCreate *velerov1api.Backup
|
||||
expectedLastBackup string
|
||||
}{
|
||||
{
|
||||
|
@ -63,54 +67,53 @@ func TestProcessSchedule(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "schedule with phase FailedValidation does not get processed",
|
||||
schedule: velerotest.NewTestSchedule("ns", "name").WithPhase(api.SchedulePhaseFailedValidation).Schedule,
|
||||
schedule: newScheduleBuilder(velerov1api.SchedulePhaseFailedValidation).Result(),
|
||||
expectedErr: false,
|
||||
},
|
||||
{
|
||||
name: "schedule with phase New gets validated and failed if invalid",
|
||||
schedule: velerotest.NewTestSchedule("ns", "name").WithPhase(api.SchedulePhaseNew).Schedule,
|
||||
schedule: newScheduleBuilder(velerov1api.SchedulePhaseNew).Result(),
|
||||
expectedErr: false,
|
||||
expectedPhase: string(api.SchedulePhaseFailedValidation),
|
||||
expectedPhase: string(velerov1api.SchedulePhaseFailedValidation),
|
||||
expectedValidationErrors: []string{"Schedule must be a non-empty valid Cron expression"},
|
||||
},
|
||||
{
|
||||
name: "schedule with phase <blank> gets validated and failed if invalid",
|
||||
schedule: velerotest.NewTestSchedule("ns", "name").Schedule,
|
||||
schedule: newScheduleBuilder(velerov1api.SchedulePhase("")).Result(),
|
||||
expectedErr: false,
|
||||
expectedPhase: string(api.SchedulePhaseFailedValidation),
|
||||
expectedPhase: string(velerov1api.SchedulePhaseFailedValidation),
|
||||
expectedValidationErrors: []string{"Schedule must be a non-empty valid Cron expression"},
|
||||
},
|
||||
{
|
||||
name: "schedule with phase Enabled gets re-validated and failed if invalid",
|
||||
schedule: velerotest.NewTestSchedule("ns", "name").WithPhase(api.SchedulePhaseEnabled).Schedule,
|
||||
schedule: newScheduleBuilder(velerov1api.SchedulePhaseEnabled).Result(),
|
||||
expectedErr: false,
|
||||
expectedPhase: string(api.SchedulePhaseFailedValidation),
|
||||
expectedPhase: string(velerov1api.SchedulePhaseFailedValidation),
|
||||
expectedValidationErrors: []string{"Schedule must be a non-empty valid Cron expression"},
|
||||
},
|
||||
{
|
||||
name: "schedule with phase New gets validated and triggers a backup",
|
||||
schedule: velerotest.NewTestSchedule("ns", "name").WithPhase(api.SchedulePhaseNew).WithCronSchedule("@every 5m").Schedule,
|
||||
schedule: newScheduleBuilder(velerov1api.SchedulePhaseNew).CronSchedule("@every 5m").Result(),
|
||||
fakeClockTime: "2017-01-01 12:00:00",
|
||||
expectedErr: false,
|
||||
expectedPhase: string(api.SchedulePhaseEnabled),
|
||||
expectedBackupCreate: defaultBackup().Namespace("ns").Name("name-20170101120000").Labels(velerov1api.ScheduleNameLabel, "name").NoTypeMeta().Backup(),
|
||||
expectedPhase: string(velerov1api.SchedulePhaseEnabled),
|
||||
expectedBackupCreate: builder.ForBackup("ns", "name-20170101120000").ObjectMeta(builder.WithLabels(velerov1api.ScheduleNameLabel, "name")).NoTypeMeta().Result(),
|
||||
expectedLastBackup: "2017-01-01 12:00:00",
|
||||
},
|
||||
{
|
||||
name: "schedule with phase Enabled gets re-validated and triggers a backup if valid",
|
||||
schedule: velerotest.NewTestSchedule("ns", "name").WithPhase(api.SchedulePhaseEnabled).WithCronSchedule("@every 5m").Schedule,
|
||||
schedule: newScheduleBuilder(velerov1api.SchedulePhaseEnabled).CronSchedule("@every 5m").Result(),
|
||||
fakeClockTime: "2017-01-01 12:00:00",
|
||||
expectedErr: false,
|
||||
expectedBackupCreate: defaultBackup().Namespace("ns").Name("name-20170101120000").Labels(velerov1api.ScheduleNameLabel, "name").NoTypeMeta().Backup(),
|
||||
expectedBackupCreate: builder.ForBackup("ns", "name-20170101120000").ObjectMeta(builder.WithLabels(velerov1api.ScheduleNameLabel, "name")).NoTypeMeta().Result(),
|
||||
expectedLastBackup: "2017-01-01 12:00:00",
|
||||
},
|
||||
{
|
||||
name: "schedule that's already run gets LastBackup updated",
|
||||
schedule: velerotest.NewTestSchedule("ns", "name").WithPhase(api.SchedulePhaseEnabled).
|
||||
WithCronSchedule("@every 5m").WithLastBackupTime("2000-01-01 00:00:00").Schedule,
|
||||
name: "schedule that's already run gets LastBackup updated",
|
||||
schedule: newScheduleBuilder(velerov1api.SchedulePhaseEnabled).CronSchedule("@every 5m").LastBackupTime("2000-01-01 00:00:00").Result(),
|
||||
fakeClockTime: "2017-01-01 12:00:00",
|
||||
expectedErr: false,
|
||||
expectedBackupCreate: defaultBackup().Namespace("ns").Name("name-20170101120000").Labels(velerov1api.ScheduleNameLabel, "name").NoTypeMeta().Backup(),
|
||||
expectedBackupCreate: builder.ForBackup("ns", "name-20170101120000").ObjectMeta(builder.WithLabels(velerov1api.ScheduleNameLabel, "name")).NoTypeMeta().Result(),
|
||||
expectedLastBackup: "2017-01-01 12:00:00",
|
||||
},
|
||||
}
|
||||
|
@ -161,7 +164,7 @@ func TestProcessSchedule(t *testing.T) {
|
|||
// these are the fields that may be updated by the controller
|
||||
phase, found, err := unstructured.NestedString(patchMap, "status", "phase")
|
||||
if err == nil && found {
|
||||
res.Status.Phase = api.SchedulePhase(phase)
|
||||
res.Status.Phase = velerov1api.SchedulePhase(phase)
|
||||
}
|
||||
|
||||
lastBackupStr, found, err := unstructured.NestedString(patchMap, "status", "lastBackup")
|
||||
|
@ -192,9 +195,9 @@ func TestProcessSchedule(t *testing.T) {
|
|||
index := 0
|
||||
|
||||
type PatchStatus struct {
|
||||
ValidationErrors []string `json:"validationErrors"`
|
||||
Phase api.SchedulePhase `json:"phase"`
|
||||
LastBackup time.Time `json:"lastBackup"`
|
||||
ValidationErrors []string `json:"validationErrors"`
|
||||
Phase velerov1api.SchedulePhase `json:"phase"`
|
||||
LastBackup time.Time `json:"lastBackup"`
|
||||
}
|
||||
|
||||
type Patch struct {
|
||||
|
@ -214,7 +217,7 @@ func TestProcessSchedule(t *testing.T) {
|
|||
expected := Patch{
|
||||
Status: PatchStatus{
|
||||
ValidationErrors: test.expectedValidationErrors,
|
||||
Phase: api.SchedulePhase(test.expectedPhase),
|
||||
Phase: velerov1api.SchedulePhase(test.expectedPhase),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -227,7 +230,7 @@ func TestProcessSchedule(t *testing.T) {
|
|||
require.True(t, len(actions) > index, "len(actions) is too small")
|
||||
|
||||
action := core.NewCreateAction(
|
||||
api.SchemeGroupVersion.WithResource("backups"),
|
||||
velerov1api.SchemeGroupVersion.WithResource("backups"),
|
||||
created.Namespace,
|
||||
created)
|
||||
|
||||
|
@ -257,43 +260,47 @@ func parseTime(timeString string) time.Time {
|
|||
}
|
||||
|
||||
func TestGetNextRunTime(t *testing.T) {
|
||||
defaultSchedule := func() *velerov1api.Schedule {
|
||||
return builder.ForSchedule("velero", "schedule-1").CronSchedule("@every 5m").Result()
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
schedule *api.Schedule
|
||||
schedule *velerov1api.Schedule
|
||||
lastRanOffset string
|
||||
expectedDue bool
|
||||
expectedNextRunTimeOffset string
|
||||
}{
|
||||
{
|
||||
name: "first run",
|
||||
schedule: &api.Schedule{Spec: api.ScheduleSpec{Schedule: "@every 5m"}},
|
||||
schedule: defaultSchedule(),
|
||||
expectedDue: true,
|
||||
expectedNextRunTimeOffset: "5m",
|
||||
},
|
||||
{
|
||||
name: "just ran",
|
||||
schedule: &api.Schedule{Spec: api.ScheduleSpec{Schedule: "@every 5m"}},
|
||||
schedule: defaultSchedule(),
|
||||
lastRanOffset: "0s",
|
||||
expectedDue: false,
|
||||
expectedNextRunTimeOffset: "5m",
|
||||
},
|
||||
{
|
||||
name: "almost but not quite time to run",
|
||||
schedule: &api.Schedule{Spec: api.ScheduleSpec{Schedule: "@every 5m"}},
|
||||
schedule: defaultSchedule(),
|
||||
lastRanOffset: "4m59s",
|
||||
expectedDue: false,
|
||||
expectedNextRunTimeOffset: "5m",
|
||||
},
|
||||
{
|
||||
name: "time to run again",
|
||||
schedule: &api.Schedule{Spec: api.ScheduleSpec{Schedule: "@every 5m"}},
|
||||
schedule: defaultSchedule(),
|
||||
lastRanOffset: "5m",
|
||||
expectedDue: true,
|
||||
expectedNextRunTimeOffset: "5m",
|
||||
},
|
||||
{
|
||||
name: "several runs missed",
|
||||
schedule: &api.Schedule{Spec: api.ScheduleSpec{Schedule: "@every 5m"}},
|
||||
schedule: defaultSchedule(),
|
||||
lastRanOffset: "5h",
|
||||
expectedDue: true,
|
||||
expectedNextRunTimeOffset: "5m",
|
||||
|
@ -339,14 +346,7 @@ func TestParseCronSchedule(t *testing.T) {
|
|||
// Start with a Schedule with:
|
||||
// - schedule: once a day at 9am
|
||||
// - last backup: 2017-08-10 12:27:00 (just happened)
|
||||
s := &api.Schedule{
|
||||
Spec: api.ScheduleSpec{
|
||||
Schedule: "0 9 * * *",
|
||||
},
|
||||
Status: api.ScheduleStatus{
|
||||
LastBackup: metav1.NewTime(now),
|
||||
},
|
||||
}
|
||||
s := builder.ForSchedule("velero", "schedule-1").CronSchedule("0 9 * * *").LastBackupTime(now.Format("2006-01-02 15:04:05")).Result()
|
||||
|
||||
logger := velerotest.NewLogger()
|
||||
|
||||
|
@ -383,121 +383,51 @@ func TestParseCronSchedule(t *testing.T) {
|
|||
func TestGetBackup(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
schedule *api.Schedule
|
||||
schedule *velerov1api.Schedule
|
||||
testClockTime string
|
||||
expectedBackup *api.Backup
|
||||
expectedBackup *velerov1api.Backup
|
||||
}{
|
||||
{
|
||||
name: "ensure name is formatted correctly (AM time)",
|
||||
schedule: &api.Schedule{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "foo",
|
||||
Name: "bar",
|
||||
},
|
||||
Spec: api.ScheduleSpec{
|
||||
Template: api.BackupSpec{},
|
||||
},
|
||||
},
|
||||
testClockTime: "2017-07-25 09:15:00",
|
||||
expectedBackup: &api.Backup{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "foo",
|
||||
Name: "bar-20170725091500",
|
||||
Labels: map[string]string{
|
||||
velerov1api.ScheduleNameLabel: "bar",
|
||||
},
|
||||
},
|
||||
Spec: api.BackupSpec{},
|
||||
},
|
||||
name: "ensure name is formatted correctly (AM time)",
|
||||
schedule: builder.ForSchedule("foo", "bar").Result(),
|
||||
testClockTime: "2017-07-25 09:15:00",
|
||||
expectedBackup: builder.ForBackup("foo", "bar-20170725091500").ObjectMeta(builder.WithLabels(velerov1api.ScheduleNameLabel, "bar")).Result(),
|
||||
},
|
||||
{
|
||||
name: "ensure name is formatted correctly (PM time)",
|
||||
schedule: &api.Schedule{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "foo",
|
||||
Name: "bar",
|
||||
},
|
||||
Spec: api.ScheduleSpec{
|
||||
Template: api.BackupSpec{},
|
||||
},
|
||||
},
|
||||
testClockTime: "2017-07-25 14:15:00",
|
||||
expectedBackup: &api.Backup{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "foo",
|
||||
Name: "bar-20170725141500",
|
||||
Labels: map[string]string{
|
||||
velerov1api.ScheduleNameLabel: "bar",
|
||||
},
|
||||
},
|
||||
Spec: api.BackupSpec{},
|
||||
},
|
||||
name: "ensure name is formatted correctly (PM time)",
|
||||
schedule: builder.ForSchedule("foo", "bar").Result(),
|
||||
testClockTime: "2017-07-25 14:15:00",
|
||||
expectedBackup: builder.ForBackup("foo", "bar-20170725141500").ObjectMeta(builder.WithLabels(velerov1api.ScheduleNameLabel, "bar")).Result(),
|
||||
},
|
||||
{
|
||||
name: "ensure schedule backup template is copied",
|
||||
schedule: &api.Schedule{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "foo",
|
||||
Name: "bar",
|
||||
},
|
||||
Spec: api.ScheduleSpec{
|
||||
Template: api.BackupSpec{
|
||||
IncludedNamespaces: []string{"ns-1", "ns-2"},
|
||||
ExcludedNamespaces: []string{"ns-3"},
|
||||
IncludedResources: []string{"foo", "bar"},
|
||||
ExcludedResources: []string{"baz"},
|
||||
LabelSelector: &metav1.LabelSelector{MatchLabels: map[string]string{"label": "value"}},
|
||||
TTL: metav1.Duration{Duration: time.Duration(300)},
|
||||
},
|
||||
},
|
||||
},
|
||||
schedule: builder.ForSchedule("foo", "bar").
|
||||
Template(builder.ForBackup("", "").
|
||||
IncludedNamespaces("ns-1", "ns-2").
|
||||
ExcludedNamespaces("ns-3").
|
||||
IncludedResources("foo", "bar").
|
||||
ExcludedResources("baz").
|
||||
LabelSelector(&metav1.LabelSelector{MatchLabels: map[string]string{"label": "value"}}).
|
||||
TTL(time.Duration(300)).
|
||||
Result().
|
||||
Spec).
|
||||
Result(),
|
||||
testClockTime: "2017-07-25 09:15:00",
|
||||
expectedBackup: &api.Backup{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "foo",
|
||||
Name: "bar-20170725091500",
|
||||
Labels: map[string]string{
|
||||
velerov1api.ScheduleNameLabel: "bar",
|
||||
},
|
||||
},
|
||||
Spec: api.BackupSpec{
|
||||
IncludedNamespaces: []string{"ns-1", "ns-2"},
|
||||
ExcludedNamespaces: []string{"ns-3"},
|
||||
IncludedResources: []string{"foo", "bar"},
|
||||
ExcludedResources: []string{"baz"},
|
||||
LabelSelector: &metav1.LabelSelector{MatchLabels: map[string]string{"label": "value"}},
|
||||
TTL: metav1.Duration{Duration: time.Duration(300)},
|
||||
},
|
||||
},
|
||||
expectedBackup: builder.ForBackup("foo", "bar-20170725091500").
|
||||
ObjectMeta(builder.WithLabels(velerov1api.ScheduleNameLabel, "bar")).
|
||||
IncludedNamespaces("ns-1", "ns-2").
|
||||
ExcludedNamespaces("ns-3").
|
||||
IncludedResources("foo", "bar").
|
||||
ExcludedResources("baz").
|
||||
LabelSelector(&metav1.LabelSelector{MatchLabels: map[string]string{"label": "value"}}).
|
||||
TTL(time.Duration(300)).
|
||||
Result(),
|
||||
},
|
||||
{
|
||||
name: "ensure schedule labels is copied",
|
||||
schedule: &api.Schedule{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "foo",
|
||||
Name: "bar",
|
||||
Labels: map[string]string{
|
||||
"foo": "bar",
|
||||
"bar": "baz",
|
||||
},
|
||||
},
|
||||
Spec: api.ScheduleSpec{
|
||||
Template: api.BackupSpec{},
|
||||
},
|
||||
},
|
||||
testClockTime: "2017-07-25 14:15:00",
|
||||
expectedBackup: &api.Backup{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "foo",
|
||||
Name: "bar-20170725141500",
|
||||
Labels: map[string]string{
|
||||
velerov1api.ScheduleNameLabel: "bar",
|
||||
"bar": "baz",
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
Spec: api.BackupSpec{},
|
||||
},
|
||||
name: "ensure schedule labels is copied",
|
||||
schedule: builder.ForSchedule("foo", "bar").ObjectMeta(builder.WithLabels("foo", "bar", "bar", "baz")).Result(),
|
||||
testClockTime: "2017-07-25 14:15:00",
|
||||
expectedBackup: builder.ForBackup("foo", "bar-20170725141500").ObjectMeta(builder.WithLabels(velerov1api.ScheduleNameLabel, "bar", "bar", "baz", "foo", "bar")).Result(),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -1,114 +0,0 @@
|
|||
/*
|
||||
Copyright 2019 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.
|
||||
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 restore
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
velerov1api "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
)
|
||||
|
||||
// Builder is a helper for concisely constructing Restore API objects.
|
||||
type Builder struct {
|
||||
restore velerov1api.Restore
|
||||
}
|
||||
|
||||
// NewBuilder returns a Builder for a Restore with no namespace/name.
|
||||
func NewBuilder() *Builder {
|
||||
return NewNamedBuilder("", "")
|
||||
}
|
||||
|
||||
// NewNamedBuilder returns a Builder for a Restore with the specified namespace
|
||||
// and name.
|
||||
func NewNamedBuilder(namespace, name string) *Builder {
|
||||
return &Builder{
|
||||
restore: velerov1api.Restore{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: velerov1api.SchemeGroupVersion.String(),
|
||||
Kind: "Restore",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Restore returns the built Restore API object.
|
||||
func (b *Builder) Restore() *velerov1api.Restore {
|
||||
return &b.restore
|
||||
}
|
||||
|
||||
// Backup sets the Restore's backup name.
|
||||
func (b *Builder) Backup(name string) *Builder {
|
||||
b.restore.Spec.BackupName = name
|
||||
return b
|
||||
}
|
||||
|
||||
// IncludedNamespaces sets the Restore's included namespaces.
|
||||
func (b *Builder) IncludedNamespaces(namespaces ...string) *Builder {
|
||||
b.restore.Spec.IncludedNamespaces = namespaces
|
||||
return b
|
||||
}
|
||||
|
||||
// ExcludedNamespaces sets the Restore's excluded namespaces.
|
||||
func (b *Builder) ExcludedNamespaces(namespaces ...string) *Builder {
|
||||
b.restore.Spec.ExcludedNamespaces = namespaces
|
||||
return b
|
||||
}
|
||||
|
||||
// IncludedResources sets the Restore's included resources.
|
||||
func (b *Builder) IncludedResources(resources ...string) *Builder {
|
||||
b.restore.Spec.IncludedResources = resources
|
||||
return b
|
||||
}
|
||||
|
||||
// ExcludedResources sets the Restore's excluded resources.
|
||||
func (b *Builder) ExcludedResources(resources ...string) *Builder {
|
||||
b.restore.Spec.ExcludedResources = resources
|
||||
return b
|
||||
}
|
||||
|
||||
// IncludeClusterResources sets the Restore's "include cluster resources" flag.
|
||||
func (b *Builder) IncludeClusterResources(val bool) *Builder {
|
||||
b.restore.Spec.IncludeClusterResources = &val
|
||||
return b
|
||||
}
|
||||
|
||||
// LabelSelector sets the Restore's label selector.
|
||||
func (b *Builder) LabelSelector(selector *metav1.LabelSelector) *Builder {
|
||||
b.restore.Spec.LabelSelector = selector
|
||||
return b
|
||||
}
|
||||
|
||||
// NamespaceMappings sets the Restore's namespace mappings.
|
||||
func (b *Builder) NamespaceMappings(mapping ...string) *Builder {
|
||||
if b.restore.Spec.NamespaceMapping == nil {
|
||||
b.restore.Spec.NamespaceMapping = make(map[string]string)
|
||||
}
|
||||
|
||||
if len(mapping)%2 != 0 {
|
||||
panic("mapping must contain an even number of values")
|
||||
}
|
||||
|
||||
for i := 0; i < len(mapping); i += 2 {
|
||||
b.restore.Spec.NamespaceMapping[mapping[i]] = mapping[i+1]
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
|
@ -29,8 +29,8 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
|
||||
"github.com/heptio/velero/pkg/builder"
|
||||
"github.com/heptio/velero/pkg/plugin/velero"
|
||||
"github.com/heptio/velero/pkg/test"
|
||||
)
|
||||
|
||||
// TestChangeStorageClassActionExecute runs the ChangeStorageClassAction's Execute
|
||||
|
@ -48,93 +48,93 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
name: "a valid mapping for a persistent volume is applied correctly",
|
||||
pvOrPVC: test.NewPV("pv-1", test.WithStorageClassName("storageclass-1")),
|
||||
configMap: test.NewConfigMap("velero", "change-storage-class",
|
||||
test.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction"),
|
||||
test.WithConfigMapData("storageclass-1", "storageclass-2"),
|
||||
),
|
||||
storageClass: test.NewStorageClass("storageclass-2"),
|
||||
want: test.NewPV("pv-1", test.WithStorageClassName("storageclass-2")),
|
||||
pvOrPVC: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Data("storageclass-1", "storageclass-2").
|
||||
Result(),
|
||||
storageClass: builder.ForStorageClass("storageclass-2").Result(),
|
||||
want: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-2").Result(),
|
||||
},
|
||||
{
|
||||
name: "a valid mapping for a persistent volume claim is applied correctly",
|
||||
pvOrPVC: test.NewPVC("velero", "pvc-1", test.WithStorageClassName("storageclass-1")),
|
||||
configMap: test.NewConfigMap("velero", "change-storage-class",
|
||||
test.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction"),
|
||||
test.WithConfigMapData("storageclass-1", "storageclass-2"),
|
||||
),
|
||||
storageClass: test.NewStorageClass("storageclass-2"),
|
||||
want: test.NewPVC("velero", "pvc-1", test.WithStorageClassName("storageclass-2")),
|
||||
pvOrPVC: builder.ForPersistentVolumeClaim("velero", "pvc-1").StorageClass("storageclass-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Data("storageclass-1", "storageclass-2").
|
||||
Result(),
|
||||
storageClass: builder.ForStorageClass("storageclass-2").Result(),
|
||||
want: builder.ForPersistentVolumeClaim("velero", "pvc-1").StorageClass("storageclass-2").Result(),
|
||||
},
|
||||
{
|
||||
name: "when no config map exists for the plugin, the item is returned as-is",
|
||||
pvOrPVC: test.NewPV("pv-1", test.WithStorageClassName("storageclass-1")),
|
||||
configMap: test.NewConfigMap("velero", "change-storage-class",
|
||||
test.WithLabels("velero.io/plugin-config", "true", "velero.io/some-other-plugin", "RestoreItemAction"),
|
||||
test.WithConfigMapData("storageclass-1", "storageclass-2"),
|
||||
),
|
||||
want: test.NewPV("pv-1", test.WithStorageClassName("storageclass-1")),
|
||||
pvOrPVC: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/some-other-plugin", "RestoreItemAction")).
|
||||
Data("storageclass-1", "storageclass-2").
|
||||
Result(),
|
||||
want: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
|
||||
},
|
||||
{
|
||||
name: "when no storage class mappings exist in the plugin config map, the item is returned as-is",
|
||||
pvOrPVC: test.NewPV("pv-1", test.WithStorageClassName("storageclass-1")),
|
||||
configMap: test.NewConfigMap("velero", "change-storage-class",
|
||||
test.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction"),
|
||||
),
|
||||
want: test.NewPV("pv-1", test.WithStorageClassName("storageclass-1")),
|
||||
pvOrPVC: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Result(),
|
||||
want: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
|
||||
},
|
||||
{
|
||||
name: "when persistent volume has no storage class, the item is returned as-is",
|
||||
pvOrPVC: test.NewPV("pv-1"),
|
||||
configMap: test.NewConfigMap("velero", "change-storage-class",
|
||||
test.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction"),
|
||||
test.WithConfigMapData("storageclass-1", "storageclass-2"),
|
||||
),
|
||||
want: test.NewPV("pv-1"),
|
||||
pvOrPVC: builder.ForPersistentVolume("pv-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Data("storageclass-1", "storageclass-2").
|
||||
Result(),
|
||||
want: builder.ForPersistentVolume("pv-1").Result(),
|
||||
},
|
||||
{
|
||||
name: "when persistent volume claim has no storage class, the item is returned as-is",
|
||||
pvOrPVC: test.NewPVC("velero", "pvc-1"),
|
||||
configMap: test.NewConfigMap("velero", "change-storage-class",
|
||||
test.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction"),
|
||||
test.WithConfigMapData("storageclass-1", "storageclass-2"),
|
||||
),
|
||||
want: test.NewPVC("velero", "pvc-1"),
|
||||
pvOrPVC: builder.ForPersistentVolumeClaim("velero", "pvc-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Data("storageclass-1", "storageclass-2").
|
||||
Result(),
|
||||
want: builder.ForPersistentVolumeClaim("velero", "pvc-1").Result(),
|
||||
},
|
||||
{
|
||||
name: "when persistent volume's storage class has no mapping in the config map, the item is returned as-is",
|
||||
pvOrPVC: test.NewPV("pv-1", test.WithStorageClassName("storageclass-1")),
|
||||
configMap: test.NewConfigMap("velero", "change-storage-class",
|
||||
test.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction"),
|
||||
test.WithConfigMapData("storageclass-3", "storageclass-4"),
|
||||
),
|
||||
want: test.NewPV("pv-1", test.WithStorageClassName("storageclass-1")),
|
||||
pvOrPVC: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Data("storageclass-3", "storageclass-4").
|
||||
Result(),
|
||||
want: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
|
||||
},
|
||||
{
|
||||
name: "when persistent volume claim's storage class has no mapping in the config map, the item is returned as-is",
|
||||
pvOrPVC: test.NewPVC("velero", "pvc-1", test.WithStorageClassName("storageclass-1")),
|
||||
configMap: test.NewConfigMap("velero", "change-storage-class",
|
||||
test.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction"),
|
||||
test.WithConfigMapData("storageclass-3", "storageclass-4"),
|
||||
),
|
||||
want: test.NewPVC("velero", "pvc-1", test.WithStorageClassName("storageclass-1")),
|
||||
pvOrPVC: builder.ForPersistentVolumeClaim("velero", "pvc-1").StorageClass("storageclass-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Data("storageclass-3", "storageclass-4").
|
||||
Result(),
|
||||
want: builder.ForPersistentVolumeClaim("velero", "pvc-1").StorageClass("storageclass-1").Result(),
|
||||
},
|
||||
{
|
||||
name: "when persistent volume's storage class is mapped to a nonexistent storage class, an error is returned",
|
||||
pvOrPVC: test.NewPV("pv-1", test.WithStorageClassName("storageclass-1")),
|
||||
configMap: test.NewConfigMap("velero", "change-storage-class",
|
||||
test.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction"),
|
||||
test.WithConfigMapData("storageclass-1", "nonexistent-storage-class"),
|
||||
),
|
||||
pvOrPVC: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Data("storageclass-1", "nonexistent-storage-class").
|
||||
Result(),
|
||||
wantErr: errors.New("error getting storage class nonexistent-storage-class from API: storageclasses.storage.k8s.io \"nonexistent-storage-class\" not found"),
|
||||
},
|
||||
{
|
||||
name: "when persistent volume claim's storage class is mapped to a nonexistent storage class, an error is returned",
|
||||
pvOrPVC: test.NewPVC("velero", "pvc-1", test.WithStorageClassName("storageclass-1")),
|
||||
configMap: test.NewConfigMap("velero", "change-storage-class",
|
||||
test.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction"),
|
||||
test.WithConfigMapData("storageclass-1", "nonexistent-storage-class"),
|
||||
),
|
||||
pvOrPVC: builder.ForPersistentVolumeClaim("velero", "pvc-1").StorageClass("storageclass-1").Result(),
|
||||
configMap: builder.ForConfigMap("velero", "change-storage-classs").
|
||||
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
|
||||
Data("storageclass-1", "nonexistent-storage-class").
|
||||
Result(),
|
||||
wantErr: errors.New("error getting storage class nonexistent-storage-class from API: storageclasses.storage.k8s.io \"nonexistent-storage-class\" not found"),
|
||||
},
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
api "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
"github.com/heptio/velero/pkg/backup"
|
||||
"github.com/heptio/velero/pkg/builder"
|
||||
cloudprovidermocks "github.com/heptio/velero/pkg/cloudprovider/mocks"
|
||||
"github.com/heptio/velero/pkg/generated/clientset/versioned/fake"
|
||||
informers "github.com/heptio/velero/pkg/generated/informers/externalversions"
|
||||
|
@ -35,8 +35,8 @@ import (
|
|||
"github.com/heptio/velero/pkg/volume"
|
||||
)
|
||||
|
||||
func defaultBackup() *backup.Builder {
|
||||
return backup.NewNamedBackupBuilder(api.DefaultNamespace, "backup-1")
|
||||
func defaultBackup() *builder.BackupBuilder {
|
||||
return builder.ForBackup(api.DefaultNamespace, "backup-1")
|
||||
}
|
||||
|
||||
func TestExecutePVAction_NoSnapshotRestores(t *testing.T) {
|
||||
|
@ -53,46 +53,46 @@ func TestExecutePVAction_NoSnapshotRestores(t *testing.T) {
|
|||
{
|
||||
name: "no name should error",
|
||||
obj: NewTestUnstructured().WithMetadata().Unstructured,
|
||||
restore: velerotest.NewDefaultTestRestore().Restore,
|
||||
restore: builder.ForRestore(api.DefaultNamespace, "").Result(),
|
||||
expectedErr: true,
|
||||
},
|
||||
{
|
||||
name: "no spec should error",
|
||||
obj: NewTestUnstructured().WithName("pv-1").Unstructured,
|
||||
restore: velerotest.NewDefaultTestRestore().Restore,
|
||||
restore: builder.ForRestore(api.DefaultNamespace, "").Result(),
|
||||
expectedErr: true,
|
||||
},
|
||||
{
|
||||
name: "ensure spec.claimRef is deleted",
|
||||
obj: NewTestUnstructured().WithName("pv-1").WithAnnotations("a", "b").WithSpec("claimRef", "someOtherField").Unstructured,
|
||||
restore: velerotest.NewDefaultTestRestore().WithRestorePVs(false).Restore,
|
||||
backup: defaultBackup().Phase(api.BackupPhaseInProgress).Backup(),
|
||||
restore: builder.ForRestore(api.DefaultNamespace, "").RestorePVs(false).Result(),
|
||||
backup: defaultBackup().Phase(api.BackupPhaseInProgress).Result(),
|
||||
expectedRes: NewTestUnstructured().WithAnnotations("a", "b").WithName("pv-1").WithSpec("someOtherField").Unstructured,
|
||||
},
|
||||
{
|
||||
name: "ensure spec.storageClassName is retained",
|
||||
obj: NewTestUnstructured().WithName("pv-1").WithAnnotations("a", "b").WithSpec("storageClassName", "someOtherField").Unstructured,
|
||||
restore: velerotest.NewDefaultTestRestore().WithRestorePVs(false).Restore,
|
||||
backup: defaultBackup().Phase(api.BackupPhaseInProgress).Backup(),
|
||||
restore: builder.ForRestore(api.DefaultNamespace, "").RestorePVs(false).Result(),
|
||||
backup: defaultBackup().Phase(api.BackupPhaseInProgress).Result(),
|
||||
expectedRes: NewTestUnstructured().WithAnnotations("a", "b").WithName("pv-1").WithSpec("storageClassName", "someOtherField").Unstructured,
|
||||
},
|
||||
{
|
||||
name: "if backup.spec.snapshotVolumes is false, ignore restore.spec.restorePVs and return early",
|
||||
obj: NewTestUnstructured().WithName("pv-1").WithAnnotations("a", "b").WithSpec("claimRef", "storageClassName", "someOtherField").Unstructured,
|
||||
restore: velerotest.NewDefaultTestRestore().WithRestorePVs(true).Restore,
|
||||
backup: defaultBackup().Phase(api.BackupPhaseInProgress).SnapshotVolumes(false).Backup(),
|
||||
restore: builder.ForRestore(api.DefaultNamespace, "").RestorePVs(true).Result(),
|
||||
backup: defaultBackup().Phase(api.BackupPhaseInProgress).SnapshotVolumes(false).Result(),
|
||||
expectedRes: NewTestUnstructured().WithName("pv-1").WithAnnotations("a", "b").WithSpec("storageClassName", "someOtherField").Unstructured,
|
||||
},
|
||||
{
|
||||
name: "restore.spec.restorePVs=false, return early",
|
||||
obj: NewTestUnstructured().WithName("pv-1").WithSpec().Unstructured,
|
||||
restore: velerotest.NewDefaultTestRestore().WithRestorePVs(false).Restore,
|
||||
backup: defaultBackup().Phase(api.BackupPhaseInProgress).Backup(),
|
||||
restore: builder.ForRestore(api.DefaultNamespace, "").RestorePVs(false).Result(),
|
||||
backup: defaultBackup().Phase(api.BackupPhaseInProgress).Result(),
|
||||
volumeSnapshots: []*volume.Snapshot{
|
||||
newSnapshot("pv-1", "loc-1", "gp", "az-1", "snap-1", 1000),
|
||||
},
|
||||
locations: []*api.VolumeSnapshotLocation{
|
||||
velerotest.NewTestVolumeSnapshotLocation().WithName("loc-1").VolumeSnapshotLocation,
|
||||
builder.ForVolumeSnapshotLocation(api.DefaultNamespace, "loc-1").Result(),
|
||||
},
|
||||
expectedErr: false,
|
||||
expectedRes: NewTestUnstructured().WithName("pv-1").WithSpec().Unstructured,
|
||||
|
@ -100,11 +100,11 @@ func TestExecutePVAction_NoSnapshotRestores(t *testing.T) {
|
|||
{
|
||||
name: "volumeSnapshots is empty: return early",
|
||||
obj: NewTestUnstructured().WithName("pv-1").WithSpec().Unstructured,
|
||||
restore: velerotest.NewDefaultTestRestore().WithRestorePVs(true).Restore,
|
||||
backup: defaultBackup().Backup(),
|
||||
restore: builder.ForRestore(api.DefaultNamespace, "").RestorePVs(true).Result(),
|
||||
backup: defaultBackup().Result(),
|
||||
locations: []*api.VolumeSnapshotLocation{
|
||||
velerotest.NewTestVolumeSnapshotLocation().WithName("loc-1").VolumeSnapshotLocation,
|
||||
velerotest.NewTestVolumeSnapshotLocation().WithName("loc-2").VolumeSnapshotLocation,
|
||||
builder.ForVolumeSnapshotLocation(api.DefaultNamespace, "loc-1").Result(),
|
||||
builder.ForVolumeSnapshotLocation(api.DefaultNamespace, "loc-2").Result(),
|
||||
},
|
||||
volumeSnapshots: []*volume.Snapshot{},
|
||||
expectedRes: NewTestUnstructured().WithName("pv-1").WithSpec().Unstructured,
|
||||
|
@ -112,11 +112,11 @@ func TestExecutePVAction_NoSnapshotRestores(t *testing.T) {
|
|||
{
|
||||
name: "volumeSnapshots doesn't have a snapshot for PV: return early",
|
||||
obj: NewTestUnstructured().WithName("pv-1").WithSpec().Unstructured,
|
||||
restore: velerotest.NewDefaultTestRestore().WithRestorePVs(true).Restore,
|
||||
backup: defaultBackup().Backup(),
|
||||
restore: builder.ForRestore(api.DefaultNamespace, "").RestorePVs(true).Result(),
|
||||
backup: defaultBackup().Result(),
|
||||
locations: []*api.VolumeSnapshotLocation{
|
||||
velerotest.NewTestVolumeSnapshotLocation().WithName("loc-1").VolumeSnapshotLocation,
|
||||
velerotest.NewTestVolumeSnapshotLocation().WithName("loc-2").VolumeSnapshotLocation,
|
||||
builder.ForVolumeSnapshotLocation(api.DefaultNamespace, "loc-1").Result(),
|
||||
builder.ForVolumeSnapshotLocation(api.DefaultNamespace, "loc-2").Result(),
|
||||
},
|
||||
volumeSnapshots: []*volume.Snapshot{
|
||||
newSnapshot("non-matching-pv-1", "loc-1", "type-1", "az-1", "snap-1", 1),
|
||||
|
@ -178,11 +178,11 @@ func TestExecutePVAction_SnapshotRestores(t *testing.T) {
|
|||
{
|
||||
name: "backup with a matching volume.Snapshot for PV executes restore",
|
||||
obj: NewTestUnstructured().WithName("pv-1").WithSpec().Unstructured,
|
||||
restore: velerotest.NewDefaultTestRestore().WithRestorePVs(true).Restore,
|
||||
backup: defaultBackup().Backup(),
|
||||
restore: builder.ForRestore(api.DefaultNamespace, "").RestorePVs(true).Result(),
|
||||
backup: defaultBackup().Result(),
|
||||
locations: []*api.VolumeSnapshotLocation{
|
||||
velerotest.NewTestVolumeSnapshotLocation().WithName("loc-1").WithProvider("provider-1").VolumeSnapshotLocation,
|
||||
velerotest.NewTestVolumeSnapshotLocation().WithName("loc-2").WithProvider("provider-2").VolumeSnapshotLocation,
|
||||
builder.ForVolumeSnapshotLocation(api.DefaultNamespace, "loc-1").Provider("provider-1").Result(),
|
||||
builder.ForVolumeSnapshotLocation(api.DefaultNamespace, "loc-2").Provider("provider-2").Result(),
|
||||
},
|
||||
volumeSnapshots: []*volume.Snapshot{
|
||||
newSnapshot("pv-1", "loc-1", "type-1", "az-1", "snap-1", 1),
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
Copyright 2018 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.
|
||||
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 serverstatusrequest
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
velerov1api "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
)
|
||||
|
||||
type Builder struct {
|
||||
serverStatusRequest velerov1api.ServerStatusRequest
|
||||
}
|
||||
|
||||
// NewBuilder returns a Builder for a ServerStatusRequest.
|
||||
func NewBuilder() *Builder {
|
||||
return &Builder{
|
||||
serverStatusRequest: velerov1api.ServerStatusRequest{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: velerov1api.SchemeGroupVersion.String(),
|
||||
Kind: "ServerStatusRequest",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ServerStatusRequest returns the built ServerStatusRequest API object.
|
||||
func (b *Builder) ServerStatusRequest() *velerov1api.ServerStatusRequest {
|
||||
return &b.serverStatusRequest
|
||||
}
|
||||
|
||||
func (b *Builder) Namespace(namespace string) *Builder {
|
||||
b.serverStatusRequest.Namespace = namespace
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Builder) Name(name string) *Builder {
|
||||
b.serverStatusRequest.Name = name
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Builder) GenerateName(name string) *Builder {
|
||||
b.serverStatusRequest.GenerateName = name
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Builder) Phase(phase velerov1api.ServerStatusRequestPhase) *Builder {
|
||||
b.serverStatusRequest.Status.Phase = phase
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Builder) ProcessedTimestamp(time time.Time) *Builder {
|
||||
b.serverStatusRequest.Status.ProcessedTimestamp.Time = time
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Builder) ServerVersion(version string) *Builder {
|
||||
b.serverStatusRequest.Status.ServerVersion = version
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Builder) Plugins(plugins []velerov1api.PluginInfo) *Builder {
|
||||
b.serverStatusRequest.Status.Plugins = plugins
|
||||
return b
|
||||
}
|
|
@ -29,13 +29,14 @@ import (
|
|||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
|
||||
velerov1api "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
"github.com/heptio/velero/pkg/builder"
|
||||
"github.com/heptio/velero/pkg/buildinfo"
|
||||
"github.com/heptio/velero/pkg/generated/clientset/versioned/fake"
|
||||
"github.com/heptio/velero/pkg/plugin/framework"
|
||||
)
|
||||
|
||||
func statusRequestBuilder() *Builder {
|
||||
return NewBuilder().Namespace(velerov1api.DefaultNamespace).Name("sr-1")
|
||||
func statusRequestBuilder() *builder.ServerStatusRequestBuilder {
|
||||
return builder.ForServerStatusRequest(velerov1api.DefaultNamespace, "sr-1")
|
||||
}
|
||||
|
||||
func TestProcess(t *testing.T) {
|
||||
|
@ -56,7 +57,7 @@ func TestProcess(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
name: "server status request with empty phase gets processed",
|
||||
req: statusRequestBuilder().ServerStatusRequest(),
|
||||
req: statusRequestBuilder().Result(),
|
||||
reqPluginLister: &fakePluginLister{
|
||||
plugins: []framework.PluginIdentifier{
|
||||
{
|
||||
|
@ -75,13 +76,13 @@ func TestProcess(t *testing.T) {
|
|||
Kind: "VolumeSnapshotter",
|
||||
},
|
||||
}).
|
||||
ServerStatusRequest(),
|
||||
Result(),
|
||||
},
|
||||
{
|
||||
name: "server status request with phase=New gets processed",
|
||||
req: statusRequestBuilder().
|
||||
Phase(velerov1api.ServerStatusRequestPhaseNew).
|
||||
ServerStatusRequest(),
|
||||
Result(),
|
||||
reqPluginLister: &fakePluginLister{
|
||||
plugins: []framework.PluginIdentifier{
|
||||
{
|
||||
|
@ -108,14 +109,14 @@ func TestProcess(t *testing.T) {
|
|||
Kind: "VolumeSnapshotter",
|
||||
},
|
||||
}).
|
||||
ServerStatusRequest(),
|
||||
Result(),
|
||||
},
|
||||
{
|
||||
name: "server status request with phase=Processed gets deleted if expired",
|
||||
req: statusRequestBuilder().
|
||||
Phase(velerov1api.ServerStatusRequestPhaseProcessed).
|
||||
ProcessedTimestamp(now.Add(-61 * time.Second)).
|
||||
ServerStatusRequest(),
|
||||
Result(),
|
||||
reqPluginLister: &fakePluginLister{
|
||||
plugins: []framework.PluginIdentifier{
|
||||
{
|
||||
|
@ -131,20 +132,20 @@ func TestProcess(t *testing.T) {
|
|||
req: statusRequestBuilder().
|
||||
Phase(velerov1api.ServerStatusRequestPhaseProcessed).
|
||||
ProcessedTimestamp(now.Add(-59 * time.Second)).
|
||||
ServerStatusRequest(),
|
||||
Result(),
|
||||
expected: statusRequestBuilder().
|
||||
Phase(velerov1api.ServerStatusRequestPhaseProcessed).
|
||||
ProcessedTimestamp(now.Add(-59 * time.Second)).
|
||||
ServerStatusRequest(),
|
||||
Result(),
|
||||
},
|
||||
{
|
||||
name: "server status request with invalid phase returns an error",
|
||||
req: statusRequestBuilder().
|
||||
Phase(velerov1api.ServerStatusRequestPhase("an-invalid-phase")).
|
||||
ServerStatusRequest(),
|
||||
Result(),
|
||||
expected: statusRequestBuilder().
|
||||
Phase(velerov1api.ServerStatusRequestPhase("an-invalid-phase")).
|
||||
ServerStatusRequest(),
|
||||
Result(),
|
||||
expectedErrMsg: "unexpected ServerStatusRequest phase \"an-invalid-phase\"",
|
||||
},
|
||||
}
|
||||
|
|
|
@ -17,14 +17,8 @@ limitations under the License.
|
|||
package test
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
storagev1 "k8s.io/api/storage/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
// APIResource stores information about a specific Kubernetes API
|
||||
|
@ -135,386 +129,3 @@ func ServiceAccounts(items ...metav1.Object) *APIResource {
|
|||
Items: items,
|
||||
}
|
||||
}
|
||||
|
||||
type ObjectOpts func(metav1.Object)
|
||||
|
||||
func NewPod(ns, name string, opts ...ObjectOpts) *corev1.Pod {
|
||||
obj := &corev1.Pod{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Pod",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: objectMeta(ns, name),
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(obj)
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
func NewPVC(ns, name string, opts ...ObjectOpts) *corev1.PersistentVolumeClaim {
|
||||
obj := &corev1.PersistentVolumeClaim{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "PersistentVolumeClaim",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: objectMeta(ns, name),
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(obj)
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
func NewPV(name string, opts ...ObjectOpts) *corev1.PersistentVolume {
|
||||
obj := &corev1.PersistentVolume{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "PersistentVolume",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: objectMeta("", name),
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(obj)
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
func NewSecret(ns, name string, opts ...ObjectOpts) *corev1.Secret {
|
||||
obj := &corev1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Secret",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: objectMeta(ns, name),
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(obj)
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
func NewDeployment(ns, name string, opts ...ObjectOpts) *appsv1.Deployment {
|
||||
obj := &appsv1.Deployment{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Deployment",
|
||||
APIVersion: "apps/v1",
|
||||
},
|
||||
ObjectMeta: objectMeta(ns, name),
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(obj)
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
func NewServiceAccount(ns, name string, opts ...ObjectOpts) *corev1.ServiceAccount {
|
||||
obj := &corev1.ServiceAccount{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "ServiceAccount",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: objectMeta(ns, name),
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(obj)
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
func NewNamespace(name string, opts ...ObjectOpts) *corev1.Namespace {
|
||||
obj := &corev1.Namespace{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Namespace",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: objectMeta("", name),
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(obj)
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
func NewConfigMap(ns, name string, opts ...ObjectOpts) *corev1.ConfigMap {
|
||||
obj := &corev1.ConfigMap{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "ConfigMap",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: objectMeta(ns, name),
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(obj)
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
func NewStorageClass(name string, opts ...ObjectOpts) *storagev1.StorageClass {
|
||||
obj := &storagev1.StorageClass{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "StorageClass",
|
||||
APIVersion: "storage/v1",
|
||||
},
|
||||
ObjectMeta: objectMeta("", name),
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(obj)
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
// VolumeOpts exists because corev1.Volume does not implement metav1.Object
|
||||
type VolumeOpts func(*corev1.Volume)
|
||||
|
||||
func NewVolume(name string, opts ...VolumeOpts) *corev1.Volume {
|
||||
obj := &corev1.Volume{Name: name}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(obj)
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
func objectMeta(ns, name string) metav1.ObjectMeta {
|
||||
return metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
}
|
||||
}
|
||||
|
||||
// WithLabels is a functional option that applies the specified
|
||||
// label keys/values to an object.
|
||||
func WithLabels(labels ...string) func(obj metav1.Object) {
|
||||
return func(obj metav1.Object) {
|
||||
objLabels := obj.GetLabels()
|
||||
if objLabels == nil {
|
||||
objLabels = make(map[string]string)
|
||||
}
|
||||
|
||||
if len(labels)%2 != 0 {
|
||||
labels = append(labels, "")
|
||||
}
|
||||
|
||||
for i := 0; i < len(labels); i += 2 {
|
||||
objLabels[labels[i]] = labels[i+1]
|
||||
}
|
||||
|
||||
obj.SetLabels(objLabels)
|
||||
}
|
||||
}
|
||||
|
||||
// WithAnnotations is a functional option that applies the specified
|
||||
// annotation keys/values to an object.
|
||||
func WithAnnotations(vals ...string) func(obj metav1.Object) {
|
||||
return func(obj metav1.Object) {
|
||||
objAnnotations := obj.GetAnnotations()
|
||||
if objAnnotations == nil {
|
||||
objAnnotations = make(map[string]string)
|
||||
}
|
||||
|
||||
if len(vals)%2 != 0 {
|
||||
vals = append(vals, "")
|
||||
}
|
||||
|
||||
for i := 0; i < len(vals); i += 2 {
|
||||
objAnnotations[vals[i]] = vals[i+1]
|
||||
}
|
||||
|
||||
obj.SetAnnotations(objAnnotations)
|
||||
}
|
||||
}
|
||||
|
||||
// WithClusterName is a functional option that applies the specified
|
||||
// cluster name to an object.
|
||||
func WithClusterName(val string) func(obj metav1.Object) {
|
||||
return func(obj metav1.Object) {
|
||||
obj.SetClusterName(val)
|
||||
}
|
||||
}
|
||||
|
||||
// WithFinalizers is a functional option that applies the specified
|
||||
// finalizers to an object.
|
||||
func WithFinalizers(vals ...string) func(obj metav1.Object) {
|
||||
return func(obj metav1.Object) {
|
||||
obj.SetFinalizers(vals)
|
||||
}
|
||||
}
|
||||
|
||||
// WithDeletionTimestamp is a functional option that applies the specified
|
||||
// deletion timestamp to an object.
|
||||
func WithDeletionTimestamp(val time.Time) func(obj metav1.Object) {
|
||||
return func(obj metav1.Object) {
|
||||
obj.SetDeletionTimestamp(&metav1.Time{Time: val})
|
||||
}
|
||||
}
|
||||
|
||||
// WithUID is a functional option that applies the specified UID to an object.
|
||||
func WithUID(val string) func(obj metav1.Object) {
|
||||
return func(obj metav1.Object) {
|
||||
obj.SetUID(types.UID(val))
|
||||
}
|
||||
}
|
||||
|
||||
// WithReclaimPolicy is a functional option for persistent volumes that sets
|
||||
// the specified reclaim policy. It panics if the object is not a persistent
|
||||
// volume.
|
||||
func WithReclaimPolicy(policy corev1.PersistentVolumeReclaimPolicy) func(obj metav1.Object) {
|
||||
return func(obj metav1.Object) {
|
||||
pv, ok := obj.(*corev1.PersistentVolume)
|
||||
if !ok {
|
||||
panic("WithReclaimPolicy is only valid for persistent volumes")
|
||||
}
|
||||
|
||||
pv.Spec.PersistentVolumeReclaimPolicy = policy
|
||||
}
|
||||
}
|
||||
|
||||
// WithClaimRef is a functional option for persistent volumes that sets the specified
|
||||
// claim ref. It panics if the object is not a persistent volume.
|
||||
func WithClaimRef(ns, name string) func(obj metav1.Object) {
|
||||
return func(obj metav1.Object) {
|
||||
pv, ok := obj.(*corev1.PersistentVolume)
|
||||
if !ok {
|
||||
panic("WithClaimRef is only valid for persistent volumes")
|
||||
}
|
||||
|
||||
pv.Spec.ClaimRef = &corev1.ObjectReference{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithAWSEBSVolumeID is a functional option for persistent volumes that sets the specified
|
||||
// AWS EBS volume ID. It panics if the object is not a persistent volume.
|
||||
func WithAWSEBSVolumeID(volumeID string) func(obj metav1.Object) {
|
||||
return func(obj metav1.Object) {
|
||||
pv, ok := obj.(*corev1.PersistentVolume)
|
||||
if !ok {
|
||||
panic("WithClaimRef is only valid for persistent volumes")
|
||||
}
|
||||
|
||||
if pv.Spec.AWSElasticBlockStore == nil {
|
||||
pv.Spec.AWSElasticBlockStore = new(corev1.AWSElasticBlockStoreVolumeSource)
|
||||
}
|
||||
|
||||
pv.Spec.AWSElasticBlockStore.VolumeID = volumeID
|
||||
}
|
||||
}
|
||||
|
||||
// WithCSI is a functional option for persistent volumes that sets the specified CSI driver name
|
||||
// and volume handle. It panics if the object is not a persistent volume.
|
||||
func WithCSI(driver, volumeHandle string) func(object metav1.Object) {
|
||||
return func(obj metav1.Object) {
|
||||
pv, ok := obj.(*corev1.PersistentVolume)
|
||||
if !ok {
|
||||
panic("WithCSI is only valid for persistent volumes")
|
||||
}
|
||||
if pv.Spec.CSI == nil {
|
||||
pv.Spec.CSI = new(corev1.CSIPersistentVolumeSource)
|
||||
}
|
||||
pv.Spec.CSI.Driver = driver
|
||||
pv.Spec.CSI.VolumeHandle = volumeHandle
|
||||
}
|
||||
}
|
||||
|
||||
// WithPVName is a functional option for persistent volume claims that sets the specified
|
||||
// persistent volume name. It panics if the object is not a persistent volume claim.
|
||||
func WithPVName(name string) func(obj metav1.Object) {
|
||||
return func(obj metav1.Object) {
|
||||
pvc, ok := obj.(*corev1.PersistentVolumeClaim)
|
||||
if !ok {
|
||||
panic("WithPVName is only valid for persistent volume claims")
|
||||
}
|
||||
|
||||
pvc.Spec.VolumeName = name
|
||||
}
|
||||
}
|
||||
|
||||
// WithStorageClassName is a functional option for persistent volumes or
|
||||
// persistent volume claims that sets the specified storage class name.
|
||||
// It panics if the object is not a persistent volume or persistent volume
|
||||
// claim.
|
||||
func WithStorageClassName(name string) func(obj metav1.Object) {
|
||||
return func(obj metav1.Object) {
|
||||
switch obj.(type) {
|
||||
case *corev1.PersistentVolume:
|
||||
obj.(*corev1.PersistentVolume).Spec.StorageClassName = name
|
||||
case *corev1.PersistentVolumeClaim:
|
||||
obj.(*corev1.PersistentVolumeClaim).Spec.StorageClassName = &name
|
||||
default:
|
||||
panic("WithStorageClassName is only valid for persistent volumes and persistent volume claims")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithVolume is a functional option for pods that sets the specified
|
||||
// volume on the pod's Spec. It panics if the object is not a pod.
|
||||
func WithVolume(volume *corev1.Volume) func(obj metav1.Object) {
|
||||
return func(obj metav1.Object) {
|
||||
pod, ok := obj.(*corev1.Pod)
|
||||
if !ok {
|
||||
panic("WithVolume is only valid for pods")
|
||||
}
|
||||
pod.Spec.Volumes = append(pod.Spec.Volumes, *volume)
|
||||
}
|
||||
}
|
||||
|
||||
// WithPVCSource is a functional option for volumes that creates a
|
||||
// PersistentVolumeClaimVolumeSource with the specified name.
|
||||
func WithPVCSource(claimName string) func(vol *corev1.Volume) {
|
||||
return func(vol *corev1.Volume) {
|
||||
vol.VolumeSource.PersistentVolumeClaim = &corev1.PersistentVolumeClaimVolumeSource{ClaimName: claimName}
|
||||
}
|
||||
}
|
||||
|
||||
// WithCSISource is a functional option for volumes that creates a
|
||||
// CSIVolumeSource with the specified driver name.
|
||||
func WithCSISource(driverName string) func(vol *corev1.Volume) {
|
||||
return func(vol *corev1.Volume) {
|
||||
vol.VolumeSource.CSI = &corev1.CSIVolumeSource{Driver: driverName}
|
||||
}
|
||||
}
|
||||
|
||||
// WithConfigMapData is a functional option for config maps that puts the specified
|
||||
// values in the Data field. It panics if the object is not a config map.
|
||||
func WithConfigMapData(vals ...string) func(obj metav1.Object) {
|
||||
return func(obj metav1.Object) {
|
||||
cm, ok := obj.(*corev1.ConfigMap)
|
||||
if !ok {
|
||||
panic("WithConfigMapData is only valid for config maps")
|
||||
}
|
||||
|
||||
if cm.Data == nil {
|
||||
cm.Data = make(map[string]string)
|
||||
}
|
||||
|
||||
if len(vals)%2 != 0 {
|
||||
vals = append(vals, "")
|
||||
}
|
||||
|
||||
for i := 0; i < len(vals); i += 2 {
|
||||
cm.Data[vals[i]] = vals[i+1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
kubeinformers "k8s.io/client-go/informers"
|
||||
|
||||
"github.com/heptio/velero/pkg/builder"
|
||||
"github.com/heptio/velero/pkg/test"
|
||||
velerotest "github.com/heptio/velero/pkg/util/test"
|
||||
)
|
||||
|
@ -152,30 +153,26 @@ func TestGetVolumeDirectorySuccess(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
name: "Non-CSI volume with a PVC/PV returns the volume's name",
|
||||
pod: test.NewPod("ns-1", "my-pod",
|
||||
test.WithVolume(test.NewVolume("my-vol", test.WithPVCSource("my-pvc")))),
|
||||
pvc: test.NewPVC("ns-1", "my-pvc", test.WithPVName("a-pv")),
|
||||
pv: test.NewPV("a-pv"),
|
||||
pod: builder.ForPod("ns-1", "my-pod").Volumes(builder.ForVolume("my-vol").PersistentVolumeClaimSource("my-pvc").Result()).Result(),
|
||||
pvc: builder.ForPersistentVolumeClaim("ns-1", "my-pvc").VolumeName("a-pv").Result(),
|
||||
pv: builder.ForPersistentVolume("a-pv").Result(),
|
||||
want: "a-pv",
|
||||
},
|
||||
{
|
||||
name: "CSI volume with a PVC/PV appends '/mount' to the volume name",
|
||||
pod: test.NewPod("ns-1", "my-pod",
|
||||
test.WithVolume(test.NewVolume("my-vol", test.WithPVCSource("my-pvc")))),
|
||||
pvc: test.NewPVC("ns-1", "my-pvc", test.WithPVName("a-pv")),
|
||||
pv: test.NewPV("a-pv", test.WithCSI("csi.test.com", "provider-volume-id")),
|
||||
pod: builder.ForPod("ns-1", "my-pod").Volumes(builder.ForVolume("my-vol").PersistentVolumeClaimSource("my-pvc").Result()).Result(),
|
||||
pvc: builder.ForPersistentVolumeClaim("ns-1", "my-pvc").VolumeName("a-pv").Result(),
|
||||
pv: builder.ForPersistentVolume("a-pv").CSI("csi.test.com", "provider-volume-id").Result(),
|
||||
want: "a-pv/mount",
|
||||
},
|
||||
{
|
||||
name: "CSI volume mounted without a PVC appends '/mount' to the volume name",
|
||||
pod: test.NewPod("ns-1", "my-pod",
|
||||
test.WithVolume(test.NewVolume("my-vol", test.WithCSISource("csi.test.com")))),
|
||||
pod: builder.ForPod("ns-1", "my-pod").Volumes(builder.ForVolume("my-vol").CSISource("csi.test.com").Result()).Result(),
|
||||
want: "my-vol/mount",
|
||||
},
|
||||
{
|
||||
name: "Non-CSI volume without a PVC returns the volume name",
|
||||
pod: test.NewPod("ns-1", "my-pod",
|
||||
test.WithVolume(test.NewVolume("my-vol"))),
|
||||
pod: builder.ForPod("ns-1", "my-pod").Volumes(builder.ForVolume("my-vol").Result()).Result(),
|
||||
want: "my-vol",
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
Copyright 2017, 2019 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.
|
||||
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 test
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
v1 "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
)
|
||||
|
||||
type TestBackupStorageLocation struct {
|
||||
*v1.BackupStorageLocation
|
||||
}
|
||||
|
||||
func NewTestBackupStorageLocation() *TestBackupStorageLocation {
|
||||
return &TestBackupStorageLocation{
|
||||
BackupStorageLocation: &v1.BackupStorageLocation{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: v1.DefaultNamespace,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (b *TestBackupStorageLocation) WithNamespace(namespace string) *TestBackupStorageLocation {
|
||||
b.Namespace = namespace
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *TestBackupStorageLocation) WithName(name string) *TestBackupStorageLocation {
|
||||
b.Name = name
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *TestBackupStorageLocation) WithLabel(key, value string) *TestBackupStorageLocation {
|
||||
if b.Labels == nil {
|
||||
b.Labels = make(map[string]string)
|
||||
}
|
||||
b.Labels[key] = value
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *TestBackupStorageLocation) WithProvider(name string) *TestBackupStorageLocation {
|
||||
b.Spec.Provider = name
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *TestBackupStorageLocation) WithObjectStorage(bucketName string) *TestBackupStorageLocation {
|
||||
if b.Spec.StorageType.ObjectStorage == nil {
|
||||
b.Spec.StorageType.ObjectStorage = &v1.ObjectStorageLocation{}
|
||||
}
|
||||
b.Spec.ObjectStorage.Bucket = bucketName
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *TestBackupStorageLocation) WithAccessMode(accessMode v1.BackupStorageLocationAccessMode) *TestBackupStorageLocation {
|
||||
b.Spec.AccessMode = accessMode
|
||||
return b
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 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.
|
||||
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 test
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
api "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
)
|
||||
|
||||
type TestRestore struct {
|
||||
*api.Restore
|
||||
}
|
||||
|
||||
func NewTestRestore(ns, name string, phase api.RestorePhase) *TestRestore {
|
||||
return &TestRestore{
|
||||
Restore: &api.Restore{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
},
|
||||
Spec: api.RestoreSpec{},
|
||||
Status: api.RestoreStatus{
|
||||
Phase: phase,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewDefaultTestRestore() *TestRestore {
|
||||
return NewTestRestore(api.DefaultNamespace, "", api.RestorePhase(""))
|
||||
}
|
||||
|
||||
func (r *TestRestore) WithIncludedNamespace(name string) *TestRestore {
|
||||
r.Spec.IncludedNamespaces = append(r.Spec.IncludedNamespaces, name)
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *TestRestore) WithExcludedNamespace(name string) *TestRestore {
|
||||
r.Spec.ExcludedNamespaces = append(r.Spec.ExcludedNamespaces, name)
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *TestRestore) WithValidationError(err string) *TestRestore {
|
||||
r.Status.ValidationErrors = append(r.Status.ValidationErrors, err)
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *TestRestore) WithBackup(name string) *TestRestore {
|
||||
r.Spec.BackupName = name
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *TestRestore) WithSchedule(name string) *TestRestore {
|
||||
r.Spec.ScheduleName = name
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *TestRestore) WithErrors(i int) *TestRestore {
|
||||
r.Status.Errors = i
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *TestRestore) WithRestorePVs(value bool) *TestRestore {
|
||||
r.Spec.RestorePVs = &value
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *TestRestore) WithMappedNamespace(from string, to string) *TestRestore {
|
||||
if r.Spec.NamespaceMapping == nil {
|
||||
r.Spec.NamespaceMapping = make(map[string]string)
|
||||
}
|
||||
r.Spec.NamespaceMapping[from] = to
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *TestRestore) WithIncludedResource(resource string) *TestRestore {
|
||||
r.Spec.IncludedResources = append(r.Spec.IncludedResources, resource)
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *TestRestore) WithExcludedResource(resource string) *TestRestore {
|
||||
r.Spec.ExcludedResources = append(r.Spec.ExcludedResources, resource)
|
||||
return r
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 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.
|
||||
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 test
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
api "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
)
|
||||
|
||||
type TestSchedule struct {
|
||||
*api.Schedule
|
||||
}
|
||||
|
||||
func NewTestSchedule(namespace, name string) *TestSchedule {
|
||||
return &TestSchedule{
|
||||
Schedule: &api.Schedule{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TestSchedule) WithPhase(phase api.SchedulePhase) *TestSchedule {
|
||||
s.Status.Phase = phase
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *TestSchedule) WithValidationError(msg string) *TestSchedule {
|
||||
s.Status.ValidationErrors = append(s.Status.ValidationErrors, msg)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *TestSchedule) WithCronSchedule(cronExpression string) *TestSchedule {
|
||||
s.Spec.Schedule = cronExpression
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *TestSchedule) WithLastBackupTime(timeString string) *TestSchedule {
|
||||
t, _ := time.Parse("2006-01-02 15:04:05", timeString)
|
||||
s.Status.LastBackup = metav1.Time{Time: t}
|
||||
return s
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
Copyright 2018 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.
|
||||
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 test
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
v1 "github.com/heptio/velero/pkg/apis/velero/v1"
|
||||
)
|
||||
|
||||
type TestVolumeSnapshotLocation struct {
|
||||
*v1.VolumeSnapshotLocation
|
||||
}
|
||||
|
||||
func NewTestVolumeSnapshotLocation() *TestVolumeSnapshotLocation {
|
||||
return &TestVolumeSnapshotLocation{
|
||||
VolumeSnapshotLocation: &v1.VolumeSnapshotLocation{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: v1.DefaultNamespace,
|
||||
},
|
||||
Spec: v1.VolumeSnapshotLocationSpec{
|
||||
Provider: "aws",
|
||||
Config: map[string]string{"region": "us-west-1"},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (location *TestVolumeSnapshotLocation) WithName(name string) *TestVolumeSnapshotLocation {
|
||||
location.Name = name
|
||||
return location
|
||||
}
|
||||
|
||||
func (location *TestVolumeSnapshotLocation) WithProvider(name string) *TestVolumeSnapshotLocation {
|
||||
location.Spec.Provider = name
|
||||
return location
|
||||
}
|
||||
|
||||
func (location *TestVolumeSnapshotLocation) WithProviderConfig(info []LocationInfo) []*TestVolumeSnapshotLocation {
|
||||
var locations []*TestVolumeSnapshotLocation
|
||||
|
||||
for _, v := range info {
|
||||
location := &TestVolumeSnapshotLocation{
|
||||
VolumeSnapshotLocation: &v1.VolumeSnapshotLocation{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: v.Name,
|
||||
Namespace: v1.DefaultNamespace,
|
||||
},
|
||||
Spec: v1.VolumeSnapshotLocationSpec{
|
||||
Provider: v.Provider,
|
||||
Config: v.Config,
|
||||
},
|
||||
},
|
||||
}
|
||||
locations = append(locations, location)
|
||||
}
|
||||
return locations
|
||||
}
|
||||
|
||||
type LocationInfo struct {
|
||||
Name, Provider string
|
||||
Config map[string]string
|
||||
}
|
Loading…
Reference in New Issue