Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(local-snapshot-restore, velero) : support to restore local snapshot to different namespace using velero #1575

Merged
merged 13 commits into from
Mar 26, 2020
8 changes: 6 additions & 2 deletions cmd/maya-apiserver/app/server/backup_endpoint_v1alpha1.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ func (bOps *backupAPIOps) create() (interface{}, error) {
return nil, CodedError(400, fmt.Sprintf("Failed to create backup '%v': missing volume name", bkp.Spec.BackupName))
}

// backupIP is expected
if len(strings.TrimSpace(bkp.Spec.BackupDest)) == 0 {
// backupIP is expected for cloud snapshot
mynktl marked this conversation as resolved.
Show resolved Hide resolved
if !bkp.Spec.LocalSnap && len(strings.TrimSpace(bkp.Spec.BackupDest)) == 0 {
return nil, CodedError(400, fmt.Sprintf("Failed to create backup '%v': missing backupIP", bkp.Spec.BackupName))
}

Expand All @@ -107,6 +107,10 @@ func (bOps *backupAPIOps) create() (interface{}, error) {
return nil, CodedError(400, fmt.Sprintf("Failed to find healthy replica"))
}

if bkp.Spec.LocalSnap {
mynktl marked this conversation as resolved.
Show resolved Hide resolved
return "", nil
}

bkp.ObjectMeta.Labels = map[string]string{
"cstorpool.openebs.io/uid": cvr.ObjectMeta.Labels["cstorpool.openebs.io/uid"],
"openebs.io/persistent-volume": cvr.ObjectMeta.Labels["openebs.io/persistent-volume"],
Expand Down
66 changes: 62 additions & 4 deletions cmd/maya-apiserver/app/server/restore_endpoint_v1alpha1.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import (

"github.com/openebs/maya/pkg/apis/openebs.io/v1alpha1"
"github.com/openebs/maya/pkg/client/generated/clientset/versioned"
"github.com/openebs/maya/pkg/volume"
"github.com/pkg/errors"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/uuid"
"k8s.io/client-go/kubernetes"
Expand Down Expand Up @@ -62,7 +64,7 @@ func (rOps *restoreAPIOps) create() (interface{}, error) {
}

// namespace is expected
if len(strings.TrimSpace(restore.Namespace)) == 0 {
if !restore.Spec.Local && len(strings.TrimSpace(restore.Namespace)) == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we throw error if Local and NameSpace is NOT 0?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case of local We are not using namespace. We are ignoring it so skipped the check.

return nil, CodedError(400, fmt.Sprintf("failed to create restore '%v': missing namespace", restore.Name))
}

Expand All @@ -81,16 +83,36 @@ func (rOps *restoreAPIOps) create() (interface{}, error) {
return nil, CodedError(400, fmt.Sprintf("failed to create restore '%v': missing restoreSrc", restore.Name))
}

// storageClass is expected if restore is for local snapshot
if restore.Spec.Local && len(strings.TrimSpace(restore.Spec.StorageClass)) == 0 {
return nil, CodedError(400, fmt.Sprintf("failed to create restore '%v': missing storageClass", restore.Name))
}

// size is expected if restore is for local snapshot
if restore.Spec.Local && len(strings.TrimSpace(restore.Spec.Size.String())) == 0 {
return nil, CodedError(400, fmt.Sprintf("failed to create restore '%v': missing size", restore.Name))
}

openebsClient, _, err = loadClientFromServiceAccount()
if err != nil {
return nil, CodedError(400, fmt.Sprintf("Failed to load openebs client:{%v}", err))
}

return createRestoreResource(openebsClient, restore)
cvol, err := createVolumeForRestore(restore)
if err != nil {
return nil, CodedError(400, fmt.Sprintf("Failed to create resources for volume: {%v}", err))
}
klog.Infof("Restore volume '%v' created successfully ", cvol.Name)

if restore.Spec.Local {
return cvol, nil
}

return createRestoreResource(openebsClient, restore, cvol)
}

// createRestoreResource create restore CR for volume's CVR
func createRestoreResource(openebsClient *versioned.Clientset, rst *v1alpha1.CStorRestore) (interface{}, error) {
func createRestoreResource(openebsClient *versioned.Clientset, rst *v1alpha1.CStorRestore, cvol *v1alpha1.CASVolume) (interface{}, error) {
//Get List of cvr's related to this pvc
listOptions := v1.ListOptions{
LabelSelector: "openebs.io/persistent-volume=" + rst.Spec.VolumeName,
Expand Down Expand Up @@ -137,7 +159,7 @@ func createRestoreResource(openebsClient *versioned.Clientset, rst *v1alpha1.CSt
}
}

return "", nil
return cvol, nil
}

// get is http handler which handles backup get request
Expand Down Expand Up @@ -255,3 +277,39 @@ func updateRestoreStatus(clientset versioned.Interface, rst v1alpha1.CStorRestor
return
}
}

func createVolumeForRestore(r *v1alpha1.CStorRestore) (*v1alpha1.CASVolume, error) {
vol := &v1alpha1.CASVolume{}

vol.Name = r.Spec.VolumeName
vol.Labels = map[string]string{
string(v1alpha1.StorageClassKey): r.Spec.StorageClass,
}
vol.Spec.Capacity = r.Spec.Size.String()

if r.Spec.Local {
vol.CloneSpec.IsClone = true
vol.CloneSpec.SourceVolume = r.Spec.RestoreSrc
vol.CloneSpec.SnapshotName = r.Spec.RestoreName
} else {
vol.Annotations = map[string]string{
v1alpha1.PVCreatedByKey: "restore",
}
}

vOps, err := volume.NewOperation(vol)
if err != nil {
return nil, errors.Wrapf(err, "Failed to create volume operation")
}

cvol, err := vOps.Read()
if err != nil {
if !isNotFound(err) {
return nil, errors.Wrapf(err, "Failed to get restore volume details")
}
} else {
return cvol, nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this possible in case of cloud backup?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, In case of cloud backups we are creating volume through PVC from velero-plugin. So this will return the existing volume. Added comment.

}

return vOps.Create()
Copy link
Contributor

@vishnuitta vishnuitta Mar 25, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this supposed to be for local backup?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It serves for local and cloud backup. As of now we are creating volume through PVC from velero-plugin in case of remote restore So this will not execute for remote backup. #1575 (comment)

}
1 change: 0 additions & 1 deletion cmd/maya-apiserver/app/server/volume_endpoint_v1alpha1.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,6 @@ func (v *volumeAPIOpsV1alpha1) delete(volumeName string) (*v1alpha1.CASVolume, e
if len(vol.Name) == 0 {
return nil, CodedErrorf(400, "failed to delete volume: missing volume name: %s", vol)
}

// use namespace from req headers if volume ns is still not set
if len(vol.Namespace) == 0 {
vol.Namespace = hdrNS
Expand Down
3 changes: 3 additions & 0 deletions pkg/apis/openebs.io/v1alpha1/cstor_backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ type CStorBackupSpec struct {

// BackupDest is the remote address for backup transfer
BackupDest string `json:"backupDest"`

// LocalSnap is flag to enable local snapshot only
LocalSnap bool `json:"localSnap"`
kmova marked this conversation as resolved.
Show resolved Hide resolved
}

// CStorBackupStatus is to hold status of backup
Expand Down
14 changes: 9 additions & 5 deletions pkg/apis/openebs.io/v1alpha1/cstor_restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package v1alpha1

import (
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

Expand All @@ -35,11 +36,14 @@ type CStorRestore struct {

// CStorRestoreSpec is the spec for a CStorRestore resource
type CStorRestoreSpec struct {
RestoreName string `json:"restoreName"` // set restore name
VolumeName string `json:"volumeName"`
RestoreSrc string `json:"restoreSrc"`
MaxRetryCount int `json:"maxretrycount"`
RetryCount int `json:"retrycount"`
RestoreName string `json:"restoreName"` // set restore name
VolumeName string `json:"volumeName"`
RestoreSrc string `json:"restoreSrc"` // it can be ip:port in case of restore from remote or volumeName in case of local restore
MaxRetryCount int `json:"maxretrycount"`
RetryCount int `json:"retrycount"`
StorageClass string `json:"storageClass"`
mynktl marked this conversation as resolved.
Show resolved Hide resolved
Size resource.Quantity `json:"size"`
Local bool `json:"localRestore"` // if restore is from local backup/snapshot
}

// CStorRestoreStatus is to hold result of action.
Expand Down
3 changes: 2 additions & 1 deletion pkg/apis/openebs.io/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.