Skip to content

Commit

Permalink
New functions to pre-provision VolumeSnapshot and VolumeSnapshotConte…
Browse files Browse the repository at this point in the history
…nt (#1282)

* Add the new CreateCSISnapshotStatuc and DeleteCSISnapshotContent functions

The new 'create' function allows user to pre-provision a pair of
VolumeSnapshot and VolumeSnapshotContent resources, which aren't associated
with any existing PersistentVolumeClaim resource.

See https://kubernetes.io/docs/concepts/storage/volume-snapshots/ for
the difference between dynamic and pre-provisioned snapshots.

Signed-off-by: Ivan Sim <ivan.sim@kasten.io>

* Update gitignore

Signed-off-by: Ivan Sim <ivan.sim@kasten.io>

* Update controller RBAC to manage snapshot class

Signed-off-by: Ivan Sim <ivan.sim@kasten.io>

* Update documentation

Signed-off-by: Ivan Sim <ivan.sim@kasten.io>

* Address Vivek's feedback

Signed-off-by: Ivan Sim <ivan.sim@kasten.io>

* Add suffix to distinguish input/output Variables

Co-authored-by: Pavan Navarathna <pavan@kasten.io>

* Add newline to method signature

Co-authored-by: Pavan Navarathna <pavan@kasten.io>

* Update documentation

Signed-off-by: Ivan Sim <ivan.sim@kasten.io>

* Change testSuite fields to local constants

Signed-off-by: Ivan Sim <ivan.sim@kasten.io>

* Fix gofmt issues from GH assisted-commit

Signed-off-by: Ivan Sim <ivan.sim@kasten.io>

Co-authored-by: Pavan Navarathna <pavan@kasten.io>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
3 people committed Mar 23, 2022
1 parent 428c402 commit e3e762e
Show file tree
Hide file tree
Showing 8 changed files with 561 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
/.vendor
/bin
/dist
**/*.swp
85 changes: 85 additions & 0 deletions docs/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1332,6 +1332,61 @@ Example:
snapshotClass: do-block-storage
CreateCSISnapshotStatic
-----------------------

This function creates a pair of CSI ``VolumeSnapshot`` and
``VolumeSnapshotContent`` resources, assuming that the underlying *real* storage
volume snapshot already exists. The deletion behavior is defined by the
``deletionPolicy`` property (``Retain``, ``Delete``) of the snapshot class.

For more information on pre-provisioned volume snapshots and snapshot deletion
policy, see the Kubernetes `documentation
<https://kubernetes.io/docs/concepts/storage/volume-snapshots/>`_.

Arguments:

.. csv-table::
:header: "Argument", "Required", "Type", "Description"
:align: left
:widths: 5,5,5,15

`name`, Yes, `string`, name of the new CSI ``VolumeSnapshot``
`namespace`, Yes, `string`, namespace of the new CSI ``VolumeSnapshot``
`driver`, Yes, `string`, name of the CSI driver for the new CSI ``VolumeSnapshotContent``
`handle`, Yes, `string`, unique identifier of the volume snapshot created on the storage backend used as the source of the new ``VolumeSnapshotContent``
`snapshotClass`, Yes, `string`, name of the ``VolumeSnapshotClass`` to use

Outputs:

.. csv-table::
:header: "Output", "Type", "Description"
:align: left
:widths: 5,5,15

`name`,`string`, name of the new CSI ``VolumeSnapshot``
`namespace`, string, namespace of the new CSI ``VolumeSnapshot``
`restoreSize`, string, required memory size to restore the volume
`snapshotContent`, string, name of the new CSI ``VolumeSnapshotContent``

Example:

.. code-block:: yaml
:linenos:
actions:
createStaticSnapshot:
phases:
- func: CreateCSISnapshotStatic
name: createCSISnapshotStatic
args:
name: volume-snapshot
namespace: default
snapshotClass: csi-hostpath-snapclass
driver: hostpath.csi.k8s.io
handle: 7bdd0de3-aaeb-11e8-9aae-0242ac110002
RestoreCSISnapshot
------------------

Expand Down Expand Up @@ -1413,6 +1468,36 @@ Example:
namespace: "{{ .ArtifactsIn.snapshotInfo.KeyValue.namespace }}"
DeleteCSISnapshotContent
------------------------

This function deletes an unbounded ``VolumeSnapshotContent`` resource. It has no
effect on bounded ``VolumeSnapshotContent`` resources, as they would be
protected by the CSI controller.

Arguments:

.. csv-table::
:header: "Argument", "Required", "Type", "Description"
:align: left
:widths: 5,5,5,15

`name`, Yes, `string`, name of the ``VolumeSnapshotContent``

Example:

.. code-block:: yaml
:linenos:
actions:
deleteVSC:
phases:
- func: DeleteCSISnapshotContent
name: deleteCSISnapshotContent
args:
name: "test-snapshot-content-content-dfc8fa67-8b11-4fdf-bf94-928589c2eed8"
Registering Functions
---------------------

Expand Down
2 changes: 2 additions & 0 deletions docs/spelling_wordlist.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
actionset
args
aws
backend
backupIdentifier
backupID
backupInfo
Expand Down Expand Up @@ -29,6 +30,7 @@ param
params
PersistentVolumeClaim
pluggable
pre
prepopulated
Quickstart
repo
Expand Down
1 change: 1 addition & 0 deletions helm/kanister-operator/templates/rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ rules:
resources:
- volumesnapshots
- volumesnapshotcontents
- volumesnapshotclasses
verbs:
- get
- create
Expand Down
160 changes: 160 additions & 0 deletions pkg/function/create_csi_snapshot_static.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// Copyright 2022 The Kanister 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 function

import (
"context"

v1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"

kanister "github.com/kanisterio/kanister/pkg"
"github.com/kanisterio/kanister/pkg/kube"
"github.com/kanisterio/kanister/pkg/kube/snapshot"
"github.com/kanisterio/kanister/pkg/param"
)

func init() {
_ = kanister.Register(&createCSISnapshotStaticFunc{})
}

var (
_ kanister.Func = (*createCSISnapshotStaticFunc)(nil)
)

const (
// CreateCSISnapshotStaticFuncName gives the name of the function
CreateCSISnapshotStaticFuncName = "CreateCSISnapshotStatic"

// CreateCSISnapshotStaticNameArg provides name of the new VolumeSnapshot
CreateCSISnapshotStaticNameArg = "name"

// CreateCSISnapshotStaticNamespaceArg specifies the namespace of the new VolumeSnapshot
CreateCSISnapshotStaticNamespaceArg = "namespace"

// CreateCSISnapshotStaticDriverArg specifies the CSI driver used in the new VolumeSnapshotContent
CreateCSISnapshotStaticDriverArg = "driver"

// CreateCSISnapshotStaticSnapshotHandleArg specifies the UID of the backend storage snapshot used in the new VolumeSnapshotContent
CreateCSISnapshotStaticSnapshotHandleArg = "snapshotHandle"

// CreateCSISnapshotStaticSnapshotClassArg specifies the name of the VolumeSnapshotClass
CreateCSISnapshotStaticSnapshotClassArg = "snapshotClass"

// CreateCSISnapshotStaticOutputRestoreSize gives the storage size required for PV/PVC restoration
CreateCSISnapshotStaticOutputRestoreSize = "restoreSize"

// CreateCSISnapshotStaticOutputSnapshotContentName provides the name of dynamically provisioned VolumeSnapshotContent
CreateCSISnapshotStaticOutputSnapshotContentName = "snapshotContent"
)

type createCSISnapshotStaticFunc struct{}

func (*createCSISnapshotStaticFunc) Name() string {
return CreateCSISnapshotStaticFuncName
}

func (*createCSISnapshotStaticFunc) Exec(ctx context.Context, tp param.TemplateParams, args map[string]interface{}) (map[string]interface{}, error) {
var (
name, namespace string
driver, snapshotHandle, snapshotClass string
)

if err := Arg(args, CreateCSISnapshotStaticNameArg, &name); err != nil {
return nil, err
}

if err := Arg(args, CreateCSISnapshotStaticNamespaceArg, &namespace); err != nil {
return nil, err
}

if err := Arg(args, CreateCSISnapshotStaticDriverArg, &driver); err != nil {
return nil, err
}

if err := Arg(args, CreateCSISnapshotStaticSnapshotHandleArg, &snapshotHandle); err != nil {
return nil, err
}

if err := Arg(args, CreateCSISnapshotStaticSnapshotClassArg, &snapshotClass); err != nil {
return nil, err
}

kubeCli, err := kube.NewClient()
if err != nil {
return nil, err
}

dynCli, err := kube.NewDynamicClient()
if err != nil {
return nil, err
}

snapshotter, err := snapshot.NewSnapshotter(kubeCli, dynCli)
if err != nil {
return nil, err
}

// waitForReady is set to true by default because snapshot information is needed as output artifacts
waitForReady := true
vs, err := createCSISnapshotStatic(ctx, snapshotter, name, namespace, driver, snapshotHandle, snapshotClass, waitForReady)
if err != nil {
return nil, err
}

return map[string]interface{}{
CreateCSISnapshotStaticNameArg: name,
CreateCSISnapshotStaticNamespaceArg: namespace,
CreateCSISnapshotStaticOutputRestoreSize: vs.Status.RestoreSize.String(),
CreateCSISnapshotStaticOutputSnapshotContentName: vs.Status.BoundVolumeSnapshotContentName,
}, nil
}

func (*createCSISnapshotStaticFunc) RequiredArgs() []string {
return []string{
CreateCSISnapshotStaticNameArg,
CreateCSISnapshotStaticNamespaceArg,
CreateCSISnapshotStaticDriverArg,
CreateCSISnapshotStaticSnapshotHandleArg,
CreateCSISnapshotStaticSnapshotClassArg,
}
}

func (*createCSISnapshotStaticFunc) Arguments() []string {
return []string{
CreateCSISnapshotStaticNameArg,
CreateCSISnapshotStaticNamespaceArg,
CreateCSISnapshotStaticDriverArg,
CreateCSISnapshotStaticSnapshotHandleArg,
CreateCSISnapshotStaticSnapshotClassArg,
}
}

func createCSISnapshotStatic(
ctx context.Context,
snapshotter snapshot.Snapshotter,
name, namespace, driver, snapshotHandle, snapshotClass string,
wait bool,
) (*v1.VolumeSnapshot, error) {
source := &snapshot.Source{
Handle: snapshotHandle,
Driver: driver,
VolumeSnapshotClassName: snapshotClass,
}
if err := snapshotter.CreateFromSource(ctx, source, name, namespace, wait); err != nil {
return nil, err
}

return snapshotter.Get(ctx, name, namespace)
}
Loading

0 comments on commit e3e762e

Please sign in to comment.