Merge lp:~salgado/launchpad/remove-auth-store into lp:launchpad/db-devel

Proposed by Guilherme Salgado
Status: Merged
Merged at revision: not available
Proposed branch: lp:~salgado/launchpad/remove-auth-store
Merge into: lp:launchpad/db-devel
Diff against target: 981 lines (+108/-263)
30 files modified
configs/development/launchpad-lazr.conf (+0/-2)
configs/replicated-development/launchpad-lazr.conf (+0/-3)
configs/test-playground/launchpad-lazr.conf (+0/-2)
configs/testrunner/launchpad-lazr.conf (+0/-2)
database/schema/security.cfg (+6/-2)
lib/canonical/buildd/debian/control (+1/-1)
lib/canonical/config/__init__.py (+2/-2)
lib/canonical/config/schema-lazr.conf (+0/-8)
lib/canonical/configure.zcml (+0/-2)
lib/canonical/database/harness.py (+1/-2)
lib/canonical/database/sqlbase.py (+2/-4)
lib/canonical/database/tests/test_zopeless_transaction_manager.py (+0/-31)
lib/canonical/launchpad/database/tests/test_oauth.py (+1/-1)
lib/canonical/launchpad/doc/account.txt (+1/-26)
lib/canonical/launchpad/doc/storm.txt (+51/-71)
lib/canonical/launchpad/pagetests/standalone/xx-opstats.txt (+0/-2)
lib/canonical/launchpad/scripts/garbo.py (+5/-13)
lib/canonical/launchpad/scripts/tests/test_garbo.py (+7/-9)
lib/canonical/launchpad/webapp/adapter.py (+5/-16)
lib/canonical/launchpad/webapp/ftests/test_adapter_permissions.txt (+1/-24)
lib/canonical/launchpad/webapp/interfaces.py (+1/-3)
lib/canonical/launchpad/webapp/tests/test_dbpolicy.py (+1/-4)
lib/lp/bugs/doc/checkwatches.txt (+4/-0)
lib/lp/bugs/doc/externalbugtracker-comment-imports.txt (+3/-3)
lib/lp/code/doc/branch-karma.txt (+1/-0)
lib/lp/registry/model/person.py (+2/-17)
lib/lp/registry/stories/person/xx-admin-person-review.txt (+1/-1)
lib/lp/registry/tests/test_personset.py (+6/-10)
lib/lp/testopenid/browser/server.py (+6/-1)
utilities/sourcedeps.conf (+0/-1)
To merge this branch: bzr merge lp:~salgado/launchpad/remove-auth-store
Reviewer Review Type Date Requested Status
Stuart Bishop (community) Approve
Review via email: mp+22478@code.launchpad.net

Description of the change

Remove the auth store, together with c-i-p.

Had to grant some extra DB permissions on security.cfg because some
things that used to be done using the launchpad_auth user (the one
always used for the auth store, regardless of what was given to
initZopeless) are now done using whichever user is used by the
script/test.

 reviewer stub

--
Guilherme Salgado <email address hidden>

To post a comment you must log in.
Revision history for this message
Stuart Bishop (stub) wrote :
Download full text (5.4 KiB)

On Wed, Mar 31, 2010 at 2:00 AM, Guilherme Salgado
<email address hidden> wrote:

> Remove the auth store, together with c-i-p.
>
> Had to grant some extra DB permissions on security.cfg because some
> things that used to be done using the launchpad_auth user (the one
> always used for the auth store, regardless of what was given to
> initZopeless) are now done using whichever user is used by the
> script/test.

Yay. This is more than I expected.

> === modified file 'lib/canonical/launchpad/database/tests/test_oauth.py'
> --- lib/canonical/launchpad/database/tests/test_oauth.py 2009-06-25 05:30:52 +0000
> +++ lib/canonical/launchpad/database/tests/test_oauth.py 2010-03-30 19:00:44 +0000
> @@ -22,7 +22,7 @@
> """Base tests for the OAuth database classes."""
> layer = DatabaseFunctionalLayer
>
> - def test__get_store_should_return_the_auth_master_store(self):
> + def test__get_store_should_return_the_main_master_store(self):
> """We want all OAuth classes to use the master store.
> Otherwise, the OAuth exchanges will fail because the authorize
> screen won't probably find the new request token on the slave store.

Does this test serve any purpose any more? Maybe remove it entirely.

> === modified file 'lib/canonical/launchpad/webapp/adapter.py'
> try:
> + # XXX: Salgado, 2010-03-22: We can get rid of the realm now that
> + # the auth DB is gone, but I'm not doing it in this branch to keep
> + # the diff simple.
> config_section, realm, flavor = self._uri.database.split('-')
> except ValueError:
> raise AssertionError(
> 'Connection uri %s does not match section-realm-flavor format'
> % repr(self._uri.database))

I don't think this XXX is warranted. We may well have more realms in
the future, for example if we move translations or codehosting to
their own database for scalability reasons.

> === modified file 'lib/canonical/launchpad/webapp/ftests/test_adapter_permissions.txt'
> -
> -A MASTER_FLAVOR Store does not allow writes to tables outside of that
> -Store's replication set.
> -
> - >>> t = transaction.begin()
> - >>> person = main_master.find(Person, name='no-priv').one()
> - >>> account = person.account
> - >>> account.displayname = "Ben Dover"
> - >>> main_master.flush()
> - Traceback (most recent call last):
> - ...
> - ProgrammingError: permission denied for relation account
> - >>> transaction.abort()
> -
> - >>> t = transaction.begin()
> - >>> auth_master = getUtility(IStoreSelector).get(AUTH_STORE, MASTER_FLAVOR)
> - >>> person = auth_master.find(Person, name='no-priv').one()
> - >>> account = person.account
> - >>> account.displayname = "Ben Dover"
> - >>> auth_master.flush()
> - >>> transaction.abort()

But this crap can certainly go. If we split the database in the
future, there will be no crossover. What I've learned from the
authdb/lpmain split is that the split needs to be clean, or we end up
with confusing code (is my email address from the authdb Store or the
lpmain Store) and a complicated and tricky to maintain repl...

Read more...

review: Approve
Revision history for this message
Guilherme Salgado (salgado) wrote :
Download full text (6.8 KiB)

On Thu, 2010-04-01 at 15:12 +0000, Stuart Bishop wrote:
> Review: Approve
> On Wed, Mar 31, 2010 at 2:00 AM, Guilherme Salgado
> <email address hidden> wrote:
>
> > Remove the auth store, together with c-i-p.
> >
> > Had to grant some extra DB permissions on security.cfg because some
> > things that used to be done using the launchpad_auth user (the one
> > always used for the auth store, regardless of what was given to
> > initZopeless) are now done using whichever user is used by the
> > script/test.
>
> Yay. This is more than I expected.

More than I expected too. :/

And to make things worse, there are a couple extra revisions that
weren't in the diff you reviewed (I'm assuming you reviewed the diff
that was sent out when the m-p was created):

http://bazaar.launchpad.net/~salgado/launchpad/remove-auth-store/revision/10563
http://bazaar.launchpad.net/~salgado/launchpad/remove-auth-store/revision/10564

They're trivial, though.

>
>
>
> > === modified file 'lib/canonical/launchpad/database/tests/test_oauth.py'
> > --- lib/canonical/launchpad/database/tests/test_oauth.py 2009-06-25 05:30:52 +0000
> > +++ lib/canonical/launchpad/database/tests/test_oauth.py 2010-03-30 19:00:44 +0000
> > @@ -22,7 +22,7 @@
> > """Base tests for the OAuth database classes."""
> > layer = DatabaseFunctionalLayer
> >
> > - def test__get_store_should_return_the_auth_master_store(self):
> > + def test__get_store_should_return_the_main_master_store(self):
> > """We want all OAuth classes to use the master store.
> > Otherwise, the OAuth exchanges will fail because the authorize
> > screen won't probably find the new request token on the slave store.
>
> Does this test serve any purpose any more? Maybe remove it entirely.
>

AIUI, it's necessary because we want to make sure that we use the master
store (by default) when dealing with OAuth-related objects. (The name
of the test method was actually wrong; this is not related to the other
changes on this branch)

>
> > === modified file 'lib/canonical/launchpad/webapp/adapter.py'
> > try:
> > + # XXX: Salgado, 2010-03-22: We can get rid of the realm now that
> > + # the auth DB is gone, but I'm not doing it in this branch to keep
> > + # the diff simple.
> > config_section, realm, flavor = self._uri.database.split('-')
> > except ValueError:
> > raise AssertionError(
> > 'Connection uri %s does not match section-realm-flavor format'
> > % repr(self._uri.database))
>
> I don't think this XXX is warranted. We may well have more realms in
> the future, for example if we move translations or codehosting to
> their own database for scalability reasons.

Fair enough; I thought we'd remove that because I had never heard of
these plans.

>
> > === modified file 'lib/canonical/launchpad/webapp/ftests/test_adapter_permissions.txt'
> > -
> > -A MASTER_FLAVOR Store does not allow writes to tables outside of that
> > -Store's replication set.
> > -
> > - >>> t = transaction.begin()
> > - >>> person = main_master.find(Person, name='no-priv').one()
> > - >>> a...

Read more...

