Unverified Commit f5ff5ebd by Shuwei Hao Committed by GitHub

Merge pull request #22 from haoshuwei/backup-restore-plugin

add restore plugin to auto convert storage capacity to be at least 20…
parents 605e37bd 1e14a51f
...@@ -14,6 +14,11 @@ const ( ...@@ -14,6 +14,11 @@ const (
metadataRegionKey = "region" metadataRegionKey = "region"
metadataZoneKey = "zone-id" metadataZoneKey = "zone-id"
regionConfigKey = "region" regionConfigKey = "region"
minReqVolSizeBytes = 21474836480
minReqVolSizeString = "20Gi"
kindKey = "kind"
persistentVolumeKey = "PersistentVolume"
persistentVolumeClaimKey = "PersistentVolumeClaim"
) )
// load environment vars from $ALIBABA_CLOUD_CREDENTIALS_FILE, if it exists // load environment vars from $ALIBABA_CLOUD_CREDENTIALS_FILE, if it exists
......
...@@ -25,6 +25,7 @@ func main() { ...@@ -25,6 +25,7 @@ func main() {
veleroplugin.NewServer(). veleroplugin.NewServer().
RegisterObjectStore("velero.io/alibabacloud", newAlibabaCloudObjectStore). RegisterObjectStore("velero.io/alibabacloud", newAlibabaCloudObjectStore).
RegisterVolumeSnapshotter("velero.io/alibabacloud", newAlibabaCloudVolumeSnapshotter). RegisterVolumeSnapshotter("velero.io/alibabacloud", newAlibabaCloudVolumeSnapshotter).
RegisterRestoreItemAction("velero.io/alibabacloud", newAlibabaCloudRestoreItemAction).
Serve() Serve()
} }
...@@ -35,3 +36,7 @@ func newAlibabaCloudObjectStore(logger logrus.FieldLogger) (interface{}, error) ...@@ -35,3 +36,7 @@ func newAlibabaCloudObjectStore(logger logrus.FieldLogger) (interface{}, error)
func newAlibabaCloudVolumeSnapshotter(logger logrus.FieldLogger) (interface{}, error) { func newAlibabaCloudVolumeSnapshotter(logger logrus.FieldLogger) (interface{}, error) {
return newVolumeSnapshotter(logger), nil return newVolumeSnapshotter(logger), nil
} }
func newAlibabaCloudRestoreItemAction(logger logrus.FieldLogger) (interface{}, error) {
return newRestoreItemAction(logger), nil
}
...@@ -70,7 +70,7 @@ type ObjectStore struct { ...@@ -70,7 +70,7 @@ type ObjectStore struct {
privateKey []byte privateKey []byte
} }
// NewObjectStore init ObjectStore // newObjectStore init ObjectStore
func newObjectStore(logger logrus.FieldLogger) *ObjectStore { func newObjectStore(logger logrus.FieldLogger) *ObjectStore {
return &ObjectStore{log: logger} return &ObjectStore{log: logger}
} }
......
package main
import (
corev1api "k8s.io/api/core/v1"
"github.com/sirupsen/logrus"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/api/resource"
)
type RestoreItemAction struct {
log logrus.FieldLogger
}
//
func newRestoreItemAction (logger logrus.FieldLogger) *RestoreItemAction {
return &RestoreItemAction{log: logger}
}
// AppliesTo returns information about which resources this action should be invoked for.
// A RestoreItemAction's Execute function will only be invoked on items that match the returned
// selector. A zero-valued ResourceSelector matches all resources.g
func (p *RestoreItemAction) AppliesTo() (velero.ResourceSelector, error) {
return velero.ResourceSelector{
IncludedResources: []string{"pvc", "persistentvolume"},
}, nil
}
// Execute allows the RestorePlugin to perform arbitrary logic with the item being restored,
// in this case, setting a custom annotation on the item being restored.
func (p *RestoreItemAction) Execute(input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error) {
p.log.Info("Alibaba Cloud RestorePlugin!")
var kind string
var err error
var ok bool
inputMap := input.Item.UnstructuredContent()
if kind, ok = inputMap[kindKey].(string); !ok {
return nil, errors.WithStack(err)
}
metadata, err := meta.Accessor(input.Item)
if err != nil {
return &velero.RestoreItemActionExecuteOutput{}, err
}
annotations := metadata.GetAnnotations()
if annotations == nil {
annotations = make(map[string]string)
}
annotations["velero.io/alibabacloud-restore-plugin"] = "1"
metadata.SetAnnotations(annotations)
switch kind {
case persistentVolumeClaimKey:
var pvc corev1api.PersistentVolumeClaim
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(input.Item.UnstructuredContent(), &pvc); err != nil {
return nil, errors.WithStack(err)
}
capacity := pvc.Spec.Resources.Requests[corev1api.ResourceName(corev1api.ResourceStorage)]
volSizeBytes := capacity.Value()
if int64(volSizeBytes) <= int64(minReqVolSizeBytes) {
p.log.Warnf("Alibaba disk volume request at least 20Gi, auto resize persistentVolumeClaim to 20Gi.")
pvc.Spec.Resources = corev1api.ResourceRequirements{
Requests : getResourceList(minReqVolSizeString),
}
pvc.Status = corev1api.PersistentVolumeClaimStatus{}
inputMap, err = runtime.DefaultUnstructuredConverter.ToUnstructured(&pvc)
if err != nil {
return nil, errors.WithStack(err)
}
}
case persistentVolumeKey:
var pv corev1api.PersistentVolume
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(input.Item.UnstructuredContent(), &pv); err != nil {
return nil, errors.WithStack(err)
}
capacity := pv.Spec.Capacity[corev1api.ResourceName(corev1api.ResourceStorage)]
volSizeBytes := capacity.Value()
if int64(volSizeBytes) <= int64(minReqVolSizeBytes) {
p.log.Warnf("Alibaba disk volume request at least 20Gi, auto resize persistentVolume to 20Gi.")
persistentVolumeSource := pv.Spec.PersistentVolumeSource
accessModes := pv.Spec.AccessModes
claimRef := pv.Spec.ClaimRef
persistentVolumeReclaimPolicy := pv.Spec.PersistentVolumeReclaimPolicy
storageClassName := pv.Spec.StorageClassName
mountOptions := pv.Spec.MountOptions
volumeMode := pv.Spec.VolumeMode
nodeAffinity := pv.Spec.NodeAffinity
pv.Spec = corev1api.PersistentVolumeSpec{
Capacity: getResourceList(minReqVolSizeString),
PersistentVolumeSource: persistentVolumeSource,
AccessModes: accessModes,
ClaimRef: claimRef,
PersistentVolumeReclaimPolicy: persistentVolumeReclaimPolicy,
StorageClassName: storageClassName,
MountOptions: mountOptions,
VolumeMode: volumeMode,
NodeAffinity: nodeAffinity,
}
pv.Status = corev1api.PersistentVolumeStatus{}
inputMap, err = runtime.DefaultUnstructuredConverter.ToUnstructured(&pv)
if err != nil {
return nil, errors.WithStack(err)
}
}
default:
p.log.Info("Nothing need to do, skip")
}
return velero.NewRestoreItemActionExecuteOutput(&unstructured.Unstructured{Object: inputMap}), nil
}
func getResourceList(storage string) corev1api.ResourceList {
res := corev1api.ResourceList{}
if storage != "" {
res[corev1api.ResourceStorage] = resource.MustParse(storage)
}
return res
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment