Merge "Add missing ws seperator between words part 2"
diff --git a/.zuul.yaml b/.zuul.yaml
index 9af79a6..93d1db5 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -1,7 +1,6 @@
 - job:
     name: devstack-tempest
     parent: devstack
-    nodeset: openstack-single-node
     description: |
       Base Tempest job.
 
@@ -53,7 +52,6 @@
 - job:
     name: devstack-tempest-ipv6
     parent: devstack-ipv6
-    nodeset: openstack-single-node
     description: |
       Base Tempest IPv6 job.
     required-projects:
@@ -196,7 +194,7 @@
 - job:
     name: tempest-multinode-full
     parent: devstack-tempest
-    nodeset: openstack-two-node
+    nodeset: openstack-two-node-bionic
     # Until the devstack changes are backported, only run this on master
     branches:
       - master
@@ -234,16 +232,6 @@
         nodes:
           - controller
 
-- job:
-    name: tempest-full-py36
-    parent: tempest-full-py3
-    nodeset: openstack-bionic-node
-    branches:
-      - master
-    description: |
-      Base integration test with Neutron networking and py36.
-    voting: false
-
 - nodeset:
     name: openstack-opensuse150-node
     nodes:
@@ -286,26 +274,31 @@
 - job:
     name: tempest-full-rocky
     parent: tempest-full
+    nodeset: openstack-single-node-xenial
     override-checkout: stable/rocky
 
 - job:
     name: tempest-full-rocky-py3
     parent: tempest-full-py3
+    nodeset: openstack-single-node-xenial
     override-checkout: stable/rocky
 
 - job:
     name: tempest-full-queens
     parent: tempest-full
+    nodeset: openstack-single-node-xenial
     override-checkout: stable/queens
 
 - job:
     name: tempest-full-queens-py3
     parent: tempest-full-py3
+    nodeset: openstack-single-node-xenial
     override-checkout: stable/queens
 
 - job:
     name: tempest-full-pike
     parent: tempest-full
+    nodeset: openstack-single-node-xenial
     override-checkout: stable/pike
 
 - job:
@@ -492,8 +485,6 @@
             irrelevant-files: *tempest-irrelevant-files
         - tempest-full-py3:
             irrelevant-files: *tempest-irrelevant-files
-        - tempest-full-py36:
-            irrelevant-files: *tempest-irrelevant-files
         - tempest-full-py3-ipv6:
             voting: false
             irrelevant-files: *tempest-irrelevant-files
@@ -522,8 +513,6 @@
               # tools/ is not here since this relies on a script in tools/.
         - tempest-slow:
             irrelevant-files: *tempest-irrelevant-files
-        - nova-cells-v1:
-            irrelevant-files: *tempest-irrelevant-files
         - nova-live-migration:
             voting: false
             irrelevant-files: *tempest-irrelevant-files
@@ -531,6 +520,8 @@
             irrelevant-files: *tempest-irrelevant-files
         - neutron-grenade:
             irrelevant-files: *tempest-irrelevant-files
+        - grenade-py3:
+            irrelevant-files: *tempest-irrelevant-files
         - devstack-plugin-ceph-tempest:
             voting: false
             irrelevant-files: *tempest-irrelevant-files
@@ -573,6 +564,8 @@
             irrelevant-files: *tempest-irrelevant-files
         - neutron-grenade:
             irrelevant-files: *tempest-irrelevant-files
+        - grenade-py3:
+            irrelevant-files: *tempest-irrelevant-files
     experimental:
       jobs:
         - tempest-cinder-v2-api:
@@ -583,6 +576,8 @@
             irrelevant-files: *tempest-irrelevant-files
         - neutron-tempest-dvr-ha-multinode-full:
             irrelevant-files: *tempest-irrelevant-files
+        - nova-cells-v1:
+            irrelevant-files: *tempest-irrelevant-files
         - legacy-tempest-dsvm-nova-v20-api:
             irrelevant-files: *tempest-irrelevant-files
         - legacy-tempest-dsvm-lvm-multibackend:
diff --git a/HACKING.rst b/HACKING.rst
index e8791f8..eb6551a 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -6,7 +6,7 @@
 - Step 2: Read on
 
 Tempest Specific Commandments
-------------------------------
+-----------------------------
 
 - [T102] Cannot import OpenStack python clients in tempest/api &
   tempest/scenario tests
diff --git a/doc/source/data/tempest-plugins-registry.header b/doc/source/data/tempest-plugins-registry.header
index 0de12b7..831d8a6 100644
--- a/doc/source/data/tempest-plugins-registry.header
+++ b/doc/source/data/tempest-plugins-registry.header
@@ -3,9 +3,9 @@
   job.  You should edit the files data/tempest-plugins-registry.footer
   and data/tempest-plugins-registry.header instead of this one.
 
-==========================
- Tempest Plugin Registry
-==========================
+=======================
+Tempest Plugin Registry
+=======================
 
 Since we've created the external plugin mechanism, it's gotten used by
 a lot of projects. The following is a list of plugins that currently
diff --git a/releasenotes/notes/add-immutable-user-source-support-dd17772a997075e0.yaml b/releasenotes/notes/add-immutable-user-source-support-dd17772a997075e0.yaml
new file mode 100644
index 0000000..931d689
--- /dev/null
+++ b/releasenotes/notes/add-immutable-user-source-support-dd17772a997075e0.yaml
@@ -0,0 +1,11 @@
+---
+features:
+  - |
+    Add a new config setting ``immutable_user_source`` in the
+    ``[identity-feature-enabled]`` group that defaults to false.
+    This setting, combined with the usage of the ``@testtools.skipIf()``
+    decorator, will allow tests that require user creation, deletion,
+    or modification to skip instead of failing in environments that
+    are LDAP-backed. In such environments, the user source is read-only,
+    so this feature flag is needed to allow such tests to gracefully skip
+    without having to blacklist them.
diff --git a/setup.cfg b/setup.cfg
index 96ee7ea..fcbe956 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -4,7 +4,7 @@
 description-file =
     README.rst
 author = OpenStack
-author-email = openstack-dev@lists.openstack.org
+author-email = openstack-discuss@lists.openstack.org
 home-page = https://docs.openstack.org/tempest/latest/
 classifier =
     Intended Audience :: Information Technology
diff --git a/tempest/README.rst b/tempest/README.rst
index a5f4a92..b345032 100644
--- a/tempest/README.rst
+++ b/tempest/README.rst
@@ -9,7 +9,7 @@
 OpenStack clouds.
 
 As such Tempest tests come in many flavors, each with their own rules
-and guidelines. Below is the overview of the Tempest respository structure
+and guidelines. Below is the overview of the Tempest repository structure
 to make this clear.
 
 .. code-block:: console
diff --git a/tempest/api/compute/admin/test_volume_swap.py b/tempest/api/compute/admin/test_volume_swap.py
index a853182..6b58939 100644
--- a/tempest/api/compute/admin/test_volume_swap.py
+++ b/tempest/api/compute/admin/test_volume_swap.py
@@ -70,6 +70,7 @@
     """The test suite for swapping of volume with admin user.
 
     The following is the scenario outline:
+
     1. Create a volume "volume1" with non-admin.
     2. Create a volume "volume2" with non-admin.
     3. Boot an instance "instance1" with non-admin.
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 4e2b59b..09dd409 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -477,7 +477,7 @@
         """Create a volume and wait for it to become 'available'.
 
         :param image_ref: Specify an image id to create a bootable volume.
