Merge "Formally deprecate the allow_port_security_disabled feature flag"
diff --git a/releasenotes/notes/add-image-clients-tests-49dbc0a0a4281a77.yaml b/releasenotes/notes/add-image-clients-tests-49dbc0a0a4281a77.yaml
new file mode 100644
index 0000000..9d1a003
--- /dev/null
+++ b/releasenotes/notes/add-image-clients-tests-49dbc0a0a4281a77.yaml
@@ -0,0 +1,9 @@
+---
+features:
+  - |
+    As in the [doc]:
+    http://developer.openstack.org/api-ref/image/v2/metadefs-index.html,
+    there are some apis are not included, add them.
+
+      * namespace_objects_client(v2)
+
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/releasenotes/notes/deprecate-identity-feature-enabled.reseller-84800a8232fe217f.yaml b/releasenotes/notes/deprecate-identity-feature-enabled.reseller-84800a8232fe217f.yaml
new file mode 100644
index 0000000..c0a06d1
--- /dev/null
+++ b/releasenotes/notes/deprecate-identity-feature-enabled.reseller-84800a8232fe217f.yaml
@@ -0,0 +1,8 @@
+---
+upgrade:
+  - The default value for the ``reseller`` option in the
+    ``identity-feature-enabled`` section has been changed from ``False``
+    to ``True``.
+deprecations:
+  - The ``reseller`` option in the ``identity-feature-enabled`` section is now
+    deprecated.
diff --git a/releasenotes/notes/deprecate-volume_feature_enabled.volume_services-dbe024ea067d5ab2.yaml b/releasenotes/notes/deprecate-volume_feature_enabled.volume_services-dbe024ea067d5ab2.yaml
new file mode 100644
index 0000000..c80f159
--- /dev/null
+++ b/releasenotes/notes/deprecate-volume_feature_enabled.volume_services-dbe024ea067d5ab2.yaml
@@ -0,0 +1,8 @@
+---
+upgrade:
+  - The default value for the ``volume_services`` option in the
+    ``volume_feature_enabled`` section has been changed from ``False``
+    to ``True``.
+deprecations:
+  - The ``volume_services`` option in the ``volume_feature_enabled`` section
+    is now deprecated.
diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py
index 140263c..eec42cd 100644
--- a/releasenotes/source/conf.py
+++ b/releasenotes/source/conf.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # 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
diff --git a/tempest/api/compute/admin/test_auto_allocate_network.py b/tempest/api/compute/admin/test_auto_allocate_network.py
index 8e481fd..08e4072 100644
--- a/tempest/api/compute/admin/test_auto_allocate_network.py
+++ b/tempest/api/compute/admin/test_auto_allocate_network.py
@@ -17,7 +17,6 @@
 from tempest.api.compute import base
 from tempest.common import compute
 from tempest.common import credentials_factory as credentials
-from tempest.common import waiters
 from tempest import config
 from tempest.lib.common.utils import test_utils
 from tempest.lib import exceptions as lib_excs
@@ -152,9 +151,7 @@
         # create the server with no networking
         server, _ = compute.create_test_server(
             self.os, networks='none', wait_until='ACTIVE')
-        self.addCleanup(waiters.wait_for_server_termination,
-                        self.servers_client, server['id'])
-        self.addCleanup(self.servers_client.delete_server, server['id'])
+        self.addCleanup(self.delete_server, server['id'])
         # get the server ips
         addresses = self.servers_client.list_addresses(
             server['id'])['addresses']
@@ -182,9 +179,7 @@
             min_count=3)
         server_nets = set()
         for server in servers:
-            self.addCleanup(waiters.wait_for_server_termination,
-                            self.servers_client, server['id'])
-            self.addCleanup(self.servers_client.delete_server, server['id'])
+            self.addCleanup(self.delete_server, server['id'])
             # get the server ips
             addresses = self.servers_client.list_addresses(
                 server['id'])['addresses']
diff --git a/tempest/api/compute/admin/test_volumes_negative.py b/tempest/api/compute/admin/test_volumes_negative.py
index b9dac6f..26b8742 100644
--- a/tempest/api/compute/admin/test_volumes_negative.py
+++ b/tempest/api/compute/admin/test_volumes_negative.py
@@ -49,6 +49,7 @@
                           self.server['id'], nonexistent_volume,
                           volumeId=volume['id'])
 