=== modified file 'lib/canonical/launchpad/webapp/adapter.py'
--- lib/canonical/launchpad/webapp/adapter.py 2010-03-30 17:25:52 +0000
+++ lib/canonical/launchpad/webapp/adapter.py 2010-04-01 15:26:28 +0000
@@ -349,9 +349,6 @@
349 raise StormAccessFromMainThread()349 raise StormAccessFromMainThread()
350350
351 try:351 try:
352 # XXX: Salgado, 2010-03-22: We can get rid of the realm now that
353 # the auth DB is gone, but I'm not doing it in this branch to keep
354 # the diff simple.
355 config_section, realm, flavor = self._uri.database.split('-')352 config_section, realm, flavor = self._uri.database.split('-')
356 except ValueError:353 except ValueError:
357 raise AssertionError(354 raise AssertionError(
358355
=== modified file 'lib/canonical/launchpad/webapp/interfaces.py'
--- lib/canonical/launchpad/webapp/interfaces.py 2010-03-30 17:25:52 +0000
+++ lib/canonical/launchpad/webapp/interfaces.py 2010-04-01 15:37:19 +0000
@@ -745,6 +745,7 @@
745#745#
746746
747MAIN_STORE = 'main' # The main database.747MAIN_STORE = 'main' # The main database.
748ALL_STORES = frozenset([MAIN_STORE])
748749
749DEFAULT_FLAVOR = 'default' # Default flavor for current state.750DEFAULT_FLAVOR = 'default' # Default flavor for current state.
750MASTER_FLAVOR = 'master' # The master database.751MASTER_FLAVOR = 'master' # The master database.
@@ -771,9 +772,6 @@
771 utility.772 utility.
772 """773 """
773774
774 # XXX: 2010-03-24, Guilherme Salgado: The 'name' argument will always be
775 # MAIN_STORE here, so it can be removed. Not doing it now as this branch
776 # will be CPed into production.
777 def getStore(name, flavor):775 def getStore(name, flavor):
778 """Retrieve a Store.776 """Retrieve a Store.
779777
@@ -843,9 +841,6 @@
843 def get_current():841 def get_current():
844 """Return the currently installed `IDatabasePolicy`."""842 """Return the currently installed `IDatabasePolicy`."""
845843
846 # XXX: 2010-03-24, Guilherme Salgado: The 'name' argument will always be
847 # MAIN_STORE here, so it can be removed. Not doing it now as this branch
848 # will be CPed into production.
849 def get(name, flavor):844 def get(name, flavor):
850 """Retrieve a Storm Store.845 """Retrieve a Storm Store.
851846
852847
=== modified file 'lib/canonical/launchpad/webapp/tests/test_dbpolicy.py'
--- lib/canonical/launchpad/webapp/tests/test_dbpolicy.py 2010-03-24 15:22:26 +0000
+++ lib/canonical/launchpad/webapp/tests/test_dbpolicy.py 2010-04-01 15:39:56 +0000
@@ -25,7 +25,7 @@
25 ReadOnlyLaunchpadDatabasePolicy, SlaveDatabasePolicy,25 ReadOnlyLaunchpadDatabasePolicy, SlaveDatabasePolicy,
26 SlaveOnlyDatabasePolicy)26 SlaveOnlyDatabasePolicy)
27from canonical.launchpad.webapp.interfaces import (27from canonical.launchpad.webapp.interfaces import (
28 DEFAULT_FLAVOR, DisallowedStore, IDatabasePolicy,28 ALL_STORES, DEFAULT_FLAVOR, DisallowedStore, IDatabasePolicy,
29 IStoreSelector, MAIN_STORE, MASTER_FLAVOR, ReadOnlyModeDisallowedStore,29 IStoreSelector, MAIN_STORE, MASTER_FLAVOR, ReadOnlyModeDisallowedStore,
30 SLAVE_FLAVOR)30 SLAVE_FLAVOR)
31from canonical.launchpad.webapp.servers import LaunchpadTestRequest31from canonical.launchpad.webapp.servers import LaunchpadTestRequest
@@ -37,9 +37,10 @@
37 layer = DatabaseFunctionalLayer37 layer = DatabaseFunctionalLayer
3838
39 def test_defaults(self):39 def test_defaults(self):
40 self.assertProvides(40 for store in ALL_STORES:
41 getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR),41 self.assertProvides(
42 IMasterStore)42 getUtility(IStoreSelector).get(store, DEFAULT_FLAVOR),
43 IMasterStore)
4344
44 def test_dbusers(self):45 def test_dbusers(self):
45 store_selector = getUtility(IStoreSelector)46 store_selector = getUtility(IStoreSelector)
@@ -79,14 +80,16 @@
79 super(SlaveDatabasePolicyTestCase, self).setUp()80 super(SlaveDatabasePolicyTestCase, self).setUp()
8081
81 def test_defaults(self):82 def test_defaults(self):
82 self.assertProvides(83 for store in ALL_STORES:
83 getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR),84 self.assertProvides(
84 ISlaveStore)85 getUtility(IStoreSelector).get(store, DEFAULT_FLAVOR),
86 ISlaveStore)
8587
86 def test_master_allowed(self):88 def test_master_allowed(self):
87 self.assertProvides(89 for store in ALL_STORES:
88 getUtility(IStoreSelector).get(MAIN_STORE, MASTER_FLAVOR),90 self.assertProvides(
89 IMasterStore)91 getUtility(IStoreSelector).get(store, MASTER_FLAVOR),
92 IMasterStore)
9093
9194
92class SlaveOnlyDatabasePolicyTestCase(SlaveDatabasePolicyTestCase):95class SlaveOnlyDatabasePolicyTestCase(SlaveDatabasePolicyTestCase):
@@ -97,15 +100,10 @@
97 super(SlaveOnlyDatabasePolicyTestCase, self).setUp()100 super(SlaveOnlyDatabasePolicyTestCase, self).setUp()
98101
99 def test_master_allowed(self):102 def test_master_allowed(self):
100 # The master store is not allowed here, but we need this empty test103 for store in ALL_STORES:
101 # to overwrite the test method from our parent class, where the master104 self.failUnlessRaises(
102 # store is allowed.105 DisallowedStore,
103 pass106 getUtility(IStoreSelector).get, store, MASTER_FLAVOR)
104
105 def test_master_not_allowed(self):
106 self.failUnlessRaises(
107 DisallowedStore,
108 getUtility(IStoreSelector).get, MAIN_STORE, MASTER_FLAVOR)
109107
110108
111class MasterDatabasePolicyTestCase(BaseDatabasePolicyTestCase):109class MasterDatabasePolicyTestCase(BaseDatabasePolicyTestCase):
@@ -129,9 +127,10 @@
129127
130 def test_slave_allowed(self):128 def test_slave_allowed(self):
131 # We get the master store even if the slave was requested.129 # We get the master store even if the slave was requested.
132 self.assertProvides(130 for store in ALL_STORES:
133 getUtility(IStoreSelector).get(MAIN_STORE, SLAVE_FLAVOR),131 self.assertProvides(
134 ISlaveStore)132 getUtility(IStoreSelector).get(store, SLAVE_FLAVOR),
133 ISlaveStore)
135134
136135
137class LaunchpadDatabasePolicyTestCase(SlaveDatabasePolicyTestCase):136class LaunchpadDatabasePolicyTestCase(SlaveDatabasePolicyTestCase):
@@ -245,20 +244,23 @@
245244
246 def test_defaults(self):245 def test_defaults(self):
247 # default Store is the slave.246 # default Store is the slave.
248 self.assertProvides(247 for store in ALL_STORES:
249 getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR),248 self.assertProvides(
250 ISlaveStore)249 getUtility(IStoreSelector).get(store, DEFAULT_FLAVOR),
250 ISlaveStore)
251251
252 def test_slave_allowed(self):252 def test_slave_allowed(self):
253 self.assertProvides(253 for store in ALL_STORES:
254 getUtility(IStoreSelector).get(MAIN_STORE, SLAVE_FLAVOR),254 self.assertProvides(
255 ISlaveStore)255 getUtility(IStoreSelector).get(store, SLAVE_FLAVOR),
256 ISlaveStore)
256257
257 def test_master_disallowed(self):258 def test_master_disallowed(self):
258 store_selector = getUtility(IStoreSelector)259 store_selector = getUtility(IStoreSelector)
259 self.assertRaises(260 for store in ALL_STORES:
260 ReadOnlyModeDisallowedStore,261 self.assertRaises(
261 store_selector.get, MAIN_STORE, MASTER_FLAVOR)262 ReadOnlyModeDisallowedStore,
263 store_selector.get, store, MASTER_FLAVOR)
262264
263265
264def test_suite():266def test_suite():
265267

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'configs/development/launchpad-lazr.conf'
--- configs/development/launchpad-lazr.conf 2010-03-05 20:49:31 +0000
+++ configs/development/launchpad-lazr.conf 2010-04-05 12:47:32 +0000
@@ -97,8 +97,6 @@
97# the rw_* configs.97# the rw_* configs.
98ro_main_master: dbname=launchpad_dev_template98ro_main_master: dbname=launchpad_dev_template
99ro_main_slave: dbname=launchpad_dev_template99ro_main_slave: dbname=launchpad_dev_template
100auth_master: dbname=launchpad_dev
101auth_slave: dbname=launchpad_dev
102100
103[distributionmirrorprober]101[distributionmirrorprober]
104use_proxy: False102use_proxy: False
105103
=== modified file 'configs/replicated-development/launchpad-lazr.conf'
--- configs/replicated-development/launchpad-lazr.conf 2010-01-05 19:09:58 +0000
+++ configs/replicated-development/launchpad-lazr.conf 2010-04-05 12:47:32 +0000
@@ -10,6 +10,3 @@
10rw_main_slave: dbname=launchpad_dev_slave10rw_main_slave: dbname=launchpad_dev_slave
11ro_main_master: dbname=launchpad_dev11ro_main_master: dbname=launchpad_dev
12ro_main_slave: dbname=launchpad_dev_slave12ro_main_slave: dbname=launchpad_dev_slave
13auth_master: dbname=launchpad_dev
14auth_slave: dbname=launchpad_dev_slave
15
1613
=== modified file 'configs/test-playground/launchpad-lazr.conf'
--- configs/test-playground/launchpad-lazr.conf 2010-01-05 19:09:58 +0000
+++ configs/test-playground/launchpad-lazr.conf 2010-04-05 12:47:32 +0000
@@ -10,5 +10,3 @@
10rw_main_slave: dbname=launchpad_ftest_playground10rw_main_slave: dbname=launchpad_ftest_playground
11ro_main_master: dbname=launchpad_ftest_playground11ro_main_master: dbname=launchpad_ftest_playground
12ro_main_slave: dbname=launchpad_ftest_playground12ro_main_slave: dbname=launchpad_ftest_playground
13auth_master: dbname=launchpad_ftest_playground
14auth_slave: dbname=launchpad_ftest_playground
1513
=== modified file 'configs/testrunner/launchpad-lazr.conf'
--- configs/testrunner/launchpad-lazr.conf 2010-03-11 01:39:25 +0000
+++ configs/testrunner/launchpad-lazr.conf 2010-04-05 12:47:32 +0000
@@ -51,8 +51,6 @@
51# the rw_* configs.51# the rw_* configs.
52ro_main_master: dbname=launchpad_ftest_template52ro_main_master: dbname=launchpad_ftest_template
53ro_main_slave: dbname=launchpad_ftest_template53ro_main_slave: dbname=launchpad_ftest_template
54auth_master: dbname=launchpad_ftest
55auth_slave: dbname=launchpad_ftest
56randomise_select_results: true54randomise_select_results: true
5755
58[error_reports]56[error_reports]
5957
=== modified file 'database/schema/security.cfg'
--- database/schema/security.cfg 2010-04-02 17:29:13 +0000
+++ database/schema/security.cfg 2010-04-05 12:47:32 +0000
@@ -118,7 +118,8 @@
118# lpmain replication set access from the main Z3 application.118# lpmain replication set access from the main Z3 application.
119type=user119type=user
120groups=write,script120groups=write,script
121public.account = SELECT121public.account = SELECT, INSERT, UPDATE, DELETE
122public.accountpassword = SELECT, INSERT, UPDATE, DELETE
122public.announcement = SELECT, INSERT, UPDATE, DELETE123public.announcement = SELECT, INSERT, UPDATE, DELETE
123public.answercontact = SELECT, INSERT, UPDATE, DELETE124public.answercontact = SELECT, INSERT, UPDATE, DELETE
124public.apportjob = SELECT, INSERT, UPDATE, DELETE125public.apportjob = SELECT, INSERT, UPDATE, DELETE
@@ -176,7 +177,7 @@
176public.distributionsourcepackagecache = SELECT177public.distributionsourcepackagecache = SELECT
177public.distroserieslanguage = SELECT, INSERT, UPDATE178public.distroserieslanguage = SELECT, INSERT, UPDATE
178public.distroseriespackagecache = SELECT179public.distroseriespackagecache = SELECT
179public.emailaddress = SELECT180public.emailaddress = SELECT, INSERT, UPDATE, DELETE
180public.entitlement = SELECT, INSERT, UPDATE, DELETE181public.entitlement = SELECT, INSERT, UPDATE, DELETE
181public.faq = SELECT, INSERT, UPDATE, DELETE182public.faq = SELECT, INSERT, UPDATE, DELETE
182public.featuredproject = SELECT, INSERT, DELETE183public.featuredproject = SELECT, INSERT, DELETE
@@ -916,6 +917,8 @@
916# Full access except for tables that are exclusively updated by917# Full access except for tables that are exclusively updated by
917# certain processes, such as the librarian tables. This group is deprecated -918# certain processes, such as the librarian tables. This group is deprecated -
918# access should be explicitly granted to users.919# access should be explicitly granted to users.
920public.account = SELECT, INSERT, UPDATE
921public.accountpassword = SELECT, INSERT
919public.archive = SELECT, INSERT, UPDATE922public.archive = SELECT, INSERT, UPDATE
920public.archivearch = SELECT, INSERT, UPDATE, DELETE923public.archivearch = SELECT, INSERT, UPDATE, DELETE
921public.binarypackagerelease = SELECT, INSERT, UPDATE924public.binarypackagerelease = SELECT, INSERT, UPDATE
@@ -949,6 +952,7 @@
949public.distribution = SELECT, INSERT, UPDATE952public.distribution = SELECT, INSERT, UPDATE
950public.distroarchseries = SELECT, INSERT, UPDATE953public.distroarchseries = SELECT, INSERT, UPDATE
951public.distroseries = SELECT, INSERT, UPDATE954public.distroseries = SELECT, INSERT, UPDATE
955public.openidrpsummary = SELECT, INSERT, UPDATE
952public.packageupload = SELECT, INSERT, UPDATE956public.packageupload = SELECT, INSERT, UPDATE
953public.packageuploadbuild = SELECT, INSERT, UPDATE957public.packageuploadbuild = SELECT, INSERT, UPDATE
954public.packageuploadsource = SELECT, INSERT, UPDATE958public.packageuploadsource = SELECT, INSERT, UPDATE
955959
=== modified file 'lib/canonical/buildd/debian/control'
--- lib/canonical/buildd/debian/control 2009-11-17 22:28:43 +0000
+++ lib/canonical/buildd/debian/control 2010-04-05 12:47:32 +0000
@@ -8,7 +8,7 @@
8Package: launchpad-buildd8Package: launchpad-buildd
9Section: misc9Section: misc
10Architecture: all10Architecture: all
11Depends: python-twisted, debootstrap, dpkg-dev, linux32, file, bzip2, sudo, ntpdate, adduser, apt-transport-https11Depends: python-twisted-core, python-twisted-web, debootstrap, dpkg-dev, linux32, file, bzip2, sudo, ntpdate, adduser, apt-transport-https
12Description: Launchpad buildd slave12Description: Launchpad buildd slave
13 This is the launchpad buildd slave package. It contains everything needed to13 This is the launchpad buildd slave package. It contains everything needed to
14 get a launchpad buildd going apart from the database manipulation required to14 get a launchpad buildd going apart from the database manipulation required to
1515
=== modified file 'lib/canonical/config/__init__.py'
--- lib/canonical/config/__init__.py 2010-01-14 16:39:18 +0000
+++ lib/canonical/config/__init__.py 2010-04-05 12:47:32 +0000
@@ -374,13 +374,13 @@
374 _db_config_attrs = frozenset([374 _db_config_attrs = frozenset([
375 'dbuser', 'auth_dbuser',375 'dbuser', 'auth_dbuser',
376 'rw_main_master', 'rw_main_slave',376 'rw_main_master', 'rw_main_slave',
377 'ro_main_master', 'ro_main_slave', 'auth_master', 'auth_slave',377 'ro_main_master', 'ro_main_slave',
378 'db_statement_timeout', 'db_statement_timeout_precision',378 'db_statement_timeout', 'db_statement_timeout_precision',
379 'isolation_level', 'randomise_select_results',379 'isolation_level', 'randomise_select_results',
380 'soft_request_timeout', 'storm_cache', 'storm_cache_size'])380 'soft_request_timeout', 'storm_cache', 'storm_cache_size'])
381 _db_config_required_attrs = frozenset([381 _db_config_required_attrs = frozenset([
382 'dbuser', 'rw_main_master', 'rw_main_slave', 'ro_main_master',382 'dbuser', 'rw_main_master', 'rw_main_slave', 'ro_main_master',
383 'ro_main_slave', 'auth_master', 'auth_slave'])383 'ro_main_slave'])
384384
385 @property385 @property
386 def main_master(self):386 def main_master(self):
387387
=== modified file 'lib/canonical/config/schema-lazr.conf'
--- lib/canonical/config/schema-lazr.conf 2010-03-24 02:37:55 +0000
+++ lib/canonical/config/schema-lazr.conf 2010-04-05 12:47:32 +0000
@@ -559,8 +559,6 @@
559rw_main_slave: dbname=launchpad_prod_2 host=chokecherry.canonical.com559rw_main_slave: dbname=launchpad_prod_2 host=chokecherry.canonical.com
560ro_main_master: dbname=launchpad_standalone_1 host=chokecherry.canonical.com560ro_main_master: dbname=launchpad_standalone_1 host=chokecherry.canonical.com
561ro_main_slave: dbname=launchpad_standalone_1 host=chokecherry.canonical.com561ro_main_slave: dbname=launchpad_standalone_1 host=chokecherry.canonical.com
562auth_master: dbname=launchpad_prod_3 host=wildcherry.canonical.com
563auth_slave: dbname=launchpad_prod_2 host=chokecherry.canonical.com
564562
565# If the replication lag is more than this many seconds, slave databases563# If the replication lag is more than this many seconds, slave databases
566# will not be used.564# will not be used.
@@ -867,16 +865,10 @@
867# datatype: integer865# datatype: integer
868max_scaling: 500866max_scaling: 500
869867
870[sso]
871dbuser: sso_main
872auth_dbuser: sso_auth
873
874
875[launchpad]868[launchpad]
876# The database user which will be used by this process.869# The database user which will be used by this process.
877# datatype: string870# datatype: string
878dbuser: launchpad_main871dbuser: launchpad_main
879auth_dbuser: launchpad_auth
880storm_cache: generational872storm_cache: generational
881storm_cache_size: 10000873storm_cache_size: 10000
882874
883875
=== modified file 'lib/canonical/configure.zcml'
--- lib/canonical/configure.zcml 2010-01-08 21:23:15 +0000
+++ lib/canonical/configure.zcml 2010-04-05 12:47:32 +0000
@@ -154,7 +154,5 @@
154 <include package="canonical.lazr" />154 <include package="canonical.lazr" />
155 <include zcml:condition="installed canonical.shipit"155 <include zcml:condition="installed canonical.shipit"
156 package="canonical.shipit" />156 package="canonical.shipit" />
157 <include zcml:condition="installed canonical.signon"
158 package="canonical.signon" />
159157
160</configure>158</configure>
161159
=== modified file 'lib/canonical/database/harness.py'
--- lib/canonical/database/harness.py 2009-11-05 03:52:51 +0000
+++ lib/canonical/database/harness.py 2010-04-05 12:47:32 +0000
@@ -48,8 +48,7 @@
48from storm.locals import *48from storm.locals import *
49from storm.expr import *49from storm.expr import *
50from canonical.launchpad.webapp.interfaces import (50from canonical.launchpad.webapp.interfaces import (
51 IStoreSelector, MAIN_STORE, AUTH_STORE, MASTER_FLAVOR,51 IStoreSelector, MAIN_STORE, MASTER_FLAVOR, SLAVE_FLAVOR, DEFAULT_FLAVOR)
52 SLAVE_FLAVOR, DEFAULT_FLAVOR)
5352
5453
55def switch_db_user(dbuser, commit_first=True):54def switch_db_user(dbuser, commit_first=True):
5655
=== modified file 'lib/canonical/database/sqlbase.py'
--- lib/canonical/database/sqlbase.py 2010-03-23 15:04:41 +0000
+++ lib/canonical/database/sqlbase.py 2010-04-05 12:47:32 +0000
@@ -271,7 +271,6 @@
271 # This is only used by scripts, so we must connect to the read-write271 # This is only used by scripts, so we must connect to the read-write
272 # DB here -- that's why we use rw_main_master directly.272 # DB here -- that's why we use rw_main_master directly.
273 main_connection_string = dbconfig.rw_main_master273 main_connection_string = dbconfig.rw_main_master
274 auth_connection_string = dbconfig.auth_master
275274
276 # Override dbname and dbhost in the connection string if they275 # Override dbname and dbhost in the connection string if they
277 # have been passed in.276 # have been passed in.
@@ -290,7 +289,7 @@
290 match = re.search(r'host=(\S*)', main_connection_string)289 match = re.search(r'host=(\S*)', main_connection_string)
291 if match is not None:290 if match is not None:
292 dbhost = match.group(1)291 dbhost = match.group(1)
293 return main_connection_string, auth_connection_string, dbname, dbhost292 return main_connection_string, dbname, dbhost
294293
295 @classmethod294 @classmethod
296 def initZopeless(cls, dbname=None, dbhost=None, dbuser=None,295 def initZopeless(cls, dbname=None, dbhost=None, dbuser=None,
@@ -298,7 +297,7 @@
298 # Connect to the auth master store as well, as some scripts might need297 # Connect to the auth master store as well, as some scripts might need
299 # to create EmailAddresses and Accounts.298 # to create EmailAddresses and Accounts.
300299
301 main_connection_string, auth_connection_string, dbname, dbhost = (300 main_connection_string, dbname, dbhost = (
302 cls._get_zopeless_connection_config(dbname, dbhost))301 cls._get_zopeless_connection_config(dbname, dbhost))
303302
304 assert dbuser is not None, '''303 assert dbuser is not None, '''
@@ -315,7 +314,6 @@
315 overlay = dedent("""\314 overlay = dedent("""\
316 [database]315 [database]
317 rw_main_master: %(main_connection_string)s316 rw_main_master: %(main_connection_string)s
318 auth_master: %(auth_connection_string)s
319 isolation_level: %(isolation_level)s317 isolation_level: %(isolation_level)s
320 """ % vars())318 """ % vars())
321319
322320
=== modified file 'lib/canonical/database/tests/test_zopeless_transaction_manager.py'
--- lib/canonical/database/tests/test_zopeless_transaction_manager.py 2009-12-14 17:38:34 +0000
+++ lib/canonical/database/tests/test_zopeless_transaction_manager.py 2010-04-05 12:47:32 +0000
@@ -1,48 +1,17 @@
1# Copyright 2009 Canonical Ltd. This software is licensed under the1# Copyright 2009 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4from textwrap import dedent
5import unittest4import unittest
65
7from zope.component import getUtility6from zope.component import getUtility
87
9from storm.zope.interfaces import IZStorm8from storm.zope.interfaces import IZStorm
109
11from canonical.config import config
12from canonical.database.sqlbase import ZopelessTransactionManager10from canonical.database.sqlbase import ZopelessTransactionManager
13from canonical.testing.layers import LaunchpadZopelessLayer11from canonical.testing.layers import LaunchpadZopelessLayer
14from lp.testing import TestCase12from lp.testing import TestCase
1513
1614
17class TestZopelessTransactionManagerNoLayer(TestCase):
18
19 def test_initZopeless_connects_to_auth_master_db(self):
20 # Some scripts might create EmailAddress and Account entries, so
21 # initZopeless has to connect to the auth master db. This is a
22 # bugfix test. The error that this test detects is that the
23 # script used to use the main_master database for the
24 # auth_master. In this test, we make sure that the auth_master
25 # and main_master have different values in the config, and then
26 # show that they are honored. Prior to the fix, ``auth_master``
27 # would have been changed to the same value as ``main_master``.
28 # Now we set up our test data and push it on the config.
29 auth_master = "dbname=example_launchpad_auth_does_not_exist"
30 overlay = dedent("""
31 [database]
32 main_master: dbname=launchpad_dev
33 auth_master: %s
34 """ % (auth_master,))
35 config.push('new-db', overlay)
36 try:
37 main_connection_string, auth_connection_string, dbname, dbhost = (
38 ZopelessTransactionManager._get_zopeless_connection_config(
39 None, None))
40 self.assertEqual(auth_connection_string, auth_master)
41 finally:
42 # Clean up the configuration
43 config.pop('new-db')
44
45
46class TestZopelessTransactionManager(TestCase):15class TestZopelessTransactionManager(TestCase):
47 layer = LaunchpadZopelessLayer16 layer = LaunchpadZopelessLayer
4817
4918
=== modified file 'lib/canonical/launchpad/database/tests/test_oauth.py'
--- lib/canonical/launchpad/database/tests/test_oauth.py 2009-06-25 05:30:52 +0000
+++ lib/canonical/launchpad/database/tests/test_oauth.py 2010-04-05 12:47:32 +0000
@@ -22,7 +22,7 @@
22 """Base tests for the OAuth database classes."""22 """Base tests for the OAuth database classes."""
23 layer = DatabaseFunctionalLayer23 layer = DatabaseFunctionalLayer
2424
25 def test__get_store_should_return_the_auth_master_store(self):25 def test__get_store_should_return_the_main_master_store(self):
26 """We want all OAuth classes to use the master store.26 """We want all OAuth classes to use the master store.
27 Otherwise, the OAuth exchanges will fail because the authorize27 Otherwise, the OAuth exchanges will fail because the authorize
28 screen won't probably find the new request token on the slave store.28 screen won't probably find the new request token on the slave store.
2929
=== modified file 'lib/canonical/launchpad/doc/account.txt'
--- lib/canonical/launchpad/doc/account.txt 2010-02-12 15:57:27 +0000
+++ lib/canonical/launchpad/doc/account.txt 2010-04-05 12:47:32 +0000
@@ -196,32 +196,6 @@
196 >>> account.status = AccountStatus.ACTIVE196 >>> account.status = AccountStatus.ACTIVE
197 >>> login('no-priv@canonical.com')197 >>> login('no-priv@canonical.com')
198198
199The Account's displayname is synced to the Person's displayname if there
200is one. If the Person.displayname is changed, the Account.displayname is
201changed too.
202
203 >>> from canonical.launchpad.interfaces import IPersonSet
204
205 >>> personset = getUtility(IPersonSet)
206 >>> person = personset.getByEmail('no-priv@canonical.com')
207 >>> person.displayname = 'Something New'
208 >>> print account.displayname
209 Something New
210
211However, the reverse is not true. If we change the Account.displayname,
212the linked Person.displayname (if there is one) is not updated
213immediately. Instead, a cron job will sync this information later. This
214allows displayname changes to happen even when the Person table is
215unavailable.
216
217 >>> account.displayname = 'No Privileges Account'
218 >>> print person.displayname
219 Something New
220
221 >>> person.displayname = 'No Privileges Person'
222 >>> print account.displayname
223 No Privileges Person
224
225An Account has an OpenID identifier used to generate the OpenID identity199An Account has an OpenID identifier used to generate the OpenID identity
226URL.200URL.
227201
@@ -242,6 +216,7 @@
242 >>> login('admin@canonical.com')216 >>> login('admin@canonical.com')
243 >>> passwordless_account = account_set.new(217 >>> passwordless_account = account_set.new(
244 ... AccountCreationRationale.USER_CREATED, 'Passwordless')218 ... AccountCreationRationale.USER_CREATED, 'Passwordless')
219 >>> transaction.commit()
245 >>> print passwordless_account.creation_rationale.name220 >>> print passwordless_account.creation_rationale.name
246 USER_CREATED221 USER_CREATED
247 >>> print passwordless_account.displayname222 >>> print passwordless_account.displayname
248223
=== modified file 'lib/canonical/launchpad/doc/storm.txt'
--- lib/canonical/launchpad/doc/storm.txt 2010-02-22 10:33:10 +0000
+++ lib/canonical/launchpad/doc/storm.txt 2010-04-05 12:47:32 +0000
@@ -7,10 +7,11 @@
7specific Storm tools to cope with our master and slave store arrangement.7specific Storm tools to cope with our master and slave store arrangement.
88
9 >>> from canonical.launchpad.interfaces import (9 >>> from canonical.launchpad.interfaces import (
10 ... EmailAddressStatus, IAccountSet, IEmailAddressSet,10 ... EmailAddressStatus, IEmailAddressSet,
11 ... IMasterObject, IMasterStore, ISlaveStore, IStore)11 ... IMasterObject, IMasterStore, ISlaveStore, IStore)
12 >>> from canonical.launchpad.database import (12 >>> from canonical.launchpad.database import (
13 ... Account, AccountPassword, EmailAddress)13 ... Account, AccountPassword, EmailAddress)
14 >>> from lp.registry.interfaces.person import IPersonSet
14 >>> from lp.registry.model.person import Person15 >>> from lp.registry.model.person import Person
15 >>> from zope.security.proxy import ProxyFactory16 >>> from zope.security.proxy import ProxyFactory
1617
@@ -19,30 +20,14 @@
19a Launchpad database object. You can use adapters to20a Launchpad database object. You can use adapters to
20retrieve the correct Store.21retrieve the correct Store.
2122
22 >>> auth_master = IMasterStore(Account)
23 >>> main_master = IMasterStore(Person)23 >>> main_master = IMasterStore(Person)
24 >>> auth_master is main_master
25 False
26
27
28You can read most tables from any Store, which is required for doing
29fast joins in the database. However, when it is not necessary to
30retrieve objects from the same store as another object, it is better to
31explicitly use the explicit Store for its replication set. Some tables
32are only available from this store, such as the AccountPassword table.
33
34 >>> auth_slave = ISlaveStore(AccountPassword)
35 >>> main_slave = ISlaveStore(Person)
36 >>> auth_slave is main_slave
37 False
38
3924
40You can detect if a store is writable by checking what interfaces it25You can detect if a store is writable by checking what interfaces it
41provides.26provides.
4227
43 >>> IMasterStore.providedBy(auth_master)28 >>> IMasterStore.providedBy(main_master)
44 True29 True
45 >>> ISlaveStore.providedBy(auth_master)30 >>> ISlaveStore.providedBy(main_master)
46 False31 False
4732
4833
@@ -53,7 +38,6 @@
53Otherwise, it gives you the master. See IStoreSelector for details.38Otherwise, it gives you the master. See IStoreSelector for details.
5439
55 >>> main_default = IStore(Person)40 >>> main_default = IStore(Person)
56 >>> main_master = IMasterStore(Person)
57 >>> main_slave = ISlaveStore(Person)41 >>> main_slave = ISlaveStore(Person)
58 >>> main_default is main_master42 >>> main_default is main_master
59 True43 True
@@ -78,11 +62,10 @@
78changes to an object, just in case you have been passed an instance62changes to an object, just in case you have been passed an instance
79from a store other than the correct Master.63from a store other than the correct Master.
8064
81 >>> auth_slave = ISlaveStore(Account)65 >>> main_slave = ISlaveStore(Person)
82 >>> t = transaction.begin()66 >>> t = transaction.begin()
83 >>> account = auth_slave.find(67 >>> person = main_slave.find(Person, name='mark').one()
84 ... Account, openid_identifier='mark_oid').one()68 >>> person.displayname = 'Cannot change'
85 >>> account.displayname = 'Cannot change'
86 >>> transaction.commit()69 >>> transaction.commit()
87 Traceback (most recent call last):70 Traceback (most recent call last):
88 ...71 ...
@@ -90,9 +73,8 @@
9073
91 >>> transaction.abort()74 >>> transaction.abort()
92 >>> t = transaction.begin()75 >>> t = transaction.begin()
93 >>> account = auth_slave.find(76 >>> person = main_slave.find(Person, name='mark').one()
94 ... Account, openid_identifier='mark_oid').one()77 >>> IMasterObject(person).displayname = 'Can change'
95 >>> IMasterObject(account).displayname = 'Can change'
96 >>> transaction.commit()78 >>> transaction.commit()
9779
9880
@@ -100,61 +82,60 @@
100similarly wrapped.82similarly wrapped.
10183
102 >>> from zope.security.proxy import removeSecurityProxy84 >>> from zope.security.proxy import removeSecurityProxy
103 >>> account = getUtility(IAccountSet).getByEmail('no-priv@canonical.com')85 >>> person = getUtility(IPersonSet).getByEmail('no-priv@canonical.com')
104 >>> removeSecurityProxy(account) is account86 >>> removeSecurityProxy(person) is person
105 False87 False
106 >>> account.displayname88 >>> person.displayname
107 u'No Privileges Person'89 u'No Privileges Person'
108 >>> account.password90 >>> person.name = 'foo'
109 Traceback (most recent call last):91 Traceback (most recent call last):
110 ...92 ...
111 Unauthorized: ...93 Unauthorized: ...
11294
113 >>> account = IMasterObject(account)95 >>> person = IMasterObject(person)
114 >>> removeSecurityProxy(account) is account96 >>> removeSecurityProxy(person) is person
115 False97 False
116 >>> account.displayname98 >>> person.displayname
117 u'No Privileges Person'99 u'No Privileges Person'
118 >>> account.password100 >>> person.name = 'foo'
119 Traceback (most recent call last):101 Traceback (most recent call last):
120 ...102 ...
121 Unauthorized: ...103 Unauthorized: ...
122104
123 >>> account = IMasterObject(removeSecurityProxy(account))105 >>> person = IMasterObject(removeSecurityProxy(person))
124 >>> removeSecurityProxy(account) is account106 >>> removeSecurityProxy(person) is person
125 True107 True
126 >>> account.displayname108 >>> person.displayname
127 u'No Privileges Person'109 u'No Privileges Person'
128 >>> account.password110 >>> person.name = 'foo'
129 u'...'
130111
131Our objects may compare equal even if they have come from different112Our objects may compare equal even if they have come from different
132stores.113stores.
133114
134 >>> auth_master_email = IMasterStore(EmailAddress).find(115 >>> master_email = IMasterStore(EmailAddress).find(
135 ... EmailAddress, Person.name == 'janitor',116 ... EmailAddress, Person.name == 'janitor',
136 ... EmailAddress.person==Person.id).one()117 ... EmailAddress.person==Person.id).one()
137 >>> auth_slave_email = ISlaveStore(EmailAddress).find(118 >>> slave_email = ISlaveStore(EmailAddress).find(
138 ... EmailAddress, Person.name == 'janitor',119 ... EmailAddress, Person.name == 'janitor',
139 ... EmailAddress.person==Person.id).one()120 ... EmailAddress.person==Person.id).one()
140 >>> auth_master_email is auth_slave_email121 >>> master_email is slave_email
141 False122 False
142 >>> auth_master_email == auth_slave_email123 >>> master_email == slave_email
143 True124 True
144 >>> auth_master_email != auth_slave_email125 >>> master_email != slave_email
145 False126 False
146127
147Comparison works for security wrapped objects too.128Comparison works for security wrapped objects too.
148129
149 >>> wrapped_email = getUtility(IEmailAddressSet).getByEmail(130 >>> wrapped_email = getUtility(IEmailAddressSet).getByEmail(
150 ... auth_master_email.email)131 ... master_email.email)
151 >>> removeSecurityProxy(wrapped_email) is auth_master_email132 >>> removeSecurityProxy(wrapped_email) is master_email
152 True133 True
153 >>> wrapped_email is auth_master_email134 >>> wrapped_email is master_email
154 False135 False
155 >>> wrapped_email == auth_master_email136 >>> wrapped_email == master_email
156 True137 True
157 >>> wrapped_email != auth_master_email138 >>> wrapped_email != master_email
158 False139 False
159140
160Objects not yet flushed to the database also compare equal.141Objects not yet flushed to the database also compare equal.
@@ -176,10 +157,9 @@
176157
177Objects differing by class never compare equal.158Objects differing by class never compare equal.
178159
179 >>> account_one = IMasterStore(Account).get(Account, 1)160 >>> email_one = IMasterStore(EmailAddress).get(EmailAddress, 1)
180 >>> person_one = IMasterStore(Account).get(Person, 1)161 >>> person_one = IMasterStore(Person).get(Person, 1)
181 >>> account_one == person_one162 >>> email_one == person_one
182 False163 False
183 >>> account_one != person_one164 >>> email_one != person_one
184 True165 True
185
186166
=== modified file 'lib/canonical/launchpad/pagetests/standalone/xx-opstats.txt'
--- lib/canonical/launchpad/pagetests/standalone/xx-opstats.txt 2010-01-13 13:50:39 +0000
+++ lib/canonical/launchpad/pagetests/standalone/xx-opstats.txt 2010-04-05 12:47:32 +0000
@@ -236,8 +236,6 @@
236 ... [database]236 ... [database]
237 ... rw_main_master: dbname=nonexistant237 ... rw_main_master: dbname=nonexistant
238 ... rw_main_slave: dbname=nonexistant238 ... rw_main_slave: dbname=nonexistant
239 ... auth_master: dbname=nonexistant
240 ... auth_slave: dbname=nonexistant
241 ...239 ...
242 ... [launchpad_session]240 ... [launchpad_session]
243 ... dbname: nonexistant241 ... dbname: nonexistant
244242
=== modified file 'lib/canonical/launchpad/scripts/garbo.py'
--- lib/canonical/launchpad/scripts/garbo.py 2010-03-26 14:33:46 +0000
+++ lib/canonical/launchpad/scripts/garbo.py 2010-04-05 12:47:32 +0000
@@ -29,7 +29,7 @@
29from canonical.launchpad.utilities.looptuner import (29from canonical.launchpad.utilities.looptuner import (
30 DBLoopTuner, TunableLoop)30 DBLoopTuner, TunableLoop)
31from canonical.launchpad.webapp.interfaces import (31from canonical.launchpad.webapp.interfaces import (
32 IStoreSelector, AUTH_STORE, MAIN_STORE, MASTER_FLAVOR)32 IStoreSelector, MAIN_STORE, MASTER_FLAVOR)
33from lp.bugs.interfaces.bug import IBugSet33from lp.bugs.interfaces.bug import IBugSet
34from lp.bugs.interfaces.bugjob import ICalculateBugHeatJobSource34from lp.bugs.interfaces.bugjob import ICalculateBugHeatJobSource
35from lp.bugs.model.bugnotification import BugNotification35from lp.bugs.model.bugnotification import BugNotification
@@ -121,19 +121,17 @@
121 transaction.commit()121 transaction.commit()
122122
123123
124class OpenIDAssociationPruner(TunableLoop):124class OpenIDConsumerAssociationPruner(TunableLoop):
125 minimum_chunk_size = 3500125 minimum_chunk_size = 3500
126 maximum_chunk_size = 50000126 maximum_chunk_size = 50000
127127
128 table_name = 'OpenIDAssociation'128 table_name = 'OpenIDConsumerAssociation'
129 store_name = AUTH_STORE
130129
131 _num_removed = None130 _num_removed = None
132131
133 def __init__(self, log, abort_time=None):132 def __init__(self, log, abort_time=None):
134 super(OpenIDAssociationPruner, self).__init__(log, abort_time)133 super(OpenIDConsumerAssociationPruner, self).__init__(log, abort_time)
135 self.store = getUtility(IStoreSelector).get(134 self.store = getUtility(IStoreSelector).get(MAIN_STORE, MASTER_FLAVOR)
136 self.store_name, MASTER_FLAVOR)
137135
138 def __call__(self, chunksize):136 def __call__(self, chunksize):
139 result = self.store.execute("""137 result = self.store.execute("""
@@ -152,11 +150,6 @@
152 return self._num_removed == 0150 return self._num_removed == 0
153151
154152
155class OpenIDConsumerAssociationPruner(OpenIDAssociationPruner):
156 table_name = 'OpenIDConsumerAssociation'
157 store_name = MAIN_STORE
158
159
160class RevisionCachePruner(TunableLoop):153class RevisionCachePruner(TunableLoop):
161 """A tunable loop to remove old revisions from the cache."""154 """A tunable loop to remove old revisions from the cache."""
162155
@@ -869,7 +862,6 @@
869 tunable_loops = [862 tunable_loops = [
870 OAuthNoncePruner,863 OAuthNoncePruner,
871 OpenIDConsumerNoncePruner,864 OpenIDConsumerNoncePruner,
872 OpenIDAssociationPruner,
873 OpenIDConsumerAssociationPruner,865 OpenIDConsumerAssociationPruner,
874 RevisionCachePruner,866 RevisionCachePruner,
875 BugHeatUpdater,867 BugHeatUpdater,
876868
=== modified file 'lib/canonical/launchpad/scripts/tests/test_garbo.py'
--- lib/canonical/launchpad/scripts/tests/test_garbo.py 2010-01-22 06:03:19 +0000
+++ lib/canonical/launchpad/scripts/tests/test_garbo.py 2010-04-05 12:47:32 +0000
@@ -29,11 +29,11 @@
29from lp.testing import TestCase, TestCaseWithFactory29from lp.testing import TestCase, TestCaseWithFactory
30from canonical.launchpad.scripts.garbo import (30from canonical.launchpad.scripts.garbo import (
31 DailyDatabaseGarbageCollector, HourlyDatabaseGarbageCollector,31 DailyDatabaseGarbageCollector, HourlyDatabaseGarbageCollector,
32 OpenIDAssociationPruner, OpenIDConsumerAssociationPruner)32 OpenIDConsumerAssociationPruner)
33from canonical.launchpad.scripts.tests import run_script33from canonical.launchpad.scripts.tests import run_script
34from canonical.launchpad.scripts.logger import QuietFakeLogger34from canonical.launchpad.scripts.logger import QuietFakeLogger
35from canonical.launchpad.webapp.interfaces import (35from canonical.launchpad.webapp.interfaces import (
36 IStoreSelector, MASTER_FLAVOR)36 IStoreSelector, MAIN_STORE, MASTER_FLAVOR)
37from canonical.testing.layers import (37from canonical.testing.layers import (
38 DatabaseLayer, LaunchpadScriptLayer, LaunchpadZopelessLayer)38 DatabaseLayer, LaunchpadScriptLayer, LaunchpadZopelessLayer)
39from lp.bugs.model.bugnotification import (39from lp.bugs.model.bugnotification import (
@@ -219,12 +219,12 @@
219 Min(CodeImportResult.date_created)).one().replace(tzinfo=UTC)219 Min(CodeImportResult.date_created)).one().replace(tzinfo=UTC)
220 >= now - timedelta(days=30))220 >= now - timedelta(days=30))
221221
222 def test_OpenIDAssociationPruner(self, pruner=OpenIDAssociationPruner):222 def test_OpenIDConsumerAssociationPruner(self):
223 store_name = pruner.store_name223 pruner = OpenIDConsumerAssociationPruner
224 table_name = pruner.table_name224 table_name = pruner.table_name
225 LaunchpadZopelessLayer.switchDbUser('testadmin')225 LaunchpadZopelessLayer.switchDbUser('testadmin')
226 store_selector = getUtility(IStoreSelector)226 store_selector = getUtility(IStoreSelector)
227 store = store_selector.get(store_name, MASTER_FLAVOR)227 store = store_selector.get(MAIN_STORE, MASTER_FLAVOR)
228 now = time.time()228 now = time.time()
229 # Create some associations in the past with lifetimes229 # Create some associations in the past with lifetimes
230 for delta in range(0, 20):230 for delta in range(0, 20):
@@ -247,7 +247,7 @@
247 self.runHourly()247 self.runHourly()
248248
249 LaunchpadZopelessLayer.switchDbUser('testadmin')249 LaunchpadZopelessLayer.switchDbUser('testadmin')
250 store = store_selector.get(store_name, MASTER_FLAVOR)250 store = store_selector.get(MAIN_STORE, MASTER_FLAVOR)
251 # Confirm all the rows we know should have been expired have251 # Confirm all the rows we know should have been expired have
252 # been expired. These are the ones that would be expired using252 # been expired. These are the ones that would be expired using
253 # the test start time as 'now'.253 # the test start time as 'now'.
@@ -263,9 +263,6 @@
263 "SELECT COUNT(*) FROM %s" % table_name).get_one()[0]263 "SELECT COUNT(*) FROM %s" % table_name).get_one()[0]
264 self.failUnless(num_unexpired > 0)264 self.failUnless(num_unexpired > 0)
265265
266 def test_OpenIDConsumerAssociationPruner(self):
267 self.test_OpenIDAssociationPruner(OpenIDConsumerAssociationPruner)
268
269 def test_RevisionAuthorEmailLinker(self):266 def test_RevisionAuthorEmailLinker(self):
270 LaunchpadZopelessLayer.switchDbUser('testadmin')267 LaunchpadZopelessLayer.switchDbUser('testadmin')
271 rev1 = self.factory.makeRevision('Author 1 <author-1@Example.Org>')268 rev1 = self.factory.makeRevision('Author 1 <author-1@Example.Org>')
@@ -373,6 +370,7 @@
373370
374 # If we remove the email address that was subscribed, the371 # If we remove the email address that was subscribed, the
375 # garbage collector removes the subscription.372 # garbage collector removes the subscription.
373 LaunchpadZopelessLayer.switchDbUser('testadmin')
376 Store.of(email).remove(email)374 Store.of(email).remove(email)
377 transaction.commit()375 transaction.commit()
378 self.runDaily()376 self.runDaily()
379377
=== modified file 'lib/canonical/launchpad/webapp/adapter.py'
--- lib/canonical/launchpad/webapp/adapter.py 2010-03-25 11:58:42 +0000
+++ lib/canonical/launchpad/webapp/adapter.py 2010-04-05 12:47:32 +0000
@@ -40,14 +40,13 @@
40from canonical.launchpad.readonly import is_read_only40from canonical.launchpad.readonly import is_read_only
41from canonical.launchpad.webapp.dbpolicy import MasterDatabasePolicy41from canonical.launchpad.webapp.dbpolicy import MasterDatabasePolicy
42from canonical.launchpad.webapp.interfaces import (42from canonical.launchpad.webapp.interfaces import (
43 AUTH_STORE, DEFAULT_FLAVOR, IStoreSelector,43 DEFAULT_FLAVOR, IStoreSelector, MAIN_STORE, MASTER_FLAVOR,
44 MAIN_STORE, MASTER_FLAVOR, ReadOnlyModeViolation, SLAVE_FLAVOR)44 ReadOnlyModeViolation, SLAVE_FLAVOR)
45from canonical.launchpad.webapp.opstats import OpStats45from canonical.launchpad.webapp.opstats import OpStats
46from canonical.lazr.utils import safe_hasattr46from canonical.lazr.utils import safe_hasattr
4747
4848
49__all__ = [49__all__ = [
50 'DisconnectionError',
51 'RequestExpired',50 'RequestExpired',
52 'set_request_started',51 'set_request_started',
53 'clear_request_started',52 'clear_request_started',
@@ -327,7 +326,7 @@
327326
328 def __init__(self, uri):327 def __init__(self, uri):
329 # The uri is just a property name in the config, such as main_master328 # The uri is just a property name in the config, such as main_master
330 # or auth_slave.329 # or main_slave.
331 # We don't invoke the superclass constructor as it has a very limited330 # We don't invoke the superclass constructor as it has a very limited
332 # opinion on what uri is.331 # opinion on what uri is.
333 # pylint: disable-msg=W0231332 # pylint: disable-msg=W0231
@@ -356,7 +355,7 @@
356 'Connection uri %s does not match section-realm-flavor format'355 'Connection uri %s does not match section-realm-flavor format'
357 % repr(self._uri.database))356 % repr(self._uri.database))
358357
359 assert realm in ('main', 'auth'), 'Unknown realm %s' % realm358 assert realm == 'main', 'Unknown realm %s' % realm
360 assert flavor in ('master', 'slave'), 'Unknown flavor %s' % flavor359 assert flavor in ('master', 'slave'), 'Unknown flavor %s' % flavor
361360
362 my_dbconfig = DatabaseConfig()361 my_dbconfig = DatabaseConfig()
@@ -572,14 +571,6 @@
572 return db_policy.getStore(name, flavor)571 return db_policy.getStore(name, flavor)
573572
574573
575# There are not many tables outside of the main replication set, so we
576# can just maintain a hardcoded list of what isn't in there for now.
577_auth_store_tables = frozenset([
578 'Account', 'AccountPassword', 'AuthToken', 'EmailAddress',
579 'OpenIDAssociation', 'OpenIDAuthorization', 'OpenIDNonce',
580 'OpenIDRPSummary'])
581
582
583# We want to be able to adapt a Storm class to an IStore, IMasterStore or574# We want to be able to adapt a Storm class to an IStore, IMasterStore or
584# ISlaveStore. Unfortunately, the component architecture provides no575# ISlaveStore. Unfortunately, the component architecture provides no
585# way for us to declare that a class, and all its subclasses, provides576# way for us to declare that a class, and all its subclasses, provides
@@ -588,9 +579,7 @@
588def get_store(storm_class, flavor=DEFAULT_FLAVOR):579def get_store(storm_class, flavor=DEFAULT_FLAVOR):
589 """Return a flavored Store for the given database class."""580 """Return a flavored Store for the given database class."""
590 table = getattr(removeSecurityProxy(storm_class), '__storm_table__', None)581 table = getattr(removeSecurityProxy(storm_class), '__storm_table__', None)
591 if table in _auth_store_tables:582 if table is not None:
592 return getUtility(IStoreSelector).get(AUTH_STORE, flavor)
593 elif table is not None:
594 return getUtility(IStoreSelector).get(MAIN_STORE, flavor)583 return getUtility(IStoreSelector).get(MAIN_STORE, flavor)
595 else:584 else:
596 return None585 return None
597586
=== modified file 'lib/canonical/launchpad/webapp/ftests/test_adapter_permissions.txt'
--- lib/canonical/launchpad/webapp/ftests/test_adapter_permissions.txt 2009-06-11 01:28:55 +0000
+++ lib/canonical/launchpad/webapp/ftests/test_adapter_permissions.txt 2010-04-05 12:47:32 +0000
@@ -10,8 +10,7 @@
1010
11 >>> from lp.registry.model.person import Person11 >>> from lp.registry.model.person import Person
12 >>> from canonical.launchpad.webapp.interfaces import (12 >>> from canonical.launchpad.webapp.interfaces import (
13 ... IStoreSelector, AUTH_STORE, MAIN_STORE,13 ... IStoreSelector, MAIN_STORE, MASTER_FLAVOR, SLAVE_FLAVOR)
14 ... MASTER_FLAVOR, SLAVE_FLAVOR)
15 >>> import transaction14 >>> import transaction
16 >>> from zope.component import getUtility15 >>> from zope.component import getUtility
1716
@@ -47,25 +46,3 @@
47 >>> main_master.find(Person, name='janitor').one().displayname46 >>> main_master.find(Person, name='janitor').one().displayname
48 u'BenD'47 u'BenD'
49 >>> transaction.abort()48 >>> transaction.abort()
50
51
52A MASTER_FLAVOR Store does not allow writes to tables outside of that
53Store's replication set.
54
55 >>> t = transaction.begin()
56 >>> person = main_master.find(Person, name='no-priv').one()
57 >>> account = person.account
58 >>> account.displayname = "Ben Dover"
59 >>> main_master.flush()
60 Traceback (most recent call last):
61 ...
62 ProgrammingError: permission denied for relation account
63 >>> transaction.abort()
64
65 >>> t = transaction.begin()
66 >>> auth_master = getUtility(IStoreSelector).get(AUTH_STORE, MASTER_FLAVOR)
67 >>> person = auth_master.find(Person, name='no-priv').one()
68 >>> account = person.account
69 >>> account.displayname = "Ben Dover"
70 >>> auth_master.flush()
71 >>> transaction.abort()
7249
=== modified file 'lib/canonical/launchpad/webapp/interfaces.py'
--- lib/canonical/launchpad/webapp/interfaces.py 2010-03-26 22:57:38 +0000
+++ lib/canonical/launchpad/webapp/interfaces.py 2010-04-05 12:47:32 +0000
@@ -745,9 +745,7 @@
745#745#
746746
747MAIN_STORE = 'main' # The main database.747MAIN_STORE = 'main' # The main database.
748AUTH_STORE = 'auth' # The authentication database.748ALL_STORES = frozenset([MAIN_STORE])
749
750ALL_STORES = frozenset([MAIN_STORE, AUTH_STORE])
751749
752DEFAULT_FLAVOR = 'default' # Default flavor for current state.750DEFAULT_FLAVOR = 'default' # Default flavor for current state.
753MASTER_FLAVOR = 'master' # The master database.751MASTER_FLAVOR = 'master' # The master database.
754752
=== modified file 'lib/canonical/launchpad/webapp/tests/test_dbpolicy.py'
--- lib/canonical/launchpad/webapp/tests/test_dbpolicy.py 2010-02-24 23:18:40 +0000
+++ lib/canonical/launchpad/webapp/tests/test_dbpolicy.py 2010-04-05 12:47:32 +0000
@@ -25,7 +25,7 @@
25 ReadOnlyLaunchpadDatabasePolicy, SlaveDatabasePolicy,25 ReadOnlyLaunchpadDatabasePolicy, SlaveDatabasePolicy,
26 SlaveOnlyDatabasePolicy)26 SlaveOnlyDatabasePolicy)
27from canonical.launchpad.webapp.interfaces import (27from canonical.launchpad.webapp.interfaces import (
28 ALL_STORES, AUTH_STORE, DEFAULT_FLAVOR, DisallowedStore, IDatabasePolicy,28 ALL_STORES, DEFAULT_FLAVOR, DisallowedStore, IDatabasePolicy,
29 IStoreSelector, MAIN_STORE, MASTER_FLAVOR, ReadOnlyModeDisallowedStore,29 IStoreSelector, MAIN_STORE, MASTER_FLAVOR, ReadOnlyModeDisallowedStore,
30 SLAVE_FLAVOR)30 SLAVE_FLAVOR)
31from canonical.launchpad.webapp.servers import LaunchpadTestRequest31from canonical.launchpad.webapp.servers import LaunchpadTestRequest
@@ -47,9 +47,6 @@
47 main_store = store_selector.get(MAIN_STORE, DEFAULT_FLAVOR)47 main_store = store_selector.get(MAIN_STORE, DEFAULT_FLAVOR)
48 self.failUnlessEqual(self.getDBUser(main_store), 'launchpad_main')48 self.failUnlessEqual(self.getDBUser(main_store), 'launchpad_main')
4949
50 auth_store = store_selector.get(AUTH_STORE, DEFAULT_FLAVOR)
51 self.failUnlessEqual(self.getDBUser(auth_store), 'launchpad_auth')
52
53 def getDBUser(self, store):50 def getDBUser(self, store):
54 return store.execute(51 return store.execute(
55 'SHOW session_authorization').get_one()[0]52 'SHOW session_authorization').get_one()[0]
5653
=== removed symlink 'lib/canonical/signon'
=== target was u'../../sourcecode/canonical-identity-provider'
=== modified file 'lib/lp/bugs/doc/checkwatches.txt'
--- lib/lp/bugs/doc/checkwatches.txt 2010-03-26 15:24:59 +0000
+++ lib/lp/bugs/doc/checkwatches.txt 2010-04-05 12:47:32 +0000
@@ -337,9 +337,13 @@
337If a bug tracker doesn't have any watches to update, forceUpdateAll()337If a bug tracker doesn't have any watches to update, forceUpdateAll()
338will ignore it.338will ignore it.
339339
340 >>> transaction.commit()
341 >>> LaunchpadZopelessLayer.switchDbUser('launchpad')
340 >>> login('test@canonical.com')342 >>> login('test@canonical.com')
341 >>> empty_tracker = factory.makeBugTracker(343 >>> empty_tracker = factory.makeBugTracker(
342 ... 'http://example.com', BugTrackerType.ROUNDUP)344 ... 'http://example.com', BugTrackerType.ROUNDUP)
345 >>> transaction.commit()
346 >>> LaunchpadZopelessLayer.switchDbUser(config.checkwatches.dbuser)
343 >>> empty_tracker_name = empty_tracker.name347 >>> empty_tracker_name = empty_tracker.name
344 >>> update_all(empty_tracker_name)348 >>> update_all(empty_tracker_name)
345 INFO Bug tracker 'auto-example.com' doesn't have any watches. Ignoring.349 INFO Bug tracker 'auto-example.com' doesn't have any watches. Ignoring.
346350
=== modified file 'lib/lp/bugs/doc/externalbugtracker-comment-imports.txt'
--- lib/lp/bugs/doc/externalbugtracker-comment-imports.txt 2010-03-25 14:28:33 +0000
+++ lib/lp/bugs/doc/externalbugtracker-comment-imports.txt 2010-04-05 12:47:32 +0000
@@ -373,8 +373,10 @@
373since they aren't a valid Launchpad user, having been created during the373since they aren't a valid Launchpad user, having been created during the
374import process.374import process.
375375
376We'll add a listener to check for Karma events.376We'll create a bug watch and add a listener to check for Karma events.
377377
378 >>> LaunchpadZopelessLayer.switchDbUser('launchpad')
379 >>> bug_watch = factory.makeBugWatch('123456')
378 >>> from lp.registry.tests.karma import KarmaAssignedEventListener380 >>> from lp.registry.tests.karma import KarmaAssignedEventListener
379 >>> karma_helper = KarmaAssignedEventListener()381 >>> karma_helper = KarmaAssignedEventListener()
380 >>> karma_helper.register_listener()382 >>> karma_helper.register_listener()
@@ -382,8 +384,6 @@
382Importing a comment with a CVE reference will produce a CVE link in384Importing a comment with a CVE reference will produce a CVE link in
383Launchpad but will result in no Karma records being created.385Launchpad but will result in no Karma records being created.
384386
385 >>> LaunchpadZopelessLayer.switchDbUser('launchpad')
386 >>> bug_watch = factory.makeBugWatch('123456')
387 >>> transaction.commit()387 >>> transaction.commit()
388 >>> LaunchpadZopelessLayer.switchDbUser(config.checkwatches.dbuser)388 >>> LaunchpadZopelessLayer.switchDbUser(config.checkwatches.dbuser)
389 >>> external_bugtracker.remote_comments = {389 >>> external_bugtracker.remote_comments = {
390390
=== modified file 'lib/lp/code/doc/branch-karma.txt'
--- lib/lp/code/doc/branch-karma.txt 2010-02-16 20:36:48 +0000
+++ lib/lp/code/doc/branch-karma.txt 2010-04-05 12:47:32 +0000
@@ -49,6 +49,7 @@
49You get karma for linking a bug to a branch.49You get karma for linking a bug to a branch.
5050
51 >>> bug = factory.makeBug(product=fooix)51 >>> bug = factory.makeBug(product=fooix)
52 Karma added: action=bugcreated, product=fooix, person=person-name11
52 >>> branch_link = bug.linkBranch(branch, eric)53 >>> branch_link = bug.linkBranch(branch, eric)
53 Karma added: action=bugbranchcreated, product=fooix, person=eric54 Karma added: action=bugbranchcreated, product=fooix, person=eric
5455
5556
=== modified file 'lib/lp/registry/model/person.py'
--- lib/lp/registry/model/person.py 2010-03-24 23:19:52 +0000
+++ lib/lp/registry/model/person.py 2010-04-05 12:47:32 +0000
@@ -124,7 +124,7 @@
124 TeamMembershipStatus)124 TeamMembershipStatus)
125from lp.registry.interfaces.wikiname import IWikiName, IWikiNameSet125from lp.registry.interfaces.wikiname import IWikiName, IWikiNameSet
126from canonical.launchpad.webapp.interfaces import (126from canonical.launchpad.webapp.interfaces import (
127 AUTH_STORE, ILaunchBag, IStoreSelector, MASTER_FLAVOR)127 ILaunchBag, IStoreSelector, MASTER_FLAVOR)
128128
129from lp.soyuz.model.archive import Archive129from lp.soyuz.model.archive import Archive
130from lp.registry.model.codeofconduct import SignedCodeOfConduct130from lp.registry.model.codeofconduct import SignedCodeOfConduct
@@ -263,22 +263,7 @@
263 return '<Person at 0x%x %s (%s)>' % (263 return '<Person at 0x%x %s (%s)>' % (
264 id(self), self.name, self.displayname)264 id(self), self.name, self.displayname)
265265
266 def _sync_displayname(self, attr, value):266 displayname = StringCol(dbName='displayname', notNull=True)
267 """Update any related Account.displayname.
268
269 We can't do this in a DB trigger as soon the Account table will
270 in a separate database to the Person table.
271 """
272 if self.accountID is not None:
273 auth_store = getUtility(IStoreSelector).get(
274 AUTH_STORE, MASTER_FLAVOR)
275 account = auth_store.get(Account, self.accountID)
276 if account.displayname != value:
277 account.displayname = value
278 return value
279
280 displayname = StringCol(dbName='displayname', notNull=True,
281 storm_validator=_sync_displayname)
282267
283 teamdescription = StringCol(dbName='teamdescription', default=None)268 teamdescription = StringCol(dbName='teamdescription', default=None)
284 homepage_content = StringCol(default=None)269 homepage_content = StringCol(default=None)
285270
=== modified file 'lib/lp/registry/stories/person/xx-admin-person-review.txt'
--- lib/lp/registry/stories/person/xx-admin-person-review.txt 2010-01-30 22:39:54 +0000
+++ lib/lp/registry/stories/person/xx-admin-person-review.txt 2010-04-05 12:47:32 +0000
@@ -63,7 +63,7 @@
63 >>> print admin_browser.title63 >>> print admin_browser.title
64 The one and only Salgado does not use Launchpad64 The one and only Salgado does not use Launchpad
65 >>> print get_feedback_messages(admin_browser.contents)[0]65 >>> print get_feedback_messages(admin_browser.contents)[0]
66 The account "The one and only Salgado" has been suspended.66 The account "Guilherme Salgado" has been suspended.
6767
68The admin can see the account information of a user that does not use68The admin can see the account information of a user that does not use
69Launchpad, and can change the account too. Note that all pages that belong69Launchpad, and can change the account too. Note that all pages that belong
7070
=== modified file 'lib/lp/registry/tests/test_personset.py'
--- lib/lp/registry/tests/test_personset.py 2010-03-11 20:54:36 +0000
+++ lib/lp/registry/tests/test_personset.py 2010-04-05 12:47:32 +0000
@@ -99,23 +99,19 @@
99 # Person in question.99 # Person in question.
100100
101 # Create a testing `Account` and a testing `Person` directly,101 # Create a testing `Account` and a testing `Person` directly,
102 # linked. However the `Account` email is not linked to the102 # linked.
103 # `Person`.
104 testing_account = self.factory.makeAccount(103 testing_account = self.factory.makeAccount(
105 self.displayname, email=self.email_address)104 self.displayname, email=self.email_address)
106 testing_person = removeSecurityProxy(105 testing_person = removeSecurityProxy(
107 testing_account).createPerson(self.rationale)106 testing_account).createPerson(self.rationale)
108 self.assertIs(None, testing_account.preferredemail.person)107 self.assertEqual(
109 self.assertIs(None, testing_person.preferredemail)108 testing_person, testing_account.preferredemail.person)
110109
110 # Since there's an existing Person for the given email address,
111 # IPersonSet.ensurePerson() will just return it.
111 ensured_person = self.person_set.ensurePerson(112 ensured_person = self.person_set.ensurePerson(
112 self.email_address, self.displayname, self.rationale)113 self.email_address, self.displayname, self.rationale)
113114 self.assertEqual(testing_person, ensured_person)
114 # The existing Person was retrieved and the Account
115 # 'preferredemail' is also bound to the existing Person.
116 self.assertEquals(testing_person.id, ensured_person.id)
117 self.assertEquals(testing_account.preferredemail.id,
118 ensured_person.preferredemail.id)
119115
120116
121class TestPersonSetMerge(TestCaseWithFactory):117class TestPersonSetMerge(TestCaseWithFactory):
122118
=== modified file 'lib/lp/testopenid/browser/server.py'
--- lib/lp/testopenid/browser/server.py 2010-02-24 12:52:08 +0000
+++ lib/lp/testopenid/browser/server.py 2010-04-05 12:47:32 +0000
@@ -6,7 +6,7 @@
6__all__ = [6__all__ = [
7 'PersistentIdentityView',7 'PersistentIdentityView',
8 'TestOpenIDApplicationNavigation',8 'TestOpenIDApplicationNavigation',
9 'TestOpenIDIndexView'9 'TestOpenIDIndexView',
10 'TestOpenIDLoginView',10 'TestOpenIDLoginView',
11 'TestOpenIDRootUrlData',11 'TestOpenIDRootUrlData',
12 'TestOpenIDView',12 'TestOpenIDView',
@@ -21,6 +21,7 @@
21from zope.security.proxy import isinstance as zisinstance21from zope.security.proxy import isinstance as zisinstance
22from zope.session.interfaces import ISession22from zope.session.interfaces import ISession
2323
24from openid import oidutil
24from openid.server.server import CheckIDRequest, Server25from openid.server.server import CheckIDRequest, Server
25from openid.store.memstore import MemoryStore26from openid.store.memstore import MemoryStore
2627
@@ -47,6 +48,10 @@
47openid_store = MemoryStore()48openid_store = MemoryStore()
4849
4950
51# Shut up noisy OpenID library
52oidutil.log = lambda message, level=0: None
53
54
50class TestOpenIDRootUrlData:55class TestOpenIDRootUrlData:
51 """`ICanonicalUrlData` for the test OpenID provider."""56 """`ICanonicalUrlData` for the test OpenID provider."""
5257
5358
=== modified file 'utilities/sourcedeps.conf'
--- utilities/sourcedeps.conf 2010-03-26 17:53:41 +0000
+++ utilities/sourcedeps.conf 2010-04-05 12:47:32 +0000
@@ -15,5 +15,4 @@
15subunit lp:~launchpad-pqm/subunit/trunk;revno=6115subunit lp:~launchpad-pqm/subunit/trunk;revno=61
16subvertpy lp:~launchpad-pqm/subvertpy/trunk;revno=204016subvertpy lp:~launchpad-pqm/subvertpy/trunk;revno=2040
17testresources lp:~launchpad-pqm/testresources/dev;revno=1617testresources lp:~launchpad-pqm/testresources/dev;revno=16
18canonical-identity-provider lp:~launchpad-pqm/canonical-identity-provider/trunk;revno=8903 optional
19shipit lp:~launchpad-pqm/shipit/trunk;revno=8903 optional18shipit lp:~launchpad-pqm/shipit/trunk;revno=8903 optional

Subscribers

People subscribed via source and target branches

to status/vote changes: