blob: 5c2a4f0fd43087096ba7c1329a8b35e422e6485a [file] [log] [blame]
koder aka kdanilov39e449e2016-12-17 15:15:26 +02001""" Collect data about ceph nodes"""
koder aka kdanilov39e449e2016-12-17 15:15:26 +02002import logging
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +03003from typing import Dict, cast, List, Set
koder aka kdanilov39e449e2016-12-17 15:15:26 +02004
kdanylov aka koder0e0cfcb2017-03-27 22:19:09 +03005from cephlib import discover
6from cephlib.discover import OSDInfo
kdanylov aka koder026e5f22017-05-15 01:04:39 +03007from cephlib.common import to_ip
8from cephlib.node import NodeInfo, IRPCNode
9from cephlib.ssh import ConnCreds, IP, parse_ssh_uri
10from cephlib.node_impl import connect, setup_rpc
11
12from .stage import Stage, StepOrder
13from .test_run_class import TestRun
14from .utils import StopTestError
kdanylov aka koder0e0cfcb2017-03-27 22:19:09 +030015
16
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020017logger = logging.getLogger("wally")
koder aka kdanilov39e449e2016-12-17 15:15:26 +020018
19
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +030020def get_osds_info(node: IRPCNode, ceph_extra_args: str = "", thcount: int = 8) -> Dict[IP, List[OSDInfo]]:
koder aka kdanilov39e449e2016-12-17 15:15:26 +020021 """Get set of osd's ip"""
kdanylov aka koder0e0cfcb2017-03-27 22:19:09 +030022 res = {} # type: Dict[IP, List[OSDInfo]]
23 return {IP(ip): osd_info_list
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +030024 for ip, osd_info_list in discover.get_osds_nodes(node.run, ceph_extra_args, thcount=thcount).items()}
koder aka kdanilov39e449e2016-12-17 15:15:26 +020025
26
kdanylov aka koder0e0cfcb2017-03-27 22:19:09 +030027def get_mons_ips(node: IRPCNode, ceph_extra_args: str = "") -> Set[IP]:
koder aka kdanilov39e449e2016-12-17 15:15:26 +020028 """Return mon ip set"""
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +030029 return {IP(ip) for ip, _ in discover.get_mons_nodes(node.run, ceph_extra_args).values()}
koder aka kdanilov39e449e2016-12-17 15:15:26 +020030
31
32class DiscoverCephStage(Stage):
33 config_block = 'ceph'
34 priority = StepOrder.DISCOVER
35
36 def run(self, ctx: TestRun) -> None:
37 """Return list of ceph's nodes NodeInfo"""
38
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +030039 if 'ceph' not in ctx.config.discover:
40 print(ctx.config.discover)
kdanylov aka koder150b2192017-04-01 16:53:01 +030041 logger.debug("Skip ceph discovery due to config setting")
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020042 return
koder aka kdanilov39e449e2016-12-17 15:15:26 +020043
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020044 if 'all_nodes' in ctx.storage:
45 logger.debug("Skip ceph discovery, use previously discovered nodes")
46 return
koder aka kdanilov39e449e2016-12-17 15:15:26 +020047
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +030048 if 'metadata' in ctx.config.discover:
kdanylov aka koder150b2192017-04-01 16:53:01 +030049 logger.exception("Ceph metadata discovery is not implemented")
50 raise StopTestError()
51
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +030052 ignore_errors = 'ignore_errors' in ctx.config.discover
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020053 ceph = ctx.config.ceph
54 root_node_uri = cast(str, ceph.root_node)
55 cluster = ceph.get("cluster", "ceph")
kdanylov aka koder026e5f22017-05-15 01:04:39 +030056 ip_remap = ctx.config.ceph.get('ip_remap', {})
kdanylov aka koder0e0cfcb2017-03-27 22:19:09 +030057
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020058 conf = ceph.get("conf")
59 key = ceph.get("key")
koder aka kdanilov39e449e2016-12-17 15:15:26 +020060
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020061 if conf is None:
62 conf = "/etc/ceph/{}.conf".format(cluster)
koder aka kdanilov39e449e2016-12-17 15:15:26 +020063
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020064 if key is None:
65 key = "/etc/ceph/{}.client.admin.keyring".format(cluster)
koder aka kdanilov39e449e2016-12-17 15:15:26 +020066
kdanylov aka koder0e0cfcb2017-03-27 22:19:09 +030067 ceph_extra_args = ""
68
69 if conf:
70 ceph_extra_args += " -c '{}'".format(conf)
71
72 if key:
73 ceph_extra_args += " -k '{}'".format(key)
74
75 logger.debug("Start discovering ceph nodes from root %s", root_node_uri)
76 logger.debug("cluster=%s key=%s conf=%s", cluster, conf, key)
77
78 info = NodeInfo(parse_ssh_uri(root_node_uri), set())
79
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020080 ceph_params = {"cluster": cluster, "conf": conf, "key": key}
81
kdanylov aka koder0e0cfcb2017-03-27 22:19:09 +030082 with setup_rpc(connect(info), ctx.rpc_code, ctx.default_rpc_plugins,
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020083 log_level=ctx.config.rpc_log_level) as node:
84
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +030085 # ssh_key = node.get_file_content("~/.ssh/id_rsa", expanduser=True)
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020086
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020087 try:
88 ips = set()
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +030089 for ip, osds_info in get_osds_info(node, ceph_extra_args, thcount=16).items():
kdanylov aka koder026e5f22017-05-15 01:04:39 +030090 ip = ip_remap.get(ip, ip)
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020091 ips.add(ip)
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +030092 # creds = ConnCreds(to_ip(cast(str, ip)), user="root", key=ssh_key)
93 creds = ConnCreds(to_ip(cast(str, ip)), user="root")
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020094 info = ctx.merge_node(creds, {'ceph-osd'})
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +030095 info.params.setdefault('ceph-osds', []).extend(info.__dict__.copy() for info in osds_info)
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020096 assert 'ceph' not in info.params or info.params['ceph'] == ceph_params
97 info.params['ceph'] = ceph_params
98
99 logger.debug("Found %s nodes with ceph-osd role", len(ips))
100 except Exception as exc:
kdanylov aka koder150b2192017-04-01 16:53:01 +0300101 if not ignore_errors:
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200102 logger.exception("OSD discovery failed")
103 raise StopTestError()
104 else:
105 logger.warning("OSD discovery failed %s", exc)
106
107 try:
108 counter = 0
kdanylov aka koder0e0cfcb2017-03-27 22:19:09 +0300109 for counter, ip in enumerate(get_mons_ips(node, ceph_extra_args)):
kdanylov aka koder026e5f22017-05-15 01:04:39 +0300110 ip = ip_remap.get(ip, ip)
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +0300111 # creds = ConnCreds(to_ip(cast(str, ip)), user="root", key=ssh_key)
112 creds = ConnCreds(to_ip(cast(str, ip)), user="root")
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200113 info = ctx.merge_node(creds, {'ceph-mon'})
114 assert 'ceph' not in info.params or info.params['ceph'] == ceph_params
115 info.params['ceph'] = ceph_params
116 logger.debug("Found %s nodes with ceph-mon role", counter + 1)
117 except Exception as exc:
kdanylov aka koder150b2192017-04-01 16:53:01 +0300118 if not ignore_errors:
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200119 logger.exception("MON discovery failed")
120 raise StopTestError()
121 else:
122 logger.warning("MON discovery failed %s", exc)
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +0300123
124
kdanylov aka koder026e5f22017-05-15 01:04:39 +0300125def raw_dev_name(path: str) -> str:
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +0300126 if path.startswith("/dev/"):
127 path = path[5:]
128 while path and path[-1].isdigit():
129 path = path[:-1]
130 return path
131
132
kdanylov aka koderb0833332017-05-13 20:39:17 +0300133class CollectCephInfoStage(Stage):
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +0300134 config_block = 'ceph'
135 priority = StepOrder.UPDATE_NODES_INFO
136
137 def run(self, ctx: TestRun) -> None:
138 for node in ctx.nodes:
139 if 'ceph_storage_devs' not in node.info.params:
140 if 'ceph-osd' in node.info.roles:
kdanylov aka koder026e5f22017-05-15 01:04:39 +0300141 jdevs = set() # type: Set[str]
142 sdevs = set() # type: Set[str]
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +0300143 for osd_info in node.info.params['ceph-osds']:
144 for key, sset in [('journal', jdevs), ('storage', sdevs)]:
145 path = osd_info.get(key)
146 if path:
147 dpath = node.conn.fs.get_dev_for_file(path)
148 if isinstance(dpath, bytes):
149 dpath = dpath.decode('utf8')
150 sset.add(raw_dev_name(dpath))
151 node.info.params['ceph_storage_devs'] = list(sdevs)
152 node.info.params['ceph_journal_devs'] = list(jdevs)