koder aka kdanilov | 39e449e | 2016-12-17 15:15:26 +0200 | [diff] [blame] | 1 | import logging |
| 2 | from typing import Dict, List, NamedTuple, Union, cast |
| 3 | |
| 4 | from paramiko.ssh_exception import AuthenticationException |
| 5 | |
kdanylov aka koder | 026e5f2 | 2017-05-15 01:04:39 +0300 | [diff] [blame] | 6 | from cephlib.common import parse_creds, to_ip |
| 7 | from cephlib.ssh import ConnCreds |
| 8 | from cephlib.node_impl import connect, setup_rpc |
| 9 | |
koder aka kdanilov | 39e449e | 2016-12-17 15:15:26 +0200 | [diff] [blame] | 10 | from .fuel_rest_api import get_cluster_id, reflect_cluster, FuelInfo, KeystoneAuth |
kdanylov aka koder | 026e5f2 | 2017-05-15 01:04:39 +0300 | [diff] [blame] | 11 | from .utils import StopTestError |
koder aka kdanilov | 39e449e | 2016-12-17 15:15:26 +0200 | [diff] [blame] | 12 | from .stage import Stage, StepOrder |
| 13 | from .test_run_class import TestRun |
koder aka kdanilov | 39e449e | 2016-12-17 15:15:26 +0200 | [diff] [blame] | 14 | from .config import ConfigBlock |
| 15 | from .openstack_api import OSCreds |
| 16 | |
| 17 | |
koder aka kdanilov | 962ee5f | 2016-12-19 02:40:08 +0200 | [diff] [blame] | 18 | logger = logging.getLogger("wally") |
koder aka kdanilov | 39e449e | 2016-12-17 15:15:26 +0200 | [diff] [blame] | 19 | |
| 20 | |
| 21 | FuelNodeInfo = NamedTuple("FuelNodeInfo", |
| 22 | [("version", List[int]), |
| 23 | ("fuel_ext_iface", str), |
| 24 | ("openrc", Dict[str, Union[str, bool]])]) |
| 25 | |
| 26 | |
| 27 | |
| 28 | class DiscoverFuelStage(Stage): |
| 29 | """"Fuel nodes discovery, also can get openstack openrc""" |
| 30 | |
| 31 | priority = StepOrder.DISCOVER |
| 32 | config_block = 'fuel' |
| 33 | |
| 34 | @classmethod |
| 35 | def validate(cls, cfg: ConfigBlock) -> None: |
| 36 | # msg = "openstack_env should be provided in fuel config" |
| 37 | # check_input_param('openstack_env' in fuel_data, msg) |
| 38 | # fuel.openstack_env |
| 39 | pass |
| 40 | |
| 41 | def run(self, ctx: TestRun) -> None: |
kdanylov aka koder | cdfcdaf | 2017-04-29 10:03:39 +0300 | [diff] [blame] | 42 | full_discovery = 'fuel' in ctx.config.discover |
| 43 | metadata_only = (not full_discovery) and ('metadata' in ctx.config.discover) |
| 44 | ignore_errors = 'ignore_errors' in ctx.config.discover |
kdanylov aka koder | 150b219 | 2017-04-01 16:53:01 +0300 | [diff] [blame] | 45 | |
| 46 | if not (metadata_only or full_discovery): |
| 47 | logger.debug("Skip ceph discovery due to config setting") |
koder aka kdanilov | 962ee5f | 2016-12-19 02:40:08 +0200 | [diff] [blame] | 48 | return |
| 49 | |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 50 | if "fuel_os_creds" in ctx.storage and 'fuel_version' in ctx.storage: |
| 51 | logger.debug("Skip FUEL credentials discovery, use previously discovered info") |
| 52 | ctx.fuel_openstack_creds = OSCreds(*cast(List, ctx.storage.get('fuel_os_creds'))) |
| 53 | ctx.fuel_version = ctx.storage.get('fuel_version') |
| 54 | if 'all_nodes' in ctx.storage: |
| 55 | logger.debug("Skip FUEL nodes discovery, use data from DB") |
| 56 | return |
kdanylov aka koder | 150b219 | 2017-04-01 16:53:01 +0300 | [diff] [blame] | 57 | elif metadata_only: |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 58 | logger.debug("Skip FUEL nodes discovery due to discovery settings") |
| 59 | return |
koder aka kdanilov | 962ee5f | 2016-12-19 02:40:08 +0200 | [diff] [blame] | 60 | |
| 61 | fuel = ctx.config.fuel |
| 62 | fuel_node_info = ctx.merge_node(fuel.ssh_creds, {'fuel_master'}) |
| 63 | creds = dict(zip(("user", "passwd", "tenant"), parse_creds(fuel.creds))) |
| 64 | fuel_conn = KeystoneAuth(fuel.url, creds) |
| 65 | |
koder aka kdanilov | 962ee5f | 2016-12-19 02:40:08 +0200 | [diff] [blame] | 66 | cluster_id = get_cluster_id(fuel_conn, fuel.openstack_env) |
| 67 | cluster = reflect_cluster(fuel_conn, cluster_id) |
koder aka kdanilov | 962ee5f | 2016-12-19 02:40:08 +0200 | [diff] [blame] | 68 | |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 69 | if ctx.fuel_version is None: |
| 70 | ctx.fuel_version = FuelInfo(fuel_conn).get_version() |
| 71 | ctx.storage.put(ctx.fuel_version, "fuel_version") |
koder aka kdanilov | 962ee5f | 2016-12-19 02:40:08 +0200 | [diff] [blame] | 72 | |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 73 | logger.info("Found FUEL {0}".format(".".join(map(str, ctx.fuel_version)))) |
| 74 | openrc = cluster.get_openrc() |
koder aka kdanilov | 962ee5f | 2016-12-19 02:40:08 +0200 | [diff] [blame] | 75 | |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 76 | if openrc: |
| 77 | auth_url = cast(str, openrc['os_auth_url']) |
| 78 | if ctx.fuel_version >= [8, 0] and auth_url.startswith("https://"): |
| 79 | logger.warning("Fixing FUEL 8.0 AUTH url - replace https://->http://") |
| 80 | auth_url = auth_url.replace("https", "http", 1) |
koder aka kdanilov | 962ee5f | 2016-12-19 02:40:08 +0200 | [diff] [blame] | 81 | |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 82 | os_creds = OSCreds(name=cast(str, openrc['username']), |
| 83 | passwd=cast(str, openrc['password']), |
| 84 | tenant=cast(str, openrc['tenant_name']), |
| 85 | auth_url=cast(str, auth_url), |
| 86 | insecure=cast(bool, openrc['insecure'])) |
| 87 | |
| 88 | ctx.fuel_openstack_creds = os_creds |
| 89 | else: |
| 90 | ctx.fuel_openstack_creds = None |
| 91 | |
| 92 | ctx.storage.put(list(ctx.fuel_openstack_creds), "fuel_os_creds") |
koder aka kdanilov | 39e449e | 2016-12-17 15:15:26 +0200 | [diff] [blame] | 93 | |
kdanylov aka koder | 150b219 | 2017-04-01 16:53:01 +0300 | [diff] [blame] | 94 | if metadata_only: |
koder aka kdanilov | 962ee5f | 2016-12-19 02:40:08 +0200 | [diff] [blame] | 95 | logger.debug("Skip FUEL nodes discovery due to discovery settings") |
| 96 | return |
koder aka kdanilov | 39e449e | 2016-12-17 15:15:26 +0200 | [diff] [blame] | 97 | |
koder aka kdanilov | 962ee5f | 2016-12-19 02:40:08 +0200 | [diff] [blame] | 98 | try: |
| 99 | fuel_rpc = setup_rpc(connect(fuel_node_info), |
| 100 | ctx.rpc_code, |
| 101 | ctx.default_rpc_plugins, |
| 102 | log_level=ctx.config.rpc_log_level) |
| 103 | except AuthenticationException: |
| 104 | msg = "FUEL nodes discovery failed - wrong FUEL master SSH credentials" |
kdanylov aka koder | 150b219 | 2017-04-01 16:53:01 +0300 | [diff] [blame] | 105 | if ignore_errors: |
koder aka kdanilov | 962ee5f | 2016-12-19 02:40:08 +0200 | [diff] [blame] | 106 | raise StopTestError(msg) |
| 107 | logger.warning(msg) |
| 108 | return |
| 109 | except Exception as exc: |
kdanylov aka koder | 150b219 | 2017-04-01 16:53:01 +0300 | [diff] [blame] | 110 | if ignore_errors: |
koder aka kdanilov | 962ee5f | 2016-12-19 02:40:08 +0200 | [diff] [blame] | 111 | logger.exception("While connection to FUEL") |
| 112 | raise StopTestError("Failed to connect to FUEL") |
| 113 | logger.warning("Failed to connect to FUEL - %s", exc) |
| 114 | return |
koder aka kdanilov | 39e449e | 2016-12-17 15:15:26 +0200 | [diff] [blame] | 115 | |
koder aka kdanilov | 962ee5f | 2016-12-19 02:40:08 +0200 | [diff] [blame] | 116 | logger.debug("Downloading FUEL node ssh master key") |
| 117 | fuel_key = fuel_rpc.get_file_content('/root/.ssh/id_rsa') |
| 118 | network = 'fuelweb_admin' if ctx.fuel_version >= [6, 0] else 'admin' |
koder aka kdanilov | 39e449e | 2016-12-17 15:15:26 +0200 | [diff] [blame] | 119 | |
koder aka kdanilov | 962ee5f | 2016-12-19 02:40:08 +0200 | [diff] [blame] | 120 | count = 0 |
| 121 | for count, fuel_node in enumerate(list(cluster.get_nodes())): |
| 122 | ip = str(fuel_node.get_ip(network)) |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 123 | ctx.merge_node(ConnCreds(to_ip(ip), "root", key=fuel_key), set(fuel_node.get_roles())) |
koder aka kdanilov | 39e449e | 2016-12-17 15:15:26 +0200 | [diff] [blame] | 124 | |
koder aka kdanilov | 962ee5f | 2016-12-19 02:40:08 +0200 | [diff] [blame] | 125 | logger.debug("Found {} FUEL nodes for env {}".format(count, fuel.openstack_env)) |