-        :**kwargs: other parameters to create volume.
+        :param kwargs: other parameters to create volume.
         :returns: The available volume.
         """
         if 'size' not in kwargs:
diff --git a/tempest/api/identity/admin/v3/test_default_project_id.py b/tempest/api/identity/admin/v3/test_default_project_id.py
index 302a0e5..a79cbc3 100644
--- a/tempest/api/identity/admin/v3/test_default_project_id.py
+++ b/tempest/api/identity/admin/v3/test_default_project_id.py
@@ -9,6 +9,8 @@
 #    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.identity import base
 from tempest import clients
 from tempest import config
@@ -32,6 +34,10 @@
         self.domains_client.update_domain(domain_id, enabled=False)
         self.domains_client.delete_domain(domain_id)
 
+    @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source,
+                      'Skipped because environment has an '
+                      'immutable user source and solely '
+                      'provides read-only access to users.')
     @decorators.idempotent_id('d6110661-6a71-49a7-a453-b5e26640ff6d')
     def test_default_project_id(self):
         # create a domain
diff --git a/tempest/api/identity/admin/v3/test_users.py b/tempest/api/identity/admin/v3/test_users.py
index 3813568..8955a93 100644
--- a/tempest/api/identity/admin/v3/test_users.py
+++ b/tempest/api/identity/admin/v3/test_users.py
@@ -28,6 +28,14 @@
 
 class UsersV3TestJSON(base.BaseIdentityV3AdminTest):
 
+    @classmethod
+    def skip_checks(cls):
+        super(UsersV3TestJSON, cls).skip_checks()
+        if CONF.identity_feature_enabled.immutable_user_source:
+            raise cls.skipException('Skipped because environment has an '
+                                    'immutable user source and solely '
+                                    'provides read-only access to users.')
+
     @decorators.idempotent_id('b537d090-afb9-4519-b95d-270b0708e87e')
     def test_user_update(self):
         # Test case to check if updating of user attributes is successful.
diff --git a/tempest/api/network/admin/test_agent_management.py b/tempest/api/network/admin/test_agent_management.py
index 30ed176..eaf477c 100644
--- a/tempest/api/network/admin/test_agent_management.py
+++ b/tempest/api/network/admin/test_agent_management.py
@@ -48,11 +48,6 @@
             agent.pop('configurations', None)
         self.assertIn(self.agent, agents)
 
-    @decorators.idempotent_id('e335be47-b9a1-46fd-be30-0874c0b751e6')
-    def test_list_agents_non_admin(self):
-        body = self.agents_client.list_agents()
-        self.assertEmpty(body["agents"])
-
     @decorators.idempotent_id('869bc8e8-0fda-4a30-9b71-f8a7cf58ca9f')
     def test_show_agent(self):
         body = self.admin_agents_client.show_agent(self.agent['id'])
@@ -95,4 +90,4 @@
         non_existent_id = data_utils.rand_uuid()
         self.assertRaises(
             lib_exc.NotFound,
-            self.agents_client.delete_agent, non_existent_id)
+            self.admin_agents_client.delete_agent, non_existent_id)
diff --git a/tempest/api/network/admin/test_routers.py b/tempest/api/network/admin/test_routers.py
index a7355f3..6ce86fb 100644
--- a/tempest/api/network/admin/test_routers.py
+++ b/tempest/api/network/admin/test_routers.py
@@ -111,7 +111,8 @@
     def _verify_gateway_port(self, router_id):
         list_body = self.admin_ports_client.list_ports(
             network_id=CONF.network.public_network_id,
-            device_id=router_id)
+            device_id=router_id,
+            device_owner="network:router_gateway")
         self.assertEqual(len(list_body['ports']), 1)
         gw_port = list_body['ports'][0]
         fixed_ips = gw_port['fixed_ips']
diff --git a/tempest/api/network/test_agent_management_negative.py b/tempest/api/network/test_agent_management_negative.py
new file mode 100644
index 0000000..d1c02ce
--- /dev/null
+++ b/tempest/api/network/test_agent_management_negative.py
@@ -0,0 +1,28 @@
+# Copyright 2018 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.api.network import base
+from tempest.lib import decorators
+
+
+class AgentManagementNegativeTest(base.BaseNetworkTest):
+
+    @decorators.idempotent_id('e335be47-b9a1-46fd-be30-0874c0b751e6')
+    @decorators.attr(type=['negative'])
+    def test_list_agents_non_admin(self):
+        """Validate that non-admin user cannot list agents."""
+        # Listing agents requires admin_only permissions.
+        body = self.agents_client.list_agents()
+        self.assertEmpty(body["agents"])
diff --git a/tempest/api/object_storage/test_container_quotas.py b/tempest/api/object_storage/test_container_quotas.py
index 982c4a1..fcd9a7c 100644
--- a/tempest/api/object_storage/test_container_quotas.py
+++ b/tempest/api/object_storage/test_container_quotas.py
@@ -31,9 +31,10 @@
 
         Quotas are set by adding meta values to the container,
         and are validated when set:
-          - X-Container-Meta-Quota-Bytes:
+
+        - X-Container-Meta-Quota-Bytes:
                      Maximum size of the container, in bytes.
-          - X-Container-Meta-Quota-Count:
+        - X-Container-Meta-Quota-Count:
                      Maximum object count of the container.
         """
         super(ContainerQuotasTest, self).setUp()
