Merge "Add "list Glance API versions" test"
diff --git a/README.rst b/README.rst
index 3d7c804..f44c503 100644
--- a/README.rst
+++ b/README.rst
@@ -4,7 +4,6 @@
 
 .. image:: http://governance.openstack.org/badges/tempest.svg
     :target: http://governance.openstack.org/reference/tags/index.html
-    :remote:
 
 .. Change things from this point on
 
diff --git a/releasenotes/notes/add-list-auth-project-client-5905076d914a3943.yaml b/releasenotes/notes/add-list-auth-project-client-5905076d914a3943.yaml
new file mode 100644
index 0000000..471f8f0
--- /dev/null
+++ b/releasenotes/notes/add-list-auth-project-client-5905076d914a3943.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    Add the list auth projects API to the identity client library. This feature
+    enables the possibility to list projects that are available to be scoped
+    to based on the X-Auth-Token provided in the request.
diff --git a/releasenotes/notes/deprecate-glance-api-version-config-options-8370b63aea8e14cf.yaml b/releasenotes/notes/deprecate-glance-api-version-config-options-8370b63aea8e14cf.yaml
new file mode 100644
index 0000000..788bc95
--- /dev/null
+++ b/releasenotes/notes/deprecate-glance-api-version-config-options-8370b63aea8e14cf.yaml
@@ -0,0 +1,10 @@
+---
+deprecations:
+  - |
+    Glance v1 APIs are deprecated and v2 are current.
+    Tempest should tests only v2 APIs.
+    Below API version selection config options
+    for glance have been deprecated and will be removed in future.
+
+    * CONF.image_feature_enabled.api_v2
+    * CONF.image_feature_enabled.api_v1
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 7dafc6b..ef13eef 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -295,20 +295,22 @@
     @classmethod
     def create_image_from_server(cls, server_id, **kwargs):
         """Wrapper utility that returns an image created from the server."""
-        name = data_utils.rand_name(cls.__name__ + "-image")
-        if 'name' in kwargs:
-            name = kwargs.pop('name')
+        name = kwargs.pop('name',
+                          data_utils.rand_name(cls.__name__ + "-image"))
+        wait_until = kwargs.pop('wait_until', None)
+        wait_for_server = kwargs.pop('wait_for_server', True)
 
-        image = cls.compute_images_client.create_image(server_id, name=name)
+        image = cls.compute_images_client.create_image(server_id, name=name,
+                                                       **kwargs)
         image_id = data_utils.parse_image_id(image.response['location'])
         cls.images.append(image_id)
 
-        if 'wait_until' in kwargs:
+        if wait_until is not None:
             try:
                 waiters.wait_for_image_status(cls.compute_images_client,
-                                              image_id, kwargs['wait_until'])
+                                              image_id, wait_until)
             except lib_exc.NotFound:
-                if kwargs['wait_until'].upper() == 'ACTIVE':
+                if wait_until.upper() == 'ACTIVE':
                     # If the image is not found after create_image returned
                     # that means the snapshot failed in nova-compute and nova
                     # deleted the image. There should be a compute fault
@@ -326,8 +328,8 @@
                     raise
             image = cls.compute_images_client.show_image(image_id)['image']
 
-            if kwargs['wait_until'] == 'ACTIVE':
-                if kwargs.get('wait_for_server', True):
+            if wait_until.upper() == 'ACTIVE':
+                if wait_for_server:
                     waiters.wait_for_server_status(cls.servers_client,
                                                    server_id, 'ACTIVE')
         return image
diff --git a/tempest/api/compute/images/test_images_negative.py b/tempest/api/compute/images/test_images_negative.py
index 945b191..86013d4 100644
--- a/tempest/api/compute/images/test_images_negative.py
+++ b/tempest/api/compute/images/test_images_negative.py
@@ -54,7 +54,7 @@
         meta = {'image_type': 'test'}
         self.assertRaises(lib_exc.NotFound,
                           self.create_image_from_server,
-                          server['id'], meta=meta)
+                          server['id'], metadata=meta)
 
     @test.attr(type=['negative'])
     @decorators.idempotent_id('82c5b0c4-9dbd-463c-872b-20c4755aae7f')
