Mercurial > hg > silvermirror
comparison silvermirror/unify.py @ 1:9b139702a8f9
use a real backend architecture with an inteface and vastly simplify unify.py
author | k0s <k0scist@gmail.com> |
---|---|
date | Sat, 26 Sep 2009 23:36:42 -0400 |
parents | abb358e2434c |
children | 743c920bc041 |
comparison
equal
deleted
inserted
replaced
0:abb358e2434c | 1:9b139702a8f9 |
---|---|
7 import subprocess | 7 import subprocess |
8 import sys | 8 import sys |
9 | 9 |
10 from martini.config import ConfigMunger | 10 from martini.config import ConfigMunger |
11 from optparse import OptionParser | 11 from optparse import OptionParser |
12 from pkg_resources import iter_entry_points | |
12 from pprint import pprint | 13 from pprint import pprint |
13 from utils import home | 14 from utils import home |
14 from utils import ip_addresses | 15 from utils import ip_addresses |
15 | 16 |
16 def make_config(filename): | 17 def make_config(filename): |
50 | 51 |
51 ### | 52 ### |
52 config = { 'main': main, 'resources': config } | 53 config = { 'main': main, 'resources': config } |
53 return config | 54 return config |
54 | 55 |
55 def unify(args=sys.argv[1:]): | 56 def unify(conf, _resources, test=False): |
56 | 57 |
57 # passwords | 58 # passwords |
58 pw = {} | 59 pw = {} |
60 | |
61 # XXX needed for now | |
62 assert conf['main']['basedir'] == home() | |
63 | |
64 ### determine hosts to sync with | |
65 hosts = conf['hosts'] | |
66 addresses = ip_addresses().values() | |
67 hosts = hosts.difference(addresses) # don't sync with self | |
68 _hosts = [] | |
69 for host in hosts: | |
70 s = socket.socket() | |
71 s.settimeout(conf['main']['timeout']) | |
72 if test: | |
73 print 'Resolving %s' % host | |
74 try: | |
75 s.connect((host, 22)) | |
76 s.close() | |
77 except (socket.gaierror, socket.timeout, socket.error): | |
78 continue | |
79 _hosts.append(host) | |
80 hosts = _hosts | |
81 if test: | |
82 print 'Hosts:' | |
83 for host in hosts: | |
84 print host | |
85 assert hosts | |
86 | |
87 if conf['main']['password']: | |
88 for host in hosts: | |
89 pw[host] = getpass.getpass('Enter password for %s: ' % host) | |
90 # TODO: ensure that the hosts are resolvable | |
91 # XXX: hosts should actually be manageable on a per-resource basis | |
92 | |
93 ### determine resources to sync | |
94 cwd = os.path.realpath(os.getcwd()) | |
95 resources = conf['resources'] | |
96 if 'all' not in _resources: | |
97 if _resources: | |
98 resources = dict([(key, value) for key, value in resources.items() | |
99 if key in _resources]) | |
100 else: | |
101 for key, value in resources.items(): | |
102 directory = os.path.realpath(value['directory']) + os.sep | |
103 if (cwd + os.sep).startswith(directory): | |
104 resources = { key: value } | |
105 break | |
106 if test: | |
107 print 'Resources:' | |
108 pprint(resources) | |
109 | |
110 ### choose reflector backend | |
111 reflectors = dict([(i.name, i.load()) for i in iter_entry_points('silvermirror.reflectors')]) | |
112 reflector = reflectors['unison']() # only one right now | |
113 | |
114 ### sync with hosts | |
115 os.chdir(conf['main']['basedir']) | |
116 for resource in resources: | |
117 for host in hosts: | |
118 reflector.sync(host, resource, resources[resource]['ignore'], pw, test) | |
119 os.chdir(cwd) | |
120 | |
121 def main(args=sys.argv[1:]): | |
59 | 122 |
60 ### command line options | 123 ### command line options |
61 parser = OptionParser() | 124 parser = OptionParser() |
62 parser.add_option('-c', '--config') | 125 parser.add_option('-c', '--config') |
63 parser.add_option('-H', '--host', dest='hosts', | 126 parser.add_option('-H', '--host', dest='hosts', |
65 parser.add_option('--no-password', dest='password', | 128 parser.add_option('--no-password', dest='password', |
66 action='store_false', default=True) | 129 action='store_false', default=True) |
67 parser.add_option('--test', dest='test', | 130 parser.add_option('--test', dest='test', |
68 action='store_true', default=False) | 131 action='store_true', default=False) |
69 (options, args) = parser.parse_args() | 132 (options, args) = parser.parse_args() |
70 | 133 |
134 | |
71 ### configuration | 135 ### configuration |
72 user_conf = os.path.join(home(), '.silvermirror') | 136 user_conf = os.path.join(home(), '.silvermirror') |
73 if options.config: | 137 if options.config: |
74 assert os.path.exists(options.config) | 138 assert os.path.exists(options.config) |
75 conf = read_config(options.config) | 139 conf = read_config(options.config) |
82 conf = make_config(user_conf) | 146 conf = make_config(user_conf) |
83 | 147 |
84 # XXX needed for now | 148 # XXX needed for now |
85 assert conf['main']['basedir'] == home() | 149 assert conf['main']['basedir'] == home() |
86 | 150 |
87 ### determine hosts to sync with | 151 # fix up configuration from command line options |
88 hosts = set(options.hosts or conf['main']['hosts']) | 152 conf['hosts'] = set(options.hosts or conf['main']['hosts']) |
89 addresses = ip_addresses().values() | 153 conf['main']['password'] = options.password and conf['main']['password'] |
90 hosts = hosts.difference(addresses) # don't sync with self | |
91 _hosts = [] | |
92 for host in hosts: | |
93 s = socket.socket() | |
94 s.settimeout(conf['main']['timeout']) | |
95 if options.test: | |
96 print 'Resolving %s' % host | |
97 try: | |
98 s.connect((host, 22)) | |
99 s.close() | |
100 except (socket.gaierror, socket.timeout, socket.error): | |
101 continue | |
102 _hosts.append(host) | |
103 hosts = _hosts | |
104 if options.test: | |
105 print 'Hosts:' | |
106 for host in hosts: | |
107 print host | |
108 assert hosts | |
109 | 154 |
110 if options.password and conf['main']['password']: | 155 unify(conf, args, options.test) |
111 for host in hosts: | |
112 pw[host] = getpass.getpass('Enter password for %s: ' % host) | |
113 # TODO: ensure that the hosts are resolvable | |
114 # XXX: hosts should actually be manageable on a per-resource basis | |
115 | |
116 ### determine resources to sync | |
117 cwd = os.path.realpath(os.getcwd()) | |
118 resources = conf['resources'] | |
119 _resources = args | |
120 if 'all' not in _resources: | |
121 if _resources: | |
122 resources = dict([(key, value) for key, value in resources.items() | |
123 if key in _resources]) | |
124 else: | |
125 for key, value in resources.items(): | |
126 directory = os.path.realpath(value['directory']) + os.sep | |
127 if (cwd + os.sep).startswith(directory): | |
128 resources = { key: value } | |
129 break | |
130 if options.test: | |
131 print 'Resources:' | |
132 pprint(resources) | |
133 | |
134 ### sync with hosts | |
135 os.chdir(conf['main']['basedir']) | |
136 for resource in resources: | |
137 for host in hosts: | |
138 command = ['unison', '-auto', '-batch', resource, 'ssh://%s/%s' % (host, resource)] | |
139 | |
140 # XXX - to refactor? | |
141 for i in resources[resource]['ignore']: | |
142 command.extend(('-ignore', "'Name %s'" % i)) | |
143 | |
144 command = ' '.join(command) | |
145 print command # XXX debug | |
146 if not options.test: | |
147 child = pexpect.spawn(command, timeout=36000, maxread=1) | |
148 child.expect('password: ') | |
149 child.sendline(pw[host]) | |
150 print child.read() | |
151 # subprocess.call(command) | |
152 os.chdir(cwd) | |
153 | 156 |
154 if __name__ == '__main__': | 157 if __name__ == '__main__': |
155 unify() | 158 unify() |