Merge "Unmanage and manage snapshots"
diff --git a/releasenotes/notes/add-snapshot-manage-client-as-library-a76ffdba9d8d01cb.yaml b/releasenotes/notes/add-snapshot-manage-client-as-library-a76ffdba9d8d01cb.yaml
new file mode 100644
index 0000000..9a4e6b1
--- /dev/null
+++ b/releasenotes/notes/add-snapshot-manage-client-as-library-a76ffdba9d8d01cb.yaml
@@ -0,0 +1,8 @@
+---
+features:
+  - |
+    Define v2 snapshot_manage_client client for the volume service as
+    library interfaces, allowing other projects to use this module as
+    stable libraries without maintenance changes.
+
+    * snapshot_manage_client(v2)
diff --git a/tempest/api/volume/admin/v2/test_snapshot_manage.py b/tempest/api/volume/admin/v2/test_snapshot_manage.py
new file mode 100644
index 0000000..98f6d32
--- /dev/null
+++ b/tempest/api/volume/admin/v2/test_snapshot_manage.py
@@ -0,0 +1,74 @@
+# Copyright 2016 Red Hat, Inc.
+# All Rights Reserved.
+#
+#    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.
+
+import testtools
+
+from tempest.api.volume import base
+from tempest.common import waiters
+from tempest import config
+from tempest import test
+
+CONF = config.CONF
+
+
+class SnapshotManageAdminV2Test(base.BaseVolumeAdminTest):
+    """Unmanage & manage snapshots
+
+     This feature provides the ability to import/export volume snapshot
+     from one Cinder to another and to import snapshots that have not been
+     managed by Cinder from a storage back end to Cinder
+    """
+
+    @test.idempotent_id('0132f42d-0147-4b45-8501-cc504bbf7810')
+    @testtools.skipIf(CONF.volume.storage_protocol == 'ceph',
+                      'Currently, Ceph does not support '
+                      'unmanage/manage snapshot')
+    def test_unmanage_manage_snapshot(self):
+        # Create a volume
+        volume = self.create_volume()
+
+        # Create a snapshot
+        snapshot = self.create_snapshot(volume_id=volume['id'])
+
+        # Unmanage the snapshot
+        # Unmanage snapshot function works almost the same as delete snapshot,
+        # but it does not delete the snapshot data
+        self.admin_snapshots_client.unmanage_snapshot(snapshot['id'])
+        self.admin_snapshots_client.wait_for_resource_deletion(snapshot['id'])
+
+        # Fetch snapshot ids
+        snapshot_list = [
+            snap['id'] for snap in
+            self.snapshots_client.list_snapshots()['snapshots']
+        ]
+
+        # Verify snapshot does not exist in snapshot list
+        self.assertNotIn(snapshot['id'], snapshot_list)
+
+        # Manage the snapshot
+        snapshot_ref = '_snapshot-%s' % snapshot['id']
+        new_snapshot = self.admin_snapshot_manage_client.manage_snapshot(
+            volume_id=volume['id'],
+            ref={'source-name': snapshot_ref})['snapshot']
+        self.addCleanup(self.delete_snapshot,
+                        self.admin_snapshots_client, new_snapshot['id'])
+
+        # Wait for the snapshot to be available after manage operation
+        waiters.wait_for_snapshot_status(self.admin_snapshots_client,
+                                         new_snapshot['id'],
+                                         'available')
+
+        # Verify the managed snapshot has the expected parent volume
+        self.assertEqual(new_snapshot['volume_id'], volume['id'])
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index 90dc7f4..d21f380 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -171,6 +171,11 @@
         client.delete_volume(volume_id)
         client.wait_for_resource_deletion(volume_id)
 
