diff options
author | Linda Wang <wangwulin@huawei.com> | 2017-11-15 03:38:34 +0000 |
---|---|---|
committer | Linda Wang <wangwulin@huawei.com> | 2017-11-15 04:17:02 +0000 |
commit | 94f0cfc2ac34396a29197fa4f22916aa6c9f1627 (patch) | |
tree | 312fdb547ce41d1d48d6d5e71630fd493da24618 | |
parent | 551740ee18dc83027654b9a0ef6de84901f86d84 (diff) |
Remove opnfv module from functest-core
The releng/opnfv git repo is still kept in upper-constraints
as it is required by sfc. And also delete the functions of
check_env_variables, get_deployment_handler and create_directories.
Change-Id: If498e68f0f94d6ebde1be55f5e3a17d06becaea4
Signed-off-by: Linda Wang <wangwulin@huawei.com>
-rw-r--r-- | functest/ci/installer_params.yaml | 16 | ||||
-rw-r--r-- | functest/ci/prepare_env.py | 121 | ||||
-rw-r--r-- | functest/tests/unit/ci/test_prepare_env.py | 389 | ||||
-rw-r--r-- | requirements.txt | 1 |
4 files changed, 0 insertions, 527 deletions
diff --git a/functest/ci/installer_params.yaml b/functest/ci/installer_params.yaml deleted file mode 100644 index 77e9355f8..000000000 --- a/functest/ci/installer_params.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apex: - ip: '' - user: 'stack' - pkey: '/root/.ssh/id_rsa' -compass: - ip: '192.168.200.2' - user: 'root' - password: 'root' -fuel: - ip: '10.20.0.2' - user: 'root' - password: 'r00tme' -# joid: -# ip: '' -# user: '' -# password: '' diff --git a/functest/ci/prepare_env.py b/functest/ci/prepare_env.py index c2b6874ce..2cb705cae 100644 --- a/functest/ci/prepare_env.py +++ b/functest/ci/prepare_env.py @@ -21,9 +21,6 @@ import functest.utils.functest_utils as ft_utils import functest.utils.openstack_utils as os_utils from functest.utils.constants import CONST -from opnfv.utils import constants as opnfv_constants -from opnfv.deployment import factory - actions = ['start', 'check'] """ logging configuration """ @@ -59,116 +56,6 @@ def print_separator(): logger.info("==============================================") -def check_env_variables(): - print_separator() - logger.info("Checking environment variables...") - - if CONST.__getattribute__('INSTALLER_TYPE') is None: - logger.warning("The env variable 'INSTALLER_TYPE' is not defined.") - CONST.__setattr__('INSTALLER_TYPE', 'undefined') - else: - if (CONST.__getattribute__('INSTALLER_TYPE') not in - opnfv_constants.INSTALLERS): - logger.warning("INSTALLER_TYPE=%s is not a valid OPNFV installer. " - "Available OPNFV Installers are : %s. " - "Setting INSTALLER_TYPE=undefined." - % (CONST.__getattribute__('INSTALLER_TYPE'), - opnfv_constants.INSTALLERS)) - CONST.__setattr__('INSTALLER_TYPE', 'undefined') - else: - logger.info(" INSTALLER_TYPE=%s" - % CONST.__getattribute__('INSTALLER_TYPE')) - - if CONST.__getattribute__('INSTALLER_IP') is None: - logger.warning( - "The env variable 'INSTALLER_IP' is not defined. It is recommended" - " to extract some information from the deployment") - else: - logger.info(" INSTALLER_IP=%s" % - CONST.__getattribute__('INSTALLER_IP')) - - if CONST.__getattribute__('DEPLOY_SCENARIO') is None: - logger.warning("The env variable 'DEPLOY_SCENARIO' is not defined. " - "Setting CI_SCENARIO=undefined.") - CONST.__setattr__('DEPLOY_SCENARIO', 'undefined') - else: - logger.info(" DEPLOY_SCENARIO=%s" - % CONST.__getattribute__('DEPLOY_SCENARIO')) - if CONST.__getattribute__('CI_DEBUG'): - logger.info(" CI_DEBUG=%s" % CONST.__getattribute__('CI_DEBUG')) - - if CONST.__getattribute__('NODE_NAME'): - logger.info(" NODE_NAME=%s" % CONST.__getattribute__('NODE_NAME')) - - if CONST.__getattribute__('BUILD_TAG'): - logger.info(" BUILD_TAG=%s" % CONST.__getattribute__('BUILD_TAG')) - - if CONST.__getattribute__('IS_CI_RUN'): - logger.info(" IS_CI_RUN=%s" % CONST.__getattribute__('IS_CI_RUN')) - - -def get_deployment_handler(): - global handler - global pod_arch - - installer_params_yaml = pkg_resources.resource_filename( - 'functest', 'ci/installer_params.yaml') - if (CONST.__getattribute__('INSTALLER_IP') and - CONST.__getattribute__('INSTALLER_TYPE') and - CONST.__getattribute__('INSTALLER_TYPE') in - opnfv_constants.INSTALLERS): - try: - installer_params = ft_utils.get_parameter_from_yaml( - CONST.__getattribute__('INSTALLER_TYPE'), - installer_params_yaml) - except ValueError as e: - logger.debug('Printing deployment info is not supported for %s' % - CONST.__getattribute__('INSTALLER_TYPE')) - logger.debug(e) - else: - user = installer_params.get('user', None) - password = installer_params.get('password', None) - pkey = installer_params.get('pkey', None) - try: - handler = factory.Factory.get_handler( - installer=CONST.__getattribute__('INSTALLER_TYPE'), - installer_ip=CONST.__getattribute__('INSTALLER_IP'), - installer_user=user, - installer_pwd=password, - pkey_file=pkey) - if handler: - pod_arch = handler.get_arch() - except Exception as e: - logger.debug("Cannot get deployment information. %s" % e) - - -def create_directories(): - print_separator() - logger.info("Creating needed directories...") - if not os.path.exists(CONST.__getattribute__('dir_functest_conf')): - os.makedirs(CONST.__getattribute__('dir_functest_conf')) - logger.info(" %s created." % - CONST.__getattribute__('dir_functest_conf')) - else: - logger.debug(" %s already exists." % - CONST.__getattribute__('dir_functest_conf')) - - if not os.path.exists(CONST.__getattribute__('dir_functest_data')): - os.makedirs(CONST.__getattribute__('dir_functest_data')) - logger.info(" %s created." % - CONST.__getattribute__('dir_functest_data')) - else: - logger.debug(" %s already exists." % - CONST.__getattribute__('dir_functest_data')) - if not os.path.exists(CONST.__getattribute__('dir_functest_images')): - os.makedirs(CONST.__getattribute__('dir_functest_images')) - logger.info(" %s created." % - CONST.__getattribute__('dir_functest_images')) - else: - logger.debug(" %s already exists." % - CONST.__getattribute__('dir_functest_images')) - - def source_rc_file(): print_separator() @@ -253,12 +140,6 @@ def check_environment(): logger.info("Functest environment is installed.") -def print_deployment_info(): - if handler: - logger.info('\n\nDeployment information:\n%s' % - handler.get_deployment_info()) - - def prepare_env(**kwargs): try: if not (kwargs['action'] in actions): @@ -267,8 +148,6 @@ def prepare_env(**kwargs): elif kwargs['action'] == "start": logger.info("######### Preparing Functest environment #########\n") verify_deployment() - check_env_variables() - create_directories() source_rc_file() update_config_file() create_flavor() diff --git a/functest/tests/unit/ci/test_prepare_env.py b/functest/tests/unit/ci/test_prepare_env.py deleted file mode 100644 index d53c68e67..000000000 --- a/functest/tests/unit/ci/test_prepare_env.py +++ /dev/null @@ -1,389 +0,0 @@ -#!/usr/bin/env python - -# 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 logging -import unittest - -import mock - -from functest.ci import prepare_env -from functest.tests.unit import test_utils -from functest.utils.constants import CONST -from opnfv.utils import constants as opnfv_constants - - -class PrepareEnvTesting(unittest.TestCase): - - def setUp(self): - self.prepare_envparser = prepare_env.PrepareEnvParser() - self.db_url_env = 'http://foo/testdb' - - @mock.patch('functest.ci.prepare_env.logger.info') - def test_print_separator(self, mock_logger_info): - str = "==============================================" - prepare_env.print_separator() - mock_logger_info.assert_called_once_with(str) - - @mock.patch('functest.ci.prepare_env.logger.info') - @mock.patch('functest.ci.prepare_env.logger.warning') - def test_check_env_variables_missing_inst_type(self, mock_logger_warn, - mock_logger_info): - CONST.__setattr__('INSTALLER_TYPE', None) - prepare_env.check_env_variables() - mock_logger_info.assert_any_call("Checking environment variables" - "...") - mock_logger_warn.assert_any_call("The env variable 'INSTALLER_TYPE'" - " is not defined.") - - @mock.patch('functest.ci.prepare_env.logger.info') - @mock.patch('functest.ci.prepare_env.logger.warning') - def test_check_env_variables_missing_inst_ip(self, mock_logger_warn, - mock_logger_info): - CONST.__setattr__('INSTALLER_IP', None) - prepare_env.check_env_variables() - mock_logger_info.assert_any_call("Checking environment variables" - "...") - mock_logger_warn.assert_any_call( - "The env variable 'INSTALLER_IP' is not defined. It is recommended" - " to extract some information from the deployment") - - @mock.patch('functest.ci.prepare_env.logger.info') - @mock.patch('functest.ci.prepare_env.logger.warning') - def test_check_env_variables_with_inst_ip(self, mock_logger_warn, - mock_logger_info): - CONST.__setattr__('INSTALLER_IP', mock.Mock()) - prepare_env.check_env_variables() - mock_logger_info.assert_any_call("Checking environment variables" - "...") - mock_logger_info.assert_any_call(test_utils. - SubstrMatch(" INSTALLER_IP=")) - - @mock.patch('functest.ci.prepare_env.logger.info') - @mock.patch('functest.ci.prepare_env.logger.warning') - def test_check_env_variables_missing_scenario(self, mock_logger_warn, - mock_logger_info): - CONST.__setattr__('DEPLOY_SCENARIO', None) - prepare_env.check_env_variables() - mock_logger_info.assert_any_call("Checking environment variables" - "...") - mock_logger_warn.assert_any_call("The env variable" - " 'DEPLOY_SCENARIO' is not defined" - ". Setting CI_SCENARIO=undefined.") - - @mock.patch('functest.ci.prepare_env.logger.info') - @mock.patch('functest.ci.prepare_env.logger.warning') - def test_check_env_variables_with_scenario(self, mock_logger_warn, - mock_logger_info): - CONST.__setattr__('DEPLOY_SCENARIO', 'test_scenario') - prepare_env.check_env_variables() - mock_logger_info.assert_any_call("Checking environment variables" - "...") - mock_logger_info.assert_any_call(test_utils. - SubstrMatch("DEPLOY_SCENARIO=")) - - @mock.patch('functest.ci.prepare_env.logger.info') - @mock.patch('functest.ci.prepare_env.logger.warning') - def test_check_env_variables_with_ci_debug(self, mock_logger_warn, - mock_logger_info): - CONST.__setattr__('CI_DEBUG', mock.Mock()) - prepare_env.check_env_variables() - mock_logger_info.assert_any_call("Checking environment variables" - "...") - mock_logger_info.assert_any_call(test_utils. - SubstrMatch(" CI_DEBUG=")) - - @mock.patch('functest.ci.prepare_env.logger.info') - @mock.patch('functest.ci.prepare_env.logger.warning') - def test_check_env_variables_with_node(self, mock_logger_warn, - mock_logger_info): - CONST.__setattr__('NODE_NAME', mock.Mock()) - prepare_env.check_env_variables() - mock_logger_info.assert_any_call("Checking environment variables" - "...") - mock_logger_info.assert_any_call(test_utils. - SubstrMatch(" NODE_NAME=")) - - @mock.patch('functest.ci.prepare_env.logger.info') - @mock.patch('functest.ci.prepare_env.logger.warning') - def test_check_env_variables_with_build_tag(self, mock_logger_warn, - mock_logger_info): - CONST.__setattr__('BUILD_TAG', mock.Mock()) - prepare_env.check_env_variables() - mock_logger_info.assert_any_call("Checking environment variables" - "...") - - mock_logger_info.assert_any_call(test_utils. - SubstrMatch(" BUILD_TAG=")) - - @mock.patch('functest.ci.prepare_env.logger.info') - @mock.patch('functest.ci.prepare_env.logger.warning') - def test_check_env_variables_with_is_ci_run(self, mock_logger_warn, - mock_logger_info): - CONST.__setattr__('IS_CI_RUN', mock.Mock()) - prepare_env.check_env_variables() - mock_logger_info.assert_any_call("Checking environment variables" - "...") - - mock_logger_info.assert_any_call(test_utils. - SubstrMatch(" IS_CI_RUN=")) - - def test_get_deployment_handler_missing_const_vars(self): - with mock.patch('functest.ci.prepare_env.' - 'factory.Factory.get_handler') as m: - CONST.__setattr__('INSTALLER_IP', None) - prepare_env.get_deployment_handler() - self.assertFalse(m.called) - - CONST.__setattr__('INSTALLER_TYPE', None) - prepare_env.get_deployment_handler() - self.assertFalse(m.called) - - @mock.patch('functest.ci.prepare_env.logger.debug') - def test_get_deployment_handler_missing_print_deploy_info(self, - mock_debug): - with mock.patch('functest.ci.prepare_env.' - 'factory.Factory.get_handler') as m, \ - mock.patch('functest.ci.prepare_env.' - 'ft_utils.get_parameter_from_yaml', - side_effect=ValueError): - CONST.__setattr__('INSTALLER_IP', 'test_ip') - CONST.__setattr__('INSTALLER_TYPE', 'test_inst_type') - opnfv_constants.INSTALLERS = ['test_inst_type'] - prepare_env.get_deployment_handler() - msg = ('Printing deployment info is not supported for ' - 'test_inst_type') - mock_debug.assert_any_call(msg) - self.assertFalse(m.called) - - @mock.patch('functest.ci.prepare_env.logger.debug') - def test_get_deployment_handler_exception(self, mock_debug): - with mock.patch('functest.ci.prepare_env.' - 'factory.Factory.get_handler', - side_effect=Exception), \ - mock.patch('functest.ci.prepare_env.' - 'ft_utils.get_parameter_from_yaml'): - CONST.__setattr__('INSTALLER_IP', 'test_ip') - CONST.__setattr__('INSTALLER_TYPE', 'test_inst_type') - opnfv_constants.INSTALLERS = ['test_inst_type'] - prepare_env.get_deployment_handler() - self.assertTrue(mock_debug.called) - - @mock.patch('functest.ci.prepare_env.logger.info') - @mock.patch('functest.ci.prepare_env.logger.debug') - def test_create_directories_missing_dir(self, mock_logger_debug, - mock_logger_info): - with mock.patch('functest.ci.prepare_env.os.path.exists', - return_value=False), \ - mock.patch('functest.ci.prepare_env.os.makedirs') \ - as mock_method: - prepare_env.create_directories() - mock_logger_info.assert_any_call("Creating needed directories...") - mock_method.assert_any_call( - CONST.__getattribute__('dir_functest_conf')) - mock_method.assert_any_call( - CONST.__getattribute__('dir_functest_data')) - mock_method.assert_any_call( - CONST.__getattribute__('dir_functest_images')) - mock_logger_info.assert_any_call(" %s created." % - CONST.__getattribute__( - 'dir_functest_conf')) - mock_logger_info.assert_any_call(" %s created." % - CONST.__getattribute__( - 'dir_functest_data')) - mock_logger_info.assert_any_call(" %s created." % - CONST.__getattribute__( - 'dir_functest_images')) - - @mock.patch('functest.ci.prepare_env.logger.info') - @mock.patch('functest.ci.prepare_env.logger.debug') - def test_create_directories_with_dir(self, mock_logger_debug, - mock_logger_info): - with mock.patch('functest.ci.prepare_env.os.path.exists', - return_value=True): - prepare_env.create_directories() - mock_logger_info.assert_any_call("Creating needed directories...") - mock_logger_debug.assert_any_call(" %s already exists." % - CONST.__getattribute__( - 'dir_functest_conf')) - mock_logger_debug.assert_any_call(" %s already exists." % - CONST.__getattribute__( - 'dir_functest_data')) - mock_logger_debug.assert_any_call(" %s already exists." % - CONST.__getattribute__( - 'dir_functest_images')) - - def _get_env_cred_dict(self, os_prefix=''): - return {'OS_USERNAME': os_prefix + 'username', - 'OS_PASSWORD': os_prefix + 'password', - 'OS_AUTH_URL': 'http://test_ip:test_port/v2.0', - 'OS_TENANT_NAME': os_prefix + 'tenant_name', - 'OS_USER_DOMAIN_NAME': os_prefix + 'user_domain_name', - 'OS_PROJECT_DOMAIN_NAME': os_prefix + 'project_domain_name', - 'OS_PROJECT_NAME': os_prefix + 'project_name', - 'OS_ENDPOINT_TYPE': os_prefix + 'endpoint_type', - 'OS_REGION_NAME': os_prefix + 'region_name'} - - @mock.patch('functest.ci.prepare_env.logger.error') - @mock.patch('functest.ci.prepare_env.logger.info') - @mock.patch('functest.ci.prepare_env.logger.warning') - def test_source_rc_missing_rc_file(self, mock_logger_warn, - mock_logger_info, - mock_logger_error): - with mock.patch('functest.ci.prepare_env.os.path.isfile', - return_value=True), \ - mock.patch('functest.ci.prepare_env.os.path.getsize', - return_value=0), \ - self.assertRaises(Exception): - CONST.__setattr__('openstack_creds', 'test_creds') - prepare_env.source_rc_file() - - def test_source_rc_missing_installer_ip(self): - with mock.patch('functest.ci.prepare_env.os.path.isfile', - return_value=False), \ - self.assertRaises(Exception): - CONST.__setattr__('INSTALLER_IP', None) - CONST.__setattr__('openstack_creds', 'test_creds') - prepare_env.source_rc_file() - - def test_source_rc_missing_installer_type(self): - with mock.patch('functest.ci.prepare_env.os.path.isfile', - return_value=False), \ - self.assertRaises(Exception): - CONST.__setattr__('INSTALLER_IP', 'test_ip') - CONST.__setattr__('openstack_creds', 'test_creds') - CONST.__setattr__('INSTALLER_TYPE', 'test_type') - opnfv_constants.INSTALLERS = [] - prepare_env.source_rc_file() - - @mock.patch('functest.ci.prepare_env.logger.debug') - def test_patch_file(self, mock_logger_debug): - with mock.patch("__builtin__.open", mock.mock_open()), \ - mock.patch('functest.ci.prepare_env.yaml.safe_load', - return_value={'test_scenario': {'tkey': 'tvalue'}}), \ - mock.patch('functest.ci.prepare_env.ft_utils.get_functest_yaml', - return_value={'tkey1': 'tvalue1'}), \ - mock.patch('functest.ci.prepare_env.os.remove') as m, \ - mock.patch('functest.ci.prepare_env.yaml.dump'): - CONST.__setattr__('DEPLOY_SCENARIO', 'test_scenario') - prepare_env.patch_file('test_file') - self.assertTrue(m.called) - - @mock.patch('functest.ci.prepare_env.ft_utils.get_functest_yaml', - return_value={'tkey1': 'tvalue1'}) - @mock.patch('functest.ci.prepare_env.yaml.safe_load', - return_value={'test_scenario': {'tkey': 'tvalue'}}) - @mock.patch('functest.ci.prepare_env.update_db_url') - def test_update_db_url(self, mock_db_url, mock_safe_load, - mock_get_functest_yaml): - CONST.__setattr__('DEPLOY_SCENARIO', 'default_scenario') - with mock.patch("__builtin__.open", mock.mock_open()), \ - mock.patch('functest.ci.prepare_env.yaml.dump'), \ - mock.patch.dict('functest.ci.prepare_env.os.environ', - {'TEST_DB_URL': self.db_url_env}, - clear=True): - prepare_env.update_config_file() - self.assertTrue(mock_db_url.called) - - def test_verify_deployment(self): - with mock.patch('functest.ci.check_deployment.CheckDeployment') \ - as mock_check_deployment: - prepare_env.verify_deployment() - self.assertTrue(mock_check_deployment.called) - - def test_verify_deployment_error(self): - with mock.patch('functest.ci.prepare_env.' - 'check_deployment.CheckDeployment', - return_value=('test_', None)), \ - self.assertRaises(Exception): - prepare_env.verify_deployment() - - def _get_rally_creds(self): - return {"type": "ExistingCloud", - "admin": {"username": 'test_user_name', - "password": 'test_password', - "tenant": 'test_tenant'}} - - def test_create_flavor(self): - with mock.patch('functest.ci.prepare_env.' - 'os_utils.get_or_create_flavor', - return_value=('test_', None)), \ - self.assertRaises(Exception) as context: - prepare_env.create_flavor() - msg = 'Failed to create flavor' - self.assertTrue(msg in context) - - @mock.patch('functest.ci.prepare_env.sys.exit') - @mock.patch('functest.ci.prepare_env.logger.error') - def test_check_environment_missing_file(self, mock_logger_error, - mock_sys_exit): - with mock.patch('functest.ci.prepare_env.os.path.isfile', - return_value=False), \ - self.assertRaises(Exception): - prepare_env.check_environment() - - @mock.patch('functest.ci.prepare_env.sys.exit') - @mock.patch('functest.ci.prepare_env.logger.error') - def test_check_environment_with_error(self, mock_logger_error, - mock_sys_exit): - with mock.patch('functest.ci.prepare_env.os.path.isfile', - return_value=True), \ - mock.patch("__builtin__.open", mock.mock_open(read_data='0')), \ - self.assertRaises(Exception): - prepare_env.check_environment() - - @mock.patch('functest.ci.prepare_env.logger.info') - def test_check_environment_default(self, mock_logger_info): - with mock.patch('functest.ci.prepare_env.os.path.isfile', - return_value=True): - with mock.patch("__builtin__.open", mock.mock_open(read_data='1')): - prepare_env.check_environment() - mock_logger_info.assert_any_call("Functest environment" - " is installed.") - - @mock.patch('functest.ci.prepare_env.check_environment') - @mock.patch('functest.ci.prepare_env.create_flavor') - @mock.patch('functest.ci.prepare_env.verify_deployment') - @mock.patch('functest.ci.prepare_env.update_config_file') - @mock.patch('functest.ci.prepare_env.source_rc_file') - @mock.patch('functest.ci.prepare_env.create_directories') - @mock.patch('functest.ci.prepare_env.check_env_variables') - @mock.patch('functest.ci.prepare_env.logger.info') - def test_main_start(self, mock_logger_info, mock_env_var, - mock_create_dir, mock_source_rc, mock_update_config, - mock_verify_depl, mock_create_flavor, - mock_check_env): - with mock.patch("__builtin__.open", mock.mock_open()) as m: - args = {'action': 'start'} - self.assertEqual(prepare_env.prepare_env(**args), 0) - mock_logger_info.assert_any_call("######### Preparing Functest " - "environment #########\n") - self.assertTrue(mock_env_var.called) - self.assertTrue(mock_create_dir.called) - self.assertTrue(mock_source_rc.called) - self.assertTrue(mock_update_config.called) - self.assertTrue(mock_verify_depl.called) - self.assertTrue(mock_create_flavor.called) - m.assert_called_once_with( - CONST.__getattribute__('env_active'), "w") - self.assertTrue(mock_check_env.called) - - @mock.patch('functest.ci.prepare_env.check_environment') - def test_main_check(self, mock_check_env): - args = {'action': 'check'} - self.assertEqual(prepare_env.prepare_env(**args), 0) - self.assertTrue(mock_check_env.called) - - @mock.patch('functest.ci.prepare_env.logger.error') - def test_main_no_arg(self, mock_logger_error): - args = {'action': 'not_valid'} - self.assertEqual(prepare_env.prepare_env(**args), -1) - mock_logger_error.assert_called_once_with('Argument not valid.') - - -if __name__ == "__main__": - logging.disable(logging.CRITICAL) - unittest.main(verbosity=2) diff --git a/requirements.txt b/requirements.txt index 0e3d846ae..49d244ec2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -27,7 +27,6 @@ mock>=2.0 # BSD iniparse==0.4 PrettyTable<0.8,>=0.7.1 # BSD six>=1.9.0 # MIT -opnfv snaps SQLAlchemy!=1.1.5,!=1.1.6,!=1.1.7,!=1.1.8,>=1.0.10 # MIT paramiko>=2.0 # LGPLv2.1+ |