def ssh_keyscan(hostnames):
"""
Fetch the SSH public key of one or more hosts
+
+ :param hostnames: A list of hostnames, or a dict keyed by hostname
+ :returns: A dict keyed by hostname, with the host keys as values
"""
if isinstance(hostnames, basestring):
raise TypeError("'hostnames' must be a list")
hostnames = [canonicalize_hostname(name, user=None) for name in
hostnames]
- args = ['ssh-keyscan', '-T', '1', '-t', 'rsa'] + hostnames
+ keys_dict = dict()
+ for hostname in hostnames:
+ with safe_while(
+ sleep=1, tries=5, action="ssh_keyscan " + hostname) as proceed:
+ while proceed():
+ key = _ssh_keyscan(hostname)
+ if key:
+ keys_dict[hostname] = key
+ break
+ if len(keys_dict) != len(hostnames):
+ missing = set(hostnames) - set(keys_dict.keys())
+ raise RuntimeError("Unable to scan these host keys: %s" % missing)
+ return keys_dict
+
+
+def _ssh_keyscan(hostname):
+ """
+ Fetch the SSH public key of one or more hosts
+
+ :param hostname: The hostname
+ :returns: The host key
+ """
+ args = ['ssh-keyscan', '-T', '1', '-t', 'rsa', hostname]
p = subprocess.Popen(
args=args,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
p.wait()
-
- keys_dict = dict()
for line in p.stderr.readlines():
line = line.strip()
if line and not line.startswith('#'):
log.error(line)
for line in p.stdout.readlines():
host, key = line.strip().split(' ', 1)
- keys_dict[host] = key
- return keys_dict
+ return key
def ssh_keyscan_wait(hostname):