@@ -63,7 +63,7 @@
         # Create a new image with invalid server id
         meta = {'image_type': 'test'}
         self.assertRaises(lib_exc.NotFound, self.create_image_from_server,
-                          data_utils.rand_name('invalid'), meta=meta)
+                          data_utils.rand_name('invalid'), metadata=meta)
 
     @test.attr(type=['negative'])
     @decorators.idempotent_id('ec176029-73dc-4037-8d72-2e4ff60cf538')
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index bc88564..db24174 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -14,10 +14,8 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest.common import waiters
 from tempest import config
 from tempest.lib.common.utils import data_utils
-from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 
 CONF = config.CONF
@@ -53,15 +51,11 @@
         # Create a new image
         name = data_utils.rand_name('image')
         meta = {'image_type': 'test'}
-        body = self.client.create_image(server_id, name=name,
-                                        metadata=meta)
-        image_id = data_utils.parse_image_id(body.response['location'])
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.client.delete_image, image_id)
-        waiters.wait_for_image_status(self.client, image_id, 'ACTIVE')
+        image = self.create_image_from_server(server_id, name=name,
+                                              metadata=meta,
+                                              wait_until='ACTIVE')
 
         # Verify the image was created correctly
-        image = self.client.show_image(image_id)['image']
         self.assertEqual(name, image['name'])
         self.assertEqual('test', image['metadata']['image_type'])
 
@@ -76,8 +70,9 @@
                       (str(original_image['minDisk']), str(flavor_disk_size)))
 
         # Verify the image was deleted correctly
-        self.client.delete_image(image_id)
-        self.client.wait_for_resource_deletion(image_id)
+        self.client.delete_image(image['id'])
+        self.images.remove(image['id'])
+        self.client.wait_for_resource_deletion(image['id'])
 
     @decorators.idempotent_id('3b7c6fe4-dfe7-477c-9243-b06359db51e6')
     def test_create_image_specify_multibyte_character_image_name(self):
diff --git a/tempest/api/compute/images/test_images_oneserver_negative.py b/tempest/api/compute/images/test_images_oneserver_negative.py
index 51826c1..68563bd 100644
--- a/tempest/api/compute/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/images/test_images_oneserver_negative.py
@@ -33,9 +33,6 @@
 
     def tearDown(self):
         """Terminate test instances created after a test is executed."""
-        for image_id in self.image_ids:
-            self.client.delete_image(image_id)
-            self.image_ids.remove(image_id)
         self.server_check_teardown()
         super(ImagesOneServerNegativeTestJSON, self).tearDown()
 
@@ -80,25 +77,21 @@
         server = cls.create_test_server(wait_until='ACTIVE')
         cls.server_id = server['id']
 
-        cls.image_ids = []
-
     @test.attr(type=['negative'])
     @decorators.idempotent_id('55d1d38c-dd66-4933-9c8e-7d92aeb60ddc')
     def test_create_image_specify_invalid_metadata(self):
         # Return an error when creating image with invalid metadata
-        snapshot_name = data_utils.rand_name('test-snap')
         meta = {'': ''}
-        self.assertRaises(lib_exc.BadRequest, self.client.create_image,
-                          self.server_id, name=snapshot_name, metadata=meta)
+        self.assertRaises(lib_exc.BadRequest, self.create_image_from_server,
+                          self.server_id, metadata=meta)
 
     @test.attr(type=['negative'])
     @decorators.idempotent_id('3d24d11f-5366-4536-bd28-cff32b748eca')
     def test_create_image_specify_metadata_over_limits(self):
         # Return an error when creating image with meta data over 255 chars
-        snapshot_name = data_utils.rand_name('test-snap')
         meta = {'a' * 256: 'b' * 256}
-        self.assertRaises(lib_exc.BadRequest, self.client.create_image,
-                          self.server_id, name=snapshot_name, metadata=meta)
+        self.assertRaises(lib_exc.BadRequest, self.create_image_from_server,
+                          self.server_id, metadata=meta)
 
     @test.attr(type=['negative'])
     @decorators.idempotent_id('0460efcf-ee88-4f94-acef-1bf658695456')
@@ -106,16 +99,16 @@
         # Disallow creating another image when first image is being saved
 
         # Create first snapshot
