Skip to content

Commit

Permalink
Adding a Kanister function to delete CSI VolumeSnapshot (#1172)
Browse files Browse the repository at this point in the history
* Added new function RestoreCSISnapshot

* reviewer comments

* Fixed failed to render outputartifact template 'snapshotInfo' issue

* Updated const comments

* Updated the return obj for the function

* Added documentation for RestoreCSISnapshot function

* Added test suite for RestoreCSISnapshot func

* gofmt update

* Reviewer comments

* Updated the testcase for RestoreCSISnapshot function

* Updated the createPVC method in testcase

* Fixed RBAC YAML

* Added the DeleteCSISnapshot function

* Added RBAC updates

* Added testcase for DeleteCSISnapshot function

* gofmt fix

* Added documentation for DeleteCSISnapshot function

* Updated the namespace in testcase

* Added validations for volumeMode and accessMode

* Updated the logic to validate volume mode

* context update

* context update

* Fixed the validateVolumeModeArg method

* Added testcase for arg validation

* gofmt updates

* Added Note in the docs

* Added table driven testcases for validate methods

* Removed multiple context.Background() calls and removed the validate method calls in main test case

* style: Add whitespace in error messages

* refactor: Update const names in test files

* refactor: Update length of random alphanumeric suffix to 5 characters

* refactor: Update const in test file

* refactor: Update argument validation methods

* style: Fix typo in a comment

* refactor: Update call to validate methods in restore unit test

* refactor: Update restore test case as per reviewer comment

* refactor: Update CreateCSiSnapshot function and the test case

* refactor: Revert random alphanumeric string length

* fix: gofmt error

* refactor: Update CreateCSiSnapshot function and the test case

* refactor: Update CreateCSiSnapshot function and the test case

* refactor: Update CreateCSiSnapshot function and the test case

* refactor: Moved code out of Exec method

* chore: Update signature of the restoreCSISnapshot method

* refactor: Revert CreateCSISnapshot Func changes in this PR

* refactor: Update create snapshot unit test

* fix: CI failure

* chore: Comment update

* fix: golangci-lint fix

* Comment update in delete snapshot unit test

* Update comment in delete snapshot unit test

* Update for CI re-run

* Fix CI issue MySQL GPG failed

Please refer the bug logged at https://bugs.mysql.com/bug.php\?id\=106188 for more details

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
Shlok Chaudhari and mergify[bot] committed Jan 19, 2022
1 parent b10d298 commit cdc321c
Show file tree
Hide file tree
Showing 3 changed files with 258 additions and 0 deletions.
35 changes: 35 additions & 0 deletions docs/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1374,6 +1374,41 @@ Example:
volumeMode: "Filesystem"
DeleteCSISnapshot
-----------------

This function deletes a VolumeSnapshot from given namespace.

Arguments:

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

`name`, Yes, `string`, name of the VolumeSnapshot
`namespace`, Yes, `string`, namespace of the VolumeSnapshot

.. note::
Output artifact ``snapshotInfo`` from ``CreateCSISnapshot`` function can be used as an input artifact in this function.

Example:

.. code-block:: yaml
:linenos:
actions:
delete:
inputArtifactNames:
- snapshotInfo
phases:
- func: DeleteCSISnapshot
name: deleteCSISnapshot
args:
name: "{{ .ArtifactsIn.snapshotInfo.KeyValue.name }}"
namespace: "{{ .ArtifactsIn.snapshotInfo.KeyValue.namespace }}"
Registering Functions
---------------------

Expand Down
86 changes: 86 additions & 0 deletions pkg/function/delete_csi_snapshot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// 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(&deleteCSISnapshotFunc{})
}

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

const (
// DeleteCSIVolumeSnapshotFuncName gives the name of the function
DeleteCSISnapshotFuncName = "DeleteCSISnapshot"
// DeleteCSISnapshotNameArg provides name of the VolumeSnapshot that needs to be deleted
DeleteCSISnapshotNameArg = "name"
// DeleteCSISnapshotNamespaceArg mentions the namespace where the VolumeSnapshot resides
DeleteCSISnapshotNamespaceArg = "namespace"
)

type deleteCSISnapshotFunc struct{}

func (*deleteCSISnapshotFunc) Name() string {
return DeleteCSISnapshotFuncName
}

func (*deleteCSISnapshotFunc) Exec(ctx context.Context, tp param.TemplateParams, args map[string]interface{}) (map[string]interface{}, error) {
var name, namespace string
if err := Arg(args, DeleteCSISnapshotNameArg, &name); err != nil {
return nil, err
}
if err := Arg(args, DeleteCSISnapshotNamespaceArg, &namespace); 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
}
if _, err := deleteCSISnapshot(ctx, snapshotter, name, namespace); err != nil {
return nil, err
}
return nil, nil
}