diff --git a/tempest/api/volume/admin/test_volume_quotas_negative.py b/tempest/api/volume/admin/test_volume_quotas_negative.py
index 915aeec..5c7ab15 100644
--- a/tempest/api/volume/admin/test_volume_quotas_negative.py
+++ b/tempest/api/volume/admin/test_volume_quotas_negative.py
@@ -45,13 +45,6 @@
         cls.addClassResourceCleanup(cls.admin_quotas_client.update_quota_set,
                                     cls.demo_tenant_id, **cleanup_quota_set)
 
-        cls.shared_quota_set = {'gigabytes': 2 * CONF.volume.volume_size,
-                                'volumes': 1}
-
-        cls.admin_quotas_client.update_quota_set(
-            cls.demo_tenant_id,
-            **cls.shared_quota_set)
-
         # NOTE(gfidente): no need to delete in tearDown as
         # they are created using utility wrapper methods.
         cls.volume = cls.create_volume()
@@ -59,6 +52,8 @@
     @decorators.attr(type='negative')
     @decorators.idempotent_id('bf544854-d62a-47f2-a681-90f7a47d86b6')
     def test_quota_volumes(self):
+        self.admin_quotas_client.update_quota_set(self.demo_tenant_id,
+                                                  volumes=1, gigabytes=-1)
         self.assertRaises(lib_exc.OverLimit,
                           self.volumes_client.create_volume,
                           size=CONF.volume.volume_size)
@@ -66,17 +61,18 @@
     @decorators.attr(type='negative')
     @decorators.idempotent_id('2dc27eee-8659-4298-b900-169d71a91374')
     def test_quota_volume_gigabytes(self):
-        # NOTE(gfidente): quota set needs to be changed for this test
-        # or we may be limited by the volumes or snaps quota number, not by
-        # actual gigs usage; next line ensures shared set is restored.
-        self.addCleanup(self.admin_quotas_client.update_quota_set,
-                        self.demo_tenant_id,
-                        **self.shared_quota_set)
-        new_quota_set = {'gigabytes': CONF.volume.volume_size,
-                         'volumes': 2, 'snapshots': 1}
         self.admin_quotas_client.update_quota_set(
-            self.demo_tenant_id,
-            **new_quota_set)
+            self.demo_tenant_id, gigabytes=CONF.volume.volume_size, volumes=-1)
         self.assertRaises(lib_exc.OverLimit,
                           self.volumes_client.create_volume,
-                          size=CONF.volume.volume_size)
+                          size=CONF.volume.volume_size * 2)
+
+    @decorators.attr(type=['negative'])
+    @decorators.idempotent_id('d321dc21-d8c6-401f-95fe-49f4845f1a6d')
+    def test_volume_extend_gigabytes_quota_deviation(self):
+        self.admin_quotas_client.update_quota_set(
+            self.demo_tenant_id, gigabytes=CONF.volume.volume_size)
+        self.assertRaises(lib_exc.OverLimit,
+                          self.volumes_client.extend_volume,
+                          self.volume['id'],
+                          new_size=CONF.volume.volume_size * 2)
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index e218d5a..375113d 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -78,23 +78,22 @@
     :param wait_until: Server status to wait for the server to reach after
         its creation.
     :param volume_backed: Whether the server is volume backed or not.
-                          If this is true, a volume will be created and
-                          create server will be requested with
-                          'block_device_mapping_v2' populated with below
-                          values:
-                          --------------------------------------------
-                          bd_map_v2 = [{
-                              'uuid': volume['volume']['id'],
-                              'source_type': 'volume',
-                              'destination_type': 'volume',
-                              'boot_index': 0,
-                              'delete_on_termination': True}]
-                          kwargs['block_device_mapping_v2'] = bd_map_v2
-                          ---------------------------------------------
-                          If server needs to be booted from volume with other
-                          combination of bdm inputs than mentioned above, then
-                          pass the bdm inputs explicitly as kwargs and image_id
-                          as empty string ('').
+        If this is true, a volume will be created and create server will be
+        requested with 'block_device_mapping_v2' populated with below values:
+
+        .. code-block:: python
+
+            bd_map_v2 = [{
+                'uuid': volume['volume']['id'],
+                'source_type': 'volume',
+                'destination_type': 'volume',
+                'boot_index': 0,
+                'delete_on_termination': True}]
+            kwargs['block_device_mapping_v2'] = bd_map_v2
+
+        If server needs to be booted from volume with other combination of bdm
+        inputs than mentioned above, then pass the bdm inputs explicitly as
+        kwargs and image_id as empty string ('').
     :param name: Name of the server to be provisioned. If not defined a random
         string ending with '-instance' will be generated.
     :param flavor: Flavor of the server to be provisioned. If not defined,
