Merge lp:~cmiller/desktopcouch/couchdb-polutes-its-ini into lp:desktopcouch

Proposed by Chad Miller
Status: Merged
Approved by: Chad Miller
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~cmiller/desktopcouch/couchdb-polutes-its-ini
Merge into: lp:desktopcouch
Diff against target: 279 lines (+69/-58)
8 files modified
bin/desktopcouch-service (+8/-3)
bin/desktopcouch-stop (+3/-15)
data/couchdb.tmpl (+2/-2)
desktopcouch/local_files.py (+22/-1)
desktopcouch/records/server_base.py (+7/-1)
desktopcouch/start_local_couchdb.py (+9/-6)
desktopcouch/stop_local_couchdb.py (+17/-28)
desktopcouch/tests/__init__.py (+1/-2)
To merge this branch: bzr merge lp:~cmiller/desktopcouch/couchdb-polutes-its-ini
Reviewer Review Type Date Requested Status
John O'Brien (community) Approve
Stuart Langridge (community) Approve
Review via email: mp+18645@code.launchpad.net

Commit message

The couchdb INI file may be updatec by couchdb to have a hashed password value, so we can not blindly take that to update the bookmark file any more. Now, store the username and password (yes in the INI also, but) in the bookmark file using a parsable format. Now, we can poke the value in initially, and later read the bookmark file to update the bookmark file.

To post a comment you must log in.
Revision history for this message
Stuart Langridge (sil) wrote :

Excellent.

review: Approve
Revision history for this message
John O'Brien (jdobrien) :
review: Approve
Revision history for this message
Chad Miller (cmiller) wrote :

The couchdb INI file may be updatec by couchdb to have a hashed password value, so we can not blindly take that to update the bookmark file any more. Now, store the username and password (yes in the INI also, but) in the bookmark file using a parsable format. Now, we can poke the value in initially, and later read the bookmark file to update the bookmark file.

Revision history for this message
Chad Miller (cmiller) wrote :
Download full text (10.9 KiB)

The attempt to merge lp:~cmiller/desktopcouch/couchdb-polutes-its-ini into lp:desktopcouch failed.Below is the output from the failed tests.

Apache CouchDB has started, time to relax.
Browse your desktop CouchDB at file:///tmp/tmpCA9l0y/data/couchdb.html
desktopcouch.contacts.tests.test_contactspicker
  TestContactsPicker
    test_can_contruct_contactspicker ... [OK]
desktopcouch.contacts.tests.test_create
  TestCreate
    test_create_many_contacts ... [OK]
    test_head_or_tails ... [OK]
    test_random_bools ... [OK]
desktopcouch.contacts.tests.test_record
  TestContactRecord
    test_contact_record ... [OK]
desktopcouch.pair.tests.test_couchdb_io
  TestCouchdbIo
    test_get_database_names_replicatable ... [OK]
    test_get_database_names_replicatable_bad_server ... [OK]
    test_get_my_host_unique_id ... [ERROR]
    test_mkuri ... [OK]
    test_obsfuscation ... [OK]
    test_put_dynamic_paired_host ... [OK]
    test_put_static_paired_service ... [OK]
desktopcouch.pair.tests.test_network_io
  TestNetworkIO
    test_successful_lifespan ... [OK]
desktopcouch.records.tests.test_couchgrid
  TestCouchGrid
    test_all_from_database ... [OK]
    test_constructor_guarded ... [OK]
    test_new_rows_with_headings ... [OK]
    test_no_headings_or_stored_records ... [OK]
    test_optional_args_no_stored_records ... [OK]
    test_optional_record_type_arg ... [OK]
    test_programatically_add_row ... [OK]
    test_selected_id_property ... [OK]
    test_single_col_from_database ... [OK]
desktopcouch.records.tests.test_field_registry
  TestFieldMapping
    test_mergeable_list_field_mapping ... [OK]
    test_mergeable_list_field_mapping_empty_field ... [OK]
    test_simple_field_mapping ... [OK]
  TestTransformer
    test_from_app ... [OK]
    test_run_doctests ... [OK]
    test_to_app ... [OK]
desktopcouch.records.tests.test_record
  TestRecordFactory
    test_build ... [OK]
  TestRecords
    test_application_annotations ... [OK]
    test_delitem ... ...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'bin/desktopcouch-service'
