| OLD | NEW |
| 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 Loading... |
| 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) |
| OLD | NEW |