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

Side by Side Diff: kick.py

Issue 5611225295618048: Issue 1267 - Provide a way to run some command on multiple hosts (Closed)
Patch Set: Print all logging output to stderr Created Aug. 29, 2014, 10:08 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
« no previous file with comments | « .hgignore ('k') | run.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
6 import re
7 import subprocess
8 import getopt 5 import getopt
9 import yaml 6 from run import resolveHostList, runCommand
10 7
11 def usage(): 8 def usage():
12 print >>sys.stderr, ''' 9 print >>sys.stderr, '''
13 Usage: %s -u <user> [-t|-q] [<host>|<group>] ... 10 Usage: %s [-u <user>] [-t|-q] [<host>|<group>] ...
14 11
15 Runs provisioning on the given hosts or groups of hosts. 12 Runs provisioning on the given hosts or groups of hosts.
16 13
17 Options: 14 Options:
18 -u <user> User name to use with the SSH command (needs access to puppet 15 -u <user> User name to use with the SSH command (needs access to puppet
19 master and all hosts) 16 master and all hosts)
20 -t Dry-run mode, will produce the usual output but not change 17 -t Dry-run mode, will produce the usual output but not change
21 host configuration 18 host configuration
22 -q Quiet mode, suppress Puppet output to console 19 -q Quiet mode, suppress Puppet output to console
23 ''' % sys.argv[0] 20 ''' % sys.argv[0]
(...skipping 14 matching lines...) Expand all
38 user = None 35 user = None
39 mode = ' --test' 36 mode = ' --test'
40 for option, value in options: 37 for option, value in options:
41 if option == '-u': 38 if option == '-u':
42 user = value 39 user = value
43 elif option == '-q': 40 elif option == '-q':
44 mode = '' 41 mode = ''
45 elif option == '-t': 42 elif option == '-t':
46 mode = ' --test --noop' 43 mode = ' --test --noop'
47 44
48 if user == None:
49 print >>sys.stderr, 'No user name specified'
50 usage()
51 sys.exit(1)
52
53 return user, mode, args 45 return user, mode, args
54 46
55 def readMonitoringConfig():
56 # Use Puppet's parser to convert monitoringserver.pp into YAML
57 manifest = os.path.join(os.path.dirname(__file__), 'manifests', 'monitoringser ver.pp')
58 parseScript = '''
59 require 'puppet'
60 require 'puppet/parser'
61 parser = Puppet::Parser::Parser.new(Puppet[:environment])
62 Puppet.settings[:ignoreimport] = true
63 parser.file = ARGV[0]
64 print ZAML.dump(parser.parse)
65 '''
66 data, dummy = subprocess.Popen(['ruby', '', manifest],
67 stdin=subprocess.PIPE,
68 stdout=subprocess.PIPE).communicate(parseScript)
69
70 # See http://stackoverflow.com/q/8357650/785541 on parsing Puppet's YAML
71 yaml.add_multi_constructor(u"!ruby/object:", lambda loader, suffix, node: load er.construct_yaml_map(node))
72 yaml.add_constructor(u"!ruby/sym", lambda loader, node: loader.construct_yaml_ str(node))
73 return yaml.load(data)
74
75 def getValidHosts():
76 def processNode(node, hosts=None, groups=None):
77 if hosts == None:
78 hosts = set()
79 if groups == None:
80 groups = {}
81
82 if 'context' in node and 'code' in node['context']:
83 node = node['context']['code']
84
85 if node.get('type', None) == 'nagios_hostgroup':
86 data = node['instances']['children'][0]
87 title = data['title']['value']
88 members = filter(lambda c: c['param'] == 'members', data['parameters']['ch ildren'])[0]['value']['value']
89 members = re.split(r'\s*,\s*', members)
90 groups[title] = members
91 elif node.get('type', None) == 'nagios_host':
92 data = node['instances']['children'][0]
93 title = data['title']['value']
94 hosts.add(title)
95
96 for child in node['children']:
97 processNode(child, hosts, groups)
98 return hosts, groups
99
100 monitoringConfig = readMonitoringConfig()
101 if not monitoringConfig:
102 print >>sys.stderr, "Failed to parse monitoring configuration"
103 return [[], []]
104 # Extract hosts and groups from monitoring config
105 return processNode(monitoringConfig)
106
107 def resolveHostList(hosts, validHosts, validGroups):
108 if not validHosts:
109 print "Warning: No valid hosts found, not validating"
110 return hosts
111
112 result = set()
113 for param in hosts:
114 if param in validGroups:
115 for host in validGroups[param]:
116 if host == '*':
117 result = result | validHosts
118 else:
119 result.add(host)
120 elif param in validHosts:
121 result.add(param)
122 elif '%s.adblockplus.org' % param in validHosts:
123 result.add('%s.adblockplus.org' % param)
124 else:
125 print >>sys.stderr, 'Warning: failed to recognize host or group %s' %param
126 return result
127
128 def updateMaster(user): 47 def updateMaster(user):
129 print 'Updating data on the puppet master...' 48 print 'Updating data on the puppet master...'
130 remoteCommand = ' && '.join([ 49 remoteCommand = ' && '.join([
131 'sudo hg pull -qu -R /etc/puppet/infrastructure', 50 'sudo hg pull -qu -R /etc/puppet/infrastructure',
132 'sudo hg pull -qu -R /etc/puppet/infrastructure/modules/private', 51 'sudo hg pull -qu -R /etc/puppet/infrastructure/modules/private',
133 ]) 52 ])
134 os.system('ssh -l %s puppetmaster.adblockplus.org "%s"' % (user, remoteCommand )) 53 runCommand(user, "puppetmaster.adblockplus.org", remoteCommand)
135 54
136 def updateClient(user, host, mode): 55 def updateClient(user, host, mode):
137 print 'Provisioning %s...' % host 56 print 'Provisioning %s...' % host
138 remoteCommand = 'sudo puppet agent%s' %mode 57 remoteCommand = 'sudo puppet agent%s' % mode
139 os.system('ssh -l %s %s "%s"' % (user, host, remoteCommand)) 58
59 # Have to ignore errors here, Puppet will return non-zero for successful runs
60 runCommand(user, host, remoteCommand, ignore_errors=True)
140 61
141 if __name__ == "__main__": 62 if __name__ == "__main__":
142 user, mode, args = parseOptions(sys.argv[1:]) 63 user, mode, args = parseOptions(sys.argv[1:])
143 hosts, groups = getValidHosts() 64 needKicking = resolveHostList(args)
144 needKicking = resolveHostList(args, hosts, groups)
145 if len(needKicking) == 0: 65 if len(needKicking) == 0:
146 print >>sys.stderr, 'No valid hosts or groups specified, nothing to do' 66 print >>sys.stderr, 'No valid hosts or groups specified, nothing to do'
147 sys.exit(0) 67 sys.exit(0)
148 updateMaster(user) 68 updateMaster(user)
149 for host in needKicking: 69 for host in needKicking:
150 updateClient(user, host, mode) 70 updateClient(user, host, mode)
OLDNEW
« no previous file with comments | « .hgignore ('k') | run.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld