Ved-vampir | a915a01 | 2015-03-18 14:38:52 +0300 | [diff] [blame] | 1 | """ Collect data about ceph nodes""" |
| 2 | import json |
koder aka kdanilov | 3a6633e | 2015-03-26 18:20:00 +0200 | [diff] [blame] | 3 | import logging |
koder aka kdanilov | 7308462 | 2016-11-16 21:51:08 +0200 | [diff] [blame^] | 4 | from typing import List, Set, Dict |
koder aka kdanilov | 3a6633e | 2015-03-26 18:20:00 +0200 | [diff] [blame] | 5 | |
Ved-vampir | a915a01 | 2015-03-18 14:38:52 +0300 | [diff] [blame] | 6 | |
koder aka kdanilov | 7308462 | 2016-11-16 21:51:08 +0200 | [diff] [blame^] | 7 | from ..node_interfaces import NodeInfo, IRPCNode |
| 8 | from ..ssh_utils import ConnCreds |
| 9 | from ..common_types import IP |
Ved-vampir | a915a01 | 2015-03-18 14:38:52 +0300 | [diff] [blame] | 10 | |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 11 | logger = logging.getLogger("wally.discover") |
koder aka kdanilov | 3a6633e | 2015-03-26 18:20:00 +0200 | [diff] [blame] | 12 | |
| 13 | |
koder aka kdanilov | 7308462 | 2016-11-16 21:51:08 +0200 | [diff] [blame^] | 14 | def discover_ceph_nodes(node: IRPCNode, |
| 15 | cluster: str = "ceph", |
| 16 | conf: str = None, |
| 17 | key: str = None) -> List[NodeInfo]: |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 18 | """Return list of ceph's nodes NodeInfo""" |
koder aka kdanilov | e06762a | 2015-03-22 23:32:09 +0200 | [diff] [blame] | 19 | |
koder aka kdanilov | 7308462 | 2016-11-16 21:51:08 +0200 | [diff] [blame^] | 20 | if conf is None: |
| 21 | conf = "/etc/ceph/{}.conf".format(cluster) |
koder aka kdanilov | e06762a | 2015-03-22 23:32:09 +0200 | [diff] [blame] | 22 | |
koder aka kdanilov | 7308462 | 2016-11-16 21:51:08 +0200 | [diff] [blame^] | 23 | if key is None: |
| 24 | key = "/etc/ceph/{}.client.admin.keyring".format(cluster) |
| 25 | |
| 26 | try: |
| 27 | osd_ips = get_osds_ips(node, conf, key) |
| 28 | except Exception as exc: |
| 29 | logger.error("OSD discovery failed: %s", exc) |
| 30 | osd_ips = set() |
| 31 | |
| 32 | try: |
| 33 | mon_ips = get_mons_ips(node, conf, key) |
| 34 | except Exception as exc: |
| 35 | logger.error("MON discovery failed: %s", exc) |
| 36 | mon_ips = set() |
| 37 | |
| 38 | ips = {} # type: Dict[str, List[str]] |
Ved-vampir | a915a01 | 2015-03-18 14:38:52 +0300 | [diff] [blame] | 39 | for ip in osd_ips: |
koder aka kdanilov | 7308462 | 2016-11-16 21:51:08 +0200 | [diff] [blame^] | 40 | ips.setdefault(ip, []).append("ceph-osd") |
koder aka kdanilov | e06762a | 2015-03-22 23:32:09 +0200 | [diff] [blame] | 41 | |
Ved-vampir | a915a01 | 2015-03-18 14:38:52 +0300 | [diff] [blame] | 42 | for ip in mon_ips: |
koder aka kdanilov | 7308462 | 2016-11-16 21:51:08 +0200 | [diff] [blame^] | 43 | ips.setdefault(ip, []).append("ceph-mon") |
koder aka kdanilov | e06762a | 2015-03-22 23:32:09 +0200 | [diff] [blame] | 44 | |
koder aka kdanilov | 7308462 | 2016-11-16 21:51:08 +0200 | [diff] [blame^] | 45 | ssh_key = node.get_file_content("~/.ssh/id_rsa") |
| 46 | return [NodeInfo(ConnCreds(host=ip, user="root", key=ssh_key), set(roles)) for ip, roles in ips.items()] |
Ved-vampir | a915a01 | 2015-03-18 14:38:52 +0300 | [diff] [blame] | 47 | |
| 48 | |
koder aka kdanilov | 7308462 | 2016-11-16 21:51:08 +0200 | [diff] [blame^] | 49 | def get_osds_ips(node: IRPCNode, conf: str, key: str) -> Set[IP]: |
| 50 | """Get set of osd's ip""" |
Ved-vampir | a915a01 | 2015-03-18 14:38:52 +0300 | [diff] [blame] | 51 | |
koder aka kdanilov | 7308462 | 2016-11-16 21:51:08 +0200 | [diff] [blame^] | 52 | data = node.run("ceph -c {} -k {} --format json osd dump".format(conf, key)) |
| 53 | jdata = json.loads(data) |
| 54 | ips = set() # type: Set[IP] |
| 55 | first_error = True |
| 56 | for osd_data in jdata["osds"]: |
| 57 | if "public_addr" not in osd_data: |
| 58 | if first_error: |
| 59 | osd_id = osd_data.get("osd", "<OSD_ID_MISSED>") |
| 60 | logger.warning("No 'public_addr' field in 'ceph osd dump' output for osd %s" + |
| 61 | "(all subsequent errors omitted)", osd_id) |
| 62 | first_error = False |
| 63 | else: |
| 64 | ip_port = osd_data["public_addr"] |
| 65 | if '/' in ip_port: |
| 66 | ip_port = ip_port.split("/", 1)[0] |
| 67 | ips.add(IP(ip_port.split(":")[0])) |
koder aka kdanilov | e06762a | 2015-03-22 23:32:09 +0200 | [diff] [blame] | 68 | return ips |
Ved-vampir | a915a01 | 2015-03-18 14:38:52 +0300 | [diff] [blame] | 69 | |
| 70 | |
koder aka kdanilov | 7308462 | 2016-11-16 21:51:08 +0200 | [diff] [blame^] | 71 | def get_mons_ips(node: IRPCNode, conf: str, key: str) -> Set[IP]: |
| 72 | """Return mon ip set""" |
| 73 | |
| 74 | data = node.run("ceph -c {} -k {} --format json mon_status".format(conf, key)) |
| 75 | jdata = json.loads(data) |
| 76 | ips = set() # type: Set[IP] |
| 77 | first_error = True |
| 78 | for mon_data in jdata["monmap"]["mons"]: |
| 79 | if "addr" not in mon_data: |
| 80 | if first_error: |
| 81 | mon_name = mon_data.get("name", "<MON_NAME_MISSED>") |
| 82 | logger.warning("No 'addr' field in 'ceph mon_status' output for mon %s" + |
| 83 | "(all subsequent errors omitted)", mon_name) |
| 84 | first_error = False |
| 85 | else: |
| 86 | ip_port = mon_data["addr"] |
| 87 | if '/' in ip_port: |
| 88 | ip_port = ip_port.split("/", 1)[0] |
| 89 | ips.add(IP(ip_port.split(":")[0])) |
| 90 | |
koder aka kdanilov | e06762a | 2015-03-22 23:32:09 +0200 | [diff] [blame] | 91 | return ips |