diff --git a/tempest/common/identity.py b/tempest/common/identity.py
index eaf651b..525110b 100644
--- a/tempest/common/identity.py
+++ b/tempest/common/identity.py
@@ -64,7 +64,8 @@
     should not be used for testing identity features.
 
     :param clients: a client manager.
-    :return
+    :return: v2 or v3 of CredsClient
+    :rtype: V2CredsClient or V3CredsClient
     """
     if CONF.identity.auth_version == 'v2':
         client = clients.identity_client
diff --git a/tempest/config.py b/tempest/config.py
index bc609bc..716c000 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -262,7 +262,13 @@
     cfg.BoolOpt('application_credentials',
                 default=False,
                 help='Does the environment have application credentials '
-                     'enabled?')
+                     'enabled?'),
+    cfg.BoolOpt('immutable_user_source',
+                default=False,
+                help='Set to True if the environment has a read-only '
+                     'user source. This will skip all tests that attempt to '
+                     'create, delete, or modify users. This should not be set '
+                     'to True if using dynamic credentials')
 ]
 
 compute_group = cfg.OptGroup(name='compute',
diff --git a/tempest/lib/common/fixed_network.py b/tempest/lib/common/fixed_network.py
index 875a79d..926c3a4 100644
--- a/tempest/lib/common/fixed_network.py
+++ b/tempest/lib/common/fixed_network.py
@@ -24,7 +24,7 @@
     """Get a full network dict from just a network name
 
     :param str name: the name of the network to use
-    :param NetworksClient compute_networks_client: The network client
+    :param network.NetworksClient compute_networks_client: The network client
         object to use for making the network lists api request
     :return: The full dictionary for the network in question
     :rtype: dict
diff --git a/tempest/lib/common/utils/data_utils.py b/tempest/lib/common/utils/data_utils.py
index c5df590..438d73e 100644
--- a/tempest/lib/common/utils/data_utils.py
+++ b/tempest/lib/common/utils/data_utils.py
@@ -65,9 +65,9 @@
     :param int length: The length of password that you expect to set
                        (If it's smaller than 3, it's same as 3.)
     :return: a random password. The format is
-             '<random upper letter>-<random number>-<random special character>
-              -<random ascii letters or digit characters or special symbols>'
-             (e.g. 'G2*ac8&lKFFgh%2')
+        ``'<random upper letter>-<random number>-<random special character>
+        -<random ascii letters or digit characters or special symbols>'``
+        (e.g. ``G2*ac8&lKFFgh%2``)
     :rtype: string
     """
     upper = random.choice(string.ascii_uppercase)
diff --git a/tempest/lib/services/volume/v1/types_client.py b/tempest/lib/services/volume/v1/types_client.py
index 58a80b7..da9eb8b 100644
--- a/tempest/lib/services/volume/v1/types_client.py
+++ b/tempest/lib/services/volume/v1/types_client.py
@@ -149,10 +149,11 @@
                                        extra_specs):
         """Update a volume_type extra spec.
 
-        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.
+        :param volume_type_id: Id of volume_type.
+        :param extra_spec_name: Name of the extra spec to be updated.
+        :param extra_specs: A dictionary of with key as extra_spec_name and the
+                            updated value.
+
         For a full list of available parameters, please refer to the official
         API reference:
         https://developer.openstack.org/api-ref/block-storage/v2/#update-extra-specs-for-a-volume-type
diff --git a/tempest/lib/services/volume/v3/types_client.py b/tempest/lib/services/volume/v3/types_client.py
index 13ecd15..1405785 100644
--- a/tempest/lib/services/volume/v3/types_client.py
+++ b/tempest/lib/services/volume/v3/types_client.py
@@ -153,6 +153,7 @@
         :param extra_spec_name: Name of the extra spec to be updated.
         :param extra_specs: A dictionary of with key as extra_spec_name and the
                             updated value.