+    @test.related_bug('1629110', status_code=400)
     @test.idempotent_id('7dcac15a-b107-46d3-a5f6-cb863f4e454a')
     def test_update_attached_volume_with_nonexistent_volume_in_body(self):
         volume = self.create_volume()
diff --git a/tempest/api/compute/images/test_images_negative.py b/tempest/api/compute/images/test_images_negative.py
index 549262e..3923068 100644
--- a/tempest/api/compute/images/test_images_negative.py
+++ b/tempest/api/compute/images/test_images_negative.py
@@ -50,21 +50,19 @@
         self.servers_client.delete_server(server['id'])
         waiters.wait_for_server_termination(self.servers_client, server['id'])
         # Create a new image after server is deleted
-        name = data_utils.rand_name('image')
         meta = {'image_type': 'test'}
         self.assertRaises(lib_exc.NotFound,
                           self.create_image_from_server,
-                          server['id'], name=name, meta=meta)
+                          server['id'], meta=meta)
 
     @test.attr(type=['negative'])
     @test.idempotent_id('82c5b0c4-9dbd-463c-872b-20c4755aae7f')
     def test_create_image_from_invalid_server(self):
         # An image should not be created with invalid server id
         # Create a new image with invalid server id
-        name = data_utils.rand_name('image')
         meta = {'image_type': 'test'}
         self.assertRaises(lib_exc.NotFound, self.create_image_from_server,
-                          '!@$^&*()', name=name, meta=meta)
+                          '!@$^&*()', meta=meta)
 
     @test.attr(type=['negative'])
     @test.idempotent_id('ec176029-73dc-4037-8d72-2e4ff60cf538')
diff --git a/tempest/api/compute/security_groups/test_security_group_rules.py b/tempest/api/compute/security_groups/test_security_group_rules.py
index 38c294b..60caa19 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules.py
@@ -43,7 +43,6 @@
         group = {}
         ip_range = {}
         cls.expected = {
-            'id': None,
             'parent_group_id': None,
             'ip_protocol': cls.ip_protocol,
             'from_port': from_port,
@@ -54,8 +53,6 @@
 
     def _check_expected_response(self, actual_rule):
         for key in self.expected:
-            if key == 'id':
-                continue
             self.assertEqual(self.expected[key], actual_rule[key],
                              "Miss-matched key is %s" % key)
 
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index a21ce94..1731bf3 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -268,9 +268,7 @@
             self.os, tenant_network=network, wait_until='ACTIVE', min_count=2)
         # add our cleanups for the servers since we bypassed the base class
         for server in servers:
-            self.addCleanup(waiters.wait_for_server_termination,
-                            self.servers_client, server['id'])
-            self.addCleanup(self.servers_client.delete_server, server['id'])
+            self.addCleanup(self.delete_server, server['id'])
 
         for server in servers:
             # attach the port to the server
diff --git a/tempest/api/compute/servers/test_device_tagging.py b/tempest/api/compute/servers/test_device_tagging.py
index b2d5ae7..1d502be 100644
--- a/tempest/api/compute/servers/test_device_tagging.py
+++ b/tempest/api/compute/servers/test_device_tagging.py
@@ -19,7 +19,6 @@
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
 from tempest.common.utils.linux import remote_client
-from tempest.common import waiters
 from tempest import config
 from tempest.lib import exceptions
 from tempest import test
@@ -196,9 +195,7 @@
                 }
             ])
 
-        self.addCleanup(waiters.wait_for_server_termination,
-                        self.servers_client, server['id'])
-        self.addCleanup(self.servers_client.delete_server, server['id'])
+        self.addCleanup(self.delete_server, server['id'])
 
         self.ssh_client = remote_client.RemoteClient(
             self.get_server_ip(server),
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index 1b1b339..f66bc72 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -217,6 +217,26 @@
                           name=server_name)
 
     @test.attr(type=['negative'])
