Merge lp:~cmiller/desktopcouch/couchdb-polutes-its-ini into lp:desktopcouch
- couchdb-polutes-its-ini
- Merge into trunk
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 |
Related bugs: |
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.
Description of the change
John O'Brien (jdobrien) : | # |
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.
Chad Miller (cmiller) wrote : | # |
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://
desktopcouch.
TestContactsP
test_
desktopcouch.
TestCreate
test_
test_
test_
desktopcouch.
TestContactRecord
test_
desktopcouch.
TestCouchdbIo
test_
test_
test_
test_mkuri ... [OK]
test_
test_
test_
desktopcouch.
TestNetworkIO
test_
desktopcouch.
TestCouchGrid
test_
test_
test_
test_
test_
test_
test_
test_
test_
desktopcouch.
TestFieldMapping
test_
test_
test_
TestTransformer
test_from_app ... [OK]
test_
test_to_app ... [OK]
desktopcouch.
TestRecordFactory
test_build ... [OK]
TestRecords
test_
test_delitem ... ...
Preview Diff
1 | === modified file 'bin/desktopcouch-service' | |||
2 | --- bin/desktopcouch-service 2009-10-14 14:48:25 +0000 | |||
3 | +++ bin/desktopcouch-service 2010-02-05 00:09:13 +0000 | |||
4 | @@ -46,6 +46,7 @@ | |||
5 | 46 | import desktopcouch | 46 | import desktopcouch |
6 | 47 | from desktopcouch import local_files | 47 | from desktopcouch import local_files |
7 | 48 | from desktopcouch import replication | 48 | from desktopcouch import replication |
8 | 49 | from desktopcouch.stop_local_couchdb import stop_couchdb | ||
9 | 49 | 50 | ||
10 | 50 | 51 | ||
11 | 51 | class PortAdvertiser(dbus.service.Object): | 52 | class PortAdvertiser(dbus.service.Object): |
12 | @@ -104,7 +105,11 @@ | |||
13 | 104 | mainloop.run() | 105 | mainloop.run() |
14 | 105 | 106 | ||
15 | 106 | finally: | 107 | finally: |
19 | 107 | if replication_runtime: | 108 | try: |
20 | 108 | print "Shutting down, but may be a moment to finish replication." | 109 | print "Shutting down...", |
21 | 109 | replication.tear_down(*replication_runtime) | 110 | if replication_runtime: |
22 | 111 | replication.tear_down(*replication_runtime) | ||
23 | 112 | finally: | ||
24 | 113 | stop_couchdb() | ||
25 | 114 | print "done." | ||
26 | 110 | 115 | ||
27 | 111 | 116 | ||
28 | === modified file 'bin/desktopcouch-stop' | |||
29 | --- bin/desktopcouch-stop 2009-07-24 19:32:52 +0000 | |||
30 | +++ bin/desktopcouch-stop 2010-02-05 00:09:13 +0000 | |||
31 | @@ -19,18 +19,6 @@ | |||
32 | 19 | """ | 19 | """ |
33 | 20 | Stop local CouchDB server. | 20 | Stop local CouchDB server. |
34 | 21 | """ | 21 | """ |
50 | 22 | import subprocess, sys | 22 | |
51 | 23 | from desktopcouch import local_files | 23 | from desktopcouch.stop_local_couchdb import stop_couchdb |
52 | 24 | 24 | stop_couchdb() | |
38 | 25 | local_exec = local_files.COUCH_EXEC_COMMAND + ["-k"] | ||
39 | 26 | try: | ||
40 | 27 | retcode = subprocess.call(local_exec, shell=False) | ||
41 | 28 | if retcode < 0: | ||
42 | 29 | print >> sys.stderr, "Child was terminated by signal", -retcode | ||
43 | 30 | elif retcode > 0: | ||
44 | 31 | print >> sys.stderr, "Child returned", retcode | ||
45 | 32 | except OSError, e: | ||
46 | 33 | print >> sys.stderr, "Execution failed: %s: %s" % (e, local_exec) | ||
47 | 34 | exit(1) | ||
48 | 35 | |||
49 | 36 | |||
53 | 37 | 25 | ||
54 | === modified file 'data/couchdb.tmpl' | |||
55 | --- data/couchdb.tmpl 2009-08-20 12:55:54 +0000 | |||
56 | +++ data/couchdb.tmpl 2010-02-05 00:09:13 +0000 | |||
57 | @@ -26,7 +26,7 @@ | |||
58 | 26 | <h1>Desktop CouchDB</h1> | 26 | <h1>Desktop CouchDB</h1> |
59 | 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. |
60 | 28 | You can browse around it to see which data your applications are storing.</p> | 28 | You can browse around it to see which data your applications are storing.</p> |
62 | 29 | <p>You should bookmark this page (by going to <strong>Bookmarks > Bookmark | 29 | <p>You should bookmark this page (by going to <strong>Bookmarks > Bookmark |
63 | 30 | This Page</strong> or pressing <strong>Ctrl-D</strong>) so you can easily | 30 | This Page</strong> or pressing <strong>Ctrl-D</strong>) so you can easily |
64 | 31 | come back to browse your CouchDB again.</p> | 31 | come back to browse your CouchDB again.</p> |
65 | 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> |
66 | @@ -35,4 +35,4 @@ | |||
67 | 35 | there straight away from now on</a> (remember to bookmark this page first!)</p> | 35 | there straight away from now on</a> (remember to bookmark this page first!)</p> |
68 | 36 | </body> | 36 | </body> |
69 | 37 | </html> | 37 | </html> |
71 | 38 | 38 | <!-- !![[COUCHDB_USERNAME]]!![[COUCHDB_PASSWORD]]!! --> | |
72 | 39 | 39 | ||
73 | === modified file 'desktopcouch/local_files.py' | |||
74 | --- desktopcouch/local_files.py 2009-12-14 14:52:48 +0000 | |||
75 | +++ desktopcouch/local_files.py 2010-02-05 00:09:13 +0000 | |||
76 | @@ -29,6 +29,7 @@ | |||
77 | 29 | import tempfile | 29 | import tempfile |
78 | 30 | import random | 30 | import random |
79 | 31 | import string | 31 | import string |
80 | 32 | import re | ||
81 | 32 | import gnomekeyring | 33 | import gnomekeyring |
82 | 33 | try: | 34 | try: |
83 | 34 | import ConfigParser as configparser | 35 | import ConfigParser as configparser |
84 | @@ -53,10 +54,16 @@ | |||
85 | 53 | # monkeypatch ConfigParser to stop it lower-casing option names | 54 | # monkeypatch ConfigParser to stop it lower-casing option names |
86 | 54 | self._c.optionxform = lambda s: s | 55 | self._c.optionxform = lambda s: s |
87 | 55 | 56 | ||
88 | 57 | bookmark_file = os.path.join(ctx.db_dir, "couchdb.html") | ||
89 | 56 | try: | 58 | try: |
90 | 59 | bookmark_file_contents = open(bookmark_file).read() | ||
91 | 60 | if "-hashed-" in bookmark_file_contents: | ||
92 | 61 | raise ValueError("Basic-auth cred lost.") | ||
93 | 62 | u, p = re.findall("<!-- !!([^!]+)!!([^!]+)!! -->", | ||
94 | 63 | bookmark_file_contents)[-1] # trial run, check sanity. | ||
95 | 57 | self._fill_from_file(self.file_name_used) | 64 | self._fill_from_file(self.file_name_used) |
96 | 58 | return | 65 | return |
98 | 59 | except (IOError,): | 66 | except (IOError, ValueError, IndexError): |
99 | 60 | pass # Loading failed. Let's fill it with sensible defaults. | 67 | pass # Loading failed. Let's fill it with sensible defaults. |
100 | 61 | 68 | ||
101 | 62 | try: | 69 | try: |
102 | @@ -123,6 +130,20 @@ | |||
103 | 123 | self._fill_from_structure(local) | 130 | self._fill_from_structure(local) |
104 | 124 | self.save_to_file(self.file_name_used) | 131 | self.save_to_file(self.file_name_used) |
105 | 125 | 132 | ||
106 | 133 | fp = open(bookmark_file, "w") | ||
107 | 134 | try: | ||
108 | 135 | fp.write("Desktopcouch is not yet started.\n") | ||
109 | 136 | fp.write("<!-- Couch clobbers useful creds in INI file. -->\n") | ||
110 | 137 | fp.write("<!-- So, store creds in the place we need it. -->\n") | ||
111 | 138 | fp.write("<!-- The '!' fmt is perpetual but port varies. -->\n") | ||
112 | 139 | fp.write("<!-- !!%(admin_username)s!!%(admin_password)s!! -->\n" \ | ||
113 | 140 | % locals()) | ||
114 | 141 | fp.write("<!-- ^^ Seeded only creds into bookmark file. -->\n") | ||
115 | 142 | fp.write("<!-- Will flesh out with port when we know it. -->\n") | ||
116 | 143 | fp.write("<!-- Replacement text also uses creds format. -->\n") | ||
117 | 144 | finally: | ||
118 | 145 | fp.close() | ||
119 | 146 | |||
120 | 126 | # randomly generate tokens and usernames | 147 | # randomly generate tokens and usernames |
121 | 127 | @staticmethod | 148 | @staticmethod |
122 | 128 | def _make_random_string(count): | 149 | def _make_random_string(count): |
123 | 129 | 150 | ||
124 | === modified file 'desktopcouch/records/server_base.py' | |||
125 | --- desktopcouch/records/server_base.py 2010-01-29 22:14:25 +0000 | |||
126 | +++ desktopcouch/records/server_base.py 2010-02-05 00:09:13 +0000 | |||
127 | @@ -153,8 +153,12 @@ | |||
128 | 153 | self.record_factory = record_factory or Record | 153 | self.record_factory = record_factory or Record |
129 | 154 | self._changes_since = 0 | 154 | self._changes_since = 0 |
130 | 155 | self._changes_last_used = 0 | 155 | self._changes_last_used = 0 |
132 | 156 | self.report_changes(lambda **_: None) # Update _changes_since. | 156 | try: |
133 | 157 | self.report_changes(lambda **_: None) # Update _changes_since. | ||
134 | 158 | except IOError: | ||
135 | 159 | pass | ||
136 | 157 | self._changes_last_used = 0 # Immediate run works. | 160 | self._changes_last_used = 0 # Immediate run works. |
137 | 161 | |||
138 | 158 | 162 | ||
139 | 159 | def _temporary_query(self, map_fun, reduce_fun=None, language='javascript', | 163 | def _temporary_query(self, map_fun, reduce_fun=None, language='javascript', |
140 | 160 | wrapper=None, **options): | 164 | wrapper=None, **options): |
141 | @@ -489,6 +493,8 @@ | |||
142 | 489 | uri = couchdburi(self._server.resource.uri, self.db.name, "_changes", | 493 | uri = couchdburi(self._server.resource.uri, self.db.name, "_changes", |
143 | 490 | since=self._changes_since) | 494 | since=self._changes_since) |
144 | 491 | resp, data = self._server.resource.http.request(uri, "GET", "", {}) | 495 | resp, data = self._server.resource.http.request(uri, "GET", "", {}) |
145 | 496 | if resp["status"] != '200': | ||
146 | 497 | raise IOError("HTTP response code %s.\n%s" % (resp["status"], data)) | ||
147 | 492 | structure = json.loads(data) | 498 | structure = json.loads(data) |
148 | 493 | for change in structure.get("results"): | 499 | for change in structure.get("results"): |
149 | 494 | # kw-args can't have unicode keys | 500 | # kw-args can't have unicode keys |
150 | 495 | 501 | ||
151 | === modified file 'desktopcouch/start_local_couchdb.py' | |||
152 | --- desktopcouch/start_local_couchdb.py 2009-12-16 14:21:09 +0000 | |||
153 | +++ desktopcouch/start_local_couchdb.py 2010-02-05 00:09:13 +0000 | |||
154 | @@ -42,6 +42,7 @@ | |||
155 | 42 | from desktopcouch.records.server import CouchDatabase | 42 | from desktopcouch.records.server import CouchDatabase |
156 | 43 | import logging | 43 | import logging |
157 | 44 | import itertools | 44 | import itertools |
158 | 45 | import re | ||
159 | 45 | 46 | ||
160 | 46 | 47 | ||
161 | 47 | def process_is_couchdb__linux(pid): | 48 | def process_is_couchdb__linux(pid): |
162 | @@ -187,10 +188,15 @@ | |||
163 | 187 | # than inefficiently just overwriting it regardless | 188 | # than inefficiently just overwriting it regardless |
164 | 188 | db.add_view(view_name, mapjs, reducejs, dd_name) | 189 | db.add_view(view_name, mapjs, reducejs, dd_name) |
165 | 189 | 190 | ||
167 | 190 | def write_bookmark_file(username, password, port, ctx=local_files.DEFAULT_CONTEXT): | 191 | def update_bookmark_file(port, ctx=local_files.DEFAULT_CONTEXT): |
168 | 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""" |
169 | 192 | bookmark_file = os.path.join(ctx.db_dir, "couchdb.html") | 193 | bookmark_file = os.path.join(ctx.db_dir, "couchdb.html") |
170 | 193 | 194 | ||
171 | 195 | try: | ||
172 | 196 | username, password = re.findall("<!-- !!([^!]+)!!([^!]+)!! -->", open(bookmark_file).read())[-1] | ||
173 | 197 | except ValueError: | ||
174 | 198 | raise IOError("Bookmark file is corrupt. Username/password are missing.") | ||
175 | 199 | |||
176 | 194 | if os.path.exists( | 200 | if os.path.exists( |
177 | 195 | os.path.join(os.path.split(__file__)[0], "../data/couchdb.tmpl")): | 201 | os.path.join(os.path.split(__file__)[0], "../data/couchdb.tmpl")): |
178 | 196 | bookmark_template = os.path.join( | 202 | bookmark_template = os.path.join( |
179 | @@ -208,9 +214,7 @@ | |||
180 | 208 | 214 | ||
181 | 209 | fp = open(bookmark_file, "w") | 215 | fp = open(bookmark_file, "w") |
182 | 210 | try: | 216 | try: |
186 | 211 | if port is None: | 217 | if port is not None: |
184 | 212 | fp.write("<html><body><p>Sorry, desktop couchdb does is not running.</body></html>\n") | ||
185 | 213 | else: | ||
187 | 214 | out = html.replace("[[COUCHDB_PORT]]", str(port)) | 218 | out = html.replace("[[COUCHDB_PORT]]", str(port)) |
188 | 215 | out = out.replace("[[COUCHDB_USERNAME]]", username) | 219 | out = out.replace("[[COUCHDB_USERNAME]]", username) |
189 | 216 | out = out.replace("[[COUCHDB_PASSWORD]]", password) | 220 | out = out.replace("[[COUCHDB_PASSWORD]]", password) |
190 | @@ -222,14 +226,13 @@ | |||
191 | 222 | 226 | ||
192 | 223 | def start_couchdb(ctx=local_files.DEFAULT_CONTEXT): | 227 | def start_couchdb(ctx=local_files.DEFAULT_CONTEXT): |
193 | 224 | """Execute each step to start a desktop CouchDB.""" | 228 | """Execute each step to start a desktop CouchDB.""" |
194 | 225 | username, password = local_files.get_admin_credentials(ctx=ctx) | ||
195 | 226 | pid, port = run_couchdb(ctx=ctx) | 229 | pid, port = run_couchdb(ctx=ctx) |
196 | 227 | # Note that we do not call update_design_documents here. This is because | 230 | # Note that we do not call update_design_documents here. This is because |
197 | 228 | # Couch won't actually have started yet, so when update_design_documents | 231 | # Couch won't actually have started yet, so when update_design_documents |
198 | 229 | # calls the Records API, that will call back into get_port and we end up | 232 | # calls the Records API, that will call back into get_port and we end up |
199 | 230 | # starting Couch again. Instead, get_port calls update_design_documents | 233 | # starting Couch again. Instead, get_port calls update_design_documents |
200 | 231 | # *after* Couch startup has occurred. | 234 | # *after* Couch startup has occurred. |
202 | 232 | write_bookmark_file(username, password, port, ctx=ctx) | 235 | update_bookmark_file(port, ctx=ctx) |
203 | 233 | return pid | 236 | return pid |
204 | 234 | 237 | ||
205 | 235 | 238 | ||
206 | 236 | 239 | ||
207 | === modified file 'desktopcouch/stop_local_couchdb.py' | |||
208 | --- desktopcouch/stop_local_couchdb.py 2009-11-24 14:55:27 +0000 | |||
209 | +++ desktopcouch/stop_local_couchdb.py 2010-02-05 00:09:13 +0000 | |||
210 | @@ -15,38 +15,27 @@ | |||
211 | 15 | # along with desktopcouch. If not, see <http://www.gnu.org/licenses/>. | 15 | # along with desktopcouch. If not, see <http://www.gnu.org/licenses/>. |
212 | 16 | # | 16 | # |
213 | 17 | # Author: Chad Miller <chad.miller@canonical.com> | 17 | # Author: Chad Miller <chad.miller@canonical.com> |
214 | 18 | # Stuart Langridge <stuart.langridge@canonical.com> | ||
215 | 19 | |||
216 | 18 | """ | 20 | """ |
217 | 19 | Stop local CouchDB server. | 21 | Stop local CouchDB server. |
218 | 20 | """ | 22 | """ |
219 | 21 | 23 | ||
248 | 22 | import os | 24 | import subprocess, sys |
249 | 23 | import desktopcouch | 25 | from desktopcouch import local_files |
250 | 24 | import time | 26 | |
251 | 25 | import signal | 27 | def stop_couchdb(ctx=local_files.DEFAULT_CONTEXT): |
252 | 26 | import errno | 28 | local_exec = ctx.couch_exec_command + ["-k"] |
253 | 27 | 29 | try: | |
254 | 28 | def stop_couchdb(pid=None): | 30 | retcode = subprocess.call(local_exec, shell=False) |
255 | 29 | by_pid = pid | 31 | if retcode < 0: |
256 | 30 | if pid is None: | 32 | print >> sys.stderr, "Child was terminated by signal", -retcode |
257 | 31 | pid = desktopcouch.find_pid(start_if_not_running=False) | 33 | elif retcode > 0: |
258 | 32 | while pid is not None: | 34 | print >> sys.stderr, "Child returned", retcode |
259 | 33 | try: | 35 | except OSError, e: |
260 | 34 | os.kill(pid, signal.SIGTERM) | 36 | print >> sys.stderr, "Execution failed: %s: %s" % (e, local_exec) |
261 | 35 | except OSError, e: | 37 | exit(1) |
262 | 36 | if e.errno == errno.ESRCH: | 38 | |
235 | 37 | break | ||
236 | 38 | raise | ||
237 | 39 | |||
238 | 40 | for retry in xrange(300): | ||
239 | 41 | try: | ||
240 | 42 | os.kill(pid, 0) # test existence. sig-zero is special. | ||
241 | 43 | except OSError: | ||
242 | 44 | break | ||
243 | 45 | time.sleep(0.01) | ||
244 | 46 | if by_pid: | ||
245 | 47 | pid = None | ||
246 | 48 | else: | ||
247 | 49 | pid = desktopcouch.find_pid(start_if_not_running=False) | ||
263 | 50 | 39 | ||
264 | 51 | if __name__ == "__main__": | 40 | if __name__ == "__main__": |
265 | 52 | stop_couchdb() | 41 | stop_couchdb() |
266 | 53 | 42 | ||
267 | === modified file 'desktopcouch/tests/__init__.py' | |||
268 | --- desktopcouch/tests/__init__.py 2009-11-11 16:24:22 +0000 | |||
269 | +++ desktopcouch/tests/__init__.py 2010-02-05 00:09:13 +0000 | |||
270 | @@ -29,8 +29,7 @@ | |||
271 | 29 | os.environ["XDG_CONFIG_DIRS"] = SOURCE_TREE_ETC_FOLDER | 29 | os.environ["XDG_CONFIG_DIRS"] = SOURCE_TREE_ETC_FOLDER |
272 | 30 | 30 | ||
273 | 31 | def stop_test_couch(temp_dir, ctx): | 31 | def stop_test_couch(temp_dir, ctx): |
276 | 32 | pid = read_pidfile(ctx) | 32 | stop_couchdb(ctx) |
275 | 33 | stop_couchdb(pid=pid) | ||
277 | 34 | shutil.rmtree(temp_dir) | 33 | shutil.rmtree(temp_dir) |
278 | 35 | 34 | ||
279 | 36 | start_couchdb(ctx=new_context) | 35 | start_couchdb(ctx=new_context) |
Excellent.