zfs-localpv/pkg/builder/restorebuilder/kubernetes.go
Pawan Prakash Sharma e40026c98a
feat(zfspv): adding backup and restore support (#162)
This commit adds support for Backup and Restore controller, which will be watching for
the events. The velero plugin will create a Backup CR to create a backup
with the remote location information, the controller will send the data
to that remote location.

In the same way, the velero plugin will create a Restore CR to restore the
volume from the the remote location and the restore controller will restore
the data.

Steps to use velero plugin for ZFS-LocalPV are :

1. install velero

2. add openebs plugin

velero plugin add openebs/velero-plugin:latest

3. Create the volumesnapshot location :

for full backup :-

```yaml
apiVersion: velero.io/v1
kind: VolumeSnapshotLocation
metadata:
  name: default
  namespace: velero
spec:
  provider: openebs.io/zfspv-blockstore
  config:
    bucket: velero
    prefix: zfs
    namespace: openebs
    provider: aws
    region: minio
    s3ForcePathStyle: "true"
    s3Url: http://minio.velero.svc:9000
```

for incremental backup :-

```yaml
apiVersion: velero.io/v1
kind: VolumeSnapshotLocation
metadata:
  name: default
  namespace: velero
spec:
  provider: openebs.io/zfspv-blockstore
  config:
    bucket: velero
    prefix: zfs
    backup: incremental
    namespace: openebs
    provider: aws
    region: minio
    s3ForcePathStyle: "true"
    s3Url: http://minio.velero.svc:9000
```

4. Create backup

velero backup create my-backup --snapshot-volumes --include-namespaces=velero-ns --volume-snapshot-locations=aws-cloud-default --storage-location=default

5. Create Schedule

velero create schedule newschedule  --schedule="*/1 * * * *" --snapshot-volumes --include-namespaces=velero-ns --volume-snapshot-locations=aws-local-default --storage-location=default

6. Restore from backup

velero restore create --from-backup my-backup --restore-volumes=true --namespace-mappings velero-ns:ns1



Signed-off-by: Pawan <pawan@mayadata.io>
2020-09-08 13:44:39 +05:30

427 lines
10 KiB
Go

// Copyright © 2020 The OpenEBS Authors
//
// 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 restorebuilder
import (
"encoding/json"
apis "github.com/openebs/zfs-localpv/pkg/apis/openebs.io/zfs/v1"
client "github.com/openebs/zfs-localpv/pkg/common/kubernetes/client"
clientset "github.com/openebs/zfs-localpv/pkg/generated/clientset/internalclientset"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// getClientsetFn is a typed function that
// abstracts fetching of internal clientset
type getClientsetFn func() (clientset *clientset.Clientset, err error)
// getClientsetFromPathFn is a typed function that
// abstracts fetching of clientset from kubeConfigPath
type getClientsetForPathFn func(kubeConfigPath string) (
clientset *clientset.Clientset,
err error,
)
// createFn is a typed function that abstracts
// creating zfsrstr rstrume instance
type createFn func(
cs *clientset.Clientset,
upgradeResultObj *apis.ZFSRestore,
namespace string,
) (*apis.ZFSRestore, error)
// getFn is a typed function that abstracts
// fetching a zfsrstr rstrume instance
type getFn func(
cli *clientset.Clientset,
name,
namespace string,
opts metav1.GetOptions,
) (*apis.ZFSRestore, error)
// listFn is a typed function that abstracts
// listing of zfsrstr rstrume instances
type listFn func(
cli *clientset.Clientset,
namespace string,
opts metav1.ListOptions,
) (*apis.ZFSRestoreList, error)
// delFn is a typed function that abstracts
// deleting a zfsrstr rstrume instance
type delFn func(
cli *clientset.Clientset,
name,
namespace string,
opts *metav1.DeleteOptions,
) error
// updateFn is a typed function that abstracts
// updating zfsrstr rstrume instance
type updateFn func(
cs *clientset.Clientset,
rstr *apis.ZFSRestore,
namespace string,
) (*apis.ZFSRestore, error)
// Kubeclient enables kubernetes API operations
// on zfsrstr rstrume instance
type Kubeclient struct {
// clientset refers to zfsrstr rstrume's
// clientset that will be responsible to
// make kubernetes API calls
clientset *clientset.Clientset
kubeConfigPath string
// namespace holds the namespace on which
// kubeclient has to operate
namespace string
// functions useful during mocking
getClientset getClientsetFn
getClientsetForPath getClientsetForPathFn
get getFn
list listFn
del delFn
create createFn
update updateFn
}
// KubeclientBuildOption defines the abstraction
// to build a kubeclient instance
type KubeclientBuildOption func(*Kubeclient)
// defaultGetClientset is the default implementation to
// get kubernetes clientset instance
func defaultGetClientset() (clients *clientset.Clientset, err error) {
config, err := client.GetConfig(client.New())
if err != nil {
return nil, err
}
return clientset.NewForConfig(config)
}
// defaultGetClientsetForPath is the default implementation to
// get kubernetes clientset instance based on the given
// kubeconfig path
func defaultGetClientsetForPath(
kubeConfigPath string,
) (clients *clientset.Clientset, err error) {
config, err := client.GetConfig(
client.New(client.WithKubeConfigPath(kubeConfigPath)))
if err != nil {
return nil, err
}
return clientset.NewForConfig(config)
}
// defaultGet is the default implementation to get
// a zfsrstr rstrume instance in kubernetes cluster
func defaultGet(
cli *clientset.Clientset,
name, namespace string,
opts metav1.GetOptions,
) (*apis.ZFSRestore, error) {
return cli.ZfsV1().
ZFSRestores(namespace).
Get(name, opts)
}
// defaultList is the default implementation to list
// zfsrstr rstrume instances in kubernetes cluster
func defaultList(
cli *clientset.Clientset,
namespace string,
opts metav1.ListOptions,
) (*apis.ZFSRestoreList, error) {
return cli.ZfsV1().
ZFSRestores(namespace).
List(opts)
}
// defaultCreate is the default implementation to delete
// a zfsrstr rstrume instance in kubernetes cluster
func defaultDel(
cli *clientset.Clientset,
name, namespace string,
opts *metav1.DeleteOptions,
) error {
deletePropagation := metav1.DeletePropagationForeground
opts.PropagationPolicy = &deletePropagation
err := cli.ZfsV1().
ZFSRestores(namespace).
Delete(name, opts)
return err
}
// defaultCreate is the default implementation to create
// a zfsrstr rstrume instance in kubernetes cluster
func defaultCreate(
cli *clientset.Clientset,
rstr *apis.ZFSRestore,
namespace string,
) (*apis.ZFSRestore, error) {
return cli.ZfsV1().
ZFSRestores(namespace).
Create(rstr)
}
// defaultUpdate is the default implementation to update
// a zfsrstr rstrume instance in kubernetes cluster
func defaultUpdate(
cli *clientset.Clientset,
rstr *apis.ZFSRestore,
namespace string,
) (*apis.ZFSRestore, error) {
return cli.ZfsV1().
ZFSRestores(namespace).
Update(rstr)
}
// withDefaults sets the default options
// of kubeclient instance
func (k *Kubeclient) withDefaults() {
if k.getClientset == nil {
k.getClientset = defaultGetClientset
}
if k.getClientsetForPath == nil {
k.getClientsetForPath = defaultGetClientsetForPath
}
if k.get == nil {
k.get = defaultGet
}
if k.list == nil {
k.list = defaultList
}
if k.del == nil {
k.del = defaultDel
}
if k.create == nil {
k.create = defaultCreate
}
if k.update == nil {
k.update = defaultUpdate
}
}
// WithClientSet sets the kubernetes client against
// the kubeclient instance
func WithClientSet(c *clientset.Clientset) KubeclientBuildOption {
return func(k *Kubeclient) {
k.clientset = c
}
}
// WithNamespace sets the kubernetes client against
// the provided namespace
func WithNamespace(namespace string) KubeclientBuildOption {
return func(k *Kubeclient) {
k.namespace = namespace
}
}
// WithNamespace sets the provided namespace
// against this Kubeclient instance
func (k *Kubeclient) WithNamespace(namespace string) *Kubeclient {
k.namespace = namespace
return k
}
// WithKubeConfigPath sets the kubernetes client
// against the provided path
func WithKubeConfigPath(path string) KubeclientBuildOption {
return func(k *Kubeclient) {
k.kubeConfigPath = path
}
}
// NewKubeclient returns a new instance of
// kubeclient meant for zfsrstr rstrume operations
func NewKubeclient(opts ...KubeclientBuildOption) *Kubeclient {
k := &Kubeclient{}
for _, o := range opts {
o(k)
}
k.withDefaults()
return k
}
func (k *Kubeclient) getClientsetForPathOrDirect() (
*clientset.Clientset,
error,
) {
if k.kubeConfigPath != "" {
return k.getClientsetForPath(k.kubeConfigPath)
}
return k.getClientset()
}
// getClientOrCached returns either a new instance
// of kubernetes client or its cached copy
func (k *Kubeclient) getClientOrCached() (*clientset.Clientset, error) {
if k.clientset != nil {
return k.clientset, nil
}
c, err := k.getClientsetForPathOrDirect()
if err != nil {
return nil,
errors.Wrapf(
err,
"failed to get clientset",
)
}
k.clientset = c
return k.clientset, nil
}
// Create creates a zfsrstr rstrume instance
// in kubernetes cluster
func (k *Kubeclient) Create(rstr *apis.ZFSRestore) (*apis.ZFSRestore, error) {
if rstr == nil {
return nil,
errors.New(
"failed to create csirstrume: nil rstr object",
)
}
cs, err := k.getClientOrCached()
if err != nil {
return nil, errors.Wrapf(
err,
"failed to create zfsrstr rstrume {%s} in namespace {%s}",
rstr.Name,
k.namespace,
)
}
return k.create(cs, rstr, k.namespace)
}
// Get returns zfsrstr rstrume object for given name
func (k *Kubeclient) Get(
name string,
opts metav1.GetOptions,
) (*apis.ZFSRestore, error) {
if name == "" {
return nil,
errors.New(
"failed to get zfsrstr rstrume: missing zfsrstr rstrume name",
)
}
cli, err := k.getClientOrCached()
if err != nil {
return nil, errors.Wrapf(
err,
"failed to get zfsrstr rstrume {%s} in namespace {%s}",
name,
k.namespace,
)
}
return k.get(cli, name, k.namespace, opts)
}
// GetRaw returns zfsrstr rstrume instance
// in bytes
func (k *Kubeclient) GetRaw(
name string,
opts metav1.GetOptions,
) ([]byte, error) {
if name == "" {
return nil, errors.New(
"failed to get raw zfsrstr rstrume: missing rstr name",
)
}
csiv, err := k.Get(name, opts)
if err != nil {
return nil, errors.Wrapf(
err,
"failed to get zfsrstr rstrume {%s} in namespace {%s}",
name,
k.namespace,
)
}
return json.Marshal(csiv)
}
// List returns a list of zfsrstr rstrume
// instances present in kubernetes cluster
func (k *Kubeclient) List(opts metav1.ListOptions) (*apis.ZFSRestoreList, error) {
cli, err := k.getClientOrCached()
if err != nil {
return nil, errors.Wrapf(
err,
"failed to list zfsrstr rstrumes in namespace {%s}",
k.namespace,
)
}
return k.list(cli, k.namespace, opts)
}
// Delete deletes the zfsrstr rstrume from
// kubernetes
func (k *Kubeclient) Delete(name string) error {
if name == "" {
return errors.New(
"failed to delete csirstrume: missing rstr name",
)
}
cli, err := k.getClientOrCached()
if err != nil {
return errors.Wrapf(
err,
"failed to delete csirstrume {%s} in namespace {%s}",
name,
k.namespace,
)
}
return k.del(cli, name, k.namespace, &metav1.DeleteOptions{})
}
// Update updates this zfsrstr rstrume instance
// against kubernetes cluster
func (k *Kubeclient) Update(rstr *apis.ZFSRestore) (*apis.ZFSRestore, error) {
if rstr == nil {
return nil,
errors.New(
"failed to update csirstrume: nil rstr object",
)
}
cs, err := k.getClientOrCached()
if err != nil {
return nil, errors.Wrapf(
err,
"failed to update csirstrume {%s} in namespace {%s}",
rstr.Name,
rstr.Namespace,
)
}
return k.update(cs, rstr, k.namespace)
}