--- bin/desktopcouch-service 2009-10-14 14:48:25 +0000
+++ bin/desktopcouch-service 2010-02-05 00:09:13 +0000
@@ -46,6 +46,7 @@
46import desktopcouch46import desktopcouch
47from desktopcouch import local_files47from desktopcouch import local_files
48from desktopcouch import replication48from desktopcouch import replication
49from desktopcouch.stop_local_couchdb import stop_couchdb
4950
5051
51class PortAdvertiser(dbus.service.Object):52class PortAdvertiser(dbus.service.Object):
@@ -104,7 +105,11 @@
104 mainloop.run()105 mainloop.run()
105106
106 finally:107 finally:
107 if replication_runtime:108 try:
108 print "Shutting down, but may be a moment to finish replication."109 print "Shutting down...",
109 replication.tear_down(*replication_runtime)110 if replication_runtime:
111 replication.tear_down(*replication_runtime)
112 finally:
113 stop_couchdb()
114 print "done."
110115
111116
=== modified file 'bin/desktopcouch-stop'
--- bin/desktopcouch-stop 2009-07-24 19:32:52 +0000
+++ bin/desktopcouch-stop 2010-02-05 00:09:13 +0000
@@ -19,18 +19,6 @@
19"""19"""
20Stop local CouchDB server.20Stop local CouchDB server.
21"""21"""
22import subprocess, sys22
23from desktopcouch import local_files23from desktopcouch.stop_local_couchdb import stop_couchdb
2424stop_couchdb()
25local_exec = local_files.COUCH_EXEC_COMMAND + ["-k"]
26try:
27 retcode = subprocess.call(local_exec, shell=False)
28 if retcode < 0:
29 print >> sys.stderr, "Child was terminated by signal", -retcode
30 elif retcode > 0:
31 print >> sys.stderr, "Child returned", retcode
32except OSError, e:
33 print >> sys.stderr, "Execution failed: %s: %s" % (e, local_exec)
34 exit(1)
35
36
3725
=== modified file 'data/couchdb.tmpl'
--- data/couchdb.tmpl 2009-08-20 12:55:54 +0000
+++ data/couchdb.tmpl 2010-02-05 00:09:13 +0000
@@ -26,7 +26,7 @@
26<h1>Desktop CouchDB</h1>26<h1>Desktop CouchDB</h1>
27<p>Your desktop CouchDB is the data store for many of your applications.27<p>Your desktop CouchDB is the data store for many of your applications.
28You can browse around it to see which data your applications are storing.</p>28You can browse around it to see which data your applications are storing.</p>
29<p>You should bookmark this page (by going to <strong>Bookmarks > Bookmark29<p>You should bookmark this page (by going to <strong>Bookmarks &gt; Bookmark
30This Page</strong> or pressing <strong>Ctrl-D</strong>) so you can easily30This Page</strong> or pressing <strong>Ctrl-D</strong>) so you can easily
31come back to browse your CouchDB again.</p>31come back to browse your CouchDB again.</p>
32<p>Don't bookmark the CouchDB page itself, because its location may change!</p>32<p>Don't bookmark the CouchDB page itself, because its location may change!</p>
@@ -35,4 +35,4 @@
35there straight away from now on</a> (remember to bookmark this page first!)</p>35there straight away from now on</a> (remember to bookmark this page first!)</p>
36</body>36</body>
37</html>37</html>
3838<!-- !![[COUCHDB_USERNAME]]!![[COUCHDB_PASSWORD]]!! -->
3939
=== modified file 'desktopcouch/local_files.py'
--- desktopcouch/local_files.py 2009-12-14 14:52:48 +0000
+++ desktopcouch/local_files.py 2010-02-05 00:09:13 +0000
@@ -29,6 +29,7 @@
29import tempfile29import tempfile
30import random30import random
31import string31import string
32import re
32import gnomekeyring33import gnomekeyring
33try:34try:
34 import ConfigParser as configparser35 import ConfigParser as configparser
@@ -53,10 +54,16 @@
53 # monkeypatch ConfigParser to stop it lower-casing option names54 # monkeypatch ConfigParser to stop it lower-casing option names
54 self._c.optionxform = lambda s: s55 self._c.optionxform = lambda s: s
5556
57 bookmark_file = os.path.join(ctx.db_dir, "couchdb.html")
56 try:58 try:
59 bookmark_file_contents = open(bookmark_file).read()
60 if "-hashed-" in bookmark_file_contents:
61 raise ValueError("Basic-auth cred lost.")
62 u, p = re.findall("<!-- !!([^!]+)!!([^!]+)!! -->",
63 bookmark_file_contents)[-1] # trial run, check sanity.
57 self._fill_from_file(self.file_name_used)64 self._fill_from_file(self.file_name_used)
58 return65 return
59 except (IOError,):66 except (IOError, ValueError, IndexError):
60 pass # Loading failed. Let's fill it with sensible defaults.67 pass # Loading failed. Let's fill it with sensible defaults.
6168
62 try:69 try:
@@ -123,6 +130,20 @@
123 self._fill_from_structure(local)130 self._fill_from_structure(local)
124 self.save_to_file(self.file_name_used)131 self.save_to_file(self.file_name_used)
125132
133 fp = open(bookmark_file, "w")
134 try:
135 fp.write("Desktopcouch is not yet started.\n")
136 fp.write("<!-- Couch clobbers useful creds in INI file. -->\n")
137 fp.write("<!-- So, store creds in the place we need it. -->\n")
138 fp.write("<!-- The '!' fmt is perpetual but port varies. -->\n")
139 fp.write("<!-- !!%(admin_username)s!!%(admin_password)s!! -->\n" \
140 % locals())
141 fp.write("<!-- ^^ Seeded only creds into bookmark file. -->\n")
142 fp.write("<!-- Will flesh out with port when we know it. -->\n")
143 fp.write("<!-- Replacement text also uses creds format. -->\n")
144 finally:
145 fp.close()
146
126 # randomly generate tokens and usernames147 # randomly generate tokens and usernames
127 @staticmethod148 @staticmethod
128 def _make_random_string(count):149 def _make_random_string(count):
129150
=== modified file 'desktopcouch/records/server_base.py'
--- desktopcouch/records/server_base.py 2010-01-29 22:14:25 +0000
+++ desktopcouch/records/server_base.py 2010-02-05 00:09:13 +0000
@@ -153,8 +153,12 @@
153 self.record_factory = record_factory or Record153 self.record_factory = record_factory or Record
154 self._changes_since = 0154 self._changes_since = 0
155 self._changes_last_used = 0155 self._changes_last_used = 0
156 self.report_changes(lambda **_: None) # Update _changes_since.156 try:
157 self.report_changes(lambda **_: None) # Update _changes_since.
158 except IOError:
159 pass
157 self._changes_last_used = 0 # Immediate run works.160 self._changes_last_used = 0 # Immediate run works.
161
158162
159 def _temporary_query(self, map_fun, reduce_fun=None, language='javascript',163 def _temporary_query(self, map_fun, reduce_fun=None, language='javascript',
160 wrapper=None, **options):164 wrapper=None, **options):
@@ -489,6 +493,8 @@
489 uri = couchdburi(self._server.resource.uri, self.db.name, "_changes",493 uri = couchdburi(self._server.resource.uri, self.db.name, "_changes",
490 since=self._changes_since)494 since=self._changes_since)
491 resp, data = self._server.resource.http.request(uri, "GET", "", {})495 resp, data = self._server.resource.http.request(uri, "GET", "", {})
496 if resp["status"] != '200':
497 raise IOError("HTTP response code %s.\n%s" % (resp["status"], data))
492 structure = json.loads(data)498 structure = json.loads(data)
493 for change in structure.get("results"):499 for change in structure.get("results"):
494 # kw-args can't have unicode keys500 # kw-args can't have unicode keys
495501
=== modified file 'desktopcouch/start_local_couchdb.py'
--- desktopcouch/start_local_couchdb.py 2009-12-16 14:21:09 +0000
+++ desktopcouch/start_local_couchdb.py 2010-02-05 00:09:13 +0000
@@ -42,6 +42,7 @@
42from desktopcouch.records.server import CouchDatabase42from desktopcouch.records.server import CouchDatabase
43import logging43import logging
44import itertools44import itertools
45import re
4546
4647
47def process_is_couchdb__linux(pid):48def process_is_couchdb__linux(pid):
@@ -187,10 +188,15 @@
187 # than inefficiently just overwriting it regardless188 # than inefficiently just overwriting it regardless
188 db.add_view(view_name, mapjs, reducejs, dd_name)189 db.add_view(view_name, mapjs, reducejs, dd_name)
189190
190def write_bookmark_file(username, password, port, ctx=local_files.DEFAULT_CONTEXT):191def update_bookmark_file(port, ctx=local_files.DEFAULT_CONTEXT):
191 """Write out an HTML document that the user can bookmark to find their DB"""192 """Write out an HTML document that the user can bookmark to find their DB"""
192 bookmark_file = os.path.join(ctx.db_dir, "couchdb.html")193 bookmark_file = os.path.join(ctx.db_dir, "couchdb.html")
193194
195 try:
196 username, password = re.findall("<!-- !!([^!]+)!!([^!]+)!! -->", open(bookmark_file).read())[-1]
197 except ValueError:
198 raise IOError("Bookmark file is corrupt. Username/password are missing.")
199
194 if os.path.exists(200 if os.path.exists(
195 os.path.join(os.path.split(__file__)[0], "../data/couchdb.tmpl")):201 os.path.join(os.path.split(__file__)[0], "../data/couchdb.tmpl")):
196 bookmark_template = os.path.join(202 bookmark_template = os.path.join(
@@ -208,9 +214,7 @@
208214
209 fp = open(bookmark_file, "w")215 fp = open(bookmark_file, "w")
210 try:216 try:
211 if port is None:217 if port is not None:
212 fp.write("<html><body><p>Sorry, desktop couchdb does is not running.</body></html>\n")
213 else:
214 out = html.replace("[[COUCHDB_PORT]]", str(port))218 out = html.replace("[[COUCHDB_PORT]]", str(port))
215 out = out.replace("[[COUCHDB_USERNAME]]", username)219 out = out.replace("[[COUCHDB_USERNAME]]", username)
216 out = out.replace("[[COUCHDB_PASSWORD]]", password)220 out = out.replace("[[COUCHDB_PASSWORD]]", password)
@@ -222,14 +226,13 @@
222226
223def start_couchdb(ctx=local_files.DEFAULT_CONTEXT):227def start_couchdb(ctx=local_files.DEFAULT_CONTEXT):
224 """Execute each step to start a desktop CouchDB."""228 """Execute each step to start a desktop CouchDB."""
225 username, password = local_files.get_admin_credentials(ctx=ctx)
226 pid, port = run_couchdb(ctx=ctx)229 pid, port = run_couchdb(ctx=ctx)
227 # Note that we do not call update_design_documents here. This is because230 # Note that we do not call update_design_documents here. This is because
228 # Couch won't actually have started yet, so when update_design_documents231 # Couch won't actually have started yet, so when update_design_documents
229 # calls the Records API, that will call back into get_port and we end up232 # calls the Records API, that will call back into get_port and we end up
230 # starting Couch again. Instead, get_port calls update_design_documents233 # starting Couch again. Instead, get_port calls update_design_documents
231 # *after* Couch startup has occurred.234 # *after* Couch startup has occurred.
232 write_bookmark_file(username, password, port, ctx=ctx)235 update_bookmark_file(port, ctx=ctx)
233 return pid236 return pid
234237
235238
236239
=== modified file 'desktopcouch/stop_local_couchdb.py'
--- desktopcouch/stop_local_couchdb.py 2009-11-24 14:55:27 +0000
+++ desktopcouch/stop_local_couchdb.py 2010-02-05 00:09:13 +0000
@@ -15,38 +15,27 @@
15# along with desktopcouch. If not, see <http://www.gnu.org/licenses/>.15# along with desktopcouch. If not, see <http://www.gnu.org/licenses/>.
16#16#
17# Author: Chad Miller <chad.miller@canonical.com>17# Author: Chad Miller <chad.miller@canonical.com>
18# Stuart Langridge <stuart.langridge@canonical.com>
19
18"""20"""
19Stop local CouchDB server.21Stop local CouchDB server.
20"""22"""
2123
22import os24import subprocess, sys
23import desktopcouch25from desktopcouch import local_files
24import time26
25import signal27def stop_couchdb(ctx=local_files.DEFAULT_CONTEXT):
26import errno28 local_exec = ctx.couch_exec_command + ["-k"]
2729 try:
28def stop_couchdb(pid=None):30 retcode = subprocess.call(local_exec, shell=False)
29 by_pid = pid31 if retcode < 0:
30 if pid is None:32 print >> sys.stderr, "Child was terminated by signal", -retcode
31 pid = desktopcouch.find_pid(start_if_not_running=False)33 elif retcode > 0:
32 while pid is not None:34 print >> sys.stderr, "Child returned", retcode
33 try:35 except OSError, e:
34 os.kill(pid, signal.SIGTERM)36 print >> sys.stderr, "Execution failed: %s: %s" % (e, local_exec)
35 except OSError, e:37 exit(1)
36 if e.errno == errno.ESRCH:38
37 break
38 raise
39
40 for retry in xrange(300):
41 try:
42 os.kill(pid, 0) # test existence. sig-zero is special.
43 except OSError:
44 break
45 time.sleep(0.01)
46 if by_pid:
47 pid = None
48 else:
49 pid = desktopcouch.find_pid(start_if_not_running=False)
5039
51if __name__ == "__main__":40if __name__ == "__main__":
52 stop_couchdb()41 stop_couchdb()
5342
=== modified file 'desktopcouch/tests/__init__.py'
--- desktopcouch/tests/__init__.py 2009-11-11 16:24:22 +0000
+++ desktopcouch/tests/__init__.py 2010-02-05 00:09:13 +0000
@@ -29,8 +29,7 @@
29 os.environ["XDG_CONFIG_DIRS"] = SOURCE_TREE_ETC_FOLDER29 os.environ["XDG_CONFIG_DIRS"] = SOURCE_TREE_ETC_FOLDER
3030
31 def stop_test_couch(temp_dir, ctx):31 def stop_test_couch(temp_dir, ctx):
32 pid = read_pidfile(ctx)32 stop_couchdb(ctx)
33 stop_couchdb(pid=pid)
34 shutil.rmtree(temp_dir)33 shutil.rmtree(temp_dir)
3534
36 start_couchdb(ctx=new_context)35 start_couchdb(ctx=new_context)

Subscribers

People subscribed via source and target branches