Merge lp:~cmiller/desktopcouch/replication-to-u1 into lp:desktopcouch

Proposed by Chad Miller
Status: Merged
Approved by: Chad Miller
Approved revision: 79
Merged at revision: not available
Proposed branch: lp:~cmiller/desktopcouch/replication-to-u1
Merge into: lp:desktopcouch
Diff against target: 253 lines
8 files modified
bin/desktopcouch-service (+1/-1)
desktopcouch/pair/couchdb_pairing/couchdb_io.py (+23/-14)
desktopcouch/records/server.py (+5/-4)
desktopcouch/records/server_base.py (+5/-2)
desktopcouch/replication.py (+1/-4)
desktopcouch/replication_services/example.py (+1/-7)
desktopcouch/replication_services/ubuntuone.py (+8/-11)
setup.py (+1/-1)
To merge this branch: bzr merge lp:~cmiller/desktopcouch/replication-to-u1
Reviewer Review Type Date Requested Status
Ubuntu One hackers Pending
Review via email: mp+12527@code.launchpad.net

Commit message

Use U1 credentials when connecting to U1 for creating databases to replicate into. Remove extraneous function for couchdb service locations.

To post a comment you must log in.
75. By Chad Miller

Switch back to HMAC, from debugging PLAINTEXT, for OAuth.

76. By Chad Miller

Log to correct place.

77. By Chad Miller

Always try to replicate. Destroy the semantic of not having a self-identity
record meaning no replication; now, always create a self-identity record in
the service.

78. By Chad Miller

Restructure replicate function so we try replicate even if we can't verify that
the database exists.

Remove bogus put of test record!

79. By Chad Miller

Use OAuthCapableServer to connect to local, for replication action unsupported
in python couchdb module.

Revision history for this message
Chad Miller (cmiller) wrote :

Reviewed by Stuart and me on phone.

80. By Chad Miller

