Left: | ||
Right: |
OLD | NEW |
---|---|
(Empty) | |
1 #!/usr/bin/env python | |
2 # coding: utf-8 | |
3 | |
4 import sys | |
5 import os | |
6 import re | |
7 import subprocess | |
8 import getopt | |
9 import yaml | |
10 | |
11 def usage(): | |
12 print >>sys.stderr, ''' | |
13 Usage: %s [-u <user>] [-h <host>|<group>] [-i] ... <command> | |
14 | |
15 Runs a command on the given hosts or groups of hosts. | |
16 | |
17 Options: | |
18 -u <user> User name to use with the SSH command | |
19 -h <host|group> Host or group to run the command on (can be specified multiple times) | |
20 -i If specified, command will be executed on all hosts despite er rors | |
21 ''' % sys.argv[0] | |
22 | |
23 def parseOptions(args): | |
24 try: | |
25 options, args = getopt.getopt(args, 'u:h:i') | |
26 except getopt.GetoptError, e: | |
27 print >>sys.stderr, e | |
28 usage() | |
29 sys.exit(1) | |
30 | |
31 user = None | |
32 hosts = [] | |
33 ignore_errors = False | |
34 for option, value in options: | |
35 if option == '-u': | |
36 user = value | |
37 elif option == '-h': | |
38 hosts.append(value) | |
39 elif option == '-i': | |
40 ignore_errors = True | |
41 | |
42 return user, hosts, ignore_errors, args | |
43 | |
44 def readMonitoringConfig(): | |
45 # Use Puppet's parser to convert monitoringserver.pp into YAML | |
46 manifest = os.path.join(os.path.dirname(__file__), 'manifests', 'monitoringser ver.pp') | |
47 parseScript = ''' | |
48 require 'puppet' | |
49 require 'puppet/parser' | |
50 parser = Puppet::Parser::Parser.new(Puppet[:environment]) | |
51 Puppet.settings[:ignoreimport] = true | |
52 parser.file = ARGV[0] | |
53 print ZAML.dump(parser.parse) | |
54 ''' | |
55 data, dummy = subprocess.Popen(['ruby', '', manifest], | |
56 stdin=subprocess.PIPE, | |
57 stdout=subprocess.PIPE).communicate(parseScript) | |
58 | |
59 # See http://stackoverflow.com/q/8357650/785541 on parsing Puppet's YAML | |
60 yaml.add_multi_constructor(u"!ruby/object:", lambda loader, suffix, node: load er.construct_yaml_map(node)) | |
61 yaml.add_constructor(u"!ruby/sym", lambda loader, node: loader.construct_yaml_ str(node)) | |
62 return yaml.load(data) | |
63 | |
64 def getValidHosts(): | |
65 def processNode(node, hosts=None, groups=None): | |
66 if hosts == None: | |
67 hosts = set() | |
68 if groups == None: | |
69 groups = {} | |
70 | |
71 if 'context' in node and 'code' in node['context']: | |
72 node = node['context']['code'] | |
73 | |
74 if node.get('type', None) == 'nagios_hostgroup': | |
75 data = node['instances']['children'][0] | |
76 title = data['title']['value'] | |
77 members = filter(lambda c: c['param'] == 'members', data['parameters']['ch ildren'])[0]['value']['value'] | |
78 members = re.split(r'\s*,\s*', members) | |
79 groups[title] = members | |
80 elif node.get('type', None) == 'nagios_host': | |
81 data = node['instances']['children'][0] | |
82 title = data['title']['value'] | |
83 hosts.add(title) | |
84 | |
85 for child in node['children']: | |
86 processNode(child, hosts, groups) | |
87 return hosts, groups | |
88 | |
89 monitoringConfig = readMonitoringConfig() | |
90 if not monitoringConfig: | |
91 print >>sys.stderr, "Failed to parse monitoring configuration" | |
92 return [[], []] | |
93 # Extract hosts and groups from monitoring config | |
94 return processNode(monitoringConfig) | |
95 | |
96 def resolveHostList(hosts): | |
97 validHosts, validGroups = getValidHosts() | |
98 if not validHosts: | |
99 print "Warning: No valid hosts found, not validating" | |
100 return hosts | |
101 | |
102 result = set() | |
103 for param in hosts: | |
104 if param in validGroups: | |
105 for host in validGroups[param]: | |
106 if host == '*': | |
107 result = result | validHosts | |
108 else: | |
109 result.add(host) | |
110 elif param in validHosts: | |
111 result.add(param) | |
112 elif '%s.adblockplus.org' % param in validHosts: | |
113 result.add('%s.adblockplus.org' % param) | |
114 else: | |
115 print >>sys.stderr, 'Warning: failed to recognize host or group %s' %param | |
116 return result | |
117 | |
118 def runCommand(user, host, command, ignore_errors=False): | |
119 if not isinstance(command, list): | |
120 command = [command] | |
121 command = ["ssh"] + (["-l", user] if user else []) + [host] + command | |
122 if ignore_errors: | |
123 subprocess.call(command) | |
124 else: | |
125 subprocess.check_call(command) | |
126 | |
127 if __name__ == "__main__": | |
128 user, hosts, ignore_errors, args = parseOptions(sys.argv[1:]) | |
129 selectedHosts = resolveHostList(hosts) | |
130 if len(selectedHosts) == 0: | |
131 print >>sys.stderr, 'No valid hosts or groups specified, nothing to do' | |
132 sys.exit(0) | |
133 for host in selectedHosts: | |
134 print 'Running on %s...' % host | |
mathias
2014/08/25 16:21:25
If all logging would be printed to >>stderr (just
Wladimir Palant
2014/08/29 22:11:15
I'm not usually using scripts on the output. And t
| |
135 runCommand(user, host, args, ignore_errors=ignore_errors) | |
OLD | NEW |