Merge lp:~salgado/launchpad/remove-auth-store into lp:launchpad/db-devel
- remove-auth-store
- Merge into db-devel
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Stuart Bishop (community) | Approve | ||
Review via email: mp+22478@code.launchpad.net |
Commit message
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>
Guilherme Salgado (salgado) wrote : | # |
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://
http://
They're trivial, though.
>
>
>
> > === modified file 'lib/canonical/
> > --- lib/canonical/
> > +++ lib/canonical/
> > @@ -22,7 +22,7 @@
> > """Base tests for the OAuth database classes."""
> > layer = DatabaseFunctio
> >
> > - def test__get_
> > + def test__get_
> > """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/
> > 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.
> > except ValueError:
> > raise AssertionError(
> > 'Connection uri %s does not match section-
> > % repr(self.
>
> 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/
> > -
> > -A MASTER_FLAVOR Store does not allow writes to tables outside of that
> > -Store's replication set.
> > -
> > - >>> t = transaction.begin()
> > - >>> person = main_master.
> > - >>> a...
1 | === modified file 'lib/canonical/launchpad/webapp/adapter.py' | |||
2 | --- lib/canonical/launchpad/webapp/adapter.py 2010-03-30 17:25:52 +0000 | |||
3 | +++ lib/canonical/launchpad/webapp/adapter.py 2010-04-01 15:26:28 +0000 | |||
4 | @@ -349,9 +349,6 @@ | |||
5 | 349 | raise StormAccessFromMainThread() | 349 | raise StormAccessFromMainThread() |
6 | 350 | 350 | ||
7 | 351 | try: | 351 | try: |
8 | 352 | # XXX: Salgado, 2010-03-22: We can get rid of the realm now that | ||
9 | 353 | # the auth DB is gone, but I'm not doing it in this branch to keep | ||
10 | 354 | # the diff simple. | ||
11 | 355 | config_section, realm, flavor = self._uri.database.split('-') | 352 | config_section, realm, flavor = self._uri.database.split('-') |
12 | 356 | except ValueError: | 353 | except ValueError: |
13 | 357 | raise AssertionError( | 354 | raise AssertionError( |
14 | 358 | 355 | ||
15 | === modified file 'lib/canonical/launchpad/webapp/interfaces.py' | |||
16 | --- lib/canonical/launchpad/webapp/interfaces.py 2010-03-30 17:25:52 +0000 | |||
17 | +++ lib/canonical/launchpad/webapp/interfaces.py 2010-04-01 15:37:19 +0000 | |||
18 | @@ -745,6 +745,7 @@ | |||
19 | 745 | # | 745 | # |
20 | 746 | 746 | ||
21 | 747 | MAIN_STORE = 'main' # The main database. | 747 | MAIN_STORE = 'main' # The main database. |
22 | 748 | ALL_STORES = frozenset([MAIN_STORE]) | ||
23 | 748 | 749 | ||
24 | 749 | DEFAULT_FLAVOR = 'default' # Default flavor for current state. | 750 | DEFAULT_FLAVOR = 'default' # Default flavor for current state. |
25 | 750 | MASTER_FLAVOR = 'master' # The master database. | 751 | MASTER_FLAVOR = 'master' # The master database. |
26 | @@ -771,9 +772,6 @@ | |||
27 | 771 | utility. | 772 | utility. |
28 | 772 | """ | 773 | """ |
29 | 773 | 774 | ||
30 | 774 | # XXX: 2010-03-24, Guilherme Salgado: The 'name' argument will always be | ||
31 | 775 | # MAIN_STORE here, so it can be removed. Not doing it now as this branch | ||
32 | 776 | # will be CPed into production. | ||
33 | 777 | def getStore(name, flavor): | 775 | def getStore(name, flavor): |
34 | 778 | """Retrieve a Store. | 776 | """Retrieve a Store. |
35 | 779 | 777 | ||
36 | @@ -843,9 +841,6 @@ | |||
37 | 843 | def get_current(): | 841 | def get_current(): |
38 | 844 | """Return the currently installed `IDatabasePolicy`.""" | 842 | """Return the currently installed `IDatabasePolicy`.""" |
39 | 845 | 843 | ||
40 | 846 | # XXX: 2010-03-24, Guilherme Salgado: The 'name' argument will always be | ||
41 | 847 | # MAIN_STORE here, so it can be removed. Not doing it now as this branch | ||
42 | 848 | # will be CPed into production. | ||
43 | 849 | def get(name, flavor): | 844 | def get(name, flavor): |
44 | 850 | """Retrieve a Storm Store. | 845 | """Retrieve a Storm Store. |
45 | 851 | 846 | ||
46 | 852 | 847 | ||
47 | === modified file 'lib/canonical/launchpad/webapp/tests/test_dbpolicy.py' | |||
48 | --- lib/canonical/launchpad/webapp/tests/test_dbpolicy.py 2010-03-24 15:22:26 +0000 | |||
49 | +++ lib/canonical/launchpad/webapp/tests/test_dbpolicy.py 2010-04-01 15:39:56 +0000 | |||
50 | @@ -25,7 +25,7 @@ | |||
51 | 25 | ReadOnlyLaunchpadDatabasePolicy, SlaveDatabasePolicy, | 25 | ReadOnlyLaunchpadDatabasePolicy, SlaveDatabasePolicy, |
52 | 26 | SlaveOnlyDatabasePolicy) | 26 | SlaveOnlyDatabasePolicy) |
53 | 27 | from canonical.launchpad.webapp.interfaces import ( | 27 | from canonical.launchpad.webapp.interfaces import ( |
55 | 28 | DEFAULT_FLAVOR, DisallowedStore, IDatabasePolicy, | 28 | ALL_STORES, DEFAULT_FLAVOR, DisallowedStore, IDatabasePolicy, |
56 | 29 | IStoreSelector, MAIN_STORE, MASTER_FLAVOR, ReadOnlyModeDisallowedStore, | 29 | IStoreSelector, MAIN_STORE, MASTER_FLAVOR, ReadOnlyModeDisallowedStore, |
57 | 30 | SLAVE_FLAVOR) | 30 | SLAVE_FLAVOR) |
58 | 31 | from canonical.launchpad.webapp.servers import LaunchpadTestRequest | 31 | from canonical.launchpad.webapp.servers import LaunchpadTestRequest |
59 | @@ -37,9 +37,10 @@ | |||
60 | 37 | layer = DatabaseFunctionalLayer | 37 | layer = DatabaseFunctionalLayer |
61 | 38 | 38 | ||
62 | 39 | def test_defaults(self): | 39 | def test_defaults(self): |
66 | 40 | self.assertProvides( | 40 | for store in ALL_STORES: |
67 | 41 | getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR), | 41 | self.assertProvides( |
68 | 42 | IMasterStore) | 42 | getUtility(IStoreSelector).get(store, DEFAULT_FLAVOR), |
69 | 43 | IMasterStore) | ||
70 | 43 | 44 | ||
71 | 44 | def test_dbusers(self): | 45 | def test_dbusers(self): |
72 | 45 | store_selector = getUtility(IStoreSelector) | 46 | store_selector = getUtility(IStoreSelector) |
73 | @@ -79,14 +80,16 @@ | |||
74 | 79 | super(SlaveDatabasePolicyTestCase, self).setUp() | 80 | super(SlaveDatabasePolicyTestCase, self).setUp() |
75 | 80 | 81 | ||
76 | 81 | def test_defaults(self): | 82 | def test_defaults(self): |
80 | 82 | self.assertProvides( | 83 | for store in ALL_STORES: |
81 | 83 | getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR), | 84 | self.assertProvides( |
82 | 84 | ISlaveStore) | 85 | getUtility(IStoreSelector).get(store, DEFAULT_FLAVOR), |
83 | 86 | ISlaveStore) | ||
84 | 85 | 87 | ||
85 | 86 | def test_master_allowed(self): | 88 | def test_master_allowed(self): |
89 | 87 | self.assertProvides( | 89 | for store in ALL_STORES: |
90 | 88 | getUtility(IStoreSelector).get(MAIN_STORE, MASTER_FLAVOR), | 90 | self.assertProvides( |
91 | 89 | IMasterStore) | 91 | getUtility(IStoreSelector).get(store, MASTER_FLAVOR), |
92 | 92 | IMasterStore) | ||
93 | 90 | 93 | ||
94 | 91 | 94 | ||
95 | 92 | class SlaveOnlyDatabasePolicyTestCase(SlaveDatabasePolicyTestCase): | 95 | class SlaveOnlyDatabasePolicyTestCase(SlaveDatabasePolicyTestCase): |
96 | @@ -97,15 +100,10 @@ | |||
97 | 97 | super(SlaveOnlyDatabasePolicyTestCase, self).setUp() | 100 | super(SlaveOnlyDatabasePolicyTestCase, self).setUp() |
98 | 98 | 101 | ||
99 | 99 | def test_master_allowed(self): | 102 | def test_master_allowed(self): |
109 | 100 | # The master store is not allowed here, but we need this empty test | 103 | for store in ALL_STORES: |
110 | 101 | # to overwrite the test method from our parent class, where the master | 104 | self.failUnlessRaises( |
111 | 102 | # store is allowed. | 105 | DisallowedStore, |
112 | 103 | pass | 106 | getUtility(IStoreSelector).get, store, MASTER_FLAVOR) |
104 | 104 | |||
105 | 105 | def test_master_not_allowed(self): | ||
106 | 106 | self.failUnlessRaises( | ||
107 | 107 | DisallowedStore, | ||
108 | 108 | getUtility(IStoreSelector).get, MAIN_STORE, MASTER_FLAVOR) | ||
113 | 109 | 107 | ||
114 | 110 | 108 | ||
115 | 111 | class MasterDatabasePolicyTestCase(BaseDatabasePolicyTestCase): | 109 | class MasterDatabasePolicyTestCase(BaseDatabasePolicyTestCase): |
116 | @@ -129,9 +127,10 @@ | |||
117 | 129 | 127 | ||
118 | 130 | def test_slave_allowed(self): | 128 | def test_slave_allowed(self): |
119 | 131 | # We get the master store even if the slave was requested. | 129 | # We get the master store even if the slave was requested. |
123 | 132 | self.assertProvides( | 130 | for store in ALL_STORES: |
124 | 133 | getUtility(IStoreSelector).get(MAIN_STORE, SLAVE_FLAVOR), | 131 | self.assertProvides( |
125 | 134 | ISlaveStore) | 132 | getUtility(IStoreSelector).get(store, SLAVE_FLAVOR), |
126 | 133 | ISlaveStore) | ||
127 | 135 | 134 | ||
128 | 136 | 135 | ||
129 | 137 | class LaunchpadDatabasePolicyTestCase(SlaveDatabasePolicyTestCase): | 136 | class LaunchpadDatabasePolicyTestCase(SlaveDatabasePolicyTestCase): |
130 | @@ -245,20 +244,23 @@ | |||
131 | 245 | 244 | ||
132 | 246 | def test_defaults(self): | 245 | def test_defaults(self): |
133 | 247 | # default Store is the slave. | 246 | # default Store is the slave. |
137 | 248 | self.assertProvides( | 247 | for store in ALL_STORES: |
138 | 249 | getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR), | 248 | self.assertProvides( |
139 | 250 | ISlaveStore) | 249 | getUtility(IStoreSelector).get(store, DEFAULT_FLAVOR), |
140 | 250 | ISlaveStore) | ||
141 | 251 | 251 | ||
142 | 252 | def test_slave_allowed(self): | 252 | def test_slave_allowed(self): |
146 | 253 | self.assertProvides( | 253 | for store in ALL_STORES: |
147 | 254 | getUtility(IStoreSelector).get(MAIN_STORE, SLAVE_FLAVOR), | 254 | self.assertProvides( |
148 | 255 | ISlaveStore) | 255 | getUtility(IStoreSelector).get(store, SLAVE_FLAVOR), |
149 | 256 | ISlaveStore) | ||
150 | 256 | 257 | ||
151 | 257 | def test_master_disallowed(self): | 258 | def test_master_disallowed(self): |
152 | 258 | store_selector = getUtility(IStoreSelector) | 259 | store_selector = getUtility(IStoreSelector) |
156 | 259 | self.assertRaises( | 260 | for store in ALL_STORES: |
157 | 260 | ReadOnlyModeDisallowedStore, | 261 | self.assertRaises( |
158 | 261 | store_selector.get, MAIN_STORE, MASTER_FLAVOR) | 262 | ReadOnlyModeDisallowedStore, |
159 | 263 | store_selector.get, store, MASTER_FLAVOR) | ||
160 | 262 | 264 | ||
161 | 263 | 265 | ||
162 | 264 | def test_suite(): | 266 | def test_suite(): |
163 | 265 | 267 |
Preview Diff
1 | === modified file 'configs/development/launchpad-lazr.conf' | |||
2 | --- configs/development/launchpad-lazr.conf 2010-03-05 20:49:31 +0000 | |||
3 | +++ configs/development/launchpad-lazr.conf 2010-04-05 12:47:32 +0000 | |||
4 | @@ -97,8 +97,6 @@ | |||
5 | 97 | # the rw_* configs. | 97 | # the rw_* configs. |
6 | 98 | ro_main_master: dbname=launchpad_dev_template | 98 | ro_main_master: dbname=launchpad_dev_template |
7 | 99 | ro_main_slave: dbname=launchpad_dev_template | 99 | ro_main_slave: dbname=launchpad_dev_template |
8 | 100 | auth_master: dbname=launchpad_dev | ||
9 | 101 | auth_slave: dbname=launchpad_dev | ||
10 | 102 | 100 | ||
11 | 103 | [distributionmirrorprober] | 101 | [distributionmirrorprober] |
12 | 104 | use_proxy: False | 102 | use_proxy: False |
13 | 105 | 103 | ||
14 | === modified file 'configs/replicated-development/launchpad-lazr.conf' | |||
15 | --- configs/replicated-development/launchpad-lazr.conf 2010-01-05 19:09:58 +0000 | |||
16 | +++ configs/replicated-development/launchpad-lazr.conf 2010-04-05 12:47:32 +0000 | |||
17 | @@ -10,6 +10,3 @@ | |||
18 | 10 | rw_main_slave: dbname=launchpad_dev_slave | 10 | rw_main_slave: dbname=launchpad_dev_slave |
19 | 11 | ro_main_master: dbname=launchpad_dev | 11 | ro_main_master: dbname=launchpad_dev |
20 | 12 | ro_main_slave: dbname=launchpad_dev_slave | 12 | ro_main_slave: dbname=launchpad_dev_slave |
21 | 13 | auth_master: dbname=launchpad_dev | ||
22 | 14 | auth_slave: dbname=launchpad_dev_slave | ||
23 | 15 | |||
24 | 16 | 13 | ||
25 | === modified file 'configs/test-playground/launchpad-lazr.conf' | |||
26 | --- configs/test-playground/launchpad-lazr.conf 2010-01-05 19:09:58 +0000 | |||
27 | +++ configs/test-playground/launchpad-lazr.conf 2010-04-05 12:47:32 +0000 | |||
28 | @@ -10,5 +10,3 @@ | |||
29 | 10 | rw_main_slave: dbname=launchpad_ftest_playground | 10 | rw_main_slave: dbname=launchpad_ftest_playground |
30 | 11 | ro_main_master: dbname=launchpad_ftest_playground | 11 | ro_main_master: dbname=launchpad_ftest_playground |
31 | 12 | ro_main_slave: dbname=launchpad_ftest_playground | 12 | ro_main_slave: dbname=launchpad_ftest_playground |
32 | 13 | auth_master: dbname=launchpad_ftest_playground | ||
33 | 14 | auth_slave: dbname=launchpad_ftest_playground | ||
34 | 15 | 13 | ||
35 | === modified file 'configs/testrunner/launchpad-lazr.conf' | |||
36 | --- configs/testrunner/launchpad-lazr.conf 2010-03-11 01:39:25 +0000 | |||
37 | +++ configs/testrunner/launchpad-lazr.conf 2010-04-05 12:47:32 +0000 | |||
38 | @@ -51,8 +51,6 @@ | |||
39 | 51 | # the rw_* configs. | 51 | # the rw_* configs. |
40 | 52 | ro_main_master: dbname=launchpad_ftest_template | 52 | ro_main_master: dbname=launchpad_ftest_template |
41 | 53 | ro_main_slave: dbname=launchpad_ftest_template | 53 | ro_main_slave: dbname=launchpad_ftest_template |
42 | 54 | auth_master: dbname=launchpad_ftest | ||
43 | 55 | auth_slave: dbname=launchpad_ftest | ||
44 | 56 | randomise_select_results: true | 54 | randomise_select_results: true |
45 | 57 | 55 | ||
46 | 58 | [error_reports] | 56 | [error_reports] |
47 | 59 | 57 | ||
48 | === modified file 'database/schema/security.cfg' | |||
49 | --- database/schema/security.cfg 2010-04-02 17:29:13 +0000 | |||
50 | +++ database/schema/security.cfg 2010-04-05 12:47:32 +0000 | |||
51 | @@ -118,7 +118,8 @@ | |||
52 | 118 | # lpmain replication set access from the main Z3 application. | 118 | # lpmain replication set access from the main Z3 application. |
53 | 119 | type=user | 119 | type=user |
54 | 120 | groups=write,script | 120 | groups=write,script |
56 | 121 | public.account = SELECT | 121 | public.account = SELECT, INSERT, UPDATE, DELETE |
57 | 122 | public.accountpassword = SELECT, INSERT, UPDATE, DELETE | ||
58 | 122 | public.announcement = SELECT, INSERT, UPDATE, DELETE | 123 | public.announcement = SELECT, INSERT, UPDATE, DELETE |
59 | 123 | public.answercontact = SELECT, INSERT, UPDATE, DELETE | 124 | public.answercontact = SELECT, INSERT, UPDATE, DELETE |
60 | 124 | public.apportjob = SELECT, INSERT, UPDATE, DELETE | 125 | public.apportjob = SELECT, INSERT, UPDATE, DELETE |
61 | @@ -176,7 +177,7 @@ | |||
62 | 176 | public.distributionsourcepackagecache = SELECT | 177 | public.distributionsourcepackagecache = SELECT |
63 | 177 | public.distroserieslanguage = SELECT, INSERT, UPDATE | 178 | public.distroserieslanguage = SELECT, INSERT, UPDATE |
64 | 178 | public.distroseriespackagecache = SELECT | 179 | public.distroseriespackagecache = SELECT |
66 | 179 | public.emailaddress = SELECT | 180 | public.emailaddress = SELECT, INSERT, UPDATE, DELETE |
67 | 180 | public.entitlement = SELECT, INSERT, UPDATE, DELETE | 181 | public.entitlement = SELECT, INSERT, UPDATE, DELETE |
68 | 181 | public.faq = SELECT, INSERT, UPDATE, DELETE | 182 | public.faq = SELECT, INSERT, UPDATE, DELETE |
69 | 182 | public.featuredproject = SELECT, INSERT, DELETE | 183 | public.featuredproject = SELECT, INSERT, DELETE |
70 | @@ -916,6 +917,8 @@ | |||
71 | 916 | # Full access except for tables that are exclusively updated by | 917 | # Full access except for tables that are exclusively updated by |
72 | 917 | # certain processes, such as the librarian tables. This group is deprecated - | 918 | # certain processes, such as the librarian tables. This group is deprecated - |
73 | 918 | # access should be explicitly granted to users. | 919 | # access should be explicitly granted to users. |
74 | 920 | public.account = SELECT, INSERT, UPDATE | ||
75 | 921 | public.accountpassword = SELECT, INSERT | ||
76 | 919 | public.archive = SELECT, INSERT, UPDATE | 922 | public.archive = SELECT, INSERT, UPDATE |
77 | 920 | public.archivearch = SELECT, INSERT, UPDATE, DELETE | 923 | public.archivearch = SELECT, INSERT, UPDATE, DELETE |
78 | 921 | public.binarypackagerelease = SELECT, INSERT, UPDATE | 924 | public.binarypackagerelease = SELECT, INSERT, UPDATE |
79 | @@ -949,6 +952,7 @@ | |||
80 | 949 | public.distribution = SELECT, INSERT, UPDATE | 952 | public.distribution = SELECT, INSERT, UPDATE |
81 | 950 | public.distroarchseries = SELECT, INSERT, UPDATE | 953 | public.distroarchseries = SELECT, INSERT, UPDATE |
82 | 951 | public.distroseries = SELECT, INSERT, UPDATE | 954 | public.distroseries = SELECT, INSERT, UPDATE |
83 | 955 | public.openidrpsummary = SELECT, INSERT, UPDATE | ||
84 | 952 | public.packageupload = SELECT, INSERT, UPDATE | 956 | public.packageupload = SELECT, INSERT, UPDATE |
85 | 953 | public.packageuploadbuild = SELECT, INSERT, UPDATE | 957 | public.packageuploadbuild = SELECT, INSERT, UPDATE |
86 | 954 | public.packageuploadsource = SELECT, INSERT, UPDATE | 958 | public.packageuploadsource = SELECT, INSERT, UPDATE |
87 | 955 | 959 | ||
88 | === modified file 'lib/canonical/buildd/debian/control' | |||
89 | --- lib/canonical/buildd/debian/control 2009-11-17 22:28:43 +0000 | |||
90 | +++ lib/canonical/buildd/debian/control 2010-04-05 12:47:32 +0000 | |||
91 | @@ -8,7 +8,7 @@ | |||
92 | 8 | Package: launchpad-buildd | 8 | Package: launchpad-buildd |
93 | 9 | Section: misc | 9 | Section: misc |
94 | 10 | Architecture: all | 10 | Architecture: all |
96 | 11 | Depends: python-twisted, debootstrap, dpkg-dev, linux32, file, bzip2, sudo, ntpdate, adduser, apt-transport-https | 11 | Depends: python-twisted-core, python-twisted-web, debootstrap, dpkg-dev, linux32, file, bzip2, sudo, ntpdate, adduser, apt-transport-https |
97 | 12 | Description: Launchpad buildd slave | 12 | Description: Launchpad buildd slave |
98 | 13 | This is the launchpad buildd slave package. It contains everything needed to | 13 | This is the launchpad buildd slave package. It contains everything needed to |
99 | 14 | get a launchpad buildd going apart from the database manipulation required to | 14 | get a launchpad buildd going apart from the database manipulation required to |
100 | 15 | 15 | ||
101 | === modified file 'lib/canonical/config/__init__.py' | |||
102 | --- lib/canonical/config/__init__.py 2010-01-14 16:39:18 +0000 | |||
103 | +++ lib/canonical/config/__init__.py 2010-04-05 12:47:32 +0000 | |||
104 | @@ -374,13 +374,13 @@ | |||
105 | 374 | _db_config_attrs = frozenset([ | 374 | _db_config_attrs = frozenset([ |
106 | 375 | 'dbuser', 'auth_dbuser', | 375 | 'dbuser', 'auth_dbuser', |
107 | 376 | 'rw_main_master', 'rw_main_slave', | 376 | 'rw_main_master', 'rw_main_slave', |
109 | 377 | 'ro_main_master', 'ro_main_slave', 'auth_master', 'auth_slave', | 377 | 'ro_main_master', 'ro_main_slave', |
110 | 378 | 'db_statement_timeout', 'db_statement_timeout_precision', | 378 | 'db_statement_timeout', 'db_statement_timeout_precision', |
111 | 379 | 'isolation_level', 'randomise_select_results', | 379 | 'isolation_level', 'randomise_select_results', |
112 | 380 | 'soft_request_timeout', 'storm_cache', 'storm_cache_size']) | 380 | 'soft_request_timeout', 'storm_cache', 'storm_cache_size']) |
113 | 381 | _db_config_required_attrs = frozenset([ | 381 | _db_config_required_attrs = frozenset([ |
114 | 382 | 'dbuser', 'rw_main_master', 'rw_main_slave', 'ro_main_master', | 382 | 'dbuser', 'rw_main_master', 'rw_main_slave', 'ro_main_master', |
116 | 383 | 'ro_main_slave', 'auth_master', 'auth_slave']) | 383 | 'ro_main_slave']) |
117 | 384 | 384 | ||
118 | 385 | @property | 385 | @property |
119 | 386 | def main_master(self): | 386 | def main_master(self): |
120 | 387 | 387 | ||
121 | === modified file 'lib/canonical/config/schema-lazr.conf' | |||
122 | --- lib/canonical/config/schema-lazr.conf 2010-03-24 02:37:55 +0000 | |||
123 | +++ lib/canonical/config/schema-lazr.conf 2010-04-05 12:47:32 +0000 | |||
124 | @@ -559,8 +559,6 @@ | |||
125 | 559 | rw_main_slave: dbname=launchpad_prod_2 host=chokecherry.canonical.com | 559 | rw_main_slave: dbname=launchpad_prod_2 host=chokecherry.canonical.com |
126 | 560 | ro_main_master: dbname=launchpad_standalone_1 host=chokecherry.canonical.com | 560 | ro_main_master: dbname=launchpad_standalone_1 host=chokecherry.canonical.com |
127 | 561 | ro_main_slave: dbname=launchpad_standalone_1 host=chokecherry.canonical.com | 561 | ro_main_slave: dbname=launchpad_standalone_1 host=chokecherry.canonical.com |
128 | 562 | auth_master: dbname=launchpad_prod_3 host=wildcherry.canonical.com | ||
129 | 563 | auth_slave: dbname=launchpad_prod_2 host=chokecherry.canonical.com | ||
130 | 564 | 562 | ||
131 | 565 | # If the replication lag is more than this many seconds, slave databases | 563 | # If the replication lag is more than this many seconds, slave databases |
132 | 566 | # will not be used. | 564 | # will not be used. |
133 | @@ -867,16 +865,10 @@ | |||
134 | 867 | # datatype: integer | 865 | # datatype: integer |
135 | 868 | max_scaling: 500 | 866 | max_scaling: 500 |
136 | 869 | 867 | ||
137 | 870 | [sso] | ||
138 | 871 | dbuser: sso_main | ||
139 | 872 | auth_dbuser: sso_auth | ||
140 | 873 | |||
141 | 874 | |||
142 | 875 | [launchpad] | 868 | [launchpad] |
143 | 876 | # The database user which will be used by this process. | 869 | # The database user which will be used by this process. |
144 | 877 | # datatype: string | 870 | # datatype: string |
145 | 878 | dbuser: launchpad_main | 871 | dbuser: launchpad_main |
146 | 879 | auth_dbuser: launchpad_auth | ||
147 | 880 | storm_cache: generational | 872 | storm_cache: generational |
148 | 881 | storm_cache_size: 10000 | 873 | storm_cache_size: 10000 |
149 | 882 | 874 | ||
150 | 883 | 875 | ||
151 | === modified file 'lib/canonical/configure.zcml' | |||
152 | --- lib/canonical/configure.zcml 2010-01-08 21:23:15 +0000 | |||
153 | +++ lib/canonical/configure.zcml 2010-04-05 12:47:32 +0000 | |||
154 | @@ -154,7 +154,5 @@ | |||
155 | 154 | <include package="canonical.lazr" /> | 154 | <include package="canonical.lazr" /> |
156 | 155 | <include zcml:condition="installed canonical.shipit" | 155 | <include zcml:condition="installed canonical.shipit" |
157 | 156 | package="canonical.shipit" /> | 156 | package="canonical.shipit" /> |
158 | 157 | <include zcml:condition="installed canonical.signon" | ||
159 | 158 | package="canonical.signon" /> | ||
160 | 159 | 157 | ||
161 | 160 | </configure> | 158 | </configure> |
162 | 161 | 159 | ||
163 | === modified file 'lib/canonical/database/harness.py' | |||
164 | --- lib/canonical/database/harness.py 2009-11-05 03:52:51 +0000 | |||
165 | +++ lib/canonical/database/harness.py 2010-04-05 12:47:32 +0000 | |||
166 | @@ -48,8 +48,7 @@ | |||
167 | 48 | from storm.locals import * | 48 | from storm.locals import * |
168 | 49 | from storm.expr import * | 49 | from storm.expr import * |
169 | 50 | from canonical.launchpad.webapp.interfaces import ( | 50 | from canonical.launchpad.webapp.interfaces import ( |
172 | 51 | IStoreSelector, MAIN_STORE, AUTH_STORE, MASTER_FLAVOR, | 51 | IStoreSelector, MAIN_STORE, MASTER_FLAVOR, SLAVE_FLAVOR, DEFAULT_FLAVOR) |
171 | 52 | SLAVE_FLAVOR, DEFAULT_FLAVOR) | ||
173 | 53 | 52 | ||
174 | 54 | 53 | ||
175 | 55 | def switch_db_user(dbuser, commit_first=True): | 54 | def switch_db_user(dbuser, commit_first=True): |
176 | 56 | 55 | ||
177 | === modified file 'lib/canonical/database/sqlbase.py' | |||
178 | --- lib/canonical/database/sqlbase.py 2010-03-23 15:04:41 +0000 | |||
179 | +++ lib/canonical/database/sqlbase.py 2010-04-05 12:47:32 +0000 | |||
180 | @@ -271,7 +271,6 @@ | |||
181 | 271 | # This is only used by scripts, so we must connect to the read-write | 271 | # This is only used by scripts, so we must connect to the read-write |
182 | 272 | # DB here -- that's why we use rw_main_master directly. | 272 | # DB here -- that's why we use rw_main_master directly. |
183 | 273 | main_connection_string = dbconfig.rw_main_master | 273 | main_connection_string = dbconfig.rw_main_master |
184 | 274 | auth_connection_string = dbconfig.auth_master | ||
185 | 275 | 274 | ||
186 | 276 | # Override dbname and dbhost in the connection string if they | 275 | # Override dbname and dbhost in the connection string if they |
187 | 277 | # have been passed in. | 276 | # have been passed in. |
188 | @@ -290,7 +289,7 @@ | |||
189 | 290 | match = re.search(r'host=(\S*)', main_connection_string) | 289 | match = re.search(r'host=(\S*)', main_connection_string) |
190 | 291 | if match is not None: | 290 | if match is not None: |
191 | 292 | dbhost = match.group(1) | 291 | dbhost = match.group(1) |
193 | 293 | return main_connection_string, auth_connection_string, dbname, dbhost | 292 | return main_connection_string, dbname, dbhost |
194 | 294 | 293 | ||
195 | 295 | @classmethod | 294 | @classmethod |
196 | 296 | def initZopeless(cls, dbname=None, dbhost=None, dbuser=None, | 295 | def initZopeless(cls, dbname=None, dbhost=None, dbuser=None, |
197 | @@ -298,7 +297,7 @@ | |||
198 | 298 | # Connect to the auth master store as well, as some scripts might need | 297 | # Connect to the auth master store as well, as some scripts might need |
199 | 299 | # to create EmailAddresses and Accounts. | 298 | # to create EmailAddresses and Accounts. |
200 | 300 | 299 | ||
202 | 301 | main_connection_string, auth_connection_string, dbname, dbhost = ( | 300 | main_connection_string, dbname, dbhost = ( |
203 | 302 | cls._get_zopeless_connection_config(dbname, dbhost)) | 301 | cls._get_zopeless_connection_config(dbname, dbhost)) |
204 | 303 | 302 | ||
205 | 304 | assert dbuser is not None, ''' | 303 | assert dbuser is not None, ''' |
206 | @@ -315,7 +314,6 @@ | |||
207 | 315 | overlay = dedent("""\ | 314 | overlay = dedent("""\ |
208 | 316 | [database] | 315 | [database] |
209 | 317 | rw_main_master: %(main_connection_string)s | 316 | rw_main_master: %(main_connection_string)s |
210 | 318 | auth_master: %(auth_connection_string)s | ||
211 | 319 | isolation_level: %(isolation_level)s | 317 | isolation_level: %(isolation_level)s |
212 | 320 | """ % vars()) | 318 | """ % vars()) |
213 | 321 | 319 | ||
214 | 322 | 320 | ||
215 | === modified file 'lib/canonical/database/tests/test_zopeless_transaction_manager.py' | |||
216 | --- lib/canonical/database/tests/test_zopeless_transaction_manager.py 2009-12-14 17:38:34 +0000 | |||
217 | +++ lib/canonical/database/tests/test_zopeless_transaction_manager.py 2010-04-05 12:47:32 +0000 | |||
218 | @@ -1,48 +1,17 @@ | |||
219 | 1 | # Copyright 2009 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009 Canonical Ltd. This software is licensed under the |
220 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
221 | 3 | 3 | ||
222 | 4 | from textwrap import dedent | ||
223 | 5 | import unittest | 4 | import unittest |
224 | 6 | 5 | ||
225 | 7 | from zope.component import getUtility | 6 | from zope.component import getUtility |
226 | 8 | 7 | ||
227 | 9 | from storm.zope.interfaces import IZStorm | 8 | from storm.zope.interfaces import IZStorm |
228 | 10 | 9 | ||
229 | 11 | from canonical.config import config | ||
230 | 12 | from canonical.database.sqlbase import ZopelessTransactionManager | 10 | from canonical.database.sqlbase import ZopelessTransactionManager |
231 | 13 | from canonical.testing.layers import LaunchpadZopelessLayer | 11 | from canonical.testing.layers import LaunchpadZopelessLayer |
232 | 14 | from lp.testing import TestCase | 12 | from lp.testing import TestCase |
233 | 15 | 13 | ||
234 | 16 | 14 | ||
235 | 17 | class TestZopelessTransactionManagerNoLayer(TestCase): | ||
236 | 18 | |||
237 | 19 | def test_initZopeless_connects_to_auth_master_db(self): | ||
238 | 20 | # Some scripts might create EmailAddress and Account entries, so | ||
239 | 21 | # initZopeless has to connect to the auth master db. This is a | ||
240 | 22 | # bugfix test. The error that this test detects is that the | ||
241 | 23 | # script used to use the main_master database for the | ||
242 | 24 | # auth_master. In this test, we make sure that the auth_master | ||
243 | 25 | # and main_master have different values in the config, and then | ||
244 | 26 | # show that they are honored. Prior to the fix, ``auth_master`` | ||
245 | 27 | # would have been changed to the same value as ``main_master``. | ||
246 | 28 | # Now we set up our test data and push it on the config. | ||
247 | 29 | auth_master = "dbname=example_launchpad_auth_does_not_exist" | ||
248 | 30 | overlay = dedent(""" | ||
249 | 31 | [database] | ||
250 | 32 | main_master: dbname=launchpad_dev | ||
251 | 33 | auth_master: %s | ||
252 | 34 | """ % (auth_master,)) | ||
253 | 35 | config.push('new-db', overlay) | ||
254 | 36 | try: | ||
255 | 37 | main_connection_string, auth_connection_string, dbname, dbhost = ( | ||
256 | 38 | ZopelessTransactionManager._get_zopeless_connection_config( | ||
257 | 39 | None, None)) | ||
258 | 40 | self.assertEqual(auth_connection_string, auth_master) | ||
259 | 41 | finally: | ||
260 | 42 | # Clean up the configuration | ||
261 | 43 | config.pop('new-db') | ||
262 | 44 | |||
263 | 45 | |||
264 | 46 | class TestZopelessTransactionManager(TestCase): | 15 | class TestZopelessTransactionManager(TestCase): |
265 | 47 | layer = LaunchpadZopelessLayer | 16 | layer = LaunchpadZopelessLayer |
266 | 48 | 17 | ||
267 | 49 | 18 | ||
268 | === modified file 'lib/canonical/launchpad/database/tests/test_oauth.py' | |||
269 | --- lib/canonical/launchpad/database/tests/test_oauth.py 2009-06-25 05:30:52 +0000 | |||
270 | +++ lib/canonical/launchpad/database/tests/test_oauth.py 2010-04-05 12:47:32 +0000 | |||
271 | @@ -22,7 +22,7 @@ | |||
272 | 22 | """Base tests for the OAuth database classes.""" | 22 | """Base tests for the OAuth database classes.""" |
273 | 23 | layer = DatabaseFunctionalLayer | 23 | layer = DatabaseFunctionalLayer |
274 | 24 | 24 | ||
276 | 25 | def test__get_store_should_return_the_auth_master_store(self): | 25 | def test__get_store_should_return_the_main_master_store(self): |
277 | 26 | """We want all OAuth classes to use the master store. | 26 | """We want all OAuth classes to use the master store. |
278 | 27 | Otherwise, the OAuth exchanges will fail because the authorize | 27 | Otherwise, the OAuth exchanges will fail because the authorize |
279 | 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. |
280 | 29 | 29 | ||
281 | === modified file 'lib/canonical/launchpad/doc/account.txt' | |||
282 | --- lib/canonical/launchpad/doc/account.txt 2010-02-12 15:57:27 +0000 | |||
283 | +++ lib/canonical/launchpad/doc/account.txt 2010-04-05 12:47:32 +0000 | |||
284 | @@ -196,32 +196,6 @@ | |||
285 | 196 | >>> account.status = AccountStatus.ACTIVE | 196 | >>> account.status = AccountStatus.ACTIVE |
286 | 197 | >>> login('no-priv@canonical.com') | 197 | >>> login('no-priv@canonical.com') |
287 | 198 | 198 | ||
288 | 199 | The Account's displayname is synced to the Person's displayname if there | ||
289 | 200 | is one. If the Person.displayname is changed, the Account.displayname is | ||
290 | 201 | changed too. | ||
291 | 202 | |||
292 | 203 | >>> from canonical.launchpad.interfaces import IPersonSet | ||
293 | 204 | |||
294 | 205 | >>> personset = getUtility(IPersonSet) | ||
295 | 206 | >>> person = personset.getByEmail('no-priv@canonical.com') | ||
296 | 207 | >>> person.displayname = 'Something New' | ||
297 | 208 | >>> print account.displayname | ||
298 | 209 | Something New | ||
299 | 210 | |||
300 | 211 | However, the reverse is not true. If we change the Account.displayname, | ||
301 | 212 | the linked Person.displayname (if there is one) is not updated | ||
302 | 213 | immediately. Instead, a cron job will sync this information later. This | ||
303 | 214 | allows displayname changes to happen even when the Person table is | ||
304 | 215 | unavailable. | ||
305 | 216 | |||
306 | 217 | >>> account.displayname = 'No Privileges Account' | ||
307 | 218 | >>> print person.displayname | ||
308 | 219 | Something New | ||
309 | 220 | |||
310 | 221 | >>> person.displayname = 'No Privileges Person' | ||
311 | 222 | >>> print account.displayname | ||
312 | 223 | No Privileges Person | ||
313 | 224 | |||
314 | 225 | An Account has an OpenID identifier used to generate the OpenID identity | 199 | An Account has an OpenID identifier used to generate the OpenID identity |
315 | 226 | URL. | 200 | URL. |
316 | 227 | 201 | ||
317 | @@ -242,6 +216,7 @@ | |||
318 | 242 | >>> login('admin@canonical.com') | 216 | >>> login('admin@canonical.com') |
319 | 243 | >>> passwordless_account = account_set.new( | 217 | >>> passwordless_account = account_set.new( |
320 | 244 | ... AccountCreationRationale.USER_CREATED, 'Passwordless') | 218 | ... AccountCreationRationale.USER_CREATED, 'Passwordless') |
321 | 219 | >>> transaction.commit() | ||
322 | 245 | >>> print passwordless_account.creation_rationale.name | 220 | >>> print passwordless_account.creation_rationale.name |
323 | 246 | USER_CREATED | 221 | USER_CREATED |
324 | 247 | >>> print passwordless_account.displayname | 222 | >>> print passwordless_account.displayname |
325 | 248 | 223 | ||
326 | === modified file 'lib/canonical/launchpad/doc/storm.txt' | |||
327 | --- lib/canonical/launchpad/doc/storm.txt 2010-02-22 10:33:10 +0000 | |||
328 | +++ lib/canonical/launchpad/doc/storm.txt 2010-04-05 12:47:32 +0000 | |||
329 | @@ -7,10 +7,11 @@ | |||
330 | 7 | specific Storm tools to cope with our master and slave store arrangement. | 7 | specific Storm tools to cope with our master and slave store arrangement. |
331 | 8 | 8 | ||
332 | 9 | >>> from canonical.launchpad.interfaces import ( | 9 | >>> from canonical.launchpad.interfaces import ( |
334 | 10 | ... EmailAddressStatus, IAccountSet, IEmailAddressSet, | 10 | ... EmailAddressStatus, IEmailAddressSet, |
335 | 11 | ... IMasterObject, IMasterStore, ISlaveStore, IStore) | 11 | ... IMasterObject, IMasterStore, ISlaveStore, IStore) |
336 | 12 | >>> from canonical.launchpad.database import ( | 12 | >>> from canonical.launchpad.database import ( |
337 | 13 | ... Account, AccountPassword, EmailAddress) | 13 | ... Account, AccountPassword, EmailAddress) |
338 | 14 | >>> from lp.registry.interfaces.person import IPersonSet | ||
339 | 14 | >>> from lp.registry.model.person import Person | 15 | >>> from lp.registry.model.person import Person |
340 | 15 | >>> from zope.security.proxy import ProxyFactory | 16 | >>> from zope.security.proxy import ProxyFactory |
341 | 16 | 17 | ||
342 | @@ -19,30 +20,14 @@ | |||
343 | 19 | a Launchpad database object. You can use adapters to | 20 | a Launchpad database object. You can use adapters to |
344 | 20 | retrieve the correct Store. | 21 | retrieve the correct Store. |
345 | 21 | 22 | ||
346 | 22 | >>> auth_master = IMasterStore(Account) | ||
347 | 23 | >>> main_master = IMasterStore(Person) | 23 | >>> main_master = IMasterStore(Person) |
348 | 24 | >>> auth_master is main_master | ||
349 | 25 | False | ||
350 | 26 | |||
351 | 27 | |||
352 | 28 | You can read most tables from any Store, which is required for doing | ||
353 | 29 | fast joins in the database. However, when it is not necessary to | ||
354 | 30 | retrieve objects from the same store as another object, it is better to | ||
355 | 31 | explicitly use the explicit Store for its replication set. Some tables | ||
356 | 32 | are only available from this store, such as the AccountPassword table. | ||
357 | 33 | |||
358 | 34 | >>> auth_slave = ISlaveStore(AccountPassword) | ||
359 | 35 | >>> main_slave = ISlaveStore(Person) | ||
360 | 36 | >>> auth_slave is main_slave | ||
361 | 37 | False | ||
362 | 38 | |||
363 | 39 | 24 | ||
364 | 40 | You can detect if a store is writable by checking what interfaces it | 25 | You can detect if a store is writable by checking what interfaces it |
365 | 41 | provides. | 26 | provides. |
366 | 42 | 27 | ||
368 | 43 | >>> IMasterStore.providedBy(auth_master) | 28 | >>> IMasterStore.providedBy(main_master) |
369 | 44 | True | 29 | True |
371 | 45 | >>> ISlaveStore.providedBy(auth_master) | 30 | >>> ISlaveStore.providedBy(main_master) |
372 | 46 | False | 31 | False |
373 | 47 | 32 | ||
374 | 48 | 33 | ||
375 | @@ -53,7 +38,6 @@ | |||
376 | 53 | Otherwise, it gives you the master. See IStoreSelector for details. | 38 | Otherwise, it gives you the master. See IStoreSelector for details. |
377 | 54 | 39 | ||
378 | 55 | >>> main_default = IStore(Person) | 40 | >>> main_default = IStore(Person) |
379 | 56 | >>> main_master = IMasterStore(Person) | ||
380 | 57 | >>> main_slave = ISlaveStore(Person) | 41 | >>> main_slave = ISlaveStore(Person) |
381 | 58 | >>> main_default is main_master | 42 | >>> main_default is main_master |
382 | 59 | True | 43 | True |
383 | @@ -78,11 +62,10 @@ | |||
384 | 78 | changes to an object, just in case you have been passed an instance | 62 | changes to an object, just in case you have been passed an instance |
385 | 79 | from a store other than the correct Master. | 63 | from a store other than the correct Master. |
386 | 80 | 64 | ||
388 | 81 | >>> auth_slave = ISlaveStore(Account) | 65 | >>> main_slave = ISlaveStore(Person) |
389 | 82 | >>> t = transaction.begin() | 66 | >>> t = transaction.begin() |
393 | 83 | >>> account = auth_slave.find( | 67 | >>> person = main_slave.find(Person, name='mark').one() |
394 | 84 | ... Account, openid_identifier='mark_oid').one() | 68 | >>> person.displayname = 'Cannot change' |
392 | 85 | >>> account.displayname = 'Cannot change' | ||
395 | 86 | >>> transaction.commit() | 69 | >>> transaction.commit() |
396 | 87 | Traceback (most recent call last): | 70 | Traceback (most recent call last): |
397 | 88 | ... | 71 | ... |
398 | @@ -90,9 +73,8 @@ | |||
399 | 90 | 73 | ||
400 | 91 | >>> transaction.abort() | 74 | >>> transaction.abort() |
401 | 92 | >>> t = transaction.begin() | 75 | >>> t = transaction.begin() |
405 | 93 | >>> account = auth_slave.find( | 76 | >>> person = main_slave.find(Person, name='mark').one() |
406 | 94 | ... Account, openid_identifier='mark_oid').one() | 77 | >>> IMasterObject(person).displayname = 'Can change' |
404 | 95 | >>> IMasterObject(account).displayname = 'Can change' | ||
407 | 96 | >>> transaction.commit() | 78 | >>> transaction.commit() |
408 | 97 | 79 | ||
409 | 98 | 80 | ||
410 | @@ -100,61 +82,60 @@ | |||
411 | 100 | similarly wrapped. | 82 | similarly wrapped. |
412 | 101 | 83 | ||
413 | 102 | >>> from zope.security.proxy import removeSecurityProxy | 84 | >>> from zope.security.proxy import removeSecurityProxy |
436 | 103 | >>> account = getUtility(IAccountSet).getByEmail('no-priv@canonical.com') | 85 | >>> person = getUtility(IPersonSet).getByEmail('no-priv@canonical.com') |
437 | 104 | >>> removeSecurityProxy(account) is account | 86 | >>> removeSecurityProxy(person) is person |
438 | 105 | False | 87 | False |
439 | 106 | >>> account.displayname | 88 | >>> person.displayname |
440 | 107 | u'No Privileges Person' | 89 | u'No Privileges Person' |
441 | 108 | >>> account.password | 90 | >>> person.name = 'foo' |
442 | 109 | Traceback (most recent call last): | 91 | Traceback (most recent call last): |
443 | 110 | ... | 92 | ... |
444 | 111 | Unauthorized: ... | 93 | Unauthorized: ... |
445 | 112 | 94 | ||
446 | 113 | >>> account = IMasterObject(account) | 95 | >>> person = IMasterObject(person) |
447 | 114 | >>> removeSecurityProxy(account) is account | 96 | >>> removeSecurityProxy(person) is person |
448 | 115 | False | 97 | False |
449 | 116 | >>> account.displayname | 98 | >>> person.displayname |
450 | 117 | u'No Privileges Person' | 99 | u'No Privileges Person' |
451 | 118 | >>> account.password | 100 | >>> person.name = 'foo' |
452 | 119 | Traceback (most recent call last): | 101 | Traceback (most recent call last): |
453 | 120 | ... | 102 | ... |
454 | 121 | Unauthorized: ... | 103 | Unauthorized: ... |
455 | 122 | 104 | ||
456 | 123 | >>> account = IMasterObject(removeSecurityProxy(account)) | 105 | >>> person = IMasterObject(removeSecurityProxy(person)) |
457 | 124 | >>> removeSecurityProxy(account) is account | 106 | >>> removeSecurityProxy(person) is person |
458 | 125 | True | 107 | True |
460 | 126 | >>> account.displayname | 108 | >>> person.displayname |
461 | 127 | u'No Privileges Person' | 109 | u'No Privileges Person' |
464 | 128 | >>> account.password | 110 | >>> person.name = 'foo' |
463 | 129 | u'...' | ||
465 | 130 | 111 | ||
466 | 131 | Our objects may compare equal even if they have come from different | 112 | Our objects may compare equal even if they have come from different |
467 | 132 | stores. | 113 | stores. |
468 | 133 | 114 | ||
476 | 134 | >>> auth_master_email = IMasterStore(EmailAddress).find( | 115 | >>> master_email = IMasterStore(EmailAddress).find( |
477 | 135 | ... EmailAddress, Person.name == 'janitor', | 116 | ... EmailAddress, Person.name == 'janitor', |
478 | 136 | ... EmailAddress.person==Person.id).one() | 117 | ... EmailAddress.person==Person.id).one() |
479 | 137 | >>> auth_slave_email = ISlaveStore(EmailAddress).find( | 118 | >>> slave_email = ISlaveStore(EmailAddress).find( |
480 | 138 | ... EmailAddress, Person.name == 'janitor', | 119 | ... EmailAddress, Person.name == 'janitor', |
481 | 139 | ... EmailAddress.person==Person.id).one() | 120 | ... EmailAddress.person==Person.id).one() |
482 | 140 | >>> auth_master_email is auth_slave_email | 121 | >>> master_email is slave_email |
483 | 141 | False | 122 | False |
485 | 142 | >>> auth_master_email == auth_slave_email | 123 | >>> master_email == slave_email |
486 | 143 | True | 124 | True |
488 | 144 | >>> auth_master_email != auth_slave_email | 125 | >>> master_email != slave_email |
489 | 145 | False | 126 | False |
490 | 146 | 127 | ||
491 | 147 | Comparison works for security wrapped objects too. | 128 | Comparison works for security wrapped objects too. |
492 | 148 | 129 | ||
493 | 149 | >>> wrapped_email = getUtility(IEmailAddressSet).getByEmail( | 130 | >>> wrapped_email = getUtility(IEmailAddressSet).getByEmail( |
496 | 150 | ... auth_master_email.email) | 131 | ... master_email.email) |
497 | 151 | >>> removeSecurityProxy(wrapped_email) is auth_master_email | 132 | >>> removeSecurityProxy(wrapped_email) is master_email |
498 | 152 | True | 133 | True |
500 | 153 | >>> wrapped_email is auth_master_email | 134 | >>> wrapped_email is master_email |
501 | 154 | False | 135 | False |
503 | 155 | >>> wrapped_email == auth_master_email | 136 | >>> wrapped_email == master_email |
504 | 156 | True | 137 | True |
506 | 157 | >>> wrapped_email != auth_master_email | 138 | >>> wrapped_email != master_email |
507 | 158 | False | 139 | False |
508 | 159 | 140 | ||
509 | 160 | Objects not yet flushed to the database also compare equal. | 141 | Objects not yet flushed to the database also compare equal. |
510 | @@ -176,10 +157,9 @@ | |||
511 | 176 | 157 | ||
512 | 177 | Objects differing by class never compare equal. | 158 | Objects differing by class never compare equal. |
513 | 178 | 159 | ||
517 | 179 | >>> account_one = IMasterStore(Account).get(Account, 1) | 160 | >>> email_one = IMasterStore(EmailAddress).get(EmailAddress, 1) |
518 | 180 | >>> person_one = IMasterStore(Account).get(Person, 1) | 161 | >>> person_one = IMasterStore(Person).get(Person, 1) |
519 | 181 | >>> account_one == person_one | 162 | >>> email_one == person_one |
520 | 182 | False | 163 | False |
522 | 183 | >>> account_one != person_one | 164 | >>> email_one != person_one |
523 | 184 | True | 165 | True |
524 | 185 | |||
525 | 186 | 166 | ||
526 | === modified file 'lib/canonical/launchpad/pagetests/standalone/xx-opstats.txt' | |||
527 | --- lib/canonical/launchpad/pagetests/standalone/xx-opstats.txt 2010-01-13 13:50:39 +0000 | |||
528 | +++ lib/canonical/launchpad/pagetests/standalone/xx-opstats.txt 2010-04-05 12:47:32 +0000 | |||
529 | @@ -236,8 +236,6 @@ | |||
530 | 236 | ... [database] | 236 | ... [database] |
531 | 237 | ... rw_main_master: dbname=nonexistant | 237 | ... rw_main_master: dbname=nonexistant |
532 | 238 | ... rw_main_slave: dbname=nonexistant | 238 | ... rw_main_slave: dbname=nonexistant |
533 | 239 | ... auth_master: dbname=nonexistant | ||
534 | 240 | ... auth_slave: dbname=nonexistant | ||
535 | 241 | ... | 239 | ... |
536 | 242 | ... [launchpad_session] | 240 | ... [launchpad_session] |
537 | 243 | ... dbname: nonexistant | 241 | ... dbname: nonexistant |
538 | 244 | 242 | ||
539 | === modified file 'lib/canonical/launchpad/scripts/garbo.py' | |||
540 | --- lib/canonical/launchpad/scripts/garbo.py 2010-03-26 14:33:46 +0000 | |||
541 | +++ lib/canonical/launchpad/scripts/garbo.py 2010-04-05 12:47:32 +0000 | |||
542 | @@ -29,7 +29,7 @@ | |||
543 | 29 | from canonical.launchpad.utilities.looptuner import ( | 29 | from canonical.launchpad.utilities.looptuner import ( |
544 | 30 | DBLoopTuner, TunableLoop) | 30 | DBLoopTuner, TunableLoop) |
545 | 31 | from canonical.launchpad.webapp.interfaces import ( | 31 | from canonical.launchpad.webapp.interfaces import ( |
547 | 32 | IStoreSelector, AUTH_STORE, MAIN_STORE, MASTER_FLAVOR) | 32 | IStoreSelector, MAIN_STORE, MASTER_FLAVOR) |
548 | 33 | from lp.bugs.interfaces.bug import IBugSet | 33 | from lp.bugs.interfaces.bug import IBugSet |
549 | 34 | from lp.bugs.interfaces.bugjob import ICalculateBugHeatJobSource | 34 | from lp.bugs.interfaces.bugjob import ICalculateBugHeatJobSource |
550 | 35 | from lp.bugs.model.bugnotification import BugNotification | 35 | from lp.bugs.model.bugnotification import BugNotification |
551 | @@ -121,19 +121,17 @@ | |||
552 | 121 | transaction.commit() | 121 | transaction.commit() |
553 | 122 | 122 | ||
554 | 123 | 123 | ||
556 | 124 | class OpenIDAssociationPruner(TunableLoop): | 124 | class OpenIDConsumerAssociationPruner(TunableLoop): |
557 | 125 | minimum_chunk_size = 3500 | 125 | minimum_chunk_size = 3500 |
558 | 126 | maximum_chunk_size = 50000 | 126 | maximum_chunk_size = 50000 |
559 | 127 | 127 | ||
562 | 128 | table_name = 'OpenIDAssociation' | 128 | table_name = 'OpenIDConsumerAssociation' |
561 | 129 | store_name = AUTH_STORE | ||
563 | 130 | 129 | ||
564 | 131 | _num_removed = None | 130 | _num_removed = None |
565 | 132 | 131 | ||
566 | 133 | def __init__(self, log, abort_time=None): | 132 | def __init__(self, log, abort_time=None): |
570 | 134 | super(OpenIDAssociationPruner, self).__init__(log, abort_time) | 133 | super(OpenIDConsumerAssociationPruner, self).__init__(log, abort_time) |
571 | 135 | self.store = getUtility(IStoreSelector).get( | 134 | self.store = getUtility(IStoreSelector).get(MAIN_STORE, MASTER_FLAVOR) |
569 | 136 | self.store_name, MASTER_FLAVOR) | ||
572 | 137 | 135 | ||
573 | 138 | def __call__(self, chunksize): | 136 | def __call__(self, chunksize): |
574 | 139 | result = self.store.execute(""" | 137 | result = self.store.execute(""" |
575 | @@ -152,11 +150,6 @@ | |||
576 | 152 | return self._num_removed == 0 | 150 | return self._num_removed == 0 |
577 | 153 | 151 | ||
578 | 154 | 152 | ||
579 | 155 | class OpenIDConsumerAssociationPruner(OpenIDAssociationPruner): | ||
580 | 156 | table_name = 'OpenIDConsumerAssociation' | ||
581 | 157 | store_name = MAIN_STORE | ||
582 | 158 | |||
583 | 159 | |||
584 | 160 | class RevisionCachePruner(TunableLoop): | 153 | class RevisionCachePruner(TunableLoop): |
585 | 161 | """A tunable loop to remove old revisions from the cache.""" | 154 | """A tunable loop to remove old revisions from the cache.""" |
586 | 162 | 155 | ||
587 | @@ -869,7 +862,6 @@ | |||
588 | 869 | tunable_loops = [ | 862 | tunable_loops = [ |
589 | 870 | OAuthNoncePruner, | 863 | OAuthNoncePruner, |
590 | 871 | OpenIDConsumerNoncePruner, | 864 | OpenIDConsumerNoncePruner, |
591 | 872 | OpenIDAssociationPruner, | ||
592 | 873 | OpenIDConsumerAssociationPruner, | 865 | OpenIDConsumerAssociationPruner, |
593 | 874 | RevisionCachePruner, | 866 | RevisionCachePruner, |
594 | 875 | BugHeatUpdater, | 867 | BugHeatUpdater, |
595 | 876 | 868 | ||
596 | === modified file 'lib/canonical/launchpad/scripts/tests/test_garbo.py' | |||
597 | --- lib/canonical/launchpad/scripts/tests/test_garbo.py 2010-01-22 06:03:19 +0000 | |||
598 | +++ lib/canonical/launchpad/scripts/tests/test_garbo.py 2010-04-05 12:47:32 +0000 | |||
599 | @@ -29,11 +29,11 @@ | |||
600 | 29 | from lp.testing import TestCase, TestCaseWithFactory | 29 | from lp.testing import TestCase, TestCaseWithFactory |
601 | 30 | from canonical.launchpad.scripts.garbo import ( | 30 | from canonical.launchpad.scripts.garbo import ( |
602 | 31 | DailyDatabaseGarbageCollector, HourlyDatabaseGarbageCollector, | 31 | DailyDatabaseGarbageCollector, HourlyDatabaseGarbageCollector, |
604 | 32 | OpenIDAssociationPruner, OpenIDConsumerAssociationPruner) | 32 | OpenIDConsumerAssociationPruner) |
605 | 33 | from canonical.launchpad.scripts.tests import run_script | 33 | from canonical.launchpad.scripts.tests import run_script |
606 | 34 | from canonical.launchpad.scripts.logger import QuietFakeLogger | 34 | from canonical.launchpad.scripts.logger import QuietFakeLogger |
607 | 35 | from canonical.launchpad.webapp.interfaces import ( | 35 | from canonical.launchpad.webapp.interfaces import ( |
609 | 36 | IStoreSelector, MASTER_FLAVOR) | 36 | IStoreSelector, MAIN_STORE, MASTER_FLAVOR) |
610 | 37 | from canonical.testing.layers import ( | 37 | from canonical.testing.layers import ( |
611 | 38 | DatabaseLayer, LaunchpadScriptLayer, LaunchpadZopelessLayer) | 38 | DatabaseLayer, LaunchpadScriptLayer, LaunchpadZopelessLayer) |
612 | 39 | from lp.bugs.model.bugnotification import ( | 39 | from lp.bugs.model.bugnotification import ( |
613 | @@ -219,12 +219,12 @@ | |||
614 | 219 | Min(CodeImportResult.date_created)).one().replace(tzinfo=UTC) | 219 | Min(CodeImportResult.date_created)).one().replace(tzinfo=UTC) |
615 | 220 | >= now - timedelta(days=30)) | 220 | >= now - timedelta(days=30)) |
616 | 221 | 221 | ||
619 | 222 | def test_OpenIDAssociationPruner(self, pruner=OpenIDAssociationPruner): | 222 | def test_OpenIDConsumerAssociationPruner(self): |
620 | 223 | store_name = pruner.store_name | 223 | pruner = OpenIDConsumerAssociationPruner |
621 | 224 | table_name = pruner.table_name | 224 | table_name = pruner.table_name |
622 | 225 | LaunchpadZopelessLayer.switchDbUser('testadmin') | 225 | LaunchpadZopelessLayer.switchDbUser('testadmin') |
623 | 226 | store_selector = getUtility(IStoreSelector) | 226 | store_selector = getUtility(IStoreSelector) |
625 | 227 | store = store_selector.get(store_name, MASTER_FLAVOR) | 227 | store = store_selector.get(MAIN_STORE, MASTER_FLAVOR) |
626 | 228 | now = time.time() | 228 | now = time.time() |
627 | 229 | # Create some associations in the past with lifetimes | 229 | # Create some associations in the past with lifetimes |
628 | 230 | for delta in range(0, 20): | 230 | for delta in range(0, 20): |
629 | @@ -247,7 +247,7 @@ | |||
630 | 247 | self.runHourly() | 247 | self.runHourly() |
631 | 248 | 248 | ||
632 | 249 | LaunchpadZopelessLayer.switchDbUser('testadmin') | 249 | LaunchpadZopelessLayer.switchDbUser('testadmin') |
634 | 250 | store = store_selector.get(store_name, MASTER_FLAVOR) | 250 | store = store_selector.get(MAIN_STORE, MASTER_FLAVOR) |
635 | 251 | # Confirm all the rows we know should have been expired have | 251 | # Confirm all the rows we know should have been expired have |
636 | 252 | # been expired. These are the ones that would be expired using | 252 | # been expired. These are the ones that would be expired using |
637 | 253 | # the test start time as 'now'. | 253 | # the test start time as 'now'. |
638 | @@ -263,9 +263,6 @@ | |||
639 | 263 | "SELECT COUNT(*) FROM %s" % table_name).get_one()[0] | 263 | "SELECT COUNT(*) FROM %s" % table_name).get_one()[0] |
640 | 264 | self.failUnless(num_unexpired > 0) | 264 | self.failUnless(num_unexpired > 0) |
641 | 265 | 265 | ||
642 | 266 | def test_OpenIDConsumerAssociationPruner(self): | ||
643 | 267 | self.test_OpenIDAssociationPruner(OpenIDConsumerAssociationPruner) | ||
644 | 268 | |||
645 | 269 | def test_RevisionAuthorEmailLinker(self): | 266 | def test_RevisionAuthorEmailLinker(self): |
646 | 270 | LaunchpadZopelessLayer.switchDbUser('testadmin') | 267 | LaunchpadZopelessLayer.switchDbUser('testadmin') |
647 | 271 | rev1 = self.factory.makeRevision('Author 1 <author-1@Example.Org>') | 268 | rev1 = self.factory.makeRevision('Author 1 <author-1@Example.Org>') |
648 | @@ -373,6 +370,7 @@ | |||
649 | 373 | 370 | ||
650 | 374 | # If we remove the email address that was subscribed, the | 371 | # If we remove the email address that was subscribed, the |
651 | 375 | # garbage collector removes the subscription. | 372 | # garbage collector removes the subscription. |
652 | 373 | LaunchpadZopelessLayer.switchDbUser('testadmin') | ||
653 | 376 | Store.of(email).remove(email) | 374 | Store.of(email).remove(email) |
654 | 377 | transaction.commit() | 375 | transaction.commit() |
655 | 378 | self.runDaily() | 376 | self.runDaily() |
656 | 379 | 377 | ||
657 | === modified file 'lib/canonical/launchpad/webapp/adapter.py' | |||
658 | --- lib/canonical/launchpad/webapp/adapter.py 2010-03-25 11:58:42 +0000 | |||
659 | +++ lib/canonical/launchpad/webapp/adapter.py 2010-04-05 12:47:32 +0000 | |||
660 | @@ -40,14 +40,13 @@ | |||
661 | 40 | from canonical.launchpad.readonly import is_read_only | 40 | from canonical.launchpad.readonly import is_read_only |
662 | 41 | from canonical.launchpad.webapp.dbpolicy import MasterDatabasePolicy | 41 | from canonical.launchpad.webapp.dbpolicy import MasterDatabasePolicy |
663 | 42 | from canonical.launchpad.webapp.interfaces import ( | 42 | from canonical.launchpad.webapp.interfaces import ( |
666 | 43 | AUTH_STORE, DEFAULT_FLAVOR, IStoreSelector, | 43 | DEFAULT_FLAVOR, IStoreSelector, MAIN_STORE, MASTER_FLAVOR, |
667 | 44 | MAIN_STORE, MASTER_FLAVOR, ReadOnlyModeViolation, SLAVE_FLAVOR) | 44 | ReadOnlyModeViolation, SLAVE_FLAVOR) |
668 | 45 | from canonical.launchpad.webapp.opstats import OpStats | 45 | from canonical.launchpad.webapp.opstats import OpStats |
669 | 46 | from canonical.lazr.utils import safe_hasattr | 46 | from canonical.lazr.utils import safe_hasattr |
670 | 47 | 47 | ||
671 | 48 | 48 | ||
672 | 49 | __all__ = [ | 49 | __all__ = [ |
673 | 50 | 'DisconnectionError', | ||
674 | 51 | 'RequestExpired', | 50 | 'RequestExpired', |
675 | 52 | 'set_request_started', | 51 | 'set_request_started', |
676 | 53 | 'clear_request_started', | 52 | 'clear_request_started', |
677 | @@ -327,7 +326,7 @@ | |||
678 | 327 | 326 | ||
679 | 328 | def __init__(self, uri): | 327 | def __init__(self, uri): |
680 | 329 | # The uri is just a property name in the config, such as main_master | 328 | # The uri is just a property name in the config, such as main_master |
682 | 330 | # or auth_slave. | 329 | # or main_slave. |
683 | 331 | # We don't invoke the superclass constructor as it has a very limited | 330 | # We don't invoke the superclass constructor as it has a very limited |
684 | 332 | # opinion on what uri is. | 331 | # opinion on what uri is. |
685 | 333 | # pylint: disable-msg=W0231 | 332 | # pylint: disable-msg=W0231 |
686 | @@ -356,7 +355,7 @@ | |||
687 | 356 | 'Connection uri %s does not match section-realm-flavor format' | 355 | 'Connection uri %s does not match section-realm-flavor format' |
688 | 357 | % repr(self._uri.database)) | 356 | % repr(self._uri.database)) |
689 | 358 | 357 | ||
691 | 359 | assert realm in ('main', 'auth'), 'Unknown realm %s' % realm | 358 | assert realm == 'main', 'Unknown realm %s' % realm |
692 | 360 | assert flavor in ('master', 'slave'), 'Unknown flavor %s' % flavor | 359 | assert flavor in ('master', 'slave'), 'Unknown flavor %s' % flavor |
693 | 361 | 360 | ||
694 | 362 | my_dbconfig = DatabaseConfig() | 361 | my_dbconfig = DatabaseConfig() |
695 | @@ -572,14 +571,6 @@ | |||
696 | 572 | return db_policy.getStore(name, flavor) | 571 | return db_policy.getStore(name, flavor) |
697 | 573 | 572 | ||
698 | 574 | 573 | ||
699 | 575 | # There are not many tables outside of the main replication set, so we | ||
700 | 576 | # can just maintain a hardcoded list of what isn't in there for now. | ||
701 | 577 | _auth_store_tables = frozenset([ | ||
702 | 578 | 'Account', 'AccountPassword', 'AuthToken', 'EmailAddress', | ||
703 | 579 | 'OpenIDAssociation', 'OpenIDAuthorization', 'OpenIDNonce', | ||
704 | 580 | 'OpenIDRPSummary']) | ||
705 | 581 | |||
706 | 582 | |||
707 | 583 | # We want to be able to adapt a Storm class to an IStore, IMasterStore or | 574 | # We want to be able to adapt a Storm class to an IStore, IMasterStore or |
708 | 584 | # ISlaveStore. Unfortunately, the component architecture provides no | 575 | # ISlaveStore. Unfortunately, the component architecture provides no |
709 | 585 | # way for us to declare that a class, and all its subclasses, provides | 576 | # way for us to declare that a class, and all its subclasses, provides |
710 | @@ -588,9 +579,7 @@ | |||
711 | 588 | def get_store(storm_class, flavor=DEFAULT_FLAVOR): | 579 | def get_store(storm_class, flavor=DEFAULT_FLAVOR): |
712 | 589 | """Return a flavored Store for the given database class.""" | 580 | """Return a flavored Store for the given database class.""" |
713 | 590 | table = getattr(removeSecurityProxy(storm_class), '__storm_table__', None) | 581 | table = getattr(removeSecurityProxy(storm_class), '__storm_table__', None) |
717 | 591 | if table in _auth_store_tables: | 582 | if table is not None: |
715 | 592 | return getUtility(IStoreSelector).get(AUTH_STORE, flavor) | ||
716 | 593 | elif table is not None: | ||
718 | 594 | return getUtility(IStoreSelector).get(MAIN_STORE, flavor) | 583 | return getUtility(IStoreSelector).get(MAIN_STORE, flavor) |
719 | 595 | else: | 584 | else: |
720 | 596 | return None | 585 | return None |
721 | 597 | 586 | ||
722 | === modified file 'lib/canonical/launchpad/webapp/ftests/test_adapter_permissions.txt' | |||
723 | --- lib/canonical/launchpad/webapp/ftests/test_adapter_permissions.txt 2009-06-11 01:28:55 +0000 | |||
724 | +++ lib/canonical/launchpad/webapp/ftests/test_adapter_permissions.txt 2010-04-05 12:47:32 +0000 | |||
725 | @@ -10,8 +10,7 @@ | |||
726 | 10 | 10 | ||
727 | 11 | >>> from lp.registry.model.person import Person | 11 | >>> from lp.registry.model.person import Person |
728 | 12 | >>> from canonical.launchpad.webapp.interfaces import ( | 12 | >>> from canonical.launchpad.webapp.interfaces import ( |
731 | 13 | ... IStoreSelector, AUTH_STORE, MAIN_STORE, | 13 | ... IStoreSelector, MAIN_STORE, MASTER_FLAVOR, SLAVE_FLAVOR) |
730 | 14 | ... MASTER_FLAVOR, SLAVE_FLAVOR) | ||
732 | 15 | >>> import transaction | 14 | >>> import transaction |
733 | 16 | >>> from zope.component import getUtility | 15 | >>> from zope.component import getUtility |
734 | 17 | 16 | ||
735 | @@ -47,25 +46,3 @@ | |||
736 | 47 | >>> main_master.find(Person, name='janitor').one().displayname | 46 | >>> main_master.find(Person, name='janitor').one().displayname |
737 | 48 | u'BenD' | 47 | u'BenD' |
738 | 49 | >>> transaction.abort() | 48 | >>> transaction.abort() |
739 | 50 | |||
740 | 51 | |||
741 | 52 | A MASTER_FLAVOR Store does not allow writes to tables outside of that | ||
742 | 53 | Store's replication set. | ||
743 | 54 | |||
744 | 55 | >>> t = transaction.begin() | ||
745 | 56 | >>> person = main_master.find(Person, name='no-priv').one() | ||
746 | 57 | >>> account = person.account | ||
747 | 58 | >>> account.displayname = "Ben Dover" | ||
748 | 59 | >>> main_master.flush() | ||
749 | 60 | Traceback (most recent call last): | ||
750 | 61 | ... | ||
751 | 62 | ProgrammingError: permission denied for relation account | ||
752 | 63 | >>> transaction.abort() | ||
753 | 64 | |||
754 | 65 | >>> t = transaction.begin() | ||
755 | 66 | >>> auth_master = getUtility(IStoreSelector).get(AUTH_STORE, MASTER_FLAVOR) | ||
756 | 67 | >>> person = auth_master.find(Person, name='no-priv').one() | ||
757 | 68 | >>> account = person.account | ||
758 | 69 | >>> account.displayname = "Ben Dover" | ||
759 | 70 | >>> auth_master.flush() | ||
760 | 71 | >>> transaction.abort() | ||
761 | 72 | 49 | ||
762 | === modified file 'lib/canonical/launchpad/webapp/interfaces.py' | |||
763 | --- lib/canonical/launchpad/webapp/interfaces.py 2010-03-26 22:57:38 +0000 | |||
764 | +++ lib/canonical/launchpad/webapp/interfaces.py 2010-04-05 12:47:32 +0000 | |||
765 | @@ -745,9 +745,7 @@ | |||
766 | 745 | # | 745 | # |
767 | 746 | 746 | ||
768 | 747 | MAIN_STORE = 'main' # The main database. | 747 | MAIN_STORE = 'main' # The main database. |
772 | 748 | AUTH_STORE = 'auth' # The authentication database. | 748 | ALL_STORES = frozenset([MAIN_STORE]) |
770 | 749 | |||
771 | 750 | ALL_STORES = frozenset([MAIN_STORE, AUTH_STORE]) | ||
773 | 751 | 749 | ||
774 | 752 | DEFAULT_FLAVOR = 'default' # Default flavor for current state. | 750 | DEFAULT_FLAVOR = 'default' # Default flavor for current state. |
775 | 753 | MASTER_FLAVOR = 'master' # The master database. | 751 | MASTER_FLAVOR = 'master' # The master database. |
776 | 754 | 752 | ||
777 | === modified file 'lib/canonical/launchpad/webapp/tests/test_dbpolicy.py' | |||
778 | --- lib/canonical/launchpad/webapp/tests/test_dbpolicy.py 2010-02-24 23:18:40 +0000 | |||
779 | +++ lib/canonical/launchpad/webapp/tests/test_dbpolicy.py 2010-04-05 12:47:32 +0000 | |||
780 | @@ -25,7 +25,7 @@ | |||
781 | 25 | ReadOnlyLaunchpadDatabasePolicy, SlaveDatabasePolicy, | 25 | ReadOnlyLaunchpadDatabasePolicy, SlaveDatabasePolicy, |
782 | 26 | SlaveOnlyDatabasePolicy) | 26 | SlaveOnlyDatabasePolicy) |
783 | 27 | from canonical.launchpad.webapp.interfaces import ( | 27 | from canonical.launchpad.webapp.interfaces import ( |
785 | 28 | ALL_STORES, AUTH_STORE, DEFAULT_FLAVOR, DisallowedStore, IDatabasePolicy, | 28 | ALL_STORES, DEFAULT_FLAVOR, DisallowedStore, IDatabasePolicy, |
786 | 29 | IStoreSelector, MAIN_STORE, MASTER_FLAVOR, ReadOnlyModeDisallowedStore, | 29 | IStoreSelector, MAIN_STORE, MASTER_FLAVOR, ReadOnlyModeDisallowedStore, |
787 | 30 | SLAVE_FLAVOR) | 30 | SLAVE_FLAVOR) |
788 | 31 | from canonical.launchpad.webapp.servers import LaunchpadTestRequest | 31 | from canonical.launchpad.webapp.servers import LaunchpadTestRequest |
789 | @@ -47,9 +47,6 @@ | |||
790 | 47 | main_store = store_selector.get(MAIN_STORE, DEFAULT_FLAVOR) | 47 | main_store = store_selector.get(MAIN_STORE, DEFAULT_FLAVOR) |
791 | 48 | self.failUnlessEqual(self.getDBUser(main_store), 'launchpad_main') | 48 | self.failUnlessEqual(self.getDBUser(main_store), 'launchpad_main') |
792 | 49 | 49 | ||
793 | 50 | auth_store = store_selector.get(AUTH_STORE, DEFAULT_FLAVOR) | ||
794 | 51 | self.failUnlessEqual(self.getDBUser(auth_store), 'launchpad_auth') | ||
795 | 52 | |||
796 | 53 | def getDBUser(self, store): | 50 | def getDBUser(self, store): |
797 | 54 | return store.execute( | 51 | return store.execute( |
798 | 55 | 'SHOW session_authorization').get_one()[0] | 52 | 'SHOW session_authorization').get_one()[0] |
799 | 56 | 53 | ||
800 | === removed symlink 'lib/canonical/signon' | |||
801 | === target was u'../../sourcecode/canonical-identity-provider' | |||
802 | === modified file 'lib/lp/bugs/doc/checkwatches.txt' | |||
803 | --- lib/lp/bugs/doc/checkwatches.txt 2010-03-26 15:24:59 +0000 | |||
804 | +++ lib/lp/bugs/doc/checkwatches.txt 2010-04-05 12:47:32 +0000 | |||
805 | @@ -337,9 +337,13 @@ | |||
806 | 337 | If a bug tracker doesn't have any watches to update, forceUpdateAll() | 337 | If a bug tracker doesn't have any watches to update, forceUpdateAll() |
807 | 338 | will ignore it. | 338 | will ignore it. |
808 | 339 | 339 | ||
809 | 340 | >>> transaction.commit() | ||
810 | 341 | >>> LaunchpadZopelessLayer.switchDbUser('launchpad') | ||
811 | 340 | >>> login('test@canonical.com') | 342 | >>> login('test@canonical.com') |
812 | 341 | >>> empty_tracker = factory.makeBugTracker( | 343 | >>> empty_tracker = factory.makeBugTracker( |
813 | 342 | ... 'http://example.com', BugTrackerType.ROUNDUP) | 344 | ... 'http://example.com', BugTrackerType.ROUNDUP) |
814 | 345 | >>> transaction.commit() | ||
815 | 346 | >>> LaunchpadZopelessLayer.switchDbUser(config.checkwatches.dbuser) | ||
816 | 343 | >>> empty_tracker_name = empty_tracker.name | 347 | >>> empty_tracker_name = empty_tracker.name |
817 | 344 | >>> update_all(empty_tracker_name) | 348 | >>> update_all(empty_tracker_name) |
818 | 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. |
819 | 346 | 350 | ||
820 | === modified file 'lib/lp/bugs/doc/externalbugtracker-comment-imports.txt' | |||
821 | --- lib/lp/bugs/doc/externalbugtracker-comment-imports.txt 2010-03-25 14:28:33 +0000 | |||
822 | +++ lib/lp/bugs/doc/externalbugtracker-comment-imports.txt 2010-04-05 12:47:32 +0000 | |||
823 | @@ -373,8 +373,10 @@ | |||
824 | 373 | since they aren't a valid Launchpad user, having been created during the | 373 | since they aren't a valid Launchpad user, having been created during the |
825 | 374 | import process. | 374 | import process. |
826 | 375 | 375 | ||
828 | 376 | We'll add a listener to check for Karma events. | 376 | We'll create a bug watch and add a listener to check for Karma events. |
829 | 377 | 377 | ||
830 | 378 | >>> LaunchpadZopelessLayer.switchDbUser('launchpad') | ||
831 | 379 | >>> bug_watch = factory.makeBugWatch('123456') | ||
832 | 378 | >>> from lp.registry.tests.karma import KarmaAssignedEventListener | 380 | >>> from lp.registry.tests.karma import KarmaAssignedEventListener |
833 | 379 | >>> karma_helper = KarmaAssignedEventListener() | 381 | >>> karma_helper = KarmaAssignedEventListener() |
834 | 380 | >>> karma_helper.register_listener() | 382 | >>> karma_helper.register_listener() |
835 | @@ -382,8 +384,6 @@ | |||
836 | 382 | Importing a comment with a CVE reference will produce a CVE link in | 384 | Importing a comment with a CVE reference will produce a CVE link in |
837 | 383 | Launchpad but will result in no Karma records being created. | 385 | Launchpad but will result in no Karma records being created. |
838 | 384 | 386 | ||
839 | 385 | >>> LaunchpadZopelessLayer.switchDbUser('launchpad') | ||
840 | 386 | >>> bug_watch = factory.makeBugWatch('123456') | ||
841 | 387 | >>> transaction.commit() | 387 | >>> transaction.commit() |
842 | 388 | >>> LaunchpadZopelessLayer.switchDbUser(config.checkwatches.dbuser) | 388 | >>> LaunchpadZopelessLayer.switchDbUser(config.checkwatches.dbuser) |
843 | 389 | >>> external_bugtracker.remote_comments = { | 389 | >>> external_bugtracker.remote_comments = { |
844 | 390 | 390 | ||
845 | === modified file 'lib/lp/code/doc/branch-karma.txt' | |||
846 | --- lib/lp/code/doc/branch-karma.txt 2010-02-16 20:36:48 +0000 | |||
847 | +++ lib/lp/code/doc/branch-karma.txt 2010-04-05 12:47:32 +0000 | |||
848 | @@ -49,6 +49,7 @@ | |||
849 | 49 | You get karma for linking a bug to a branch. | 49 | You get karma for linking a bug to a branch. |
850 | 50 | 50 | ||
851 | 51 | >>> bug = factory.makeBug(product=fooix) | 51 | >>> bug = factory.makeBug(product=fooix) |
852 | 52 | Karma added: action=bugcreated, product=fooix, person=person-name11 | ||
853 | 52 | >>> branch_link = bug.linkBranch(branch, eric) | 53 | >>> branch_link = bug.linkBranch(branch, eric) |
854 | 53 | Karma added: action=bugbranchcreated, product=fooix, person=eric | 54 | Karma added: action=bugbranchcreated, product=fooix, person=eric |
855 | 54 | 55 | ||
856 | 55 | 56 | ||
857 | === modified file 'lib/lp/registry/model/person.py' | |||
858 | --- lib/lp/registry/model/person.py 2010-03-24 23:19:52 +0000 | |||
859 | +++ lib/lp/registry/model/person.py 2010-04-05 12:47:32 +0000 | |||
860 | @@ -124,7 +124,7 @@ | |||
861 | 124 | TeamMembershipStatus) | 124 | TeamMembershipStatus) |
862 | 125 | from lp.registry.interfaces.wikiname import IWikiName, IWikiNameSet | 125 | from lp.registry.interfaces.wikiname import IWikiName, IWikiNameSet |
863 | 126 | from canonical.launchpad.webapp.interfaces import ( | 126 | from canonical.launchpad.webapp.interfaces import ( |
865 | 127 | AUTH_STORE, ILaunchBag, IStoreSelector, MASTER_FLAVOR) | 127 | ILaunchBag, IStoreSelector, MASTER_FLAVOR) |
866 | 128 | 128 | ||
867 | 129 | from lp.soyuz.model.archive import Archive | 129 | from lp.soyuz.model.archive import Archive |
868 | 130 | from lp.registry.model.codeofconduct import SignedCodeOfConduct | 130 | from lp.registry.model.codeofconduct import SignedCodeOfConduct |
869 | @@ -263,22 +263,7 @@ | |||
870 | 263 | return '<Person at 0x%x %s (%s)>' % ( | 263 | return '<Person at 0x%x %s (%s)>' % ( |
871 | 264 | id(self), self.name, self.displayname) | 264 | id(self), self.name, self.displayname) |
872 | 265 | 265 | ||
889 | 266 | def _sync_displayname(self, attr, value): | 266 | displayname = StringCol(dbName='displayname', notNull=True) |
874 | 267 | """Update any related Account.displayname. | ||
875 | 268 | |||
876 | 269 | We can't do this in a DB trigger as soon the Account table will | ||
877 | 270 | in a separate database to the Person table. | ||
878 | 271 | """ | ||
879 | 272 | if self.accountID is not None: | ||
880 | 273 | auth_store = getUtility(IStoreSelector).get( | ||
881 | 274 | AUTH_STORE, MASTER_FLAVOR) | ||
882 | 275 | account = auth_store.get(Account, self.accountID) | ||
883 | 276 | if account.displayname != value: | ||
884 | 277 | account.displayname = value | ||
885 | 278 | return value | ||
886 | 279 | |||
887 | 280 | displayname = StringCol(dbName='displayname', notNull=True, | ||
888 | 281 | storm_validator=_sync_displayname) | ||
890 | 282 | 267 | ||
891 | 283 | teamdescription = StringCol(dbName='teamdescription', default=None) | 268 | teamdescription = StringCol(dbName='teamdescription', default=None) |
892 | 284 | homepage_content = StringCol(default=None) | 269 | homepage_content = StringCol(default=None) |
893 | 285 | 270 | ||
894 | === modified file 'lib/lp/registry/stories/person/xx-admin-person-review.txt' | |||
895 | --- lib/lp/registry/stories/person/xx-admin-person-review.txt 2010-01-30 22:39:54 +0000 | |||
896 | +++ lib/lp/registry/stories/person/xx-admin-person-review.txt 2010-04-05 12:47:32 +0000 | |||
897 | @@ -63,7 +63,7 @@ | |||
898 | 63 | >>> print admin_browser.title | 63 | >>> print admin_browser.title |
899 | 64 | The one and only Salgado does not use Launchpad | 64 | The one and only Salgado does not use Launchpad |
900 | 65 | >>> print get_feedback_messages(admin_browser.contents)[0] | 65 | >>> print get_feedback_messages(admin_browser.contents)[0] |
902 | 66 | The account "The one and only Salgado" has been suspended. | 66 | The account "Guilherme Salgado" has been suspended. |
903 | 67 | 67 | ||
904 | 68 | The admin can see the account information of a user that does not use | 68 | The admin can see the account information of a user that does not use |
905 | 69 | Launchpad, and can change the account too. Note that all pages that belong | 69 | Launchpad, and can change the account too. Note that all pages that belong |
906 | 70 | 70 | ||
907 | === modified file 'lib/lp/registry/tests/test_personset.py' | |||
908 | --- lib/lp/registry/tests/test_personset.py 2010-03-11 20:54:36 +0000 | |||
909 | +++ lib/lp/registry/tests/test_personset.py 2010-04-05 12:47:32 +0000 | |||
910 | @@ -99,23 +99,19 @@ | |||
911 | 99 | # Person in question. | 99 | # Person in question. |
912 | 100 | 100 | ||
913 | 101 | # Create a testing `Account` and a testing `Person` directly, | 101 | # Create a testing `Account` and a testing `Person` directly, |
916 | 102 | # linked. However the `Account` email is not linked to the | 102 | # linked. |
915 | 103 | # `Person`. | ||
917 | 104 | testing_account = self.factory.makeAccount( | 103 | testing_account = self.factory.makeAccount( |
918 | 105 | self.displayname, email=self.email_address) | 104 | self.displayname, email=self.email_address) |
919 | 106 | testing_person = removeSecurityProxy( | 105 | testing_person = removeSecurityProxy( |
920 | 107 | testing_account).createPerson(self.rationale) | 106 | testing_account).createPerson(self.rationale) |
923 | 108 | self.assertIs(None, testing_account.preferredemail.person) | 107 | self.assertEqual( |
924 | 109 | self.assertIs(None, testing_person.preferredemail) | 108 | testing_person, testing_account.preferredemail.person) |
925 | 110 | 109 | ||
926 | 110 | # Since there's an existing Person for the given email address, | ||
927 | 111 | # IPersonSet.ensurePerson() will just return it. | ||
928 | 111 | ensured_person = self.person_set.ensurePerson( | 112 | ensured_person = self.person_set.ensurePerson( |
929 | 112 | self.email_address, self.displayname, self.rationale) | 113 | self.email_address, self.displayname, self.rationale) |
936 | 113 | 114 | self.assertEqual(testing_person, ensured_person) | |
931 | 114 | # The existing Person was retrieved and the Account | ||
932 | 115 | # 'preferredemail' is also bound to the existing Person. | ||
933 | 116 | self.assertEquals(testing_person.id, ensured_person.id) | ||
934 | 117 | self.assertEquals(testing_account.preferredemail.id, | ||
935 | 118 | ensured_person.preferredemail.id) | ||
937 | 119 | 115 | ||
938 | 120 | 116 | ||
939 | 121 | class TestPersonSetMerge(TestCaseWithFactory): | 117 | class TestPersonSetMerge(TestCaseWithFactory): |
940 | 122 | 118 | ||
941 | === modified file 'lib/lp/testopenid/browser/server.py' | |||
942 | --- lib/lp/testopenid/browser/server.py 2010-02-24 12:52:08 +0000 | |||
943 | +++ lib/lp/testopenid/browser/server.py 2010-04-05 12:47:32 +0000 | |||
944 | @@ -6,7 +6,7 @@ | |||
945 | 6 | __all__ = [ | 6 | __all__ = [ |
946 | 7 | 'PersistentIdentityView', | 7 | 'PersistentIdentityView', |
947 | 8 | 'TestOpenIDApplicationNavigation', | 8 | 'TestOpenIDApplicationNavigation', |
949 | 9 | 'TestOpenIDIndexView' | 9 | 'TestOpenIDIndexView', |
950 | 10 | 'TestOpenIDLoginView', | 10 | 'TestOpenIDLoginView', |
951 | 11 | 'TestOpenIDRootUrlData', | 11 | 'TestOpenIDRootUrlData', |
952 | 12 | 'TestOpenIDView', | 12 | 'TestOpenIDView', |
953 | @@ -21,6 +21,7 @@ | |||
954 | 21 | from zope.security.proxy import isinstance as zisinstance | 21 | from zope.security.proxy import isinstance as zisinstance |
955 | 22 | from zope.session.interfaces import ISession | 22 | from zope.session.interfaces import ISession |
956 | 23 | 23 | ||
957 | 24 | from openid import oidutil | ||
958 | 24 | from openid.server.server import CheckIDRequest, Server | 25 | from openid.server.server import CheckIDRequest, Server |
959 | 25 | from openid.store.memstore import MemoryStore | 26 | from openid.store.memstore import MemoryStore |
960 | 26 | 27 | ||
961 | @@ -47,6 +48,10 @@ | |||
962 | 47 | openid_store = MemoryStore() | 48 | openid_store = MemoryStore() |
963 | 48 | 49 | ||
964 | 49 | 50 | ||
965 | 51 | # Shut up noisy OpenID library | ||
966 | 52 | oidutil.log = lambda message, level=0: None | ||
967 | 53 | |||
968 | 54 | |||
969 | 50 | class TestOpenIDRootUrlData: | 55 | class TestOpenIDRootUrlData: |
970 | 51 | """`ICanonicalUrlData` for the test OpenID provider.""" | 56 | """`ICanonicalUrlData` for the test OpenID provider.""" |
971 | 52 | 57 | ||
972 | 53 | 58 | ||
973 | === modified file 'utilities/sourcedeps.conf' | |||
974 | --- utilities/sourcedeps.conf 2010-03-26 17:53:41 +0000 | |||
975 | +++ utilities/sourcedeps.conf 2010-04-05 12:47:32 +0000 | |||
976 | @@ -15,5 +15,4 @@ | |||
977 | 15 | subunit lp:~launchpad-pqm/subunit/trunk;revno=61 | 15 | subunit lp:~launchpad-pqm/subunit/trunk;revno=61 |
978 | 16 | subvertpy lp:~launchpad-pqm/subvertpy/trunk;revno=2040 | 16 | subvertpy lp:~launchpad-pqm/subvertpy/trunk;revno=2040 |
979 | 17 | testresources lp:~launchpad-pqm/testresources/dev;revno=16 | 17 | testresources lp:~launchpad-pqm/testresources/dev;revno=16 |
980 | 18 | canonical-identity-provider lp:~launchpad-pqm/canonical-identity-provider/trunk;revno=8903 optional | ||
981 | 19 | shipit lp:~launchpad-pqm/shipit/trunk;revno=8903 optional | 18 | shipit lp:~launchpad-pqm/shipit/trunk;revno=8903 optional |
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' launchpad/ database/ tests/test_ oauth.py 2009-06-25 05:30:52 +0000 launchpad/ database/ tests/test_ oauth.py 2010-03-30 19:00:44 +0000 nalLayer store_should_ return_ the_auth_ master_ store(self) : store_should_ return_ the_main_ master_ store(self) :
> --- lib/canonical/
> +++ lib/canonical/
> @@ -22,7 +22,7 @@
> """Base tests for the OAuth database classes."""
> layer = DatabaseFunctio
>
> - def test__get_
> + def test__get_
> """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' database. split(' -') realm-flavor format' _uri.database) )
> 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.
> except ValueError:
> raise AssertionError(
> 'Connection uri %s does not match section-
> % repr(self.
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' find(Person, name='no- priv'). one() IStoreSelector) .get(AUTH_ STORE, MASTER_FLAVOR) find(Person, name='no- priv'). one()
> -
> -A MASTER_FLAVOR Store does not allow writes to tables outside of that
> -Store's replication set.
> -
> - >>> t = transaction.begin()
> - >>> person = main_master.
> - >>> 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(
> - >>> person = auth_master.
> - >>> 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...