From 816695878485fb6cb8742e10c81f1d43b2052501 Mon Sep 17 00:00:00 2001 From: "jose.lausuch" Date: Thu, 17 Nov 2016 23:03:44 +0100 Subject: Create Apex Adapter JIRA: RELENG-152 This implementation will help collect information from the deployment. For example: - overcloudrc file - files from the undercloud - files from the overcloud nodes (i.e. logs) Change-Id: I293837695a4b82e57b9fac6027fe8197d68b1f14 Signed-off-by: jose.lausuch --- .../opnfv/installer_adapters/InstallerHandler.py | 10 +- .../opnfv/installer_adapters/apex/ApexAdapter.py | 146 +++++++++++++++++++-- modules/opnfv/installer_adapters/apex/example.py | 16 +++ modules/opnfv/utils/SSHUtils.py | 22 +++- 4 files changed, 174 insertions(+), 20 deletions(-) create mode 100644 modules/opnfv/installer_adapters/apex/example.py diff --git a/modules/opnfv/installer_adapters/InstallerHandler.py b/modules/opnfv/installer_adapters/InstallerHandler.py index dc5bdb9d6..6c43a46f0 100644 --- a/modules/opnfv/installer_adapters/InstallerHandler.py +++ b/modules/opnfv/installer_adapters/InstallerHandler.py @@ -1,5 +1,5 @@ ############################################################################## -# Copyright (c) 2015 Ericsson AB and others. +# Copyright (c) 2017 Ericsson AB and others. # Author: 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 @@ -23,18 +23,22 @@ class InstallerHandler: installer, installer_ip, installer_user, - installer_pwd=None): + installer_pwd=None, + private_key_file=None): self.installer = installer.lower() self.installer_ip = installer_ip self.installer_user = installer_user self.installer_pwd = installer_pwd + self.private_key_file = private_key_file if self.installer == INSTALLERS[0]: self.InstallerAdapter = FuelAdapter(self.installer_ip, self.installer_user, self.installer_pwd) elif self.installer == INSTALLERS[1]: - self.InstallerAdapter = ApexAdapter(self.installer_ip) + self.InstallerAdapter = ApexAdapter(installer_ip=self.installer_ip, + user=self.installer_user, + pkey_file=self.private_key_file) elif self.installer == INSTALLERS[2]: self.InstallerAdapter = CompassAdapter(self.installer_ip) elif self.installer == INSTALLERS[3]: diff --git a/modules/opnfv/installer_adapters/apex/ApexAdapter.py b/modules/opnfv/installer_adapters/apex/ApexAdapter.py index 17a27b10a..29637d700 100644 --- a/modules/opnfv/installer_adapters/apex/ApexAdapter.py +++ b/modules/opnfv/installer_adapters/apex/ApexAdapter.py @@ -7,26 +7,148 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## +import os +import re + +import opnfv.utils.SSHUtils as ssh_utils +import opnfv.utils.OPNFVLogger as logger + class ApexAdapter: - def __init__(self, installer_ip): + def __init__(self, installer_ip, pkey_file, user="stack"): self.installer_ip = installer_ip + self.installer_user = user + self.pkey_file = pkey_file + self.installer_connection = ssh_utils.get_ssh_client( + self.installer_ip, + self.installer_user, + pkey_file=self.pkey_file) + self.logger = logger.Logger("ApexHandler").getLogger() - def get_deployment_info(self): - pass + def runcmd_apex_installer(self, cmd): + _, stdout, stderr = (self.installer_connection.exec_command(cmd)) + error = stderr.readlines() + if len(error) > 0: + self.logger.error("error %s" % ''.join(error)) + return error + output = ''.join(stdout.readlines()) + return output def get_nodes(self): - pass + nodes = [] + output = self.runcmd_apex_installer( + "source /home/stack/stackrc;nova list") + lines = output.rsplit('\n') + if len(lines) < 4: + self.logger.info("No nodes found in the deployment.") + return None + + for line in lines: + if 'controller' in line: + roles = "controller" + elif 'compute' in line: + roles = "compute" + else: + continue + if 'Daylight' in line: + roles = + ", OpenDaylight" + fields = line.split('|') + dict = {"id": re.sub('[!| ]', '', fields[1]), + "roles": roles, + "name": re.sub('[!| ]', '', fields[2]), + "status": re.sub('[!| ]', '', fields[3]), + "ip": re.sub('[!| ctlplane=]', '', fields[6])} + nodes.append(dict) + + return nodes + + def get_deployment_info(self): + str = "Deployment details:\n" + str += "\tINSTALLER: Apex\n" + str += ("\tSCENARIO: %s\n" % + os.getenv('DEPLOY_SCENARIO', 'Unknown')) + sdn = "None" + + nodes = self.get_nodes() + if nodes is None: + self.logger.info("No nodes found in the deployment.") + return + num_nodes = len(nodes) + num_controllers = 0 + num_computes = 0 + for node in nodes: + if 'controller' in node['roles']: + num_controllers += 1 + if 'compute' in node['roles']: + num_computes += 1 + if 'Daylight' in node['name']: + sdn = 'OpenDaylight' + + ha = str(num_controllers >= 3) + + str += "\tHA: %s\n" % ha + str += "\tNUM.NODES: %s\n" % num_nodes + str += "\tCONTROLLERS: %s\n" % num_controllers + str += "\tCOMPUTES: %s\n" % num_computes + str += "\tSDN CONTR.: %s\n\n" % sdn + + str += "\tNODES:\n" + for node in nodes: + str += ("\t ID: %s\n" % node['id']) + str += ("\t Name: %s\n" % node['name']) + str += ("\t Roles: %s\n" % node['roles']) + str += ("\t Status: %s\n" % node['status']) + str += ("\t IP: %s\n\n" % node['ip']) + + return str + + def get_controller_ips(self, options=None): + nodes = self.get_nodes() + controllers = [] + for node in nodes: + if "controller" in node["roles"]: + controllers.append(node['ip']) + return controllers + + def get_compute_ips(self, options=None): + nodes = self.get_nodes() + computes = [] + for node in nodes: + if "compute" in node["roles"]: + computes.append(node['ip']) + return computes - def get_controller_ips(self): - pass + def get_file_from_installer(self, remote_path, local_path, options=None): + self.logger.debug("Fetching %s from Undercloud %s" % + (remote_path, self.installer_ip)) + get_file_result = ssh_utils.get_file(self.installer_connection, + remote_path, + local_path) + if get_file_result is None: + self.logger.error("SFTP failed to retrieve the file.") + return 1 + self.logger.info("%s successfully copied from Undercloud to %s" % + (remote_path, local_path)) - def get_compute_ips(self): - pass + def get_file_from_controller(self, + remote_path, + local_path, + ip=None, + options=None): + if ip is None: + controllers = self.get_controller_ips() + ip = controllers[0] - def get_file_from_installer(self, origin, target, options=None): - pass + connection = ssh_utils.get_ssh_client(ip, + 'heat-admin', + pkey_file=self.pkey_file) - def get_file_from_controller(self, origin, target, ip=None, options=None): - pass + get_file_result = ssh_utils.get_file(connection, + remote_path, + local_path) + if get_file_result is None: + self.logger.error("SFTP failed to retrieve the file.") + return 1 + self.logger.info("%s successfully copied from %s to %s" % + (remote_path, ip, local_path)) diff --git a/modules/opnfv/installer_adapters/apex/example.py b/modules/opnfv/installer_adapters/apex/example.py new file mode 100644 index 000000000..c8c473727 --- /dev/null +++ b/modules/opnfv/installer_adapters/apex/example.py @@ -0,0 +1,16 @@ +# This is an example of usage of this Tool +# Author: Jose Lausuch (jose.lausuch@ericsson.com) + +import opnfv.installer_adapters.InstallerHandler as ins_handler + +apex_handler = ins_handler.InstallerHandler(installer='apex', + installer_ip='192.168.122.135', + installer_user='stack', + private_key_file='/root/.ssh/id_rsa') +apex_handler.get_file_from_installer( + '/home/stack/overcloudrc', './overcloudrc') + +print("\n%s\n" % apex_handler.get_deployment_info()) + +apex_handler.get_file_from_controller( + '/etc/resolv.conf', './resolv.conf') diff --git a/modules/opnfv/utils/SSHUtils.py b/modules/opnfv/utils/SSHUtils.py index 16e34c3e5..e0a830caa 100644 --- a/modules/opnfv/utils/SSHUtils.py +++ b/modules/opnfv/utils/SSHUtils.py @@ -16,7 +16,11 @@ import os logger = OPNFVLogger.Logger('SSHUtils').getLogger() -def get_ssh_client(hostname, username, password=None, proxy=None): +def get_ssh_client(hostname, + username, + password=None, + proxy=None, + pkey_file=None): client = None try: if proxy is None: @@ -26,14 +30,21 @@ def get_ssh_client(hostname, username, password=None, proxy=None): client.configure_jump_host(proxy['ip'], proxy['username'], proxy['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) + if pkey_file is not None: + key = paramiko.RSAKey.from_private_key_file(pkey_file) + client.load_system_host_keys() + client.connect(hostname, + username=username, + pkey=key) + else: + client.connect(hostname, + username=username, + password=password) + return client except Exception, e: logger.error(e) @@ -66,6 +77,7 @@ class ProxyHopClient(paramiko.SSHClient): ''' Connect to a remote server using a proxy hop ''' + def __init__(self, *args, **kwargs): self.logger = OPNFVLogger.Logger("ProxyHopClient").getLogger() self.proxy_ssh = None -- cgit 1.2.3-korg