| Index: kick.py |
| =================================================================== |
| --- a/kick.py |
| +++ b/kick.py |
| @@ -2,20 +2,21 @@ |
| # coding: utf-8 |
| import sys |
| import os |
| import re |
| import subprocess |
| import getopt |
| import yaml |
| +from run import resolveHostList, runCommand |
| def usage(): |
| print >>sys.stderr, ''' |
| -Usage: %s -u <user> [-t|-q] [<host>|<group>] ... |
| +Usage: %s [-u <user>] [-t|-q] [<host>|<group>] ... |
| Runs provisioning on the given hosts or groups of hosts. |
| Options: |
| -u <user> User name to use with the SSH command (needs access to puppet |
| master and all hosts) |
| -t Dry-run mode, will produce the usual output but not change |
| host configuration |
| @@ -40,111 +41,34 @@ def parseOptions(args): |
| for option, value in options: |
| if option == '-u': |
| user = value |
| elif option == '-q': |
| mode = '' |
| elif option == '-t': |
| mode = ' --test --noop' |
| - if user == None: |
| - print >>sys.stderr, 'No user name specified' |
| - usage() |
| - sys.exit(1) |
| - |
| return user, mode, args |
| -def readMonitoringConfig(): |
| - # Use Puppet's parser to convert monitoringserver.pp into YAML |
| - manifest = os.path.join(os.path.dirname(__file__), 'manifests', 'monitoringserver.pp') |
| - parseScript = ''' |
| - require 'puppet' |
| - require 'puppet/parser' |
| - parser = Puppet::Parser::Parser.new(Puppet[:environment]) |
| - Puppet.settings[:ignoreimport] = true |
| - parser.file = ARGV[0] |
| - print ZAML.dump(parser.parse) |
| - ''' |
| - data, dummy = subprocess.Popen(['ruby', '', manifest], |
| - stdin=subprocess.PIPE, |
| - stdout=subprocess.PIPE).communicate(parseScript) |
| - |
| - # See http://stackoverflow.com/q/8357650/785541 on parsing Puppet's YAML |
| - yaml.add_multi_constructor(u"!ruby/object:", lambda loader, suffix, node: loader.construct_yaml_map(node)) |
| - yaml.add_constructor(u"!ruby/sym", lambda loader, node: loader.construct_yaml_str(node)) |
| - return yaml.load(data) |
| - |
| -def getValidHosts(): |
| - def processNode(node, hosts=None, groups=None): |
| - if hosts == None: |
| - hosts = set() |
| - if groups == None: |
| - groups = {} |
| - |
| - if 'context' in node and 'code' in node['context']: |
| - node = node['context']['code'] |
| - |
| - if node.get('type', None) == 'nagios_hostgroup': |
| - data = node['instances']['children'][0] |
| - title = data['title']['value'] |
| - members = filter(lambda c: c['param'] == 'members', data['parameters']['children'])[0]['value']['value'] |
| - members = re.split(r'\s*,\s*', members) |
| - groups[title] = members |
| - elif node.get('type', None) == 'nagios_host': |
| - data = node['instances']['children'][0] |
| - title = data['title']['value'] |
| - hosts.add(title) |
| - |
| - for child in node['children']: |
| - processNode(child, hosts, groups) |
| - return hosts, groups |
| - |
| - monitoringConfig = readMonitoringConfig() |
| - if not monitoringConfig: |
| - print >>sys.stderr, "Failed to parse monitoring configuration" |
| - return [[], []] |
| - # Extract hosts and groups from monitoring config |
| - return processNode(monitoringConfig) |
| - |
| -def resolveHostList(hosts, validHosts, validGroups): |
| - if not validHosts: |
| - print "Warning: No valid hosts found, not validating" |
| - return hosts |
| - |
| - result = set() |
| - for param in hosts: |
| - if param in validGroups: |
| - for host in validGroups[param]: |
| - if host == '*': |
| - result = result | validHosts |
| - else: |
| - result.add(host) |
| - elif param in validHosts: |
| - result.add(param) |
| - elif '%s.adblockplus.org' % param in validHosts: |
| - result.add('%s.adblockplus.org' % param) |
| - else: |
| - print >>sys.stderr, 'Warning: failed to recognize host or group %s' %param |
| - return result |
| - |
| def updateMaster(user): |
| print 'Updating data on the puppet master...' |
| remoteCommand = ' && '.join([ |
| 'sudo hg pull -qu -R /etc/puppet/infrastructure', |
| 'sudo hg pull -qu -R /etc/puppet/infrastructure/modules/private', |
| ]) |
| - os.system('ssh -l %s puppetmaster.adblockplus.org "%s"' % (user, remoteCommand)) |
| + runCommand(user, "puppetmaster.adblockplus.org", remoteCommand) |
| def updateClient(user, host, mode): |
| print 'Provisioning %s...' % host |
| - remoteCommand = 'sudo puppet agent%s' %mode |
| - os.system('ssh -l %s %s "%s"' % (user, host, remoteCommand)) |
| + remoteCommand = 'sudo puppet agent%s' % mode |
| + |
| + # Have to ignore errors here, Puppet will return non-zero for successful runs |
| + runCommand(user, host, remoteCommand, ignore_errors=True) |
| if __name__ == "__main__": |
| user, mode, args = parseOptions(sys.argv[1:]) |
| - hosts, groups = getValidHosts() |
| - needKicking = resolveHostList(args, hosts, groups) |
| + needKicking = resolveHostList(args) |
| if len(needKicking) == 0: |
| print >>sys.stderr, 'No valid hosts or groups specified, nothing to do' |
| sys.exit(0) |
| updateMaster(user) |
| for host in needKicking: |
| updateClient(user, host, mode) |