Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: run.py

Issue 4810150141493248: Issue 122 - Puppet ENC via Hiera (Closed)
Patch Set: 112 - Integrate run.py and monitoring with Hiera Created Feb. 26, 2015, 5:59 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # coding: utf-8 2 # coding: utf-8
3 3
4 import sys 4 import sys
5 import os 5 import os
6 import os.path
Felix Dahlke 2015/03/03 16:43:32 Not necessary, we're already importing os. Looks l
mathias 2015/03/04 12:32:37 Agreed, the explicit os.path import will be remove
6 import re 7 import re
7 import subprocess 8 import subprocess
8 import getopt 9 import getopt
9 import yaml 10 import yaml
10 11
11 def usage(): 12 def usage():
12 print >>sys.stderr, ''' 13 print >>sys.stderr, '''
13 Usage: %s [-u <user>] [-h <host>|<group>] [-i] ... <command> 14 Usage: %s [-u <user>] [-h <host>|<group>] [-i] ... <command>
14 15
15 Runs a command on the given hosts or groups of hosts. 16 Runs a command on the given hosts or groups of hosts.
(...skipping 18 matching lines...) Expand all
34 for option, value in options: 35 for option, value in options:
35 if option == '-u': 36 if option == '-u':
36 user = value 37 user = value
37 elif option == '-h': 38 elif option == '-h':
38 hosts.append(value) 39 hosts.append(value)
39 elif option == '-i': 40 elif option == '-i':
40 ignore_errors = True 41 ignore_errors = True
41 42
42 return user, hosts, ignore_errors, args 43 return user, hosts, ignore_errors, args
43 44
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 45
64 def getValidHosts(): 46 def getValidHosts():
65 def processNode(node, hosts=None, groups=None): 47 dirname = os.path.dirname(sys.argv[0])
66 if hosts == None: 48 path_name = os.path.join(dirname, "hiera", "private", "hosts.yaml")
67 hosts = set() 49 with open(path_name, 'rb') as handle:
68 if groups == None: 50 config = yaml.load(handle)
69 groups = {} 51 servers = config.get('servers', {})
70 52 return servers
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 53
96 def resolveHostList(hosts): 54 def resolveHostList(hosts):
97 validHosts, validGroups = getValidHosts()
98 if not validHosts:
99 print >>sys.stderr, "Warning: No valid hosts found, not validating"
100 return hosts
101 55
56 host_names = set(str(item) for item in hosts)
Wladimir Palant 2015/03/03 20:00:19 Given that hosts is a list of string, this seems e
mathias 2015/03/04 12:32:37 "Given that hosts is a list of string" <- this is
Felix Dahlke 2015/03/04 14:27:53 Nit: The parentheses are now not necessary anymore
Wladimir Palant 2015/03/04 15:14:11 This isn't a library function you wrote here, it i
mathias 2015/03/04 18:13:51 Done.
mathias 2015/03/04 18:13:51 Done.
102 result = set() 57 result = set()
103 for param in hosts: 58
104 if param in validGroups: 59 try:
105 for host in validGroups[param]: 60 valid_hosts = getValidHosts()
Felix Dahlke 2015/03/03 16:43:32 Host validation doesn't make _that_ much sense any
Wladimir Palant 2015/03/03 20:00:19 Indeed, that's something we discussed previously -
mathias 2015/03/04 12:32:37 This version does two jobs at the same time; valid
Felix Dahlke 2015/03/04 14:27:53 For the record: I actually prefer Wladimir's sugge
Wladimir Palant 2015/03/04 15:14:11 Actually, changing the current validation code to
mathias 2015/03/04 18:13:51 @Felix As I wrote before, this is actually intende
Felix Dahlke 2015/03/09 23:14:51 Didn't realise this, but yeah, the catch clause st
106 if host == '*': 61 except Warning as error:
107 result = result | validHosts 62 print >>sys.stderr, 'Warning: failed to determine valid hosts:', error
108 else: 63 result.update(host_names)
109 result.add(host) 64 else:
110 elif param in validHosts: 65 for name in host_names:
111 result.add(param) 66 chunk = tuple(
112 elif '%s.adblockplus.org' % param in validHosts: 67 item[1].get('dns', item[0]) for item in valid_hosts.items()
Wladimir Palant 2015/03/03 20:00:19 for (key, value) in valid_hosts.iteritems() please
mathias 2015/03/04 12:32:37 Done. To answer your question: There is no need
Wladimir Palant 2015/03/04 15:14:11 The difference between a list and a tuple isn't th
mathias 2015/03/04 18:13:51 This has already been changed in the current patch
113 result.add('%s.adblockplus.org' % param) 68
114 else: 69 if name == item[0]
115 print >>sys.stderr, 'Warning: failed to recognize host or group %s' %param 70 or name == '*'
71 or name == item[1].get('dns', None)
72 or name in item[1]['ip']
mathias 2015/02/26 18:41:23 While resolving IPs would be a nice feature, this
mathias 2015/03/04 12:32:37 Done.
73 or name in item[1].get('groups', ())
74 )
75
76 if len(chunk) == 0:
77 print >>sys.stderr, 'Warning: failed to recognize host or group', name
78 else:
79 result.update(chunk)
80
116 return result 81 return result
117 82
118 def runCommand(user, host, command, ignore_errors=False): 83 def runCommand(user, host, command, ignore_errors=False):
119 if not isinstance(command, list): 84 if not isinstance(command, list):
120 command = [command] 85 command = [command]
121 command = ["ssh"] + (["-l", user] if user else []) + [host] + command 86 command = ["ssh"] + (["-l", user] if user else []) + [host] + command
122 if ignore_errors: 87 if ignore_errors:
123 subprocess.call(command) 88 subprocess.call(command)
124 else: 89 else:
125 subprocess.check_call(command) 90 subprocess.check_call(command)
126 91
127 if __name__ == "__main__": 92 if __name__ == "__main__":
128 user, hosts, ignore_errors, args = parseOptions(sys.argv[1:]) 93 user, hosts, ignore_errors, args = parseOptions(sys.argv[1:])
129 selectedHosts = resolveHostList(hosts) 94 selectedHosts = resolveHostList(hosts)
130 if len(selectedHosts) == 0: 95 if len(selectedHosts) == 0:
131 print >>sys.stderr, 'No valid hosts or groups specified, nothing to do' 96 print >>sys.stderr, 'No valid hosts or groups specified, nothing to do'
132 sys.exit(0) 97 sys.exit(0)
133 for host in selectedHosts: 98 for host in selectedHosts:
134 print >>sys.stderr, 'Running on %s...' % host 99 print >>sys.stderr, 'Running on %s...' % host
135 runCommand(user, host, args, ignore_errors=ignore_errors) 100 runCommand(user, host, args, ignore_errors=ignore_errors)
OLDNEW
« modules/nagios/manifests/server.pp ('K') | « modules/statsmaster/manifests/init.pp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld