blob: 4f342989963a7b1f42a3fa7d47618d20863aed4f [file] [log] [blame]
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +03001import re
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +03002import socket
3import logging
4from urlparse import urlparse
5
koder aka kdanilovf86d7af2015-05-06 04:01:54 +03006import sshtunnel
7from paramiko import AuthenticationException
8
9
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030010from wally.fuel_rest_api import (KeystoneAuth, get_cluster_id,
11 reflect_cluster, FuelInfo)
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030012from wally.utils import (parse_creds, check_input_param, StopTestError,
13 clean_resource, get_ip_for_target)
14from wally.ssh_utils import (run_over_ssh, connect, set_key_for_node,
15 read_from_remote)
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030016
17from .node import Node
18
19
20logger = logging.getLogger("wally.discover")
koder aka kdanilov168f6092015-04-19 02:33:38 +030021BASE_PF_PORT = 44006
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030022
23
koder aka kdanilove87ae652015-04-20 02:14:35 +030024def discover_fuel_nodes(fuel_data, var_dir, discover_nodes=True):
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030025 username, tenant_name, password = parse_creds(fuel_data['creds'])
26 creds = {"username": username,
27 "tenant_name": tenant_name,
28 "password": password}
29
30 conn = KeystoneAuth(fuel_data['url'], creds, headers=None)
31
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030032 msg = "openstack_env should be provided in fuel config"
33 check_input_param('openstack_env' in fuel_data, msg)
34
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030035 cluster_id = get_cluster_id(conn, fuel_data['openstack_env'])
36 cluster = reflect_cluster(conn, cluster_id)
koder aka kdanilov05e15b92016-02-07 19:32:46 +020037 version = FuelInfo(conn).get_version()
koder aka kdanilove87ae652015-04-20 02:14:35 +030038
39 if not discover_nodes:
40 logger.warning("Skip fuel cluster discovery")
koder aka kdanilov05e15b92016-02-07 19:32:46 +020041 return ([], None, cluster.get_openrc(), version)
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030042
43 fuel_nodes = list(cluster.get_nodes())
44
koder aka kdanilov416b87a2015-05-12 00:26:04 +030045 logger.info("Found FUEL {0}".format(".".join(map(str, version))))
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030046
47 network = 'fuelweb_admin' if version >= [6, 0] else 'admin'
48
49 ssh_creds = fuel_data['ssh_creds']
50
51 fuel_host = urlparse(fuel_data['url']).hostname
52 fuel_ip = socket.gethostbyname(fuel_host)
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030053
54 try:
55 ssh_conn = connect("{0}@{1}".format(ssh_creds, fuel_host))
56 except AuthenticationException:
57 raise StopTestError("Wrong fuel credentials")
58 except Exception:
59 logger.exception("While connection to FUEL")
60 raise StopTestError("Failed to connect to FUEL")
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030061
62 fuel_ext_iface = get_external_interface(ssh_conn, fuel_ip)
63
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030064 logger.debug("Downloading fuel master key")
65 fuel_key = download_master_key(ssh_conn)
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030066
67 nodes = []
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030068 ips_ports = []
69
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030070 logger.info("Forwarding ssh ports from FUEL nodes to localhost")
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030071 fuel_usr, fuel_passwd = ssh_creds.split(":", 1)
72 ips = [str(fuel_node.get_ip(network)) for fuel_node in fuel_nodes]
73 port_fw = forward_ssh_ports(fuel_host, fuel_usr, fuel_passwd, ips)
74 listen_ip = get_ip_for_target(fuel_host)
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030075
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030076 for port, fuel_node, ip in zip(port_fw, fuel_nodes, ips):
77 logger.debug(
78 "SSH port forwarding {0} => localhost:{1}".format(ip, port))
79
80 conn_url = "ssh://root@127.0.0.1:{0}".format(port)
81 set_key_for_node(('127.0.0.1', port), fuel_key)
82
koder aka kdanilov168f6092015-04-19 02:33:38 +030083 node = Node(conn_url, fuel_node['roles'])
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030084 node.monitor_ip = listen_ip
koder aka kdanilov168f6092015-04-19 02:33:38 +030085 nodes.append(node)
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030086 ips_ports.append((ip, port))
87
88 logger.debug("Found %s fuel nodes for env %r" %
89 (len(nodes), fuel_data['openstack_env']))
90
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030091 return (nodes,
92 (ssh_conn, fuel_ext_iface, ips_ports),
koder aka kdanilov05e15b92016-02-07 19:32:46 +020093 cluster.get_openrc(),
94 version)
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030095
96
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030097def download_master_key(conn):
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030098 # download master key
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030099 with conn.open_sftp() as sftp:
100 return read_from_remote(sftp, '/root/.ssh/id_rsa')
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300101
102
103def get_external_interface(conn, ip):
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300104 data = run_over_ssh(conn, "ip a", node='fuel-master', nolog=True)
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300105 curr_iface = None
106 for line in data.split("\n"):
107
108 match1 = re.match(r"\d+:\s+(?P<name>.*?):\s\<", line)
109 if match1 is not None:
110 curr_iface = match1.group('name')
111
112 match2 = re.match(r"\s+inet\s+(?P<ip>[0-9.]+)/", line)
113 if match2 is not None:
114 if match2.group('ip') == ip:
115 assert curr_iface is not None
116 return curr_iface
117 raise KeyError("Can't found interface for ip {0}".format(ip))
118
119
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300120def forward_ssh_ports(proxy_ip, proxy_user, proxy_passwd, ips):
121 for ip in ips:
122 tunnel = sshtunnel.open(
123 (proxy_ip, 22),
124 ssh_username=proxy_user,
125 ssh_password=proxy_passwd,
126 threaded=True,
127 remote_bind_address=(ip, 22))
128 tunnel.__enter__()
129 clean_resource(tunnel.__exit__, None, None, None)
130 yield tunnel.local_bind_port