+
         For a full list of available parameters, please refer to the official
         API reference:
         https://developer.openstack.org/api-ref/block-storage/v3/index.html#update-extra-specification-for-volume-type
diff --git a/tempest/lib/services/volume/v3/volumes_client.py b/tempest/lib/services/volume/v3/volumes_client.py
index 11c5767..fec2950 100644
--- a/tempest/lib/services/volume/v3/volumes_client.py
+++ b/tempest/lib/services/volume/v3/volumes_client.py
@@ -182,7 +182,7 @@
 
         :param id: A checked resource id
         :raises lib_exc.DeleteErrorException: If the specified resource is on
-        the status the delete was failed.
+            the status the delete was failed.
         """
         try:
             volume = self.show_volume(id)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 00d45cd..dbb9acc 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -378,12 +378,12 @@
                           server=None):
         """Get a SSH client to a remote server
 
-        @param ip_address the server floating or fixed IP address to use
-                          for ssh validation
-        @param username name of the Linux account on the remote server
-        @param private_key the SSH private key to use
-        @param server: server dict, used for debugging purposes
-        @return a RemoteClient object
+        :param ip_address: the server floating or fixed IP address to use
+                           for ssh validation
+        :param username: name of the Linux account on the remote server
+        :param private_key: the SSH private key to use
+        :param server: server dict, used for debugging purposes
+        :return: a RemoteClient object
         """
 
         if username is None:
diff --git a/tempest/scenario/test_encrypted_cinder_volumes.py b/tempest/scenario/test_encrypted_cinder_volumes.py
index 8c210d5..008d1ae 100644
--- a/tempest/scenario/test_encrypted_cinder_volumes.py
+++ b/tempest/scenario/test_encrypted_cinder_volumes.py
@@ -29,11 +29,12 @@
 
     For both LUKS and cryptsetup encryption types, this test performs
     the following:
-        * Creates an image in Glance
-        * Boots an instance from the image
-        * Creates an encryption type (as admin)
-        * Creates a volume of that encryption type (as a regular user)
-        * Attaches and detaches the encrypted volume to the instance
+
+    * Creates an image in Glance
+    * Boots an instance from the image
+    * Creates an encryption type (as admin)
+    * Creates a volume of that encryption type (as a regular user)
+    * Attaches and detaches the encrypted volume to the instance
     """
 
     @classmethod
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index c522cf3..c11070c 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -374,39 +374,37 @@
     def test_network_basic_ops(self):
         """Basic network operation test
 
-        For a freshly-booted VM with an IP address ("port") on a given
-            network:
+        For a freshly-booted VM with an IP address ("port") on a given network:
 
         - the Tempest host can ping the IP address.  This implies, but
-         does not guarantee (see the ssh check that follows), that the
-         VM has been assigned the correct IP address and has
-         connectivity to the Tempest host.
+            does not guarantee (see the ssh check that follows), that the
+            VM has been assigned the correct IP address and has
+            connectivity to the Tempest host.
 
         - the Tempest host can perform key-based authentication to an
-         ssh server hosted at the IP address.  This check guarantees
-         that the IP address is associated with the target VM.
+            ssh server hosted at the IP address.  This check guarantees
+            that the IP address is associated with the target VM.
 
         - the Tempest host can ssh into the VM via the IP address and
-         successfully execute the following:
+            successfully execute the following:
 
-         - ping an external IP address, implying external connectivity.
+            - ping an external IP address, implying external connectivity.
 
-         - ping an external hostname, implying that dns is correctly
-           configured.
+            - ping an external hostname, implying that dns is correctly
+                configured.
 
-         - ping an internal IP address, implying connectivity to another
-           VM on the same network.
+            - ping an internal IP address, implying connectivity to another
+               VM on the same network.
 
         - detach the floating-ip from the VM and verify that it becomes
-        unreachable
+            unreachable
 
         - associate detached floating ip to a new VM and verify connectivity.
-        VMs are created with unique keypair so connectivity also asserts that
-        floating IP is associated with the new VM instead of the old one
+            VMs are created with unique keypair so connectivity also asserts
+            that floating IP is associated with the new VM instead of the old
+            one
 
         Verifies that floating IP status is updated correctly after each change
-
-
         """
         self._setup_network_and_servers()
         self._check_public_network_connectivity(should_connect=True)
@@ -445,30 +443,25 @@
     def test_connectivity_between_vms_on_different_networks(self):
         """Test connectivity between VMs on different networks
 
-        For a freshly-booted VM with an IP address ("port") on a given
-            network:
+        For a freshly-booted VM with an IP address ("port") on a given network:
 
         - the Tempest host can ping the IP address.
-
         - the Tempest host can ssh into the VM via the IP address and
-         successfully execute the following:
+            successfully execute the following:
 
-         - ping an external IP address, implying external connectivity.
-
-         - ping an external hostname, implying that dns is correctly
-           configured.
-
-         - ping an internal IP address, implying connectivity to another
-           VM on the same network.
+            - ping an external IP address, implying external connectivity.
+            - ping an external hostname, implying that dns is correctly
+               configured.
+            - ping an internal IP address, implying connectivity to another
+               VM on the same network.
 
         - Create another network on the same tenant with subnet, create
-        an VM on the new network.
+            an VM on the new network.
 
-         - Ping the new VM from previous VM failed since the new network
-         was not attached to router yet.
-
-         - Attach the new network to the router, Ping the new VM from
-         previous VM succeed.
+            - Ping the new VM from previous VM failed since the new network
+                was not attached to router yet.
+            - Attach the new network to the router, Ping the new VM from
+                previous VM succeed.
 
         """
         self._setup_network_and_servers()
@@ -561,24 +554,25 @@
     def test_subnet_details(self):
         """Tests that subnet's extra configuration details are affecting VMs.
 
-         This test relies on non-shared, isolated tenant networks.
+        This test relies on non-shared, isolated tenant networks.
 
-         NOTE: Neutron subnets push data to servers via dhcp-agent, so any
-         update in subnet requires server to actively renew its DHCP lease.
+        NOTE: Neutron subnets push data to servers via dhcp-agent, so any
+        update in subnet requires server to actively renew its DHCP lease.
 
-         1. Configure subnet with dns nameserver
-         2. retrieve the VM's configured dns and verify it matches the one
-         configured for the subnet.
-         3. update subnet's dns
-         4. retrieve the VM's configured dns and verify it matches the new one
-         configured for the subnet.
+        1. Configure subnet with dns nameserver
+        2. retrieve the VM's configured dns and verify it matches the one
+           configured for the subnet.
+        3. update subnet's dns
+        4. retrieve the VM's configured dns and verify it matches the new one
+           configured for the subnet.
 
-         TODO(yfried): add host_routes
+        TODO(yfried): add host_routes
 
-         any resolution check would be testing either:
-            * l3 forwarding (tested in test_network_basic_ops)
-            * Name resolution of an external DNS nameserver - out of scope for
-            Tempest
+        any resolution check would be testing either:
+
+        * l3 forwarding (tested in test_network_basic_ops)
+        * Name resolution of an external DNS nameserver - out of scope for
+          Tempest
         """
         # this test check only updates (no actual resolution) so using
         # arbitrary ip addresses as nameservers, instead of parsing CONF
@@ -748,7 +742,7 @@
         2. Remove router from all l3-agents
         3. Verify connectivity is down
         4. Assign router to new l3-agent (or old one if no new agent is
-         available)
+           available)
         5. Verify connectivity
         """
 
@@ -829,7 +823,8 @@
         prevents traffic to pass through the VM. Anti-spoof rules are not
         required in cases where the VM routes traffic through it.
 
-        The test steps are :
+        The test steps are:
+
         1. Create a new network.
         2. Connect (hotplug) the VM to a new network.
         3. Check the VM can ping a server on the new network ("peer")
@@ -838,7 +833,7 @@
            spoofed interface (VM cannot ping the peer).
         6. Disable port-security of the spoofed port- set the flag to false.
         7. Retest 3rd step and check that the Security Group allows pings via
-        the spoofed interface.
+           the spoofed interface.
         """
 
         spoof_mac = "00:00:00:00:00:01"