+    @test.related_bug('1651064', status_code=500)
+    @test.idempotent_id('12146ac1-d7df-4928-ad25-b1f99e5286cd')
+    def test_create_server_invalid_bdm_in_2nd_dict(self):
+        volume = self.create_volume()
+        bdm_1st = {"source_type": "image",
+                   "delete_on_termination": True,
+                   "boot_index": 0,
+                   "uuid": self.image_ref,
+                   "destination_type": "local"}
+        bdm_2nd = {"source_type": "volume",
+                   "uuid": volume["id"],
+                   "destination_type": "invalid"}
+        bdm = [bdm_1st, bdm_2nd]
+
+        self.assertRaises(lib_exc.BadRequest,
+                          self.create_test_server,
+                          image_id=self.image_ref,
+                          block_device_mapping_v2=bdm)
+
+    @test.attr(type=['negative'])
     @test.idempotent_id('4e72dc2d-44c5-4336-9667-f7972e95c402')
     def test_create_with_invalid_network_uuid(self):
         # Pass invalid network uuid while creating a server
diff --git a/tempest/api/identity/v3/test_users.py b/tempest/api/identity/v3/test_users.py
index f5b357c..f389a8f 100644
--- a/tempest/api/identity/v3/test_users.py
+++ b/tempest/api/identity/v3/test_users.py
@@ -157,4 +157,4 @@
 
         # If we wait the required time, the user account will be unlocked
         time.sleep(CONF.identity.user_lockout_duration + 1)
-        self.token.auth(user_id=self.user_id, password=password)
+        self.non_admin_token.auth(user_id=self.user_id, password=password)
diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py
index 812c436..23bd628 100644
--- a/tempest/api/image/base.py
+++ b/tempest/api/image/base.py
@@ -142,6 +142,7 @@
         cls.namespaces_client = cls.os.namespaces_client
         cls.resource_types_client = cls.os.resource_types_client
         cls.namespace_properties_client = cls.os.namespace_properties_client
+        cls.namespace_objects_client = cls.os.namespace_objects_client
         cls.schemas_client = cls.os.schemas_client
 
     def create_namespace(cls, namespace_name=None, visibility='public',
diff --git a/tempest/api/image/v1/test_images.py b/tempest/api/image/v1/test_images.py
index 0caaa67..b22ceed 100644
--- a/tempest/api/image/v1/test_images.py
+++ b/tempest/api/image/v1/test_images.py
@@ -30,13 +30,23 @@
     a_formats = ['ami', 'ari', 'aki']
 
     container_format = CONF.image.container_formats[0]
-    disk_format = CONF.image.disk_formats[0]
 
-    if container_format in a_formats and container_format != disk_format:
-        msg = ("The container format and the disk format don't match. "
-               "Container format: %(container)s, Disk format: %(disk)s." %
-               {'container': container_format, 'disk': disk_format})
-        raise exceptions.InvalidConfiguration(msg)
+    # In v1, If container_format is one of ['ami', 'ari', 'aki'], then
+    # disk_format must be same with container_format.
+    # If they are of different item sequence in tempest.conf, such as:
+    #     container_formats = ami,ari,aki,bare
+    #     disk_formats = ari,ami,aki,vhd
+    # we can select one in disk_format list that is same with container_format.
+    if container_format in a_formats:
+        if container_format in CONF.image.disk_formats:
+            disk_format = container_format
+        else:
+            msg = ("The container format and the disk format don't match. "
+                   "Container format: %(container)s, Disk format: %(disk)s." %
+                   {'container': container_format, 'disk': disk_format})
+            raise exceptions.InvalidConfiguration(msg)
+    else:
+        disk_format = CONF.image.disk_formats[0]
 
     return container_format, disk_format
 
diff --git a/tempest/api/image/v1/test_images_negative.py b/tempest/api/image/v1/test_images_negative.py
index d8f103a..3493cc2 100644
--- a/tempest/api/image/v1/test_images_negative.py
+++ b/tempest/api/image/v1/test_images_negative.py
@@ -15,6 +15,7 @@
 
 
 from tempest.api.image import base
+from tempest.common.utils import data_utils
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -44,7 +45,7 @@
     def test_delete_non_existent_image(self):
         # Return an error while trying to delete a non-existent image
 
-        non_existent_image_id = '11a22b9-12a9-5555-cc11-00ab112223fa'
+        non_existent_image_id = data_utils.rand_uuid()
         self.assertRaises(lib_exc.NotFound, self.client.delete_image,
                           non_existent_image_id)
 
@@ -58,9 +59,9 @@
     @test.idempotent_id('950e5054-a3c7-4dee-ada5-e576f1087abd')
     def test_delete_image_non_hex_string_id(self):
         # Return an error while trying to delete an image with non hex id
-        image_id = '11a22b9-120q-5555-cc11-00ab112223gj'
+        invalid_image_id = data_utils.rand_uuid()[:-1] + "j"
         self.assertRaises(lib_exc.NotFound, self.client.delete_image,
-                          image_id)
+                          invalid_image_id)
 
     @test.attr(type=['negative'])
     @test.idempotent_id('4ed757cd-450c-44b1-9fd1-c819748c650d')
