koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 1 | import socket |
| 2 | import logging |
koder aka kdanilov | 7308462 | 2016-11-16 21:51:08 +0200 | [diff] [blame^] | 3 | from typing import Dict, Any, List |
koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 4 | |
| 5 | |
| 6 | from novaclient.client import Client |
| 7 | |
koder aka kdanilov | 7308462 | 2016-11-16 21:51:08 +0200 | [diff] [blame^] | 8 | from ..node_interfaces import NodeInfo |
| 9 | from ..config import ConfigBlock |
| 10 | from ..utils import parse_creds |
koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 11 | |
| 12 | |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 13 | logger = logging.getLogger("wally.discover") |
koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 14 | |
| 15 | |
koder aka kdanilov | 7308462 | 2016-11-16 21:51:08 +0200 | [diff] [blame^] | 16 | def get_floating_ip(vm: Any) -> str: |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 17 | """Get VM floating IP address""" |
| 18 | |
| 19 | for net_name, ifaces in vm.addresses.items(): |
koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 20 | for iface in ifaces: |
| 21 | if iface.get('OS-EXT-IPS:type') == "floating": |
| 22 | return iface['addr'] |
| 23 | |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 24 | raise ValueError("VM {} has no floating ip".format(vm)) |
koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 25 | |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 26 | |
| 27 | def get_ssh_url(user: str, password: str, ip: str, key: str) -> str: |
| 28 | """Get ssh connection URL from parts""" |
| 29 | |
| 30 | if password is not None: |
| 31 | assert key is None, "Both key and password provided" |
| 32 | return "ssh://{}:{}@{}".format(user, password, ip) |
| 33 | else: |
| 34 | assert key is not None, "None of key/password provided" |
| 35 | return "ssh://{}@{}::{}".format(user, ip, key) |
| 36 | |
| 37 | |
koder aka kdanilov | 7308462 | 2016-11-16 21:51:08 +0200 | [diff] [blame^] | 38 | def discover_vms(client: Client, search_opts: Dict) -> List[NodeInfo]: |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 39 | """Discover virtual machines""" |
koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 40 | user, password, key = parse_creds(search_opts.pop('auth')) |
| 41 | |
| 42 | servers = client.servers.list(search_opts=search_opts) |
| 43 | logger.debug("Found %s openstack vms" % len(servers)) |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 44 | |
koder aka kdanilov | 7308462 | 2016-11-16 21:51:08 +0200 | [diff] [blame^] | 45 | nodes = [] # type: List[NodeInfo] |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 46 | for server in servers: |
| 47 | ip = get_floating_ip(server) |
koder aka kdanilov | 7308462 | 2016-11-16 21:51:08 +0200 | [diff] [blame^] | 48 | nodes.append(NodeInfo(get_ssh_url(user, password, ip, key), roles={"test_vm"})) |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 49 | return nodes |
koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 50 | |
| 51 | |
koder aka kdanilov | 7308462 | 2016-11-16 21:51:08 +0200 | [diff] [blame^] | 52 | def discover_services(client: Client, opts: Dict[str, Any]) -> List[NodeInfo]: |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 53 | """Discover openstack services for given cluster""" |
koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 54 | user, password, key = parse_creds(opts.pop('auth')) |
| 55 | |
| 56 | services = [] |
| 57 | if opts['service'] == "all": |
| 58 | services = client.services.list() |
| 59 | else: |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 60 | if isinstance(opts['service'], str): |
koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 61 | opts['service'] = [opts['service']] |
| 62 | |
| 63 | for s in opts['service']: |
| 64 | services.extend(client.services.list(binary=s)) |
| 65 | |
koder aka kdanilov | 7308462 | 2016-11-16 21:51:08 +0200 | [diff] [blame^] | 66 | host_services_mapping = {} # type: Dict[str, [str]] |
koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 67 | |
| 68 | for service in services: |
| 69 | ip = socket.gethostbyname(service.host) |
koder aka kdanilov | 7308462 | 2016-11-16 21:51:08 +0200 | [diff] [blame^] | 70 | host_services_mapping.get(ip, []).append(service.binary) |
koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 71 | |
| 72 | logger.debug("Found %s openstack service nodes" % |
| 73 | len(host_services_mapping)) |
koder aka kdanilov | 7308462 | 2016-11-16 21:51:08 +0200 | [diff] [blame^] | 74 | |
| 75 | nodes = [] # type: List[NodeInfo] |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 76 | for host, services in host_services_mapping.items(): |
| 77 | ssh_url = get_ssh_url(user, password, host, key) |
| 78 | nodes.append(NodeInfo(ssh_url, services)) |
| 79 | |
| 80 | return nodes |
koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 81 | |
| 82 | |
koder aka kdanilov | 7308462 | 2016-11-16 21:51:08 +0200 | [diff] [blame^] | 83 | def discover_openstack_nodes(conn_details: Dict[str, str], conf: ConfigBlock) -> List[NodeInfo]: |
koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 84 | """Discover vms running in openstack |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 85 | conn_details - dict with openstack connection details - |
koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 86 | auth_url, api_key (password), username |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 87 | conf - test configuration object |
koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 88 | """ |
| 89 | client = Client(version='1.1', **conn_details) |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 90 | |
koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 91 | if conf.get('discover'): |
| 92 | services_to_discover = conf['discover'].get('nodes') |
| 93 | if services_to_discover: |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 94 | return discover_services(client, services_to_discover) |
koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 95 | |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 96 | return [] |