Merge "Add compute API tests for 'get-me-a-network'"
diff --git a/releasenotes/notes/volume-clients-as-library-9a3444dd63c134b3.yaml b/releasenotes/notes/volume-clients-as-library-9a3444dd63c134b3.yaml
index 6a4fc2b..cf504ad 100644
--- a/releasenotes/notes/volume-clients-as-library-9a3444dd63c134b3.yaml
+++ b/releasenotes/notes/volume-clients-as-library-9a3444dd63c134b3.yaml
@@ -12,5 +12,7 @@
       * extensions_client(v2)
       * hosts_client(v1)
       * hosts_client(v2)
+      * quotas_client(v1)
+      * quotas_client(v2)
       * services_client(v1)
       * services_client(v2)
diff --git a/tempest/api/compute/volumes/test_volumes_get.py b/tempest/api/compute/volumes/test_volumes_get.py
index 6074054..c276fe0 100644
--- a/tempest/api/compute/volumes/test_volumes_get.py
+++ b/tempest/api/compute/volumes/test_volumes_get.py
@@ -42,15 +42,14 @@
     @test.idempotent_id('f10f25eb-9775-4d9d-9cbe-1cf54dae9d5f')
     def test_volume_create_get_delete(self):
         # CREATE, GET, DELETE Volume
-        volume = None
         v_name = data_utils.rand_name('Volume')
         metadata = {'Type': 'work'}
         # Create volume
         volume = self.client.create_volume(size=CONF.volume.volume_size,
                                            display_name=v_name,
                                            metadata=metadata)['volume']
-        self.addCleanup(self.delete_volume, volume['id'])
         self.assertIn('id', volume)
+        self.addCleanup(self.delete_volume, volume['id'])
         self.assertIn('displayName', volume)
         self.assertEqual(volume['displayName'], v_name,
                          "The created volume name is not equal "
@@ -66,6 +65,10 @@
                          fetched_volume['displayName'],
                          'The fetched Volume is different '
                          'from the created Volume')