@@ -70,7 +71,8 @@
 
     @test.attr(type=['negative'])
     @test.idempotent_id('a4a448ab-3db2-4d2d-b9b2-6a1271241dfe')
-    def test_delete_image_id_is_over_35_character_limit(self):
+    def test_delete_image_id_over_character_limit(self):
         # Return an error while trying to delete image with id over limit
+        overlimit_image_id = data_utils.rand_uuid() + "1"
         self.assertRaises(lib_exc.NotFound, self.client.delete_image,
-                          '11a22b9-12a9-5555-cc11-00ab112223fa-3fac')
+                          overlimit_image_id)
diff --git a/tempest/api/image/v2/test_images_metadefs_namespace_objects.py b/tempest/api/image/v2/test_images_metadefs_namespace_objects.py
new file mode 100644
index 0000000..95d1521
--- /dev/null
+++ b/tempest/api/image/v2/test_images_metadefs_namespace_objects.py
@@ -0,0 +1,73 @@
+#    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 tempest.api.image import base
+from tempest.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
+from tempest import test
+
+
+class MetadataNamespaceObjectsTest(base.BaseV2ImageTest):
+    """Test the Metadata definition namespace objects basic functionality"""
+
+    def _create_namespace_object(self, namespace):
+        object_name = data_utils.rand_name(self.__class__.__name__ + '-object')
+        namespace_object = self.namespace_objects_client.\
+            create_namespace_object(namespace['namespace'], name=object_name)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.namespace_objects_client.delete_namespace_object,
+                        namespace['namespace'], object_name)
+        return namespace_object
+
+    @test.idempotent_id('b1a3775e-3b5c-4f6a-a3b4-1ba3574ae718')
+    def test_create_update_delete_meta_namespace_objects(self):
+        # Create a namespace
+        namespace = self.create_namespace()
+        # Create a namespace object
+        body = self._create_namespace_object(namespace)
+        # Update a namespace object
+        up_object_name = data_utils.rand_name('update-object')
+        body = self.namespace_objects_client.update_namespace_object(
+            namespace['namespace'], body['name'],
+            name=up_object_name)
+        self.assertEqual(up_object_name, body['name'])
+        # Delete a namespace object
+        self.namespace_objects_client.delete_namespace_object(
+            namespace['namespace'], up_object_name)
+        # List namespace objects and validate deletion
+        namespace_objects = [
+            namespace_object['name'] for namespace_object in
+            self.namespace_objects_client.list_namespace_objects(
+                namespace['namespace'])['objects']]
+        self.assertNotIn(up_object_name, namespace_objects)
+
+    @test.idempotent_id('a2a3615e-3b5c-3f6a-a2b1-1ba3574ae738')
+    def test_list_meta_namespace_objects(self):
+        # Create a namespace object
+        namespace = self.create_namespace()
+        meta_namespace_object = self._create_namespace_object(namespace)
+        # List namespace objects
+        namespace_objects = [
+            namespace_object['name'] for namespace_object in
+            self.namespace_objects_client.list_namespace_objects(
+                namespace['namespace'])['objects']]
+        self.assertIn(meta_namespace_object['name'], namespace_objects)
+
+    @test.idempotent_id('b1a3674e-3b4c-3f6a-a3b4-1ba3573ca768')
+    def test_show_meta_namespace_objects(self):
+        # Create a namespace object
+        namespace = self.create_namespace()
+        namespace_object = self._create_namespace_object(namespace)
+        # Show a namespace object
+        body = self.namespace_objects_client.show_namespace_object(
+            namespace['namespace'], namespace_object['name'])
+        self.assertEqual(namespace_object['name'], body['name'])
diff --git a/tempest/api/orchestration/stacks/test_swift_resources.py b/tempest/api/orchestration/stacks/test_swift_resources.py
index c0f1c4b..3672526 100644
--- a/tempest/api/orchestration/stacks/test_swift_resources.py
+++ b/tempest/api/orchestration/stacks/test_swift_resources.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
 #
 # Licensed under the Apache License, Version 2.0 (the "License"); you may
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..6a3f9ee
--- /dev/null
+++ b/tempest/api/volume/admin/v2/test_snapshot_manage.py
@@ -0,0 +1,73 @@
+# 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.skipUnless(CONF.volume_feature_enabled.manage_snapshot,
+                          "Manage snapshot tests are disabled")
+    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..98e050e 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -165,14 +165,20 @@
     # NOTE(afazekas): these create_* and clean_* could be defined
     # only in a single location in the source, and could be more general.
 