Bumped version number for release.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'bin/desktopcouch-pair'
=== modified file 'bin/desktopcouch-service'
--- bin/desktopcouch-service 2009-09-11 03:18:00 +0000
+++ bin/desktopcouch-service 2009-09-28 18:39:12 +0000
@@ -72,7 +72,7 @@
72 import xdg.BaseDirectory72 import xdg.BaseDirectory
7373
74 log_directory = os.path.join(xdg.BaseDirectory.xdg_cache_home,74 log_directory = os.path.join(xdg.BaseDirectory.xdg_cache_home,
75 "ubuntuone/log")75 "desktop-couch/log")
76 try:76 try:
77 os.makedirs(log_directory)77 os.makedirs(log_directory)
78 except:78 except:
7979
=== modified file 'desktopcouch/pair/couchdb_pairing/couchdb_io.py'
--- desktopcouch/pair/couchdb_pairing/couchdb_io.py 2009-09-26 11:49:49 +0000
+++ desktopcouch/pair/couchdb_pairing/couchdb_io.py 2009-09-28 18:39:12 +0000
@@ -180,10 +180,12 @@
180 logging.debug("found %d %s records", len(values), key)180 logging.debug("found %d %s records", len(values), key)
181 return values181 return values
182182
183def create_database(dst_host, dst_port, dst_name):183def create_database(dst_host, dst_port, dst_name, use_ssl=False,
184 oauth_tokens=None):
184 """Given parts, create a database."""185 """Given parts, create a database."""
185 dst_url = mkuri(dst_host, dst_port)186 dst_url = mkuri(dst_host, dst_port, use_ssl)
186 return server.CouchDatabase(dst_name, dst_url, create=True)187 return server.CouchDatabase(dst_name, dst_url, create=True,
188 oauth_tokens=oauth_tokens)
187189
188def replicate(source_database, target_database, target_host=None,190def replicate(source_database, target_database, target_host=None,
189 target_port=None, source_host=None, source_port=None,191 target_port=None, source_host=None, source_port=None,
@@ -211,27 +213,34 @@
211213
212 record = dict(source=source, target=target)214 record = dict(source=source, target=target)
213 try:215 try:
214 # regardless of source and target, we talk to our local couchdb :(
215 url = None # so logging works in exception handler
216 port = int(desktopcouch_find_port())
217 # TODO: Get admin username and password from keyring. Populate URL.
218 url = mkuri("localhost", port,)
219216
220 if target_host:217 if target_host:
221 # Target databases must exist before replicating to them.218 # Target databases must exist before replicating to them.
222 logging.debug("creating %r %s:%d", target_database, target_host,219 logging.debug("creating %r %s:%d", target_database, target_host,
223 target_port)220 target_port)
224 create_database(target_host, target_port, target_database)221 create_database(target_host, target_port, target_database,
222 target_ssl, target_oauth)
223 except:
224 logging.exception("can't talk to couchdb. %r %s:%d oauth=%s",
225 target_database, target_host, target_port, target_oauth)
226
227 logging.debug("db exists, and we're ready to replicate")
228 try:
229 # regardless of source and target, we talk to our local couchdb :(
230 port = int(desktopcouch_find_port())
231 url = mkuri("localhost", port,)
232
233 logging.debug("asking %r to send %s to %s", url, source, target)
225234
226 ### All until python-couchdb gets a Server.replicate() function235 ### All until python-couchdb gets a Server.replicate() function
227 import couchdb236 local_server = server.OAuthCapableServer(url)
228 logging.debug("asking %r to send %s to %s", url, source, target)237 resp, data = local_server.resource.post(path='/_replicate', content=record)
229 server = couchdb.client.Server(url)238
230 resp, data = server.resource.post(path='/_replicate', content=record)
231 logging.debug("replicate result: %r %r", resp, data)239 logging.debug("replicate result: %r %r", resp, data)
232 ###240 ###
233 except:241 except:
234 logging.exception("can't talk to couchdb. %r <== %r", url, record)242 logging.error("can't talk to couchdb. %r <== %r", url, record)
243 raise
235244
236def get_pairings(uri=None):245def get_pairings(uri=None):
237 """Get a list of paired servers."""246 """Get a list of paired servers."""
238247
=== modified file 'desktopcouch/records/server.py'
--- desktopcouch/records/server.py 2009-09-14 20:18:53 +0000
+++ desktopcouch/records/server.py 2009-09-28 18:39:12 +0000
@@ -26,12 +26,13 @@
26from desktopcouch.records import server_base26from desktopcouch.records import server_base
2727
28class OAuthCapableServer(Server):28class OAuthCapableServer(Server):
29 def __init__(self, uri):29 def __init__(self, uri, oauth_tokens=None):
30 """Subclass of couchdb.client.Server which creates a custom30 """Subclass of couchdb.client.Server which creates a custom
31 httplib2.Http subclass which understands OAuth"""31 httplib2.Http subclass which understands OAuth"""
32 http = server_base.OAuthCapableHttp()32 http = server_base.OAuthCapableHttp()
33 http.force_exception_to_status_code = False33 http.force_exception_to_status_code = False
34 oauth_tokens = desktopcouch.local_files.get_oauth_tokens()34 if oauth_tokens is None:
35 oauth_tokens = desktopcouch.local_files.get_oauth_tokens()
35 (consumer_key, consumer_secret, token, token_secret) = (36 (consumer_key, consumer_secret, token, token_secret) = (
36 oauth_tokens["consumer_key"], oauth_tokens["consumer_secret"], 37 oauth_tokens["consumer_key"], oauth_tokens["consumer_secret"],
37 oauth_tokens["token"], oauth_tokens["token_secret"])38 oauth_tokens["token"], oauth_tokens["token_secret"])
@@ -42,11 +43,11 @@
42 """An small records specific abstraction over a couch db database."""43 """An small records specific abstraction over a couch db database."""
43 44
44 def __init__(self, database, uri=None, record_factory=None, create=False,45 def __init__(self, database, uri=None, record_factory=None, create=False,
45 server_class=OAuthCapableServer):46 server_class=OAuthCapableServer, oauth_tokens=None):
46 if not uri:47 if not uri:
47 desktopcouch.find_pid()48 desktopcouch.find_pid()
48 port = desktopcouch.find_port()49 port = desktopcouch.find_port()
49 uri = "http://localhost:%s" % port50 uri = "http://localhost:%s" % port
50 super(CouchDatabase, self).__init__(51 super(CouchDatabase, self).__init__(
51 database, uri, record_factory=record_factory, create=create,52 database, uri, record_factory=record_factory, create=create,
52 server_class=server_class)53 server_class=server_class, oauth_tokens=oauth_tokens)
5354
=== modified file 'desktopcouch/records/server_base.py'
--- desktopcouch/records/server_base.py 2009-09-14 20:22:03 +0000
+++ desktopcouch/records/server_base.py 2009-09-28 18:39:12 +0000
@@ -29,6 +29,7 @@
29from oauth import oauth29from oauth import oauth
30import urlparse30import urlparse
31import cgi31import cgi
32import logging
3233
33#DEFAULT_DESIGN_DOCUMENT = "design"34#DEFAULT_DESIGN_DOCUMENT = "design"
34DEFAULT_DESIGN_DOCUMENT = None # each view in its own eponymous design doc.35DEFAULT_DESIGN_DOCUMENT = None # each view in its own eponymous design doc.
@@ -72,6 +73,8 @@
72 )73 )
73 req.sign_request(oauth.OAuthSignatureMethod_HMAC_SHA1(), consumer, access_token)74 req.sign_request(oauth.OAuthSignatureMethod_HMAC_SHA1(), consumer, access_token)
74 headers.update(httplib2._normalize_headers(req.to_header()))75 headers.update(httplib2._normalize_headers(req.to_header()))
76 for header in headers.iteritems():
77 logging.debug("header %s", header)
7578
76class OAuthCapableHttp(httplib2.Http):79class OAuthCapableHttp(httplib2.Http):
77 """Subclass of httplib2.Http which specifically uses our OAuth 80 """Subclass of httplib2.Http which specifically uses our OAuth
@@ -107,9 +110,9 @@
107 """An small records specific abstraction over a couch db database."""110 """An small records specific abstraction over a couch db database."""
108111
109 def __init__(self, database, uri, record_factory=None, create=False,112 def __init__(self, database, uri, record_factory=None, create=False,
110 server_class=Server):113 server_class=Server, **server_class_extras):
111 self.server_uri = uri114 self.server_uri = uri
112 self._server = server_class(self.server_uri)115 self._server = server_class(self.server_uri, **server_class_extras)
113 if database not in self._server:116 if database not in self._server:
114 if create:117 if create:
115 self._server.create(database)118 self._server.create(database)
116119
=== modified file 'desktopcouch/replication.py'
--- desktopcouch/replication.py 2009-09-16 17:03:02 +0000
+++ desktopcouch/replication.py 2009-09-28 18:39:12 +0000
@@ -205,10 +205,7 @@
205def set_up(port_getter):205def set_up(port_getter):
206 port = port_getter()206 port = port_getter()
207 unique_identifiers = couchdb_io.get_my_host_unique_id(207 unique_identifiers = couchdb_io.get_my_host_unique_id(
208 couchdb_io.mkuri("localhost", int(port)), create=False)208 couchdb_io.mkuri("localhost", int(port)), create=True)
209 if unique_identifiers is None:
210 log.warn("No unique hostaccount id is set, so pairing not enabled.")
211 return None
212209
213 beacons = [dbus_io.LocationAdvertisement(port, "desktopcouch " + i)210 beacons = [dbus_io.LocationAdvertisement(port, "desktopcouch " + i)
214 for i in unique_identifiers]211 for i in unique_identifiers]
215212
=== modified file 'desktopcouch/replication_services/example.py'
--- desktopcouch/replication_services/example.py 2009-09-04 22:25:44 +0000
+++ desktopcouch/replication_services/example.py 2009-09-28 18:39:12 +0000
@@ -19,14 +19,8 @@
19 # or to symbolize failure19 # or to symbolize failure
20 return None20 return None
2121
22# Required
23def couchdb_location():
24 """Give a tuple of hostname and port number."""
25
26 return "couchdb.example.com", 5984
27
28# Access to this as a string fires off functions.22# Access to this as a string fires off functions.
29# Required23# Required
30db_name_prefix = "foo"24db_name_prefix = "http://host.required.example.com/a_prefix_if_necessary"
31# You can be sure that access to this will always, always be through its25# You can be sure that access to this will always, always be through its
32# __str__ method.26# __str__ method.
3327
=== modified file 'desktopcouch/replication_services/ubuntuone.py'
--- desktopcouch/replication_services/ubuntuone.py 2009-09-17 09:58:35 +0000
+++ desktopcouch/replication_services/ubuntuone.py 2009-09-28 18:39:12 +0000
@@ -8,6 +8,9 @@
8name = "Ubuntu One"8name = "Ubuntu One"
9description = "The Ubuntu One cloud service"9description = "The Ubuntu One cloud service"
1010
11oauth_consumer_key = "ubuntuone"
12oauth_consumer_secret = "hammertime"
13
11def is_active():14def is_active():
12 """Can we deliver information?"""15 """Can we deliver information?"""
13 return get_oauth_data() is not None16 return get_oauth_data() is not None
@@ -24,7 +27,7 @@
24 matches = gnomekeyring.find_items_sync(27 matches = gnomekeyring.find_items_sync(
25 gnomekeyring.ITEM_GENERIC_SECRET,28 gnomekeyring.ITEM_GENERIC_SECRET,
26 {'ubuntuone-realm': "https://ubuntuone.com",29 {'ubuntuone-realm': "https://ubuntuone.com",
27 'oauth-consumer-key': "ubuntuone"})30 'oauth-consumer-key': oauth_consumer_key})
28 if matches:31 if matches:
29 # parse "a=b&c=d" to {"a":"b","c":"d"}32 # parse "a=b&c=d" to {"a":"b","c":"d"}
30 kv_list = [x.split("=", 1) for x in matches[0].secret.split("&")]33 kv_list = [x.split("=", 1) for x in matches[0].secret.split("&")]
@@ -32,8 +35,8 @@
32 keys = [k.replace("oauth_", "") for k in keys]35 keys = [k.replace("oauth_", "") for k in keys]
33 oauth_data = dict(zip(keys, values))36 oauth_data = dict(zip(keys, values))
34 oauth_data.update({37 oauth_data.update({
35 "consumer_key": "ubuntuone",38 "consumer_key": oauth_consumer_key,
36 "consumer_secret": "",39 "consumer_secret": oauth_consumer_secret,
37 })40 })
38 return oauth_data41 return oauth_data
39 except ImportError, e:42 except ImportError, e:
@@ -47,13 +50,6 @@
47 logging.error("No keyring daemon found in this session, so we have "50 logging.error("No keyring daemon found in this session, so we have "
48 "no access to Ubuntu One data.")51 "no access to Ubuntu One data.")
4952
50def couchdb_location():
51 """This can vary more often than the OAuth information. Support SRV
52 records and whatnot."""
53
54 # ...eventually. For now, hard-coded. Maybe YAGNI.
55 return "couchdb.one.ubuntu.com", 5984
56
57def get_oauth_token(consumer):53def get_oauth_token(consumer):
58 """Get the token from the keyring"""54 """Get the token from the keyring"""
59 import gobject55 import gobject
@@ -96,7 +92,8 @@
9692
97 url = "https://one.ubuntu.com/api/account/"93 url = "https://one.ubuntu.com/api/account/"
98 if self.oauth_header is None:94 if self.oauth_header is None:
99 consumer = oauth.OAuthConsumer("ubuntuone", "hammertime")95 consumer = oauth.OAuthConsumer(oauth_consumer_key,
96 oauth_consumer_secret)
100 try:97 try:
101 access_token = get_oauth_token(consumer)98 access_token = get_oauth_token(consumer)
102 except gnomekeyring.NoKeyringDaemonError:99 except gnomekeyring.NoKeyringDaemonError:
103100
=== modified file 'setup.py'
--- setup.py 2009-09-14 21:48:36 +0000
+++ setup.py 2009-09-28 18:39:12 +0000
@@ -22,7 +22,7 @@
2222
23setup(23setup(
24 name='desktopcouch',24 name='desktopcouch',
25 version='0.4',25 version='0.4.2',
26 description='A Desktop CouchDB instance.',26 description='A Desktop CouchDB instance.',
27 url='https://launchpad.net/desktopcouch',27 url='https://launchpad.net/desktopcouch',
28 license='LGPL-3',28 license='LGPL-3',

Subscribers

People subscribed via source and target branches