@@ -461,6 +461,46 @@ def _set_iface_and_cidr(self):
461461 return
462462 raise RuntimeError ("Could not determine interface/CIDR!" )
463463
464+
465+ def resolve_ip (self , name = None , ipv = '4' ) -> str :
466+ """
467+ Resolve IP address of the remote host via remote host
468+
469+ Because remote object maybe behind bastion host we need
470+ the remote host address resolvable from remote side.
471+ So in order to the ip address we just call `host` remotely
472+ and parse output like:
473+ 'smithi001.front.sepia.ceph.com has address 172.21.15.1\n '
474+
475+ :param name: hostname to resolve, by defaults remote host itself.
476+ :param ipv: the IP version, 4 or 6, defaults to 4.
477+
478+ :raises: :class:`Exception`: when the hostname cannot be resolved.
479+ :raises: :class:`ValueError`: when the ipv argument mismatch 4 or 6.
480+
481+ :returns: str object, the ip addres of the remote host.
482+ """
483+ hostname = name or self .hostname
484+ version = str (ipv )
485+ if version in ['4' , '6' ]:
486+ remote_host_ip = self .sh (f'host -{ ipv } { hostname } ' )
487+ else :
488+ raise ValueError (f'Unknown IP version { ipv } , expected 4 or 6' )
489+ # `host -4` or `host -6` may have multiline output: a host can have
490+ # several address; thus try and find the first suitable
491+ for info in remote_host_ip .split ("\n " ):
492+ if version == '4' and 'has address' in info :
493+ (host , ip ) = info .strip ().split (' has address ' )
494+ if hostname in host :
495+ return ip
496+ elif version == '6' and 'has IPv6 address' in info :
497+ (host , ip ) = info .strip ().split (' has IPv6 address ' )
498+ if hostname in host :
499+ return ip
500+ else :
501+ raise Exception (f'Cannot get IPv{ ipv } address for the host "{ hostname } " via remote "{ self .hostname } "' )
502+
503+
464504 @property
465505 def hostname (self ):
466506 if not hasattr (self , '_hostname' ):
0 commit comments