diff --git a/tempest/scenario/test_object_storage_basic_ops.py b/tempest/scenario/test_object_storage_basic_ops.py
index cbe321e..b635ca0 100644
--- a/tempest/scenario/test_object_storage_basic_ops.py
+++ b/tempest/scenario/test_object_storage_basic_ops.py
@@ -24,15 +24,15 @@
     def test_swift_basic_ops(self):
         """Test swift basic ops.
 
-         * get swift stat.
-         * create container.
-         * upload a file to the created container.
-         * list container's objects and assure that the uploaded file is
-         present.
-         * download the object and check the content
-         * delete object from container.
-         * list container's objects and assure that the deleted file is gone.
-         * delete a container.
+        * get swift stat.
+        * create container.
+        * upload a file to the created container.
+        * list container's objects and assure that the uploaded file is
+          present.
+        * download the object and check the content
+        * delete object from container.
+        * list container's objects and assure that the deleted file is gone.
+        * delete a container.
         """
         self.get_swift_stat()
         container_name = self.create_container()
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index 28a2d64..2b7926a 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -63,28 +63,28 @@
                 a. a security group open to incoming ssh connection
                 b. a VM with a floating ip
             5. create a general empty security group (same as "default", but
-            without rules allowing in-tenant traffic)
+               without rules allowing in-tenant traffic)
 
     tests:
         1. _verify_network_details
         2. _verify_mac_addr: for each access point verify that
-        (subnet, fix_ip, mac address) are as defined in the port list
+           (subnet, fix_ip, mac address) are as defined in the port list
         3. _test_in_tenant_block: test that in-tenant traffic is disabled
-        without rules allowing it
+           without rules allowing it
         4. _test_in_tenant_allow: test that in-tenant traffic is enabled
-        once an appropriate rule has been created
+           once an appropriate rule has been created
         5. _test_cross_tenant_block: test that cross-tenant traffic is disabled
-        without a rule allowing it on destination tenant
+           without a rule allowing it on destination tenant
         6. _test_cross_tenant_allow:
             * test that cross-tenant traffic is enabled once an appropriate
-            rule has been created on destination tenant.
+              rule has been created on destination tenant.
             * test that reverse traffic is still blocked
             * test than reverse traffic is enabled once an appropriate rule has
-            been created on source tenant
-        7._test_port_update_new_security_group:
-           * test that traffic is blocked with default security group
-           * test that traffic is enabled after updating port with new security
-           group having appropriate rule
+              been created on source tenant
+        7. _test_port_update_new_security_group:
+            * test that traffic is blocked with default security group
+            * test that traffic is enabled after updating port with new
+              security group having appropriate rule
         8. _test_multiple_security_groups: test multiple security groups can be
            associated with the vm
 
@@ -93,11 +93,13 @@
         2. Public network is defined and reachable from the Tempest host
         3. Public router can either be:
             * defined, in which case all tenants networks can connect directly
-            to it, and cross tenant check will be done on the private IP of the
-            destination tenant
+              to it, and cross tenant check will be done on the private IP of
+              the destination tenant
+
             or
+
             * not defined (empty string), in which case each tenant will have
-            its own router connected to the public network
+              its own router connected to the public network
     """
 
     credentials = ['primary', 'alt', 'admin']
diff --git a/tempest/test.py b/tempest/test.py
index 3e98c33..c3c58dc 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -259,6 +259,7 @@
         based on the result of an API call are discouraged.
 
         The following checks are implemented in `test.py` already:
+
         - check that alt credentials are available when requested by the test
         - check that admin credentials are available when requested by the test
         - check that the identity version specified by the test is marked as
@@ -310,6 +311,7 @@
         `os_[type]`:
 
         Valid values in `credentials` are:
+
         - 'primary':
             A normal user is provisioned.
             It can be used only once. Multiple entries will be ignored.
diff --git a/tempest/tests/files/setup.cfg b/tempest/tests/files/setup.cfg
index bd68708..a81d31e 100644
--- a/tempest/tests/files/setup.cfg
+++ b/tempest/tests/files/setup.cfg
@@ -3,7 +3,7 @@
 version = 1
 summary = Fake Project for testing wrapper scripts
 author = OpenStack
-author-email = openstack-dev@lists.openstack.org
+author-email = openstack-discuss@lists.openstack.org
 home-page = https://docs.openstack.org/tempest/latest/
 classifier =
     Intended Audience :: Information Technology
diff --git a/tox.ini b/tox.ini
index 4d3c622..4068054 100644
--- a/tox.ini
+++ b/tox.ini
@@ -48,6 +48,10 @@
   coverage xml -o cover/coverage.xml
   coverage report
 
+[testenv:debug]
+basepython = python3
+commands = oslo_debug_helper -t tempest/tests {posargs}
+
 [testenv:all]
 envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}