+        self.assertEqual(CONF.volume.volume_size,
+                         fetched_volume['size'],
+                         'The fetched volume size is different '
+                         'from the created Volume')
         self.assertEqual(volume['id'],
                          fetched_volume['id'],
                          'The fetched Volume is different '
diff --git a/tempest/api/object_storage/test_account_quotas_negative.py b/tempest/api/object_storage/test_account_quotas_negative.py
index 0eec387..ae8dfcc 100644
--- a/tempest/api/object_storage/test_account_quotas_negative.py
+++ b/tempest/api/object_storage/test_account_quotas_negative.py
@@ -13,9 +13,7 @@
 # under the License.
 
 from tempest.api.object_storage import base
-from tempest.common.utils import data_utils
 from tempest import config
-from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
@@ -91,14 +89,3 @@
         self.assertRaises(lib_exc.Forbidden,
                           self.account_client.create_account_metadata,
                           {"Quota-Bytes": "100"})
-
-    @test.attr(type=["negative"])
-    @decorators.skip_because(bug="1310597")
-    @test.idempotent_id('cf9e21f5-3aa4-41b1-9462-28ac550d8d3f')
-    @test.requires_ext(extension='account_quotas', service='object')
-    def test_upload_large_object(self):
-        object_name = data_utils.rand_name(name="TestObject")
-        data = data_utils.arbitrary_string(30)
-        self.assertRaises(lib_exc.OverLimit,
-                          self.object_client.create_object,
-                          self.container_name, object_name, data)
diff --git a/tempest/api/object_storage/test_container_quotas.py b/tempest/api/object_storage/test_container_quotas.py
index c26e49b..5ed92c4 100644
--- a/tempest/api/object_storage/test_container_quotas.py
+++ b/tempest/api/object_storage/test_container_quotas.py
@@ -70,7 +70,7 @@
     @test.requires_ext(extension='container_quotas', service='object')
     @test.attr(type="smoke")
     def test_upload_large_object(self):
-        """Attempts to upload an object lagger than the bytes quota."""
+        """Attempts to upload an object larger than the bytes quota."""
         object_name = data_utils.rand_name(name="TestObject")
         data = data_utils.arbitrary_string(QUOTA_BYTES + 1)
 
diff --git a/tempest/api/object_storage/test_container_services.py b/tempest/api/object_storage/test_container_services.py
index 296d8ee..cf6ded1 100644
--- a/tempest/api/object_storage/test_container_services.py
+++ b/tempest/api/object_storage/test_container_services.py
@@ -124,7 +124,6 @@
         # delete container, success asserted within
         resp, _ = self.container_client.delete_container(container_name)
         self.assertHeaders(resp, 'Container', 'DELETE')
-        self.containers.remove(container_name)
 
     @test.attr(type='smoke')
     @test.idempotent_id('312ff6bd-5290-497f-bda1-7c5fec6697ab')
diff --git a/tempest/api/volume/admin/test_multi_backend.py b/tempest/api/volume/admin/test_multi_backend.py
index 5615cf3..b7c4236 100644
--- a/tempest/api/volume/admin/test_multi_backend.py
+++ b/tempest/api/volume/admin/test_multi_backend.py
@@ -53,7 +53,7 @@
             cls._create_type_and_volume(backend_name, True)
 
     @classmethod
-    def _create_type_and_volume(self, backend_name_key, with_prefix):
+    def _create_type_and_volume(cls, backend_name_key, with_prefix):
         # Volume/Type creation
         type_name = data_utils.rand_name('Type')
         vol_name = data_utils.rand_name('Volume')
@@ -63,20 +63,20 @@
             extra_specs = {spec_key_with_prefix: backend_name_key}
         else:
             extra_specs = {spec_key_without_prefix: backend_name_key}
-        self.type = self.create_volume_type(name=type_name,
-                                            extra_specs=extra_specs)
+        cls.type = cls.create_volume_type(name=type_name,
+                                          extra_specs=extra_specs)
 
-        params = {self.name_field: vol_name, 'volume_type': type_name}
+        params = {cls.name_field: vol_name, 'volume_type': type_name}
 
-        self.volume = self.admin_volume_client.create_volume(
+        cls.volume = cls.admin_volume_client.create_volume(
             **params)['volume']
         if with_prefix:
-            self.volume_id_list_with_prefix.append(self.volume['id'])
+            cls.volume_id_list_with_prefix.append(cls.volume['id'])
         else:
-            self.volume_id_list_without_prefix.append(
-                self.volume['id'])
-        waiters.wait_for_volume_status(self.admin_volume_client,
-                                       self.volume['id'], 'available')
+            cls.volume_id_list_without_prefix.append(
+                cls.volume['id'])
+        waiters.wait_for_volume_status(cls.admin_volume_client,
+                                       cls.volume['id'], 'available')
 
     @classmethod
     def resource_cleanup(cls):
diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py
index e5fcdfe..4c6aeb7 100644
--- a/tempest/api/volume/test_volumes_get.py
+++ b/tempest/api/volume/test_volumes_get.py
@@ -41,7 +41,6 @@
 
     def _volume_create_get_update_delete(self, **kwargs):
         # Create a volume, Get it's details and Delete the volume
-        volume = {}
         v_name = data_utils.rand_name('Volume')
         metadata = {'Type': 'Test'}
         # Create a volume
@@ -103,7 +102,6 @@
         # Test volume create when display_name is none and display_description
         # contains specific characters,
         # then test volume update if display_name is duplicated
-        new_volume = {}
         new_v_desc = data_utils.rand_name('@#$%^* description')
         params = {self.descrip_field: new_v_desc,
                   'availability_zone': volume['availability_zone']}
diff --git a/tempest/services/volume/base/admin/base_quotas_client.py b/tempest/lib/services/volume/v1/quotas_client.py
similarity index 91%
copy from tempest/services/volume/base/admin/base_quotas_client.py
copy to tempest/lib/services/volume/v1/quotas_client.py
index 2c1f50d..8924b42 100644
--- a/tempest/services/volume/base/admin/base_quotas_client.py
+++ b/tempest/lib/services/volume/v1/quotas_client.py
@@ -18,8 +18,8 @@
 from tempest.lib.common import rest_client
 
 
-class BaseQuotasClient(rest_client.RestClient):
-    """Client class to send CRUD Volume Quotas API requests"""
+class QuotasClient(rest_client.RestClient):
+    """Client class to send CRUD Volume Quotas API V1 requests"""
 
     def show_default_quota_set(self, tenant_id):
         """List the default volume quota set for a tenant."""
@@ -46,7 +46,7 @@
         """Updates quota set
 
         Available params: see http://developer.openstack.org/
-                              api-ref-blockstorage-v2.html#updateQuotas-v2
+                              api-ref-blockstorage-v1.html#updateQuota
         """
         put_body = jsonutils.dumps({'quota_set': kwargs})
         resp, body = self.put('os-quota-sets/%s' % tenant_id, put_body)
diff --git a/tempest/services/volume/base/admin/base_quotas_client.py b/tempest/lib/services/volume/v2/quotas_client.py
similarity index 91%
rename from tempest/services/volume/base/admin/base_quotas_client.py
rename to tempest/lib/services/volume/v2/quotas_client.py
index 2c1f50d..a302045 100644
--- a/tempest/services/volume/base/admin/base_quotas_client.py
+++ b/tempest/lib/services/volume/v2/quotas_client.py
@@ -1,4 +1,5 @@
-# Copyright (C) 2014 eNovance SAS <licensing@enovance.com>
+# Copyright 2014 OpenStack Foundation
+# 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
@@ -18,8 +19,9 @@
 from tempest.lib.common import rest_client
 
 
-class BaseQuotasClient(rest_client.RestClient):
-    """Client class to send CRUD Volume Quotas API requests"""
+class QuotasClient(rest_client.RestClient):
+    """Client class to send CRUD Volume Quotas API V2 requests"""
+    api_version = "v2"
 
     def show_default_quota_set(self, tenant_id):
         """List the default volume quota set for a tenant."""
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 6da0570..62ab67d 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -235,7 +235,7 @@
             # and net['id'] if they come from
             # clients.networks_client.list_networks
             for net in networks:
-                net_id = net.get('uuid', net['id'])
+                net_id = net.get('uuid', net.get('id'))
                 if 'port' not in net:
                     port = self._create_port(network_id=net_id,
                                              client=clients.ports_client,
diff --git a/tempest/scenario/test_shelve_instance.py b/tempest/scenario/test_shelve_instance.py
index 4b9c61c..7f04b0d 100644
--- a/tempest/scenario/test_shelve_instance.py
+++ b/tempest/scenario/test_shelve_instance.py
@@ -53,25 +53,12 @@
         security_group = self._create_security_group()
         security_groups = [{'name': security_group['name']}]
 
-        if boot_from_volume:
-            volume = self.create_volume(size=CONF.volume.volume_size,
-                                        imageRef=CONF.compute.image_ref)
-            bd_map = [{
-                'device_name': 'vda',
-                'volume_id': volume['id'],
-                'delete_on_termination': '0'}]
-
-            server = self.create_server(
-                key_name=keypair['name'],
-                security_groups=security_groups,
-                block_device_mapping=bd_map,
-                wait_until='ACTIVE')
-        else:
-            server = self.create_server(
-                image_id=CONF.compute.image_ref,
-                key_name=keypair['name'],
-                security_groups=security_groups,
-                wait_until='ACTIVE')
+        server = self.create_server(
+            image_id=CONF.compute.image_ref,
+            key_name=keypair['name'],
+            security_groups=security_groups,
+            wait_until='ACTIVE',
+            volume_backed=boot_from_volume)
 
         instance_ip = self.get_server_ip(server)
         timestamp = self.create_timestamp(instance_ip,
diff --git a/tempest/services/volume/base/admin/base_types_client.py b/tempest/services/volume/base/admin/base_types_client.py
index afca752..0b0e061 100755
--- a/tempest/services/volume/base/admin/base_types_client.py
+++ b/tempest/services/volume/base/admin/base_types_client.py
@@ -62,13 +62,13 @@
         self.expected_success(200, resp.status)
         return rest_client.ResponseBody(resp, body)
 
-    def show_volume_type(self, volume_id):
+    def show_volume_type(self, volume_type_id):
         """Returns the details of a single volume_type.
 
         Available params: see http://developer.openstack.org/
                               api-ref-blockstorage-v2.html#showVolumeType
         """
-        url = "types/%s" % str(volume_id)
+        url = "types/%s" % volume_type_id
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
@@ -86,24 +86,24 @@
         self.expected_success(200, resp.status)
         return rest_client.ResponseBody(resp, body)
 
-    def delete_volume_type(self, volume_id):
+    def delete_volume_type(self, volume_type_id):
         """Deletes the Specified Volume_type.
 
         Available params: see http://developer.openstack.org/
                               api-ref-blockstorage-v2.html#deleteVolumeType
         """
-        resp, body = self.delete("types/%s" % str(volume_id))
+        resp, body = self.delete("types/%s" % volume_type_id)
         self.expected_success(202, resp.status)
         return rest_client.ResponseBody(resp, body)
 
-    def list_volume_types_extra_specs(self, vol_type_id, **params):
+    def list_volume_types_extra_specs(self, volume_type_id, **params):
         """List all the volume_types extra specs created.
 
         TODO: Current api-site doesn't contain this API description.
         After fixing the api-site, we need to fix here also for putting
         the link to api-site.
         """
-        url = 'types/%s/extra_specs' % str(vol_type_id)
+        url = 'types/%s/extra_specs' % volume_type_id
         if params:
             url += '?%s' % urllib.urlencode(params)
 
@@ -112,40 +112,39 @@
         self.expected_success(200, resp.status)
         return rest_client.ResponseBody(resp, body)
 
-    def show_volume_type_extra_specs(self, vol_type_id, extra_specs_name):
+    def show_volume_type_extra_specs(self, volume_type_id, extra_specs_name):
         """Returns the details of a single volume_type extra spec."""
-        url = "types/%s/extra_specs/%s" % (str(vol_type_id),
-                                           str(extra_specs_name))
+        url = "types/%s/extra_specs/%s" % (volume_type_id, extra_specs_name)
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
         return rest_client.ResponseBody(resp, body)
 
-    def create_volume_type_extra_specs(self, vol_type_id, extra_specs):
+    def create_volume_type_extra_specs(self, volume_type_id, extra_specs):
         """Creates a new Volume_type extra spec.
 
-        vol_type_id: Id of volume_type.
+        volume_type_id: Id of volume_type.
         extra_specs: A dictionary of values to be used as extra_specs.
         """
-        url = "types/%s/extra_specs" % str(vol_type_id)
+        url = "types/%s/extra_specs" % volume_type_id
         post_body = json.dumps({'extra_specs': extra_specs})
         resp, body = self.post(url, post_body)
         body = json.loads(body)
         self.expected_success(200, resp.status)
         return rest_client.ResponseBody(resp, body)
 
-    def delete_volume_type_extra_specs(self, vol_id, extra_spec_name):
+    def delete_volume_type_extra_specs(self, volume_type_id, extra_spec_name):
         """Deletes the Specified Volume_type extra spec."""
         resp, body = self.delete("types/%s/extra_specs/%s" % (
-            (str(vol_id)), str(extra_spec_name)))
+            volume_type_id, extra_spec_name))
         self.expected_success(202, resp.status)
         return rest_client.ResponseBody(resp, body)
 
-    def update_volume_type_extra_specs(self, vol_type_id, extra_spec_name,
+    def update_volume_type_extra_specs(self, volume_type_id, extra_spec_name,
                                        extra_specs):
         """Update a volume_type extra spec.
 
-        vol_type_id: Id of volume_type.
+        volume_type_id: Id of volume_type.
         extra_spec_name: Name of the extra spec to be updated.
         extra_spec: A dictionary of with key as extra_spec_name and the
                      updated value.
@@ -153,43 +152,42 @@
                               api-ref-blockstorage-v2.html#
                               updateVolumeTypeExtraSpecs
         """
-        url = "types/%s/extra_specs/%s" % (str(vol_type_id),
-                                           str(extra_spec_name))
+        url = "types/%s/extra_specs/%s" % (volume_type_id, extra_spec_name)
         put_body = json.dumps(extra_specs)
         resp, body = self.put(url, put_body)
         body = json.loads(body)
         self.expected_success(200, resp.status)
         return rest_client.ResponseBody(resp, body)
 
-    def show_encryption_type(self, vol_type_id):
+    def show_encryption_type(self, volume_type_id):
         """Get the volume encryption type for the specified volume type.
 
-        vol_type_id: Id of volume_type.
+        volume_type_id: Id of volume_type.
         """
-        url = "/types/%s/encryption" % str(vol_type_id)
+        url = "/types/%s/encryption" % volume_type_id
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
         return rest_client.ResponseBody(resp, body)
 
-    def create_encryption_type(self, vol_type_id, **kwargs):
+    def create_encryption_type(self, volume_type_id, **kwargs):
         """Create encryption type.
 
         TODO: Current api-site doesn't contain this API description.
         After fixing the api-site, we need to fix here also for putting
         the link to api-site.
         """
-        url = "/types/%s/encryption" % str(vol_type_id)
+        url = "/types/%s/encryption" % volume_type_id
         post_body = json.dumps({'encryption': kwargs})
         resp, body = self.post(url, post_body)
         body = json.loads(body)
         self.expected_success(200, resp.status)
         return rest_client.ResponseBody(resp, body)
 
-    def delete_encryption_type(self, vol_type_id):
+    def delete_encryption_type(self, volume_type_id):
         """Delete the encryption type for the specified volume-type."""
         resp, body = self.delete(
-            "/types/%s/encryption/provider" % str(vol_type_id))
+            "/types/%s/encryption/provider" % volume_type_id)
         self.expected_success(202, resp.status)
         return rest_client.ResponseBody(resp, body)
 
@@ -201,7 +199,7 @@
                               #createVolumeTypeAccessExt
         """
         post_body = json.dumps({'addProjectAccess': kwargs})
-        url = 'types/%s/action' % (volume_type_id)
+        url = 'types/%s/action' % volume_type_id
         resp, body = self.post(url, post_body)
         self.expected_success(202, resp.status)
         return rest_client.ResponseBody(resp, body)
@@ -214,7 +212,7 @@
                               #removeVolumeTypeAccessExt
         """
         post_body = json.dumps({'removeProjectAccess': kwargs})
-        url = 'types/%s/action' % (volume_type_id)
+        url = 'types/%s/action' % volume_type_id
         resp, body = self.post(url, post_body)
         self.expected_success(202, resp.status)
         return rest_client.ResponseBody(resp, body)
@@ -226,7 +224,7 @@
                               api-ref-blockstorage-v2.html#
                               listVolumeTypeAccessExt
         """
-        url = 'types/%s/os-volume-type-access' % (volume_type_id)
+        url = 'types/%s/os-volume-type-access' % volume_type_id
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
diff --git a/tempest/services/volume/v1/__init__.py b/tempest/services/volume/v1/__init__.py
index 52d2942..945d2f2 100644
--- a/tempest/services/volume/v1/__init__.py
+++ b/tempest/services/volume/v1/__init__.py
@@ -16,8 +16,8 @@
     AvailabilityZoneClient
 from tempest.lib.services.volume.v1.extensions_client import ExtensionsClient
 from tempest.lib.services.volume.v1.hosts_client import HostsClient
+from tempest.lib.services.volume.v1.quotas_client import QuotasClient
 from tempest.lib.services.volume.v1.services_client import ServicesClient
-from tempest.services.volume.v1.json.admin.quotas_client import QuotasClient
 from tempest.services.volume.v1.json.admin.types_client import TypesClient
 from tempest.services.volume.v1.json.backups_client import BackupsClient
 from tempest.services.volume.v1.json.qos_client import QosSpecsClient
diff --git a/tempest/services/volume/v1/json/admin/quotas_client.py b/tempest/services/volume/v1/json/admin/quotas_client.py
deleted file mode 100644
index 27fc301..0000000
--- a/tempest/services/volume/v1/json/admin/quotas_client.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright (C) 2014 eNovance SAS <licensing@enovance.com>
-#
-#    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.services.volume.base.admin import base_quotas_client
-
-
-class QuotasClient(base_quotas_client.BaseQuotasClient):
-    """Client class to send CRUD Volume Type API V1 requests"""
diff --git a/tempest/services/volume/v2/__init__.py b/tempest/services/volume/v2/__init__.py
index 26fbc2b..80f7a94 100644
--- a/tempest/services/volume/v2/__init__.py
+++ b/tempest/services/volume/v2/__init__.py
@@ -16,8 +16,8 @@
     AvailabilityZoneClient
 from tempest.lib.services.volume.v2.extensions_client import ExtensionsClient
 from tempest.lib.services.volume.v2.hosts_client import HostsClient
+from tempest.lib.services.volume.v2.quotas_client import QuotasClient
 from tempest.lib.services.volume.v2.services_client import ServicesClient
-from tempest.services.volume.v2.json.admin.quotas_client import QuotasClient
 from tempest.services.volume.v2.json.admin.types_client import TypesClient
 from tempest.services.volume.v2.json.backups_client import BackupsClient
 from tempest.services.volume.v2.json.qos_client import QosSpecsClient
diff --git a/tempest/services/volume/v2/json/admin/quotas_client.py b/tempest/services/volume/v2/json/admin/quotas_client.py
deleted file mode 100644
index 11e0e22..0000000
--- a/tempest/services/volume/v2/json/admin/quotas_client.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright 2014 OpenStack Foundation
-# 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.services.volume.base.admin import base_quotas_client
-
-
-class QuotasClient(base_quotas_client.BaseQuotasClient):
-    """Client class to send CRUD Volume V2 API requests"""
-    api_version = "v2"