Merge "Fix indentation in docs"
diff --git a/.zuul.yaml b/.zuul.yaml
index 5b73695..e646d9b 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -11,6 +11,7 @@
       devstack_services:
         tempest: True
     run: playbooks/devstack-tempest.yaml
+    post-run: playbooks/post-tempest.yaml
 
 - project:
     name: openstack/tempest
diff --git a/playbooks/post-tempest.yaml b/playbooks/post-tempest.yaml
new file mode 100644
index 0000000..c0b9dd4
--- /dev/null
+++ b/playbooks/post-tempest.yaml
@@ -0,0 +1,16 @@
+- hosts: all
+  become: true
+  vars:
+    logs_root: "{{ devstack_base_dir|default('/opt/stack') }}"
+    stage_dir: "{{ devstack_base_dir|default('/opt/stack') }}"
+  roles:
+    - role: stage-output
+      zuul_copy_output:
+        { '{{ logs_root }}/tempest/etc/tempest.conf': 'logs',
+          '{{ logs_root }}/tempest/etc/accounts.yaml': 'logs',
+          '{{ logs_root }}/tempest/tempest.log': 'logs' }
+      extensions_to_txt:
+        - conf
+        - log
+        - yaml
+        - yml
diff --git a/requirements.txt b/requirements.txt
index 4b8de27..023148b 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,7 +4,7 @@
 pbr!=2.1.0,>=2.0.0 # Apache-2.0
 cliff!=2.9.0,>=2.8.0 # Apache-2.0
 jsonschema<3.0.0,>=2.6.0 # MIT
-testtools>=1.4.0 # MIT
+testtools>=2.2.0 # MIT
 paramiko>=2.0.0 # LGPLv2.1+
 netaddr>=0.7.18 # BSD
 testrepository>=0.0.18 # Apache-2.0/BSD
@@ -13,10 +13,10 @@
 oslo.log>=3.30.0 # Apache-2.0
 oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0
 oslo.utils>=3.31.0 # Apache-2.0
-six>=1.9.0 # MIT
+six>=1.10.0 # MIT
 fixtures>=3.0.0 # Apache-2.0/BSD
 PyYAML>=3.10 # MIT
-python-subunit>=0.0.18 # Apache-2.0/BSD
+python-subunit>=1.0.0 # Apache-2.0/BSD
 stevedore>=1.20.0 # Apache-2.0
 PrettyTable<0.8,>=0.7.1 # BSD
 os-testr>=1.0.0 # Apache-2.0
diff --git a/roles/run-tempest/README.rst b/roles/run-tempest/README.rst
index a75fc31..001586e 100644
--- a/roles/run-tempest/README.rst
+++ b/roles/run-tempest/README.rst
@@ -12,6 +12,13 @@
 
    The number of parallel test processes.
 
+.. zuul:rolevar:: tempest_test_regex
+   :default: ''
+
+   A regular expression used to select the tests.
+   It works only when used with some specific tox environments
+   ('all', 'all-plugin'.)
+
 .. zuul:rolevar:: tox_venvlist
    :default: smoke
 
diff --git a/roles/run-tempest/defaults/main.yaml b/roles/run-tempest/defaults/main.yaml
index e1e81da..3e57511 100644
--- a/roles/run-tempest/defaults/main.yaml
+++ b/roles/run-tempest/defaults/main.yaml
@@ -1,2 +1,3 @@
 devstack_base_dir: /opt/stack
+tempest_test_regex: ''
 tox_venvlist: smoke
diff --git a/roles/run-tempest/tasks/main.yaml b/roles/run-tempest/tasks/main.yaml
index d079513..297cd72 100644
--- a/roles/run-tempest/tasks/main.yaml
+++ b/roles/run-tempest/tasks/main.yaml
@@ -21,7 +21,7 @@
   when: num_cores|int > 3
 
 - name: Run Tempest
-  command: tox -e {{tox_venvlist}} -- --concurrency={{tempest_concurrency|default(default_concurrency)}}
+  command: tox -e {{tox_venvlist}} -- {{tempest_test_regex|quote}} --concurrency={{tempest_concurrency|default(default_concurrency)}}
   args:
     chdir: "{{devstack_base_dir}}/tempest"
   become: true
diff --git a/tempest/cmd/account_generator.py b/tempest/cmd/account_generator.py
index 8636405..c2f8627 100755
--- a/tempest/cmd/account_generator.py
+++ b/tempest/cmd/account_generator.py
@@ -55,8 +55,15 @@
 **-h**, **--help** (Optional) Shows help message with the description of
 utility and its arguments, and exits.
 