-        snapshot_name = data_utils.rand_name('test-snap')
-        body = self.client.create_image(self.server_id, name=snapshot_name)
-        image_id = data_utils.parse_image_id(body.response['location'])
-        self.image_ids.append(image_id)
+        image = self.create_image_from_server(self.server_id)
         self.addCleanup(self._reset_server)
 
         # Create second snapshot
-        alt_snapshot_name = data_utils.rand_name('test-snap')
-        self.assertRaises(lib_exc.Conflict, self.client.create_image,
-                          self.server_id, name=alt_snapshot_name)
+        self.assertRaises(lib_exc.Conflict, self.create_image_from_server,
+                          self.server_id)
+
+        image_id = data_utils.parse_image_id(image.response['location'])
+        self.client.delete_image(image_id)
+        self.images.remove(image_id)
 
     @test.attr(type=['negative'])
     @decorators.idempotent_id('084f0cbc-500a-4963-8a4e-312905862581')
@@ -131,14 +124,13 @@
     def test_delete_image_that_is_not_yet_active(self):
         # Return an error while trying to delete an image what is creating
 
-        snapshot_name = data_utils.rand_name('test-snap')
-        body = self.client.create_image(self.server_id, name=snapshot_name)
-        image_id = data_utils.parse_image_id(body.response['location'])
-        self.image_ids.append(image_id)
+        image = self.create_image_from_server(self.server_id)
+        image_id = data_utils.parse_image_id(image.response['location'])
+
         self.addCleanup(self._reset_server)
 
         # Do not wait, attempt to delete the image, ensure it's successful
         self.client.delete_image(image_id)
-        self.image_ids.remove(image_id)
-
-        self.assertRaises(lib_exc.NotFound, self.client.show_image, image_id)
+        self.images.remove(image_id)
+        self.assertRaises(lib_exc.NotFound,
+                          self.client.show_image, image_id)
diff --git a/tempest/api/identity/admin/v3/test_tokens.py b/tempest/api/identity/admin/v3/test_tokens.py
index ed4d31a..fabb91c 100644
--- a/tempest/api/identity/admin/v3/test_tokens.py
+++ b/tempest/api/identity/admin/v3/test_tokens.py
@@ -16,10 +16,13 @@
 import six
 
 from tempest.api.identity import base
+from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 
+CONF = config.CONF
+
 
 class TokensV3TestJSON(base.BaseIdentityV3AdminTest):
 
@@ -150,3 +153,34 @@
                          token_auth['token']['project']['id'])
         self.assertEqual(project2['name'],
                          token_auth['token']['project']['name'])
+
+    @decorators.idempotent_id('08ed85ce-2ba8-4864-b442-bcc61f16ae89')
+    def test_get_available_project_scopes(self):
+        manager_project_id = self.manager.credentials.project_id
+        admin_user_id = self.os_adm.credentials.user_id
+        admin_role_id = self.get_role_by_name(CONF.identity.admin_role)['id']
+
+        # Grant the user the role on both projects.
+        self.roles_client.create_user_role_on_project(
+            manager_project_id, admin_user_id, admin_role_id)
+        self.addCleanup(
+            self.roles_client.delete_role_from_user_on_project,
+            manager_project_id, admin_user_id, admin_role_id)
+
+        assigned_project_ids = [self.os_adm.credentials.project_id,
+                                manager_project_id]
+
+        # Get available project scopes
+        available_projects =\
+            self.client.list_auth_projects()['projects']
+
+        # create list to save fetched project's id
+        fetched_project_ids = [i['id'] for i in available_projects]
+
+        # verifying the project ids in list
+        missing_project_ids = \
+            [p for p in assigned_project_ids
+             if p not in fetched_project_ids]
+        self.assertEmpty(missing_project_ids,
+                         "Failed to find project_id %s in fetched list" %
+                         ', '.join(missing_project_ids))
diff --git a/tempest/api/network/test_security_groups_negative.py b/tempest/api/network/test_security_groups_negative.py
index f46b873..218a79a 100644
--- a/tempest/api/network/test_security_groups_negative.py
+++ b/tempest/api/network/test_security_groups_negative.py
@@ -176,6 +176,16 @@
                           name=name)
 
     @test.attr(type=['negative'])