func (*deleteCSISnapshotFunc) RequiredArgs() []string {
return []string{
DeleteCSISnapshotNameArg,
DeleteCSISnapshotNamespaceArg,
}
}

func deleteCSISnapshot(ctx context.Context, snapshotter snapshot.Snapshotter, name, namespace string) (*v1.VolumeSnapshot, error) {
return snapshotter.Delete(ctx, name, namespace)
}
137 changes: 137 additions & 0 deletions pkg/function/delete_csi_snapshot_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// 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"

. "gopkg.in/check.v1"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
dynfake "k8s.io/client-go/dynamic/fake"
"k8s.io/client-go/kubernetes/fake"

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

const (
// testDeleteNamespace specifies the namespace where testing is done
testDeleteNamespace = "test-delete-csi-snapshot"
)

type DeleteCSISnapshotTestSuite struct {
snapName string
pvcName string
newPVCName string
namespace string
volumeSnapshotClass string
storageClass string
}

var _ = Suite(&DeleteCSISnapshotTestSuite{})

func (testSuite *DeleteCSISnapshotTestSuite) SetUpSuite(c *C) {
testSuite.volumeSnapshotClass = snapshotClass
testSuite.storageClass = storageClass
testSuite.pvcName = originalPVCName
testSuite.newPVCName = newPVCName
testSuite.snapName = snapshotName
testSuite.namespace = testDeleteNamespace
}

func (testSuite *DeleteCSISnapshotTestSuite) TestDeleteCSISnapshot(c *C) {
for _, apiResourceList := range []*metav1.APIResourceList{
{
TypeMeta: metav1.TypeMeta{
Kind: "VolumeSnapshot",
APIVersion: "v1alpha1",
},
GroupVersion: "snapshot.storage.k8s.io/v1alpha1",
},
{
TypeMeta: metav1.TypeMeta{
Kind: "VolumeSnapshot",
APIVersion: "v1beta1",
},
GroupVersion: "snapshot.storage.k8s.io/v1beta1",
},
{
TypeMeta: metav1.TypeMeta{
Kind: "VolumeSnapshot",
APIVersion: "v1",
},
GroupVersion: "snapshot.storage.k8s.io/v1",
},
} {
ctx := context.Background()
fakeCli := fake.NewSimpleClientset()
fakeCli.Resources = []*metav1.APIResourceList{apiResourceList}

_, err := fakeCli.CoreV1().Namespaces().Create(ctx, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: testSuite.namespace}}, metav1.CreateOptions{})
c.Assert(err, IsNil)

scheme := runtime.NewScheme()
fakeSnapshotter, err := snapshot.NewSnapshotter(fakeCli, dynfake.NewSimpleDynamicClient(scheme))
c.Assert(err, IsNil)

originalPVC := &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: testSuite.pvcName,
},
Spec: v1.PersistentVolumeClaimSpec{
StorageClassName: &testSuite.storageClass,
AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce},
Resources: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceStorage: resource.MustParse("1Gi"),
},
},
},
}
_, err = fakeCli.CoreV1().PersistentVolumeClaims(testSuite.namespace).Create(ctx, originalPVC, metav1.CreateOptions{})
c.Assert(err, IsNil)

err = fakeSnapshotter.Create(ctx, testSuite.snapName, testSuite.namespace, testSuite.pvcName, &testSuite.volumeSnapshotClass, false, nil)
c.Assert(err, IsNil)

vs, err := fakeSnapshotter.Get(ctx, testSuite.snapName, testSuite.namespace)
c.Assert(err, IsNil)
c.Assert(vs.Name, Equals, testSuite.snapName)

restoreArgs := restoreCSISnapshotArgs{
Name: testSuite.snapName,
PVC: testSuite.newPVCName,
Namespace: testSuite.namespace,
StorageClass: testSuite.storageClass,
RestoreSize: originalPVC.Spec.Resources.Requests.Storage(),
AccessModes: originalPVC.Spec.AccessModes,
Labels: nil,
}
newPVC := newPVCManifest(restoreArgs)
_, err = fakeCli.CoreV1().PersistentVolumeClaims(restoreArgs.Namespace).Create(ctx, newPVC, metav1.CreateOptions{})
c.Assert(err, IsNil)
c.Assert(newPVC.Name, Equals, testSuite.newPVCName)

_, err = deleteCSISnapshot(ctx, fakeSnapshotter, testSuite.snapName, testSuite.namespace)
c.Assert(err, IsNil)
_, err = fakeSnapshotter.Get(ctx, testSuite.snapName, testSuite.namespace)
c.Assert(err, NotNil)

err = fakeCli.CoreV1().Namespaces().Delete(ctx, testSuite.namespace, metav1.DeleteOptions{})
c.Assert(err, IsNil)
}
}

0 comments on commit cdc321c

Please sign in to comment.