Dump basic network info  in the test_network_basic_ops

Add minimal debug debug capability for basic network informations,
These information, especially the nat rules in the router namespaces
 usually very helpful.

Change-Id: I8840cb5e388fc8b674b66f8de4e25754ccbe0863
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 8d96858..e8f898d 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -409,3 +409,7 @@
 log_check_interval = 60
 # The default number of threads created while stress test
 default_thread_number_per_action=4
+
+[debug]
+# Enable diagnostic commands
+enable = True
diff --git a/tempest/common/commands.py b/tempest/common/commands.py
new file mode 100644
index 0000000..4fc85b6
--- /dev/null
+++ b/tempest/common/commands.py
@@ -0,0 +1,76 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# 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 shlex
+import subprocess
+
+from tempest.openstack.common import log as logging
+
+LOG = logging.getLogger(__name__)
+
+# NOTE(afazekas):
+# These commands assumes the tempest node is the same as
+# the only one service node. all-in-one installation.
+
+
+def sudo_cmd_call(cmd):
+    args = shlex.split(cmd)
+    subprocess_args = {'stdout': subprocess.PIPE,
+                       'stderr': subprocess.STDOUT}
+    try:
+        proc = subprocess.Popen(['/usr/bin/sudo'] + args, **subprocess_args)
+        return proc.communicate()[0]
+        if proc.returncode != 0:
+            LOG.error(cmd + "returned with: " +
+                      proc.returncode + "exit status")
+    except subprocess.CalledProcessError as e:
+        LOG.error("command output:\n%s" % e.output)
+
+
+def ip_addr_raw():
+    return sudo_cmd_call("ip a")
+
+
+def ip_route_raw():
+    return sudo_cmd_call("ip r")
+
+
+def ip_ns_raw():
+    return sudo_cmd_call("ip netns list")
+
+
+def iptables_raw(table):
+    return sudo_cmd_call("iptables -v -S -t " + table)
+
+
+def ip_ns_list():
+    return ip_ns_raw().split()
+
+
+def ip_ns_exec(ns, cmd):
+    return sudo_cmd_call(" ".join(("ip netns exec", ns, cmd)))
+
+
+def ip_ns_addr(ns):
+    return ip_ns_exec(ns, "ip a")
+
+
+def ip_ns_route(ns):
+    return ip_ns_exec(ns, "ip r")
+
+
+def iptables_ns(ns, table):
+    return ip_ns_exec(ns, "iptables -v -S -t " + table)
diff --git a/tempest/common/debug.py b/tempest/common/debug.py
new file mode 100644
index 0000000..69c933c
--- /dev/null
+++ b/tempest/common/debug.py
@@ -0,0 +1,41 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# 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.common import commands
+from tempest import config
+
+from tempest.openstack.common import log as logging
+
+LOG = logging.getLogger(__name__)
+
+tables = ['filter', 'nat', 'mangle']
+
+
+def log_ip_ns():
+    if not config.TempestConfig().debug.enable:
+        return
+    LOG.info("Host Addr:\n" + commands.ip_addr_raw())
+    LOG.info("Host Route:\n" + commands.ip_route_raw())
+    for table in ['filter', 'nat', 'mangle']:
+        LOG.info('Host %s table:\n%s', table, commands.iptables_raw(table))
+    ns_list = commands.ip_ns_list()
+    LOG.info("Host ns list" + str(ns_list))
+    for ns in ns_list:
+        LOG.info("ns(%s) Addr:\n%s", ns, commands.ip_ns_addr(ns))
+        LOG.info("ns(%s) Route:\n%s", ns, commands.ip_ns_route(ns))
+        for table in ['filter', 'nat', 'mangle']:
+            LOG.info('ns(%s) table(%s):\n%s', ns, table,
+                     commands.iptables_ns(ns, table))
diff --git a/tempest/config.py b/tempest/config.py
index 7245b10..ce87bc6 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -609,6 +609,21 @@
     for opt in ServiceAvailableGroup:
         conf.register_opt(opt, group='service_available')
 
+debug_group = cfg.OptGroup(name="debug",
+                           title="Debug System")
+
+DebugGroup = [
+    cfg.BoolOpt('enable',
+                default=True,
+                help="Enable diagnostic commands"),
+]
+
+
+def register_debug_opts(conf):
+    conf.register_group(debug_group)
+    for opt in DebugGroup:
+        conf.register_opt(opt, group='debug')
+
 
 @singleton
 class TempestConfig:
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 930ffae..7ea0353 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -17,6 +17,7 @@
 #    under the License.
 
 from tempest.api.network import common as net_common
+from tempest.common import debug
 from tempest.common.utils.data_utils import rand_name
 from tempest import config
 from tempest.openstack.common import log as logging
@@ -245,10 +246,17 @@
         # key-based authentication by cloud-init.
         ssh_login = self.config.compute.image_ssh_user
         private_key = self.keypairs[self.tenant_id].private_key
-        for server, floating_ips in self.floating_ips.iteritems():
-            for floating_ip in floating_ips:
-                ip_address = floating_ip.floating_ip_address
-                self._check_vm_connectivity(ip_address, ssh_login, private_key)
+        try:
+            for server, floating_ips in self.floating_ips.iteritems():
+                for floating_ip in floating_ips:
+                    ip_address = floating_ip.floating_ip_address
+                    self._check_vm_connectivity(ip_address,
+                                                ssh_login,
+                                                private_key)
+        except Exception as exc:
+            LOG.exception(exc)
+            debug.log_ip_ns()
+            raise exc
 
     @attr(type='smoke')
     def test_network_basic_ops(self):