Remove storing xml files on each feed generation

This commit removes the file storing from the rss endpoint. The code
is buggy and also a potential sec issue. It also isn't actually needed
as most (if not all) rss reader will handle missing entries fine, as
long as the ids are unique it shouldn't matter. So even if we lose old
entries on a crash or restart it won't be an issue.

Change-Id: I595abc566880ae6c778b00affde12e2227c9ec35
This commit is contained in:
Matthew Treinish 2016-04-21 23:00:16 -04:00
parent 6939cd42f6
commit 04610c054e
No known key found for this signature in database
GPG Key ID: FD12A0F214C9E177
4 changed files with 9 additions and 102 deletions

View File

@ -17,14 +17,11 @@ import argparse
from contextlib import contextmanager from contextlib import contextmanager
from dateutil import parser as date_parser from dateutil import parser as date_parser
import itertools import itertools
import os
import six import six
from six.moves import configparser as ConfigParser from six.moves import configparser as ConfigParser
from six.moves.urllib import parse from six.moves.urllib import parse
import tempfile
from feedgen import feed from feedgen import feed
import feedparser
import flask import flask
from flask import abort from flask import abort
from flask.ext.jsonpify import jsonify from flask.ext.jsonpify import jsonify
@ -73,10 +70,6 @@ def setup():
pool_recycle=pool_recycle) pool_recycle=pool_recycle)
global Session global Session
Session = sessionmaker(bind=engine) Session = sessionmaker(bind=engine)
try:
rss_opts['data_dir'] = config.get('default', 'data_dir')
except ConfigParser.Error:
rss_opts['data_dir'] = tempfile.gettempdir()
try: try:
rss_opts['frontend_url'] = config.get('default', 'frontend_url') rss_opts['frontend_url'] = config.get('default', 'frontend_url')
except ConfigParser.Error: except ConfigParser.Error:
@ -356,29 +349,6 @@ def _gen_feed(url, key, value):
return fg return fg
def _get_stored_feed(url, key, value):
filename = key + '_' + value + '.xml'
file_path = os.path.join(rss_opts['data_dir'], filename)
if not os.path.isfile(file_path):
return None
feed = feedparser.parse(file_path)
out_feed = _gen_feed(url, key, value)
if not feed.entries:
return None
last_run = sorted(
[date_parser.parse(x.published) for x in feed.entries])[-1]
last_run = last_run.replace(tzinfo=None)
for i in feed.entries:
entry = out_feed.add_entry()
entry.id(i.id)
entry.title(i.title)
time = date_parser.parse(i.published)
entry.published(time)
entry.link({'href': i.link, 'rel': 'alternate'})
entry.description(i.description)
return out_feed, last_run
@app.route('/runs/key/<path:run_metadata_key>/<path:value>/recent/rss', @app.route('/runs/key/<path:run_metadata_key>/<path:value>/recent/rss',
methods=['GET']) methods=['GET'])
def get_recent_failed_runs_rss(run_metadata_key, value): def get_recent_failed_runs_rss(run_metadata_key, value):
@ -386,25 +356,15 @@ def get_recent_failed_runs_rss(run_metadata_key, value):
value = parse.unquote(value) value = parse.unquote(value)
url = request.url url = request.url
if run_metadata_key not in feeds: if run_metadata_key not in feeds:
stored_feed = _get_stored_feed(url, run_metadata_key, value) feeds[run_metadata_key] = {value: _gen_feed(url,
if stored_feed: run_metadata_key,
feeds[run_metadata_key] = {value: stored_feed[0]} value)}
feeds["last runs"][run_metadata_key] = {value: stored_feed[1]} feeds["last runs"][run_metadata_key] = {value: None}
else:
feeds[run_metadata_key] = {value: _gen_feed(url,
run_metadata_key,
value)}
feeds["last runs"][run_metadata_key] = {value: None}
elif value not in feeds[run_metadata_key]: elif value not in feeds[run_metadata_key]:
stored_feed = _get_stored_feed(url, run_metadata_key, value) feeds[run_metadata_key][value] = _gen_feed(url,
if stored_feed: run_metadata_key,
feeds[run_metadata_key][value] = stored_feed[0] value)
feeds["last runs"][run_metadata_key][value] = stored_feed[1] feeds["last runs"][run_metadata_key][value] = None
else:
feeds[run_metadata_key][value] = _gen_feed(url,
run_metadata_key,
value)
feeds["last runs"][run_metadata_key][value] = None
fg = feeds[run_metadata_key][value] fg = feeds[run_metadata_key][value]
with session_scope() as session: with session_scope() as session:
failed_runs = api.get_recent_failed_runs_by_run_metadata( failed_runs = api.get_recent_failed_runs_by_run_metadata(
@ -437,9 +397,6 @@ def get_recent_failed_runs_rss(run_metadata_key, value):
content = 'Metadata page: %s\n' % metadata_url content = 'Metadata page: %s\n' % metadata_url
content += '\nJob Page %s' % job_url content += '\nJob Page %s' % job_url
entry.description(content) entry.description(content)
filename = run_metadata_key + '_' + value + '.xml'
out_path = os.path.join(rss_opts['data_dir'], filename)
feeds[run_metadata_key][value].rss_file(out_path)
return feeds[run_metadata_key][value].rss_str() return feeds[run_metadata_key][value].rss_str()

View File

@ -14,7 +14,6 @@
import datetime import datetime
import json import json
import os
import tempfile import tempfile
import uuid import uuid
@ -22,7 +21,6 @@ from dateutil import parser as date_parser
import feedparser import feedparser
import mock import mock
import numpy import numpy
import pytz
import six import six
from subunit2sql.db import models from subunit2sql.db import models
@ -841,48 +839,6 @@ class TestRestAPI(base.TestCase):
self.assertEqual(url, res['feed']['link']) self.assertEqual(url, res['feed']['link'])
self.assertEqual('en', res['feed']['language']) self.assertEqual('en', res['feed']['language'])
def test__get_stored_feed_no_feed(self):
api.rss_opts['data_dir'] = tempfile.gettempdir()
self.assertIsNone(
api._get_stored_feed('fake_url', 'not_a_real_key', 'real_value'))
def test__get_stored_feed_with_file_no_entries(self):
api.rss_opts['data_dir'] = tempfile.gettempdir()
url = 'fake_url'
key = 'zeon'
value = 'zaku'
fg = api._gen_feed(url, key, value)
filename = key + '_' + value + '.xml'
path = os.path.join(api.rss_opts['data_dir'], filename)
fg.rss_file(path)
self.addCleanup(os.remove, path)
self.assertIsNone(api._get_stored_feed(url, key, value))
def test__get_stored_feed_with_file_with_entries(self):
api.rss_opts['data_dir'] = tempfile.gettempdir()
url = 'fake_url'
key = 'zeon'
value = 'gouf'
fg = api._gen_feed(url, key, value)
entry = fg.add_entry()
entry.id('not a zaku')
entry.title("This i snot the title you're looking for")
entry.published(pytz.utc.localize(timestamp_a))
entry.link({'href': 'a_link'})
entry.description('A description')
filename = key + '_' + value + '.xml'
path = os.path.join(api.rss_opts['data_dir'], filename)
fg.rss_file(path)
self.addCleanup(os.remove, path)
out = api._get_stored_feed(url, key, value)
res = feedparser.parse(out[0].rss_str())
title = 'Failures for %s: %s' % (key, value)
self.assertEqual(timestamp_a, out[1])
self.assertEqual(title, res['feed']['title'])
self.assertEqual(url, res['feed']['link'])
self.assertEqual('en', res['feed']['language'])
self.assertEqual(1, len(res.entries))
@mock.patch('subunit2sql.db.api.get_recent_failed_runs_by_run_metadata', @mock.patch('subunit2sql.db.api.get_recent_failed_runs_by_run_metadata',
return_value=[ return_value=[
models.Run(uuid='a_uuid', run_at=timestamp_b, models.Run(uuid='a_uuid', run_at=timestamp_b,
@ -891,9 +847,6 @@ class TestRestAPI(base.TestCase):
]) ])
def test_get_recent_failed_runs_rss_no_previous(self, db_mock): def test_get_recent_failed_runs_rss_no_previous(self, db_mock):
api.rss_opts['data_dir'] = tempfile.gettempdir() api.rss_opts['data_dir'] = tempfile.gettempdir()
filename = 'a_key_a_value.xml'
path = os.path.join(api.rss_opts['data_dir'], filename)
self.addCleanup(os.remove, path)
api.rss_opts['frontend_url'] = 'http://status.openstack.org' api.rss_opts['frontend_url'] = 'http://status.openstack.org'
build_uuid = str(uuid.uuid4()) build_uuid = str(uuid.uuid4())
meta_mock = mock.patch( meta_mock = mock.patch(
@ -925,9 +878,6 @@ class TestRestAPI(base.TestCase):
]) ])
def test_get_recent_failed_runs_rss_with_previous(self, db_mock): def test_get_recent_failed_runs_rss_with_previous(self, db_mock):
api.rss_opts['data_dir'] = tempfile.gettempdir() api.rss_opts['data_dir'] = tempfile.gettempdir()
filename = 'b_key_b_value.xml'
path = os.path.join(api.rss_opts['data_dir'], filename)
self.addCleanup(os.remove, path)
api.rss_opts['frontend_url'] = 'http://status.openstack.org' api.rss_opts['frontend_url'] = 'http://status.openstack.org'
build_uuid = str(uuid.uuid4()) build_uuid = str(uuid.uuid4())
meta_mock = mock.patch( meta_mock = mock.patch(

View File

@ -13,4 +13,3 @@ numpy>=1.7.0 # BSD
six>=1.9.0 # MIT six>=1.9.0 # MIT
pytz>=2013.6 # MIT pytz>=2013.6 # MIT
feedgen>=0.3.2 # BSD feedgen>=0.3.2 # BSD
feedparser>=5.2.1

View File

@ -9,3 +9,4 @@ mock>=1.2 # BSD
fixtures>=1.3.1 # Apache-2.0/BSD fixtures>=1.3.1 # Apache-2.0/BSD
sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 # BSD sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 # BSD
oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0 oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0
feedparser>=5.2.1