1# Copyright (c) 2009-2012, Andrew McNabb 2# Copyright (c) 2003-2008, Brent N. Chun 3 4import fcntl 5import sys 6import subprocess 7 8HOST_FORMAT = 'Host format is [user@]host[:port] [user]' 9 10 11def read_host_files(paths, default_user=None, default_port=None): 12 """Reads the given host files. 13 14 Returns a list of (host, port, user) triples. 15 """ 16 hosts = [] 17 if paths: 18 for path in paths: 19 hosts.extend(read_host_file(path, default_user=default_user)) 20 return hosts 21 22 23def read_host_file(path, default_user=None, default_port=None): 24 """Reads the given host file. 25 26 Lines are of the form: host[:port] [login]. 27 Returns a list of (host, port, user) triples. 28 """ 29 lines = [] 30 f = open(path) 31 for line in f: 32 lines.append(line.strip()) 33 f.close() 34 35 hosts = [] 36 for line in lines: 37 # Skip blank lines or lines starting with # 38 line = line.strip() 39 if not line or line.startswith('#'): 40 continue 41 host, port, user = parse_host_entry(line, default_user, default_port) 42 if host: 43 hosts.append((host, port, user)) 44 return hosts 45 46 47# TODO: deprecate the second host field and standardize on the 48# [user@]host[:port] format. 49def parse_host_entry(line, default_user, default_port): 50 """Parses a single host entry. 51 52 This may take either the of the form [user@]host[:port] or 53 host[:port][ user]. 54 55 Returns a (host, port, user) triple. 56 """ 57 fields = line.split() 58 if len(fields) > 2: 59 sys.stderr.write('Bad line: "%s". Format should be' 60 ' [user@]host[:port] [user]\n' % line) 61 return None, None, None 62 host_field = fields[0] 63 host, port, user = parse_host(host_field, default_port=default_port) 64 if len(fields) == 2: 65 if user is None: 66 user = fields[1] 67 else: 68 sys.stderr.write('User specified twice in line: "%s"\n' % line) 69 return None, None, None 70 if user is None: 71 user = default_user 72 return host, port, user 73 74 75def parse_host_string(host_string, default_user=None, default_port=None): 76 """Parses a whitespace-delimited string of "[user@]host[:port]" entries. 77 78 Returns a list of (host, port, user) triples. 79 """ 80 hosts = [] 81 entries = host_string.split() 82 for entry in entries: 83 hosts.append(parse_host(entry, default_user, default_port)) 84 return hosts 85 86 87def parse_host(host, default_user=None, default_port=None): 88 """Parses host entries of the form "[user@]host[:port]". 89 90 Returns a (host, port, user) triple. 91 """ 92 # TODO: when we stop supporting Python 2.4, switch to using str.partition. 93 user = default_user 94 port = default_port 95 if '@' in host: 96 user, host = host.split('@', 1) 97 if ':' in host: 98 host, port = host.rsplit(':', 1) 99 return (host, port, user) 100 101 102def get_pacemaker_nodes(): 103 """Get the list of nodes from crm_node -l. 104 105 Returns a list of (host, port, user) triples. 106 """ 107 hosts = [] 108 if subprocess.call("which crm_node >/dev/null 2>&1", shell=True) != 0: 109 sys.stderr.write('crm_node not available\n') 110 return hosts 111 cmd = "crm_node -l" 112 p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) 113 try: 114 outp = p.communicate()[0] 115 p.wait() 116 rc = p.returncode 117 except IOError as msg: 118 sys.stderr.write('%s failed: %s\n' % (cmd, msg)) 119 return hosts 120 if rc != 0: 121 sys.stderr.write('%s failed: exit code %d\n' % (cmd, rc)) 122 return hosts 123 for s in outp.split('\n'): 124 a = s.split() 125 if len(a) < 2: 126 continue 127 hosts.append((a[1], None, None)) 128 return hosts 129 130 131def set_cloexec(filelike): 132 """Sets the underlying filedescriptor to automatically close on exec. 133 134 If set_cloexec is called for all open files, then subprocess.Popen does 135 not require the close_fds option. 136 """ 137 fcntl.fcntl(filelike.fileno(), fcntl.FD_CLOEXEC, 1) 138 139# vim:ts=4:sw=4:et: 140