Mercurial > hg > silvermirror
view silvermirror/unify.py @ 0:abb358e2434c
initial commit of silvermirror, from http://my-svn.assembla.com/svn/arbez/silvermirror
author | k0s <k0scist@gmail.com> |
---|---|
date | Mon, 07 Sep 2009 15:39:06 -0400 |
parents | |
children | 9b139702a8f9 |
line wrap: on
line source
#!/usr/bin/env python import getpass import os import pexpect import socket import subprocess import sys from martini.config import ConfigMunger from optparse import OptionParser from pprint import pprint from utils import home from utils import ip_addresses def make_config(filename): # XXX needed? raise NotImplementedError('Need to specify a config file, like\n~/silvermirror/silvermirror.ini') def read_config(filename): config = ConfigMunger(filename).dict() ### main configuration main = config.pop('::SilverMirror::', {}) if not main.get('basedir'): main['basedir'] = home() main['ignore'] = main.get('ignore', '').split() # patterns to ignore - not used main['hosts'] = main.get('hosts', '').split() main['password'] = main.get('password', 'true') # XXX not used main['timeout'] = float(main.get('timeout', '10.')) ### resources for resource in config: # directory of resource directory = config[resource].get('directory', resource) if not os.path.isabs(directory): # XXX note: absolute directories will not work for now # XXX so....don't do this! directory = os.path.join(main['basedir'], directory) config[resource]['directory'] = directory.rstrip(os.path.sep) # per-resource files to ignore # XXX regexps for now (see `man unison`) # - this is bad as whitespace patterns cannot be ignored ignore = main['ignore'][:] if config[resource].has_key('ignore'): ignore += config[resource]['ignore'].split() config[resource]['ignore'] = ignore ### config = { 'main': main, 'resources': config } return config def unify(args=sys.argv[1:]): # passwords pw = {} ### command line options parser = OptionParser() parser.add_option('-c', '--config') parser.add_option('-H', '--host', dest='hosts', action='append', default=None) parser.add_option('--no-password', dest='password', action='store_false', default=True) parser.add_option('--test', dest='test', action='store_true', default=False) (options, args) = parser.parse_args() ### configuration user_conf = os.path.join(home(), '.silvermirror') if options.config: assert os.path.exists(options.config) conf = read_config(options.config) else: for i in user_conf, '/etc/silvermirror': if os.path.exists(i): conf = read_config(i) break else: conf = make_config(user_conf) # XXX needed for now assert conf['main']['basedir'] == home() ### determine hosts to sync with hosts = set(options.hosts or conf['main']['hosts']) addresses = ip_addresses().values() hosts = hosts.difference(addresses) # don't sync with self _hosts = [] for host in hosts: s = socket.socket() s.settimeout(conf['main']['timeout']) if options.test: print 'Resolving %s' % host try: s.connect((host, 22)) s.close() except (socket.gaierror, socket.timeout, socket.error): continue _hosts.append(host) hosts = _hosts if options.test: print 'Hosts:' for host in hosts: print host assert hosts if options.password and conf['main']['password']: for host in hosts: pw[host] = getpass.getpass('Enter password for %s: ' % host) # TODO: ensure that the hosts are resolvable # XXX: hosts should actually be manageable on a per-resource basis ### determine resources to sync cwd = os.path.realpath(os.getcwd()) resources = conf['resources'] _resources = args if 'all' not in _resources: if _resources: resources = dict([(key, value) for key, value in resources.items() if key in _resources]) else: for key, value in resources.items(): directory = os.path.realpath(value['directory']) + os.sep if (cwd + os.sep).startswith(directory): resources = { key: value } break if options.test: print 'Resources:' pprint(resources) ### sync with hosts os.chdir(conf['main']['basedir']) for resource in resources: for host in hosts: command = ['unison', '-auto', '-batch', resource, 'ssh://%s/%s' % (host, resource)] # XXX - to refactor? for i in resources[resource]['ignore']: command.extend(('-ignore', "'Name %s'" % i)) command = ' '.join(command) print command # XXX debug if not options.test: child = pexpect.spawn(command, timeout=36000, maxread=1) child.expect('password: ') child.sendline(pw[host]) print child.read() # subprocess.call(command) os.chdir(cwd) if __name__ == '__main__': unify()