import errno
+import ipaddress
import logging
-from typing import Any, Dict, List, Tuple, cast, Optional
+from typing import Any, Dict, List, Tuple, cast, Optional, Iterable, Union
from mgr_module import HandleCommandResult
CephadmDaemonDeploySpec,
simplified_keyring,
)
+from ..schedule import DaemonPlacement
logger = logging.getLogger(__name__)
if daemon_id is not None:
self.fence(smb_spec.cluster_id)
del rank_map[rank][gen]
- self.mgr.spec_store.save_rank_map(spec.service_name(), rank_map)
+ self.mgr.spec_store.save_rank_map(
+ spec.service_name(), rank_map
+ )
+
+ def filter_host_candidates(
+ self,
+ spec: ServiceSpec,
+ candidates: Iterable[DaemonPlacement],
+ ) -> List[DaemonPlacement]:
+ logger.debug(
+ 'SMBService.filter_host_candidates with candidates: %r',
+ candidates,
+ )
+ smb_spec = cast(SMBSpec, spec)
+ if not smb_spec.bind_addrs:
+ return list(candidates)
+ addr_src = AddressPool.from_spec(smb_spec)
+ filtered = [
+ dc
+ for dc in (self._candidate_in(c, addr_src) for c in candidates)
+ if dc is not None
+ ]
+ if len(filtered) != len(list(candidates)):
+ logger.debug('Filtered host candidates to: %r', filtered)
+ return filtered
+
+ def _candidate_in(
+ self, candidate: DaemonPlacement, addr_src: 'AddressPool'
+ ) -> Optional[DaemonPlacement]:
+ hostnw = self.mgr.cache.networks.get(candidate.hostname, {})
+ if not hostnw:
+ return None
+ ips = set()
+ for net_vals in hostnw.values():
+ for if_vals in net_vals.values():
+ ips.update(if_vals)
+ logger.debug(
+ 'Checking if IPs %r from %s are in bindable addrs',
+ ips,
+ candidate.hostname,
+ )
+ for ip in ips:
+ if ip in addr_src:
+ return candidate._replace(ip=ip)
+ return None
def prepare_create(
self, daemon_spec: CephadmDaemonDeploySpec
logger.debug("smb daemon map: %r", smb_dmap)
with clustermeta.rados_object(self.mgr, uri) as cmeta:
cmeta.sync_ranks(rank_map, smb_dmap)
+
+
+Network = Union[ipaddress.IPv4Network, ipaddress.IPv6Network]
+
+
+class AddressPool:
+ def __init__(self, nets: Iterable[Network]) -> None:
+ self._nets = set(nets)
+
+ def __contains__(self, other: Union[str, ipaddress.IPv4Address]) -> bool:
+ if isinstance(other, str):
+ addr = ipaddress.ip_address(other)
+ else:
+ addr = other
+ return any((addr in net) for net in self._nets)
+
+ @classmethod
+ def from_spec(cls, spec: SMBSpec) -> 'AddressPool':
+ nets = set()
+ for baddr in spec.bind_addrs or []:
+ for net in baddr.as_networks():
+ nets.add(net)
+ return cls(nets)