From 09bff0da2a2292faf81cb1eab5c48e0ca6dcca68 Mon Sep 17 00:00:00 2001 From: George Paraskevopoulos Date: Fri, 21 Oct 2016 14:39:35 +0300 Subject: Add OVS logger Add utility class to log OVS flows from a remote server. Change-Id: I80cb5b20dc15477771beb912f44cab28c7397e24 Signed-off-by: George Paraskevopoulos (cherry picked from commit b2b00380b8d77b0037c9ef809d2538bb4e9428aa) --- testcases/features/sfc/SSHUtils.py | 120 ++++++++++++++++++++++++++++++++ testcases/features/sfc/ovs_utils.py | 80 +++++++++++++++++++++ testcases/features/sfc/sfc.py | 1 + testcases/features/sfc/sfc_colorado1.py | 1 + 4 files changed, 202 insertions(+) create mode 100644 testcases/features/sfc/SSHUtils.py create mode 100644 testcases/features/sfc/ovs_utils.py diff --git a/testcases/features/sfc/SSHUtils.py b/testcases/features/sfc/SSHUtils.py new file mode 100644 index 000000000..55cc5108b --- /dev/null +++ b/testcases/features/sfc/SSHUtils.py @@ -0,0 +1,120 @@ +############################################################################## +# Copyright (c) 2015 Ericsson AB and others. +# Authors: George Paraskevopoulos (geopar@intracom-telecom.com) +# Jose Lausuch (jose.lausuch@ericsson.com) +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + + +import paramiko +import functest.utils.functest_logger as rl +import os + +logger = rl.Logger('SSHUtils').getLogger() + + +def get_ssh_client(hostname, username, password=None, jumphost=None): + client = None + try: + if jumphost is None: + client = paramiko.SSHClient() + else: + client = JumpHostHopClient() + client.configure_jump_host(jumphost['ip'], + jumphost['username'], + jumphost['password']) + + if client is None: + raise Exception('Could not connect to client') + + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + client.connect(hostname, + username=username, + password=password) + return client + except Exception, e: + logger.error(e) + return None + + +def get_file(ssh_conn, src, dest): + try: + sftp = ssh_conn.open_sftp() + sftp.get(src, dest) + return True + except Exception, e: + logger.error("Error [get_file(ssh_conn, '%s', '%s']: %s" % + (src, dest, e)) + return None + + +def put_file(ssh_conn, src, dest): + try: + sftp = ssh_conn.open_sftp() + sftp.put(src, dest) + return True + except Exception, e: + logger.error("Error [put_file(ssh_conn, '%s', '%s']: %s" % + (src, dest, e)) + return None + + +class JumpHostHopClient(paramiko.SSHClient): + ''' + Connect to a remote server using a jumphost hop + ''' + def __init__(self, *args, **kwargs): + self.logger = rl.Logger("JumpHostHopClient").getLogger() + self.jumphost_ssh = None + self.jumphost_transport = None + self.jumphost_channel = None + self.jumphost_ip = None + self.jumphost_ssh_key = None + self.local_ssh_key = os.path.join(os.getcwd(), 'id_rsa') + super(JumpHostHopClient, self).__init__(*args, **kwargs) + + def configure_jump_host(self, jh_ip, jh_user, jh_pass, + jh_ssh_key='/root/.ssh/id_rsa'): + self.jumphost_ip = jh_ip + self.jumphost_ssh_key = jh_ssh_key + self.jumphost_ssh = paramiko.SSHClient() + self.jumphost_ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + self.jumphost_ssh.connect(jh_ip, + username=jh_user, + password=jh_pass) + self.jumphost_transport = self.jumphost_ssh.get_transport() + + def connect(self, hostname, port=22, username='root', password=None, + pkey=None, key_filename=None, timeout=None, allow_agent=True, + look_for_keys=True, compress=False, sock=None, gss_auth=False, + gss_kex=False, gss_deleg_creds=True, gss_host=None, + banner_timeout=None): + try: + if self.jumphost_ssh is None: + raise Exception('You must configure the jump ' + 'host before calling connect') + + get_file_res = get_file(self.jumphost_ssh, + self.jumphost_ssh_key, + self.local_ssh_key) + if get_file_res is None: + raise Exception('Could\'t fetch SSH key from jump host') + jumphost_key = (paramiko.RSAKey + .from_private_key_file(self.local_ssh_key)) + + self.jumphost_channel = self.jumphost_transport.open_channel( + "direct-tcpip", + (hostname, 22), + (self.jumphost_ip, 22)) + + self.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + super(JumpHostHopClient, self).connect(hostname, + username=username, + pkey=jumphost_key, + sock=self.jumphost_channel) + os.remove(self.local_ssh_key) + except Exception, e: + self.logger.error(e) diff --git a/testcases/features/sfc/ovs_utils.py b/testcases/features/sfc/ovs_utils.py new file mode 100644 index 000000000..83a36286d --- /dev/null +++ b/testcases/features/sfc/ovs_utils.py @@ -0,0 +1,80 @@ +############################################################################## +# Copyright (c) 2015 Ericsson AB and others. +# Author: George Paraskevopoulos (geopar@intracom-telecom.com) +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +import functest.utils.functest_logger as rl +import os +import time + +logger = rl.Logger('ovs_utils').getLogger() + + +class OVSLogger(object): + def __init__(self, basedir): + self.ovs_dir = os.path.join(basedir, 'odl-sfc/ovs') + self.__mkdir_p(self.ovs_dir) + + def __mkdir_p(self, dirpath): + if not os.path.exists(dirpath): + os.makedirs(dirpath) + + def __ssh_host(self, ssh_conn): + return ssh_conn.get_transport().getpeername()[0] + + def __dump_to_file(self, operation, host, text, timestamp=None): + ts = (timestamp if timestamp is not None + else time.strftime("%Y%m%d-%H%M%S")) + dumpdir = os.path.join(self.ovs_dir, ts) + self.__mkdir_p(dumpdir) + fname = '{0}_{1}'.format(operation, host) + with open(os.path.join(dumpdir, fname), 'w') as f: + f.write(text) + + def __remote_cmd(self, ssh_conn, cmd): + try: + _, stdout, stderr = ssh_conn.exec_command(cmd) + errors = stderr.readlines() + if len(errors) > 0: + host = self.__ssh_host(ssh_conn) + logger.error(''.join(errors)) + raise Exception('Could not execute {0} in {1}' + .format(cmd, host)) + output = ''.join(stdout.readlines()) + return output + except Exception, e: + logger.error('[__remote_command(ssh_client, {0})]: {1}' + .format(cmd, e)) + return None + + def ofctl_dump_flows(self, ssh_conn, br='br-int', + choose_table=None, timestamp=None): + try: + cmd = 'ovs-ofctl -OOpenFlow13 dump-flows {0}'.format(br) + if choose_table is not None: + cmd = '{0} table={1}'.format(cmd, choose_table) + output = self.__remote_cmd(ssh_conn, cmd) + operation = 'ofctl_dump_flows' + host = self.__ssh_host(ssh_conn) + self.__dump_to_file(operation, host, output, timestamp=timestamp) + return output + except Exception, e: + logger.error('[ofctl_dump_flows(ssh_client, {0}, {1})]: {2}' + .format(br, choose_table, e)) + return None + + def vsctl_show(self, ssh_conn, timestamp=None): + try: + cmd = 'ovs-vsctl show' + output = self.__remote_cmd(ssh_conn, cmd) + operation = 'vsctl_show' + host = self.__ssh_host(ssh_conn) + self.__dump_to_file(operation, host, output, timestamp=timestamp) + return output + except Exception, e: + logger.error('[vsctl_show(ssh_client)]: {0}'.format(e)) + return None diff --git a/testcases/features/sfc/sfc.py b/testcases/features/sfc/sfc.py index 8fd68bc3f..038f165ca 100755 --- a/testcases/features/sfc/sfc.py +++ b/testcases/features/sfc/sfc.py @@ -21,6 +21,7 @@ args = parser.parse_args() """ logging configuration """ logger = ft_logger.Logger("ODL_SFC").getLogger() +FUNCTEST_RESULTS_DIR = '/home/opnfv/functest/results/' FUNCTEST_REPO = ft_utils.FUNCTEST_REPO HOME = os.environ['HOME'] + "/" diff --git a/testcases/features/sfc/sfc_colorado1.py b/testcases/features/sfc/sfc_colorado1.py index a1cf8a871..8c82d6dc1 100755 --- a/testcases/features/sfc/sfc_colorado1.py +++ b/testcases/features/sfc/sfc_colorado1.py @@ -20,6 +20,7 @@ args = parser.parse_args() """ logging configuration """ logger = ft_logger.Logger("ODL_SFC").getLogger() +FUNCTEST_RESULTS_DIR = '/home/opnfv/functest/results/' FUNCTEST_REPO = ft_utils.FUNCTEST_REPO HOME = os.environ['HOME'] + "/" -- cgit 1.2.3-korg