-    @classmethod
-    def delete_volume(cls, client, volume_id):
+    @staticmethod
+    def delete_volume(client, volume_id):
         """Delete volume by the given client"""
         client.delete_volume(volume_id)
         client.wait_for_resource_deletion(volume_id)
 
+    @staticmethod
+    def delete_snapshot(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"""
+        """Attach a volume to a server"""
         self.servers_client.attach_volume(
             server_id, volumeId=volume_id,
             device='/dev/%s' % CONF.compute.volume_device_name)
@@ -257,6 +263,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/api/volume/test_volumes_backup.py b/tempest/api/volume/test_volumes_backup.py
index 70b3c58..6dcde08 100644
--- a/tempest/api/volume/test_volumes_backup.py
+++ b/tempest/api/volume/test_volumes_backup.py
@@ -89,14 +89,7 @@
                         volume['id'])
         server = self.create_server(wait_until='ACTIVE')
         # Attach volume to instance
-        self.servers_client.attach_volume(server['id'],
-                                          volumeId=volume['id'])
-        waiters.wait_for_volume_status(self.volumes_client,
-                                       volume['id'], 'in-use')
-        self.addCleanup(waiters.wait_for_volume_status, self.volumes_client,
-                        volume['id'], 'available')
-        self.addCleanup(self.servers_client.detach_volume, server['id'],
-                        volume['id'])
+        self.attach_volume(server['id'], volume['id'])
         # Create backup using force flag
         backup_name = data_utils.rand_name(
             self.__class__.__name__ + '-Backup')
diff --git a/tempest/clients.py b/tempest/clients.py
index 838f128..8093a72 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -127,6 +127,8 @@
             self.image_member_client_v2 = self.image_v2.ImageMembersClient()
             self.namespaces_client = self.image_v2.NamespacesClient()
             self.resource_types_client = self.image_v2.ResourceTypesClient()
+            self.namespace_objects_client = \
+                self.image_v2.NamespaceObjectsClient()
             self.schemas_client = self.image_v2.SchemasClient()
             self.namespace_properties_client = \
                 self.image_v2.NamespacePropertiesClient()
@@ -259,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/cmd/run.py b/tempest/cmd/run.py
index 5fa8b74..54b844a 100644
--- a/tempest/cmd/run.py
+++ b/tempest/cmd/run.py
@@ -21,7 +21,7 @@
 
  * **--regex/-r**: This is a selection regex like what testr uses. It will run
                    any tests that match on re.match() with the regex
- * **--smoke**: Run all the tests tagged as smoke
+ * **--smoke/-s**: Run all the tests tagged as smoke
 
 There are also the **--blacklist-file** and **--whitelist-file** options that
 let you pass a filepath to tempest run with the file format being a line
@@ -52,7 +52,7 @@
 There are several options to control how the tests are executed. By default
 tempest will run in parallel with a worker for each CPU present on the machine.
 If you want to adjust the number of workers use the **--concurrency** option
-and if you want to run tests serially use **--serial**
+and if you want to run tests serially use **--serial/-t**
 
 Running with Workspaces
 -----------------------
@@ -88,6 +88,7 @@
 from cliff import command
 from os_testr import regex_builder
 from os_testr import subunit_trace
+import six
 from testrepository.commands import run_argv
 
 from tempest.cmd import init
@@ -109,6 +110,12 @@
             return
         else:
             os.environ["TESTR_PDB"] = ""
+        # NOTE(dims): most of our .testr.conf try to test for PYTHON
+        # environment variable and fall back to "python", under python3
+        # if it does not exist. we should set it to the python3 executable
+        # to deal with this situation better for now.
+        if six.PY3 and 'PYTHON' not in os.environ:
+            os.environ['PYTHON'] = sys.executable
 
     def _create_testrepository(self):
         if not os.path.isdir('.testrepository'):
@@ -191,7 +198,7 @@
                             help='Configuration file to run tempest with')
         # test selection args
         regex = parser.add_mutually_exclusive_group()
-        regex.add_argument('--smoke', action='store_true',
+        regex.add_argument('--smoke', '-s', action='store_true',
                            help="Run the smoke tests only")
         regex.add_argument('--regex', '-r', default='',
                            help='A normal testr selection regex used to '
@@ -218,7 +225,7 @@
                               action='store_true',
                               help='Run tests in parallel (this is the'
                                    ' default)')
-        parallel.add_argument('--serial', dest='parallel',
+        parallel.add_argument('--serial', '-t', dest='parallel',
                               action='store_false',
                               help='Run tests serially')
         # output args
diff --git a/tempest/config.py b/tempest/config.py
index ba100a8..68f2667 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -220,8 +220,11 @@
     # TODO(rodrigods): Remove the reseller flag when Kilo and Liberty is end
     # of life.
     cfg.BoolOpt('reseller',
-                default=False,
-                help='Does the environment support reseller?'),
+                default=True,
+                help='Does the environment support reseller?',
+                deprecated_for_removal=True,
+                deprecated_reason="All supported version of OpenStack now "
+                                  "supports the 'reseller' feature"),
     cfg.BoolOpt('security_compliance',
                 default=False,
                 help='Does the environment have the security compliance '
@@ -804,6 +807,9 @@
     cfg.BoolOpt('clone',
                 default=True,
                 help='Runs Cinder volume clone test'),
+    cfg.BoolOpt('manage_snapshot',
+                default=False,
+                help='Runs Cinder manage snapshot tests'),
     cfg.ListOpt('api_extensions',
                 default=['all'],
                 help='A list of enabled volume extensions with a special '
@@ -820,8 +826,11 @@
                 help="Is the v3 volume API enabled"),
     # TODO(ynesenenko): Remove volume_services once liberty-eol happens.
     cfg.BoolOpt('volume_services',
-                default=False,
-                help='Extract correct host info from host@backend')
+                default=True,
+                help='Extract correct host info from host@backend',
+                deprecated_for_removal=True,
+                deprecated_reason='This config switch was added for Liberty '
+                                  'which is not supported anymore.')
 ]
 
 
diff --git a/tempest/lib/services/image/v2/__init__.py b/tempest/lib/services/image/v2/__init__.py
index d359d4b..a35ce17 100644
--- a/tempest/lib/services/image/v2/__init__.py
+++ b/tempest/lib/services/image/v2/__init__.py
@@ -15,6 +15,8 @@
 from tempest.lib.services.image.v2.image_members_client import \
     ImageMembersClient
 from tempest.lib.services.image.v2.images_client import ImagesClient
+from tempest.lib.services.image.v2.namespace_objects_client import \
+    NamespaceObjectsClient
 from tempest.lib.services.image.v2.namespace_properties_client import \
     NamespacePropertiesClient
 from tempest.lib.services.image.v2.namespaces_client import NamespacesClient
@@ -22,5 +24,6 @@
     ResourceTypesClient
 from tempest.lib.services.image.v2.schemas_client import SchemasClient
 
-__all__ = ['ImageMembersClient', 'ImagesClient', 'NamespacePropertiesClient',
-           'NamespacesClient', 'ResourceTypesClient', 'SchemasClient']
+__all__ = ['ImageMembersClient', 'ImagesClient', 'NamespaceObjectsClient',
+           'NamespacePropertiesClient', 'NamespacesClient',
+           'ResourceTypesClient', 'SchemasClient']
diff --git a/tempest/lib/services/image/v2/namespace_objects_client.py b/tempest/lib/services/image/v2/namespace_objects_client.py
new file mode 100644
index 0000000..ac2e63e
--- /dev/null
+++ b/tempest/lib/services/image/v2/namespace_objects_client.py
@@ -0,0 +1,91 @@
+# Copyright 2016 EasyStack.
+# 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 six.moves.urllib import parse as urllib
+
+from tempest.lib.common import rest_client
+
+
+class NamespaceObjectsClient(rest_client.RestClient):
+    api_version = "v2"
+
+    def list_namespace_objects(self, namespace, **kwargs):
+        """Lists all namespace objects.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#list-objects
+        """
+        url = 'metadefs/namespaces/%s/objects' % namespace
+        if kwargs:
+            url += '?%s' % urllib.urlencode(kwargs)
+        resp, body = self.get(url)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def create_namespace_object(self, namespace, **kwargs):
+        """Create a namespace object
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#create-object
+        """
+        url = 'metadefs/namespaces/%s/objects' % namespace
+        data = json.dumps(kwargs)
+        resp, body = self.post(url, data)
+        self.expected_success(201, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def update_namespace_object(self, namespace, object_name, **kwargs):
+        """Update a namespace object
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#update-object
+        """
+        url = 'metadefs/namespaces/%s/objects/%s' % (namespace, object_name)
+        data = json.dumps(kwargs)
+        resp, body = self.put(url, data)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_namespace_object(self, namespace, object_name):
+        """Show a namespace object
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#show-object
+        """
+        url = 'metadefs/namespaces/%s/objects/%s' % (namespace, object_name)
+        resp, body = self.get(url)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_namespace_object(self, namespace, object_name):
+        """Delete a namespace object
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#delete-object
+        """
+        url = 'metadefs/namespaces/%s/objects/%s' % (namespace, object_name)
+        resp, _ = self.delete(url)
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp)
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)
diff --git a/tempest/tests/lib/services/image/v2/test_namespace_object_client.py b/tempest/tests/lib/services/image/v2/test_namespace_object_client.py
new file mode 100644
index 0000000..8d29660
--- /dev/null
+++ b/tempest/tests/lib/services/image/v2/test_namespace_object_client.py
@@ -0,0 +1,210 @@
+# Copyright 2016 EasyStack. 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 tempest.lib.services.image.v2 import namespace_objects_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestNamespaceObjectClient(base.BaseServiceTest):
+    FAKE_CREATE_SHOW_OBJECTS = {
+        "created_at": "2016-09-19T18:20:56Z",
+        "description": "You can configure the CPU limits.",
+        "name": "CPU Limits",
+        "properties": {
+            "quota:cpu_period": {
+                "description": "Specifies the enforcement interval",
+                "maximum": 1000000,
+                "minimum": 1000,
+                "title": "Quota: CPU Period",
+                "type": "integer"
+            },
+            "quota:cpu_quota": {
+                "description": "Specifies the maximum allowed bandwidth ",
+                "title": "Quota: CPU Quota",
+                "type": "integer"
+            },
+            "quota:cpu_shares": {
+                "description": "Specifies the proportional weighted share.",
+                "title": "Quota: CPU Shares",
+                "type": "integer"
+            }
+        },
+        "required": [],
+        "schema": "/v2/schemas/metadefs/object",
+        "self": "/v2/metadefs/namespaces/OS::Compute::Quota/objects/CPU",
+        "updated_at": "2016-09-19T18:20:56Z"
+    }
+
+    FAKE_LIST_OBJECTS = {
+        "objects": [
+            {
+                "created_at": "2016-09-18T18:16:35Z",
+                "description": "You can configure the CPU limits.",
+                "name": "CPU Limits",
+                "properties": {
+                    "quota:cpu_period": {
+                        "description": "Specifies the enforcement interval ",
+                        "maximum": 1000000,
+                        "minimum": 1000,
+                        "title": "Quota: CPU Period",
+                        "type": "integer"
+                    },
+                    "quota:cpu_quota": {
+                        "description": "Specifies the maximum.",
+                        "title": "Quota: CPU Quota",
+                        "type": "integer"
+                    },
+                    "quota:cpu_shares": {
+                        "description": " Desc.",
+                        "title": "Quota: CPU Shares",
+                        "type": "integer"
+                    }
+                },
+                "required": [],
+                "schema": "/v2/schemas/metadefs/object",
+                "self":
+                    "/v2/metadefs/namespaces/OS::Compute::Quota/objects/CPU"
+            },
+            {
+                "created_at": "2016-09-18T18:16:35Z",
+                "description": "Using disk I/O quotas.",
+                "name": "Disk QoS",
+                "properties": {
+                    "quota:disk_read_bytes_sec": {
+                        "description": "Sets disk I/O quota.",
+                        "title": "Quota: Disk read bytes / sec",
+                        "type": "integer"
+                    },
+                    "quota:disk_read_iops_sec": {
+                        "description": "Sets disk I/O quota",
+                        "title": "Quota: Disk read IOPS / sec",
+                        "type": "integer"
+                    },
+                    "quota:disk_total_bytes_sec": {
+                        "description": "Sets disk I/O quota.",
+                        "title": "Quota: Disk Total Bytes / sec",
+                        "type": "integer"
+                    },
+                    "quota:disk_total_iops_sec": {
+                        "description": "Sets disk I/O quota.",
+                        "title": "Quota: Disk Total IOPS / sec",
+                        "type": "integer"
+                    },
+                    "quota:disk_write_bytes_sec": {
+                        "description": "Sets disk I/O quota.",
+                        "title": "Quota: Disk Write Bytes / sec",
+                        "type": "integer"
+                    },
+                    "quota:disk_write_iops_sec": {
+                        "description": "Sets disk I/O quota.",
+                        "title": "Quota: Disk Write IOPS / sec",
+                        "type": "integer"
+                    }
+                },
+                "required": [],
+                "schema": "/v2/schemas/metadefs/object",
+                "self":
+                "/v2/metadefs/namespaces/OS::Compute::Quota/objects/Disk QoS"
+            },
+        ],
+        "schema": "v2/schemas/metadefs/objects"
+    }
+
+    FAKE_UPDATE_OBJECTS = {
+        "description": "You can configure the CPU limits.",
+        "name": "CPU",
+        "properties": {
+            "quota:cpu_shares": {
+                "description": "Specify.",
+                "title": "Quota: CPU Shares",
+                "type": "integer"
+            }
+        },
+        "required": []
+    }
+
+    def setUp(self):
+        super(TestNamespaceObjectClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = namespace_objects_client.NamespaceObjectsClient(
+            fake_auth, 'image', 'regionOne')
+
+    def _test_create_namespace_objects(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.create_namespace_object,
+            'tempest.lib.common.rest_client.RestClient.post',
+            self.FAKE_CREATE_SHOW_OBJECTS,
+            bytes_body, status=201,
+            namespace="OS::Compute::Hypervisor",
+            object_name="OS::Glance::Image")
+
+    def _test_list_namespace_objects(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_namespace_objects,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_LIST_OBJECTS,
+            bytes_body,
+            namespace="OS::Compute::Hypervisor")
+
+    def _test_show_namespace_objects(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_namespace_object,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_CREATE_SHOW_OBJECTS,
+            bytes_body,
+            namespace="OS::Compute::Hypervisor",
+            object_name="OS::Glance::Image")
+
+    def _test_update_namespace_objects(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.update_namespace_object,
+            'tempest.lib.common.rest_client.RestClient.put',
+            self.FAKE_UPDATE_OBJECTS,
+            bytes_body,
+            namespace="OS::Compute::Hypervisor",
+            object_name="OS::Glance::Image",
+            name="CPU")
+
+    def test_create_namespace_object_with_str_body(self):
+        self._test_create_namespace_objects()
+
+    def test_create_namespace_object_with_bytes_body(self):
+        self._test_create_namespace_objects(bytes_body=True)
+
+    def test_list_namespace_object_with_str_body(self):
+        self._test_list_namespace_objects()
+
+    def test_list_namespace_object_with_bytes_body(self):
+        self._test_list_namespace_objects(bytes_body=True)
+
+    def test_show_namespace_object_with_str_body(self):
+        self._test_show_namespace_objects()
+
+    def test_show_namespace_object_with_bytes_body(self):
+        self._test_show_namespace_objects(bytes_body=True)
+
+    def test_update_namespace_object_with_str_body(self):
+        self._test_update_namespace_objects()
+
+    def test_update_namespace_object_with_bytes_body(self):
+        self._test_update_namespace_objects(bytes_body=True)
+
+    def test_delete_namespace_objects(self):
+        self.check_service_client_function(
+            self.client.delete_namespace_object,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {}, namespace="OS::Compute::Hypervisor",
+            object_name="OS::Glance::Image",
+            status=204)
diff --git a/tempest/tests/lib/test_tempest_lib.py b/tempest/tests/lib/test_tempest_lib.py
index d70e53d..4d9f099 100644
--- a/tempest/tests/lib/test_tempest_lib.py
+++ b/tempest/tests/lib/test_tempest_lib.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
 # 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