From 8c33b9ac28db24617e5fa0b32f2273fc7a1e23b2 Mon Sep 17 00:00:00 2001 From: Federico Ressi Date: Thu, 13 Feb 2020 08:05:23 +0000 Subject: [PATCH] Allow to configure undercloud via ssh_config file This reverts commit 6bebf4945919d87cbb0439578a437a43be48a5ee. Change-Id: If8c218d7fa29414d6af13d2adcf6f0e3bfda24de --- .gitignore | 1 + tobiko/openstack/keystone/_credentials.py | 4 +- tobiko/shell/ssh/_client.py | 5 ++- tobiko/shell/ssh/_config.py | 39 +++++++++-------- tobiko/shell/ssh/config.py | 6 +-- tobiko/tests/unit/tripleo/test_config.py | 13 +++--- tobiko/tripleo/config.py | 8 ++-- tobiko/tripleo/undercloud.py | 51 +++++++++++------------ 8 files changed, 66 insertions(+), 61 deletions(-) diff --git a/.gitignore b/.gitignore index 42bca0b41..6c0957ce2 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,4 @@ Pipfile.lock tobiko.conf clouds.yaml ssh_config +ssh_id* diff --git a/tobiko/openstack/keystone/_credentials.py b/tobiko/openstack/keystone/_credentials.py index 4a7032ff2..37d4582ec 100644 --- a/tobiko/openstack/keystone/_credentials.py +++ b/tobiko/openstack/keystone/_credentials.py @@ -272,8 +272,8 @@ class DefaultKeystoneCredentialsFixture(KeystoneCredentialsFixture): for fixture in self.fixtures: try: credentials = tobiko.setup_fixture(fixture).credentials - except Exception: - LOG.debug("Error getting cretentials from %r", fixture) + except Exception as ex: + LOG.debug("Error getting cretentials from %r: %s", fixture, ex) errors.append(tobiko.exc_info()) continue diff --git a/tobiko/shell/ssh/_client.py b/tobiko/shell/ssh/_client.py index acef12607..952cae3a6 100644 --- a/tobiko/shell/ssh/_client.py +++ b/tobiko/shell/ssh/_client.py @@ -75,7 +75,10 @@ def positive_int(value): def get_key_filename(value): if isinstance(value, six.string_types): value = [value] - return [os.path.realpath(os.path.expanduser(v)) for v in value] + key_filename = [tobiko.tobiko_config_path(v) for v in value] + return [f + for f in key_filename + if os.path.isfile(f)] SSH_CONNECT_PARAMETERS = { diff --git a/tobiko/shell/ssh/_config.py b/tobiko/shell/ssh/_config.py index 7613b454c..b8d9d6888 100644 --- a/tobiko/shell/ssh/_config.py +++ b/tobiko/shell/ssh/_config.py @@ -27,38 +27,43 @@ import tobiko LOG = log.getLogger(__name__) -def ssh_config(config_files=None): - if config_files: - fixture = SSHConfigFixture(config_files=config_files) +def ssh_config(config_files=None, **defaults): + if config_files or defaults: + fixture = SSHConfigFixture(config_files=config_files, **defaults) else: fixture = SSHConfigFixture return tobiko.setup_fixture(fixture) -def ssh_host_config(host=None, config_files=None): - return ssh_config(config_files=config_files).lookup(host) +def ssh_host_config(host=None, config_files=None, **defaults): + return ssh_config(config_files=config_files, **defaults).lookup(host) class SSHDefaultConfigFixture(tobiko.SharedFixture): - conf = None - - def setup_fixture(self): - self.conf = tobiko.tobiko_config().ssh + def __init__(self, **defaults): + super(SSHDefaultConfigFixture, self).__init__() + self.__dict__.update((key, value) + for key, value in defaults.items() + if value is not None) def __getattr__(self, name): - return getattr(self.conf, name) + config = tobiko.tobiko_config().ssh + value = getattr(config, name) + self.__dict__[name] = value + return value class SSHConfigFixture(tobiko.SharedFixture): - default = tobiko.required_setup_fixture(SSHDefaultConfigFixture) - + default = None config_files = None config = None - def __init__(self, config_files=None): + def __init__(self, config_files=None, **defaults): super(SSHConfigFixture, self).__init__() + self.default = tobiko.setup_fixture( + SSHDefaultConfigFixture(**defaults)) if config_files: self.config_files = tuple(config_files) else: @@ -87,7 +92,8 @@ class SSHConfigFixture(tobiko.SharedFixture): return SSHHostConfig(host=host, ssh_config=self, host_config=host_config, - config_files=self.config_files) + config_files=self.config_files, + default=self.default) def __repr__(self): return "{class_name!s}(config_files={config_files!r})".format( @@ -97,9 +103,8 @@ class SSHConfigFixture(tobiko.SharedFixture): class SSHHostConfig(collections.namedtuple('SSHHostConfig', ['host', 'ssh_config', 'host_config', - 'config_files'])): - - default = tobiko.required_setup_fixture(SSHDefaultConfigFixture) + 'config_files', + 'default'])): @property def hostname(self): diff --git a/tobiko/shell/ssh/config.py b/tobiko/shell/ssh/config.py index 1c08d13f1..4e2e9df77 100644 --- a/tobiko/shell/ssh/config.py +++ b/tobiko/shell/ssh/config.py @@ -37,9 +37,9 @@ OPTIONS = [ default=['/etc/ssh/ssh_config', '~/.ssh/config', './ssh_config'], help="Default user SSH configuration files"), - cfg.StrOpt('key_file', - default='~/.ssh/id_rsa', - help="Default SSH private key file"), + cfg.ListOpt('key_file', + default=['ssh_identity', '~/.ssh/id_rsa', '~/.ssh/id_dsa'], + help="Default SSH private key file"), cfg.BoolOpt('allow_agent', default=False, help=("Set to False to disable connecting to the " diff --git a/tobiko/tests/unit/tripleo/test_config.py b/tobiko/tests/unit/tripleo/test_config.py index a25c107e4..4582859aa 100644 --- a/tobiko/tests/unit/tripleo/test_config.py +++ b/tobiko/tests/unit/tripleo/test_config.py @@ -23,15 +23,14 @@ CONF = config.CONF TIPLEO_CONF = CONF.tobiko.tripleo -class TripleoConfigTest(unit.TobikoUnitTest): - - def test_ssh_key_filename(self): - self.assertIsInstance(TIPLEO_CONF.undercloud_ssh_key_filename, - six.string_types) - - class UndercloudConfigTest(unit.TobikoUnitTest): + def test_undercloud_ssh_key_filename(self): + value = TIPLEO_CONF.undercloud_ssh_key_filename + if value is not None: + self.assertIsInstance(value, + six.string_types) + def test_undercloud_ssh_hostname(self): value = TIPLEO_CONF.undercloud_ssh_hostname if value is not None: diff --git a/tobiko/tripleo/config.py b/tobiko/tripleo/config.py index 7a7899165..611573ddb 100644 --- a/tobiko/tripleo/config.py +++ b/tobiko/tripleo/config.py @@ -21,7 +21,7 @@ GROUP_NAME = 'tripleo' OPTIONS = [ # Undercloud options cfg.StrOpt('undercloud_ssh_hostname', - default=None, + default='undercloud-0', help="hostname or IP address to be used to connect to " "undercloud host"), cfg.IntOpt('undercloud_ssh_port', @@ -30,9 +30,9 @@ OPTIONS = [ cfg.StrOpt('undercloud_ssh_username', default='stack', help="Username with access to stackrc and overcloudrc files"), - cfg.StrOpt('undercloud_ssh_key_filename', - default='~/.ssh/id_rsa', - help="SSH key filename used to login to Undercloud node"), + cfg.ListOpt('undercloud_ssh_key_filename', + default=None, + help="SSH key filename used to login to Undercloud node"), cfg.StrOpt('undercloud_rcfile', default='~/stackrc', help="Undercloud RC filename"), diff --git a/tobiko/tripleo/undercloud.py b/tobiko/tripleo/undercloud.py index e736d3b59..b37c98be0 100644 --- a/tobiko/tripleo/undercloud.py +++ b/tobiko/tripleo/undercloud.py @@ -13,6 +13,10 @@ # under the License. from __future__ import absolute_import +import socket + +import netaddr + import tobiko from tobiko import config from tobiko.openstack import keystone @@ -28,7 +32,12 @@ def undercloud_ssh_client(): def undercloud_host_config(): - return tobiko.setup_fixture(UndecloudHostConfig) + tripleo_config = tobiko.tobiko_config().tripleo + return ssh.ssh_host_config( + host=tripleo_config.undercloud_ssh_hostname, + username=tripleo_config.undercloud_ssh_username, + port=tripleo_config.undercloud_ssh_port, + key_file=tripleo_config.undercloud_ssh_key_filename) def fetch_os_env(rcfile): @@ -51,40 +60,28 @@ class UndercloudKeystoneCredentialsFixture( return load_undercloud_rcfile() +def gethost_by_name(hostname): + try: + return netaddr.IPAddress(hostname) + except Exception: + ip_address = socket.gethostbyname(hostname) + return netaddr.IPAddress(ip_address) + + def has_undercloud(): host_config = undercloud_host_config() - return bool(host_config.hostname) + try: + gethost_by_name(host_config.hostname) + except Exception: + return False + else: + return True skip_if_missing_undercloud = tobiko.skip_unless( 'TripleO undercloud hostname not configured', has_undercloud) -class UndecloudHostConfig(tobiko.SharedFixture): - - host = 'undercloud-0' - hostname = None - port = None - username = None - key_filename = None - - def __init__(self, **kwargs): - super(UndecloudHostConfig, self).__init__() - self._connect_parameters = ssh.gather_ssh_connect_parameters(**kwargs) - - def setup_fixture(self): - self.hostname = CONF.tobiko.tripleo.undercloud_ssh_hostname - self.port = CONF.tobiko.tripleo.undercloud_ssh_port - self.username = CONF.tobiko.tripleo.undercloud_ssh_username - self.key_filename = CONF.tobiko.tripleo.undercloud_ssh_key_filename - - @property - def connect_parameters(self): - parameters = ssh.gather_ssh_connect_parameters(self) - parameters.update(self._connect_parameters) - return parameters - - def undercloud_keystone_client(): session = undercloud_keystone_session() return keystone.get_keystone_client(session=session)