Added cron plugin to clean old access tokens.
This cron plugin runs every hour and deletes any access tokens whose expiration date has passed for more than a week. Tests provided. Change-Id: Ief9b25b684364f3ecdf58b2725fd2bb4228a6720
This commit is contained in:
parent
a4065b7fca
commit
16e11b0beb
@ -42,6 +42,7 @@ storyboard.worker.task =
|
||||
storyboard.plugin.user_preferences =
|
||||
storyboard.plugin.cron =
|
||||
cron-management = storyboard.plugin.cron.manager:CronManager
|
||||
token-cleaner = storyboard.plugin.oauth.cleaner:TokenCleaner
|
||||
|
||||
[build_sphinx]
|
||||
source-dir = doc/source
|
||||
|
0
storyboard/plugin/oauth/__init__.py
Normal file
0
storyboard/plugin/oauth/__init__.py
Normal file
59
storyboard/plugin/oauth/cleaner.py
Normal file
59
storyboard/plugin/oauth/cleaner.py
Normal file
@ -0,0 +1,59 @@
|
||||
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
|
||||
import storyboard.db.api.base as api_base
|
||||
from storyboard.db.models import AccessToken
|
||||
from storyboard.plugin.cron.base import CronPluginBase
|
||||
|
||||
|
||||
class TokenCleaner(CronPluginBase):
|
||||
"""A Cron Plugin which checks periodically for expired auth tokens and
|
||||
removes them from the database. By default it only cleans up expired
|
||||
tokens that are more than a week old, to permit some historical debugging
|
||||
forensics.
|
||||
"""
|
||||
|
||||
def enabled(self):
|
||||
"""Indicate whether this plugin is enabled. This indicates whether
|
||||
this plugin alone is runnable, as opposed to the entire cron system.
|
||||
"""
|
||||
return True
|
||||
|
||||
def interval(self):
|
||||
"""This plugin executes on startup, and once every hour after that.
|
||||
|
||||
:return: "? * * * *"
|
||||
"""
|
||||
return "? * * * *"
|
||||
|
||||
def run(self, start_time, end_time):
|
||||
"""Remove all oauth tokens that are more than a week old.
|
||||
|
||||
:param start_time: The last time the plugin was run.
|
||||
:param end_time: The current timestamp.
|
||||
"""
|
||||
# Calculate last week.
|
||||
lastweek = datetime.utcnow() - timedelta(weeks=1)
|
||||
|
||||
# Build the query.
|
||||
query = api_base.model_query(AccessToken)
|
||||
|
||||
# Apply the filter.
|
||||
query = query.filter(AccessToken.expires_at < lastweek)
|
||||
|
||||
# Batch delete.
|
||||
query.delete()
|
@ -245,8 +245,8 @@ class TestCronManager(base.TestCase):
|
||||
manager = cronmanager.CronManager(CONF, tabfile=self.tabfile)
|
||||
manager.execute()
|
||||
|
||||
# We're expecting 1 in-branch plugins.
|
||||
self.assertCronLength(1, command='storyboard-cron')
|
||||
# We're expecting 2 in-branch plugins.
|
||||
self.assertCronLength(2, command='storyboard-cron')
|
||||
|
||||
def test_execute_update(self):
|
||||
"""Test that execute() method updates plugins."""
|
||||
@ -311,9 +311,8 @@ class TestCronManager(base.TestCase):
|
||||
manager.execute()
|
||||
|
||||
# Check a new crontab to see what we find.
|
||||
cron = crontab.CronTab(tabfile=self.tabfile)
|
||||
self.assertCronLength(0, command=plugin_command)
|
||||
self.assertCronLength(1, command='storyboard-cron')
|
||||
self.assertCronLength(2, command='storyboard-cron')
|
||||
|
||||
# Cleanup after ourselves.
|
||||
manager.remove()
|
||||
@ -344,7 +343,7 @@ class TestCronManager(base.TestCase):
|
||||
manager.execute()
|
||||
|
||||
# Check a new crontab to see what we find.
|
||||
self.assertCronLength(1, command='storyboard-cron')
|
||||
self.assertCronLength(2, command='storyboard-cron')
|
||||
|
||||
# Cleanup after ourselves.
|
||||
manager.remove()
|
||||
|
0
storyboard/tests/plugin/oauth/__init__.py
Normal file
0
storyboard/tests/plugin/oauth/__init__.py
Normal file
85
storyboard/tests/plugin/oauth/test_cleaner.py
Normal file
85
storyboard/tests/plugin/oauth/test_cleaner.py
Normal file
@ -0,0 +1,85 @@
|
||||
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
|
||||
from oslo.config import cfg
|
||||
import storyboard.db.api.base as db_api
|
||||
from storyboard.db.models import AccessToken
|
||||
from storyboard.plugin.oauth.cleaner import TokenCleaner
|
||||
import storyboard.tests.base as base
|
||||
from storyboard.tests.mock_data import load_data
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class TestTokenCleaner(base.FunctionalTest):
|
||||
"""Test cases for our OAuth Token cleaner plugin."""
|
||||
|
||||
def setUp(self):
|
||||
super(TestTokenCleaner, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestTokenCleaner, self).tearDown()
|
||||
|
||||
def test_enabled(self):
|
||||
"""This plugin must always be enabled. The only time it's not enabled
|
||||
is when cron has been disabled.
|
||||
"""
|
||||
plugin = TokenCleaner(CONF)
|
||||
self.assertTrue(plugin.enabled())
|
||||
|
||||
def test_interval(self):
|
||||
"""Assert that the cron manager runs every 5 minutes."""
|
||||
plugin = TokenCleaner(CONF)
|
||||
self.assertEqual("? * * * *", plugin.interval())
|
||||
|
||||
def test_token_removal(self):
|
||||
"""Assert that the plugin deletes tokens whose expiration date passed
|
||||
over a week ago.
|
||||
"""
|
||||
|
||||
# Start with a clean database.
|
||||
db_api.model_query(AccessToken).delete()
|
||||
self.assertEqual(0, db_api.model_query(AccessToken).count())
|
||||
|
||||
# Build 100 tokens, each one day older than the other, with 24 hour
|
||||
# expiration dates. I subtract 5 seconds here because the time it
|
||||
# takes to execute the script may, or may not, result in an
|
||||
# 8-day-old-token to remain valid.
|
||||
for i in range(0, 100):
|
||||
created_at = datetime.utcnow() - timedelta(days=i)
|
||||
expires_in = (60 * 60 * 24) - 5 # Minus five seconds, see above.
|
||||
expires_at = created_at + timedelta(seconds=expires_in)
|
||||
|
||||
load_data([
|
||||
AccessToken(
|
||||
user_id=1,
|
||||
created_at=created_at.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
expires_in=expires_in,
|
||||
expires_at=expires_at.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
access_token='test_token_%s' % (i,))
|
||||
])
|
||||
|
||||
# Make sure we have 100 tokens.
|
||||
self.assertEqual(100, db_api.model_query(AccessToken).count())
|
||||
|
||||
# Run the plugin.
|
||||
plugin = TokenCleaner(CONF)
|
||||
plugin.execute()
|
||||
|
||||
# Make sure we have 8 tokens left (since one plugin starts today).
|
||||
self.assertEqual(8, db_api.model_query(AccessToken).count())
|
Loading…
x
Reference in New Issue
Block a user