← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~stub/launchpad/garbo-lockfile into lp:launchpad

 

Stuart Bishop has proposed merging lp:~stub/launchpad/garbo-lockfile into lp:launchpad with lp:~stub/launchpad/garbo-bulk-pruner as a prerequisite.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #553254 in Launchpad itself: "Need to remove old login tokens"
  https://bugs.launchpad.net/launchpad/+bug/553254

For more details, see:
https://code.launchpad.net/~stub/launchpad/garbo-lockfile/+merge/77882

= Summary =

LoginToken has 4000000+ rows, most of which is utterly irrelevant to us now we use the SSO.

== Proposed fix ==

Prune it with garbo lovin'.

== Pre-implementation notes ==

== Implementation details ==

== Tests ==

bin/test -vv --test=test_LoginToken test_garbo

== Demo and Q/A ==


= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  database/schema/security.cfg
  lib/lp/scripts/garbo.py
  lib/lp/scripts/tests/test_garbo.py
-- 
https://code.launchpad.net/~stub/launchpad/garbo-lockfile/+merge/77882
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~stub/launchpad/garbo-lockfile into lp:launchpad.
=== modified file 'database/schema/security.cfg'
--- database/schema/security.cfg	2011-09-25 21:44:40 +0000
+++ database/schema/security.cfg	2011-10-03 09:55:09 +0000
@@ -2129,6 +2129,7 @@
 public.emailaddress                     = SELECT, UPDATE
 public.hwsubmission                     = SELECT, UPDATE
 public.job                              = SELECT, INSERT, DELETE
+public.logintoken                       = SELECT, DELETE
 public.mailinglistsubscription          = SELECT, DELETE
 public.oauthnonce                       = SELECT, DELETE
 public.openidconsumerassociation        = SELECT, DELETE

=== modified file 'lib/lp/scripts/garbo.py'
--- lib/lp/scripts/garbo.py	2011-09-27 07:53:02 +0000
+++ lib/lp/scripts/garbo.py	2011-10-03 09:55:09 +0000
@@ -45,6 +45,7 @@
     )
 from canonical.launchpad.database.emailaddress import EmailAddress
 from canonical.launchpad.database.librarian import TimeLimitedToken
+from canonical.launchpad.database.logintoken import LoginToken
 from canonical.launchpad.database.oauth import OAuthNonce
 from canonical.launchpad.database.openidconsumer import OpenIDConsumerNonce
 from canonical.launchpad.interfaces.account import AccountStatus
@@ -192,6 +193,18 @@
         self.store.execute("CLOSE %s" % self.cursor_name)
 
 
+class LoginTokenPruner(BulkPruner):
+    """Remove old LoginToken rows.
+
+    After 1 year, they are useless even for archaeology.
+    """
+    target_table_class = LoginToken
+    ids_to_prune_query = """
+        SELECT id FROM LoginToken WHERE
+        created < CURRENT_TIMESTAMP - CAST('1 year' AS interval)
+        """
+
+
 class POTranslationPruner(BulkPruner):
     """Remove unlinked POTranslation entries.
 
@@ -1282,6 +1295,7 @@
         CodeImportEventPruner,
         CodeImportResultPruner,
         HWSubmissionEmailLinker,
+        LoginTokenPruner,
         ObsoleteBugAttachmentPruner,
         OldTimeLimitedTokenDeleter,
         RevisionAuthorEmailLinker,

=== modified file 'lib/lp/scripts/tests/test_garbo.py'
--- lib/lp/scripts/tests/test_garbo.py	2011-09-27 02:14:38 +0000
+++ lib/lp/scripts/tests/test_garbo.py	2011-10-03 09:55:09 +0000
@@ -43,12 +43,14 @@
     UTC_NOW,
     )
 from canonical.launchpad.database.librarian import TimeLimitedToken
+from canonical.launchpad.database.logintoken import LoginToken
 from canonical.launchpad.database.oauth import (
     OAuthAccessToken,
     OAuthNonce,
     )
 from canonical.launchpad.database.openidconsumer import OpenIDConsumerNonce
 from canonical.launchpad.interfaces.account import AccountStatus
+from canonical.launchpad.interfaces.authtoken import LoginTokenType
 from canonical.launchpad.interfaces.emailaddress import EmailAddressStatus
 from canonical.launchpad.interfaces.lpstorm import IMasterStore
 from canonical.launchpad.scripts.tests import run_script
@@ -91,6 +93,7 @@
     DuplicateSessionPruner,
     FrequentDatabaseGarbageCollector,
     HourlyDatabaseGarbageCollector,
+    LoginTokenPruner,
     OpenIDConsumerAssociationPruner,
     UnusedSessionPruner,
     )
@@ -1039,3 +1042,43 @@
         self.runHourly()
         self.assertEqual(spn, spph.sourcepackagename)
         self.assertEqual(bpn, bpph.binarypackagename)
+
+
+class TestGarboTasks(TestCaseWithFactory):
+    layer = LaunchpadZopelessLayer
+
+    def test_LoginTokenPruner(self):
+        store = IMasterStore(LoginToken)
+        now = datetime.now(UTC)
+        LaunchpadZopelessLayer.switchDbUser('testadmin')
+
+        # It is configured as a daily task.
+        self.assertTrue(
+            LoginTokenPruner in DailyDatabaseGarbageCollector.tunable_loops)
+
+        # Create a token that will be pruned.
+        old_token = LoginToken(
+            email='whatever', tokentype=LoginTokenType.NEWACCOUNT)
+        old_token.date_created = now - timedelta(days=666)
+        old_token_id = old_token.id
+        store.add(old_token)
+
+        # Create a token that will not be pruned.
+        current_token = LoginToken(
+            email='whatever', tokentype=LoginTokenType.NEWACCOUNT)
+        current_token_id = current_token.id
+        store.add(current_token)
+
+        # Run the pruner. Batching is tested by the BulkPruner tests so
+        # no need to repeat here.
+        LaunchpadZopelessLayer.switchDbUser('garbo_daily')
+        pruner = LoginTokenPruner(logging.getLogger('garbo'))
+        while not pruner.isDone():
+            pruner(10)
+        pruner.cleanUp()
+
+        # Only the old LoginToken is gone.
+        self.assertEqual(
+            store.find(LoginToken, id=old_token_id).count(), 0)
+        self.assertEqual(
+            store.find(LoginToken, id=current_token_id).count(), 1)