From 8c17dd593620d962011cb4e810634182cba1d100 Mon Sep 17 00:00:00 2001 From: "jose.lausuch" Date: Fri, 3 Feb 2017 20:45:46 +0100 Subject: [deployment_handler] Remove current scripts This work has been done from scratch following a better OO approach and better structured. The library is renamed by 'deploment handler' Change-Id: I7af2963ebb4e33d90481e91cabfc015718b0bb68 Signed-off-by: jose.lausuch --- .../opnfv/installer_adapters/InstallerHandler.py | 85 -------- modules/opnfv/installer_adapters/__init__.py | 0 .../opnfv/installer_adapters/apex/ApexAdapter.py | 154 -------------- modules/opnfv/installer_adapters/apex/__init__.py | 0 modules/opnfv/installer_adapters/apex/example.py | 16 -- .../installer_adapters/compass/CompassAdapter.py | 32 --- .../opnfv/installer_adapters/compass/__init__.py | 0 .../opnfv/installer_adapters/daisy/DaisyAdapter.py | 32 --- modules/opnfv/installer_adapters/daisy/__init__.py | 0 .../opnfv/installer_adapters/fuel/FuelAdapter.py | 236 --------------------- modules/opnfv/installer_adapters/fuel/__init__.py | 0 modules/opnfv/installer_adapters/fuel/example.py | 22 -- .../opnfv/installer_adapters/joid/JoidAdapter.py | 32 --- modules/opnfv/installer_adapters/joid/__init__.py | 0 14 files changed, 609 deletions(-) delete mode 100644 modules/opnfv/installer_adapters/InstallerHandler.py delete mode 100644 modules/opnfv/installer_adapters/__init__.py delete mode 100644 modules/opnfv/installer_adapters/apex/ApexAdapter.py delete mode 100644 modules/opnfv/installer_adapters/apex/__init__.py delete mode 100644 modules/opnfv/installer_adapters/apex/example.py delete mode 100644 modules/opnfv/installer_adapters/compass/CompassAdapter.py delete mode 100644 modules/opnfv/installer_adapters/compass/__init__.py delete mode 100644 modules/opnfv/installer_adapters/daisy/DaisyAdapter.py delete mode 100644 modules/opnfv/installer_adapters/daisy/__init__.py delete mode 100644 modules/opnfv/installer_adapters/fuel/FuelAdapter.py delete mode 100644 modules/opnfv/installer_adapters/fuel/__init__.py delete mode 100644 modules/opnfv/installer_adapters/fuel/example.py delete mode 100644 modules/opnfv/installer_adapters/joid/JoidAdapter.py delete mode 100644 modules/opnfv/installer_adapters/joid/__init__.py (limited to 'modules/opnfv') diff --git a/modules/opnfv/installer_adapters/InstallerHandler.py b/modules/opnfv/installer_adapters/InstallerHandler.py deleted file mode 100644 index 6c43a46f0..000000000 --- a/modules/opnfv/installer_adapters/InstallerHandler.py +++ /dev/null @@ -1,85 +0,0 @@ -############################################################################## -# 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 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - -from opnfv.installer_adapters.fuel.FuelAdapter import FuelAdapter -from opnfv.installer_adapters.apex.ApexAdapter import ApexAdapter -from opnfv.installer_adapters.compass.CompassAdapter import CompassAdapter -from opnfv.installer_adapters.joid.JoidAdapter import JoidAdapter -from opnfv.installer_adapters.daisy.DaisyAdapter import DaisyAdapter - - -INSTALLERS = ["fuel", "apex", "compass", "joid", "daisy"] - - -class InstallerHandler: - - def __init__(self, - installer, - installer_ip, - installer_user, - 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(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]: - self.InstallerAdapter = JoidAdapter(self.installer_ip) - elif self.installer == INSTALLERS[4]: - self.InstallerAdapter = DaisyAdapter(self.installer_ip) - else: - print("Installer %s is not valid. " - "Please use one of the followings: %s" - % (self.installer, INSTALLERS)) - exit(1) - - def get_deployment_info(self): - return self.InstallerAdapter.get_deployment_info() - - def get_nodes(self, options=None): - return self.InstallerAdapter.get_nodes(options=options) - - def get_controller_ips(self, options=None): - return self.InstallerAdapter.get_controller_ips(options=options) - - def get_compute_ips(self, options=None): - return self.InstallerAdapter.get_compute_ips(options=options) - - def get_file_from_installer(self, - remote_path, - local_path, - options=None): - return self.InstallerAdapter.get_file_from_installer(remote_path, - local_path, - options=options) - - def get_file_from_controller(self, - remote_path, - local_path, - ip=None, - options=None): - return self.InstallerAdapter.get_file_from_controller(remote_path, - local_path, - ip=ip, - options=options) - - def get_all(self): - pass diff --git a/modules/opnfv/installer_adapters/__init__.py b/modules/opnfv/installer_adapters/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/modules/opnfv/installer_adapters/apex/ApexAdapter.py b/modules/opnfv/installer_adapters/apex/ApexAdapter.py deleted file mode 100644 index 29637d700..000000000 --- a/modules/opnfv/installer_adapters/apex/ApexAdapter.py +++ /dev/null @@ -1,154 +0,0 @@ -############################################################################## -# Copyright (c) 2016 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 -# which accompanies this distribution, and is available at -# 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, 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 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): - 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_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_file_from_controller(self, - remote_path, - local_path, - ip=None, - options=None): - if ip is None: - controllers = self.get_controller_ips() - ip = controllers[0] - - connection = ssh_utils.get_ssh_client(ip, - 'heat-admin', - pkey_file=self.pkey_file) - - 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/__init__.py b/modules/opnfv/installer_adapters/apex/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/modules/opnfv/installer_adapters/apex/example.py b/modules/opnfv/installer_adapters/apex/example.py deleted file mode 100644 index c8c473727..000000000 --- a/modules/opnfv/installer_adapters/apex/example.py +++ /dev/null @@ -1,16 +0,0 @@ -# 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/installer_adapters/compass/CompassAdapter.py b/modules/opnfv/installer_adapters/compass/CompassAdapter.py deleted file mode 100644 index 47cbc646d..000000000 --- a/modules/opnfv/installer_adapters/compass/CompassAdapter.py +++ /dev/null @@ -1,32 +0,0 @@ -############################################################################## -# Copyright (c) 2016 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 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - - -class CompassAdapter: - - def __init__(self, installer_ip): - self.installer_ip = installer_ip - - def get_deployment_info(self): - pass - - def get_nodes(self): - pass - - def get_controller_ips(self): - pass - - def get_compute_ips(self): - pass - - def get_file_from_installer(self, origin, target, options=None): - pass - - def get_file_from_controller(self, origin, target, ip=None, options=None): - pass diff --git a/modules/opnfv/installer_adapters/compass/__init__.py b/modules/opnfv/installer_adapters/compass/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/modules/opnfv/installer_adapters/daisy/DaisyAdapter.py b/modules/opnfv/installer_adapters/daisy/DaisyAdapter.py deleted file mode 100644 index 9b06f4c3c..000000000 --- a/modules/opnfv/installer_adapters/daisy/DaisyAdapter.py +++ /dev/null @@ -1,32 +0,0 @@ -############################################################################## -# Copyright (c) 2016 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 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - - -class DaisyAdapter: - - def __init__(self, installer_ip): - self.installer_ip = installer_ip - - def get_deployment_info(self): - pass - - def get_nodes(self): - pass - - def get_controller_ips(self): - pass - - def get_compute_ips(self): - pass - - def get_file_from_installer(self, origin, target, options=None): - pass - - def get_file_from_controller(self, origin, target, ip=None, options=None): - pass diff --git a/modules/opnfv/installer_adapters/daisy/__init__.py b/modules/opnfv/installer_adapters/daisy/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/modules/opnfv/installer_adapters/fuel/FuelAdapter.py b/modules/opnfv/installer_adapters/fuel/FuelAdapter.py deleted file mode 100644 index 8ed8f8937..000000000 --- a/modules/opnfv/installer_adapters/fuel/FuelAdapter.py +++ /dev/null @@ -1,236 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Ericsson AB and others. -# Author: Jose Lausuch (jose.lausuch@ericsson.com) -# 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 opnfv.utils.SSHUtils as ssh_utils -import opnfv.utils.OPNFVLogger as logger - - -class FuelAdapter: - - def __init__(self, installer_ip, user="root", password="r00tme"): - self.installer_ip = installer_ip - self.installer_user = user - self.installer_password = password - self.installer_connection = ssh_utils.get_ssh_client( - installer_ip, - self.installer_user, - password=self.installer_password) - self.logger = logger.Logger("FuelHandler").getLogger() - - def runcmd_fuel_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 runcmd_fuel_nodes(self): - return self.runcmd_fuel_installer('fuel nodes') - - def runcmd_fuel_env(self): - return self.runcmd_fuel_installer('fuel env') - - def get_clusters(self): - environments = [] - output = self.runcmd_fuel_env() - lines = output.rsplit('\n') - if len(lines) < 2: - self.logger.infp("No environments found in the deployment.") - return None - else: - fields = lines[0].rsplit(' | ') - - index_id = -1 - index_status = -1 - index_name = -1 - index_release_id = -1 - - for i in range(0, len(fields) - 1): - if "id" in fields[i]: - index_id = i - elif "status" in fields[i]: - index_status = i - elif "name" in fields[i]: - index_name = i - elif "release_id" in fields[i]: - index_release_id = i - - # order env info - for i in range(2, len(lines) - 1): - fields = lines[i].rsplit(' | ') - dict = {"id": fields[index_id].strip(), - "status": fields[index_status].strip(), - "name": fields[index_name].strip(), - "release_id": fields[index_release_id].strip()} - environments.append(dict) - - return environments - - def get_nodes(self, options=None): - nodes = [] - output = self.runcmd_fuel_nodes() - lines = output.rsplit('\n') - if len(lines) < 2: - self.logger.info("No nodes found in the deployment.") - return None - else: - # get fields indexes - fields = lines[0].rsplit(' | ') - - index_id = -1 - index_status = -1 - index_name = -1 - index_cluster = -1 - index_ip = -1 - index_mac = -1 - index_roles = -1 - index_online = -1 - - for i in range(0, len(fields) - 1): - if "id" in fields[i]: - index_id = i - elif "status" in fields[i]: - index_status = i - elif "name" in fields[i]: - index_name = i - elif "cluster" in fields[i]: - index_cluster = i - elif "ip" in fields[i]: - index_ip = i - elif "mac" in fields[i]: - index_mac = i - elif "roles " in fields[i]: - index_roles = i - elif "online" in fields[i]: - index_online = i - - # order nodes info - for i in range(2, len(lines) - 1): - fields = lines[i].rsplit(' | ') - dict = {"id": fields[index_id].strip(), - "status": fields[index_status].strip(), - "name": fields[index_name].strip(), - "cluster": fields[index_cluster].strip(), - "ip": fields[index_ip].strip(), - "mac": fields[index_mac].strip(), - "roles": fields[index_roles].strip(), - "online": fields[index_online].strip()} - if options and options['cluster']: - if fields[index_cluster].strip() == options['cluster']: - nodes.append(dict) - else: - nodes.append(dict) - - return nodes - - def get_controller_ips(self, options): - nodes = self.get_nodes(options=options) - 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(options=options) - computes = [] - for node in nodes: - if "compute" in node["roles"]: - computes.append(node['ip']) - return computes - - def get_deployment_info(self): - str = "Deployment details:\n" - str += "\tInstaller: Fuel\n" - str += "\tScenario: Unknown\n" - sdn = "None" - clusters = self.get_clusters() - str += "\tN.Clusters: %s\n" % len(clusters) - for cluster in clusters: - cluster_dic = {'cluster': cluster['id']} - str += "\tCluster info:\n" - str += "\t ID: %s\n" % cluster['id'] - str += "\t NAME: %s\n" % cluster['name'] - str += "\t STATUS: %s\n" % cluster['status'] - nodes = self.get_nodes(options=cluster_dic) - num_nodes = len(nodes) - for node in nodes: - if "opendaylight" in node['roles']: - sdn = "OpenDaylight" - elif "onos" in node['roles']: - sdn = "ONOS" - num_controllers = len( - self.get_controller_ips(options=cluster_dic)) - num_computes = len(self.get_compute_ips(options=cluster_dic)) - ha = False - if num_controllers > 1: - ha = True - - str += "\t HA: %s\n" % ha - str += "\t NUM.NODES: %s\n" % num_nodes - str += "\t CONTROLLERS: %s\n" % num_controllers - str += "\t COMPUTES: %s\n" % num_computes - str += "\t SDN CONTR.: %s\n\n" % sdn - str += self.runcmd_fuel_nodes() - return str - - def get_file_from_installer(self, remote_path, local_path, options=None): - self.logger.debug("Fetching %s from %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 Fuel to %s" % - (remote_path, local_path)) - - def get_file_from_controller(self, - remote_path, - local_path, - ip=None, - user='root', - options=None): - if ip is None: - controllers = self.get_controller_ips(options=options) - if len(controllers) == 0: - self.logger.info("No controllers found in the deployment.") - return 1 - else: - target_ip = controllers[0] - else: - target_ip = ip - - installer_proxy = { - 'ip': self.installer_ip, - 'username': self.installer_user, - 'password': self.installer_password - } - controller_conn = ssh_utils.get_ssh_client( - target_ip, - user, - proxy=installer_proxy) - - self.logger.debug("Fetching %s from %s" % - (remote_path, target_ip)) - - get_file_result = ssh_utils.get_file(controller_conn, - 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, target_ip, local_path)) diff --git a/modules/opnfv/installer_adapters/fuel/__init__.py b/modules/opnfv/installer_adapters/fuel/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/modules/opnfv/installer_adapters/fuel/example.py b/modules/opnfv/installer_adapters/fuel/example.py deleted file mode 100644 index 7fea4dfd7..000000000 --- a/modules/opnfv/installer_adapters/fuel/example.py +++ /dev/null @@ -1,22 +0,0 @@ -# This is an example of usage of this Tool -# Author: Jose Lausuch (jose.lausuch@ericsson.com) - -import opnfv.installer_adapters.InstallerHandler as ins_handler - -fuel_handler = ins_handler.InstallerHandler(installer='fuel', - installer_ip='10.20.0.2', - installer_user='root', - installer_pwd='r00tme') -print("Nodes in cluster 1:\n%s\n" % - fuel_handler.get_nodes(options={'cluster': '1'})) -print("Nodes in cluster 2:\n%s\n" % - fuel_handler.get_nodes(options={'cluster': '2'})) -print("Nodes:\n%s\n" % fuel_handler.get_nodes()) -print("Controller nodes:\n%s\n" % fuel_handler.get_controller_ips()) -print("Compute nodes:\n%s\n" % fuel_handler.get_compute_ips()) -print("\n%s\n" % fuel_handler.get_deployment_info()) -fuel_handler.get_file_from_installer('/root/deploy/dea.yaml', './dea.yaml') -fuel_handler.get_file_from_controller( - '/etc/neutron/neutron.conf', './neutron.conf') -fuel_handler.get_file_from_controller( - '/root/openrc', './openrc') diff --git a/modules/opnfv/installer_adapters/joid/JoidAdapter.py b/modules/opnfv/installer_adapters/joid/JoidAdapter.py deleted file mode 100644 index be8c2ebac..000000000 --- a/modules/opnfv/installer_adapters/joid/JoidAdapter.py +++ /dev/null @@ -1,32 +0,0 @@ -############################################################################## -# Copyright (c) 2016 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 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - - -class JoidAdapter: - - def __init__(self, installer_ip): - self.installer_ip = installer_ip - - def get_deployment_info(self): - pass - - def get_nodes(self): - pass - - def get_controller_ips(self): - pass - - def get_compute_ips(self): - pass - - def get_file_from_installer(self, origin, target, options=None): - pass - - def get_file_from_controller(self, origin, target, ip=None, options=None): - pass diff --git a/modules/opnfv/installer_adapters/joid/__init__.py b/modules/opnfv/installer_adapters/joid/__init__.py deleted file mode 100644 index e69de29bb..000000000 -- cgit 1.2.3-korg From ba25afb8b30e8f757ea1a6a2819d30dd1644e5d3 Mon Sep 17 00:00:00 2001 From: "jose.lausuch" Date: Mon, 6 Feb 2017 22:10:00 +0100 Subject: [deployment handler] Refactor the old installer_handler This is a util library to interact with the deployment regardless of the installer. Objects: - Deployment - Node - DeploymentHandler - ApexAdapter - FuelAdapter - Factory The installer adapters implement some of the abstract functions of DeploymentHandler class that can't be generalized. Printout of example.py: http://pastebin.com/raw/SF3A1fee More info: JIRA: RELENG-149 Change-Id: I5c9e94459d5be0bfad6ffac29908a8cfc7ba919c Signed-off-by: jose.lausuch --- modules/opnfv/deployment/__init__.py | 0 modules/opnfv/deployment/apex/__init__.py | 0 modules/opnfv/deployment/apex/adapter.py | 93 ++++++++++ modules/opnfv/deployment/example.py | 21 +++ modules/opnfv/deployment/factory.py | 44 +++++ modules/opnfv/deployment/fuel/__init__.py | 0 modules/opnfv/deployment/fuel/adapter.py | 167 +++++++++++++++++ modules/opnfv/deployment/manager.py | 299 ++++++++++++++++++++++++++++++ modules/opnfv/utils/OPNFVLogger.py | 51 ----- modules/opnfv/utils/SSHUtils.py | 132 ------------- modules/opnfv/utils/opnfv_logger.py | 51 +++++ modules/opnfv/utils/ssh_utils.py | 132 +++++++++++++ 12 files changed, 807 insertions(+), 183 deletions(-) create mode 100644 modules/opnfv/deployment/__init__.py create mode 100644 modules/opnfv/deployment/apex/__init__.py create mode 100644 modules/opnfv/deployment/apex/adapter.py create mode 100644 modules/opnfv/deployment/example.py create mode 100644 modules/opnfv/deployment/factory.py create mode 100644 modules/opnfv/deployment/fuel/__init__.py create mode 100644 modules/opnfv/deployment/fuel/adapter.py create mode 100644 modules/opnfv/deployment/manager.py delete mode 100644 modules/opnfv/utils/OPNFVLogger.py delete mode 100644 modules/opnfv/utils/SSHUtils.py create mode 100644 modules/opnfv/utils/opnfv_logger.py create mode 100644 modules/opnfv/utils/ssh_utils.py (limited to 'modules/opnfv') diff --git a/modules/opnfv/deployment/__init__.py b/modules/opnfv/deployment/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/modules/opnfv/deployment/apex/__init__.py b/modules/opnfv/deployment/apex/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/modules/opnfv/deployment/apex/adapter.py b/modules/opnfv/deployment/apex/adapter.py new file mode 100644 index 000000000..1b81e781b --- /dev/null +++ b/modules/opnfv/deployment/apex/adapter.py @@ -0,0 +1,93 @@ +############################################################################## +# 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 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +import re + +from opnfv.deployment import manager +from opnfv.utils import opnfv_logger as logger +from opnfv.utils import ssh_utils + +logger = logger.Logger(__name__).getLogger() + + +class ApexAdapter(manager.DeploymentHandler): + + def __init__(self, installer_ip, installer_user, pkey_file): + super(ApexAdapter, self).__init__(installer='apex', + installer_ip=installer_ip, + installer_user=installer_user, + installer_pwd=None, + pkey_file=pkey_file) + + def nodes(self): + nodes = [] + cmd = "source /home/stack/stackrc;nova list 2>/dev/null" + output = self.installer_node.run_cmd(cmd) + lines = output.rsplit('\n') + if len(lines) < 4: + 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('|') + id = re.sub('[!| ]', '', fields[1]) + name = re.sub('[!| ]', '', fields[2]) + status_node = re.sub('[!| ]', '', fields[3]) + ip = re.sub('[!| ctlplane=]', '', fields[6]) + + if status_node == 'ACTIVE': + status = manager.Node.STATUS_OK + ssh_client = ssh_utils.get_ssh_client(hostname=ip, + username='heat-admin', + pkey_file=self.pkey_file) + else: + status = manager.Node.STATUS_INACTIVE + ssh_client = None + + node = manager.Node(id, ip, name, status, roles, ssh_client) + nodes.append(node) + + return nodes + + def get_openstack_version(self): + cmd = 'source overcloudrc;sudo nova-manage version' + result = self.installer_node.run_cmd(cmd) + return result + + def get_sdn_version(self): + cmd_descr = ("sudo yum info opendaylight 2>/dev/null|" + "grep Description|sed 's/^.*\: //'") + cmd_ver = ("sudo yum info opendaylight 2>/dev/null|" + "grep Version|sed 's/^.*\: //'") + for node in self.nodes: + if 'controller' in node.get_attribute('roles'): + description = node.run_cmd(cmd_descr) + version = node.run_cmd(cmd_ver) + break + + if description is None: + return None + else: + return description + ':' + version + + def get_deployment_status(self): + cmd = 'source stackrc;openstack stack list|grep CREATE_COMPLETE' + result = self.installer_node.run_cmd(cmd) + if result is None or len(result) == 0: + return 'failed' + else: + return 'active' diff --git a/modules/opnfv/deployment/example.py b/modules/opnfv/deployment/example.py new file mode 100644 index 000000000..6a76eb9c3 --- /dev/null +++ b/modules/opnfv/deployment/example.py @@ -0,0 +1,21 @@ +# This is an example of usage of this Tool +# Author: Jose Lausuch (jose.lausuch@ericsson.com) + +from opnfv.deployment import factory + +handler = factory.Factory.get_handler('apex', + '192.168.122.135', + 'stack', + pkey_file='/root/.ssh/id_rsa') + + +installer_node = handler.get_installer_node() +print("Hello, I am node '%s'" % installer_node.run_cmd('hostname')) +installer_node.get_file('/home/stack/overcloudrc', './overcloudrc') + +nodes = handler.get_nodes() +for node in nodes: + print("Hello, I am node '%s' and my ip is %s." % + (node.run_cmd('hostname'), node.ip)) + +print handler.get_deployment_info() diff --git a/modules/opnfv/deployment/factory.py b/modules/opnfv/deployment/factory.py new file mode 100644 index 000000000..e48a751ad --- /dev/null +++ b/modules/opnfv/deployment/factory.py @@ -0,0 +1,44 @@ +############################################################################## +# 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 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + + +from opnfv.deployment.apex import adapter as apex_adapter +from opnfv.deployment.fuel import adapter as fuel_adapter +from opnfv.utils import opnfv_logger as logger + +logger = logger.Logger(__name__).getLogger() + + +class Factory(object): + + INSTALLERS = ["fuel", "apex", "compass", "joid", "daisy"] + + def __init__(self): + pass + + @staticmethod + def get_handler(installer, + installer_ip, + installer_user, + installer_pwd=None, + pkey_file=None): + + if installer not in Factory.INSTALLERS: + raise Exception("This is not an OPNFV installer.") + + if installer.lower() == "apex": + return apex_adapter.ApexAdapter(installer_ip=installer_ip, + installer_user=installer_user, + pkey_file=pkey_file) + elif installer.lower() == "fuel": + return fuel_adapter.FuelAdapter(installer_ip=installer_ip, + installer_user=installer_user, + installer_pwd=installer_pwd) + else: + raise Exception("Installer adapter is not implemented.") diff --git a/modules/opnfv/deployment/fuel/__init__.py b/modules/opnfv/deployment/fuel/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/modules/opnfv/deployment/fuel/adapter.py b/modules/opnfv/deployment/fuel/adapter.py new file mode 100644 index 000000000..d53966e82 --- /dev/null +++ b/modules/opnfv/deployment/fuel/adapter.py @@ -0,0 +1,167 @@ +############################################################################## +# Copyright (c) 2017 Ericsson AB and others. +# Author: Jose Lausuch (jose.lausuch@ericsson.com) +# 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 +############################################################################## + + +from opnfv.deployment import manager +from opnfv.utils import opnfv_logger as logger +from opnfv.utils import ssh_utils + +logger = logger.Logger("FuelAdapter").getLogger() + + +class FuelAdapter(manager.DeploymentHandler): + + def __init__(self, installer_ip, installer_user, installer_pwd): + super(FuelAdapter, self).__init__(installer='fuel', + installer_ip=installer_ip, + installer_user=installer_user, + installer_pwd=installer_pwd, + pkey_file=None) + + def _get_clusters(self): + environments = [] + output = self.runcmd_fuel_env() + lines = output.rsplit('\n') + if len(lines) < 2: + logger.info("No environments found in the deployment.") + return None + else: + fields = lines[0].rsplit(' | ') + + index_id = -1 + index_status = -1 + index_name = -1 + index_release_id = -1 + + for i in range(len(fields) - 1): + if "id" in fields[i]: + index_id = i + elif "status" in fields[i]: + index_status = i + elif "name" in fields[i]: + index_name = i + elif "release_id" in fields[i]: + index_release_id = i + + # order env info + for i in range(2, len(lines) - 1): + fields = lines[i].rsplit(' | ') + dict = {"id": fields[index_id].strip(), + "status": fields[index_status].strip(), + "name": fields[index_name].strip(), + "release_id": fields[index_release_id].strip()} + environments.append(dict) + + return environments + + def nodes(self, options=None): + nodes = [] + cmd = 'fuel node' + output = self.installer_node.run_cmd(cmd) + lines = output.rsplit('\n') + if len(lines) < 2: + logger.info("No nodes found in the deployment.") + return None + else: + # get fields indexes + fields = lines[0].rsplit(' | ') + + index_id = -1 + index_status = -1 + index_name = -1 + index_cluster = -1 + index_ip = -1 + index_mac = -1 + index_roles = -1 + index_online = -1 + + for i in range(0, len(fields) - 1): + if "id" in fields[i]: + index_id = i + elif "status" in fields[i]: + index_status = i + elif "name" in fields[i]: + index_name = i + elif "cluster" in fields[i]: + index_cluster = i + elif "ip" in fields[i]: + index_ip = i + elif "mac" in fields[i]: + index_mac = i + elif "roles " in fields[i]: + index_roles = i + elif "online" in fields[i]: + index_online = i + + # order nodes info + for i in range(2, len(lines) - 1): + fields = lines[i].rsplit(' | ') + + id = fields[index_id].strip(), + ip = fields[index_ip].strip() + status_node = fields[index_status].strip() + name = fields[index_name].strip() + roles = fields[index_roles].strip() + + dict = {"cluster": fields[index_cluster].strip(), + "mac": fields[index_mac].strip(), + "online": fields[index_online].strip()} + + if status_node == 'ready': + status = manager.Node.STATUS_OK + proxy = {'ip': self.installer_ip, + 'username': self.installer_user, + 'password': self.installer_pwd} + ssh_client = ssh_utils.get_ssh_client(hostname=ip, + username='root', + proxy=proxy) + else: + status = manager.Node.STATUS_INACTIVE + ssh_client = None + + node = manager.Node( + id, ip, name, status, roles, ssh_client, dict) + nodes.append(node) + + # TODO: Add support for Fuel cluster selection + ''' + if options and options['cluster']: + if fields[index_cluster].strip() == options['cluster']: + ''' + + return nodes + + def get_openstack_version(self): + cmd = 'source openrc;nova-manage version 2>/dev/null' + version = None + for node in self.nodes: + if 'controller' in node.get_attribute('roles'): + version = node.run_cmd(cmd) + break + return version + + def get_sdn_version(self): + cmd = "apt-cache show opendaylight|grep Version|sed 's/^.*\: //'" + version = None + for node in self.nodes: + if 'controller' in node.get_attribute('roles'): + odl_version = node.run_cmd(cmd) + if odl_version: + version = 'OpenDaylight ' + odl_version + break + return version + + def get_deployment_status(self): + cmd = 'fuel env|grep operational' + result = self.installer_node.run_cmd(cmd) + if result is None or len(result) == 0: + return 'failed' + else: + return 'active' diff --git a/modules/opnfv/deployment/manager.py b/modules/opnfv/deployment/manager.py new file mode 100644 index 000000000..f0e442903 --- /dev/null +++ b/modules/opnfv/deployment/manager.py @@ -0,0 +1,299 @@ +############################################################################## +# 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 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +from abc import abstractmethod +import os + + +from opnfv.utils import opnfv_logger as logger +from opnfv.utils import ssh_utils + +logger = logger.Logger(__name__).getLogger() + + +class Deployment(object): + + def __init__(self, + installer, + installer_ip, + scenario, + pod, + status, + openstack_version, + sdn_controller, + nodes=[]): + + self.deployment_info = { + 'installer': installer, + 'installer_ip': installer_ip, + 'scenario': scenario, + 'pod': pod, + 'status': status, + 'openstack_version': openstack_version, + 'sdn_controller': sdn_controller, + 'nodes': nodes + } + + def _get_openstack_release(self): + ''' + Translates an openstack version into the release name + ''' + os_versions = { + '12': 'Liberty', + '13': 'Mitaka', + '14': 'Newton', + '15': 'Ocata', + '16': 'Pike', + '17': 'Queens' + } + try: + version = self.deployment_info['openstack_version'].split('.')[0] + name = os_versions[version] + return name + except Exception as e: + return 'Unknown release' + + def get_dict(self): + ''' + Returns a dictionary will all the attributes + ''' + return self.deployment_info + + def __str__(self): + ''' + Override of the str method + ''' + s = ''' + INSTALLER: {installer} + SCENARIO: {scenario} + INSTALLER IP: {installer_ip} + POD: {pod} + STATUS: {status} + OPENSTACK: {openstack_version} ({openstack_release}) + SDN: {sdn_controller} + NODES: + '''.format(installer=self.deployment_info['installer'], + scenario=self.deployment_info['scenario'], + installer_ip=self.deployment_info['installer_ip'], + pod=self.deployment_info['pod'], + status=self.deployment_info['status'], + openstack_version=self.deployment_info[ + 'openstack_version'], + openstack_release=self._get_openstack_release(), + sdn_controller=self.deployment_info['sdn_controller']) + + for node in self.deployment_info['nodes']: + s += '\t\t{node_object}\n'.format(node_object=node) + + return s + + +class Node(object): + + STATUS_OK = 'active' + STATUS_INACTIVE = 'inactive' + STATUS_OFFLINE = 'offline' + STATUS_FAILED = 'failed' + + def __init__(self, + id, + ip, + name, + status, + roles, + ssh_client, + info={}): + self.id = id + self.ip = ip + self.name = name + self.status = status + self.ssh_client = ssh_client + self.roles = roles + self.info = info + + def get_file(self, src, dest): + ''' + SCP file from a node + ''' + if self.status is not Node.STATUS_OK: + logger.info("The node %s is not active" % self.ip) + return 1 + logger.info("Fetching %s from %s" % (src, self.ip)) + get_file_result = ssh_utils.get_file(self.ssh_client, src, dest) + if get_file_result is None: + logger.error("SFTP failed to retrieve the file.") + else: + logger.info("Successfully copied %s:%s to %s" % + (self.ip, src, dest)) + return get_file_result + + def put_file(self, src, dest): + ''' + SCP file to a node + ''' + if self.status is not Node.STATUS_OK: + logger.info("The node %s is not active" % self.ip) + return 1 + logger.info("Copying %s to %s" % (src, self.ip)) + put_file_result = ssh_utils.put_file(self.ssh_client, src, dest) + if put_file_result is None: + logger.error("SFTP failed to retrieve the file.") + else: + logger.info("Successfully copied %s to %s:%s" % + (src, dest, self.ip)) + return put_file_result + + def run_cmd(self, cmd): + ''' + Run command remotely on a node + ''' + if self.status is not Node.STATUS_OK: + logger.info("The node %s is not active" % self.ip) + return 1 + _, stdout, stderr = (self.ssh_client.exec_command(cmd)) + error = stderr.readlines() + if len(error) > 0: + logger.error("error %s" % ''.join(error)) + return error + output = ''.join(stdout.readlines()).rstrip() + return output + + def get_dict(self): + ''' + Returns a dictionary with all the attributes + ''' + return { + 'id': self.id, + 'ip': self.ip, + 'name': self.name, + 'status': self.status, + 'roles': self.roles, + 'info': self.info + } + + def get_attribute(self, attribute): + ''' + Returns an attribute given the name + ''' + return self.get_dict()[attribute] + + def is_controller(self): + ''' + Returns if the node is a controller + ''' + if 'controller' in self.get_attribute('roles'): + return True + return False + + def is_compute(self): + ''' + Returns if the node is a compute + ''' + if 'compute' in self.get_attribute('roles'): + return True + return False + + def __str__(self): + return str(self.get_dict()) + + +class DeploymentHandler(object): + + EX_OK = os.EX_OK + EX_ERROR = os.EX_SOFTWARE + FUNCTION_NOT_IMPLEMENTED = "Function not implemented by adapter!" + + def __init__(self, + installer, + installer_ip, + installer_user, + installer_pwd=None, + pkey_file=None): + + self.installer = installer.lower() + self.installer_ip = installer_ip + self.installer_user = installer_user + self.installer_pwd = installer_pwd + self.pkey_file = pkey_file + + if pkey_file is not None and not os.path.isfile(pkey_file): + raise Exception( + 'The private key file %s does not exist!' % pkey_file) + + self.installer_connection = ssh_utils.get_ssh_client( + hostname=self.installer_ip, + username=self.installer_user, + password=self.installer_pwd, + pkey_file=self.pkey_file) + + if self.installer_connection: + self.installer_node = Node(id='', + ip=installer_ip, + name=installer, + status='active', + ssh_client=self.installer_connection, + roles='installer node') + else: + raise Exception( + 'Cannot establish connection to the installer node!') + + self.nodes = self.nodes() + + @abstractmethod + def get_openstack_version(self): + ''' + Returns a string of the openstack version (nova-compute) + ''' + raise Exception(DeploymentHandler.FUNCTION_NOT_IMPLEMENTED) + + @abstractmethod + def get_sdn_version(self): + ''' + Returns a string of the sdn controller and its version, if exists + ''' + raise Exception(DeploymentHandler.FUNCTION_NOT_IMPLEMENTED) + + @abstractmethod + def get_deployment_status(self): + ''' + Returns a string of the status of the deployment + ''' + raise Exception(DeploymentHandler.FUNCTION_NOT_IMPLEMENTED) + + @abstractmethod + def nodes(self, options=None): + ''' + Generates a list of all the nodes in the deployment + ''' + raise Exception(DeploymentHandler.FUNCTION_NOT_IMPLEMENTED) + + def get_nodes(self, options=None): + ''' + Returns the list of Node objects + ''' + return self.nodes + + def get_installer_node(self): + ''' + Returns the installer node object + ''' + return self.installer_node + + def get_deployment_info(self): + ''' + Returns an object of type Deployment + ''' + return Deployment(installer=self.installer, + installer_ip=self.installer_ip, + scenario=os.getenv('DEPLOY_SCENARIO', 'Unknown'), + status=self.get_deployment_status(), + pod=os.getenv('NODE_NAME', 'Unknown'), + openstack_version=self.get_openstack_version(), + sdn_controller=self.get_sdn_version(), + nodes=self.nodes) diff --git a/modules/opnfv/utils/OPNFVLogger.py b/modules/opnfv/utils/OPNFVLogger.py deleted file mode 100644 index 6fa4ef2e2..000000000 --- a/modules/opnfv/utils/OPNFVLogger.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python -# -# 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 -# -# Logging levels: -# Level Numeric value -# CRITICAL 50 -# ERROR 40 -# WARNING 30 -# INFO 20 -# DEBUG 10 -# NOTSET 0 -# -# Usage: -# import RelengLogger as rl -# logger = fl.Logger("script_name").getLogger() -# logger.info("message to be shown with - INFO - ") -# logger.debug("message to be shown with - DEBUG -") - -import logging - - -class Logger: - - def __init__(self, logger_name, level="INFO"): - - self.logger = logging.getLogger(logger_name) - self.logger.propagate = 0 - self.logger.setLevel(logging.DEBUG) - - ch = logging.StreamHandler() - formatter = logging.Formatter('%(asctime)s - %(name)s - ' - '%(levelname)s - %(message)s') - ch.setFormatter(formatter) - if level.lower() == "debug": - ch.setLevel(logging.DEBUG) - else: - ch.setLevel(logging.INFO) - self.logger.addHandler(ch) - - hdlr = logging.FileHandler('/tmp/releng.log') - hdlr.setFormatter(formatter) - hdlr.setLevel(logging.DEBUG) - self.logger.addHandler(hdlr) - - def getLogger(self): - return self.logger diff --git a/modules/opnfv/utils/SSHUtils.py b/modules/opnfv/utils/SSHUtils.py deleted file mode 100644 index e0a830caa..000000000 --- a/modules/opnfv/utils/SSHUtils.py +++ /dev/null @@ -1,132 +0,0 @@ -############################################################################## -# 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 opnfv.utils.OPNFVLogger as OPNFVLogger -import os - -logger = OPNFVLogger.Logger('SSHUtils').getLogger() - - -def get_ssh_client(hostname, - username, - password=None, - proxy=None, - pkey_file=None): - client = None - try: - if proxy is None: - client = paramiko.SSHClient() - else: - client = ProxyHopClient() - 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()) - 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) - 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 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 - self.proxy_transport = None - self.proxy_channel = None - self.proxy_ip = None - self.proxy_ssh_key = None - self.local_ssh_key = os.path.join(os.getcwd(), 'id_rsa') - super(ProxyHopClient, self).__init__(*args, **kwargs) - - def configure_jump_host(self, jh_ip, jh_user, jh_pass, - jh_ssh_key='/root/.ssh/id_rsa'): - self.proxy_ip = jh_ip - self.proxy_ssh_key = jh_ssh_key - self.proxy_ssh = paramiko.SSHClient() - self.proxy_ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - self.proxy_ssh.connect(jh_ip, - username=jh_user, - password=jh_pass) - self.proxy_transport = self.proxy_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.proxy_ssh is None: - raise Exception('You must configure the jump ' - 'host before calling connect') - - get_file_res = get_file(self.proxy_ssh, - self.proxy_ssh_key, - self.local_ssh_key) - if get_file_res is None: - raise Exception('Could\'t fetch SSH key from jump host') - proxy_key = (paramiko.RSAKey - .from_private_key_file(self.local_ssh_key)) - - self.proxy_channel = self.proxy_transport.open_channel( - "direct-tcpip", - (hostname, 22), - (self.proxy_ip, 22)) - - self.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - super(ProxyHopClient, self).connect(hostname, - username=username, - pkey=proxy_key, - sock=self.proxy_channel) - os.remove(self.local_ssh_key) - except Exception, e: - self.logger.error(e) diff --git a/modules/opnfv/utils/opnfv_logger.py b/modules/opnfv/utils/opnfv_logger.py new file mode 100644 index 000000000..6fa4ef2e2 --- /dev/null +++ b/modules/opnfv/utils/opnfv_logger.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# +# 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 +# +# Logging levels: +# Level Numeric value +# CRITICAL 50 +# ERROR 40 +# WARNING 30 +# INFO 20 +# DEBUG 10 +# NOTSET 0 +# +# Usage: +# import RelengLogger as rl +# logger = fl.Logger("script_name").getLogger() +# logger.info("message to be shown with - INFO - ") +# logger.debug("message to be shown with - DEBUG -") + +import logging + + +class Logger: + + def __init__(self, logger_name, level="INFO"): + + self.logger = logging.getLogger(logger_name) + self.logger.propagate = 0 + self.logger.setLevel(logging.DEBUG) + + ch = logging.StreamHandler() + formatter = logging.Formatter('%(asctime)s - %(name)s - ' + '%(levelname)s - %(message)s') + ch.setFormatter(formatter) + if level.lower() == "debug": + ch.setLevel(logging.DEBUG) + else: + ch.setLevel(logging.INFO) + self.logger.addHandler(ch) + + hdlr = logging.FileHandler('/tmp/releng.log') + hdlr.setFormatter(formatter) + hdlr.setLevel(logging.DEBUG) + self.logger.addHandler(hdlr) + + def getLogger(self): + return self.logger diff --git a/modules/opnfv/utils/ssh_utils.py b/modules/opnfv/utils/ssh_utils.py new file mode 100644 index 000000000..f90045540 --- /dev/null +++ b/modules/opnfv/utils/ssh_utils.py @@ -0,0 +1,132 @@ +############################################################################## +# 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 os +import paramiko + +from opnfv.utils import opnfv_logger as logger + +logger = logger.Logger("SSH utils").getLogger() + + +def get_ssh_client(hostname, + username, + password=None, + proxy=None, + pkey_file=None): + client = None + try: + if proxy is None: + client = paramiko.SSHClient() + else: + client = ProxyHopClient() + 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()) + 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) + 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 ProxyHopClient(paramiko.SSHClient): + ''' + Connect to a remote server using a proxy hop + ''' + + def __init__(self, *args, **kwargs): + self.proxy_ssh = None + self.proxy_transport = None + self.proxy_channel = None + self.proxy_ip = None + self.proxy_ssh_key = None + self.local_ssh_key = os.path.join(os.getcwd(), 'id_rsa') + super(ProxyHopClient, self).__init__(*args, **kwargs) + + def configure_jump_host(self, jh_ip, jh_user, jh_pass, + jh_ssh_key='/root/.ssh/id_rsa'): + self.proxy_ip = jh_ip + self.proxy_ssh_key = jh_ssh_key + self.proxy_ssh = paramiko.SSHClient() + self.proxy_ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + self.proxy_ssh.connect(jh_ip, + username=jh_user, + password=jh_pass) + self.proxy_transport = self.proxy_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.proxy_ssh is None: + raise Exception('You must configure the jump ' + 'host before calling connect') + + get_file_res = get_file(self.proxy_ssh, + self.proxy_ssh_key, + self.local_ssh_key) + if get_file_res is None: + raise Exception('Could\'t fetch SSH key from jump host') + proxy_key = (paramiko.RSAKey + .from_private_key_file(self.local_ssh_key)) + + self.proxy_channel = self.proxy_transport.open_channel( + "direct-tcpip", + (hostname, 22), + (self.proxy_ip, 22)) + + self.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + super(ProxyHopClient, self).connect(hostname, + username=username, + pkey=proxy_key, + sock=self.proxy_channel) + os.remove(self.local_ssh_key) + except Exception, e: + logger.error(e) -- cgit 1.2.3-korg