+    def delete_snapshot(self, client, snapshot_id):
+        """Delete snapshot by the given client"""
+        client.delete_snapshot(snapshot_id)
+        client.wait_for_resource_deletion(snapshot_id)
+
     def attach_volume(self, server_id, volume_id):
         """Attachs a volume to a server"""
         self.servers_client.attach_volume(
@@ -257,6 +262,8 @@
             cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
             cls.admin_volume_client = cls.os_adm.volumes_v2_client
             cls.admin_hosts_client = cls.os_adm.volume_hosts_v2_client
+            cls.admin_snapshot_manage_client = \
+                cls.os_adm.snapshot_manage_v2_client
             cls.admin_snapshots_client = cls.os_adm.snapshots_v2_client
             cls.admin_backups_client = cls.os_adm.backups_v2_client
             cls.admin_encryption_types_client = \
diff --git a/tempest/clients.py b/tempest/clients.py
index f99060a..8093a72 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -261,6 +261,7 @@
         self.encryption_types_client = self.volume_v1.EncryptionTypesClient()
         self.encryption_types_v2_client = \
             self.volume_v2.EncryptionTypesClient()
+        self.snapshot_manage_v2_client = self.volume_v2.SnapshotManageClient()
         self.snapshots_client = self.volume_v1.SnapshotsClient()
         self.snapshots_v2_client = self.volume_v2.SnapshotsClient()
         self.volumes_client = self.volume_v1.VolumesClient()
diff --git a/tempest/lib/services/volume/v2/__init__.py b/tempest/lib/services/volume/v2/__init__.py
index 837b4f6..8acad0f 100644
--- a/tempest/lib/services/volume/v2/__init__.py
+++ b/tempest/lib/services/volume/v2/__init__.py
@@ -27,6 +27,8 @@
 from tempest.lib.services.volume.v2.scheduler_stats_client import \
     SchedulerStatsClient
 from tempest.lib.services.volume.v2.services_client import ServicesClient
+from tempest.lib.services.volume.v2.snapshot_manage_client import \
+    SnapshotManageClient
 from tempest.lib.services.volume.v2.snapshots_client import SnapshotsClient
 from tempest.lib.services.volume.v2.types_client import TypesClient
 from tempest.lib.services.volume.v2.volumes_client import VolumesClient
@@ -34,4 +36,5 @@
 __all__ = ['AvailabilityZoneClient', 'BackupsClient', 'EncryptionTypesClient',
            'ExtensionsClient', 'HostsClient', 'QosSpecsClient', 'QuotasClient',
            'ServicesClient', 'SnapshotsClient', 'TypesClient', 'VolumesClient',
-           'LimitsClient', 'CapabilitiesClient', 'SchedulerStatsClient']
+           'LimitsClient', 'CapabilitiesClient', 'SchedulerStatsClient',
+           'SnapshotManageClient']
diff --git a/tempest/lib/services/volume/v2/snapshot_manage_client.py b/tempest/lib/services/volume/v2/snapshot_manage_client.py
new file mode 100644
index 0000000..aecd30b
--- /dev/null
+++ b/tempest/lib/services/volume/v2/snapshot_manage_client.py
@@ -0,0 +1,33 @@
+# Copyright 2016 Red Hat, Inc.
+# All Rights Reserved.
+#
+#    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.
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+
+
+class SnapshotManageClient(rest_client.RestClient):
+    """Snapshot manage V2 client."""
+
+    api_version = "v2"
+
+    def manage_snapshot(self, **kwargs):
+        """Manage a snapshot."""
+        post_body = json.dumps({'snapshot': kwargs})
+        url = 'os-snapshot-manage'
+        resp, body = self.post(url, post_body)
+        self.expected_success(202, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/volume/v2/snapshots_client.py b/tempest/lib/services/volume/v2/snapshots_client.py
index 6f51b51..2bdf1b1 100644
--- a/tempest/lib/services/volume/v2/snapshots_client.py
+++ b/tempest/lib/services/volume/v2/snapshots_client.py
@@ -184,3 +184,11 @@
         resp, body = self.post('snapshots/%s/action' % snapshot_id, post_body)
         self.expected_success(202, resp.status)
         return rest_client.ResponseBody(resp, body)
+
+    def unmanage_snapshot(self, snapshot_id):
+        """Unmanage a snapshot."""
+        post_body = json.dumps({'os-unmanage': {}})
+        url = 'snapshots/%s/action' % (snapshot_id)
+        resp, body = self.post(url, post_body)
+        self.expected_success(202, resp.status)
+        return rest_client.ResponseBody(resp, body)