+    @decorators.idempotent_id('966e2b96-023a-11e7-a9e4-fa163e4fa634')
+    def test_create_security_group_update_name_default(self):
+        # Update security group name to 'default', it should be failed.
+        group_create_body, _ = self._create_security_group()
+        self.assertRaises(lib_exc.Conflict,
+                          self.security_groups_client.update_security_group,
+                          group_create_body['security_group']['id'],
+                          name="default")
+
+    @test.attr(type=['negative'])
     @decorators.idempotent_id('8fde898f-ce88-493b-adc9-4e4692879fc5')
     def test_create_duplicate_security_group_rule_fails(self):
         # Create duplicate security group rule, it should fail.
diff --git a/tempest/config.py b/tempest/config.py
index fb3b8f4..d5c8ea9 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -514,10 +514,20 @@
 ImageFeaturesGroup = [
     cfg.BoolOpt('api_v2',
                 default=True,
-                help="Is the v2 image API enabled"),
+                help="Is the v2 image API enabled",
+                deprecated_for_removal=True,
+                deprecated_reason='Glance v1 APIs are deprecated and v2 APIs '
+                                  'are current one. In future, Tempest will '
+                                  'test v2 APIs only so this config option '
+                                  'will be removed.'),
     cfg.BoolOpt('api_v1',
                 default=True,
-                help="Is the v1 image API enabled"),
+                help="Is the v1 image API enabled",
+                deprecated_for_removal=True,
+                deprecated_reason='Glance v1 APIs are deprecated and v2 APIs '
+                                  'are current one. In future, Tempest will '
+                                  'test v2 APIs only so this config option '
+                                  'will be removed.'),
     cfg.BoolOpt('deactivate_image',
                 default=False,
                 help="Is the deactivate-image feature enabled."
diff --git a/tempest/lib/services/identity/v3/identity_client.py b/tempest/lib/services/identity/v3/identity_client.py
index 8177e35..755c14b 100644
--- a/tempest/lib/services/identity/v3/identity_client.py
+++ b/tempest/lib/services/identity/v3/identity_client.py
@@ -43,3 +43,10 @@
         resp, body = self.delete("auth/tokens", headers=headers)
         self.expected_success(204, resp.status)
         return rest_client.ResponseBody(resp, body)
+
+    def list_auth_projects(self):
+        """Get available project scopes."""
+        resp, body = self.get("auth/projects")
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/tests/lib/services/identity/v3/test_identity_client.py b/tempest/tests/lib/services/identity/v3/test_identity_client.py
index 9eaaaaf..e435fe2 100644
--- a/tempest/tests/lib/services/identity/v3/test_identity_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_identity_client.py
@@ -32,6 +32,34 @@
         "description": "test_description"
     }
 
+    FAKE_AUTH_PROJECTS = {
+        "projects": [
+            {
+                "domain_id": "1789d1",
+                "enabled": True,
+                "id": "263fd9",
+                "links": {
+                    "self": "https://example.com/identity/v3/projects/263fd9"
+                },
+                "name": "Test Group"
+            },
+            {
+                "domain_id": "1789d1",
+                "enabled": True,
+                "id": "50ef01",
+                "links": {
+                    "self": "https://example.com/identity/v3/projects/50ef01"
+                },
+                "name": "Build Group"
+            }
+        ],
+        "links": {
+            "self": "https://example.com/identity/v3/auth/projects",
+            "previous": None,
+            "next": None
+        }
+    }
+
     def setUp(self):
         super(TestIdentityClient, self).setUp()
         fake_auth = fake_auth_provider.FakeAuthProvider()
@@ -54,6 +82,13 @@
             bytes_body,
             resp_token="cbc36478b0bd8e67e89")
 
+    def _test_list_auth_projects(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_auth_projects,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_AUTH_PROJECTS,
+            bytes_body)
+
     def test_show_api_description_with_str_body(self):
         self._test_show_api_description()
 
@@ -73,3 +108,9 @@
             {},
             resp_token="cbc36478b0bd8e67e89",
             status=204)
+
+    def test_list_auth_projects_with_str_body(self):
+        self._test_list_auth_projects()
+
+    def test_list_auth_projects_with_bytes_body(self):
+        self._test_list_auth_projects(bytes_body=True)