diff --git a/pkg/function/create_csi_snapshot.go b/pkg/function/create_csi_snapshot.go index fde31a2c72..4e999c135b 100644 --- a/pkg/function/create_csi_snapshot.go +++ b/pkg/function/create_csi_snapshot.go @@ -143,7 +143,13 @@ func (*createCSISnapshotFunc) Arguments() []string { } func createCSISnapshot(ctx context.Context, snapshotter snapshot.Snapshotter, name, namespace, pvc, snapshotClass string, wait bool, labels map[string]string) (*v1.VolumeSnapshot, error) { - if err := snapshotter.Create(ctx, name, namespace, pvc, &snapshotClass, wait, labels); err != nil { + snapshotMeta := snapshot.ObjectMeta{ + Name: name, + Namespace: namespace, + Labels: labels, + Annotations: nil, + } + if err := snapshotter.Create(ctx, pvc, &snapshotClass, wait, snapshotMeta); err != nil { return nil, err } vs, err := snapshotter.Get(ctx, name, namespace) diff --git a/pkg/function/create_csi_snapshot_static.go b/pkg/function/create_csi_snapshot_static.go index d82c96142f..ae741b688e 100644 --- a/pkg/function/create_csi_snapshot_static.go +++ b/pkg/function/create_csi_snapshot_static.go @@ -162,7 +162,12 @@ func createCSISnapshotStatic( Driver: driver, VolumeSnapshotClassName: snapshotClass, } - if err := snapshotter.CreateFromSource(ctx, source, name, namespace, wait, nil); err != nil { + snapshotMeta := snapshot.ObjectMeta{ + Name: name, + Namespace: namespace, + } + snapshotContentMeta := snapshot.ObjectMeta{} + if err := snapshotter.CreateFromSource(ctx, source, wait, snapshotMeta, snapshotContentMeta); err != nil { return nil, err } diff --git a/pkg/function/delete_csi_snapshot_content_test.go b/pkg/function/delete_csi_snapshot_content_test.go index 5ab0e94328..14c9db2d70 100644 --- a/pkg/function/delete_csi_snapshot_content_test.go +++ b/pkg/function/delete_csi_snapshot_content_test.go @@ -82,11 +82,11 @@ func (testSuite *DeleteCSISnapshotContentTestSuite) TestDeleteCSISnapshotContent Driver: driver, VolumeSnapshotClassName: snapshotClassName, } - err = fakeSnapshotter.CreateContentFromSource(ctx, source, - snapshotContentName, - snapshotName, - snapshotNamespace, - deletionPolicy) + fakeSnapshotContentMeta := snapshot.ObjectMeta{ + Name: snapshotContentName, + } + err = fakeSnapshotter.CreateContentFromSource(ctx, source, snapshotName, + snapshotNamespace, deletionPolicy, fakeSnapshotContentMeta) c.Assert(err, IsNil) gv := strings.Split(api.GroupVersion, "/") diff --git a/pkg/function/delete_csi_snapshot_test.go b/pkg/function/delete_csi_snapshot_test.go index 41ba3dc4b3..2814dc6fb2 100644 --- a/pkg/function/delete_csi_snapshot_test.go +++ b/pkg/function/delete_csi_snapshot_test.go @@ -104,8 +104,11 @@ func (testSuite *DeleteCSISnapshotTestSuite) TestDeleteCSISnapshot(c *C) { } _, 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) + fakeSnapshotMeta := snapshot.ObjectMeta{ + Name: testSuite.snapName, + Namespace: testSuite.namespace, + } + err = fakeSnapshotter.Create(ctx, testSuite.pvcName, &testSuite.volumeSnapshotClass, false, fakeSnapshotMeta) c.Assert(err, IsNil) vs, err := fakeSnapshotter.Get(ctx, testSuite.snapName, testSuite.namespace) diff --git a/pkg/function/restore_csi_snapshot_test.go b/pkg/function/restore_csi_snapshot_test.go index b101179929..9a2ddb590b 100644 --- a/pkg/function/restore_csi_snapshot_test.go +++ b/pkg/function/restore_csi_snapshot_test.go @@ -94,8 +94,11 @@ func (testSuite *RestoreCSISnapshotTestSuite) TestRestoreCSISnapshot(c *C) { originalPVC := getOriginalPVCManifest(testSuite.pvcName, testSuite.storageClass) createPVC(c, testSuite.namespace, originalPVC, fakeCli) - - err = fakeSnapshotter.Create(ctx, testSuite.snapName, testSuite.namespace, testSuite.pvcName, &testSuite.volumeSnapshotClass, false, nil) + fakeSnapshotMeta := snapshot.ObjectMeta{ + Name: testSuite.snapName, + Namespace: testSuite.namespace, + } + err = fakeSnapshotter.Create(ctx, testSuite.pvcName, &testSuite.volumeSnapshotClass, false, fakeSnapshotMeta) c.Assert(err, IsNil) vs, err := fakeSnapshotter.Get(ctx, testSuite.snapName, testSuite.namespace) diff --git a/pkg/kube/snapshot/mocks/mock_snapshotter.go b/pkg/kube/snapshot/mocks/mock_snapshotter.go index 21fe6449af..00dbca011d 100644 --- a/pkg/kube/snapshot/mocks/mock_snapshotter.go +++ b/pkg/kube/snapshot/mocks/mock_snapshotter.go @@ -39,188 +39,188 @@ func (m *MockSnapshotter) EXPECT() *MockSnapshotterMockRecorder { } // Clone mocks base method. -func (m *MockSnapshotter) Clone(arg0 context.Context, arg1, arg2, arg3, arg4 string, arg5 bool, arg6 map[string]string) error { +func (m *MockSnapshotter) Clone(ctx context.Context, name, namespace string, waitForReady bool, snapshotMeta, snapshotContentMeta snapshot.ObjectMeta) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Clone", arg0, arg1, arg2, arg3, arg4, arg5, arg6) + ret := m.ctrl.Call(m, "Clone", ctx, name, namespace, waitForReady, snapshotMeta, snapshotContentMeta) ret0, _ := ret[0].(error) return ret0 } // Clone indicates an expected call of Clone. -func (mr *MockSnapshotterMockRecorder) Clone(arg0, arg1, arg2, arg3, arg4, arg5, arg6 interface{}) *gomock.Call { +func (mr *MockSnapshotterMockRecorder) Clone(ctx, name, namespace, waitForReady, snapshotMeta, snapshotContentMeta interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Clone", reflect.TypeOf((*MockSnapshotter)(nil).Clone), arg0, arg1, arg2, arg3, arg4, arg5, arg6) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Clone", reflect.TypeOf((*MockSnapshotter)(nil).Clone), ctx, name, namespace, waitForReady, snapshotMeta, snapshotContentMeta) } // CloneVolumeSnapshotClass mocks base method. -func (m *MockSnapshotter) CloneVolumeSnapshotClass(arg0 context.Context, arg1, arg2, arg3 string, arg4 []string) error { +func (m *MockSnapshotter) CloneVolumeSnapshotClass(ctx context.Context, sourceClassName, targetClassName, newDeletionPolicy string, excludeAnnotations []string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CloneVolumeSnapshotClass", arg0, arg1, arg2, arg3, arg4) + ret := m.ctrl.Call(m, "CloneVolumeSnapshotClass", ctx, sourceClassName, targetClassName, newDeletionPolicy, excludeAnnotations) ret0, _ := ret[0].(error) return ret0 } // CloneVolumeSnapshotClass indicates an expected call of CloneVolumeSnapshotClass. -func (mr *MockSnapshotterMockRecorder) CloneVolumeSnapshotClass(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { +func (mr *MockSnapshotterMockRecorder) CloneVolumeSnapshotClass(ctx, sourceClassName, targetClassName, newDeletionPolicy, excludeAnnotations interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloneVolumeSnapshotClass", reflect.TypeOf((*MockSnapshotter)(nil).CloneVolumeSnapshotClass), arg0, arg1, arg2, arg3, arg4) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloneVolumeSnapshotClass", reflect.TypeOf((*MockSnapshotter)(nil).CloneVolumeSnapshotClass), ctx, sourceClassName, targetClassName, newDeletionPolicy, excludeAnnotations) } // Create mocks base method. -func (m *MockSnapshotter) Create(arg0 context.Context, arg1, arg2, arg3 string, arg4 *string, arg5 bool, arg6 map[string]string) error { +func (m *MockSnapshotter) Create(ctx context.Context, pvcName string, snapshotClass *string, waitForReady bool, snapshotMeta snapshot.ObjectMeta) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Create", arg0, arg1, arg2, arg3, arg4, arg5, arg6) + ret := m.ctrl.Call(m, "Create", ctx, pvcName, snapshotClass, waitForReady, snapshotMeta) ret0, _ := ret[0].(error) return ret0 } // Create indicates an expected call of Create. -func (mr *MockSnapshotterMockRecorder) Create(arg0, arg1, arg2, arg3, arg4, arg5, arg6 interface{}) *gomock.Call { +func (mr *MockSnapshotterMockRecorder) Create(ctx, pvcName, snapshotClass, waitForReady, snapshotMeta interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockSnapshotter)(nil).Create), arg0, arg1, arg2, arg3, arg4, arg5, arg6) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockSnapshotter)(nil).Create), ctx, pvcName, snapshotClass, waitForReady, snapshotMeta) } // CreateContentFromSource mocks base method. -func (m *MockSnapshotter) CreateContentFromSource(arg0 context.Context, arg1 *snapshot.Source, arg2, arg3, arg4, arg5 string) error { +func (m *MockSnapshotter) CreateContentFromSource(ctx context.Context, source *snapshot.Source, snapshotName, namespace, deletionPolicy string, snapshotContentMeta snapshot.ObjectMeta) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateContentFromSource", arg0, arg1, arg2, arg3, arg4, arg5) + ret := m.ctrl.Call(m, "CreateContentFromSource", ctx, source, snapshotName, namespace, deletionPolicy, snapshotContentMeta) ret0, _ := ret[0].(error) return ret0 } // CreateContentFromSource indicates an expected call of CreateContentFromSource. -func (mr *MockSnapshotterMockRecorder) CreateContentFromSource(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call { +func (mr *MockSnapshotterMockRecorder) CreateContentFromSource(ctx, source, snapshotName, namespace, deletionPolicy, snapshotContentMeta interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateContentFromSource", reflect.TypeOf((*MockSnapshotter)(nil).CreateContentFromSource), arg0, arg1, arg2, arg3, arg4, arg5) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateContentFromSource", reflect.TypeOf((*MockSnapshotter)(nil).CreateContentFromSource), ctx, source, snapshotName, namespace, deletionPolicy, snapshotContentMeta) } // CreateFromSource mocks base method. -func (m *MockSnapshotter) CreateFromSource(arg0 context.Context, arg1 *snapshot.Source, arg2, arg3 string, arg4 bool, arg5 map[string]string) error { +func (m *MockSnapshotter) CreateFromSource(ctx context.Context, source *snapshot.Source, waitForReady bool, snapshotMeta, snapshotContentMeta snapshot.ObjectMeta) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateFromSource", arg0, arg1, arg2, arg3, arg4, arg5) + ret := m.ctrl.Call(m, "CreateFromSource", ctx, source, waitForReady, snapshotMeta, snapshotContentMeta) ret0, _ := ret[0].(error) return ret0 } // CreateFromSource indicates an expected call of CreateFromSource. -func (mr *MockSnapshotterMockRecorder) CreateFromSource(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call { +func (mr *MockSnapshotterMockRecorder) CreateFromSource(ctx, source, waitForReady, snapshotMeta, snapshotContentMeta interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateFromSource", reflect.TypeOf((*MockSnapshotter)(nil).CreateFromSource), arg0, arg1, arg2, arg3, arg4, arg5) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateFromSource", reflect.TypeOf((*MockSnapshotter)(nil).CreateFromSource), ctx, source, waitForReady, snapshotMeta, snapshotContentMeta) } // Delete mocks base method. -func (m *MockSnapshotter) Delete(arg0 context.Context, arg1, arg2 string) (*v1.VolumeSnapshot, error) { +func (m *MockSnapshotter) Delete(ctx context.Context, name, namespace string) (*v1.VolumeSnapshot, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Delete", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "Delete", ctx, name, namespace) ret0, _ := ret[0].(*v1.VolumeSnapshot) ret1, _ := ret[1].(error) return ret0, ret1 } // Delete indicates an expected call of Delete. -func (mr *MockSnapshotterMockRecorder) Delete(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockSnapshotterMockRecorder) Delete(ctx, name, namespace interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockSnapshotter)(nil).Delete), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockSnapshotter)(nil).Delete), ctx, name, namespace) } // DeleteContent mocks base method. -func (m *MockSnapshotter) DeleteContent(arg0 context.Context, arg1 string) error { +func (m *MockSnapshotter) DeleteContent(ctx context.Context, name string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteContent", arg0, arg1) + ret := m.ctrl.Call(m, "DeleteContent", ctx, name) ret0, _ := ret[0].(error) return ret0 } // DeleteContent indicates an expected call of DeleteContent. -func (mr *MockSnapshotterMockRecorder) DeleteContent(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockSnapshotterMockRecorder) DeleteContent(ctx, name interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteContent", reflect.TypeOf((*MockSnapshotter)(nil).DeleteContent), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteContent", reflect.TypeOf((*MockSnapshotter)(nil).DeleteContent), ctx, name) } // Get mocks base method. -func (m *MockSnapshotter) Get(arg0 context.Context, arg1, arg2 string) (*v1.VolumeSnapshot, error) { +func (m *MockSnapshotter) Get(ctx context.Context, name, namespace string) (*v1.VolumeSnapshot, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Get", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "Get", ctx, name, namespace) ret0, _ := ret[0].(*v1.VolumeSnapshot) ret1, _ := ret[1].(error) return ret0, ret1 } // Get indicates an expected call of Get. -func (mr *MockSnapshotterMockRecorder) Get(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockSnapshotterMockRecorder) Get(ctx, name, namespace interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockSnapshotter)(nil).Get), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockSnapshotter)(nil).Get), ctx, name, namespace) } // GetSource mocks base method. -func (m *MockSnapshotter) GetSource(arg0 context.Context, arg1, arg2 string) (*snapshot.Source, error) { +func (m *MockSnapshotter) GetSource(ctx context.Context, snapshotName, namespace string) (*snapshot.Source, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSource", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetSource", ctx, snapshotName, namespace) ret0, _ := ret[0].(*snapshot.Source) ret1, _ := ret[1].(error) return ret0, ret1 } // GetSource indicates an expected call of GetSource. -func (mr *MockSnapshotterMockRecorder) GetSource(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockSnapshotterMockRecorder) GetSource(ctx, snapshotName, namespace interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSource", reflect.TypeOf((*MockSnapshotter)(nil).GetSource), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSource", reflect.TypeOf((*MockSnapshotter)(nil).GetSource), ctx, snapshotName, namespace) } // GetVolumeSnapshotClass mocks base method. -func (m *MockSnapshotter) GetVolumeSnapshotClass(arg0 context.Context, arg1, arg2, arg3 string) (string, error) { +func (m *MockSnapshotter) GetVolumeSnapshotClass(ctx context.Context, annotationKey, annotationValue, storageClassName string) (string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetVolumeSnapshotClass", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "GetVolumeSnapshotClass", ctx, annotationKey, annotationValue, storageClassName) ret0, _ := ret[0].(string) ret1, _ := ret[1].(error) return ret0, ret1 } // GetVolumeSnapshotClass indicates an expected call of GetVolumeSnapshotClass. -func (mr *MockSnapshotterMockRecorder) GetVolumeSnapshotClass(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockSnapshotterMockRecorder) GetVolumeSnapshotClass(ctx, annotationKey, annotationValue, storageClassName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVolumeSnapshotClass", reflect.TypeOf((*MockSnapshotter)(nil).GetVolumeSnapshotClass), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVolumeSnapshotClass", reflect.TypeOf((*MockSnapshotter)(nil).GetVolumeSnapshotClass), ctx, annotationKey, annotationValue, storageClassName) } // GroupVersion mocks base method. -func (m *MockSnapshotter) GroupVersion(arg0 context.Context) schema.GroupVersion { +func (m *MockSnapshotter) GroupVersion(ctx context.Context) schema.GroupVersion { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GroupVersion", arg0) + ret := m.ctrl.Call(m, "GroupVersion", ctx) ret0, _ := ret[0].(schema.GroupVersion) return ret0 } // GroupVersion indicates an expected call of GroupVersion. -func (mr *MockSnapshotterMockRecorder) GroupVersion(arg0 interface{}) *gomock.Call { +func (mr *MockSnapshotterMockRecorder) GroupVersion(ctx interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GroupVersion", reflect.TypeOf((*MockSnapshotter)(nil).GroupVersion), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GroupVersion", reflect.TypeOf((*MockSnapshotter)(nil).GroupVersion), ctx) } // List mocks base method. -func (m *MockSnapshotter) List(arg0 context.Context, arg1 string, arg2 map[string]string) (*v1.VolumeSnapshotList, error) { +func (m *MockSnapshotter) List(ctx context.Context, namespace string, labels map[string]string) (*v1.VolumeSnapshotList, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "List", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "List", ctx, namespace, labels) ret0, _ := ret[0].(*v1.VolumeSnapshotList) ret1, _ := ret[1].(error) return ret0, ret1 } // List indicates an expected call of List. -func (mr *MockSnapshotterMockRecorder) List(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockSnapshotterMockRecorder) List(ctx, namespace, labels interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockSnapshotter)(nil).List), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockSnapshotter)(nil).List), ctx, namespace, labels) } // WaitOnReadyToUse mocks base method. -func (m *MockSnapshotter) WaitOnReadyToUse(arg0 context.Context, arg1, arg2 string) error { +func (m *MockSnapshotter) WaitOnReadyToUse(ctx context.Context, snapshotName, namespace string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "WaitOnReadyToUse", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "WaitOnReadyToUse", ctx, snapshotName, namespace) ret0, _ := ret[0].(error) return ret0 } // WaitOnReadyToUse indicates an expected call of WaitOnReadyToUse. -func (mr *MockSnapshotterMockRecorder) WaitOnReadyToUse(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockSnapshotterMockRecorder) WaitOnReadyToUse(ctx, snapshotName, namespace interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitOnReadyToUse", reflect.TypeOf((*MockSnapshotter)(nil).WaitOnReadyToUse), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitOnReadyToUse", reflect.TypeOf((*MockSnapshotter)(nil).WaitOnReadyToUse), ctx, snapshotName, namespace) } diff --git a/pkg/kube/snapshot/snapshot.go b/pkg/kube/snapshot/snapshot.go index 379ef4ed04..8228c9954e 100644 --- a/pkg/kube/snapshot/snapshot.go +++ b/pkg/kube/snapshot/snapshot.go @@ -56,13 +56,11 @@ type Snapshotter interface { CloneVolumeSnapshotClass(ctx context.Context, sourceClassName, targetClassName, newDeletionPolicy string, excludeAnnotations []string) error // Create creates a VolumeSnapshot and returns it or any error happened meanwhile. // - // 'name' is the name of the VolumeSnapshot. - // 'namespace' is namespace of the PVC. VolumeSnapshot will be crated in the same namespace. // 'pvcName' is the name of the PVC of which we will take snapshot. It must be in the same namespace 'ns'. // 'waitForReady' will block the caller until the snapshot status is 'ReadyToUse'. // or 'ctx.Done()' is signalled. Otherwise it will return immediately after the snapshot is cut. - // 'labels' can also be addded to the volume snapshot. - Create(ctx context.Context, name, namespace, pvcName string, snapshotClass *string, waitForReady bool, labels map[string]string) error + // 'snapshotMeta' has metadata of the VolumeSnapshot resource that is going to get created. + Create(ctx context.Context, pvcName string, snapshotClass *string, waitForReady bool, snapshotMeta ObjectMeta) error // Get will return the VolumeSnapshot in the namespace 'namespace' with given 'name'. // // 'name' is the name of the VolumeSnapshot that will be returned. @@ -84,36 +82,34 @@ type Snapshotter interface { // // 'name' is the name of the VolumeSnapshot that will be cloned. // 'namespace' is the namespace of the VolumeSnapshot that will be cloned. - // 'cloneName' is name of the clone. - // 'cloneNamespace' is the namespace where the clone will be created. // 'waitForReady' will make the function blocks until the clone's status is ready to use. - // 'labels' is the labels to set on the created VSC - Clone(ctx context.Context, name, namespace, cloneName, cloneNamespace string, waitForReady bool, labels map[string]string) error + // 'snapshotMeta' has metadata of the VolumeSnapshot resource that is going to get created. + // 'snapshotContentMeta' has metadata of the VolumeSnapshotContent content resource that is going to get created. + Clone(ctx context.Context, name, namespace string, waitForReady bool, snapshotMeta, snapshotContentMeta ObjectMeta) error // GetSource will return the CSI source that backs the volume snapshot. // - // 'snapshotName' is the name of the Volumesnapshot. - // 'namespace' is the namespace of the Volumesnapshot. + // 'snapshotName' is the name of the VolumeSnapshot. + // 'namespace' is the namespace of the VolumeSnapshot. GetSource(ctx context.Context, snapshotName, namespace string) (*Source, error) - // CreateFromSource will create a 'Volumesnapshot' and 'VolumesnaphotContent' pair for the underlying snapshot source. + // CreateFromSource will create a 'VolumeSnapshot' and 'VolumeSnapshotContent' pair for the underlying snapshot source. // // 'source' contains information about CSI snapshot. - // 'snapshotName' is the name of the snapshot that will be created. - // 'namespace' is the namespace of the snapshot. // 'waitForReady' blocks the caller until snapshot is ready to use or context is cancelled. - // 'labels' is the labels to set on the created VSC - CreateFromSource(ctx context.Context, source *Source, snapshotName, namespace string, waitForReady bool, labels map[string]string) error - // CreateContentFromSource will create a 'VolumesnaphotContent' for the underlying snapshot source. + // 'snapshotMeta' has metadata of the VolumeSnapshot resource that is going to get created. + // 'snapshotContentMeta' has metadata of the VolumeSnapshotContent resource that is going to get created. + CreateFromSource(ctx context.Context, source *Source, waitForReady bool, snapshotMeta, snapshotContentMeta ObjectMeta) error + // CreateContentFromSource will create a 'VolumeSnapshotContent' for the underlying snapshot source. // // 'source' contains information about CSI snapshot. - // 'contentName' is the name of the VSC that will be created - // 'snapshotName' is the name of the snapshot that will be reference the VSC + // 'snapshotName' is the name of the snapshot that will be reference the VSC. // 'namespace' is the namespace of the snapshot. // 'deletionPolicy' is the deletion policy to set on the created VSC - CreateContentFromSource(ctx context.Context, source *Source, contentName, snapshotName, namespace, deletionPolicy string) error - // WaitOnReadyToUse will block until the Volumesnapshot in namespace 'namespace' with name 'snapshotName' + // 'snapshotContentMeta' has metadata of the VolumeSnapshotContent resource that is going to get created. + CreateContentFromSource(ctx context.Context, source *Source, snapshotName, namespace, deletionPolicy string, snapshotContentMeta ObjectMeta) error + // WaitOnReadyToUse will block until the VolumeSnapshot in namespace 'namespace' with name 'snapshotName' // has status 'ReadyToUse' or 'ctx.Done()' is signalled. WaitOnReadyToUse(ctx context.Context, snapshotName, namespace string) error - // List will list the volumesnapshots in a namespace that match search. If labels aren't provided, + // List will list the VolumeSnapshot in a namespace that match search. If labels aren't provided, // it will list all the snapshots in the namespace List(ctx context.Context, namespace string, labels map[string]string) (*v1.VolumeSnapshotList, error) // GroupVersion returns the group and version according to snapshotter version diff --git a/pkg/kube/snapshot/snapshot_alpha.go b/pkg/kube/snapshot/snapshot_alpha.go index d864a83a33..edd818de86 100644 --- a/pkg/kube/snapshot/snapshot_alpha.go +++ b/pkg/kube/snapshot/snapshot_alpha.go @@ -87,15 +87,16 @@ func (sna *SnapshotAlpha) GetVolumeSnapshotClass(ctx context.Context, annotation } // Create creates a VolumeSnapshot and returns it or any error that happened meanwhile. -func (sna *SnapshotAlpha) Create(ctx context.Context, name, namespace, pvcName string, snapshotClass *string, waitForReady bool, labels map[string]string) error { - if _, err := sna.kubeCli.CoreV1().PersistentVolumeClaims(namespace).Get(ctx, pvcName, metav1.GetOptions{}); err != nil { +func (sna *SnapshotAlpha) Create(ctx context.Context, pvcName string, snapshotClass *string, waitForReady bool, snapshotMeta ObjectMeta) error { + if _, err := sna.kubeCli.CoreV1().PersistentVolumeClaims(snapshotMeta.Namespace).Get(ctx, pvcName, metav1.GetOptions{}); err != nil { if apierrors.IsNotFound(err) { - return errkit.New("Failed to find PVC", "pvc", pvcName, "namespace", namespace) + return errkit.New("Failed to find PVC", "pvc", pvcName, "namespace", snapshotMeta.Namespace) } - return errkit.Wrap(err, "Failed to query PVC", "pvc", pvcName, "namespace", namespace) + return errkit.Wrap(err, "Failed to query PVC", "pvc", pvcName, "namespace", snapshotMeta.Namespace) } - snap := UnstructuredVolumeSnapshotAlpha(name, namespace, pvcName, "", *snapshotClass, blockstorage.SanitizeTags(labels)) - if _, err := sna.dynCli.Resource(v1alpha1.VolSnapGVR).Namespace(namespace).Create(ctx, snap, metav1.CreateOptions{}); err != nil { + snapshotMeta.Labels = blockstorage.SanitizeTags(snapshotMeta.Labels) + snap := UnstructuredVolumeSnapshotAlpha(pvcName, *snapshotClass, snapshotMeta, ObjectMeta{}) + if _, err := sna.dynCli.Resource(v1alpha1.VolSnapGVR).Namespace(snapshotMeta.Namespace).Create(ctx, snap, metav1.CreateOptions{}); err != nil { return err } @@ -103,11 +104,11 @@ func (sna *SnapshotAlpha) Create(ctx context.Context, name, namespace, pvcName s return nil } - if err := sna.WaitOnReadyToUse(ctx, name, namespace); err != nil { + if err := sna.WaitOnReadyToUse(ctx, snapshotMeta.Name, snapshotMeta.Namespace); err != nil { return err } - _, err := sna.Get(ctx, name, namespace) + _, err := sna.Get(ctx, snapshotMeta.Name, snapshotMeta.Namespace) return err } @@ -216,20 +217,20 @@ func (sna *SnapshotAlpha) DeleteContent(ctx context.Context, name string) error // Clone will clone the VolumeSnapshot to namespace 'cloneNamespace'. // Underlying VolumeSnapshotContent will be cloned with a different name. -func (sna *SnapshotAlpha) Clone(ctx context.Context, name, namespace, cloneName, cloneNamespace string, waitForReady bool, labels map[string]string) error { - _, err := sna.Get(ctx, cloneName, cloneNamespace) +func (sna *SnapshotAlpha) Clone(ctx context.Context, name, namespace string, waitForReady bool, snapshotMeta, snapshotContentMeta ObjectMeta) error { + _, err := sna.Get(ctx, snapshotMeta.Name, snapshotMeta.Namespace) if err == nil { - return errkit.New("Target snapshot already exists in target namespace", "name", cloneName, "namespace", cloneNamespace) + return errkit.New("Target snapshot already exists in target namespace", "name", snapshotMeta.Name, "namespace", snapshotMeta.Namespace) } if !apierrors.IsNotFound(err) { - return errkit.Wrap(err, "Failed to query target Volumesnapshot", "name", cloneName, "namespace", cloneNamespace) + return errkit.Wrap(err, "Failed to query target Volumesnapshot", "name", snapshotMeta.Name, "namespace", snapshotMeta.Namespace) } src, err := sna.GetSource(ctx, name, namespace) if err != nil { return errkit.Wrap(err, "Failed to get source") } - return sna.CreateFromSource(ctx, src, cloneName, cloneNamespace, waitForReady, labels) + return sna.CreateFromSource(ctx, src, waitForReady, snapshotMeta, snapshotContentMeta) } // GetSource will return the CSI source that backs the volume snapshot. @@ -259,23 +260,24 @@ func (sna *SnapshotAlpha) GetSource(ctx context.Context, snapshotName, namespace } // CreateFromSource will create a 'Volumesnapshot' and 'VolumesnaphotContent' pair for the underlying snapshot source. -func (sna *SnapshotAlpha) CreateFromSource(ctx context.Context, source *Source, snapshotName, namespace string, waitForReady bool, labels map[string]string) error { +func (sna *SnapshotAlpha) CreateFromSource(ctx context.Context, source *Source, waitForReady bool, snapshotMeta, snapshotContentMeta ObjectMeta) error { deletionPolicy, err := sna.getDeletionPolicyFromClass(source.VolumeSnapshotClassName) if err != nil { return errkit.Wrap(err, "Failed to get DeletionPolicy from VolumeSnapshotClass") } - contentName := snapshotName + "-content-" + string(uuid.NewUUID()) - snap := UnstructuredVolumeSnapshotAlpha(snapshotName, namespace, "", contentName, source.VolumeSnapshotClassName, blockstorage.SanitizeTags(labels)) - if err := sna.CreateContentFromSource(ctx, source, contentName, snapshotName, namespace, deletionPolicy); err != nil { + snapshotContentMeta.Name = snapshotMeta.Name + "-content-" + string(uuid.NewUUID()) + snapshotMeta.Labels = blockstorage.SanitizeTags(snapshotMeta.Labels) + snap := UnstructuredVolumeSnapshotAlpha("", source.VolumeSnapshotClassName, snapshotMeta, snapshotContentMeta) + if err := sna.CreateContentFromSource(ctx, source, snapshotMeta.Name, snapshotMeta.Namespace, deletionPolicy, snapshotContentMeta); err != nil { return err } - if _, err := sna.dynCli.Resource(v1alpha1.VolSnapGVR).Namespace(namespace).Create(ctx, snap, metav1.CreateOptions{}); err != nil { - return errkit.Wrap(err, "Failed to create content", "name", snap.GetName(), "namespace", namespace) + if _, err := sna.dynCli.Resource(v1alpha1.VolSnapGVR).Namespace(snapshotMeta.Namespace).Create(ctx, snap, metav1.CreateOptions{}); err != nil { + return errkit.Wrap(err, "Failed to create content", "name", snap.GetName(), "namespace", snapshotMeta.Namespace) } if !waitForReady { return nil } - return sna.WaitOnReadyToUse(ctx, snapshotName, namespace) + return sna.WaitOnReadyToUse(ctx, snapshotMeta.Name, snapshotMeta.Namespace) } // UpdateVolumeSnapshotStatusAlpha sets the readyToUse valuse of a VolumeSnapshot. @@ -297,8 +299,8 @@ func (sna *SnapshotAlpha) UpdateVolumeSnapshotStatusAlpha(ctx context.Context, n } // CreateContentFromSource will create a 'VolumesnaphotContent' for the underlying snapshot source. -func (sna *SnapshotAlpha) CreateContentFromSource(ctx context.Context, source *Source, contentName, snapshotName, namespace, deletionPolicy string) error { - content := UnstructuredVolumeSnapshotContentAlpha(contentName, snapshotName, namespace, deletionPolicy, source.Driver, source.Handle, source.VolumeSnapshotClassName) +func (sna *SnapshotAlpha) CreateContentFromSource(ctx context.Context, source *Source, snapshotName, namespace, deletionPolicy string, snapshotContentMeta ObjectMeta) error { + content := UnstructuredVolumeSnapshotContentAlpha(snapshotName, namespace, deletionPolicy, source.Driver, source.Handle, source.VolumeSnapshotClassName, snapshotContentMeta) if _, err := sna.dynCli.Resource(v1alpha1.VolSnapContentGVR).Create(ctx, content, metav1.CreateOptions{}); err != nil { return errkit.Wrap(err, "Failed to create content", "contentName", content.GetName()) } @@ -353,14 +355,16 @@ func (sna *SnapshotAlpha) getDeletionPolicyFromClass(snapClassName string) (stri return vsc.DeletionPolicy, nil } -func UnstructuredVolumeSnapshotAlpha(name, namespace, pvcName, contentName, snapClassName string, labels map[string]string) *unstructured.Unstructured { +// UnstructuredVolumeSnapshotAlpha returns Unstructured object for the VolumeSnapshot resource. +// If snapshotContentMeta has name value set, UnstructuredVolumeSnapshotAlpha will return VolumeSnapshot object with VolumeSnapshotContent information. +func UnstructuredVolumeSnapshotAlpha(pvcName, snapClassName string, snapshotMeta, snapshotContentMeta ObjectMeta) *unstructured.Unstructured { snap := &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": fmt.Sprintf("%s/%s", v1alpha1.GroupName, v1alpha1.Version), "kind": VolSnapKind, "metadata": map[string]interface{}{ - "name": name, - "namespace": namespace, + "name": snapshotMeta.Name, + "namespace": snapshotMeta.Namespace, }, }, } @@ -369,31 +373,35 @@ func UnstructuredVolumeSnapshotAlpha(name, namespace, pvcName, contentName, snap "source": map[string]interface{}{ "kind": PVCKind, "name": pvcName, - "namespace": namespace, + "namespace": snapshotMeta.Namespace, }, "snapshotClassName": snapClassName, "deletionPolicy": "Delete", } } - if contentName != "" { + if snapshotContentMeta.Name != "" { snap.Object["spec"] = map[string]interface{}{ - "snapshotContentName": contentName, + "snapshotContentName": snapshotContentMeta.Name, "snapshotClassName": snapClassName, } } - if labels != nil { - snap.SetLabels(labels) + if snapshotMeta.Labels != nil { + snap.SetLabels(snapshotMeta.Labels) + } + if snapshotMeta.Annotations != nil { + snap.SetAnnotations(snapshotMeta.Annotations) } return snap } -func UnstructuredVolumeSnapshotContentAlpha(name, snapshotName, snapshotNs, deletionPolicy, driver, handle, snapClassName string) *unstructured.Unstructured { - return &unstructured.Unstructured{ +// UnstructuredVolumeSnapshotContentAlpha returns Unstructured object for the VolumeSnapshotContent resource. +func UnstructuredVolumeSnapshotContentAlpha(snapshotName, snapshotNS, deletionPolicy, driver, handle, snapClassName string, snapshotContentMeta ObjectMeta) *unstructured.Unstructured { + snaphotContent := unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": fmt.Sprintf("%s/%s", v1alpha1.GroupName, v1alpha1.Version), "kind": VolSnapContentKind, "metadata": map[string]interface{}{ - "name": name, + "name": snapshotContentMeta.Name, }, "spec": map[string]interface{}{ "csiVolumeSnapshotSource": map[string]interface{}{ @@ -403,13 +411,20 @@ func UnstructuredVolumeSnapshotContentAlpha(name, snapshotName, snapshotNs, dele "volumeSnapshotRef": map[string]interface{}{ "kind": VolSnapKind, "name": snapshotName, - "namespace": snapshotNs, + "namespace": snapshotNS, }, "snapshotClassName": snapClassName, "deletionPolicy": deletionPolicy, }, }, } + if snapshotContentMeta.Labels != nil { + snaphotContent.SetLabels(snapshotContentMeta.Labels) + } + if snapshotContentMeta.Annotations != nil { + snaphotContent.SetAnnotations(snapshotContentMeta.Annotations) + } + return &snaphotContent } func UnstructuredVolumeSnapshotClassAlpha(name, driver, deletionPolicy string, params map[string]string) *unstructured.Unstructured { diff --git a/pkg/kube/snapshot/snapshot_beta.go b/pkg/kube/snapshot/snapshot_beta.go index e69fc6b25f..64fb1213c3 100644 --- a/pkg/kube/snapshot/snapshot_beta.go +++ b/pkg/kube/snapshot/snapshot_beta.go @@ -77,8 +77,8 @@ func (sna *SnapshotBeta) GetVolumeSnapshotClass(ctx context.Context, annotationK } // Create creates a VolumeSnapshot and returns it or any error happened meanwhile. -func (sna *SnapshotBeta) Create(ctx context.Context, name, namespace, volumeName string, snapshotClass *string, waitForReady bool, labels map[string]string) error { - return createSnapshot(ctx, sna.dynCli, sna.kubeCli, v1beta1.VolSnapGVR, name, namespace, volumeName, snapshotClass, waitForReady, labels) +func (sna *SnapshotBeta) Create(ctx context.Context, volumeName string, snapshotClass *string, waitForReady bool, snapshotMeta ObjectMeta) error { + return createSnapshot(ctx, sna.dynCli, sna.kubeCli, v1beta1.VolSnapGVR, volumeName, snapshotClass, waitForReady, snapshotMeta) } func createSnapshot( @@ -86,34 +86,33 @@ func createSnapshot( dynCli dynamic.Interface, kubeCli kubernetes.Interface, snapGVR schema.GroupVersionResource, - name, - namespace, volumeName string, snapshotClass *string, waitForReady bool, - labels map[string]string, + snapshotMeta ObjectMeta, ) error { - if _, err := kubeCli.CoreV1().PersistentVolumeClaims(namespace).Get(ctx, volumeName, metav1.GetOptions{}); err != nil { + if _, err := kubeCli.CoreV1().PersistentVolumeClaims(snapshotMeta.Namespace).Get(ctx, volumeName, metav1.GetOptions{}); err != nil { if apierrors.IsNotFound(err) { - return errkit.New("Failed to find PVC", "pvc", volumeName, "namespace", namespace) + return errkit.New("Failed to find PVC", "pvc", volumeName, "namespace", snapshotMeta.Namespace) } - return errkit.Wrap(err, "Failed to query PVC", "pvc", volumeName, "namespace", namespace) + return errkit.Wrap(err, "Failed to query PVC", "pvc", volumeName, "namespace", snapshotMeta.Namespace) } - - snap := UnstructuredVolumeSnapshot(snapGVR, name, namespace, volumeName, "", *snapshotClass, blockstorage.SanitizeTags(labels)) - if _, err := dynCli.Resource(snapGVR).Namespace(namespace).Create(ctx, snap, metav1.CreateOptions{}); err != nil { - return errkit.Wrap(err, "Failed to create snapshot resource", "name", name, "namespace", namespace) + snapshotMeta.Labels = blockstorage.SanitizeTags(snapshotMeta.Labels) + snapshotContentMeta := ObjectMeta{} + snap := UnstructuredVolumeSnapshot(snapGVR, volumeName, *snapshotClass, snapshotMeta, snapshotContentMeta) + if _, err := dynCli.Resource(snapGVR).Namespace(snapshotMeta.Namespace).Create(ctx, snap, metav1.CreateOptions{}); err != nil { + return errkit.Wrap(err, "Failed to create snapshot resource", "name", snapshotMeta.Name, "namespace", snapshotMeta.Namespace) } if !waitForReady { return nil } - if err := waitOnReadyToUse(ctx, dynCli, snapGVR, name, namespace, isReadyToUseBeta); err != nil { + if err := waitOnReadyToUse(ctx, dynCli, snapGVR, snapshotMeta.Name, snapshotMeta.Namespace, isReadyToUseBeta); err != nil { return err } - _, err := getSnapshot(ctx, dynCli, snapGVR, name, namespace) + _, err := getSnapshot(ctx, dynCli, snapGVR, snapshotMeta.Name, snapshotMeta.Namespace) return err } @@ -189,22 +188,22 @@ func (sna *SnapshotBeta) DeleteContent(ctx context.Context, name string) error { return nil } -// Clone will clone the VolumeSnapshot to namespace 'cloneNamespace'. +// Clone will clone the VolumeSnapshot to namespace 'snapshotMeta.Namespace'. // Underlying VolumeSnapshotContent will be cloned with a different name. -func (sna *SnapshotBeta) Clone(ctx context.Context, name, namespace, cloneName, cloneNamespace string, waitForReady bool, labels map[string]string) error { - _, err := sna.Get(ctx, cloneName, cloneNamespace) +func (sna *SnapshotBeta) Clone(ctx context.Context, name, namespace string, waitForReady bool, snapshotMeta, snapshotContentMeta ObjectMeta) error { + _, err := sna.Get(ctx, snapshotMeta.Name, snapshotMeta.Namespace) if err == nil { - return errkit.New("Target snapshot already exists in target namespace", "volumeSnapshot", cloneName, "namespace", cloneNamespace) + return errkit.New("Target snapshot already exists in target namespace", "volumeSnapshot", snapshotMeta.Name, "namespace", snapshotMeta.Namespace) } if !apierrors.IsNotFound(err) { - return errkit.Wrap(err, "Failed to query target Volumesnapshot", "volumeSnapshot", cloneName, "namespace", cloneNamespace) + return errkit.Wrap(err, "Failed to query target Volumesnapshot", "volumeSnapshot", snapshotMeta.Name, "namespace", snapshotMeta.Namespace) } src, err := sna.GetSource(ctx, name, namespace) if err != nil { return errkit.New("Failed to get source") } - return sna.CreateFromSource(ctx, src, cloneName, cloneNamespace, waitForReady, labels) + return sna.CreateFromSource(ctx, src, waitForReady, snapshotMeta, snapshotContentMeta) } // GetSource will return the CSI source that backs the volume snapshot. @@ -239,24 +238,24 @@ func getSnapshotSource(ctx context.Context, dynCli dynamic.Interface, snapGVR, s } // CreateFromSource will create a 'Volumesnapshot' and 'VolumesnaphotContent' pair for the underlying snapshot source. -func (sna *SnapshotBeta) CreateFromSource(ctx context.Context, source *Source, snapshotName, namespace string, waitForReady bool, labels map[string]string) error { +func (sna *SnapshotBeta) CreateFromSource(ctx context.Context, source *Source, waitForReady bool, snapshotMeta, snapshotContentMeta ObjectMeta) error { deletionPolicy, err := getDeletionPolicyFromClass(sna.dynCli, v1beta1.VolSnapClassGVR, source.VolumeSnapshotClassName) if err != nil { return errkit.Wrap(err, "Failed to get DeletionPolicy from VolumeSnapshotClass") } - contentName := snapshotName + "-content-" + string(uuid.NewUUID()) - snap := UnstructuredVolumeSnapshot(v1beta1.VolSnapGVR, snapshotName, namespace, "", contentName, source.VolumeSnapshotClassName, blockstorage.SanitizeTags(labels)) - - if err := sna.CreateContentFromSource(ctx, source, contentName, snapshotName, namespace, deletionPolicy); err != nil { + snapshotContentMeta.Name = snapshotMeta.Name + "-content-" + string(uuid.NewUUID()) + snapshotMeta.Labels = blockstorage.SanitizeTags(snapshotMeta.Labels) + snap := UnstructuredVolumeSnapshot(v1beta1.VolSnapGVR, "", source.VolumeSnapshotClassName, snapshotMeta, snapshotContentMeta) + if err := sna.CreateContentFromSource(ctx, source, snapshotMeta.Name, snapshotMeta.Namespace, deletionPolicy, snapshotContentMeta); err != nil { return err } - if _, err := sna.dynCli.Resource(v1beta1.VolSnapGVR).Namespace(namespace).Create(ctx, snap, metav1.CreateOptions{}); err != nil { + if _, err := sna.dynCli.Resource(v1beta1.VolSnapGVR).Namespace(snapshotMeta.Namespace).Create(ctx, snap, metav1.CreateOptions{}); err != nil { return errkit.Wrap(err, "Failed to create content", "volumeSnapshot", snap.GetName()) } if !waitForReady { return nil } - err = sna.WaitOnReadyToUse(ctx, snapshotName, namespace) + err = sna.WaitOnReadyToUse(ctx, snapshotMeta.Name, snapshotMeta.Namespace) return err } @@ -290,8 +289,8 @@ func updateVolumeSnapshotStatus(ctx context.Context, dynCli dynamic.Interface, s } // CreateContentFromSource will create a 'VolumesnaphotContent' for the underlying snapshot source. -func (sna *SnapshotBeta) CreateContentFromSource(ctx context.Context, source *Source, contentName, snapshotName, namespace, deletionPolicy string) error { - content := UnstructuredVolumeSnapshotContent(v1beta1.VolSnapContentGVR, contentName, snapshotName, namespace, deletionPolicy, source.Driver, source.Handle, source.VolumeSnapshotClassName) +func (sna *SnapshotBeta) CreateContentFromSource(ctx context.Context, source *Source, snapshotName, namespace, deletionPolicy string, snapshotContentMeta ObjectMeta) error { + content := UnstructuredVolumeSnapshotContent(v1beta1.VolSnapContentGVR, snapshotName, namespace, deletionPolicy, source.Driver, source.Handle, source.VolumeSnapshotClassName, snapshotContentMeta) if _, err := sna.dynCli.Resource(v1beta1.VolSnapContentGVR).Create(ctx, content, metav1.CreateOptions{}); err != nil { return errkit.Wrap(err, "Failed to create content", "volumeSnapshotContent", content.GetName()) } @@ -343,14 +342,16 @@ func getDeletionPolicyFromClass(dynCli dynamic.Interface, snapClassGVR schema.Gr return vsc.DeletionPolicy, nil } -func UnstructuredVolumeSnapshot(gvr schema.GroupVersionResource, name, namespace, pvcName, contentName, snapClassName string, labels map[string]string) *unstructured.Unstructured { +// UnstructuredVolumeSnapshot returns Unstructured object for the VolumeSnapshot resource. +// If snapshotContentMeta has name value set, UnstructuredVolumeSnapshot will return VolumeSnapshot object with VolumeSnapshotContent information. +func UnstructuredVolumeSnapshot(gvr schema.GroupVersionResource, pvcName, snapClassName string, snapshotMeta, snapshotContentMeta ObjectMeta) *unstructured.Unstructured { snap := &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": fmt.Sprintf("%s/%s", gvr.Group, gvr.Version), "kind": VolSnapKind, "metadata": map[string]interface{}{ - "name": name, - "namespace": namespace, + "name": snapshotMeta.Name, + "namespace": snapshotMeta.Namespace, }, }, } @@ -362,33 +363,37 @@ func UnstructuredVolumeSnapshot(gvr schema.GroupVersionResource, name, namespace "volumeSnapshotClassName": snapClassName, } } - if contentName != "" { + if snapshotContentMeta.Name != "" { snap.Object["spec"] = map[string]interface{}{ "source": map[string]interface{}{ - "volumeSnapshotContentName": contentName, + "volumeSnapshotContentName": snapshotContentMeta.Name, }, "volumeSnapshotClassName": snapClassName, } } - if labels != nil { - snap.SetLabels(labels) + if snapshotMeta.Labels != nil { + snap.SetLabels(snapshotMeta.Labels) + } + if snapshotMeta.Annotations != nil { + snap.SetAnnotations(snapshotMeta.Annotations) } return snap } -func UnstructuredVolumeSnapshotContent(gvr schema.GroupVersionResource, name, snapshotName, snapshotNs, deletionPolicy, driver, handle, snapClassName string) *unstructured.Unstructured { - return &unstructured.Unstructured{ +// UnstructuredVolumeSnapshotContent returns Unstructured object for the VolumeSnapshotContent resource. +func UnstructuredVolumeSnapshotContent(gvr schema.GroupVersionResource, snapshotName, snapshotNS, deletionPolicy, driver, handle, snapClassName string, snapshotContentMeta ObjectMeta) *unstructured.Unstructured { + snapshotContent := unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": fmt.Sprintf("%s/%s", gvr.Group, gvr.Version), "kind": VolSnapContentKind, "metadata": map[string]interface{}{ - "name": name, + "name": snapshotContentMeta.Name, }, "spec": map[string]interface{}{ "volumeSnapshotRef": map[string]interface{}{ "kind": VolSnapKind, "name": snapshotName, - "namespace": snapshotNs, + "namespace": snapshotNS, }, "deletionPolicy": deletionPolicy, "driver": driver, @@ -399,6 +404,13 @@ func UnstructuredVolumeSnapshotContent(gvr schema.GroupVersionResource, name, sn }, }, } + if snapshotContentMeta.Labels != nil { + snapshotContent.SetLabels(snapshotContentMeta.Labels) + } + if snapshotContentMeta.Annotations != nil { + snapshotContent.SetAnnotations(snapshotContentMeta.Annotations) + } + return &snapshotContent } func UnstructuredVolumeSnapshotClass(gvr schema.GroupVersionResource, name, driver, deletionPolicy string, params map[string]string) *unstructured.Unstructured { diff --git a/pkg/kube/snapshot/snapshot_stable.go b/pkg/kube/snapshot/snapshot_stable.go index a2c6864ed6..e9cda64108 100644 --- a/pkg/kube/snapshot/snapshot_stable.go +++ b/pkg/kube/snapshot/snapshot_stable.go @@ -70,8 +70,8 @@ func (sna *SnapshotStable) GetVolumeSnapshotClass(ctx context.Context, annotatio } // Create creates a VolumeSnapshot and returns it or any error happened meanwhile. -func (sna *SnapshotStable) Create(ctx context.Context, name, namespace, volumeName string, snapshotClass *string, waitForReady bool, labels map[string]string) error { - return createSnapshot(ctx, sna.dynCli, sna.kubeCli, VolSnapGVR, name, namespace, volumeName, snapshotClass, waitForReady, labels) +func (sna *SnapshotStable) Create(ctx context.Context, volumeName string, snapshotClass *string, waitForReady bool, snapshotMeta ObjectMeta) error { + return createSnapshot(ctx, sna.dynCli, sna.kubeCli, VolSnapGVR, volumeName, snapshotClass, waitForReady, snapshotMeta) } // Get will return the VolumeSnapshot in the 'namespace' with given 'name'. @@ -99,20 +99,20 @@ func (sna *SnapshotStable) DeleteContent(ctx context.Context, name string) error // Clone will clone the VolumeSnapshot to namespace 'cloneNamespace'. // Underlying VolumeSnapshotContent will be cloned with a different name. -func (sna *SnapshotStable) Clone(ctx context.Context, name, namespace, cloneName, cloneNamespace string, waitForReady bool, labels map[string]string) error { - _, err := sna.Get(ctx, cloneName, cloneNamespace) +func (sna *SnapshotStable) Clone(ctx context.Context, name, namespace string, waitForReady bool, snapshotMeta, snapshotContentMeta ObjectMeta) error { + _, err := sna.Get(ctx, snapshotMeta.Name, snapshotMeta.Namespace) if err == nil { - return errkit.New("Target snapshot already exists in target namespace", "volumeSnapshot", cloneName, "namespace", cloneNamespace) + return errkit.New("Target snapshot already exists in target namespace", "volumeSnapshot", snapshotMeta.Name, "namespace", snapshotMeta.Namespace) } if !apierrors.IsNotFound(err) { - return errkit.Wrap(err, "Failed to query target", "volumeSnapshot", cloneName, "namespace", cloneNamespace) + return errkit.Wrap(err, "Failed to query target", "volumeSnapshot", snapshotMeta.Name, "namespace", snapshotMeta.Namespace) } src, err := sna.GetSource(ctx, name, namespace) if err != nil { return errkit.New("Failed to get source") } - return sna.CreateFromSource(ctx, src, cloneName, cloneNamespace, waitForReady, labels) + return sna.CreateFromSource(ctx, src, waitForReady, snapshotMeta, snapshotContentMeta) } // GetSource will return the CSI source that backs the volume snapshot. @@ -121,32 +121,31 @@ func (sna *SnapshotStable) GetSource(ctx context.Context, snapshotName, namespac } // CreateFromSource will create a 'Volumesnapshot' and 'VolumesnaphotContent' pair for the underlying snapshot source. -func (sna *SnapshotStable) CreateFromSource(ctx context.Context, source *Source, snapshotName, namespace string, waitForReady bool, labels map[string]string) error { +func (sna *SnapshotStable) CreateFromSource(ctx context.Context, source *Source, waitForReady bool, snapshotMeta, snapshotContentMeta ObjectMeta) error { deletionPolicy, err := getDeletionPolicyFromClass(sna.dynCli, VolSnapClassGVR, source.VolumeSnapshotClassName) if err != nil { return errkit.Wrap(err, "Failed to get DeletionPolicy from VolumeSnapshotClass") } - contentName := snapshotName + "-content-" + string(uuid.NewUUID()) + snapshotContentMeta.Name = snapshotMeta.Name + "-content-" + string(uuid.NewUUID()) + snapshotMeta.Labels = blockstorage.SanitizeTags(snapshotMeta.Labels) snap := UnstructuredVolumeSnapshot( VolSnapGVR, - snapshotName, - namespace, "", - contentName, source.VolumeSnapshotClassName, - blockstorage.SanitizeTags(labels), + snapshotMeta, + snapshotContentMeta, ) - if err := sna.CreateContentFromSource(ctx, source, contentName, snapshotName, namespace, deletionPolicy); err != nil { + if err := sna.CreateContentFromSource(ctx, source, snapshotMeta.Name, snapshotMeta.Namespace, deletionPolicy, snapshotContentMeta); err != nil { return err } - if _, err := sna.dynCli.Resource(VolSnapGVR).Namespace(namespace).Create(ctx, snap, metav1.CreateOptions{}); err != nil { + if _, err := sna.dynCli.Resource(VolSnapGVR).Namespace(snapshotMeta.Namespace).Create(ctx, snap, metav1.CreateOptions{}); err != nil { return errkit.Wrap(err, "Failed to create content", "volumeSnapshot", snap.GetName()) } if !waitForReady { return nil } - err = sna.WaitOnReadyToUse(ctx, snapshotName, namespace) + err = sna.WaitOnReadyToUse(ctx, snapshotMeta.Name, snapshotMeta.Namespace) return err } @@ -156,8 +155,8 @@ func (sna *SnapshotStable) UpdateVolumeSnapshotStatusStable(ctx context.Context, } // CreateContentFromSource will create a 'VolumesnaphotContent' for the underlying snapshot source. -func (sna *SnapshotStable) CreateContentFromSource(ctx context.Context, source *Source, contentName, snapshotName, namespace, deletionPolicy string) error { - content := UnstructuredVolumeSnapshotContent(VolSnapContentGVR, contentName, snapshotName, namespace, deletionPolicy, source.Driver, source.Handle, source.VolumeSnapshotClassName) +func (sna *SnapshotStable) CreateContentFromSource(ctx context.Context, source *Source, snapshotName, snapshotNS, deletionPolicy string, snapshotContentMeta ObjectMeta) error { + content := UnstructuredVolumeSnapshotContent(VolSnapContentGVR, snapshotName, snapshotNS, deletionPolicy, source.Driver, source.Handle, source.VolumeSnapshotClassName, snapshotContentMeta) if _, err := sna.dynCli.Resource(VolSnapContentGVR).Create(ctx, content, metav1.CreateOptions{}); err != nil { return errkit.Wrap(err, "Failed to create content", "volumeSnapshotContent", content.GetName()) } diff --git a/pkg/kube/snapshot/snapshot_test.go b/pkg/kube/snapshot/snapshot_test.go index 0675a2a177..e7e5b9f514 100644 --- a/pkg/kube/snapshot/snapshot_test.go +++ b/pkg/kube/snapshot/snapshot_test.go @@ -178,13 +178,17 @@ func (s *SnapshotTestSuite) TestVolumeSnapshotFake(c *C) { snapshot.NewSnapshotBeta(fakeCli, dynfake.NewSimpleDynamicClient(scheme)), snapshot.NewSnapshotStable(fakeCli, dynfake.NewSimpleDynamicClient(scheme)), } { - err = fakeSs.Create(context.Background(), snapshotName, defaultNamespace, volName, &fakeClass, false, nil) + snapshotMeta := snapshot.ObjectMeta{ + Name: snapshotName, + Namespace: defaultNamespace, + } + err = fakeSs.Create(context.Background(), volName, &fakeClass, false, snapshotMeta) c.Assert(err, IsNil) snap, err := fakeSs.Get(context.Background(), snapshotName, defaultNamespace) c.Assert(err, IsNil) c.Assert(snap.Name, Equals, snapshotName) - err = fakeSs.Create(context.Background(), snapshotName, defaultNamespace, volName, &fakeClass, false, nil) + err = fakeSs.Create(context.Background(), volName, &fakeClass, false, snapshotMeta) c.Assert(err, NotNil) deletedSnap, err := fakeSs.Delete(context.Background(), snap.Name, snap.Namespace) c.Assert(err, IsNil) @@ -275,6 +279,13 @@ func (s *SnapshotTestSuite) TestVolumeSnapshotCloneFake(c *C) { fakeSnapshotName := "snap-1-fake" fakeContentName := "snapcontent-1-fake" deletionPolicy := "Delete" + fakeContentAnnotation := map[string]string{ + "snapshot.storage.kubernetes.io/allow-volume-mode-change": "true", + } + + fakeSnapshotAnnotation := map[string]string{ + "testAnnotation": "true", + } scheme := runtime.NewScheme() dynCli := dynfake.NewSimpleDynamicClient(scheme) @@ -292,11 +303,20 @@ func (s *SnapshotTestSuite) TestVolumeSnapshotCloneFake(c *C) { fakeSs snapshot.Snapshotter }{ { - snapClassSpec: snapshot.UnstructuredVolumeSnapshotClassAlpha(fakeClass, fakeDriver, deletionPolicy, nil), - snapClassGVR: v1alpha1.VolSnapClassGVR, - contentSpec: snapshot.UnstructuredVolumeSnapshotContentAlpha(fakeContentName, fakeSnapshotName, defaultNamespace, deletionPolicy, fakeDriver, fakeSnapshotHandle, fakeClass), - contentGVR: v1alpha1.VolSnapContentGVR, - snapSpec: snapshot.UnstructuredVolumeSnapshotAlpha(fakeSnapshotName, defaultNamespace, "", fakeContentName, fakeClass, nil), + snapClassSpec: snapshot.UnstructuredVolumeSnapshotClassAlpha(fakeClass, fakeDriver, deletionPolicy, nil), + snapClassGVR: v1alpha1.VolSnapClassGVR, + contentSpec: snapshot.UnstructuredVolumeSnapshotContentAlpha(fakeSnapshotName, defaultNamespace, deletionPolicy, fakeDriver, fakeSnapshotHandle, fakeClass, snapshot.ObjectMeta{ + Name: fakeContentName, + Annotations: fakeContentAnnotation, + }), + contentGVR: v1alpha1.VolSnapContentGVR, + snapSpec: snapshot.UnstructuredVolumeSnapshotAlpha("", fakeClass, snapshot.ObjectMeta{ + Name: fakeSnapshotName, + Namespace: defaultNamespace, + Annotations: fakeSnapshotAnnotation, + }, snapshot.ObjectMeta{ + Name: fakeContentName, + }), snapGVR: v1alpha1.VolSnapGVR, snapContentObject: &v1alpha1.VolumeSnapshotContent{}, fakeSs: snapshot.NewSnapshotAlpha(nil, dynCli), @@ -304,10 +324,19 @@ func (s *SnapshotTestSuite) TestVolumeSnapshotCloneFake(c *C) { { snapClassSpec: snapshot.UnstructuredVolumeSnapshotClass(v1beta1.VolSnapClassGVR, fakeClass, fakeDriver, deletionPolicy, nil), snapClassGVR: v1beta1.VolSnapClassGVR, - contentSpec: snapshot.UnstructuredVolumeSnapshotContent(v1beta1.VolSnapContentGVR, fakeContentName, fakeSnapshotName, defaultNamespace, deletionPolicy, fakeDriver, fakeSnapshotHandle, fakeClass), - contentGVR: v1beta1.VolSnapContentGVR, - - snapSpec: snapshot.UnstructuredVolumeSnapshot(v1beta1.VolSnapGVR, fakeSnapshotName, defaultNamespace, "", fakeContentName, fakeClass, nil), + contentSpec: snapshot.UnstructuredVolumeSnapshotContent(v1beta1.VolSnapContentGVR, fakeSnapshotName, defaultNamespace, deletionPolicy, fakeDriver, fakeSnapshotHandle, fakeClass, snapshot.ObjectMeta{ + Name: fakeContentName, + Annotations: fakeContentAnnotation, + }), + contentGVR: v1beta1.VolSnapContentGVR, + + snapSpec: snapshot.UnstructuredVolumeSnapshot(v1beta1.VolSnapGVR, "", fakeClass, snapshot.ObjectMeta{ + Name: fakeSnapshotName, + Namespace: defaultNamespace, + Annotations: fakeSnapshotAnnotation, + }, snapshot.ObjectMeta{ + Name: fakeContentName, + }), snapGVR: v1beta1.VolSnapGVR, snapContentObject: &v1beta1.VolumeSnapshotContent{}, fakeSs: snapshot.NewSnapshotBeta(nil, dynCli), @@ -315,10 +344,19 @@ func (s *SnapshotTestSuite) TestVolumeSnapshotCloneFake(c *C) { { snapClassSpec: snapshot.UnstructuredVolumeSnapshotClass(snapshot.VolSnapClassGVR, fakeClass, fakeDriver, deletionPolicy, nil), snapClassGVR: snapshot.VolSnapClassGVR, - contentSpec: snapshot.UnstructuredVolumeSnapshotContent(snapshot.VolSnapContentGVR, fakeContentName, fakeSnapshotName, defaultNamespace, deletionPolicy, fakeDriver, fakeSnapshotHandle, fakeClass), - contentGVR: snapshot.VolSnapContentGVR, - - snapSpec: snapshot.UnstructuredVolumeSnapshot(snapshot.VolSnapGVR, fakeSnapshotName, defaultNamespace, "", fakeContentName, fakeClass, nil), + contentSpec: snapshot.UnstructuredVolumeSnapshotContent(snapshot.VolSnapContentGVR, fakeSnapshotName, defaultNamespace, deletionPolicy, fakeDriver, fakeSnapshotHandle, fakeClass, snapshot.ObjectMeta{ + Name: fakeContentName, + Annotations: fakeContentAnnotation, + }), + contentGVR: snapshot.VolSnapContentGVR, + + snapSpec: snapshot.UnstructuredVolumeSnapshot(snapshot.VolSnapGVR, "", fakeClass, snapshot.ObjectMeta{ + Name: fakeSnapshotName, + Namespace: defaultNamespace, + Annotations: fakeSnapshotAnnotation, + }, snapshot.ObjectMeta{ + Name: fakeContentName, + }), snapGVR: snapshot.VolSnapGVR, snapContentObject: &snapv1.VolumeSnapshotContent{}, fakeSs: snapshot.NewSnapshotStable(nil, dynCli), @@ -342,7 +380,15 @@ func (s *SnapshotTestSuite) TestVolumeSnapshotCloneFake(c *C) { _, err = tc.fakeSs.Get(context.Background(), fakeSnapshotName, defaultNamespace) c.Assert(err, IsNil) - err = tc.fakeSs.Clone(context.Background(), fakeSnapshotName, defaultNamespace, fakeClone, fakeTargetNamespace, false, map[string]string{"tag": "value"}) + err = tc.fakeSs.Clone(context.Background(), fakeSnapshotName, defaultNamespace, false, snapshot.ObjectMeta{ + Name: fakeClone, + Namespace: fakeTargetNamespace, + Labels: map[string]string{"tag": "value"}, + Annotations: fakeSnapshotAnnotation, + }, snapshot.ObjectMeta{ + Annotations: fakeContentAnnotation, + }) + c.Assert(err, IsNil) clone, err := tc.fakeSs.Get(context.Background(), fakeClone, fakeTargetNamespace) @@ -413,8 +459,11 @@ func (s *SnapshotTestSuite) TestWaitOnReadyToUse(c *C) { volumeSnapshotGVR = snapshot.VolSnapGVR snapshotName = snapshotNameBase + "-stable" } - - err = fakeSs.Create(ctx, snapshotName, defaultNamespace, volName, &fakeClass, false, nil) + snapshotMeta := snapshot.ObjectMeta{ + Name: snapshotName, + Namespace: defaultNamespace, + } + err = fakeSs.Create(ctx, volName, &fakeClass, false, snapshotMeta) c.Assert(err, IsNil) // This function should timeout @@ -623,7 +672,16 @@ func (s *SnapshotTestSuite) testVolumeSnapshot(c *C, snapshotter snapshot.Snapsh label := map[string]string{ "snapshottest": "testlabel", } - err = snapshotter.Create(ctx, snapshotName, s.sourceNamespace, pvc.Name, snapshotClass, wait, label) + annotations := map[string]string{ + "snapshotannotation": "testannotation", + } + snapshotMeta := snapshot.ObjectMeta{ + Name: snapshotName, + Namespace: s.sourceNamespace, + Labels: label, + Annotations: annotations, + } + err = snapshotter.Create(ctx, pvc.Name, snapshotClass, wait, snapshotMeta) c.Assert(err, IsNil) snap, err := snapshotter.Get(ctx, snapshotName, s.sourceNamespace) @@ -636,8 +694,12 @@ func (s *SnapshotTestSuite) testVolumeSnapshot(c *C, snapshotter snapshot.Snapsh c.Assert(err, IsNil) c.Assert(len(snapList.Items), Equals, 1) c.Assert(snapList.Items[0].Labels, DeepEquals, label) - - err = snapshotter.Create(ctx, snapshotName, s.sourceNamespace, pvc.Name, snapshotClass, wait, nil) + snapshotMeta = snapshot.ObjectMeta{ + Name: snapshotName, + Namespace: s.sourceNamespace, + Annotations: annotations, + } + err = snapshotter.Create(ctx, pvc.Name, snapshotClass, wait, snapshotMeta) c.Assert(err, NotNil) snapshotCloneName := snapshotName + "-clone" @@ -646,7 +708,19 @@ func (s *SnapshotTestSuite) testVolumeSnapshot(c *C, snapshotter snapshot.Snapsh label = map[string]string{ "snapshottest": "testlabel2", } - err = snapshotter.Clone(ctx, snapshotName, s.sourceNamespace, snapshotCloneName, s.targetNamespace, wait, label) + contentAnnotation := map[string]string{ + "test": "value", + } + snapshotMeta = snapshot.ObjectMeta{ + Name: snapshotCloneName, + Namespace: s.targetNamespace, + Labels: label, + Annotations: annotations, + } + snapshotContentMeta := snapshot.ObjectMeta{ + Annotations: contentAnnotation, + } + err = snapshotter.Clone(ctx, snapshotName, s.sourceNamespace, wait, snapshotMeta, snapshotContentMeta) c.Assert(err, IsNil) snapList, err = snapshotter.List(ctx, s.targetNamespace, label) @@ -1118,8 +1192,19 @@ func (s *SnapshotTestSuite) TestCreateFromSourceAlpha(c *C) { namespace := "namespace" snapshotName := "snapname" snapshotClass := "volSnapClass" - - volSnap := snapshot.UnstructuredVolumeSnapshotAlpha(snapshotName, namespace, "pvcName", "content", snapshotClass, nil) + annotation := map[string]string{ + "test": "value", + } + snapshotMeta := snapshot.ObjectMeta{ + Name: snapshotName, + Namespace: namespace, + Annotations: annotation, + } + snapshotContentMeta := snapshot.ObjectMeta{ + Name: "content", + } + volSnap := snapshot.UnstructuredVolumeSnapshotAlpha("pvcName", snapshotClass, + snapshotMeta, snapshotContentMeta) volSnap.Object["status"] = map[string]interface{}{ "readyToUse": false, } @@ -1148,8 +1233,16 @@ func (s *SnapshotTestSuite) TestCreateFromSourceAlpha(c *C) { c.Assert(ok, Equals, true) c.Assert(status["readyToUse"], Equals, false) + snapshotMeta = snapshot.ObjectMeta{ + Name: snapshotName, + Namespace: namespace, + } + snapshotContentMeta = snapshot.ObjectMeta{ + Name: "content", + } // status not set - volSnap = snapshot.UnstructuredVolumeSnapshotAlpha(snapshotName, namespace, "pvcName", "content", snapshotClass, nil) + volSnap = snapshot.UnstructuredVolumeSnapshotAlpha("pvcName", snapshotClass, + snapshotMeta, snapshotContentMeta) dynCli = dynfake.NewSimpleDynamicClient(scheme, volSnap) snapshotterAlpha, ok = snapshot.NewSnapshotAlpha(kubeCli, dynCli).(*snapshot.SnapshotAlpha) c.Assert(ok, Equals, true) @@ -1162,8 +1255,15 @@ func (s *SnapshotTestSuite) TestCreateFromSourceBeta(c *C) { namespace := "namespace" snapshotName := "snapname" snapshotClass := "volSnapClass" - - volSnap := snapshot.UnstructuredVolumeSnapshot(v1beta1.VolSnapGVR, snapshotName, namespace, "pvcName", "content", snapshotClass, nil) + snapshotMeta := snapshot.ObjectMeta{ + Name: snapshotName, + Namespace: namespace, + } + snapshotContentMeta := snapshot.ObjectMeta{ + Name: "content", + } + volSnap := snapshot.UnstructuredVolumeSnapshot(v1beta1.VolSnapGVR, "pvcName", snapshotClass, + snapshotMeta, snapshotContentMeta) volSnap.Object["status"] = map[string]interface{}{ "readyToUse": false, } @@ -1193,7 +1293,14 @@ func (s *SnapshotTestSuite) TestCreateFromSourceBeta(c *C) { c.Assert(status["readyToUse"], Equals, false) // status not set - volSnap = snapshot.UnstructuredVolumeSnapshot(v1beta1.VolSnapGVR, snapshotName, namespace, "pvcName", "content", snapshotClass, nil) + snapshotMeta = snapshot.ObjectMeta{ + Name: snapshotName, + Namespace: namespace, + } + snapshotContentMeta = snapshot.ObjectMeta{ + Name: "content", + } + volSnap = snapshot.UnstructuredVolumeSnapshot(v1beta1.VolSnapGVR, "pvcName", snapshotClass, snapshotMeta, snapshotContentMeta) dynCli = dynfake.NewSimpleDynamicClient(scheme, volSnap) snapshotterBeta, ok = snapshot.NewSnapshotBeta(kubeCli, dynCli).(*snapshot.SnapshotBeta) c.Assert(ok, Equals, true) @@ -1209,49 +1316,68 @@ func (s *SnapshotTestSuite) TestCreateFromSource(c *C) { snapshotClass := "volSnapClass" driver := "driver" labels := map[string]string{"Label": "1/"} + annotations := map[string]string{"annotationtest": "true"} source := &snapshot.Source{ Handle: namespace, Driver: driver, VolumeSnapshotClassName: snapshotClass, } scheme := runtime.NewScheme() - - volSnap := snapshot.UnstructuredVolumeSnapshot(v1alpha1.VolSnapGVR, existingSnapshotName, namespace, "pvcName", "content", snapshotClass, nil) + snapshotMeta := snapshot.ObjectMeta{ + Name: existingSnapshotName, + Namespace: namespace, + Annotations: annotations, + } + snapshotContentMeta := snapshot.ObjectMeta{ + Name: "content", + } + volSnap := snapshot.UnstructuredVolumeSnapshot(v1alpha1.VolSnapGVR, "pvcName", snapshotClass, snapshotMeta, snapshotContentMeta) volSnapClass := snapshot.UnstructuredVolumeSnapshotClass(v1alpha1.VolSnapClassGVR, snapshotClass, "driver", "DELETE", nil) dynCli := dynfake.NewSimpleDynamicClient(scheme, volSnap, volSnapClass) kubeCli := fake.NewSimpleClientset() snapshoterAlpha := snapshot.NewSnapshotAlpha(kubeCli, dynCli) - + snapshotMeta = snapshot.ObjectMeta{ + Name: existingSnapshotName, + Namespace: namespace, + Annotations: annotations, + } + snapshotContentMeta = snapshot.ObjectMeta{ + Name: "content", + } volSnap = snapshot.UnstructuredVolumeSnapshot( v1beta1.VolSnapGVR, - existingSnapshotName, - namespace, "pvcName", - "content", snapshotClass, - nil, - ) + snapshotMeta, snapshotContentMeta) volSnapClass = snapshot.UnstructuredVolumeSnapshotClass(v1beta1.VolSnapClassGVR, snapshotClass, "driver", "DELETE", nil) dynCli = dynfake.NewSimpleDynamicClient(scheme, volSnap, volSnapClass) kubeCli = fake.NewSimpleClientset() snapshoterBeta := snapshot.NewSnapshotBeta(kubeCli, dynCli) - + snapshotMeta = snapshot.ObjectMeta{ + Name: existingSnapshotName, + Namespace: namespace, + Annotations: annotations, + } + snapshotContentMeta = snapshot.ObjectMeta{ + Name: "content", + } volSnap = snapshot.UnstructuredVolumeSnapshot( snapshot.VolSnapGVR, - existingSnapshotName, - namespace, "pvcName", - "content", snapshotClass, - nil, - ) + snapshotMeta, snapshotContentMeta) volSnapClass = snapshot.UnstructuredVolumeSnapshotClass(snapshot.VolSnapClassGVR, snapshotClass, "driver", "DELETE", nil) dynCli = dynfake.NewSimpleDynamicClient(scheme, volSnap, volSnapClass) kubeCli = fake.NewSimpleClientset() snapshoterStable := snapshot.NewSnapshotStable(kubeCli, dynCli) - for _, snapshoter := range []snapshot.Snapshotter{snapshoterAlpha, snapshoterBeta, snapshoterStable} { - err := snapshoter.CreateFromSource(ctx, source, snapshotName, namespace, false, labels) + snapshotMeta = snapshot.ObjectMeta{ + Name: snapshotName, + Namespace: namespace, + Labels: labels, + Annotations: annotations, + } + err := snapshoter.CreateFromSource(ctx, source, false, snapshotMeta, snapshot.ObjectMeta{}) c.Assert(err, IsNil) foundSns, err := snapshoter.List(ctx, namespace, labels) c.Assert(err, IsNil) @@ -1265,8 +1391,17 @@ func (s *SnapshotTestSuite) TestCreateFromSourceStable(c *C) { namespace := "namespace" snapshotName := "snapname" snapshotClass := "volSnapClass" - - volSnap := snapshot.UnstructuredVolumeSnapshot(snapshot.VolSnapGVR, snapshotName, namespace, "pvcName", "content", snapshotClass, nil) + annotations := map[string]string{"annotationtest": "true"} + snapshotMeta := snapshot.ObjectMeta{ + Name: snapshotName, + Namespace: namespace, + Annotations: annotations, + } + snapshotContentMeta := snapshot.ObjectMeta{ + Name: "content", + } + volSnap := snapshot.UnstructuredVolumeSnapshot(snapshot.VolSnapGVR, "pvcName", snapshotClass, + snapshotMeta, snapshotContentMeta) volSnap.Object["status"] = map[string]interface{}{ "readyToUse": false, } @@ -1296,7 +1431,16 @@ func (s *SnapshotTestSuite) TestCreateFromSourceStable(c *C) { c.Assert(status["readyToUse"], Equals, false) // status not set - volSnap = snapshot.UnstructuredVolumeSnapshot(snapshot.VolSnapGVR, snapshotName, namespace, "pvcName", "content", snapshotClass, nil) + snapshotMeta = snapshot.ObjectMeta{ + Name: snapshotName, + Namespace: namespace, + Annotations: annotations, + } + snapshotContentMeta = snapshot.ObjectMeta{ + Name: "content", + } + volSnap = snapshot.UnstructuredVolumeSnapshot(snapshot.VolSnapGVR, "pvcName", snapshotClass, + snapshotMeta, snapshotContentMeta) dynCli = dynfake.NewSimpleDynamicClient(scheme, volSnap) snapshotterStable, ok = snapshot.NewSnapshotStable(kubeCli, dynCli).(*snapshot.SnapshotStable) c.Assert(ok, Equals, true) @@ -1449,7 +1593,12 @@ func (s *SnapshotLocalTestSuite) TestLabels(c *C) { } { var err error var list *snapv1.VolumeSnapshotList - err = fakeSs.Create(ctx, snapName, ns, volName, &snapClass, false, tc.createLabels) + snapshotMeta := snapshot.ObjectMeta{ + Name: snapName, + Namespace: ns, + Labels: tc.createLabels, + } + err = fakeSs.Create(ctx, volName, &snapClass, false, snapshotMeta) if err == nil { list, err = fakeSs.List(ctx, ns, tc.listLabel) c.Assert(len(list.Items), Equals, tc.numResults) @@ -1458,7 +1607,70 @@ func (s *SnapshotLocalTestSuite) TestLabels(c *C) { } } } - +func (s *SnapshotLocalTestSuite) TestAnnotations(c *C) { + ctx := context.Background() + scheme := runtime.NewScheme() + scheme.AddKnownTypeWithName(schema.GroupVersionKind{Group: "snapshot.storage.k8s.io", Version: "v1alpha1", Kind: "VolumeSnapshotList"}, &unstructured.UnstructuredList{}) + scheme.AddKnownTypeWithName(schema.GroupVersionKind{Group: "snapshot.storage.k8s.io", Version: "v1beta1", Kind: "VolumeSnapshotList"}, &unstructured.UnstructuredList{}) + scheme.AddKnownTypeWithName(schema.GroupVersionKind{Group: "snapshot.storage.k8s.io", Version: "v1", Kind: "VolumeSnapshotList"}, &unstructured.UnstructuredList{}) + ns := "namespace" + volName := "vol1" + snapName := "snap1" + snapClass := "snapClass" + fakeCli := fake.NewSimpleClientset(fakePVC(volName, ns)) + for _, tc := range []struct { + dynCli dynamic.Interface + snapshotAnnotations map[string]string + errChecker Checker + }{ + { + dynCli: dynfake.NewSimpleDynamicClient(scheme), + snapshotAnnotations: map[string]string{ + "annotationtest": "true", + }, + errChecker: IsNil, + }, + { // empty annotations list + dynCli: dynfake.NewSimpleDynamicClient(scheme), + snapshotAnnotations: map[string]string{}, + errChecker: IsNil, + }, + { // annotations list matches + dynCli: dynfake.NewSimpleDynamicClient(scheme), + snapshotAnnotations: map[string]string{ + "annotationtest": "true", + "annotationtest1": "false", + }, + errChecker: IsNil, + }, + { // nil lists + dynCli: dynfake.NewSimpleDynamicClient(scheme), + errChecker: IsNil, + }, + } { + for _, fakeSs := range []snapshot.Snapshotter{ + snapshot.NewSnapshotAlpha(fakeCli, tc.dynCli), + snapshot.NewSnapshotBeta(fakeCli, tc.dynCli), + snapshot.NewSnapshotStable(fakeCli, tc.dynCli), + } { + var err error + var vs *snapv1.VolumeSnapshot + snapshotMeta := snapshot.ObjectMeta{ + Name: snapName, + Namespace: ns, + Annotations: tc.snapshotAnnotations, + } + err = fakeSs.Create(ctx, volName, &snapClass, false, snapshotMeta) + if err == nil { + vs, err = fakeSs.Get(ctx, snapName, ns) + annotation := vs.GetAnnotations() + c.Assert(len(annotation), Equals, len(tc.snapshotAnnotations)) + c.Assert(annotation, DeepEquals, tc.snapshotAnnotations) + } + c.Check(err, tc.errChecker) + } + } +} func fakePVC(name, namespace string) *corev1.PersistentVolumeClaim { return &corev1.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ diff --git a/pkg/kube/snapshot/types.go b/pkg/kube/snapshot/types.go new file mode 100644 index 0000000000..dc8f8f5d18 --- /dev/null +++ b/pkg/kube/snapshot/types.go @@ -0,0 +1,9 @@ +package snapshot + +// ObjectMeta has common metadata fields that can be used to pass meta data of a resource around. +type ObjectMeta struct { + Name string `json:"name,omitempty"` + Namespace string `json:"namespace,omitempty"` + Labels map[string]string `json:"labels,omitempty"` + Annotations map[string]string `json:"annotations,omitempty"` +} diff --git a/releasenotes/notes/support-annotation-on-snapshotter-function-ff9b7ba2daf10427.yaml b/releasenotes/notes/support-annotation-on-snapshotter-function-ff9b7ba2daf10427.yaml new file mode 100644 index 0000000000..989f786dd2 --- /dev/null +++ b/releasenotes/notes/support-annotation-on-snapshotter-function-ff9b7ba2daf10427.yaml @@ -0,0 +1,2 @@ +--- +features: Add support to pass labels and annotations to the methods that create/clone VolumeSnapshot and VolumeSnapshotContent resources.