From: Sebastian Wagner Date: Fri, 6 Aug 2021 09:41:39 +0000 (+0200) Subject: cephadm: list-networks: Avoid duplicated IPs X-Git-Tag: v16.2.6~25^2~2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=48f2c9876c3dcc3a9ec92f34841dbf18a8a20f30;p=ceph.git cephadm: list-networks: Avoid duplicated IPs Fixes: https://tracker.ceph.com/issues/52083 Signed-off-by: Sebastian Wagner (cherry picked from commit b65822fc8cd3cbf541d50e9ee69d77ef9d1e9cfd) --- diff --git a/src/cephadm/cephadm b/src/cephadm/cephadm index 510b344dd10..13f0f6e6a59 100755 --- a/src/cephadm/cephadm +++ b/src/cephadm/cephadm @@ -31,7 +31,7 @@ from contextlib import redirect_stdout import ssl from enum import Enum -from typing import Dict, List, Tuple, Optional, Union, Any, NoReturn, Callable, IO, Sequence, TypeVar, cast +from typing import Dict, List, Tuple, Optional, Union, Any, NoReturn, Callable, IO, Sequence, TypeVar, cast, Set import re import uuid @@ -4798,7 +4798,7 @@ def command_logs(ctx): def list_networks(ctx): - # type: (CephadmContext) -> Dict[str,Dict[str,List[str]]] + # type: (CephadmContext) -> Dict[str,Dict[str, Set[str]]] # sadly, 18.04's iproute2 4.15.0-2ubun doesn't support the -j flag, # so we'll need to use a regex to parse 'ip' command output. @@ -4806,13 +4806,12 @@ def list_networks(ctx): # out, _, _ = call_throws(['ip', '-j', 'route', 'ls']) # j = json.loads(out) # for x in j: - res = _list_ipv4_networks(ctx) res.update(_list_ipv6_networks(ctx)) return res -def _list_ipv4_networks(ctx: CephadmContext) -> Dict[str, Dict[str, List[str]]]: +def _list_ipv4_networks(ctx: CephadmContext) -> Dict[str, Dict[str, Set[str]]]: execstr: Optional[str] = find_executable('ip') if not execstr: raise FileNotFoundError("unable to find 'ip' command") @@ -4820,8 +4819,8 @@ def _list_ipv4_networks(ctx: CephadmContext) -> Dict[str, Dict[str, List[str]]]: return _parse_ipv4_route(out) -def _parse_ipv4_route(out: str) -> Dict[str, Dict[str, List[str]]]: - r = {} # type: Dict[str,Dict[str,List[str]]] +def _parse_ipv4_route(out: str) -> Dict[str, Dict[str, Set[str]]]: + r = {} # type: Dict[str, Dict[str, Set[str]]] p = re.compile(r'^(\S+) dev (\S+) (.*)scope link (.*)src (\S+)') for line in out.splitlines(): m = p.findall(line) @@ -4833,12 +4832,12 @@ def _parse_ipv4_route(out: str) -> Dict[str, Dict[str, List[str]]]: if net not in r: r[net] = {} if iface not in r[net]: - r[net][iface] = [] - r[net][iface].append(ip) + r[net][iface] = set() + r[net][iface].add(ip) return r -def _list_ipv6_networks(ctx: CephadmContext) -> Dict[str, Dict[str, List[str]]]: +def _list_ipv6_networks(ctx: CephadmContext) -> Dict[str, Dict[str, Set[str]]]: execstr: Optional[str] = find_executable('ip') if not execstr: raise FileNotFoundError("unable to find 'ip' command") @@ -4847,8 +4846,8 @@ def _list_ipv6_networks(ctx: CephadmContext) -> Dict[str, Dict[str, List[str]]]: return _parse_ipv6_route(routes, ips) -def _parse_ipv6_route(routes: str, ips: str) -> Dict[str, Dict[str, List[str]]]: - r = {} # type: Dict[str,Dict[str,List[str]]] +def _parse_ipv6_route(routes: str, ips: str) -> Dict[str, Dict[str, Set[str]]]: + r = {} # type: Dict[str, Dict[str, Set[str]]] route_p = re.compile(r'^(\S+) dev (\S+) proto (\S+) metric (\S+) .*pref (\S+)$') ip_p = re.compile(r'^\s+inet6 (\S+)/(.*)scope (.*)$') iface_p = re.compile(r'^(\d+): (\S+): (.*)$') @@ -4863,7 +4862,7 @@ def _parse_ipv6_route(routes: str, ips: str) -> Dict[str, Dict[str, List[str]]]: if net not in r: r[net] = {} if iface not in r[net]: - r[net][iface] = [] + r[net][iface] = set() iface = None for line in ips.splitlines(): @@ -4880,7 +4879,7 @@ def _parse_ipv6_route(routes: str, ips: str) -> Dict[str, Dict[str, List[str]]]: if ipaddress.ip_address(ip) in ipaddress.ip_network(n)] if net: assert(iface) - r[net[0]][iface].append(ip) + r[net[0]][iface].add(ip) return r @@ -4888,7 +4887,11 @@ def _parse_ipv6_route(routes: str, ips: str) -> Dict[str, Dict[str, List[str]]]: def command_list_networks(ctx): # type: (CephadmContext) -> None r = list_networks(ctx) - print(json.dumps(r, indent=4)) + + def serialize_sets(obj: Any) -> Any: + return list(obj) if isinstance(obj, set) else obj + + print(json.dumps(r, indent=4, default=serialize_sets)) ##################################