-**c /etc/tempest.conf**, **--config-file /etc/tempest.conf** (Optional) Path to
-tempest config file.
+**-c /etc/tempest.conf**, **--config-file /etc/tempest.conf** (Optional) Path
+to tempest config file. If not specified, it searches for tempest.conf in these
+locations:
+
+- ./etc/
+- /etc/tempest
+- ~/.tempest/
+- ~/
+- /etc/
 
 **--os-username <auth-user-name>** (Optional) Name used for authentication with
 the OpenStack Identity service. Defaults to env[OS_USERNAME]. Note: User should
@@ -78,7 +85,7 @@
 will have the prefix with the given TAG in its name. Using tag is recommended
 for the further using, cleaning resources.
 
-**-r CONCURRENCY**, **--concurrency CONCURRENCY** (Required) Concurrency count
+**-r CONCURRENCY**, **--concurrency CONCURRENCY** (Optional) Concurrency count
 (default: 1). The number of accounts required can be estimated as
 CONCURRENCY x 2. Each user provided in *accounts.yaml* file will be in
 a different tenant. This is required to provide isolation between test for
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 6a12b59..06b4b59 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -649,9 +649,7 @@
                 addresses = server['addresses'][
                     CONF.validation.network_for_ssh]
             else:
-                creds_provider = self._get_credentials_provider()
-                net_creds = creds_provider.get_primary_creds()
-                network = getattr(net_creds, 'network', None)
+                network = self.get_tenant_network()
                 addresses = (server['addresses'][network['name']]
                              if network else [])
             for address in addresses:
@@ -900,13 +898,17 @@
 
         result = test_utils.call_until_true(ping_remote,
                                             CONF.validation.ping_timeout, 1)
+        if result:
+            return
+
         source_host = source.ssh_client.host
         if should_succeed:
             msg = "Timed out waiting for %s to become reachable from %s" \
                 % (dest, source_host)
         else:
             msg = "%s is reachable from %s" % (dest, source_host)
-        self.assertTrue(result, msg)
+        self._log_console_output()
+        self.fail(msg)
 
     def _create_security_group(self, security_group_rules_client=None,
                                tenant_id=None,
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index 934e1dd..9f4e62b 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -130,7 +130,7 @@
         ssh = self.get_remote_client(
             ip_address=fip['floating_ip_address'],
             username=username, server=srv)
-        return ssh, ips, srv["id"]
+        return ssh, ips, srv
 
     def turn_nic6_on(self, ssh, sid, network_id):
         """Turns the IPv6 vNIC on
@@ -161,8 +161,8 @@
                                         n_subnets6=n_subnets6,
                                         dualnet=dualnet)
 
-        sshv4_1, ips_from_api_1, sid1 = self.prepare_server(networks=net_list)
-        sshv4_2, ips_from_api_2, sid2 = self.prepare_server(networks=net_list)
+        sshv4_1, ips_from_api_1, srv1 = self.prepare_server(networks=net_list)
+        sshv4_2, ips_from_api_2, srv2 = self.prepare_server(networks=net_list)
 
         def guest_has_address(ssh, addr):
             return addr in ssh.exec_command("ip address")
@@ -170,8 +170,8 @@
         # Turn on 2nd NIC for Cirros when dualnet
         if dualnet:
             _, network_v6 = net_list
-            self.turn_nic6_on(sshv4_1, sid1, network_v6['id'])
-            self.turn_nic6_on(sshv4_2, sid2, network_v6['id'])
+            self.turn_nic6_on(sshv4_1, srv1['id'], network_v6['id'])
+            self.turn_nic6_on(sshv4_2, srv2['id'], network_v6['id'])
 
         # get addresses assigned to vNIC as reported by 'ip address' utility
         ips_from_ip_1 = sshv4_1.exec_command("ip address")
@@ -181,13 +181,19 @@
         for i in range(n_subnets6):
             # v6 should be configured since the image supports it
             # It can take time for ipv6 automatic address to get assigned
-            self.assertTrue(test_utils.call_until_true(guest_has_address,
-                            CONF.validation.ping_timeout, 1,
-                            sshv4_1, ips_from_api_1['6'][i]))
-
-            self.assertTrue(test_utils.call_until_true(guest_has_address,
-                            CONF.validation.ping_timeout, 1,
-                            sshv4_2, ips_from_api_2['6'][i]))
+            for srv, ssh, ips in (
+                    (srv1, sshv4_1, ips_from_api_1),
+                    (srv2, sshv4_2, ips_from_api_2)):
+                ip = ips['6'][i]
+                result = test_utils.call_until_true(
+                    guest_has_address,
+                    CONF.validation.ping_timeout, 1, ssh, ip)
+                if not result:
+                    self._log_console_output(servers=[srv])
+                    self.fail(
+                        'Address %s not configured for instance %s, '
+                        'ip address output is\n%s' %
+                        (ip, srv['id'], ssh.exec_command("ip address")))
 
         self.check_remote_connectivity(sshv4_1, ips_from_api_2['4'])
         self.check_remote_connectivity(sshv4_2, ips_from_api_1['4'])