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

New functions to pre-provision VolumeSnapshot and VolumeSnapshotContent #1282

Merged
merged 13 commits into from
Mar 23, 2022
Merged
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
ihcsim marked this conversation as resolved.
Show resolved Hide resolved
------------------

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


DeleteCSISnapshotContent
ihcsim marked this conversation as resolved.
Show resolved Hide resolved
------------------------

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