summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/README.rst (renamed from modules/Readme.txt)7
-rw-r--r--modules/opnfv/__init__.py (renamed from modules/__init.py__)0
-rw-r--r--modules/opnfv/installer_adapters/InstallerHandler.py78
-rw-r--r--modules/opnfv/installer_adapters/__init__.py (renamed from modules/installer_adapters/__init.py__)0
-rw-r--r--modules/opnfv/installer_adapters/apex/ApexAdapter.py32
-rw-r--r--modules/opnfv/installer_adapters/apex/__init__.py (renamed from modules/utils/__init.py__)0
-rw-r--r--modules/opnfv/installer_adapters/compass/CompassAdapter.py32
-rw-r--r--modules/opnfv/installer_adapters/compass/__init__.py0
-rw-r--r--modules/opnfv/installer_adapters/fuel/FuelAdapter.py236
-rw-r--r--modules/opnfv/installer_adapters/fuel/__init__.py0
-rw-r--r--modules/opnfv/installer_adapters/fuel/example.py22
-rw-r--r--modules/opnfv/installer_adapters/joid/JoidAdapter.py32
-rw-r--r--modules/opnfv/installer_adapters/joid/__init__.py0
-rw-r--r--modules/opnfv/utils/Connection.py30
-rw-r--r--modules/opnfv/utils/Credentials.py101
-rw-r--r--modules/opnfv/utils/OPNFVExceptions.py126
-rw-r--r--modules/opnfv/utils/OPNFVLogger.py51
-rw-r--r--modules/opnfv/utils/SSHUtils.py121
-rw-r--r--modules/opnfv/utils/__init__.py0
-rw-r--r--modules/opnfv/utils/constants.py15
-rwxr-xr-xmodules/run_unit_tests.sh36
-rw-r--r--modules/setup.py25
-rw-r--r--modules/tests/__init__.py0
-rw-r--r--modules/tests/unit/__init__.py0
-rw-r--r--modules/tests/unit/utils/__init__.py0
-rw-r--r--modules/tests/unit/utils/test_OPNFVExceptions.py74
26 files changed, 1015 insertions, 3 deletions
diff --git a/modules/Readme.txt b/modules/README.rst
index 32becc21e..caec46b1d 100644
--- a/modules/Readme.txt
+++ b/modules/README.rst
@@ -3,9 +3,10 @@ This directory may be used to add new tools that might be useful for any
project in OPNFV. This tools must be python based and shall be imported
as follows:
- from releng.modules.utils import SSHUtils
- from releng.modules.utils import RelengLogger
- ...
+ from opnfv.utils import SSHUtils
+ from opnfv.utils import OPNFVLogger
+ from opnfv.utils import OPNFVException
+ from opnfv.utils import constants
For further information about how to use this modules directory, contact:
fatih.degirmenci@ericsson.com
diff --git a/modules/__init.py__ b/modules/opnfv/__init__.py
index e69de29bb..e69de29bb 100644
--- a/modules/__init.py__
+++ b/modules/opnfv/__init__.py
diff --git a/modules/opnfv/installer_adapters/InstallerHandler.py b/modules/opnfv/installer_adapters/InstallerHandler.py
new file mode 100644
index 000000000..e353ef3f4
--- /dev/null
+++ b/modules/opnfv/installer_adapters/InstallerHandler.py
@@ -0,0 +1,78 @@
+##############################################################################
+# Copyright (c) 2015 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
+
+
+INSTALLERS = ["fuel", "apex", "compass", "joid"]
+
+
+class InstallerHandler:
+
+ def __init__(self,
+ installer,
+ installer_ip,
+ installer_user,
+ installer_pwd=None):
+ self.installer = installer.lower()
+ self.installer_ip = installer_ip
+ self.installer_user = installer_user
+ self.installer_pwd = installer_pwd
+
+ 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)
+ elif self.installer == INSTALLERS[2]:
+ self.InstallerAdapter = CompassAdapter(self.installer_ip)
+ elif self.installer == INSTALLERS[3]:
+ self.InstallerAdapter = JoidAdapter(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/installer_adapters/__init.py__ b/modules/opnfv/installer_adapters/__init__.py
index e69de29bb..e69de29bb 100644
--- a/modules/installer_adapters/__init.py__
+++ b/modules/opnfv/installer_adapters/__init__.py
diff --git a/modules/opnfv/installer_adapters/apex/ApexAdapter.py b/modules/opnfv/installer_adapters/apex/ApexAdapter.py
new file mode 100644
index 000000000..17a27b10a
--- /dev/null
+++ b/modules/opnfv/installer_adapters/apex/ApexAdapter.py
@@ -0,0 +1,32 @@
+##############################################################################
+# 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 ApexAdapter:
+
+ 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/utils/__init.py__ b/modules/opnfv/installer_adapters/apex/__init__.py
index e69de29bb..e69de29bb 100644
--- a/modules/utils/__init.py__
+++ b/modules/opnfv/installer_adapters/apex/__init__.py
diff --git a/modules/opnfv/installer_adapters/compass/CompassAdapter.py b/modules/opnfv/installer_adapters/compass/CompassAdapter.py
new file mode 100644
index 000000000..47cbc646d
--- /dev/null
+++ b/modules/opnfv/installer_adapters/compass/CompassAdapter.py
@@ -0,0 +1,32 @@
+##############################################################################
+# 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
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/modules/opnfv/installer_adapters/compass/__init__.py
diff --git a/modules/opnfv/installer_adapters/fuel/FuelAdapter.py b/modules/opnfv/installer_adapters/fuel/FuelAdapter.py
new file mode 100644
index 000000000..6f079404c
--- /dev/null
+++ b/modules/opnfv/installer_adapters/fuel/FuelAdapter.py
@@ -0,0 +1,236 @@
+##############################################################################
+# 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_jumphost = {
+ 'ip': self.installer_ip,
+ 'username': self.installer_user,
+ 'password': self.installer_password
+ }
+ controller_conn = ssh_utils.get_ssh_client(
+ target_ip,
+ user,
+ jumphost=installer_jumphost)
+
+ 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
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/modules/opnfv/installer_adapters/fuel/__init__.py
diff --git a/modules/opnfv/installer_adapters/fuel/example.py b/modules/opnfv/installer_adapters/fuel/example.py
new file mode 100644
index 000000000..7fea4dfd7
--- /dev/null
+++ b/modules/opnfv/installer_adapters/fuel/example.py
@@ -0,0 +1,22 @@
+# 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
new file mode 100644
index 000000000..be8c2ebac
--- /dev/null
+++ b/modules/opnfv/installer_adapters/joid/JoidAdapter.py
@@ -0,0 +1,32 @@
+##############################################################################
+# 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
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/modules/opnfv/installer_adapters/joid/__init__.py
diff --git a/modules/opnfv/utils/Connection.py b/modules/opnfv/utils/Connection.py
new file mode 100644
index 000000000..a3be51409
--- /dev/null
+++ b/modules/opnfv/utils/Connection.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2016 Orange and others.
+#
+# 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 time
+
+
+class Connection(object):
+
+ def __init__(self):
+ pass
+
+ def verify_connectivity(self, target):
+ for x in range(0, 10):
+ ping_cmd = ("ping -c 1 -W 1 %s >/dev/null" % target)
+ response = os.system(ping_cmd)
+ if response == 0:
+ return os.EX_OK
+ time.sleep(1)
+ return os.EX_UNAVAILABLE
+
+ def check_internet_access(self, url="www.google.com"):
+ return self.verify_connectivity(url)
diff --git a/modules/opnfv/utils/Credentials.py b/modules/opnfv/utils/Credentials.py
new file mode 100644
index 000000000..1882692b3
--- /dev/null
+++ b/modules/opnfv/utils/Credentials.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2016 Orange and others.
+#
+# 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
+#
+# Usage example:
+# from opnfv.utils.Credentials import Credentials as credentials
+# credentials("fuel", "10.20.0.2", "root", "r00tme").fetch('./openrc')
+#
+
+import os
+
+import opnfv.installer_adapters.InstallerHandler as ins_handler
+import opnfv.utils.Connection as con
+import opnfv.utils.OPNFVLogger as logger
+
+
+class Credentials(object):
+
+ def __init__(self, installer, ip, user, password=None):
+ self.installer = installer
+ self.ip = ip
+ self.logger = logger.Logger("Credentials", level="DEBUG").getLogger()
+ self.connection = con.Connection()
+
+ if self.__check_installer_name(self.installer) != os.EX_OK:
+ self.logger.error("Installer %s not supported!" % self.installer)
+ return os.EX_CONFIG
+ else:
+ self.logger.debug("Installer %s supported." % self.installer)
+
+ if self.connection.verify_connectivity(self.ip) != os.EX_OK:
+ self.logger.error("Installer %s not reachable!" % self.ip)
+ return os.EX_UNAVAILABLE
+ else:
+ self.logger.debug("IP %s is reachable!" % self.ip)
+
+ self.logger.debug(
+ "Trying to stablish ssh connection to %s ..." % self.ip)
+ self.handler = ins_handler.InstallerHandler(installer,
+ ip,
+ user,
+ password)
+
+ def __check_installer_name(self, installer):
+ if installer not in ("apex", "compass", "fuel", "joid"):
+ return os.EX_CONFIG
+ else:
+ return os.EX_OK
+
+ def __check_path(self, path):
+ try:
+ with open(path, 'a'):
+ os.utime(path, None)
+ return os.EX_OK
+ except IOError as e:
+ self.logger.error(e)
+ return os.EX_IOERR
+
+ def __fetch_creds_apex(self, target_path):
+ # TODO
+ pass
+
+ def __fetch_creds_compass(self, target_path):
+ # TODO
+ pass
+
+ def __fetch_creds_fuel(self, target_path):
+ creds_file = '/root/openrc'
+ try:
+ self.handler.get_file_from_controller(creds_file, target_path)
+ except Exception, e:
+ self.logger.error(
+ "Cannot get %s from controller. %e" % (creds_file, e))
+ pass
+
+ def __fetch_creds_joid(self, target_path):
+ # TODO
+ pass
+
+ def fetch(self, target_path):
+ if self.__check_path(target_path) != os.EX_OK:
+ self.logger.error(
+ "Target path %s does not exist!" % target_path)
+ return os.EX_IOERR
+ else:
+ self.logger.debug("Target path correct.")
+
+ self.logger.info("Fetching credentials from the deployment...")
+ if self.installer == "apex":
+ self.__fetch_creds_apex(target_path)
+ elif self.installer == "compass":
+ self.__fetch_creds_compass(target_path)
+ elif self.installer == "fuel":
+ self.__fetch_creds_fuel(target_path)
+ elif self.installer == "joid":
+ self.__fetch_creds_joid(target_path)
diff --git a/modules/opnfv/utils/OPNFVExceptions.py b/modules/opnfv/utils/OPNFVExceptions.py
new file mode 100644
index 000000000..03b3ea981
--- /dev/null
+++ b/modules/opnfv/utils/OPNFVExceptions.py
@@ -0,0 +1,126 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2016 Orange and others.
+#
+# 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
+#
+# This class defines Python OPNFV exceptions
+#
+
+
+class OPNFVException(Exception):
+ def __call__(self, *args):
+ return self.__class__(*(self.args + args))
+
+
+# ************************************
+# Generic
+# ************************************
+class OPNFVSUTNotReachable(OPNFVException):
+ """Target System Under Test is not reachable"""
+ pass
+
+
+class OPNFVCiExecutionError(OPNFVException):
+ """Error occurs during CI exection"""
+ pass
+
+
+class TestDashboardError(OPNFVException):
+ """Impossible to report results to dashboard"""
+ pass
+
+
+class TestReportingError(OPNFVException):
+ """Impossible to report results to reporting"""
+ pass
+
+
+# ************************************
+# Exceptions related to test DB
+# ************************************
+class TestDbNotReachable(OPNFVException):
+ """Test database is not reachable"""
+ pass
+
+
+class UnknownScenario(OPNFVException):
+ """Test scenario is unknown"""
+ pass
+
+
+class UnknownPod(OPNFVException):
+ """Test POD is unknown"""
+ pass
+
+
+class UnknownProject(OPNFVException):
+ """Project is unknown"""
+ pass
+
+
+class UnknownTestCase(OPNFVException):
+ """Test case is unknown"""
+ pass
+
+
+class UnknownVersion(OPNFVException):
+ """Version is unknown"""
+ pass
+
+
+class UnknownInstaller(OPNFVException):
+ """Installer is not supported"""
+ pass
+
+
+# *******************
+# Test project errors
+# *******************
+class FunctestExecutionError(OPNFVException):
+ """Internal Functest error"""
+ pass
+
+
+class YardstickExecutionError(OPNFVException):
+ """Internal Yardstick error"""
+ pass
+
+
+# **********************************
+# Errors related to Feature projects
+# **********************************
+class TestCaseNotRunnable(OPNFVException):
+ """test case incompatible with SUT, scenario, installer"""
+ pass
+
+
+class FeatureTestIntegrationError(OPNFVException):
+ """Impossible to integrate Feature test"""
+ pass
+
+
+class FeatureTestExecutionError(OPNFVException):
+ """Error during Feature test execution"""
+ pass
+
+
+# *********************************
+# Errors related to VNF on boarding
+# *********************************
+class VNFTestNotRunnable(OPNFVException):
+ """VNF test is not compatible with SUT, scenario, installer"""
+ pass
+
+
+class VNFIntegrationError(OPNFVException):
+ """Impossible to integrate the VNF test"""
+ pass
+
+
+class VNFExecutionError(OPNFVException):
+ """Error during VNF test execution"""
+ pass
diff --git a/modules/opnfv/utils/OPNFVLogger.py b/modules/opnfv/utils/OPNFVLogger.py
new file mode 100644
index 000000000..6fa4ef2e2
--- /dev/null
+++ b/modules/opnfv/utils/OPNFVLogger.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/SSHUtils.py b/modules/opnfv/utils/SSHUtils.py
new file mode 100644
index 000000000..6c794c274
--- /dev/null
+++ b/modules/opnfv/utils/SSHUtils.py
@@ -0,0 +1,121 @@
+##############################################################################
+# 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, 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 = OPNFVLogger.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/modules/opnfv/utils/__init__.py b/modules/opnfv/utils/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/modules/opnfv/utils/__init__.py
diff --git a/modules/opnfv/utils/constants.py b/modules/opnfv/utils/constants.py
new file mode 100644
index 000000000..29f0d02c5
--- /dev/null
+++ b/modules/opnfv/utils/constants.py
@@ -0,0 +1,15 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2016 Orange and others.
+#
+# 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
+
+INSTALLERS = ['apex', 'fuel', 'compass', 'joid']
+VERSIONS = ['arno', 'brahmaputra', 'colorado', 'danube']
+
+EXIT_OK = 0
+EXIT_RUN_ERROR = -1
+EXIT_PUSH_TO_TEST_DB_ERROR = -2
diff --git a/modules/run_unit_tests.sh b/modules/run_unit_tests.sh
new file mode 100755
index 000000000..df511ce0c
--- /dev/null
+++ b/modules/run_unit_tests.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+set -o errexit
+set -o pipefail
+
+# Either Workspace is set (CI)
+if [ -z $WORKSPACE ]
+then
+ WORKSPACE="."
+fi
+
+
+# ***************
+# Run unit tests
+# ***************
+echo "Running unit tests..."
+
+# start vitual env
+virtualenv $WORKSPACE/modules_venv
+source $WORKSPACE/modules_venv/bin/activate
+
+# install python packages
+easy_install -U setuptools
+easy_install -U pip
+pip install $WORKSPACE
+
+
+# unit tests
+nosetests --with-xunit \
+ --cover-package=opnfv \
+ --with-coverage \
+ --cover-xml \
+ --cover-html \
+ tests/unit
+rc=$?
+
+deactivate
diff --git a/modules/setup.py b/modules/setup.py
new file mode 100644
index 000000000..8ac5ceac3
--- /dev/null
+++ b/modules/setup.py
@@ -0,0 +1,25 @@
+##############################################################################
+# 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 setuptools import setup, find_packages
+
+
+setup(
+ name="opnfv",
+ version="danube",
+ packages=find_packages(),
+ include_package_data=True,
+ package_data={
+ },
+ url="https://www.opnfv.org",
+ install_requires=["paramiko>=2.0.1",
+ "mock==1.3.0",
+ "nose==1.3.7",
+ "coverage==4.1",
+ "requests==2.9.1"]
+)
diff --git a/modules/tests/__init__.py b/modules/tests/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/modules/tests/__init__.py
diff --git a/modules/tests/unit/__init__.py b/modules/tests/unit/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/modules/tests/unit/__init__.py
diff --git a/modules/tests/unit/utils/__init__.py b/modules/tests/unit/utils/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/modules/tests/unit/utils/__init__.py
diff --git a/modules/tests/unit/utils/test_OPNFVExceptions.py b/modules/tests/unit/utils/test_OPNFVExceptions.py
new file mode 100644
index 000000000..fca927b58
--- /dev/null
+++ b/modules/tests/unit/utils/test_OPNFVExceptions.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2016 Orange and others.
+#
+# 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.0import requests
+import unittest
+import requests
+
+from opnfv.utils import OPNFVExceptions
+
+
+def base_function():
+ raise OPNFVExceptions.TestDbNotReachable('Test database is not reachable')
+
+
+def base_function_wrong():
+ raise OPNFVExceptions.NotSelfDefinedException
+
+
+def db_connectivity():
+ url = 'http://testresults.opnfv2.org/test/api/v1/projects/functest/cases'
+ r = requests.get(url)
+ if r.status_code is not 200:
+ raise OPNFVExceptions.TestDbNotReachable('Database not found')
+
+
+def project_unknown():
+ url = 'http://testresults.opnfv.org/test/api/v1/projects/functest2/cases'
+ r = requests.get(url)
+ if len(r.json()['testcases']) is 0:
+ raise OPNFVExceptions.UnknownProject
+
+
+class TestBasicRaise(unittest.TestCase):
+ def test(self):
+ with self.assertRaises(Exception) as context:
+ base_function()
+ self.assertTrue('Test database is not reachable' in context.exception)
+
+
+class TestWrongRaise(unittest.TestCase):
+ def test(self):
+ try:
+ base_function_wrong()
+ except OPNFVExceptions.OPNFVException:
+ assert(False)
+ except AttributeError:
+ assert(True)
+
+
+class TestCaseDBNotReachable(unittest.TestCase):
+ def test(self):
+ with self.assertRaises(Exception) as context:
+ db_connectivity()
+ self.assertTrue('Database not found' in context.exception)
+
+
+class TestUnkownProject(unittest.TestCase):
+ def test(self):
+ try:
+ project_unknown()
+ except OPNFVExceptions.TestDashboardError:
+ # should not be there
+ assert(False)
+ except OPNFVExceptions.UnknownProject:
+ assert(True)
+ except Exception:
+ assert(False)
+
+if __name__ == '__main__':
+ unittest.main()