Merge branch 'main' into data-mover-generic-data-path

This commit is contained in:
Lyndon-Li
2023-05-17 10:15:52 +08:00
165 changed files with 4814 additions and 1437 deletions
@@ -14,11 +14,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
package shared
// PodVolumeOperationProgress represents the progress of a
// PodVolumeBackup/Restore operation
type PodVolumeOperationProgress struct {
// DataMoveOperationProgress represents the progress of a
// data movement operation
// +k8s:deepcopy-gen=true
type DataMoveOperationProgress struct {
// +optional
TotalBytes int64 `json:"totalBytes,omitempty"`
+10
View File
@@ -165,6 +165,16 @@ type BackupSpec struct {
// ResourcePolicy specifies the referenced resource policies that backup should follow
// +optional
ResourcePolicy *v1.TypedLocalObjectReference `json:"resourcePolicy,omitempty"`
// SnapshotMoveData specifies whether snapshot data should be moved
// +optional
// +nullable
SnapshotMoveData *bool `json:"snapshotMoveData,omitempty"`
// DataMover specifies the data mover to be used by the backup.
// If DataMover is "" or "velero", the built-in data mover will be used.
// +optional
DataMover string `json:"datamover,omitempty"`
}
// BackupHooks contains custom behaviors that should be executed at different phases of the backup.
@@ -19,6 +19,8 @@ package v1
import (
corev1api "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/vmware-tanzu/velero/pkg/apis/velero/shared"
)
// PodVolumeBackupSpec is the specification for a PodVolumeBackup.
@@ -100,7 +102,7 @@ type PodVolumeBackupStatus struct {
// number of backed up bytes. This can be used to display progress information
// about the backup operation.
// +optional
Progress PodVolumeOperationProgress `json:"progress,omitempty"`
Progress shared.DataMoveOperationProgress `json:"progress,omitempty"`
}
// TODO(2.0) After converting all resources to use the runttime-controller client,
@@ -19,6 +19,8 @@ package v1
import (
corev1api "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/vmware-tanzu/velero/pkg/apis/velero/shared"
)
// PodVolumeRestoreSpec is the specification for a PodVolumeRestore.
@@ -86,7 +88,7 @@ type PodVolumeRestoreStatus struct {
// number of restored bytes. This can be used to display progress information
// about the restore operation.
// +optional
Progress PodVolumeOperationProgress `json:"progress,omitempty"`
Progress shared.DataMoveOperationProgress `json:"progress,omitempty"`
}
// TODO(2.0) After converting all resources to use the runtime-controller client, the genclient and k8s:deepcopy markers will no longer be needed and should be removed.
+5 -15
View File
@@ -376,6 +376,11 @@ func (in *BackupSpec) DeepCopyInto(out *BackupSpec) {
*out = new(corev1.TypedLocalObjectReference)
(*in).DeepCopyInto(*out)
}
if in.SnapshotMoveData != nil {
in, out := &in.SnapshotMoveData, &out.SnapshotMoveData
*out = new(bool)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupSpec.
@@ -977,21 +982,6 @@ func (in *PodVolumeBackupStatus) DeepCopy() *PodVolumeBackupStatus {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PodVolumeOperationProgress) DeepCopyInto(out *PodVolumeOperationProgress) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodVolumeOperationProgress.
func (in *PodVolumeOperationProgress) DeepCopy() *PodVolumeOperationProgress {
if in == nil {
return nil
}
out := new(PodVolumeOperationProgress)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PodVolumeRestore) DeepCopyInto(out *PodVolumeRestore) {
*out = *in
@@ -0,0 +1,156 @@
/*
Copyright 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 v2alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/vmware-tanzu/velero/pkg/apis/velero/shared"
)
// DataDownloadSpec is the specification for a DataDownload.
type DataDownloadSpec struct {
// TargetVolume is the information of the target PVC and PV.
TargetVolume TargetVolumeSpec `json:"targetVolume"`
// BackupStorageLocation is the name of the backup storage location
// where the backup repository is stored.
BackupStorageLocation string `json:"backupStorageLocation"`
// DataMover specifies the data mover to be used by the backup.
// If DataMover is "" or "velero", the built-in data mover will be used.
// +optional
DataMover string `json:"datamover,omitempty"`
// SnapshotID is the ID of the Velero backup snapshot to be restored from.
SnapshotID string `json:"snapshotID"`
// SourceNamespace is the original namespace where the volume is backed up from.
// It may be different from SourcePVC's namespace if namespace is remapped during restore.
SourceNamespace string `json:"sourceNamespace"`
// DataMoverConfig is for data-mover-specific configuration fields.
// +optional
DataMoverConfig map[string]string `json:"dataMoverConfig,omitempty"`
// Cancel indicates request to cancel the ongoing DataDownload. It can be set
// when the DataDownload is in InProgress phase
Cancel bool `json:"cancel,omitempty"`
// OperationTimeout specifies the time used to wait internal operations,
// before returning error as timeout.
OperationTimeout metav1.Duration `json:"operationTimeout"`
}
// TargetPVCSpec is the specification for a target PVC.
type TargetVolumeSpec struct {
// PVC is the name of the target PVC that is created by Velero restore
PVC string `json:"pvc"`
// PV is the name of the target PV that is created by Velero restore
PV string `json:"pv"`
// Namespace is the target namespace
Namespace string `json:"namespace"`
}
// DataDownloadPhase represents the lifecycle phase of a DataDownload.
// +kubebuilder:validation:Enum=New;Accepted;Prepared;InProgress;Canceling;Canceled;Completed;Failed
type DataDownloadPhase string
const (
DataDownloadPhaseNew DataDownloadPhase = "New"
DataDownloadPhaseAccepted DataDownloadPhase = "Accepted"
DataDownloadPhasePrepared DataDownloadPhase = "Prepared"
DataDownloadPhaseInProgress DataDownloadPhase = "InProgress"
DataDownloadPhaseCanceling DataDownloadPhase = "Canceling"
DataDownloadPhaseCanceled DataDownloadPhase = "Canceled"
DataDownloadPhaseCompleted DataDownloadPhase = "Completed"
DataDownloadPhaseFailed DataDownloadPhase = "Failed"
)
// DataDownloadStatus is the current status of a DataDownload.
type DataDownloadStatus struct {
// Phase is the current state of the DataDownload.
// +optional
Phase DataDownloadPhase `json:"phase,omitempty"`
// Message is a message about the DataDownload's status.
// +optional
Message string `json:"message,omitempty"`
// StartTimestamp records the time a restore was started.
// The server's time is used for StartTimestamps
// +optional
// +nullable
StartTimestamp *metav1.Time `json:"startTimestamp,omitempty"`
// CompletionTimestamp records the time a restore was completed.
// Completion time is recorded even on failed restores.
// The server's time is used for CompletionTimestamps
// +optional
// +nullable
CompletionTimestamp *metav1.Time `json:"completionTimestamp,omitempty"`
// Progress holds the total number of bytes of the snapshot and the current
// number of restored bytes. This can be used to display progress information
// about the restore operation.
// +optional
Progress shared.DataMoveOperationProgress `json:"progress,omitempty"`
}
// TODO(2.0) After converting all resources to use the runtime-controller client, the genclient and k8s:deepcopy markers will no longer be needed and should be removed.
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +kubebuilder:object:generate=true
// +kubebuilder:object:root=true
// +kubebuilder:storageversion
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.phase",description="DataDownload status such as New/InProgress"
// +kubebuilder:printcolumn:name="Started",type="date",JSONPath=".status.startTimestamp",description="Time duration since this DataDownload was started"
// +kubebuilder:printcolumn:name="Bytes Done",type="integer",format="int64",JSONPath=".status.progress.bytesDone",description="Completed bytes"
// +kubebuilder:printcolumn:name="Total Bytes",type="integer",format="int64",JSONPath=".status.progress.totalBytes",description="Total bytes"
// +kubebuilder:printcolumn:name="Storage Location",type="string",JSONPath=".spec.backupStorageLocation",description="Name of the Backup Storage Location where the backup data is stored"
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since this DataDownload was created"
type DataDownload struct {
metav1.TypeMeta `json:",inline"`
// +optional
metav1.ObjectMeta `json:"metadata,omitempty"`
// +optional
Spec DataDownloadSpec `json:"spec,omitempty"`
// +optional
Status DataDownloadStatus `json:"status,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +kubebuilder:object:generate=true
// +kubebuilder:object:root=true
// +kubebuilder:rbac:groups=velero.io,resources=datadownloads,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=velero.io,resources=datadownloads/status,verbs=get;update;patch
// DataDownloadList is a list of DataDownloads.
type DataDownloadList struct {
metav1.TypeMeta `json:",inline"`
// +optional
metav1.ListMeta `json:"metadata,omitempty"`
Items []DataDownload `json:"items"`
}
@@ -0,0 +1,209 @@
/*
Copyright 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 v2alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/vmware-tanzu/velero/pkg/apis/velero/shared"
)
// DataUploadSpec is the specification for a DataUpload.
type DataUploadSpec struct {
// SnapshotType is the type of the snapshot to be backed up.
SnapshotType SnapshotType `json:"snapshotType"`
// If SnapshotType is CSI, CSISnapshot provides the information of the CSI snapshot.
// +optional
// +nullable
CSISnapshot *CSISnapshotSpec `json:"csiSnapshot"`
// SourcePVC is the name of the PVC which the snapshot is taken for.
SourcePVC string `json:"sourcePVC"`
// DataMover specifies the data mover to be used by the backup.
// If DataMover is "" or "velero", the built-in data mover will be used.
// +optional
DataMover string `json:"datamover,omitempty"`
// BackupStorageLocation is the name of the backup storage location
// where the backup repository is stored.
BackupStorageLocation string `json:"backupStorageLocation"`
// SourceNamespace is the original namespace where the volume is backed up from.
// It is the same namespace for SourcePVC and CSI namespaced objects.
SourceNamespace string `json:"sourceNamespace"`
// DataMoverConfig is for data-mover-specific configuration fields.
// +optional
// +nullable
DataMoverConfig *map[string]string `json:"dataMoverConfig,omitempty"`
// Cancel indicates request to cancel the ongoing DataUpload. It can be set
// when the DataUpload is in InProgress phase
Cancel bool `json:"cancel,omitempty"`
// OperationTimeout specifies the time used to wait internal operations,
// before returning error as timeout.
OperationTimeout metav1.Duration `json:"operationTimeout"`
}
type SnapshotType string
const (
SnapshotTypeCSI SnapshotType = "CSI"
)
// CSISnapshotSpec is the specification for a CSI snapshot.
type CSISnapshotSpec struct {
// VolumeSnapshot is the name of the volume snapshot to be backed up
VolumeSnapshot string `json:"volumeSnapshot"`
// StorageClass is the name of the storage class of the PVC that the volume snapshot is created from
StorageClass string `json:"storageClass"`
// StorageClass is the name of the snapshot class that the volume snapshot is created with
// +optional
SnapshotClass string `json:"snapshotClass"`
}
// DataUploadPhase represents the lifecycle phase of a DataUpload.
// +kubebuilder:validation:Enum=New;Accepted;Prepared;InProgress;Canceling;Canceled;Completed;Failed
type DataUploadPhase string
const (
DataUploadPhaseNew DataUploadPhase = "New"
DataUploadPhaseAccepted DataUploadPhase = "Accepted"
DataUploadPhasePrepared DataUploadPhase = "Prepared"
DataUploadPhaseInProgress DataUploadPhase = "InProgress"
DataUploadPhaseCanceling DataUploadPhase = "Canceling"
DataUploadPhaseCanceled DataUploadPhase = "Canceled"
DataUploadPhaseCompleted DataUploadPhase = "Completed"
DataUploadPhaseFailed DataUploadPhase = "Failed"
)
// DataUploadStatus is the current status of a DataUpload.
type DataUploadStatus struct {
// Phase is the current state of the DataUpload.
// +optional
Phase DataUploadPhase `json:"phase,omitempty"`
// Path is the full path of the snapshot volume being backed up.
// +optional
Path string `json:"path,omitempty"`
// SnapshotID is the identifier for the snapshot in the backup repository.
// +optional
SnapshotID string `json:"snapshotID,omitempty"`
// DataMoverResult stores data-mover-specific information as a result of the DataUpload.
// +optional
// +nullable
DataMoverResult *map[string]string `json:"dataMoverResult,omitempty"`
// Message is a message about the DataUpload's status.
// +optional
Message string `json:"message,omitempty"`
// StartTimestamp records the time a backup was started.
// Separate from CreationTimestamp, since that value changes
// on restores.
// The server's time is used for StartTimestamps
// +optional
// +nullable
StartTimestamp *metav1.Time `json:"startTimestamp,omitempty"`
// CompletionTimestamp records the time a backup was completed.
// Completion time is recorded even on failed backups.
// Completion time is recorded before uploading the backup object.
// The server's time is used for CompletionTimestamps
// +optional
// +nullable
CompletionTimestamp *metav1.Time `json:"completionTimestamp,omitempty"`
// Progress holds the total number of bytes of the volume and the current
// number of backed up bytes. This can be used to display progress information
// about the backup operation.
// +optional
Progress shared.DataMoveOperationProgress `json:"progress,omitempty"`
}
// TODO(2.0) After converting all resources to use the runttime-controller client,
// the genclient and k8s:deepcopy markers will no longer be needed and should be removed.
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +kubebuilder:object:root=true
// +kubebuilder:object:generate=true
// +kubebuilder:storageversion
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.phase",description="DataUpload status such as New/InProgress"
// +kubebuilder:printcolumn:name="Started",type="date",JSONPath=".status.startTimestamp",description="Time duration since this DataUpload was started"
// +kubebuilder:printcolumn:name="Bytes Done",type="integer",format="int64",JSONPath=".status.progress.bytesDone",description="Completed bytes"
// +kubebuilder:printcolumn:name="Total Bytes",type="integer",format="int64",JSONPath=".status.progress.totalBytes",description="Total bytes"
// +kubebuilder:printcolumn:name="Storage Location",type="string",JSONPath=".spec.backupStorageLocation",description="Name of the Backup Storage Location where this backup should be stored"
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since this DataUpload was created"
type DataUpload struct {
metav1.TypeMeta `json:",inline"`
// +optional
metav1.ObjectMeta `json:"metadata,omitempty"`
// +optional
Spec DataUploadSpec `json:"spec,omitempty"`
// +optional
Status DataUploadStatus `json:"status,omitempty"`
}
// TODO(2.0) After converting all resources to use the runtime-controller client,
// the k8s:deepcopy marker will no longer be needed and should be removed.
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +kubebuilder:object:root=true
// +kubebuilder:rbac:groups=velero.io,resources=datauploads,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=velero.io,resources=datauploads/status,verbs=get;update;patch
// DataUploadList is a list of DataUploads.
type DataUploadList struct {
metav1.TypeMeta `json:",inline"`
// +optional
metav1.ListMeta `json:"metadata,omitempty"`
Items []DataUpload `json:"items"`
}
// DataUploadResult represents the SnasphotBackup result to be used by DataDownload.
type DataUploadResult struct {
// BackupStorageLocation is the name of the backup storage location
// where the backup repository is stored.
BackupStorageLocation string `json:"backupStorageLocation"`
// DataMover specifies the data mover used by the DataUpload
// +optional
DataMover string `json:"datamover,omitempty"`
// SnapshotID is the identifier for the snapshot in the backup repository.
SnapshotID string `json:"snapshotID,omitempty"`
// SourceNamespace is the original namespace where the volume is backed up from.
SourceNamespace string `json:"sourceNamespace"`
// DataMoverResult stores data-mover-specific information as a result of the DataUpload.
// +optional
// +nullable
DataMoverResult *map[string]string `json:"dataMoverResult,omitempty"`
}
+21
View File
@@ -0,0 +1,21 @@
/*
Copyright 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.
*/
// +k8s:deepcopy-gen=package
// Package v2alpha1 is the v2alpha1 version of the API.
// +groupName=velero.io
package v2alpha1
@@ -0,0 +1,36 @@
/*
Copyright 2020 the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
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 v2alpha1 contains API Schema definitions for the velero v2alpha1 API group
// +kubebuilder:object:generate=true
// +groupName=velero.io
package v2alpha1
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
var (
// SchemeGroupVersion is group version used to register these objects
SchemeGroupVersion = schema.GroupVersion{Group: "velero.io", Version: "v2alpha1"}
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
// AddToScheme adds the types in this group-version to the given scheme.
AddToScheme = SchemeBuilder.AddToScheme
)
+60
View File
@@ -0,0 +1,60 @@
/*
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 v2alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// Resource gets a Velero GroupResource for a specified resource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
type typeInfo struct {
PluralName string
ItemType runtime.Object
ItemListType runtime.Object
}
func newTypeInfo(pluralName string, itemType, itemListType runtime.Object) typeInfo {
return typeInfo{
PluralName: pluralName,
ItemType: itemType,
ItemListType: itemListType,
}
}
// CustomResources returns a map of all custom resources within the Velero
// API group, keyed on Kind.
func CustomResources() map[string]typeInfo {
return map[string]typeInfo{
"DataUpload": newTypeInfo("datauploads", &DataUpload{}, &DataUploadList{}),
"DataDownload": newTypeInfo("datadownloads", &DataDownload{}, &DataDownloadList{}),
}
}
func addKnownTypes(scheme *runtime.Scheme) error {
for _, typeInfo := range CustomResources() {
scheme.AddKnownTypes(SchemeGroupVersion, typeInfo.ItemType, typeInfo.ItemListType)
}
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}
@@ -0,0 +1,299 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
// Code generated by controller-gen. DO NOT EDIT.
package v2alpha1
import (
"k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CSISnapshotSpec) DeepCopyInto(out *CSISnapshotSpec) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSISnapshotSpec.
func (in *CSISnapshotSpec) DeepCopy() *CSISnapshotSpec {
if in == nil {
return nil
}
out := new(CSISnapshotSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DataDownload) DeepCopyInto(out *DataDownload) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataDownload.
func (in *DataDownload) DeepCopy() *DataDownload {
if in == nil {
return nil
}
out := new(DataDownload)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *DataDownload) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DataDownloadList) DeepCopyInto(out *DataDownloadList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]DataDownload, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataDownloadList.
func (in *DataDownloadList) DeepCopy() *DataDownloadList {
if in == nil {
return nil
}
out := new(DataDownloadList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *DataDownloadList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DataDownloadSpec) DeepCopyInto(out *DataDownloadSpec) {
*out = *in
out.TargetVolume = in.TargetVolume
if in.DataMoverConfig != nil {
in, out := &in.DataMoverConfig, &out.DataMoverConfig
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
out.OperationTimeout = in.OperationTimeout
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataDownloadSpec.
func (in *DataDownloadSpec) DeepCopy() *DataDownloadSpec {
if in == nil {
return nil
}
out := new(DataDownloadSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DataDownloadStatus) DeepCopyInto(out *DataDownloadStatus) {
*out = *in
if in.StartTimestamp != nil {
in, out := &in.StartTimestamp, &out.StartTimestamp
*out = (*in).DeepCopy()
}
if in.CompletionTimestamp != nil {
in, out := &in.CompletionTimestamp, &out.CompletionTimestamp
*out = (*in).DeepCopy()
}
out.Progress = in.Progress
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataDownloadStatus.
func (in *DataDownloadStatus) DeepCopy() *DataDownloadStatus {
if in == nil {
return nil
}
out := new(DataDownloadStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DataUpload) DeepCopyInto(out *DataUpload) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataUpload.
func (in *DataUpload) DeepCopy() *DataUpload {
if in == nil {
return nil
}
out := new(DataUpload)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *DataUpload) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DataUploadList) DeepCopyInto(out *DataUploadList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]DataUpload, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataUploadList.
func (in *DataUploadList) DeepCopy() *DataUploadList {
if in == nil {
return nil
}
out := new(DataUploadList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *DataUploadList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DataUploadResult) DeepCopyInto(out *DataUploadResult) {
*out = *in
if in.DataMoverResult != nil {
in, out := &in.DataMoverResult, &out.DataMoverResult
*out = new(map[string]string)
if **in != nil {
in, out := *in, *out
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataUploadResult.
func (in *DataUploadResult) DeepCopy() *DataUploadResult {
if in == nil {
return nil
}
out := new(DataUploadResult)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DataUploadSpec) DeepCopyInto(out *DataUploadSpec) {
*out = *in
if in.CSISnapshot != nil {
in, out := &in.CSISnapshot, &out.CSISnapshot
*out = new(CSISnapshotSpec)
**out = **in
}
if in.DataMoverConfig != nil {
in, out := &in.DataMoverConfig, &out.DataMoverConfig
*out = new(map[string]string)
if **in != nil {
in, out := *in, *out
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
}
out.OperationTimeout = in.OperationTimeout
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataUploadSpec.
func (in *DataUploadSpec) DeepCopy() *DataUploadSpec {
if in == nil {
return nil
}
out := new(DataUploadSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DataUploadStatus) DeepCopyInto(out *DataUploadStatus) {
*out = *in
if in.DataMoverResult != nil {
in, out := &in.DataMoverResult, &out.DataMoverResult
*out = new(map[string]string)
if **in != nil {
in, out := *in, *out
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
}
if in.StartTimestamp != nil {
in, out := &in.StartTimestamp, &out.StartTimestamp
*out = (*in).DeepCopy()
}
if in.CompletionTimestamp != nil {
in, out := &in.CompletionTimestamp, &out.CompletionTimestamp
*out = (*in).DeepCopy()
}
out.Progress = in.Progress
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataUploadStatus.
func (in *DataUploadStatus) DeepCopy() *DataUploadStatus {
if in == nil {
return nil
}
out := new(DataUploadStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TargetVolumeSpec) DeepCopyInto(out *TargetVolumeSpec) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetVolumeSpec.
func (in *TargetVolumeSpec) DeepCopy() *TargetVolumeSpec {
if in == nil {
return nil
}
out := new(TargetVolumeSpec)
in.DeepCopyInto(out)
return out
}
+5 -1
View File
@@ -635,7 +635,11 @@ func (kb *kubernetesBackupper) FinalizeBackup(log logrus.FieldLogger,
}
// write new tar archive replacing files in original with content updateFiles for matches
buildFinalTarball(tr, tw, updateFiles)
if err := buildFinalTarball(tr, tw, updateFiles); err != nil {
log.Errorf("Error building final tarball: %s", err.Error())
return err
}
log.WithField("progress", "").Infof("Updated a total of %d items", len(backupRequest.BackedUpItems))
return nil
+16 -4
View File
@@ -32,6 +32,7 @@ import (
"k8s.io/client-go/rest"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
velerov2alpha1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1"
clientset "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned"
)
@@ -153,10 +154,21 @@ func (f *factory) KubebuilderClient() (kbclient.Client, error) {
}
scheme := runtime.NewScheme()
velerov1api.AddToScheme(scheme)
k8scheme.AddToScheme(scheme)
apiextv1beta1.AddToScheme(scheme)
apiextv1.AddToScheme(scheme)
if err := velerov1api.AddToScheme(scheme); err != nil {
return nil, err
}
if err := velerov2alpha1api.AddToScheme(scheme); err != nil {
return nil, err
}
if err := k8scheme.AddToScheme(scheme); err != nil {
return nil, err
}
if err := apiextv1beta1.AddToScheme(scheme); err != nil {
return nil, err
}
if err := apiextv1.AddToScheme(scheme); err != nil {
return nil, err
}
kubebuilderClient, err := kbclient.New(clientConfig, kbclient.Options{
Scheme: scheme,
})
+3 -1
View File
@@ -162,7 +162,9 @@ func getKubectlVersion() (string, error) {
case <-time.After(kubectlTimeout):
// we don't care about the possible error returned from Kill() here,
// just return an empty string
kubectlCmd.Process.Kill()
if err := kubectlCmd.Process.Kill(); err != nil {
return "", fmt.Errorf("error killing kubectl process: %w", err)
}
return "", errors.New("timeout waiting for kubectl version")
case err := <-done:
+16 -4
View File
@@ -64,7 +64,10 @@ $ velero completion fish > ~/.config/fish/completions/velero.fish
shell := args[0]
switch shell {
case "bash":
cmd.Root().GenBashCompletion(os.Stdout)
if err := cmd.Root().GenBashCompletion(os.Stdout); err != nil {
fmt.Println("fail to generate bash completion script", err)
os.Exit(1)
}
case "zsh":
// # fix #4912
// cobra does not support zsh completion ouptput used by source command
@@ -72,11 +75,20 @@ $ velero completion fish > ~/.config/fish/completions/velero.fish
// Need to append compdef manually to do that.
zshHead := "#compdef velero\ncompdef _velero velero\n"
out := os.Stdout
out.Write([]byte(zshHead))
if _, err := out.Write([]byte(zshHead)); err != nil {
fmt.Println("fail to append compdef command into zsh completion script: ", err)
os.Exit(1)
}
cmd.Root().GenZshCompletion(out)
if err := cmd.Root().GenZshCompletion(out); err != nil {
fmt.Println("fail to generate zsh completion script: ", err)
os.Exit(1)
}
case "fish":
cmd.Root().GenFishCompletion(os.Stdout, true)
if err := cmd.Root().GenFishCompletion(os.Stdout, true); err != nil {
fmt.Println("fail to generate fish completion script: ", err)
os.Exit(1)
}
default:
fmt.Println("Invalid shell specified, specify bash, zsh, or fish")
os.Exit(1)
+17 -3
View File
@@ -44,6 +44,7 @@ import (
"github.com/vmware-tanzu/velero/internal/credentials"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
velerov2alpha1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1"
"github.com/vmware-tanzu/velero/pkg/buildinfo"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd"
@@ -134,9 +135,22 @@ func newNodeAgentServer(logger logrus.FieldLogger, factory client.Factory, confi
ctrl.SetLogger(zap.New(zap.UseDevMode(true)))
velerov1api.AddToScheme(scheme)
v1.AddToScheme(scheme)
storagev1api.AddToScheme(scheme)
if err := velerov1api.AddToScheme(scheme); err != nil {
cancelFunc()
return nil, err
}
if err := velerov2alpha1api.AddToScheme(scheme); err != nil {
cancelFunc()
return nil, err
}
if err := v1.AddToScheme(scheme); err != nil {
cancelFunc()
return nil, err
}
if err := storagev1api.AddToScheme(scheme); err != nil {
cancelFunc()
return nil, err
}
nodeName := os.Getenv("NODE_NAME")
+17 -3
View File
@@ -55,6 +55,7 @@ import (
"github.com/vmware-tanzu/velero/internal/credentials"
"github.com/vmware-tanzu/velero/internal/storage"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
velerov2alpha1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1"
"github.com/vmware-tanzu/velero/pkg/backup"
"github.com/vmware-tanzu/velero/pkg/buildinfo"
"github.com/vmware-tanzu/velero/pkg/client"
@@ -313,9 +314,22 @@ func newServer(f client.Factory, config serverConfig, logger *logrus.Logger) (*s
}
scheme := runtime.NewScheme()
velerov1api.AddToScheme(scheme)
corev1api.AddToScheme(scheme)
snapshotv1api.AddToScheme(scheme)
if err := velerov1api.AddToScheme(scheme); err != nil {
cancelFunc()
return nil, err
}
if err := velerov2alpha1api.AddToScheme(scheme); err != nil {
cancelFunc()
return nil, err
}
if err := corev1api.AddToScheme(scheme); err != nil {
cancelFunc()
return nil, err
}
if err := snapshotv1api.AddToScheme(scheme); err != nil {
cancelFunc()
return nil, err
}
ctrl.SetLogger(logrusr.New(logger))
+2 -1
View File
@@ -32,6 +32,7 @@ import (
"github.com/fatih/color"
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
veleroapishared "github.com/vmware-tanzu/velero/pkg/apis/velero/shared"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/cmd/util/downloadrequest"
"github.com/vmware-tanzu/velero/pkg/features"
@@ -597,7 +598,7 @@ type volumesByPod struct {
// Add adds a pod volume with the specified pod namespace, name
// and volume to the appropriate group.
func (v *volumesByPod) Add(namespace, name, volume, phase string, progress velerov1api.PodVolumeOperationProgress) {
func (v *volumesByPod) Add(namespace, name, volume, phase string, progress veleroapishared.DataMoveOperationProgress) {
if v.volumesByPodMap == nil {
v.volumesByPodMap = make(map[string]*podVolumeGroup)
}
+3 -1
View File
@@ -61,7 +61,9 @@ func ClearOutputFlagDefault(cmd *cobra.Command) {
return
}
f.DefValue = ""
f.Value.Set("")
if err := f.Value.Set(""); err != nil {
fmt.Printf("error clear the default value of output flag: %s\n", err.Error())
}
}
// GetOutputFlagValue returns the value of the "output" flag
+1 -2
View File
@@ -561,8 +561,7 @@ func (b *backupReconciler) validateAndGetSnapshotLocations(backup *velerov1api.B
continue
}
location := &velerov1api.VolumeSnapshotLocation{}
b.kbClient.Get(context.Background(), kbclient.ObjectKey{Namespace: backup.Namespace, Name: defaultLocation}, location)
if err != nil {
if err := b.kbClient.Get(context.Background(), kbclient.ObjectKey{Namespace: backup.Namespace, Name: defaultLocation}, location); err != nil {
errors = append(errors, fmt.Sprintf("error getting volume snapshot location named %s: %v", defaultLocation, err))
continue
}
@@ -96,7 +96,9 @@ func (r *BackupRepoReconciler) invalidateBackupReposForBSL(bslObj client.Object)
for i := range list.Items {
r.logger.WithField("BSL", bsl.Name).Infof("Invalidating Backup Repository %s", list.Items[i].Name)
r.patchBackupRepository(context.Background(), &list.Items[i], repoNotReady("re-establish on BSL change"))
if err := r.patchBackupRepository(context.Background(), &list.Items[i], repoNotReady("re-establish on BSL change")); err != nil {
r.logger.WithField("BSL", bsl.Name).WithError(err).Errorf("fail to patch BackupRepository %s", list.Items[i].Name)
}
}
return []reconcile.Request{}
+5 -1
View File
@@ -18,6 +18,7 @@ package controller
import (
"context"
"fmt"
"time"
snapshotv1api "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
@@ -397,7 +398,10 @@ func backupSyncSourceOrderFunc(objList client.ObjectList) client.ObjectList {
cpBsl := bsl
bslArray = append(bslArray, &cpBsl)
}
meta.SetList(resultBSLList, bslArray)
if err := meta.SetList(resultBSLList, bslArray); err != nil {
fmt.Printf("fail to sort BSL list: %s", err.Error())
return &velerov1api.BackupStorageLocationList{}
}
return resultBSLList
}
@@ -33,6 +33,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/vmware-tanzu/velero/internal/credentials"
veleroapishared "github.com/vmware-tanzu/velero/pkg/apis/velero/shared"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/datapath"
"github.com/vmware-tanzu/velero/pkg/exposer"
@@ -264,7 +265,7 @@ func (r *PodVolumeBackupReconciler) OnDataPathProgress(ctx context.Context, name
}
original := pvb.DeepCopy()
pvb.Status.Progress = velerov1api.PodVolumeOperationProgress{TotalBytes: progress.TotalBytes, BytesDone: progress.BytesDone}
pvb.Status.Progress = veleroapishared.DataMoveOperationProgress{TotalBytes: progress.TotalBytes, BytesDone: progress.BytesDone}
if err := r.Client.Patch(ctx, &pvb, client.MergeFrom(original)); err != nil {
log.WithError(err).Error("Failed to update progress")
@@ -358,10 +359,10 @@ func UpdatePVBStatusToFailed(ctx context.Context, c client.Client, pvb *velerov1
pvb.Status.Message = errString
pvb.Status.CompletionTimestamp = &metav1.Time{Time: time}
if err := c.Patch(ctx, pvb, client.MergeFrom(original)); err != nil {
err := c.Patch(ctx, pvb, client.MergeFrom(original))
if err != nil {
log.WithError(err).Error("error updating PodVolumeBackup status")
return err
} else {
return nil
}
return err
}
@@ -38,6 +38,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/source"
"github.com/vmware-tanzu/velero/internal/credentials"
veleroapishared "github.com/vmware-tanzu/velero/pkg/apis/velero/shared"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/datapath"
"github.com/vmware-tanzu/velero/pkg/exposer"
@@ -167,12 +168,12 @@ func UpdatePVRStatusToFailed(ctx context.Context, c client.Client, pvb *velerov1
pvb.Status.Message = errString
pvb.Status.CompletionTimestamp = &metav1.Time{Time: time}
if err := c.Patch(ctx, pvb, client.MergeFrom(original)); err != nil {
err := c.Patch(ctx, pvb, client.MergeFrom(original))
if err != nil {
log.WithError(err).Error("error updating PodVolumeRestore status")
return err
} else {
return nil
}
return err
}
func (c *PodVolumeRestoreReconciler) shouldProcess(ctx context.Context, log logrus.FieldLogger, pvr *velerov1api.PodVolumeRestore) (bool, *corev1api.Pod, error) {
@@ -357,7 +358,7 @@ func (c *PodVolumeRestoreReconciler) OnDataPathProgress(ctx context.Context, nam
}
original := pvr.DeepCopy()
pvr.Status.Progress = velerov1api.PodVolumeOperationProgress{TotalBytes: progress.TotalBytes, BytesDone: progress.BytesDone}
pvr.Status.Progress = veleroapishared.DataMoveOperationProgress{TotalBytes: progress.TotalBytes, BytesDone: progress.BytesDone}
if err := c.Client.Patch(ctx, &pvr, client.MergeFrom(original)); err != nil {
log.WithError(err).Error("Failed to update progress")
+1 -4
View File
@@ -305,10 +305,7 @@ func (r *restoreReconciler) validateAndComplete(restore *api.Restore) backupInfo
}))
backupList := &api.BackupList{}
r.kbClient.List(context.Background(), backupList, &client.ListOptions{
LabelSelector: selector,
})
if err != nil {
if err := r.kbClient.List(context.Background(), backupList, &client.ListOptions{LabelSelector: selector}); err != nil {
restore.Status.ValidationErrors = append(restore.Status.ValidationErrors, "Unable to list backups for schedule")
return backupInfo{}
}
@@ -96,7 +96,6 @@ func (r *restoreOperationsReconciler) SetupWithManager(mgr ctrl.Manager) error {
// +kubebuilder:rbac:groups=velero.io,resources=restores,verbs=get;list;watch;update
// +kubebuilder:rbac:groups=velero.io,resources=restores/status,verbs=get
// +kubebuilder:rbac:groups=velero.io,resources=restorestoragelocations,verbs=get
func (r *restoreOperationsReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
log := r.logger.WithField("restore operations for restore", req.String())
+4
View File
@@ -36,6 +36,7 @@ import (
. "github.com/onsi/gomega"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
velerov2alpha1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
@@ -98,6 +99,9 @@ func newTestEnvironment() *testEnvironment {
err := velerov1api.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
err = velerov2alpha1api.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
env = &envtest.Environment{
CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")},
}
+15 -1
View File
@@ -22,6 +22,7 @@ import (
"fmt"
velerov1 "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v1"
velerov2alpha1 "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v2alpha1"
discovery "k8s.io/client-go/discovery"
rest "k8s.io/client-go/rest"
flowcontrol "k8s.io/client-go/util/flowcontrol"
@@ -30,13 +31,15 @@ import (
type Interface interface {
Discovery() discovery.DiscoveryInterface
VeleroV1() velerov1.VeleroV1Interface
VeleroV2alpha1() velerov2alpha1.VeleroV2alpha1Interface
}
// Clientset contains the clients for groups. Each group has exactly one
// version included in a Clientset.
type Clientset struct {
*discovery.DiscoveryClient
veleroV1 *velerov1.VeleroV1Client
veleroV1 *velerov1.VeleroV1Client
veleroV2alpha1 *velerov2alpha1.VeleroV2alpha1Client
}
// VeleroV1 retrieves the VeleroV1Client
@@ -44,6 +47,11 @@ func (c *Clientset) VeleroV1() velerov1.VeleroV1Interface {
return c.veleroV1
}
// VeleroV2alpha1 retrieves the VeleroV2alpha1Client
func (c *Clientset) VeleroV2alpha1() velerov2alpha1.VeleroV2alpha1Interface {
return c.veleroV2alpha1
}
// Discovery retrieves the DiscoveryClient
func (c *Clientset) Discovery() discovery.DiscoveryInterface {
if c == nil {
@@ -69,6 +77,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) {
if err != nil {
return nil, err
}
cs.veleroV2alpha1, err = velerov2alpha1.NewForConfig(&configShallowCopy)
if err != nil {
return nil, err
}
cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy)
if err != nil {
@@ -82,6 +94,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) {
func NewForConfigOrDie(c *rest.Config) *Clientset {
var cs Clientset
cs.veleroV1 = velerov1.NewForConfigOrDie(c)
cs.veleroV2alpha1 = velerov2alpha1.NewForConfigOrDie(c)
cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c)
return &cs
@@ -91,6 +104,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset {
func New(c rest.Interface) *Clientset {
var cs Clientset
cs.veleroV1 = velerov1.New(c)
cs.veleroV2alpha1 = velerov2alpha1.New(c)
cs.DiscoveryClient = discovery.NewDiscoveryClient(c)
return &cs
@@ -22,6 +22,8 @@ import (
clientset "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned"
velerov1 "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v1"
fakevelerov1 "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v1/fake"
velerov2alpha1 "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v2alpha1"
fakevelerov2alpha1 "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v2alpha1/fake"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/discovery"
@@ -83,3 +85,8 @@ var (
func (c *Clientset) VeleroV1() velerov1.VeleroV1Interface {
return &fakevelerov1.FakeVeleroV1{Fake: &c.Fake}
}
// VeleroV2alpha1 retrieves the VeleroV2alpha1Client
func (c *Clientset) VeleroV2alpha1() velerov2alpha1.VeleroV2alpha1Interface {
return &fakevelerov2alpha1.FakeVeleroV2alpha1{Fake: &c.Fake}
}
@@ -20,6 +20,7 @@ package fake
import (
velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
velerov2alpha1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
schema "k8s.io/apimachinery/pkg/runtime/schema"
@@ -32,6 +33,7 @@ var codecs = serializer.NewCodecFactory(scheme)
var localSchemeBuilder = runtime.SchemeBuilder{
velerov1.AddToScheme,
velerov2alpha1.AddToScheme,
}
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
@@ -20,6 +20,7 @@ package scheme
import (
velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
velerov2alpha1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
schema "k8s.io/apimachinery/pkg/runtime/schema"
@@ -32,6 +33,7 @@ var Codecs = serializer.NewCodecFactory(Scheme)
var ParameterCodec = runtime.NewParameterCodec(Scheme)
var localSchemeBuilder = runtime.SchemeBuilder{
velerov1.AddToScheme,
velerov2alpha1.AddToScheme,
}
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
@@ -0,0 +1,195 @@
/*
Copyright 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package v2alpha1
import (
"context"
"time"
v2alpha1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1"
scheme "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/scheme"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
rest "k8s.io/client-go/rest"
)
// DataDownloadsGetter has a method to return a DataDownloadInterface.
// A group's client should implement this interface.
type DataDownloadsGetter interface {
DataDownloads(namespace string) DataDownloadInterface
}
// DataDownloadInterface has methods to work with DataDownload resources.
type DataDownloadInterface interface {
Create(ctx context.Context, dataDownload *v2alpha1.DataDownload, opts v1.CreateOptions) (*v2alpha1.DataDownload, error)
Update(ctx context.Context, dataDownload *v2alpha1.DataDownload, opts v1.UpdateOptions) (*v2alpha1.DataDownload, error)
UpdateStatus(ctx context.Context, dataDownload *v2alpha1.DataDownload, opts v1.UpdateOptions) (*v2alpha1.DataDownload, error)
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
Get(ctx context.Context, name string, opts v1.GetOptions) (*v2alpha1.DataDownload, error)
List(ctx context.Context, opts v1.ListOptions) (*v2alpha1.DataDownloadList, error)
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2alpha1.DataDownload, err error)
DataDownloadExpansion
}
// dataDownloads implements DataDownloadInterface
type dataDownloads struct {
client rest.Interface
ns string
}
// newDataDownloads returns a DataDownloads
func newDataDownloads(c *VeleroV2alpha1Client, namespace string) *dataDownloads {
return &dataDownloads{
client: c.RESTClient(),
ns: namespace,
}
}
// Get takes name of the dataDownload, and returns the corresponding dataDownload object, and an error if there is any.
func (c *dataDownloads) Get(ctx context.Context, name string, options v1.GetOptions) (result *v2alpha1.DataDownload, err error) {
result = &v2alpha1.DataDownload{}
err = c.client.Get().
Namespace(c.ns).
Resource("datadownloads").
Name(name).
VersionedParams(&options, scheme.ParameterCodec).
Do(ctx).
Into(result)
return
}
// List takes label and field selectors, and returns the list of DataDownloads that match those selectors.
func (c *dataDownloads) List(ctx context.Context, opts v1.ListOptions) (result *v2alpha1.DataDownloadList, err error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
result = &v2alpha1.DataDownloadList{}
err = c.client.Get().
Namespace(c.ns).
Resource("datadownloads").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Do(ctx).
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested dataDownloads.
func (c *dataDownloads) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
opts.Watch = true
return c.client.Get().
Namespace(c.ns).
Resource("datadownloads").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Watch(ctx)
}
// Create takes the representation of a dataDownload and creates it. Returns the server's representation of the dataDownload, and an error, if there is any.
func (c *dataDownloads) Create(ctx context.Context, dataDownload *v2alpha1.DataDownload, opts v1.CreateOptions) (result *v2alpha1.DataDownload, err error) {
result = &v2alpha1.DataDownload{}
err = c.client.Post().
Namespace(c.ns).
Resource("datadownloads").
VersionedParams(&opts, scheme.ParameterCodec).
Body(dataDownload).
Do(ctx).
Into(result)
return
}
// Update takes the representation of a dataDownload and updates it. Returns the server's representation of the dataDownload, and an error, if there is any.
func (c *dataDownloads) Update(ctx context.Context, dataDownload *v2alpha1.DataDownload, opts v1.UpdateOptions) (result *v2alpha1.DataDownload, err error) {
result = &v2alpha1.DataDownload{}
err = c.client.Put().
Namespace(c.ns).
Resource("datadownloads").
Name(dataDownload.Name).
VersionedParams(&opts, scheme.ParameterCodec).
Body(dataDownload).
Do(ctx).
Into(result)
return
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *dataDownloads) UpdateStatus(ctx context.Context, dataDownload *v2alpha1.DataDownload, opts v1.UpdateOptions) (result *v2alpha1.DataDownload, err error) {
result = &v2alpha1.DataDownload{}
err = c.client.Put().
Namespace(c.ns).
Resource("datadownloads").
Name(dataDownload.Name).
SubResource("status").
VersionedParams(&opts, scheme.ParameterCodec).
Body(dataDownload).
Do(ctx).
Into(result)
return
}
// Delete takes name of the dataDownload and deletes it. Returns an error if one occurs.
func (c *dataDownloads) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("datadownloads").
Name(name).
Body(&opts).
Do(ctx).
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *dataDownloads) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
var timeout time.Duration
if listOpts.TimeoutSeconds != nil {
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
}
return c.client.Delete().
Namespace(c.ns).
Resource("datadownloads").
VersionedParams(&listOpts, scheme.ParameterCodec).
Timeout(timeout).
Body(&opts).
Do(ctx).
Error()
}
// Patch applies the patch and returns the patched dataDownload.
func (c *dataDownloads) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2alpha1.DataDownload, err error) {
result = &v2alpha1.DataDownload{}
err = c.client.Patch(pt).
Namespace(c.ns).
Resource("datadownloads").
Name(name).
SubResource(subresources...).
VersionedParams(&opts, scheme.ParameterCodec).
Body(data).
Do(ctx).
Into(result)
return
}
@@ -0,0 +1,195 @@
/*
Copyright 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package v2alpha1
import (
"context"
"time"
v2alpha1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1"
scheme "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/scheme"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
rest "k8s.io/client-go/rest"
)
// DataUploadsGetter has a method to return a DataUploadInterface.
// A group's client should implement this interface.
type DataUploadsGetter interface {
DataUploads(namespace string) DataUploadInterface
}
// DataUploadInterface has methods to work with DataUpload resources.
type DataUploadInterface interface {
Create(ctx context.Context, dataUpload *v2alpha1.DataUpload, opts v1.CreateOptions) (*v2alpha1.DataUpload, error)
Update(ctx context.Context, dataUpload *v2alpha1.DataUpload, opts v1.UpdateOptions) (*v2alpha1.DataUpload, error)
UpdateStatus(ctx context.Context, dataUpload *v2alpha1.DataUpload, opts v1.UpdateOptions) (*v2alpha1.DataUpload, error)
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
Get(ctx context.Context, name string, opts v1.GetOptions) (*v2alpha1.DataUpload, error)
List(ctx context.Context, opts v1.ListOptions) (*v2alpha1.DataUploadList, error)
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2alpha1.DataUpload, err error)
DataUploadExpansion
}
// dataUploads implements DataUploadInterface
type dataUploads struct {
client rest.Interface
ns string
}
// newDataUploads returns a DataUploads
func newDataUploads(c *VeleroV2alpha1Client, namespace string) *dataUploads {
return &dataUploads{
client: c.RESTClient(),
ns: namespace,
}
}
// Get takes name of the dataUpload, and returns the corresponding dataUpload object, and an error if there is any.
func (c *dataUploads) Get(ctx context.Context, name string, options v1.GetOptions) (result *v2alpha1.DataUpload, err error) {
result = &v2alpha1.DataUpload{}
err = c.client.Get().
Namespace(c.ns).
Resource("datauploads").
Name(name).
VersionedParams(&options, scheme.ParameterCodec).
Do(ctx).
Into(result)
return
}
// List takes label and field selectors, and returns the list of DataUploads that match those selectors.
func (c *dataUploads) List(ctx context.Context, opts v1.ListOptions) (result *v2alpha1.DataUploadList, err error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
result = &v2alpha1.DataUploadList{}
err = c.client.Get().
Namespace(c.ns).
Resource("datauploads").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Do(ctx).
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested dataUploads.
func (c *dataUploads) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
opts.Watch = true
return c.client.Get().
Namespace(c.ns).
Resource("datauploads").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Watch(ctx)
}
// Create takes the representation of a dataUpload and creates it. Returns the server's representation of the dataUpload, and an error, if there is any.
func (c *dataUploads) Create(ctx context.Context, dataUpload *v2alpha1.DataUpload, opts v1.CreateOptions) (result *v2alpha1.DataUpload, err error) {
result = &v2alpha1.DataUpload{}
err = c.client.Post().
Namespace(c.ns).
Resource("datauploads").
VersionedParams(&opts, scheme.ParameterCodec).
Body(dataUpload).
Do(ctx).
Into(result)
return
}
// Update takes the representation of a dataUpload and updates it. Returns the server's representation of the dataUpload, and an error, if there is any.
func (c *dataUploads) Update(ctx context.Context, dataUpload *v2alpha1.DataUpload, opts v1.UpdateOptions) (result *v2alpha1.DataUpload, err error) {
result = &v2alpha1.DataUpload{}
err = c.client.Put().
Namespace(c.ns).
Resource("datauploads").
Name(dataUpload.Name).
VersionedParams(&opts, scheme.ParameterCodec).
Body(dataUpload).
Do(ctx).
Into(result)
return
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *dataUploads) UpdateStatus(ctx context.Context, dataUpload *v2alpha1.DataUpload, opts v1.UpdateOptions) (result *v2alpha1.DataUpload, err error) {
result = &v2alpha1.DataUpload{}
err = c.client.Put().
Namespace(c.ns).
Resource("datauploads").
Name(dataUpload.Name).
SubResource("status").
VersionedParams(&opts, scheme.ParameterCodec).
Body(dataUpload).
Do(ctx).
Into(result)
return
}
// Delete takes name of the dataUpload and deletes it. Returns an error if one occurs.
func (c *dataUploads) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("datauploads").
Name(name).
Body(&opts).
Do(ctx).
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *dataUploads) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
var timeout time.Duration
if listOpts.TimeoutSeconds != nil {
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
}
return c.client.Delete().
Namespace(c.ns).
Resource("datauploads").
VersionedParams(&listOpts, scheme.ParameterCodec).
Timeout(timeout).
Body(&opts).
Do(ctx).
Error()
}
// Patch applies the patch and returns the patched dataUpload.
func (c *dataUploads) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2alpha1.DataUpload, err error) {
result = &v2alpha1.DataUpload{}
err = c.client.Patch(pt).
Namespace(c.ns).
Resource("datauploads").
Name(name).
SubResource(subresources...).
VersionedParams(&opts, scheme.ParameterCodec).
Body(data).
Do(ctx).
Into(result)
return
}
@@ -0,0 +1,20 @@
/*
Copyright 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.
*/
// Code generated by client-gen. DO NOT EDIT.
// This package has the automatically generated typed clients.
package v2alpha1
@@ -0,0 +1,20 @@
/*
Copyright 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.
*/
// Code generated by client-gen. DO NOT EDIT.
// Package fake has the automatically generated clients.
package fake
@@ -0,0 +1,142 @@
/*
Copyright 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
"context"
v2alpha1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
labels "k8s.io/apimachinery/pkg/labels"
schema "k8s.io/apimachinery/pkg/runtime/schema"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
testing "k8s.io/client-go/testing"
)
// FakeDataDownloads implements DataDownloadInterface
type FakeDataDownloads struct {
Fake *FakeVeleroV2alpha1
ns string
}
var datadownloadsResource = schema.GroupVersionResource{Group: "velero.io", Version: "v2alpha1", Resource: "datadownloads"}
var datadownloadsKind = schema.GroupVersionKind{Group: "velero.io", Version: "v2alpha1", Kind: "DataDownload"}
// Get takes name of the dataDownload, and returns the corresponding dataDownload object, and an error if there is any.
func (c *FakeDataDownloads) Get(ctx context.Context, name string, options v1.GetOptions) (result *v2alpha1.DataDownload, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetAction(datadownloadsResource, c.ns, name), &v2alpha1.DataDownload{})
if obj == nil {
return nil, err
}
return obj.(*v2alpha1.DataDownload), err
}
// List takes label and field selectors, and returns the list of DataDownloads that match those selectors.
func (c *FakeDataDownloads) List(ctx context.Context, opts v1.ListOptions) (result *v2alpha1.DataDownloadList, err error) {
obj, err := c.Fake.
Invokes(testing.NewListAction(datadownloadsResource, datadownloadsKind, c.ns, opts), &v2alpha1.DataDownloadList{})
if obj == nil {
return nil, err
}
label, _, _ := testing.ExtractFromListOptions(opts)
if label == nil {
label = labels.Everything()
}
list := &v2alpha1.DataDownloadList{ListMeta: obj.(*v2alpha1.DataDownloadList).ListMeta}
for _, item := range obj.(*v2alpha1.DataDownloadList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested dataDownloads.
func (c *FakeDataDownloads) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(datadownloadsResource, c.ns, opts))
}
// Create takes the representation of a dataDownload and creates it. Returns the server's representation of the dataDownload, and an error, if there is any.
func (c *FakeDataDownloads) Create(ctx context.Context, dataDownload *v2alpha1.DataDownload, opts v1.CreateOptions) (result *v2alpha1.DataDownload, err error) {
obj, err := c.Fake.
Invokes(testing.NewCreateAction(datadownloadsResource, c.ns, dataDownload), &v2alpha1.DataDownload{})
if obj == nil {
return nil, err
}
return obj.(*v2alpha1.DataDownload), err
}
// Update takes the representation of a dataDownload and updates it. Returns the server's representation of the dataDownload, and an error, if there is any.
func (c *FakeDataDownloads) Update(ctx context.Context, dataDownload *v2alpha1.DataDownload, opts v1.UpdateOptions) (result *v2alpha1.DataDownload, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateAction(datadownloadsResource, c.ns, dataDownload), &v2alpha1.DataDownload{})
if obj == nil {
return nil, err
}
return obj.(*v2alpha1.DataDownload), err
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *FakeDataDownloads) UpdateStatus(ctx context.Context, dataDownload *v2alpha1.DataDownload, opts v1.UpdateOptions) (*v2alpha1.DataDownload, error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(datadownloadsResource, "status", c.ns, dataDownload), &v2alpha1.DataDownload{})
if obj == nil {
return nil, err
}
return obj.(*v2alpha1.DataDownload), err
}
// Delete takes name of the dataDownload and deletes it. Returns an error if one occurs.
func (c *FakeDataDownloads) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewDeleteAction(datadownloadsResource, c.ns, name), &v2alpha1.DataDownload{})
return err
}
// DeleteCollection deletes a collection of objects.
func (c *FakeDataDownloads) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
action := testing.NewDeleteCollectionAction(datadownloadsResource, c.ns, listOpts)
_, err := c.Fake.Invokes(action, &v2alpha1.DataDownloadList{})
return err
}
// Patch applies the patch and returns the patched dataDownload.
func (c *FakeDataDownloads) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2alpha1.DataDownload, err error) {
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(datadownloadsResource, c.ns, name, pt, data, subresources...), &v2alpha1.DataDownload{})
if obj == nil {
return nil, err
}
return obj.(*v2alpha1.DataDownload), err
}
@@ -0,0 +1,142 @@
/*
Copyright 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
"context"
v2alpha1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
labels "k8s.io/apimachinery/pkg/labels"
schema "k8s.io/apimachinery/pkg/runtime/schema"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
testing "k8s.io/client-go/testing"
)
// FakeDataUploads implements DataUploadInterface
type FakeDataUploads struct {
Fake *FakeVeleroV2alpha1
ns string
}
var datauploadsResource = schema.GroupVersionResource{Group: "velero.io", Version: "v2alpha1", Resource: "datauploads"}
var datauploadsKind = schema.GroupVersionKind{Group: "velero.io", Version: "v2alpha1", Kind: "DataUpload"}
// Get takes name of the dataUpload, and returns the corresponding dataUpload object, and an error if there is any.
func (c *FakeDataUploads) Get(ctx context.Context, name string, options v1.GetOptions) (result *v2alpha1.DataUpload, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetAction(datauploadsResource, c.ns, name), &v2alpha1.DataUpload{})
if obj == nil {
return nil, err
}
return obj.(*v2alpha1.DataUpload), err
}
// List takes label and field selectors, and returns the list of DataUploads that match those selectors.
func (c *FakeDataUploads) List(ctx context.Context, opts v1.ListOptions) (result *v2alpha1.DataUploadList, err error) {
obj, err := c.Fake.
Invokes(testing.NewListAction(datauploadsResource, datauploadsKind, c.ns, opts), &v2alpha1.DataUploadList{})
if obj == nil {
return nil, err
}
label, _, _ := testing.ExtractFromListOptions(opts)
if label == nil {
label = labels.Everything()
}
list := &v2alpha1.DataUploadList{ListMeta: obj.(*v2alpha1.DataUploadList).ListMeta}
for _, item := range obj.(*v2alpha1.DataUploadList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested dataUploads.
func (c *FakeDataUploads) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(datauploadsResource, c.ns, opts))
}
// Create takes the representation of a dataUpload and creates it. Returns the server's representation of the dataUpload, and an error, if there is any.
func (c *FakeDataUploads) Create(ctx context.Context, dataUpload *v2alpha1.DataUpload, opts v1.CreateOptions) (result *v2alpha1.DataUpload, err error) {
obj, err := c.Fake.
Invokes(testing.NewCreateAction(datauploadsResource, c.ns, dataUpload), &v2alpha1.DataUpload{})
if obj == nil {
return nil, err
}
return obj.(*v2alpha1.DataUpload), err
}
// Update takes the representation of a dataUpload and updates it. Returns the server's representation of the dataUpload, and an error, if there is any.
func (c *FakeDataUploads) Update(ctx context.Context, dataUpload *v2alpha1.DataUpload, opts v1.UpdateOptions) (result *v2alpha1.DataUpload, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateAction(datauploadsResource, c.ns, dataUpload), &v2alpha1.DataUpload{})
if obj == nil {
return nil, err
}
return obj.(*v2alpha1.DataUpload), err
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *FakeDataUploads) UpdateStatus(ctx context.Context, dataUpload *v2alpha1.DataUpload, opts v1.UpdateOptions) (*v2alpha1.DataUpload, error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(datauploadsResource, "status", c.ns, dataUpload), &v2alpha1.DataUpload{})
if obj == nil {
return nil, err
}
return obj.(*v2alpha1.DataUpload), err
}
// Delete takes name of the dataUpload and deletes it. Returns an error if one occurs.
func (c *FakeDataUploads) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewDeleteAction(datauploadsResource, c.ns, name), &v2alpha1.DataUpload{})
return err
}
// DeleteCollection deletes a collection of objects.
func (c *FakeDataUploads) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
action := testing.NewDeleteCollectionAction(datauploadsResource, c.ns, listOpts)
_, err := c.Fake.Invokes(action, &v2alpha1.DataUploadList{})
return err
}
// Patch applies the patch and returns the patched dataUpload.
func (c *FakeDataUploads) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2alpha1.DataUpload, err error) {
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(datauploadsResource, c.ns, name, pt, data, subresources...), &v2alpha1.DataUpload{})
if obj == nil {
return nil, err
}
return obj.(*v2alpha1.DataUpload), err
}
@@ -0,0 +1,44 @@
/*
Copyright 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
v2alpha1 "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v2alpha1"
rest "k8s.io/client-go/rest"
testing "k8s.io/client-go/testing"
)
type FakeVeleroV2alpha1 struct {
*testing.Fake
}
func (c *FakeVeleroV2alpha1) DataDownloads(namespace string) v2alpha1.DataDownloadInterface {
return &FakeDataDownloads{c, namespace}
}
func (c *FakeVeleroV2alpha1) DataUploads(namespace string) v2alpha1.DataUploadInterface {
return &FakeDataUploads{c, namespace}
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *FakeVeleroV2alpha1) RESTClient() rest.Interface {
var ret *rest.RESTClient
return ret
}
@@ -0,0 +1,23 @@
/*
Copyright 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package v2alpha1
type DataDownloadExpansion interface{}
type DataUploadExpansion interface{}
@@ -0,0 +1,94 @@
/*
Copyright 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package v2alpha1
import (
v2alpha1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1"
"github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/scheme"
rest "k8s.io/client-go/rest"
)
type VeleroV2alpha1Interface interface {
RESTClient() rest.Interface
DataDownloadsGetter
DataUploadsGetter
}
// VeleroV2alpha1Client is used to interact with features provided by the velero.io group.
type VeleroV2alpha1Client struct {
restClient rest.Interface
}
func (c *VeleroV2alpha1Client) DataDownloads(namespace string) DataDownloadInterface {
return newDataDownloads(c, namespace)
}
func (c *VeleroV2alpha1Client) DataUploads(namespace string) DataUploadInterface {
return newDataUploads(c, namespace)
}
// NewForConfig creates a new VeleroV2alpha1Client for the given config.
func NewForConfig(c *rest.Config) (*VeleroV2alpha1Client, error) {
config := *c
if err := setConfigDefaults(&config); err != nil {
return nil, err
}
client, err := rest.RESTClientFor(&config)
if err != nil {
return nil, err
}
return &VeleroV2alpha1Client{client}, nil
}
// NewForConfigOrDie creates a new VeleroV2alpha1Client for the given config and
// panics if there is an error in the config.
func NewForConfigOrDie(c *rest.Config) *VeleroV2alpha1Client {
client, err := NewForConfig(c)
if err != nil {
panic(err)
}
return client
}
// New creates a new VeleroV2alpha1Client for the given RESTClient.
func New(c rest.Interface) *VeleroV2alpha1Client {
return &VeleroV2alpha1Client{c}
}
func setConfigDefaults(config *rest.Config) error {
gv := v2alpha1.SchemeGroupVersion
config.GroupVersion = &gv
config.APIPath = "/apis"
config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
if config.UserAgent == "" {
config.UserAgent = rest.DefaultKubernetesUserAgent()
}
return nil
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *VeleroV2alpha1Client) RESTClient() rest.Interface {
if c == nil {
return nil
}
return c.restClient
}
@@ -22,6 +22,7 @@ import (
"fmt"
v1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
v2alpha1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1"
schema "k8s.io/apimachinery/pkg/runtime/schema"
cache "k8s.io/client-go/tools/cache"
)
@@ -76,6 +77,12 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource
case v1.SchemeGroupVersion.WithResource("volumesnapshotlocations"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Velero().V1().VolumeSnapshotLocations().Informer()}, nil
// Group=velero.io, Version=v2alpha1
case v2alpha1.SchemeGroupVersion.WithResource("datadownloads"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Velero().V2alpha1().DataDownloads().Informer()}, nil
case v2alpha1.SchemeGroupVersion.WithResource("datauploads"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Velero().V2alpha1().DataUploads().Informer()}, nil
}
return nil, fmt.Errorf("no informer found for %v", resource)
@@ -21,12 +21,15 @@ package velero
import (
internalinterfaces "github.com/vmware-tanzu/velero/pkg/generated/informers/externalversions/internalinterfaces"
v1 "github.com/vmware-tanzu/velero/pkg/generated/informers/externalversions/velero/v1"
v2alpha1 "github.com/vmware-tanzu/velero/pkg/generated/informers/externalversions/velero/v2alpha1"
)
// Interface provides access to each of this group's versions.
type Interface interface {
// V1 provides access to shared informers for resources in V1.
V1() v1.Interface
// V2alpha1 provides access to shared informers for resources in V2alpha1.
V2alpha1() v2alpha1.Interface
}
type group struct {
@@ -44,3 +47,8 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList
func (g *group) V1() v1.Interface {
return v1.New(g.factory, g.namespace, g.tweakListOptions)
}
// V2alpha1 returns a new v2alpha1.Interface.
func (g *group) V2alpha1() v2alpha1.Interface {
return v2alpha1.New(g.factory, g.namespace, g.tweakListOptions)
}
@@ -0,0 +1,90 @@
/*
Copyright 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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v2alpha1
import (
"context"
time "time"
velerov2alpha1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1"
versioned "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned"
internalinterfaces "github.com/vmware-tanzu/velero/pkg/generated/informers/externalversions/internalinterfaces"
v2alpha1 "github.com/vmware-tanzu/velero/pkg/generated/listers/velero/v2alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
// DataDownloadInformer provides access to a shared informer and lister for
// DataDownloads.
type DataDownloadInformer interface {
Informer() cache.SharedIndexInformer
Lister() v2alpha1.DataDownloadLister
}
type dataDownloadInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewDataDownloadInformer constructs a new informer for DataDownload type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewDataDownloadInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredDataDownloadInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredDataDownloadInformer constructs a new informer for DataDownload type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredDataDownloadInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.VeleroV2alpha1().DataDownloads(namespace).List(context.TODO(), options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.VeleroV2alpha1().DataDownloads(namespace).Watch(context.TODO(), options)
},
},
&velerov2alpha1.DataDownload{},
resyncPeriod,
indexers,
)
}
func (f *dataDownloadInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredDataDownloadInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *dataDownloadInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&velerov2alpha1.DataDownload{}, f.defaultInformer)
}
func (f *dataDownloadInformer) Lister() v2alpha1.DataDownloadLister {
return v2alpha1.NewDataDownloadLister(f.Informer().GetIndexer())
}
@@ -0,0 +1,90 @@
/*
Copyright 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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v2alpha1
import (
"context"
time "time"
velerov2alpha1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1"
versioned "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned"
internalinterfaces "github.com/vmware-tanzu/velero/pkg/generated/informers/externalversions/internalinterfaces"
v2alpha1 "github.com/vmware-tanzu/velero/pkg/generated/listers/velero/v2alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
// DataUploadInformer provides access to a shared informer and lister for
// DataUploads.
type DataUploadInformer interface {
Informer() cache.SharedIndexInformer
Lister() v2alpha1.DataUploadLister
}
type dataUploadInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewDataUploadInformer constructs a new informer for DataUpload type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewDataUploadInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredDataUploadInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredDataUploadInformer constructs a new informer for DataUpload type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredDataUploadInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.VeleroV2alpha1().DataUploads(namespace).List(context.TODO(), options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.VeleroV2alpha1().DataUploads(namespace).Watch(context.TODO(), options)
},
},
&velerov2alpha1.DataUpload{},
resyncPeriod,
indexers,
)
}
func (f *dataUploadInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredDataUploadInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *dataUploadInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&velerov2alpha1.DataUpload{}, f.defaultInformer)
}
func (f *dataUploadInformer) Lister() v2alpha1.DataUploadLister {
return v2alpha1.NewDataUploadLister(f.Informer().GetIndexer())
}
@@ -0,0 +1,52 @@
/*
Copyright 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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v2alpha1
import (
internalinterfaces "github.com/vmware-tanzu/velero/pkg/generated/informers/externalversions/internalinterfaces"
)
// Interface provides access to all the informers in this group version.
type Interface interface {
// DataDownloads returns a DataDownloadInformer.
DataDownloads() DataDownloadInformer
// DataUploads returns a DataUploadInformer.
DataUploads() DataUploadInformer
}
type version struct {
factory internalinterfaces.SharedInformerFactory
namespace string
tweakListOptions internalinterfaces.TweakListOptionsFunc
}
// New returns a new Interface.
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
}
// DataDownloads returns a DataDownloadInformer.
func (v *version) DataDownloads() DataDownloadInformer {
return &dataDownloadInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
// DataUploads returns a DataUploadInformer.
func (v *version) DataUploads() DataUploadInformer {
return &dataUploadInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
@@ -0,0 +1,99 @@
/*
Copyright 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.
*/
// Code generated by lister-gen. DO NOT EDIT.
package v2alpha1
import (
v2alpha1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/tools/cache"
)
// DataDownloadLister helps list DataDownloads.
// All objects returned here must be treated as read-only.
type DataDownloadLister interface {
// List lists all DataDownloads in the indexer.
// Objects returned here must be treated as read-only.
List(selector labels.Selector) (ret []*v2alpha1.DataDownload, err error)
// DataDownloads returns an object that can list and get DataDownloads.
DataDownloads(namespace string) DataDownloadNamespaceLister
DataDownloadListerExpansion
}
// dataDownloadLister implements the DataDownloadLister interface.
type dataDownloadLister struct {
indexer cache.Indexer
}
// NewDataDownloadLister returns a new DataDownloadLister.
func NewDataDownloadLister(indexer cache.Indexer) DataDownloadLister {
return &dataDownloadLister{indexer: indexer}
}
// List lists all DataDownloads in the indexer.
func (s *dataDownloadLister) List(selector labels.Selector) (ret []*v2alpha1.DataDownload, err error) {
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
ret = append(ret, m.(*v2alpha1.DataDownload))
})
return ret, err
}
// DataDownloads returns an object that can list and get DataDownloads.
func (s *dataDownloadLister) DataDownloads(namespace string) DataDownloadNamespaceLister {
return dataDownloadNamespaceLister{indexer: s.indexer, namespace: namespace}
}
// DataDownloadNamespaceLister helps list and get DataDownloads.
// All objects returned here must be treated as read-only.
type DataDownloadNamespaceLister interface {
// List lists all DataDownloads in the indexer for a given namespace.
// Objects returned here must be treated as read-only.
List(selector labels.Selector) (ret []*v2alpha1.DataDownload, err error)
// Get retrieves the DataDownload from the indexer for a given namespace and name.
// Objects returned here must be treated as read-only.
Get(name string) (*v2alpha1.DataDownload, error)
DataDownloadNamespaceListerExpansion
}
// dataDownloadNamespaceLister implements the DataDownloadNamespaceLister
// interface.
type dataDownloadNamespaceLister struct {
indexer cache.Indexer
namespace string
}
// List lists all DataDownloads in the indexer for a given namespace.
func (s dataDownloadNamespaceLister) List(selector labels.Selector) (ret []*v2alpha1.DataDownload, err error) {
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
ret = append(ret, m.(*v2alpha1.DataDownload))
})
return ret, err
}
// Get retrieves the DataDownload from the indexer for a given namespace and name.
func (s dataDownloadNamespaceLister) Get(name string) (*v2alpha1.DataDownload, error) {
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound(v2alpha1.Resource("datadownload"), name)
}
return obj.(*v2alpha1.DataDownload), nil
}
@@ -0,0 +1,99 @@
/*
Copyright 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.
*/
// Code generated by lister-gen. DO NOT EDIT.
package v2alpha1
import (
v2alpha1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/tools/cache"
)
// DataUploadLister helps list DataUploads.
// All objects returned here must be treated as read-only.
type DataUploadLister interface {
// List lists all DataUploads in the indexer.
// Objects returned here must be treated as read-only.
List(selector labels.Selector) (ret []*v2alpha1.DataUpload, err error)
// DataUploads returns an object that can list and get DataUploads.
DataUploads(namespace string) DataUploadNamespaceLister
DataUploadListerExpansion
}
// dataUploadLister implements the DataUploadLister interface.
type dataUploadLister struct {
indexer cache.Indexer
}
// NewDataUploadLister returns a new DataUploadLister.
func NewDataUploadLister(indexer cache.Indexer) DataUploadLister {
return &dataUploadLister{indexer: indexer}
}
// List lists all DataUploads in the indexer.
func (s *dataUploadLister) List(selector labels.Selector) (ret []*v2alpha1.DataUpload, err error) {
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
ret = append(ret, m.(*v2alpha1.DataUpload))
})
return ret, err
}
// DataUploads returns an object that can list and get DataUploads.
func (s *dataUploadLister) DataUploads(namespace string) DataUploadNamespaceLister {
return dataUploadNamespaceLister{indexer: s.indexer, namespace: namespace}
}
// DataUploadNamespaceLister helps list and get DataUploads.
// All objects returned here must be treated as read-only.
type DataUploadNamespaceLister interface {
// List lists all DataUploads in the indexer for a given namespace.
// Objects returned here must be treated as read-only.
List(selector labels.Selector) (ret []*v2alpha1.DataUpload, err error)
// Get retrieves the DataUpload from the indexer for a given namespace and name.
// Objects returned here must be treated as read-only.
Get(name string) (*v2alpha1.DataUpload, error)
DataUploadNamespaceListerExpansion
}
// dataUploadNamespaceLister implements the DataUploadNamespaceLister
// interface.
type dataUploadNamespaceLister struct {
indexer cache.Indexer
namespace string
}
// List lists all DataUploads in the indexer for a given namespace.
func (s dataUploadNamespaceLister) List(selector labels.Selector) (ret []*v2alpha1.DataUpload, err error) {
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
ret = append(ret, m.(*v2alpha1.DataUpload))
})
return ret, err
}
// Get retrieves the DataUpload from the indexer for a given namespace and name.
func (s dataUploadNamespaceLister) Get(name string) (*v2alpha1.DataUpload, error) {
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound(v2alpha1.Resource("dataupload"), name)
}
return obj.(*v2alpha1.DataUpload), nil
}
@@ -0,0 +1,35 @@
/*
Copyright 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.
*/
// Code generated by lister-gen. DO NOT EDIT.
package v2alpha1
// DataDownloadListerExpansion allows custom methods to be added to
// DataDownloadLister.
type DataDownloadListerExpansion interface{}
// DataDownloadNamespaceListerExpansion allows custom methods to be added to
// DataDownloadNamespaceLister.
type DataDownloadNamespaceListerExpansion interface{}
// DataUploadListerExpansion allows custom methods to be added to
// DataUploadLister.
type DataUploadListerExpansion interface{}
// DataUploadNamespaceListerExpansion allows custom methods to be added to
// DataUploadNamespaceLister.
type DataUploadNamespaceListerExpansion interface{}
+36 -9
View File
@@ -17,6 +17,7 @@ limitations under the License.
package install
import (
"fmt"
"time"
corev1 "k8s.io/api/core/v1"
@@ -27,6 +28,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
v1crds "github.com/vmware-tanzu/velero/config/crd/v1/crds"
v2alpha1crds "github.com/vmware-tanzu/velero/config/crd/v2alpha1/crds"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
)
@@ -250,7 +252,16 @@ func AllCRDs() *unstructured.UnstructuredList {
for _, crd := range v1crds.CRDs {
crd.SetLabels(Labels())
appendUnstructured(resources, crd)
if err := appendUnstructured(resources, crd); err != nil {
fmt.Printf("error appending v1 CRD %s: %s\n", crd.GetName(), err.Error())
}
}
for _, crd := range v2alpha1crds.CRDs {
crd.SetLabels(Labels())
if err := appendUnstructured(resources, crd); err != nil {
fmt.Printf("error appending v2alpha1 CRD %s: %s\n", crd.GetName(), err.Error())
}
}
return resources
@@ -262,32 +273,44 @@ func AllResources(o *VeleroOptions) *unstructured.UnstructuredList {
resources := AllCRDs()
ns := Namespace(o.Namespace)
appendUnstructured(resources, ns)
if err := appendUnstructured(resources, ns); err != nil {
fmt.Printf("error appending Namespace %s: %s\n", ns.GetName(), err.Error())
}
serviceAccountName := defaultServiceAccountName
if o.ServiceAccountName == "" {
crb := ClusterRoleBinding(o.Namespace)
appendUnstructured(resources, crb)
if err := appendUnstructured(resources, crb); err != nil {
fmt.Printf("error appending ClusterRoleBinding %s: %s\n", crb.GetName(), err.Error())
}
sa := ServiceAccount(o.Namespace, o.ServiceAccountAnnotations)
appendUnstructured(resources, sa)
if err := appendUnstructured(resources, sa); err != nil {
fmt.Printf("error appending ServiceAccount %s: %s\n", sa.GetName(), err.Error())
}
} else {
serviceAccountName = o.ServiceAccountName
}
if o.SecretData != nil {
sec := Secret(o.Namespace, o.SecretData)
appendUnstructured(resources, sec)
if err := appendUnstructured(resources, sec); err != nil {
fmt.Printf("error appending Secret %s: %s\n", sec.GetName(), err.Error())
}
}
if !o.NoDefaultBackupLocation {
bsl := BackupStorageLocation(o.Namespace, o.ProviderName, o.Bucket, o.Prefix, o.BSLConfig, o.CACertData)
appendUnstructured(resources, bsl)
if err := appendUnstructured(resources, bsl); err != nil {
fmt.Printf("error appending BackupStorageLocation %s: %s\n", bsl.GetName(), err.Error())
}
}
// A snapshot location may not be desirable for users relying on pod volume backup/restore
if o.UseVolumeSnapshots {
vsl := VolumeSnapshotLocation(o.Namespace, o.ProviderName, o.VSLConfig)
appendUnstructured(resources, vsl)
if err := appendUnstructured(resources, vsl); err != nil {
fmt.Printf("error appending VolumeSnapshotLocation %s: %s\n", vsl.GetName(), err.Error())
}
}
secretPresent := o.SecretData != nil
@@ -322,7 +345,9 @@ func AllResources(o *VeleroOptions) *unstructured.UnstructuredList {
deploy := Deployment(o.Namespace, deployOpts...)
appendUnstructured(resources, deploy)
if err := appendUnstructured(resources, deploy); err != nil {
fmt.Printf("error appending Deployment %s: %s\n", deploy.GetName(), err.Error())
}
if o.UseNodeAgent {
dsOpts := []podTemplateOption{
@@ -337,7 +362,9 @@ func AllResources(o *VeleroOptions) *unstructured.UnstructuredList {
dsOpts = append(dsOpts, WithFeatures(o.Features))
}
ds := DaemonSet(o.Namespace, dsOpts...)
appendUnstructured(resources, ds)
if err := appendUnstructured(resources, ds); err != nil {
fmt.Printf("error appending DaemonSet %s: %s\n", ds.GetName(), err.Error())
}
}
return resources
@@ -0,0 +1,58 @@
/*
Copyright 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 common
import (
"context"
"fmt"
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
)
func PluginConfigLabelSelector(kind PluginKind, name string) string {
return fmt.Sprintf("velero.io/plugin-config,%s=%s", name, kind)
}
func GetPluginConfig(kind PluginKind, name string, client corev1client.ConfigMapInterface) (*corev1.ConfigMap, error) {
opts := metav1.ListOptions{
// velero.io/plugin-config: true
// velero.io/pod-volume-restore: RestoreItemAction
LabelSelector: PluginConfigLabelSelector(kind, name),
}
list, err := client.List(context.Background(), opts)
if err != nil {
return nil, errors.WithStack(err)
}
if len(list.Items) == 0 {
return nil, nil
}
if len(list.Items) > 1 {
var items []string
for _, item := range list.Items {
items = append(items, item.Name)
}
return nil, errors.Errorf("found more than one ConfigMap matching label selector %q: %v", opts.LabelSelector, items)
}
return &list.Items[0], nil
}
@@ -0,0 +1,121 @@
/*
Copyright 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 common
import (
"reflect"
"testing"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/fake"
velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
)
func TestGetPluginConfig(t *testing.T) {
type args struct {
kind PluginKind
name string
objects []runtime.Object
}
pluginLabelsMap := map[string]string{"velero.io/plugin-config": "", "foo": "RestoreItemAction"}
testConfigMap := &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{
Kind: "ConfigMap",
},
ObjectMeta: metav1.ObjectMeta{
Name: "foo-config",
Namespace: velerov1.DefaultNamespace,
Labels: pluginLabelsMap,
},
}
tests := []struct {
name string
args args
want *corev1.ConfigMap
wantErr bool
}{
{
name: "should return nil if no config map found",
args: args{
kind: PluginKindRestoreItemAction,
name: "foo",
objects: []runtime.Object{},
},
want: nil,
wantErr: false,
},
{
name: "should return error if more than one config map found",
args: args{
kind: PluginKindRestoreItemAction,
name: "foo",
objects: []runtime.Object{
&corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{
Kind: "ConfigMap",
},
ObjectMeta: metav1.ObjectMeta{
Name: "foo-config",
Namespace: velerov1.DefaultNamespace,
Labels: pluginLabelsMap,
},
},
&corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{
Kind: "ConfigMap",
},
ObjectMeta: metav1.ObjectMeta{
Name: "foo-config-duplicate",
Namespace: velerov1.DefaultNamespace,
Labels: pluginLabelsMap,
},
},
},
},
want: nil,
wantErr: true,
},
{
name: "should return pointer to configmap if only one config map with label found",
args: args{
kind: PluginKindRestoreItemAction,
name: "foo",
objects: []runtime.Object{
testConfigMap,
},
},
want: testConfigMap,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
fakeClient := fake.NewSimpleClientset(tt.args.objects...)
got, err := GetPluginConfig(tt.args.kind, tt.args.name, fakeClient.CoreV1().ConfigMaps(velerov1.DefaultNamespace))
if (err != nil) != tt.wantErr {
t.Errorf("GetPluginConfig() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetPluginConfig() = %v, want %v", got, tt.want)
}
})
}
}
+3 -1
View File
@@ -87,7 +87,9 @@ func (c *ObjectStoreGRPCClient) PutObject(bucket, key string, body io.Reader) er
return nil
}
if err != nil {
stream.CloseSend()
if err := stream.CloseSend(); err != nil {
return common.FromGRPCError(err)
}
return errors.WithStack(err)
}
+4 -1
View File
@@ -232,7 +232,10 @@ func getNames(command string, kind common.PluginKind, plugin Interface) []Plugin
func (s *server) Serve() {
if s.flagSet != nil && !s.flagSet.Parsed() {
s.log.Debugf("Parsing flags")
s.flagSet.Parse(os.Args[1:])
if err := s.flagSet.Parse(os.Args[1:]); err != nil {
s.log.Errorf("fail to parse the flags: %s", err.Error())
return
}
}
s.log.Level = s.logLevelFlag.Parse()
+1 -1
View File
@@ -131,7 +131,7 @@ func (b *backupper) BackupPodVolumes(backup *velerov1api.Backup, pod *corev1api.
if len(volumesToBackup) == 0 {
return nil, nil
}
log.Infof("pod %s/%s has volumes to backup: %v", pod.Namespace, pod.Name, volumesToBackup)
err := kube.IsPodRunning(pod)
if err != nil {
for _, volumeName := range volumesToBackup {
+65
View File
@@ -17,13 +17,19 @@ limitations under the License.
package podvolume
import (
"bytes"
"context"
"fmt"
"testing"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
corev1api "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/vmware-tanzu/velero/internal/resourcepolicies"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
)
func TestIsHostPathVolume(t *testing.T) {
@@ -139,3 +145,62 @@ func (g *fakePVGetter) Get(ctx context.Context, name string, opts metav1.GetOpti
return nil, errors.New("item not found")
}
func Test_backupper_BackupPodVolumes_log_test(t *testing.T) {
type args struct {
backup *velerov1api.Backup
pod *corev1api.Pod
volumesToBackup []string
resPolicies *resourcepolicies.Policies
}
tests := []struct {
name string
args args
wantLog string
}{
{
name: "backup pod volumes should log volume names",
args: args{
backup: &velerov1api.Backup{
ObjectMeta: metav1.ObjectMeta{
Name: "backup-1",
Namespace: "ns-1",
},
},
pod: &corev1api.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod-1",
Namespace: "ns-1",
},
Spec: corev1api.PodSpec{
Volumes: []corev1api.Volume{
{
Name: "vol-1",
},
{
Name: "vol-2",
},
},
},
},
volumesToBackup: []string{"vol-1", "vol-2"},
resPolicies: nil,
},
wantLog: "pod ns-1/pod-1 has volumes to backup: [vol-1 vol-2]",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b := &backupper{
ctx: context.Background(),
}
logOutput := bytes.Buffer{}
var log = logrus.New()
log.SetOutput(&logOutput)
b.BackupPodVolumes(tt.args.backup, tt.args.pod, tt.args.volumesToBackup, tt.args.resPolicies, log)
fmt.Println(logOutput.String())
assert.Contains(t, logOutput.String(), tt.wantLog)
})
}
}
+102 -24
View File
@@ -1,18 +1,4 @@
/*
Copyright 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.
*/
// Code generated by mockery v2.22.1. DO NOT EDIT.
package mocks
@@ -64,11 +50,39 @@ func (_m *RepositoryWriter) Close(ctx context.Context) error {
return r0
}
// ConcatenateObjects provides a mock function with given fields: ctx, objectIDs
func (_m *RepositoryWriter) ConcatenateObjects(ctx context.Context, objectIDs []object.ID) (object.ID, error) {
ret := _m.Called(ctx, objectIDs)
var r0 object.ID
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, []object.ID) (object.ID, error)); ok {
return rf(ctx, objectIDs)
}
if rf, ok := ret.Get(0).(func(context.Context, []object.ID) object.ID); ok {
r0 = rf(ctx, objectIDs)
} else {
r0 = ret.Get(0).(object.ID)
}
if rf, ok := ret.Get(1).(func(context.Context, []object.ID) error); ok {
r1 = rf(ctx, objectIDs)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// ContentInfo provides a mock function with given fields: ctx, contentID
func (_m *RepositoryWriter) ContentInfo(ctx context.Context, contentID index.ID) (index.Info, error) {
ret := _m.Called(ctx, contentID)
var r0 index.Info
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, index.ID) (index.Info, error)); ok {
return rf(ctx, contentID)
}
if rf, ok := ret.Get(0).(func(context.Context, index.ID) index.Info); ok {
r0 = rf(ctx, contentID)
} else {
@@ -77,7 +91,6 @@ func (_m *RepositoryWriter) ContentInfo(ctx context.Context, contentID index.ID)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, index.ID) error); ok {
r1 = rf(ctx, contentID)
} else {
@@ -106,6 +119,10 @@ func (_m *RepositoryWriter) FindManifests(ctx context.Context, labels map[string
ret := _m.Called(ctx, labels)
var r0 []*manifest.EntryMetadata
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, map[string]string) ([]*manifest.EntryMetadata, error)); ok {
return rf(ctx, labels)
}
if rf, ok := ret.Get(0).(func(context.Context, map[string]string) []*manifest.EntryMetadata); ok {
r0 = rf(ctx, labels)
} else {
@@ -114,7 +131,6 @@ func (_m *RepositoryWriter) FindManifests(ctx context.Context, labels map[string
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, map[string]string) error); ok {
r1 = rf(ctx, labels)
} else {
@@ -143,6 +159,10 @@ func (_m *RepositoryWriter) GetManifest(ctx context.Context, id manifest.ID, dat
ret := _m.Called(ctx, id, data)
var r0 *manifest.EntryMetadata
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, manifest.ID, interface{}) (*manifest.EntryMetadata, error)); ok {
return rf(ctx, id, data)
}
if rf, ok := ret.Get(0).(func(context.Context, manifest.ID, interface{}) *manifest.EntryMetadata); ok {
r0 = rf(ctx, id, data)
} else {
@@ -151,7 +171,6 @@ func (_m *RepositoryWriter) GetManifest(ctx context.Context, id manifest.ID, dat
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, manifest.ID, interface{}) error); ok {
r1 = rf(ctx, id, data)
} else {
@@ -182,6 +201,11 @@ func (_m *RepositoryWriter) NewWriter(ctx context.Context, opt repo.WriteSession
ret := _m.Called(ctx, opt)
var r0 context.Context
var r1 repo.RepositoryWriter
var r2 error
if rf, ok := ret.Get(0).(func(context.Context, repo.WriteSessionOptions) (context.Context, repo.RepositoryWriter, error)); ok {
return rf(ctx, opt)
}
if rf, ok := ret.Get(0).(func(context.Context, repo.WriteSessionOptions) context.Context); ok {
r0 = rf(ctx, opt)
} else {
@@ -190,7 +214,6 @@ func (_m *RepositoryWriter) NewWriter(ctx context.Context, opt repo.WriteSession
}
}
var r1 repo.RepositoryWriter
if rf, ok := ret.Get(1).(func(context.Context, repo.WriteSessionOptions) repo.RepositoryWriter); ok {
r1 = rf(ctx, opt)
} else {
@@ -199,7 +222,6 @@ func (_m *RepositoryWriter) NewWriter(ctx context.Context, opt repo.WriteSession
}
}
var r2 error
if rf, ok := ret.Get(2).(func(context.Context, repo.WriteSessionOptions) error); ok {
r2 = rf(ctx, opt)
} else {
@@ -209,11 +231,20 @@ func (_m *RepositoryWriter) NewWriter(ctx context.Context, opt repo.WriteSession
return r0, r1, r2
}
// OnSuccessfulFlush provides a mock function with given fields: callback
func (_m *RepositoryWriter) OnSuccessfulFlush(callback repo.RepositoryWriterCallback) {
_m.Called(callback)
}
// OpenObject provides a mock function with given fields: ctx, id
func (_m *RepositoryWriter) OpenObject(ctx context.Context, id object.ID) (object.Reader, error) {
ret := _m.Called(ctx, id)
var r0 object.Reader
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, object.ID) (object.Reader, error)); ok {
return rf(ctx, id)
}
if rf, ok := ret.Get(0).(func(context.Context, object.ID) object.Reader); ok {
r0 = rf(ctx, id)
} else {
@@ -222,7 +253,6 @@ func (_m *RepositoryWriter) OpenObject(ctx context.Context, id object.ID) (objec
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, object.ID) error); ok {
r1 = rf(ctx, id)
} else {
@@ -253,6 +283,10 @@ func (_m *RepositoryWriter) PrefetchObjects(ctx context.Context, objectIDs []obj
ret := _m.Called(ctx, objectIDs, hint)
var r0 []index.ID
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, []object.ID, string) ([]index.ID, error)); ok {
return rf(ctx, objectIDs, hint)
}
if rf, ok := ret.Get(0).(func(context.Context, []object.ID, string) []index.ID); ok {
r0 = rf(ctx, objectIDs, hint)
} else {
@@ -261,7 +295,6 @@ func (_m *RepositoryWriter) PrefetchObjects(ctx context.Context, objectIDs []obj
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, []object.ID, string) error); ok {
r1 = rf(ctx, objectIDs, hint)
} else {
@@ -276,13 +309,16 @@ func (_m *RepositoryWriter) PutManifest(ctx context.Context, labels map[string]s
ret := _m.Called(ctx, labels, payload)
var r0 manifest.ID
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, map[string]string, interface{}) (manifest.ID, error)); ok {
return rf(ctx, labels, payload)
}
if rf, ok := ret.Get(0).(func(context.Context, map[string]string, interface{}) manifest.ID); ok {
r0 = rf(ctx, labels, payload)
} else {
r0 = ret.Get(0).(manifest.ID)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, map[string]string, interface{}) error); ok {
r1 = rf(ctx, labels, payload)
} else {
@@ -306,6 +342,30 @@ func (_m *RepositoryWriter) Refresh(ctx context.Context) error {
return r0
}
// ReplaceManifests provides a mock function with given fields: ctx, labels, payload
func (_m *RepositoryWriter) ReplaceManifests(ctx context.Context, labels map[string]string, payload interface{}) (manifest.ID, error) {
ret := _m.Called(ctx, labels, payload)
var r0 manifest.ID
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, map[string]string, interface{}) (manifest.ID, error)); ok {
return rf(ctx, labels, payload)
}
if rf, ok := ret.Get(0).(func(context.Context, map[string]string, interface{}) manifest.ID); ok {
r0 = rf(ctx, labels, payload)
} else {
r0 = ret.Get(0).(manifest.ID)
}
if rf, ok := ret.Get(1).(func(context.Context, map[string]string, interface{}) error); ok {
r1 = rf(ctx, labels, payload)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Time provides a mock function with given fields:
func (_m *RepositoryWriter) Time() time.Time {
ret := _m.Called()
@@ -330,6 +390,10 @@ func (_m *RepositoryWriter) VerifyObject(ctx context.Context, id object.ID) ([]i
ret := _m.Called(ctx, id)
var r0 []index.ID
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, object.ID) ([]index.ID, error)); ok {
return rf(ctx, id)
}
if rf, ok := ret.Get(0).(func(context.Context, object.ID) []index.ID); ok {
r0 = rf(ctx, id)
} else {
@@ -338,7 +402,6 @@ func (_m *RepositoryWriter) VerifyObject(ctx context.Context, id object.ID) ([]i
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, object.ID) error); ok {
r1 = rf(ctx, id)
} else {
@@ -347,3 +410,18 @@ func (_m *RepositoryWriter) VerifyObject(ctx context.Context, id object.ID) ([]i
return r0, r1
}
type mockConstructorTestingTNewRepositoryWriter interface {
mock.TestingT
Cleanup(func())
}
// NewRepositoryWriter creates a new instance of RepositoryWriter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewRepositoryWriter(t mockConstructorTestingTNewRepositoryWriter) *RepositoryWriter {
mock := &RepositoryWriter{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}
+5
View File
@@ -18,6 +18,7 @@ package provider
import (
"context"
"encoding/base64"
"fmt"
"net/url"
"path"
@@ -496,6 +497,10 @@ func getStorageVariables(backupLocation *velerov1api.BackupStorageLocation, repo
result[udmrepo.StoreOptionS3Endpoint] = strings.Trim(s3URL, "/")
result[udmrepo.StoreOptionS3DisableTLSVerify] = config["insecureSkipTLSVerify"]
result[udmrepo.StoreOptionS3DisableTLS] = strconv.FormatBool(disableTLS)
if backupLocation.Spec.ObjectStorage != nil && backupLocation.Spec.ObjectStorage.CACert != nil {
result[udmrepo.StoreOptionS3CustomCA] = base64.StdEncoding.EncodeToString(backupLocation.Spec.ObjectStorage.CACert)
}
} else if backendType == repoconfig.AzureBackend {
domain, err := getAzureStorageDomain(config)
if err != nil {
@@ -18,6 +18,7 @@ package provider
import (
"context"
"encoding/base64"
"errors"
"testing"
@@ -366,6 +367,42 @@ func TestGetStorageVariables(t *testing.T) {
"skipTLSVerify": "false",
},
},
{
name: "aws, ObjectStorage section exists in BSL, s3Url exist, https, custom CA exist",
backupLocation: velerov1api.BackupStorageLocation{
Spec: velerov1api.BackupStorageLocationSpec{
Provider: "velero.io/aws",
Config: map[string]string{
"bucket": "fake-bucket-config",
"prefix": "fake-prefix-config",
"region": "fake-region",
"s3Url": "https://fake-url/",
"insecureSkipTLSVerify": "false",
},
StorageType: velerov1api.StorageType{
ObjectStorage: &velerov1api.ObjectStorageLocation{
Bucket: "fake-bucket-object-store",
Prefix: "fake-prefix-object-store",
CACert: []byte{0x01, 0x02, 0x03, 0x04, 0x05},
},
},
},
},
getS3BucketRegion: func(bucket string) (string, error) {
return "region from bucket: " + bucket, nil
},
repoBackend: "fake-repo-type",
expected: map[string]string{
"bucket": "fake-bucket-object-store",
"prefix": "fake-prefix-object-store/fake-repo-type/",
"region": "fake-region",
"fspath": "",
"endpoint": "fake-url",
"doNotUseTLS": "false",
"skipTLSVerify": "false",
"customCA": base64.StdEncoding.EncodeToString([]byte{0x01, 0x02, 0x03, 0x04, 0x05}),
},
},
{
name: "azure, getAzureStorageDomain fail",
backupLocation: velerov1api.BackupStorageLocation{
@@ -56,5 +56,5 @@ func (c *AzureBackend) Setup(ctx context.Context, flags map[string]string) error
}
func (c *AzureBackend) Connect(ctx context.Context, isCreate bool) (blob.Storage, error) {
return azure.New(ctx, &c.options)
return azure.New(ctx, &c.options, false)
}
@@ -25,8 +25,8 @@ import (
"github.com/kopia/kopia/repo/blob/throttling"
"github.com/kopia/kopia/repo/content"
"github.com/kopia/kopia/repo/encryption"
"github.com/kopia/kopia/repo/format"
"github.com/kopia/kopia/repo/hashing"
"github.com/kopia/kopia/repo/object"
"github.com/kopia/kopia/repo/splitter"
"github.com/vmware-tanzu/velero/pkg/repository/udmrepo"
@@ -51,12 +51,12 @@ func setupLimits(ctx context.Context, flags map[string]string) throttling.Limits
// SetupNewRepositoryOptions setups the options when creating a new Kopia repository
func SetupNewRepositoryOptions(ctx context.Context, flags map[string]string) repo.NewRepositoryOptions {
return repo.NewRepositoryOptions{
BlockFormat: content.FormattingOptions{
BlockFormat: format.ContentFormat{
Hash: optionalHaveStringWithDefault(udmrepo.StoreOptionGenHashAlgo, flags, hashing.DefaultAlgorithm),
Encryption: optionalHaveStringWithDefault(udmrepo.StoreOptionGenEncryptAlgo, flags, encryption.DefaultAlgorithm),
},
ObjectFormat: object.Format{
ObjectFormat: format.ObjectFormat{
Splitter: optionalHaveStringWithDefault(udmrepo.StoreOptionGenSplitAlgo, flags, splitter.DefaultAlgorithm),
},
@@ -50,5 +50,5 @@ func (c *GCSBackend) Setup(ctx context.Context, flags map[string]string) error {
}
func (c *GCSBackend) Connect(ctx context.Context, isCreate bool) (blob.Storage, error) {
return gcs.New(ctx, &c.options)
return gcs.New(ctx, &c.options, false)
}
@@ -1,4 +1,4 @@
// Code generated by mockery v2.14.0. DO NOT EDIT.
// Code generated by mockery v2.22.1. DO NOT EDIT.
package mocks
@@ -8,8 +8,12 @@ import (
context "context"
format "github.com/kopia/kopia/repo/format"
index "github.com/kopia/kopia/repo/content/index"
indexblob "github.com/kopia/kopia/repo/content/indexblob"
manifest "github.com/kopia/kopia/repo/manifest"
mock "github.com/stretchr/testify/mock"
@@ -44,20 +48,6 @@ func (_m *DirectRepository) AlsoLogToContentLog(ctx context.Context) context.Con
return r0
}
// BlobCfg provides a mock function with given fields:
func (_m *DirectRepository) BlobCfg() content.BlobCfgBlob {
ret := _m.Called()
var r0 content.BlobCfgBlob
if rf, ok := ret.Get(0).(func() content.BlobCfgBlob); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(content.BlobCfgBlob)
}
return r0
}
// BlobReader provides a mock function with given fields:
func (_m *DirectRepository) BlobReader() blob.Reader {
ret := _m.Called()
@@ -137,6 +127,10 @@ func (_m *DirectRepository) ContentInfo(ctx context.Context, contentID index.ID)
ret := _m.Called(ctx, contentID)
var r0 index.Info
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, index.ID) (index.Info, error)); ok {
return rf(ctx, contentID)
}
if rf, ok := ret.Get(0).(func(context.Context, index.ID) index.Info); ok {
r0 = rf(ctx, contentID)
} else {
@@ -145,7 +139,6 @@ func (_m *DirectRepository) ContentInfo(ctx context.Context, contentID index.ID)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, index.ID) error); ok {
r1 = rf(ctx, contentID)
} else {
@@ -171,22 +164,6 @@ func (_m *DirectRepository) ContentReader() content.Reader {
return r0
}
// Crypter provides a mock function with given fields:
func (_m *DirectRepository) Crypter() *content.Crypter {
ret := _m.Called()
var r0 *content.Crypter
if rf, ok := ret.Get(0).(func() *content.Crypter); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*content.Crypter)
}
}
return r0
}
// DeriveKey provides a mock function with given fields: purpose, keyLength
func (_m *DirectRepository) DeriveKey(purpose []byte, keyLength int) []byte {
ret := _m.Called(purpose, keyLength)
@@ -213,6 +190,10 @@ func (_m *DirectRepository) FindManifests(ctx context.Context, labels map[string
ret := _m.Called(ctx, labels)
var r0 []*manifest.EntryMetadata
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, map[string]string) ([]*manifest.EntryMetadata, error)); ok {
return rf(ctx, labels)
}
if rf, ok := ret.Get(0).(func(context.Context, map[string]string) []*manifest.EntryMetadata); ok {
r0 = rf(ctx, labels)
} else {
@@ -221,7 +202,6 @@ func (_m *DirectRepository) FindManifests(ctx context.Context, labels map[string
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, map[string]string) error); ok {
r1 = rf(ctx, labels)
} else {
@@ -231,11 +211,31 @@ func (_m *DirectRepository) FindManifests(ctx context.Context, labels map[string
return r0, r1
}
// FormatManager provides a mock function with given fields:
func (_m *DirectRepository) FormatManager() *format.Manager {
ret := _m.Called()
var r0 *format.Manager
if rf, ok := ret.Get(0).(func() *format.Manager); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*format.Manager)
}
}
return r0
}
// GetManifest provides a mock function with given fields: ctx, id, data
func (_m *DirectRepository) GetManifest(ctx context.Context, id manifest.ID, data interface{}) (*manifest.EntryMetadata, error) {
ret := _m.Called(ctx, id, data)
var r0 *manifest.EntryMetadata
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, manifest.ID, interface{}) (*manifest.EntryMetadata, error)); ok {
return rf(ctx, id, data)
}
if rf, ok := ret.Get(0).(func(context.Context, manifest.ID, interface{}) *manifest.EntryMetadata); ok {
r0 = rf(ctx, id, data)
} else {
@@ -244,7 +244,6 @@ func (_m *DirectRepository) GetManifest(ctx context.Context, id manifest.ID, dat
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, manifest.ID, interface{}) error); ok {
r1 = rf(ctx, id, data)
} else {
@@ -255,19 +254,22 @@ func (_m *DirectRepository) GetManifest(ctx context.Context, id manifest.ID, dat
}
// IndexBlobs provides a mock function with given fields: ctx, includeInactive
func (_m *DirectRepository) IndexBlobs(ctx context.Context, includeInactive bool) ([]content.IndexBlobInfo, error) {
func (_m *DirectRepository) IndexBlobs(ctx context.Context, includeInactive bool) ([]indexblob.Metadata, error) {
ret := _m.Called(ctx, includeInactive)
var r0 []content.IndexBlobInfo
if rf, ok := ret.Get(0).(func(context.Context, bool) []content.IndexBlobInfo); ok {
var r0 []indexblob.Metadata
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, bool) ([]indexblob.Metadata, error)); ok {
return rf(ctx, includeInactive)
}
if rf, ok := ret.Get(0).(func(context.Context, bool) []indexblob.Metadata); ok {
r0 = rf(ctx, includeInactive)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]content.IndexBlobInfo)
r0 = ret.Get(0).([]indexblob.Metadata)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, bool) error); ok {
r1 = rf(ctx, includeInactive)
} else {
@@ -282,6 +284,11 @@ func (_m *DirectRepository) NewDirectWriter(ctx context.Context, opt repo.WriteS
ret := _m.Called(ctx, opt)
var r0 context.Context
var r1 repo.DirectRepositoryWriter
var r2 error
if rf, ok := ret.Get(0).(func(context.Context, repo.WriteSessionOptions) (context.Context, repo.DirectRepositoryWriter, error)); ok {
return rf(ctx, opt)
}
if rf, ok := ret.Get(0).(func(context.Context, repo.WriteSessionOptions) context.Context); ok {
r0 = rf(ctx, opt)
} else {
@@ -290,7 +297,6 @@ func (_m *DirectRepository) NewDirectWriter(ctx context.Context, opt repo.WriteS
}
}
var r1 repo.DirectRepositoryWriter
if rf, ok := ret.Get(1).(func(context.Context, repo.WriteSessionOptions) repo.DirectRepositoryWriter); ok {
r1 = rf(ctx, opt)
} else {
@@ -299,7 +305,6 @@ func (_m *DirectRepository) NewDirectWriter(ctx context.Context, opt repo.WriteS
}
}
var r2 error
if rf, ok := ret.Get(2).(func(context.Context, repo.WriteSessionOptions) error); ok {
r2 = rf(ctx, opt)
} else {
@@ -314,6 +319,11 @@ func (_m *DirectRepository) NewWriter(ctx context.Context, opt repo.WriteSession
ret := _m.Called(ctx, opt)
var r0 context.Context
var r1 repo.RepositoryWriter
var r2 error
if rf, ok := ret.Get(0).(func(context.Context, repo.WriteSessionOptions) (context.Context, repo.RepositoryWriter, error)); ok {
return rf(ctx, opt)
}
if rf, ok := ret.Get(0).(func(context.Context, repo.WriteSessionOptions) context.Context); ok {
r0 = rf(ctx, opt)
} else {
@@ -322,7 +332,6 @@ func (_m *DirectRepository) NewWriter(ctx context.Context, opt repo.WriteSession
}
}
var r1 repo.RepositoryWriter
if rf, ok := ret.Get(1).(func(context.Context, repo.WriteSessionOptions) repo.RepositoryWriter); ok {
r1 = rf(ctx, opt)
} else {
@@ -331,7 +340,6 @@ func (_m *DirectRepository) NewWriter(ctx context.Context, opt repo.WriteSession
}
}
var r2 error
if rf, ok := ret.Get(2).(func(context.Context, repo.WriteSessionOptions) error); ok {
r2 = rf(ctx, opt)
} else {
@@ -342,14 +350,14 @@ func (_m *DirectRepository) NewWriter(ctx context.Context, opt repo.WriteSession
}
// ObjectFormat provides a mock function with given fields:
func (_m *DirectRepository) ObjectFormat() object.Format {
func (_m *DirectRepository) ObjectFormat() format.ObjectFormat {
ret := _m.Called()
var r0 object.Format
if rf, ok := ret.Get(0).(func() object.Format); ok {
var r0 format.ObjectFormat
if rf, ok := ret.Get(0).(func() format.ObjectFormat); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(object.Format)
r0 = ret.Get(0).(format.ObjectFormat)
}
return r0
@@ -360,6 +368,10 @@ func (_m *DirectRepository) OpenObject(ctx context.Context, id object.ID) (objec
ret := _m.Called(ctx, id)
var r0 object.Reader
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, object.ID) (object.Reader, error)); ok {
return rf(ctx, id)
}
if rf, ok := ret.Get(0).(func(context.Context, object.ID) object.Reader); ok {
r0 = rf(ctx, id)
} else {
@@ -368,7 +380,6 @@ func (_m *DirectRepository) OpenObject(ctx context.Context, id object.ID) (objec
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, object.ID) error); ok {
r1 = rf(ctx, id)
} else {
@@ -399,6 +410,10 @@ func (_m *DirectRepository) PrefetchObjects(ctx context.Context, objectIDs []obj
ret := _m.Called(ctx, objectIDs, hint)
var r0 []index.ID
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, []object.ID, string) ([]index.ID, error)); ok {
return rf(ctx, objectIDs, hint)
}
if rf, ok := ret.Get(0).(func(context.Context, []object.ID, string) []index.ID); ok {
r0 = rf(ctx, objectIDs, hint)
} else {
@@ -407,7 +422,6 @@ func (_m *DirectRepository) PrefetchObjects(ctx context.Context, objectIDs []obj
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, []object.ID, string) error); ok {
r1 = rf(ctx, objectIDs, hint)
} else {
@@ -466,13 +480,16 @@ func (_m *DirectRepository) Token(password string) (string, error) {
ret := _m.Called(password)
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func(string) (string, error)); ok {
return rf(password)
}
if rf, ok := ret.Get(0).(func(string) string); ok {
r0 = rf(password)
} else {
r0 = ret.Get(0).(string)
}
var r1 error
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(password)
} else {
@@ -508,6 +525,10 @@ func (_m *DirectRepository) VerifyObject(ctx context.Context, id object.ID) ([]i
ret := _m.Called(ctx, id)
var r0 []index.ID
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, object.ID) ([]index.ID, error)); ok {
return rf(ctx, id)
}
if rf, ok := ret.Get(0).(func(context.Context, object.ID) []index.ID); ok {
r0 = rf(ctx, id)
} else {
@@ -516,7 +537,6 @@ func (_m *DirectRepository) VerifyObject(ctx context.Context, id object.ID) ([]i
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, object.ID) error); ok {
r1 = rf(ctx, id)
} else {
@@ -1,4 +1,4 @@
// Code generated by mockery v2.14.0. DO NOT EDIT.
// Code generated by mockery v2.22.1. DO NOT EDIT.
package mocks
@@ -8,8 +8,12 @@ import (
context "context"
format "github.com/kopia/kopia/repo/format"
index "github.com/kopia/kopia/repo/content/index"
indexblob "github.com/kopia/kopia/repo/content/indexblob"
manifest "github.com/kopia/kopia/repo/manifest"
mock "github.com/stretchr/testify/mock"
@@ -44,20 +48,6 @@ func (_m *DirectRepositoryWriter) AlsoLogToContentLog(ctx context.Context) conte
return r0
}
// BlobCfg provides a mock function with given fields:
func (_m *DirectRepositoryWriter) BlobCfg() content.BlobCfgBlob {
ret := _m.Called()
var r0 content.BlobCfgBlob
if rf, ok := ret.Get(0).(func() content.BlobCfgBlob); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(content.BlobCfgBlob)
}
return r0
}
// BlobReader provides a mock function with given fields:
func (_m *DirectRepositoryWriter) BlobReader() blob.Reader {
ret := _m.Called()
@@ -106,20 +96,6 @@ func (_m *DirectRepositoryWriter) BlobVolume() blob.Volume {
return r0
}
// ChangePassword provides a mock function with given fields: ctx, newPassword
func (_m *DirectRepositoryWriter) ChangePassword(ctx context.Context, newPassword string) error {
ret := _m.Called(ctx, newPassword)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
r0 = rf(ctx, newPassword)
} else {
r0 = ret.Error(0)
}
return r0
}
// ClientOptions provides a mock function with given fields:
func (_m *DirectRepositoryWriter) ClientOptions() repo.ClientOptions {
ret := _m.Called()
@@ -148,18 +124,28 @@ func (_m *DirectRepositoryWriter) Close(ctx context.Context) error {
return r0
}
// CommitUpgrade provides a mock function with given fields: ctx
func (_m *DirectRepositoryWriter) CommitUpgrade(ctx context.Context) error {
ret := _m.Called(ctx)
// ConcatenateObjects provides a mock function with given fields: ctx, objectIDs
func (_m *DirectRepositoryWriter) ConcatenateObjects(ctx context.Context, objectIDs []object.ID) (object.ID, error) {
ret := _m.Called(ctx, objectIDs)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context) error); ok {
r0 = rf(ctx)
var r0 object.ID
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, []object.ID) (object.ID, error)); ok {
return rf(ctx, objectIDs)
}
if rf, ok := ret.Get(0).(func(context.Context, []object.ID) object.ID); ok {
r0 = rf(ctx, objectIDs)
} else {
r0 = ret.Error(0)
r0 = ret.Get(0).(object.ID)
}
return r0
if rf, ok := ret.Get(1).(func(context.Context, []object.ID) error); ok {
r1 = rf(ctx, objectIDs)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// ConfigFilename provides a mock function with given fields:
@@ -181,6 +167,10 @@ func (_m *DirectRepositoryWriter) ContentInfo(ctx context.Context, contentID ind
ret := _m.Called(ctx, contentID)
var r0 index.Info
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, index.ID) (index.Info, error)); ok {
return rf(ctx, contentID)
}
if rf, ok := ret.Get(0).(func(context.Context, index.ID) index.Info); ok {
r0 = rf(ctx, contentID)
} else {
@@ -189,7 +179,6 @@ func (_m *DirectRepositoryWriter) ContentInfo(ctx context.Context, contentID ind
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, index.ID) error); ok {
r1 = rf(ctx, contentID)
} else {
@@ -231,22 +220,6 @@ func (_m *DirectRepositoryWriter) ContentReader() content.Reader {
return r0
}
// Crypter provides a mock function with given fields:
func (_m *DirectRepositoryWriter) Crypter() *content.Crypter {
ret := _m.Called()
var r0 *content.Crypter
if rf, ok := ret.Get(0).(func() *content.Crypter); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*content.Crypter)
}
}
return r0
}
// DeleteManifest provides a mock function with given fields: ctx, id
func (_m *DirectRepositoryWriter) DeleteManifest(ctx context.Context, id manifest.ID) error {
ret := _m.Called(ctx, id)
@@ -287,6 +260,10 @@ func (_m *DirectRepositoryWriter) FindManifests(ctx context.Context, labels map[
ret := _m.Called(ctx, labels)
var r0 []*manifest.EntryMetadata
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, map[string]string) ([]*manifest.EntryMetadata, error)); ok {
return rf(ctx, labels)
}
if rf, ok := ret.Get(0).(func(context.Context, map[string]string) []*manifest.EntryMetadata); ok {
r0 = rf(ctx, labels)
} else {
@@ -295,7 +272,6 @@ func (_m *DirectRepositoryWriter) FindManifests(ctx context.Context, labels map[
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, map[string]string) error); ok {
r1 = rf(ctx, labels)
} else {
@@ -319,11 +295,31 @@ func (_m *DirectRepositoryWriter) Flush(ctx context.Context) error {
return r0
}
// FormatManager provides a mock function with given fields:
func (_m *DirectRepositoryWriter) FormatManager() *format.Manager {
ret := _m.Called()
var r0 *format.Manager
if rf, ok := ret.Get(0).(func() *format.Manager); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*format.Manager)
}
}
return r0
}
// GetManifest provides a mock function with given fields: ctx, id, data
func (_m *DirectRepositoryWriter) GetManifest(ctx context.Context, id manifest.ID, data interface{}) (*manifest.EntryMetadata, error) {
ret := _m.Called(ctx, id, data)
var r0 *manifest.EntryMetadata
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, manifest.ID, interface{}) (*manifest.EntryMetadata, error)); ok {
return rf(ctx, id, data)
}
if rf, ok := ret.Get(0).(func(context.Context, manifest.ID, interface{}) *manifest.EntryMetadata); ok {
r0 = rf(ctx, id, data)
} else {
@@ -332,7 +328,6 @@ func (_m *DirectRepositoryWriter) GetManifest(ctx context.Context, id manifest.I
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, manifest.ID, interface{}) error); ok {
r1 = rf(ctx, id, data)
} else {
@@ -343,19 +338,22 @@ func (_m *DirectRepositoryWriter) GetManifest(ctx context.Context, id manifest.I
}
// IndexBlobs provides a mock function with given fields: ctx, includeInactive
func (_m *DirectRepositoryWriter) IndexBlobs(ctx context.Context, includeInactive bool) ([]content.IndexBlobInfo, error) {
func (_m *DirectRepositoryWriter) IndexBlobs(ctx context.Context, includeInactive bool) ([]indexblob.Metadata, error) {
ret := _m.Called(ctx, includeInactive)
var r0 []content.IndexBlobInfo
if rf, ok := ret.Get(0).(func(context.Context, bool) []content.IndexBlobInfo); ok {
var r0 []indexblob.Metadata
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, bool) ([]indexblob.Metadata, error)); ok {
return rf(ctx, includeInactive)
}
if rf, ok := ret.Get(0).(func(context.Context, bool) []indexblob.Metadata); ok {
r0 = rf(ctx, includeInactive)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]content.IndexBlobInfo)
r0 = ret.Get(0).([]indexblob.Metadata)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, bool) error); ok {
r1 = rf(ctx, includeInactive)
} else {
@@ -370,6 +368,11 @@ func (_m *DirectRepositoryWriter) NewDirectWriter(ctx context.Context, opt repo.
ret := _m.Called(ctx, opt)
var r0 context.Context
var r1 repo.DirectRepositoryWriter
var r2 error
if rf, ok := ret.Get(0).(func(context.Context, repo.WriteSessionOptions) (context.Context, repo.DirectRepositoryWriter, error)); ok {
return rf(ctx, opt)
}
if rf, ok := ret.Get(0).(func(context.Context, repo.WriteSessionOptions) context.Context); ok {
r0 = rf(ctx, opt)
} else {
@@ -378,7 +381,6 @@ func (_m *DirectRepositoryWriter) NewDirectWriter(ctx context.Context, opt repo.
}
}
var r1 repo.DirectRepositoryWriter
if rf, ok := ret.Get(1).(func(context.Context, repo.WriteSessionOptions) repo.DirectRepositoryWriter); ok {
r1 = rf(ctx, opt)
} else {
@@ -387,7 +389,6 @@ func (_m *DirectRepositoryWriter) NewDirectWriter(ctx context.Context, opt repo.
}
}
var r2 error
if rf, ok := ret.Get(2).(func(context.Context, repo.WriteSessionOptions) error); ok {
r2 = rf(ctx, opt)
} else {
@@ -418,6 +419,11 @@ func (_m *DirectRepositoryWriter) NewWriter(ctx context.Context, opt repo.WriteS
ret := _m.Called(ctx, opt)
var r0 context.Context
var r1 repo.RepositoryWriter
var r2 error
if rf, ok := ret.Get(0).(func(context.Context, repo.WriteSessionOptions) (context.Context, repo.RepositoryWriter, error)); ok {
return rf(ctx, opt)
}
if rf, ok := ret.Get(0).(func(context.Context, repo.WriteSessionOptions) context.Context); ok {
r0 = rf(ctx, opt)
} else {
@@ -426,7 +432,6 @@ func (_m *DirectRepositoryWriter) NewWriter(ctx context.Context, opt repo.WriteS
}
}
var r1 repo.RepositoryWriter
if rf, ok := ret.Get(1).(func(context.Context, repo.WriteSessionOptions) repo.RepositoryWriter); ok {
r1 = rf(ctx, opt)
} else {
@@ -435,7 +440,6 @@ func (_m *DirectRepositoryWriter) NewWriter(ctx context.Context, opt repo.WriteS
}
}
var r2 error
if rf, ok := ret.Get(2).(func(context.Context, repo.WriteSessionOptions) error); ok {
r2 = rf(ctx, opt)
} else {
@@ -446,24 +450,33 @@ func (_m *DirectRepositoryWriter) NewWriter(ctx context.Context, opt repo.WriteS
}
// ObjectFormat provides a mock function with given fields:
func (_m *DirectRepositoryWriter) ObjectFormat() object.Format {
func (_m *DirectRepositoryWriter) ObjectFormat() format.ObjectFormat {
ret := _m.Called()
var r0 object.Format
if rf, ok := ret.Get(0).(func() object.Format); ok {
var r0 format.ObjectFormat
if rf, ok := ret.Get(0).(func() format.ObjectFormat); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(object.Format)
r0 = ret.Get(0).(format.ObjectFormat)
}
return r0
}
// OnSuccessfulFlush provides a mock function with given fields: callback
func (_m *DirectRepositoryWriter) OnSuccessfulFlush(callback repo.RepositoryWriterCallback) {
_m.Called(callback)
}
// OpenObject provides a mock function with given fields: ctx, id
func (_m *DirectRepositoryWriter) OpenObject(ctx context.Context, id object.ID) (object.Reader, error) {
ret := _m.Called(ctx, id)
var r0 object.Reader
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, object.ID) (object.Reader, error)); ok {
return rf(ctx, id)
}
if rf, ok := ret.Get(0).(func(context.Context, object.ID) object.Reader); ok {
r0 = rf(ctx, id)
} else {
@@ -472,7 +485,6 @@ func (_m *DirectRepositoryWriter) OpenObject(ctx context.Context, id object.ID)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, object.ID) error); ok {
r1 = rf(ctx, id)
} else {
@@ -503,6 +515,10 @@ func (_m *DirectRepositoryWriter) PrefetchObjects(ctx context.Context, objectIDs
ret := _m.Called(ctx, objectIDs, hint)
var r0 []index.ID
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, []object.ID, string) ([]index.ID, error)); ok {
return rf(ctx, objectIDs, hint)
}
if rf, ok := ret.Get(0).(func(context.Context, []object.ID, string) []index.ID); ok {
r0 = rf(ctx, objectIDs, hint)
} else {
@@ -511,7 +527,6 @@ func (_m *DirectRepositoryWriter) PrefetchObjects(ctx context.Context, objectIDs
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, []object.ID, string) error); ok {
r1 = rf(ctx, objectIDs, hint)
} else {
@@ -526,13 +541,16 @@ func (_m *DirectRepositoryWriter) PutManifest(ctx context.Context, labels map[st
ret := _m.Called(ctx, labels, payload)
var r0 manifest.ID
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, map[string]string, interface{}) (manifest.ID, error)); ok {
return rf(ctx, labels, payload)
}
if rf, ok := ret.Get(0).(func(context.Context, map[string]string, interface{}) manifest.ID); ok {
r0 = rf(ctx, labels, payload)
} else {
r0 = ret.Get(0).(manifest.ID)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, map[string]string, interface{}) error); ok {
r1 = rf(ctx, labels, payload)
} else {
@@ -556,50 +574,23 @@ func (_m *DirectRepositoryWriter) Refresh(ctx context.Context) error {
return r0
}
// RollbackUpgrade provides a mock function with given fields: ctx
func (_m *DirectRepositoryWriter) RollbackUpgrade(ctx context.Context) error {
ret := _m.Called(ctx)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context) error); ok {
r0 = rf(ctx)
} else {
r0 = ret.Error(0)
}
return r0
}
// SetParameters provides a mock function with given fields: ctx, m, blobcfg
func (_m *DirectRepositoryWriter) SetParameters(ctx context.Context, m content.MutableParameters, blobcfg content.BlobCfgBlob) error {
ret := _m.Called(ctx, m, blobcfg)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, content.MutableParameters, content.BlobCfgBlob) error); ok {
r0 = rf(ctx, m, blobcfg)
} else {
r0 = ret.Error(0)
}
return r0
}
// SetUpgradeLockIntent provides a mock function with given fields: ctx, l
func (_m *DirectRepositoryWriter) SetUpgradeLockIntent(ctx context.Context, l content.UpgradeLock) (*content.UpgradeLock, error) {
ret := _m.Called(ctx, l)
var r0 *content.UpgradeLock
if rf, ok := ret.Get(0).(func(context.Context, content.UpgradeLock) *content.UpgradeLock); ok {
r0 = rf(ctx, l)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*content.UpgradeLock)
}
}
// ReplaceManifests provides a mock function with given fields: ctx, labels, payload
func (_m *DirectRepositoryWriter) ReplaceManifests(ctx context.Context, labels map[string]string, payload interface{}) (manifest.ID, error) {
ret := _m.Called(ctx, labels, payload)
var r0 manifest.ID
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, content.UpgradeLock) error); ok {
r1 = rf(ctx, l)
if rf, ok := ret.Get(0).(func(context.Context, map[string]string, interface{}) (manifest.ID, error)); ok {
return rf(ctx, labels, payload)
}
if rf, ok := ret.Get(0).(func(context.Context, map[string]string, interface{}) manifest.ID); ok {
r0 = rf(ctx, labels, payload)
} else {
r0 = ret.Get(0).(manifest.ID)
}
if rf, ok := ret.Get(1).(func(context.Context, map[string]string, interface{}) error); ok {
r1 = rf(ctx, labels, payload)
} else {
r1 = ret.Error(1)
}
@@ -642,13 +633,16 @@ func (_m *DirectRepositoryWriter) Token(password string) (string, error) {
ret := _m.Called(password)
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func(string) (string, error)); ok {
return rf(password)
}
if rf, ok := ret.Get(0).(func(string) string); ok {
r0 = rf(password)
} else {
r0 = ret.Get(0).(string)
}
var r1 error
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(password)
} else {
@@ -684,6 +678,10 @@ func (_m *DirectRepositoryWriter) VerifyObject(ctx context.Context, id object.ID
ret := _m.Called(ctx, id)
var r0 []index.ID
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, object.ID) ([]index.ID, error)); ok {
return rf(ctx, id)
}
if rf, ok := ret.Get(0).(func(context.Context, object.ID) []index.ID); ok {
r0 = rf(ctx, id)
} else {
@@ -692,7 +690,6 @@ func (_m *DirectRepositoryWriter) VerifyObject(ctx context.Context, id object.ID
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, object.ID) error); ok {
r1 = rf(ctx, id)
} else {
@@ -1,62 +1,99 @@
// Code generated by mockery v2.14.0. DO NOT EDIT.
// Code generated by mockery v2.22.1. DO NOT EDIT.
package mocks
import mock "github.com/stretchr/testify/mock"
import (
mock "github.com/stretchr/testify/mock"
zapcore "go.uber.org/zap/zapcore"
)
// Logger is an autogenerated mock type for the Logger type
type Logger struct {
// Core is an autogenerated mock type for the Core type
type Core struct {
mock.Mock
}
// Debugf provides a mock function with given fields: msg, args
func (_m *Logger) Debugf(msg string, args ...interface{}) {
var _ca []interface{}
_ca = append(_ca, msg)
_ca = append(_ca, args...)
_m.Called(_ca...)
// Check provides a mock function with given fields: _a0, _a1
func (_m *Core) Check(_a0 zapcore.Entry, _a1 *zapcore.CheckedEntry) *zapcore.CheckedEntry {
ret := _m.Called(_a0, _a1)
var r0 *zapcore.CheckedEntry
if rf, ok := ret.Get(0).(func(zapcore.Entry, *zapcore.CheckedEntry) *zapcore.CheckedEntry); ok {
r0 = rf(_a0, _a1)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*zapcore.CheckedEntry)
}
}
return r0
}
// Debugw provides a mock function with given fields: msg, keyValuePairs
func (_m *Logger) Debugw(msg string, keyValuePairs ...interface{}) {
var _ca []interface{}
_ca = append(_ca, msg)
_ca = append(_ca, keyValuePairs...)
_m.Called(_ca...)
// Enabled provides a mock function with given fields: _a0
func (_m *Core) Enabled(_a0 zapcore.Level) bool {
ret := _m.Called(_a0)
var r0 bool
if rf, ok := ret.Get(0).(func(zapcore.Level) bool); ok {
r0 = rf(_a0)
} else {
r0 = ret.Get(0).(bool)
}
return r0
}
// Errorf provides a mock function with given fields: msg, args
func (_m *Logger) Errorf(msg string, args ...interface{}) {
var _ca []interface{}
_ca = append(_ca, msg)
_ca = append(_ca, args...)
_m.Called(_ca...)
// Sync provides a mock function with given fields:
func (_m *Core) Sync() error {
ret := _m.Called()
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
} else {
r0 = ret.Error(0)
}
return r0
}
// Infof provides a mock function with given fields: msg, args
func (_m *Logger) Infof(msg string, args ...interface{}) {
var _ca []interface{}
_ca = append(_ca, msg)
_ca = append(_ca, args...)
_m.Called(_ca...)
// With provides a mock function with given fields: _a0
func (_m *Core) With(_a0 []zapcore.Field) zapcore.Core {
ret := _m.Called(_a0)
var r0 zapcore.Core
if rf, ok := ret.Get(0).(func([]zapcore.Field) zapcore.Core); ok {
r0 = rf(_a0)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(zapcore.Core)
}
}
return r0
}
// Warnf provides a mock function with given fields: msg, args
func (_m *Logger) Warnf(msg string, args ...interface{}) {
var _ca []interface{}
_ca = append(_ca, msg)
_ca = append(_ca, args...)
_m.Called(_ca...)
// Write provides a mock function with given fields: _a0, _a1
func (_m *Core) Write(_a0 zapcore.Entry, _a1 []zapcore.Field) error {
ret := _m.Called(_a0, _a1)
var r0 error
if rf, ok := ret.Get(0).(func(zapcore.Entry, []zapcore.Field) error); ok {
r0 = rf(_a0, _a1)
} else {
r0 = ret.Error(0)
}
return r0
}
type mockConstructorTestingTNewLogger interface {
type mockConstructorTestingTNewCore interface {
mock.TestingT
Cleanup(func())
}
// NewLogger creates a new instance of Logger. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewLogger(t mockConstructorTestingTNewLogger) *Logger {
mock := &Logger{}
// NewCore creates a new instance of Core. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewCore(t mockConstructorTestingTNewCore) *Core {
mock := &Core{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
@@ -52,6 +52,7 @@ func (c *S3Backend) Setup(ctx context.Context, flags map[string]string) error {
c.options.DoNotUseTLS = optionalHaveBool(ctx, udmrepo.StoreOptionS3DisableTLS, flags)
c.options.DoNotVerifyTLS = optionalHaveBool(ctx, udmrepo.StoreOptionS3DisableTLSVerify, flags)
c.options.SessionToken = optionalHaveString(udmrepo.StoreOptionS3Token, flags)
c.options.RootCA = optionalHaveBase64(ctx, udmrepo.StoreOptionS3CustomCA, flags)
c.options.Limits = setupLimits(ctx, flags)
@@ -59,5 +60,5 @@ func (c *S3Backend) Setup(ctx context.Context, flags map[string]string) error {
}
func (c *S3Backend) Connect(ctx context.Context, isCreate bool) (blob.Storage, error) {
return s3.New(ctx, &c.options)
return s3.New(ctx, &c.options, false)
}
@@ -18,6 +18,7 @@ package backend
import (
"context"
"encoding/base64"
"strconv"
"time"
@@ -84,6 +85,19 @@ func optionalHaveDuration(ctx context.Context, key string, flags map[string]stri
return 0
}
func optionalHaveBase64(ctx context.Context, key string, flags map[string]string) []byte {
if value, exist := flags[key]; exist {
ret, err := base64.StdEncoding.DecodeString(value)
if err == nil {
return ret
}
backendLog()(ctx).Errorf("Ignore %s, value [%s] is invalid, err %v", key, value, err)
}
return nil
}
func backendLog() func(ctx context.Context) logging.Logger {
return logging.Module("kopialib-bd")
}
@@ -18,12 +18,13 @@ package backend
import (
"context"
"fmt"
"testing"
"github.com/kopia/kopia/repo/logging"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
storagemocks "github.com/vmware-tanzu/velero/pkg/repository/udmrepo/kopialib/backend/mocks"
)
@@ -31,13 +32,13 @@ import (
func TestOptionalHaveBool(t *testing.T) {
var expectMsg string
testCases := []struct {
name string
key string
flags map[string]string
logger *storagemocks.Logger
retFuncErrorf func(mock.Arguments)
expectMsg string
retValue bool
name string
key string
flags map[string]string
logger *storagemocks.Core
retFuncCheck func(mock.Arguments)
expectMsg string
retValue bool
}{
{
name: "key not exist",
@@ -59,9 +60,12 @@ func TestOptionalHaveBool(t *testing.T) {
flags: map[string]string{
"fake-key": "fake-value",
},
logger: new(storagemocks.Logger),
retFuncErrorf: func(args mock.Arguments) {
expectMsg = fmt.Sprintf(args[0].(string), args[1].(string), args[2].(string), args[3].(error))
logger: new(storagemocks.Core),
retFuncCheck: func(args mock.Arguments) {
ent := args[0].(zapcore.Entry)
if ent.Level == zapcore.ErrorLevel {
expectMsg = ent.Message
}
},
expectMsg: "Ignore fake-key, value [fake-value] is invalid, err strconv.ParseBool: parsing \"fake-value\": invalid syntax",
retValue: false,
@@ -71,11 +75,12 @@ func TestOptionalHaveBool(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
if tc.logger != nil {
tc.logger.On("Errorf", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Run(tc.retFuncErrorf)
tc.logger.On("Enabled", mock.Anything).Return(true)
tc.logger.On("Check", mock.Anything, mock.Anything).Run(tc.retFuncCheck).Return(&zapcore.CheckedEntry{})
}
ctx := logging.WithLogger(context.Background(), func(module string) logging.Logger {
return tc.logger
return zap.New(tc.logger).Sugar()
})
retValue := optionalHaveBool(ctx, tc.key, tc.flags)
+10 -11
View File
@@ -19,7 +19,6 @@ package kopialib
import (
"context"
"os"
"runtime"
"strings"
"sync/atomic"
"time"
@@ -234,7 +233,12 @@ func (kr *kopiaRepository) OpenObject(ctx context.Context, id udmrepo.ID) (udmre
return nil, errors.New("repo is closed or not open")
}
reader, err := kr.rawRepo.OpenObject(logging.SetupKopiaLog(ctx, kr.logger), object.ID(id))
objID, err := object.ParseID(string(id))
if err != nil {
return nil, errors.Wrapf(err, "error to parse object ID from %v", id)
}
reader, err := kr.rawRepo.OpenObject(logging.SetupKopiaLog(ctx, kr.logger), objID)
if err != nil {
return nil, errors.Wrap(err, "error to open object")
}
@@ -309,8 +313,8 @@ func (kr *kopiaRepository) NewObjectWriter(ctx context.Context, opt udmrepo.Obje
writer := kr.rawWriter.NewObjectWriter(logging.SetupKopiaLog(ctx, kr.logger), object.WriterOptions{
Description: opt.Description,
Prefix: index.ID(opt.Prefix),
AsyncWrites: getAsyncWrites(),
Prefix: index.IDPrefix(opt.Prefix),
AsyncWrites: opt.AsyncWrites,
Compressor: getCompressorForObject(opt),
})
@@ -438,7 +442,7 @@ func (kow *kopiaObjectWriter) Checkpoint() (udmrepo.ID, error) {
return udmrepo.ID(""), errors.Wrap(err, "error to checkpoint object")
}
return udmrepo.ID(id), nil
return udmrepo.ID(id.String()), nil
}
func (kow *kopiaObjectWriter) Result() (udmrepo.ID, error) {
@@ -451,7 +455,7 @@ func (kow *kopiaObjectWriter) Result() (udmrepo.ID, error) {
return udmrepo.ID(""), errors.Wrap(err, "error to wait object")
}
return udmrepo.ID(id), nil
return udmrepo.ID(id.String()), nil
}
func (kow *kopiaObjectWriter) Close() error {
@@ -469,11 +473,6 @@ func (kow *kopiaObjectWriter) Close() error {
return nil
}
// getAsyncWrites returns the number of concurrent async writes
func getAsyncWrites() int {
return runtime.NumCPU()
}
// getCompressorForObject returns the compressor for an object, at present, we don't support compression
func getCompressorForObject(opt udmrepo.ObjectWriteOptions) compression.Name {
return ""
@@ -23,6 +23,7 @@ import (
"time"
"github.com/kopia/kopia/repo"
"github.com/kopia/kopia/repo/manifest"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
@@ -262,14 +263,14 @@ func TestMaintain(t *testing.T) {
func TestWriteInitParameters(t *testing.T) {
var directRpo *repomocks.DirectRepository
testCases := []struct {
name string
repoOptions udmrepo.RepoOptions
returnRepo *repomocks.DirectRepository
returnRepoWriter *repomocks.DirectRepositoryWriter
repoOpen func(context.Context, string, string, *repo.Options) (repo.Repository, error)
newRepoWriterError error
findManifestError error
expectedErr string
name string
repoOptions udmrepo.RepoOptions
returnRepo *repomocks.DirectRepository
returnRepoWriter *repomocks.DirectRepositoryWriter
repoOpen func(context.Context, string, string, *repo.Options) (repo.Repository, error)
newRepoWriterError error
replaceManifestError error
expectedErr string
}{
{
name: "repo open fail, repo not exist",
@@ -315,10 +316,10 @@ func TestWriteInitParameters(t *testing.T) {
repoOpen: func(context.Context, string, string, *repo.Options) (repo.Repository, error) {
return directRpo, nil
},
returnRepo: new(repomocks.DirectRepository),
returnRepoWriter: new(repomocks.DirectRepositoryWriter),
findManifestError: errors.New("fake-find-manifest-error"),
expectedErr: "error to init write repo parameters: error to set maintenance params: error looking for maintenance manifest: fake-find-manifest-error",
returnRepo: new(repomocks.DirectRepository),
returnRepoWriter: new(repomocks.DirectRepositoryWriter),
replaceManifestError: errors.New("fake-replace-manifest-error"),
expectedErr: "error to init write repo parameters: error to set maintenance params: put manifest: fake-replace-manifest-error",
},
}
@@ -343,7 +344,7 @@ func TestWriteInitParameters(t *testing.T) {
if tc.returnRepoWriter != nil {
tc.returnRepoWriter.On("Close", mock.Anything).Return(nil)
tc.returnRepoWriter.On("FindManifests", mock.Anything, mock.Anything).Return(nil, tc.findManifestError)
tc.returnRepoWriter.On("ReplaceManifests", mock.Anything, mock.Anything, mock.Anything).Return(manifest.ID(""), tc.replaceManifestError)
}
err := writeInitParameters(ctx, tc.repoOptions, logger)
+1
View File
@@ -68,6 +68,7 @@ type ObjectWriteOptions struct {
Prefix ID // A prefix of the name used to save the object
AccessMode int // OBJECT_DATA_ACCESS_*
BackupMode int // OBJECT_DATA_BACKUP_*
AsyncWrites int // Num of async writes for the object, 0 means no async write
}
// BackupRepoService is used to initialize, open or maintain a backup repository
+1
View File
@@ -42,6 +42,7 @@ const (
StoreOptionS3Endpoint = "endpoint"
StoreOptionS3DisableTLS = "doNotUseTLS"
StoreOptionS3DisableTLSVerify = "skipTLSVerify"
StoreOptionS3CustomCA = "customCA"
StoreOptionAzureKey = "storageKey"
StoreOptionAzureDomain = "storageDomain"
+6 -6
View File
@@ -55,7 +55,7 @@ func TestChangeImageRepositoryActionExecute(t *testing.T) {
Image: "1.1.1.1:5000/abc:test",
}).Result(),
configMap: builder.ForConfigMap("velero", "change-image-name").
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-image-name", "RestoreItemAction")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-image-name", "RestoreItemAction")).
Data("case1", "1.1.1.1:5000 , 2.2.2.2:3000").
Result(),
freshedImageName: "2.2.2.2:3000/abc:test",
@@ -70,7 +70,7 @@ func TestChangeImageRepositoryActionExecute(t *testing.T) {
Image: "1.1.1.1:5000/abc:test",
}).Result(),
configMap: builder.ForConfigMap("velero", "change-image-name").
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-image-name", "RestoreItemAction")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-image-name", "RestoreItemAction")).
Data("specific", "1.1.1.1:5000,2.2.2.2:3000").
Result(),
freshedImageName: "2.2.2.2:3000/abc:test",
@@ -85,7 +85,7 @@ func TestChangeImageRepositoryActionExecute(t *testing.T) {
Image: "1.1.1.1:5000/abc:test",
}).Result(),
configMap: builder.ForConfigMap("velero", "change-image-name").
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-image-name", "RestoreItemAction")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-image-name", "RestoreItemAction")).
Data("specific", "abc:test,myproject:latest").
Result(),
freshedImageName: "1.1.1.1:5000/myproject:latest",
@@ -100,7 +100,7 @@ func TestChangeImageRepositoryActionExecute(t *testing.T) {
Image: "1.1.1.1:5000/abc:test",
}).Result(),
configMap: builder.ForConfigMap("velero", "change-image-name").
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-image-name", "RestoreItemAction")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-image-name", "RestoreItemAction")).
Data("specific", "5000,3333").
Result(),
freshedImageName: "1.1.1.1:5000/abc:test",
@@ -115,7 +115,7 @@ func TestChangeImageRepositoryActionExecute(t *testing.T) {
Image: "1.1.1.1:5000/abc:test",
}).Result(),
configMap: builder.ForConfigMap("velero", "change-image-name").
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-image-name", "RestoreItemAction")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-image-name", "RestoreItemAction")).
Data("specific", "test,latest").
Result(),
freshedImageName: "1.1.1.1:5000/abc:test",
@@ -130,7 +130,7 @@ func TestChangeImageRepositoryActionExecute(t *testing.T) {
Image: "dev/image1:dev",
}).Result(),
configMap: builder.ForConfigMap("velero", "change-image-name").
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-image-name", "RestoreItemAction")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-image-name", "RestoreItemAction")).
Data("specific", "dev/,test/").
Result(),
freshedImageName: "dev/image1:dev",
+1 -1
View File
@@ -140,7 +140,7 @@ func (p *ChangePVCNodeSelectorAction) Execute(input *velero.RestoreItemActionExe
func getNewNodeFromConfigMap(client corev1client.ConfigMapInterface, node string) (string, error) {
// fetch node mapping from configMap
config, err := getPluginConfig(common.PluginKindRestoreItemAction, "velero.io/change-pvc-node-selector", client)
config, err := common.GetPluginConfig(common.PluginKindRestoreItemAction, "velero.io/change-pvc-node-selector", client)
if err != nil {
return "", err
}
+6 -6
View File
@@ -57,7 +57,7 @@ func TestChangePVCNodeSelectorActionExecute(t *testing.T) {
builder.WithAnnotations("volume.kubernetes.io/selected-node", "source-node"),
).Result(),
configMap: builder.ForConfigMap("velero", "change-pvc-node").
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-pvc-node-selector", "RestoreItemAction")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-pvc-node-selector", "RestoreItemAction")).
Data("source-node", "dest-node").
Result(),
newNode: builder.ForNode("dest-node").Result(),
@@ -73,7 +73,7 @@ func TestChangePVCNodeSelectorActionExecute(t *testing.T) {
builder.WithAnnotations("volume.kubernetes.io/selected-node", "source-node"),
).Result(),
configMap: builder.ForConfigMap("velero", "change-pvc-node").
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/some-other-plugin", "RestoreItemAction")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/some-other-plugin", "RestoreItemAction")).
Data("source-noed", "dest-node").
Result(),
want: builder.ForPersistentVolumeClaim("source-ns", "pvc-1").Result(),
@@ -85,7 +85,7 @@ func TestChangePVCNodeSelectorActionExecute(t *testing.T) {
builder.WithAnnotations("volume.kubernetes.io/selected-node", "source-node"),
).Result(),
configMap: builder.ForConfigMap("velero", "change-pvc-node").
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-pvc-node-selector", "RestoreItemAction")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-pvc-node-selector", "RestoreItemAction")).
Result(),
want: builder.ForPersistentVolumeClaim("source-ns", "pvc-1").Result(),
},
@@ -96,7 +96,7 @@ func TestChangePVCNodeSelectorActionExecute(t *testing.T) {
builder.WithAnnotations("volume.kubernetes.io/selected-node", "source-node"),
).Result(),
configMap: builder.ForConfigMap("velero", "change-pvc-node").
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-pvc-node-selector", "RestoreItemAction")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-pvc-node-selector", "RestoreItemAction")).
Result(),
// MAYANK TODO
node: builder.ForNode("source-node").Result(),
@@ -109,7 +109,7 @@ func TestChangePVCNodeSelectorActionExecute(t *testing.T) {
name: "when persistent volume claim has no node selector, the item is returned as-is",
pvc: builder.ForPersistentVolumeClaim("source-ns", "pvc-1").Result(),
configMap: builder.ForConfigMap("velero", "change-pvc-node").
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-pvc-node-selector", "RestoreItemAction")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-pvc-node-selector", "RestoreItemAction")).
Data("source-node", "dest-node").
Result(),
want: builder.ForPersistentVolumeClaim("source-ns", "pvc-1").Result(),
@@ -121,7 +121,7 @@ func TestChangePVCNodeSelectorActionExecute(t *testing.T) {
builder.WithAnnotations("volume.kubernetes.io/selected-node", "source-node"),
).Result(),
configMap: builder.ForConfigMap("velero", "change-pvc-node").
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-pvc-node-selector", "RestoreItemAction")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-pvc-node-selector", "RestoreItemAction")).
Data("source-node-1", "dest-node").
Result(),
want: builder.ForPersistentVolumeClaim("source-ns", "pvc-1").Result(),
+1 -1
View File
@@ -69,7 +69,7 @@ func (a *ChangeStorageClassAction) Execute(input *velero.RestoreItemActionExecut
defer a.logger.Info("Done executing ChangeStorageClassAction")
a.logger.Debug("Getting plugin config")
config, err := getPluginConfig(common.PluginKindRestoreItemAction, "velero.io/change-storage-class", a.configMapClient)
config, err := common.GetPluginConfig(common.PluginKindRestoreItemAction, "velero.io/change-storage-class", a.configMapClient)
if err != nil {
return nil, err
}
+18 -18
View File
@@ -53,7 +53,7 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
name: "a valid mapping for a persistent volume is applied correctly",
pvOrPvcOrSTS: 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")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-storage-class", "RestoreItemAction")).
Data("storageclass-1", "storageclass-2").
Result(),
storageClass: builder.ForStorageClass("storageclass-2").Result(),
@@ -63,7 +63,7 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
name: "a valid mapping for a persistent volume claim is applied correctly",
pvOrPvcOrSTS: 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")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-storage-class", "RestoreItemAction")).
Data("storageclass-1", "storageclass-2").
Result(),
storageClass: builder.ForStorageClass("storageclass-2").Result(),
@@ -73,7 +73,7 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
name: "when no config map exists for the plugin, the item is returned as-is",
pvOrPvcOrSTS: 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")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/some-other-plugin", "RestoreItemAction")).
Data("storageclass-1", "storageclass-2").
Result(),
want: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
@@ -82,7 +82,7 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
name: "when no storage class mappings exist in the plugin config map, the item is returned as-is",
pvOrPvcOrSTS: 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")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-storage-class", "RestoreItemAction")).
Result(),
want: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
},
@@ -90,7 +90,7 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
name: "when persistent volume has no storage class, the item is returned as-is",
pvOrPvcOrSTS: 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")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-storage-class", "RestoreItemAction")).
Data("storageclass-1", "storageclass-2").
Result(),
want: builder.ForPersistentVolume("pv-1").Result(),
@@ -99,7 +99,7 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
name: "when persistent volume claim has no storage class, the item is returned as-is",
pvOrPvcOrSTS: 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")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-storage-class", "RestoreItemAction")).
Data("storageclass-1", "storageclass-2").
Result(),
want: builder.ForPersistentVolumeClaim("velero", "pvc-1").Result(),
@@ -108,7 +108,7 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
name: "when persistent volume's storage class has no mapping in the config map, the item is returned as-is",
pvOrPvcOrSTS: 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")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-storage-class", "RestoreItemAction")).
Data("storageclass-3", "storageclass-4").
Result(),
want: builder.ForPersistentVolume("pv-1").StorageClass("storageclass-1").Result(),
@@ -117,7 +117,7 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
name: "when persistent volume claim's storage class has no mapping in the config map, the item is returned as-is",
pvOrPvcOrSTS: 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")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-storage-class", "RestoreItemAction")).
Data("storageclass-3", "storageclass-4").
Result(),
want: builder.ForPersistentVolumeClaim("velero", "pvc-1").StorageClass("storageclass-1").Result(),
@@ -126,7 +126,7 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
name: "when persistent volume's storage class is mapped to a nonexistent storage class, an error is returned",
pvOrPvcOrSTS: 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")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "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"),
@@ -135,7 +135,7 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
name: "when persistent volume claim's storage class is mapped to a nonexistent storage class, an error is returned",
pvOrPvcOrSTS: 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")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "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"),
@@ -144,7 +144,7 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
name: "when statefulset's VolumeClaimTemplates has only one pvc, a valid mapping for a statefulset is applied correctly",
pvOrPvcOrSTS: builder.ForStatefulSet("velero", "sts-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")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-storage-class", "RestoreItemAction")).
Data("storageclass-1", "storageclass-2").
Result(),
storageClass: builder.ForStorageClass("storageclass-2").Result(),
@@ -154,7 +154,7 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
name: "when statefulset's VolumeClaimTemplates has more than one same pvc's storageClassName, a valid mapping for a statefulset is applied correctly",
pvOrPvcOrSTS: builder.ForStatefulSet("velero", "sts-1").StorageClass("storageclass-1", "storageclass-1").Result(),
configMap: builder.ForConfigMap("velero", "change-storage-classs").
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-storage-class", "RestoreItemAction")).
Data("storageclass-1", "storageclass-2", "storageclass-3", "storageclass-4").
Result(),
storageClass: builder.ForStorageClass("storageclass-2").Result(),
@@ -164,7 +164,7 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
name: "when statefulset's VolumeClaimTemplates has more than one different pvc's storageClassName, a valid mapping for a statefulset is applied correctly",
pvOrPvcOrSTS: builder.ForStatefulSet("velero", "sts-1").StorageClass("storageclass-1", "storageclass-2", "storageclass-3").Result(),
configMap: builder.ForConfigMap("velero", "change-storage-classs").
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-storage-class", "RestoreItemAction")).
Data("storageclass-1", "storageclass-a", "storageclass-2", "storageclass-b", "storageclass-3", "storageclass-c").
Result(),
storageClassSlice: builder.ForStorageClassSlice("storageclass-a", "storageclass-b", "storageclass-c").SliceResult(),
@@ -174,7 +174,7 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
name: "when no config map exists for the plugin, the statefulset item is returned as-is",
pvOrPvcOrSTS: builder.ForStatefulSet("velero", "sts-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")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/some-other-plugin", "RestoreItemAction")).
Data("storageclass-1", "storageclass-2").
Result(),
want: builder.ForStatefulSet("velero", "sts-1").StorageClass("storageclass-1").Result(),
@@ -183,7 +183,7 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
name: "when no storage class mappings exist in the plugin config map, the statefulset item is returned as-is",
pvOrPvcOrSTS: builder.ForStatefulSet("velero", "sts-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")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-storage-class", "RestoreItemAction")).
Result(),
want: builder.ForStatefulSet("velero", "sts-1").StorageClass("storageclass-1").Result(),
},
@@ -191,7 +191,7 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
name: "when persistent volume claim has no storage class, the statefulset item is returned as-is",
pvOrPvcOrSTS: builder.ForStatefulSet("velero", "sts-1").Result(),
configMap: builder.ForConfigMap("velero", "change-storage-classs").
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "true", "velero.io/change-storage-class", "RestoreItemAction")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-storage-class", "RestoreItemAction")).
Result(),
want: builder.ForStatefulSet("velero", "sts-1").Result(),
},
@@ -199,7 +199,7 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
name: "when statefulset's storage class has no mapping in the config map, the item is returned as-is",
pvOrPvcOrSTS: builder.ForStatefulSet("velero", "sts-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")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-storage-class", "RestoreItemAction")).
Data("storageclass-3", "storageclass-4").
Result(),
want: builder.ForStatefulSet("velero", "sts-1").StorageClass("storageclass-1").Result(),
@@ -208,7 +208,7 @@ func TestChangeStorageClassActionExecute(t *testing.T) {
name: "when statefulset's storage class is mapped to a nonexistent storage class, an error is returned",
pvOrPvcOrSTS: builder.ForStatefulSet("velero", "sts-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")).
ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "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"),
+1 -31
View File
@@ -24,7 +24,6 @@ import (
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
@@ -108,7 +107,7 @@ func (a *PodVolumeRestoreAction) Execute(input *velero.RestoreItemActionExecuteI
// TODO we might want/need to get plugin config at the top of this method at some point; for now, wait
// until we know we're doing a restore before getting config.
log.Debugf("Getting plugin config")
config, err := getPluginConfig(common.PluginKindRestoreItemAction, "velero.io/pod-volume-restore", a.client)
config, err := common.GetPluginConfig(common.PluginKindRestoreItemAction, "velero.io/pod-volume-restore", a.client)
if err != nil {
return nil, err
}
@@ -259,35 +258,6 @@ func getSecurityContext(log logrus.FieldLogger, config *corev1.ConfigMap) (strin
config.Data["secCtx"]
}
// TODO eventually this can move to pkg/plugin/framework since it'll be used across multiple
// plugins.
func getPluginConfig(kind common.PluginKind, name string, client corev1client.ConfigMapInterface) (*corev1.ConfigMap, error) {
opts := metav1.ListOptions{
// velero.io/plugin-config: true
// velero.io/pod-volume-restore: RestoreItemAction
LabelSelector: fmt.Sprintf("velero.io/plugin-config,%s=%s", name, kind),
}
list, err := client.List(context.TODO(), opts)
if err != nil {
return nil, errors.WithStack(err)
}
if len(list.Items) == 0 {
return nil, nil
}
if len(list.Items) > 1 {
var items []string
for _, item := range list.Items {
items = append(items, item.Name)
}
return nil, errors.Errorf("found more than one ConfigMap matching label selector %q: %v", opts.LabelSelector, items)
}
return &list.Items[0], nil
}
func newRestoreInitContainerBuilder(image, restoreUID string) *builder.ContainerBuilder {
return builder.ForContainer(restorehelper.WaitInitContainer, image).
Args(restoreUID).
+5 -1
View File
@@ -401,7 +401,11 @@ func (ctx *restoreContext) execute() (results.Result, results.Result) {
errs.AddVeleroError(err)
return warnings, errs
}
defer ctx.fileSystem.RemoveAll(dir)
defer func() {
if err := ctx.fileSystem.RemoveAll(dir); err != nil {
ctx.log.Errorf("error removing temporary directory %s: %s", dir, err.Error())
}
}()
// Need to set this for additionalItems to be restored.
ctx.restoreDir = dir
@@ -27,12 +27,15 @@ import (
k8sfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
velerov2alpha1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1"
)
func NewFakeControllerRuntimeClientBuilder(t *testing.T) *k8sfake.ClientBuilder {
scheme := runtime.NewScheme()
err := velerov1api.AddToScheme(scheme)
require.NoError(t, err)
err = velerov2alpha1api.AddToScheme(scheme)
require.NoError(t, err)
err = corev1api.AddToScheme(scheme)
require.NoError(t, err)
err = snapshotv1api.AddToScheme(scheme)
@@ -44,6 +47,8 @@ func NewFakeControllerRuntimeClient(t *testing.T, initObjs ...runtime.Object) cl
scheme := runtime.NewScheme()
err := velerov1api.AddToScheme(scheme)
require.NoError(t, err)
err = velerov2alpha1api.AddToScheme(scheme)
require.NoError(t, err)
err = corev1api.AddToScheme(scheme)
require.NoError(t, err)
err = snapshotv1api.AddToScheme(scheme)
+3 -3
View File
@@ -81,7 +81,7 @@ func (fs *FakeFileSystem) Stat(path string) (os.FileInfo, error) {
func (fs *FakeFileSystem) WithFile(path string, data []byte) *FakeFileSystem {
file, _ := fs.fs.Create(path)
file.Write(data)
_, _ = file.Write(data)
file.Close()
return fs
@@ -89,14 +89,14 @@ func (fs *FakeFileSystem) WithFile(path string, data []byte) *FakeFileSystem {
func (fs *FakeFileSystem) WithFileAndMode(path string, data []byte, mode os.FileMode) *FakeFileSystem {
file, _ := fs.fs.OpenFile(path, os.O_CREATE|os.O_RDWR, mode)
file.Write(data)
_, _ = file.Write(data)
file.Close()
return fs
}
func (fs *FakeFileSystem) WithDirectory(path string) *FakeFileSystem {
fs.fs.MkdirAll(path, 0755)
_ = fs.fs.MkdirAll(path, 0755)
return fs
}
+7
View File
@@ -27,3 +27,10 @@ func NewLogger() logrus.FieldLogger {
logger.Out = io.Discard
return logrus.NewEntry(logger)
}
func NewLoggerWithLevel(level logrus.Level) logrus.FieldLogger {
logger := logrus.New()
logger.Out = io.Discard
logger.Level = level
return logrus.NewEntry(logger)
}
+2
View File
@@ -151,3 +151,5 @@ func (p *Progress) ProgressBytes(processedBytes int64, totalBytes int64) {
atomic.StoreInt64(&p.estimatedTotalBytes, totalBytes)
p.UpdateProgress()
}
func (p *Progress) FinishedFile(fname string, err error) {}
+38 -8
View File
@@ -55,7 +55,7 @@ func NewShimRepo(repo udmrepo.BackupRepo) repo.RepositoryWriter {
// OpenObject open specific object
func (sr *shimRepository) OpenObject(ctx context.Context, id object.ID) (object.Reader, error) {
reader, err := sr.udmRepo.OpenObject(ctx, udmrepo.ID(id))
reader, err := sr.udmRepo.OpenObject(ctx, udmrepo.ID(id.String()))
if err != nil {
return nil, errors.Wrapf(err, "failed to open object with id %v", id)
}
@@ -70,7 +70,7 @@ func (sr *shimRepository) OpenObject(ctx context.Context, id object.ID) (object.
// VerifyObject not supported
func (sr *shimRepository) VerifyObject(ctx context.Context, id object.ID) ([]content.ID, error) {
return nil, errors.New("not supported")
return nil, errors.New("VerifyObject is not supported")
}
// Get one or more manifest data that match the specific manifest id
@@ -135,12 +135,12 @@ func (sr *shimRepository) ClientOptions() repo.ClientOptions {
// Refresh not supported
func (sr *shimRepository) Refresh(ctx context.Context) error {
return errors.New("not supported")
return errors.New("Refresh is not supported")
}
// ContentInfo not supported
func (sr *shimRepository) ContentInfo(ctx context.Context, contentID content.ID) (content.Info, error) {
return nil, errors.New("not supported")
return nil, errors.New("ContentInfo is not supported")
}
// PrefetchContents is not supported by unified repo
@@ -150,7 +150,7 @@ func (sr *shimRepository) PrefetchContents(ctx context.Context, contentIDs []con
// PrefetchObjects is not supported by unified repo
func (sr *shimRepository) PrefetchObjects(ctx context.Context, objectIDs []object.ID, hint string) ([]content.ID, error) {
return nil, errors.New("not supported")
return nil, errors.New("PrefetchObjects is not supported")
}
// UpdateDescription is not supported by unified repo
@@ -159,7 +159,7 @@ func (sr *shimRepository) UpdateDescription(d string) {
// NewWriter is not supported by unified repo
func (sr *shimRepository) NewWriter(ctx context.Context, option repo.WriteSessionOptions) (context.Context, repo.RepositoryWriter, error) {
return nil, nil, errors.New("not supported")
return nil, nil, errors.New("NewWriter is not supported")
}
// Close will close unified repo
@@ -174,6 +174,7 @@ func (sr *shimRepository) NewObjectWriter(ctx context.Context, option object.Wri
opt.Prefix = udmrepo.ID(option.Prefix)
opt.FullPath = ""
opt.AccessMode = udmrepo.ObjectDataAccessModeFile
opt.AsyncWrites = option.AsyncWrites
if strings.HasPrefix(option.Description, "DIR:") {
opt.DataType = udmrepo.ObjectDataTypeMetadata
@@ -208,11 +209,22 @@ func (sr *shimRepository) DeleteManifest(ctx context.Context, id manifest.ID) er
return sr.udmRepo.DeleteManifest(ctx, udmrepo.ID(id))
}
func (sr *shimRepository) ReplaceManifests(ctx context.Context, labels map[string]string, payload interface{}) (manifest.ID, error) {
return manifest.ID(""), errors.New("ReplaceManifests is not supported")
}
// Flush all the unifited repository data
func (sr *shimRepository) Flush(ctx context.Context) error {
return sr.udmRepo.Flush(ctx)
}
func (sr *shimRepository) ConcatenateObjects(ctx context.Context, objectIDs []object.ID) (object.ID, error) {
return object.ID{}, errors.New("ConcatenateObjects is not supported")
}
func (sr *shimRepository) OnSuccessfulFlush(callback repo.RepositoryWriterCallback) {
}
// Flush all the unifited repository data
func (sr *shimObjectReader) Read(p []byte) (n int, err error) {
return sr.repoReader.Read(p)
@@ -240,13 +252,31 @@ func (sr *shimObjectWriter) Write(p []byte) (n int, err error) {
// Periodically called to preserve the state of data written to the repo so far.
func (sr *shimObjectWriter) Checkpoint() (object.ID, error) {
id, err := sr.repoWriter.Checkpoint()
return object.ID(id), err
if err != nil {
return object.ID{}, err
}
objID, err := object.ParseID(string(id))
if err != nil {
return object.ID{}, errors.Wrapf(err, "error to parse object ID from %v", id)
}
return objID, err
}
// Result returns the object's unified identifier after the write completes.
func (sr *shimObjectWriter) Result() (object.ID, error) {
id, err := sr.repoWriter.Result()
return object.ID(id), err
if err != nil {
return object.ID{}, err
}
objID, err := object.ParseID(string(id))
if err != nil {
return object.ID{}, errors.Wrapf(err, "error to parse object ID from %v", id)
}
return objID, err
}
// Close closes the repository and releases all resources.
+19 -31
View File
@@ -44,9 +44,7 @@ import (
)
// All function mainly used to make testing more convenient
var treeForSourceFunc = policy.TreeForSource
var applyRetentionPolicyFunc = policy.ApplyRetentionPolicy
var setPolicyFunc = policy.SetPolicy
var saveSnapshotFunc = snapshot.SaveSnapshot
var loadSnapshotFunc = snapshot.LoadSnapshot
@@ -72,24 +70,17 @@ func newOptionalBool(b bool) *policy.OptionalBool {
}
// setupDefaultPolicy set default policy for kopia
func setupDefaultPolicy(ctx context.Context, rep repo.RepositoryWriter, sourceInfo snapshot.SourceInfo) error {
return setPolicyFunc(ctx, rep, sourceInfo, &policy.Policy{
RetentionPolicy: policy.RetentionPolicy{
KeepLatest: newOptionalInt(math.MaxInt32),
},
CompressionPolicy: policy.CompressionPolicy{
CompressorName: "none",
},
UploadPolicy: policy.UploadPolicy{
MaxParallelFileReads: newOptionalInt(runtime.NumCPU()),
},
SchedulingPolicy: policy.SchedulingPolicy{
Manual: true,
},
ErrorHandlingPolicy: policy.ErrorHandlingPolicy{
IgnoreUnknownTypes: newOptionalBool(true),
},
})
func setupDefaultPolicy() *policy.Tree {
defaultPolicy := *policy.DefaultPolicy
defaultPolicy.RetentionPolicy.KeepLatest = newOptionalInt(math.MaxInt32)
defaultPolicy.CompressionPolicy.CompressorName = "none"
defaultPolicy.UploadPolicy.MaxParallelFileReads = newOptionalInt(runtime.NumCPU())
defaultPolicy.UploadPolicy.ParallelUploadAboveSize = nil
defaultPolicy.SchedulingPolicy.Manual = true
defaultPolicy.ErrorHandlingPolicy.IgnoreUnknownTypes = newOptionalBool(true)
return policy.BuildTree(nil, &defaultPolicy)
}
// Backup backup specific sourcePath and update progress
@@ -198,17 +189,9 @@ func SnapshotSource(
}
}
var manifest *snapshot.Manifest
if err := setupDefaultPolicy(ctx, rep, sourceInfo); err != nil {
return "", 0, errors.Wrapf(err, "unable to set policy for si %v", sourceInfo)
}
policyTree := setupDefaultPolicy()
policyTree, err := treeForSourceFunc(ctx, rep, sourceInfo)
if err != nil {
return "", 0, errors.Wrapf(err, "unable to create policy getter for si %v", sourceInfo)
}
manifest, err = u.Upload(ctx, rootDir, policyTree, sourceInfo, previous...)
manifest, err := u.Upload(ctx, rootDir, policyTree, sourceInfo, previous...)
if err != nil {
return "", 0, errors.Wrapf(err, "Failed to upload the kopia snapshot for si %v", sourceInfo)
}
@@ -254,7 +237,7 @@ func reportSnapshotStatus(manifest *snapshot.Manifest, policyTree *policy.Tree)
// findPreviousSnapshotManifest returns the list of previous snapshots for a given source, including
// last complete snapshot following it.
func findPreviousSnapshotManifest(ctx context.Context, rep repo.Repository, sourceInfo snapshot.SourceInfo, snapshotTags map[string]string, noLaterThan *time.Time) ([]*snapshot.Manifest, error) {
func findPreviousSnapshotManifest(ctx context.Context, rep repo.Repository, sourceInfo snapshot.SourceInfo, snapshotTags map[string]string, noLaterThan *fs.UTCTimestamp) ([]*snapshot.Manifest, error) {
man, err := snapshot.ListSnapshots(ctx, rep, sourceInfo)
if err != nil {
return nil, err
@@ -313,6 +296,11 @@ func Restore(ctx context.Context, rep repo.RepositoryWriter, progress *Progress,
IgnorePermissionErrors: true,
}
err = output.Init(ctx)
if err != nil {
return 0, 0, errors.Wrap(err, "error to init output")
}
stat, err := restore.Entry(kopiaCtx, rep, output, rootEntry, restore.Options{
Parallel: runtime.NumCPU(),
RestoreDirEntryAtDepth: math.MaxInt32,
-15
View File
@@ -50,8 +50,6 @@ func injectSnapshotFuncs() *snapshotMockes {
repoWriterMock: &repomocks.RepositoryWriter{},
}
setPolicyFunc = s.policyMock.SetPolicy
treeForSourceFunc = s.policyMock.TreeForSource
applyRetentionPolicyFunc = s.policyMock.ApplyRetentionPolicy
loadSnapshotFunc = s.snapshotMock.LoadSnapshot
saveSnapshotFunc = s.snapshotMock.SaveSnapshot
@@ -141,19 +139,6 @@ func TestSnapshotSource(t *testing.T) {
},
notError: false,
},
{
name: "failed to set policy",
args: []mockArgs{
{methodName: "LoadSnapshot", returns: []interface{}{manifest, nil}},
{methodName: "SaveSnapshot", returns: []interface{}{manifest.ID, nil}},
{methodName: "TreeForSource", returns: []interface{}{nil, nil}},
{methodName: "ApplyRetentionPolicy", returns: []interface{}{nil, nil}},
{methodName: "SetPolicy", returns: []interface{}{errors.New("failed to set policy")}},
{methodName: "Upload", returns: []interface{}{manifest, nil}},
{methodName: "Flush", returns: []interface{}{nil}},
},
notError: false,
},
{
name: "failed to upload snapshot",
args: []mockArgs{
+106 -34
View File
@@ -21,6 +21,8 @@ import (
"github.com/kopia/kopia/repo/logging"
"github.com/sirupsen/logrus"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
type kopiaLog struct {
@@ -32,59 +34,129 @@ type kopiaLog struct {
// call the logger in the context to write logs
func SetupKopiaLog(ctx context.Context, logger logrus.FieldLogger) context.Context {
return logging.WithLogger(ctx, func(module string) logging.Logger {
return &kopiaLog{
module: module,
logger: logger,
}
kpLog := &kopiaLog{module, logger}
return zap.New(kpLog).Sugar()
})
}
func (kl *kopiaLog) Debugf(msg string, args ...interface{}) {
logger := kl.logger.WithField("logModule", kl.getLogModule())
logger.Debugf(msg, args...)
// Enabled decides whether a given logging level is enabled when logging a message
func (kl *kopiaLog) Enabled(level zapcore.Level) bool {
entry := kl.logger.WithField("null", "null")
switch level {
case zapcore.DebugLevel:
return (entry.Logger.GetLevel() >= logrus.DebugLevel)
case zapcore.InfoLevel:
return (entry.Logger.GetLevel() >= logrus.InfoLevel)
case zapcore.WarnLevel:
return (entry.Logger.GetLevel() >= logrus.WarnLevel)
case zapcore.ErrorLevel:
return (entry.Logger.GetLevel() >= logrus.ErrorLevel)
case zapcore.DPanicLevel:
return (entry.Logger.GetLevel() >= logrus.PanicLevel)
case zapcore.PanicLevel:
return (entry.Logger.GetLevel() >= logrus.PanicLevel)
case zapcore.FatalLevel:
return (entry.Logger.GetLevel() >= logrus.FatalLevel)
default:
return false
}
}
func (kl *kopiaLog) Debugw(msg string, keyValuePairs ...interface{}) {
logger := kl.logger.WithField("logModule", kl.getLogModule())
logger.WithFields(getLogFields(keyValuePairs...)).Debug(msg)
// With adds structured context to the Core.
func (kl *kopiaLog) With(fields []zapcore.Field) zapcore.Core {
copied := kl.logrusFields(fields)
return &kopiaLog{
module: kl.module,
logger: kl.logger.WithFields(copied),
}
}
func (kl *kopiaLog) Infof(msg string, args ...interface{}) {
logger := kl.logger.WithField("logModule", kl.getLogModule())
logger.Infof(msg, args...)
// Check determines whether the supplied Entry should be logged. If the entry
// should be logged, the Core adds itself to the CheckedEntry and returns the result.
func (kl *kopiaLog) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
if kl.Enabled(ent.Level) {
return ce.AddCore(ent, kl)
}
return ce
}
func (kl *kopiaLog) Warnf(msg string, args ...interface{}) {
logger := kl.logger.WithField("logModule", kl.getLogModule())
logger.Warnf(msg, args...)
// Write serializes the Entry and any Fields supplied at the log site and writes them to their destination.
func (kl *kopiaLog) Write(ent zapcore.Entry, fields []zapcore.Field) error {
copied := kl.logrusFieldsForWrite(ent, fields)
logger := kl.logger.WithFields(copied)
switch ent.Level {
case zapcore.DebugLevel:
logger.Debug(ent.Message)
case zapcore.InfoLevel:
logger.Info(ent.Message)
case zapcore.WarnLevel:
logger.Warn(ent.Message)
case zapcore.ErrorLevel:
// We see Kopia generates error logs for some normal cases or non-critical
// cases. So Kopia's error logs are regarded as warning logs so that they don't
// affect Velero's workflow.
logger.Warn(ent.Message)
case zapcore.DPanicLevel:
logger.Panic(ent.Message)
case zapcore.PanicLevel:
logger.Panic(ent.Message)
case zapcore.FatalLevel:
logger.Fatal(ent.Message)
}
return nil
}
// We see Kopia generates error logs for some normal cases or non-critical
// cases. So Kopia's error logs are regarded as warning logs so that they don't
// affect Velero's workflow.
func (kl *kopiaLog) Errorf(msg string, args ...interface{}) {
logger := kl.logger.WithFields(logrus.Fields{
"logModule": kl.getLogModule(),
"sublevel": "error",
})
// Sync flushes buffered logs (if any).
func (kl *kopiaLog) Sync() error {
return nil
}
logger.Warnf(msg, args...)
func (kl *kopiaLog) logrusFields(fields []zapcore.Field) logrus.Fields {
if fields == nil {
return logrus.Fields{}
}
m := zapcore.NewMapObjectEncoder()
for _, field := range fields {
field.AddTo(m)
}
return m.Fields
}
func (kl *kopiaLog) getLogModule() string {
return "kopia/" + kl.module
}
func getLogFields(keyValuePairs ...interface{}) map[string]interface{} {
m := map[string]interface{}{}
for i := 0; i+1 < len(keyValuePairs); i += 2 {
s, ok := keyValuePairs[i].(string)
if !ok {
s = "non-string-key"
}
func (kl *kopiaLog) logrusFieldsForWrite(ent zapcore.Entry, fields []zapcore.Field) logrus.Fields {
copied := kl.logrusFields(fields)
m[s] = keyValuePairs[i+1]
copied["logModule"] = kl.getLogModule()
if ent.Caller.Function != "" {
copied["function"] = ent.Caller.Function
}
return m
path := ent.Caller.FullPath()
if path != "undefined" {
copied["path"] = path
}
if ent.LoggerName != "" {
copied["logger name"] = ent.LoggerName
}
if ent.Stack != "" {
copied["stack"] = ent.Stack
}
if ent.Level == zap.ErrorLevel {
copied["sublevel"] = "error"
}
return copied
}
+119 -38
View File
@@ -19,66 +19,147 @@ package logging
import (
"testing"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/require"
"go.uber.org/zap/zapcore"
"github.com/vmware-tanzu/velero/pkg/test"
)
func TestGetLogFields(t *testing.T) {
func TestEnabled(t *testing.T) {
testCases := []struct {
name string
pairs []interface{}
expected map[string]interface{}
level logrus.Level
zapLevel zapcore.Level
expected bool
}{
{
name: "normal",
pairs: []interface{}{
"fake-key1",
"fake-value1",
"fake-key2",
10,
"fake-key3",
struct{ v int }{v: 10},
name: "check debug again debug",
level: logrus.DebugLevel,
zapLevel: zapcore.DebugLevel,
expected: true,
},
{
name: "check debug again info",
level: logrus.InfoLevel,
zapLevel: zapcore.DebugLevel,
expected: false,
},
{
name: "check info again debug",
level: logrus.DebugLevel,
zapLevel: zapcore.InfoLevel,
expected: true,
},
{
name: "check info again info",
level: logrus.InfoLevel,
zapLevel: zapcore.InfoLevel,
expected: true,
},
{
name: "check info again error",
level: logrus.ErrorLevel,
zapLevel: zapcore.InfoLevel,
expected: false,
},
{
name: "check error again error",
level: logrus.ErrorLevel,
zapLevel: zapcore.ErrorLevel,
expected: true,
},
{
name: "check panic again error",
level: logrus.ErrorLevel,
zapLevel: zapcore.PanicLevel,
expected: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
log := kopiaLog{
logger: test.NewLoggerWithLevel(tc.level),
}
m := log.Enabled(tc.zapLevel)
require.Equal(t, tc.expected, m)
})
}
}
func TestWrite(t *testing.T) {
testCases := []struct {
name string
module string
zapEntry zapcore.Entry
zapFields []zapcore.Field
expected logrus.Fields
}{
{
name: "debug with nil fields",
module: "module-01",
zapEntry: zapcore.Entry{
Level: zapcore.DebugLevel,
},
expected: map[string]interface{}{
"fake-key1": "fake-value1",
"fake-key2": 10,
"fake-key3": struct{ v int }{v: 10},
zapFields: nil,
expected: logrus.Fields{
"logModule": "kopia/module-01",
},
},
{
name: "non string key",
pairs: []interface{}{
"fake-key1",
"fake-value1",
10,
10,
"fake-key3",
struct{ v int }{v: 10},
name: "error with nil fields",
module: "module-02",
zapEntry: zapcore.Entry{
Level: zapcore.ErrorLevel,
},
expected: map[string]interface{}{
"fake-key1": "fake-value1",
"non-string-key": 10,
"fake-key3": struct{ v int }{v: 10},
zapFields: nil,
expected: logrus.Fields{
"logModule": "kopia/module-02",
"sublevel": "error",
},
},
{
name: "missing value",
pairs: []interface{}{
"fake-key1",
"fake-value1",
"fake-key2",
10,
"fake-key3",
name: "info with nil string filed",
module: "module-03",
zapEntry: zapcore.Entry{
Level: zapcore.InfoLevel,
},
expected: map[string]interface{}{
"fake-key1": "fake-value1",
"fake-key2": 10,
zapFields: []zapcore.Field{
{
Key: "key-01",
Type: zapcore.StringType,
String: "value-01",
},
},
expected: logrus.Fields{
"logModule": "kopia/module-03",
"key-01": "value-01",
},
},
{
name: "info with logger name",
module: "module-04",
zapEntry: zapcore.Entry{
Level: zapcore.InfoLevel,
LoggerName: "logger-name-01",
},
zapFields: nil,
expected: logrus.Fields{
"logModule": "kopia/module-04",
"logger name": "logger-name-01",
},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
m := getLogFields(tc.pairs...)
log := kopiaLog{
module: tc.module,
logger: test.NewLogger(),
}
m := log.logrusFieldsForWrite(tc.zapEntry, tc.zapFields)
require.Equal(t, tc.expected, m)
})