Some code simplifications & logging for Zencoder notifications.

This commit is contained in:
Sybren A. Stüvel 2016-03-25 17:21:18 +01:00
parent d7ee2121d9
commit fd5bcaec52
2 changed files with 102 additions and 45 deletions

View File

@ -1,40 +1,51 @@
import logging
from bson import ObjectId from bson import ObjectId
from eve.methods.put import put_internal from eve.methods.put import put_internal
from flask import Blueprint from flask import Blueprint
from flask import abort from flask import abort
from flask import request from flask import request
from application import app from application import app
from application import utils
encoding = Blueprint('encoding', __name__) encoding = Blueprint('encoding', __name__)
log = logging.getLogger(__name__)
@encoding.route('/zencoder/notifications', methods=['POST']) @encoding.route('/zencoder/notifications', methods=['POST'])
def zencoder_notifications(): def zencoder_notifications():
if app.config['ENCODING_BACKEND'] == 'zencoder': if app.config['ENCODING_BACKEND'] != 'zencoder':
log.warning('Received notification from Zencoder but app not configured for Zencoder.')
return abort(403)
if not app.config['DEBUG']: if not app.config['DEBUG']:
# If we are in production, look for the Zencoder header secret # If we are in production, look for the Zencoder header secret
try: try:
notification_secret_request = request.headers[ notification_secret_request = request.headers[
'X-Zencoder-Notification-Secret'] 'X-Zencoder-Notification-Secret']
except KeyError: except KeyError:
log.warning('Received Zencoder notification without secret.')
return abort(401) return abort(401)
# If the header is found, check it agains the one in the config # If the header is found, check it agains the one in the config
notification_secret = app.config['ZENCODER_NOTIFICATIONS_SECRET'] notification_secret = app.config['ZENCODER_NOTIFICATIONS_SECRET']
if notification_secret_request != notification_secret: if notification_secret_request != notification_secret:
log.warning('Received Zencoder notification with incorrect secret.')
return abort(401) return abort(401)
# Cast request data into a dict # Cast request data into a dict
data = request.get_json() data = request.get_json()
files_collection = app.data.driver.db['files'] files_collection = app.data.driver.db['files']
# Find the file object based on processing backend and job_id # Find the file object based on processing backend and job_id
lookup = {'processing.backend': 'zencoder', 'processing.job_id': str( lookup = {'processing.backend': 'zencoder', 'processing.job_id': str(data['job']['id'])}
data['job']['id'])}
f = files_collection.find_one(lookup) f = files_collection.find_one(lookup)
if f: if not f:
log.warning('Unknown Zencoder job id %r', data['job']['id'])
return abort(404)
file_id = f['_id'] file_id = f['_id']
# Remove internal keys (so that we can run put internal) # Remove internal keys (so that we can run put internal)
internal_fields = ['_id', '_etag', '_updated', '_created', '_status'] f = utils.remove_private_keys(f)
for field in internal_fields:
f.pop(field, None)
# Update processing status # Update processing status
f['processing']['status'] = data['job']['state'] f['processing']['status'] = data['job']['state']
# For every variation encoded, try to update the file object # For every variation encoded, try to update the file object
@ -50,9 +61,5 @@ def zencoder_notifications():
if variation: if variation:
variation['length'] = output['file_size_in_bytes'] variation['length'] = output['file_size_in_bytes']
r = put_internal('files', f, **{'_id': ObjectId(file_id)}) put_internal('files', f, _id=ObjectId(file_id))
return '' return ''
else:
return abort(404)
else:
return abort(403)

50
tests/test_encoding.py Normal file
View File

@ -0,0 +1,50 @@
"""Test cases for the zencoder notifications."""
import json
from common_test_class import AbstractPillarTest
class ZencoderNotificationTest(AbstractPillarTest):
def test_missing_secret(self):
with self.app.test_request_context():
resp = self.client.post('/encoding/zencoder/notifications')
self.assertEqual(401, resp.status_code)
def test_wrong_secret(self):
with self.app.test_request_context():
resp = self.client.post('/encoding/zencoder/notifications',
headers={'X-Zencoder-Notification-Secret': 'koro'})
self.assertEqual(401, resp.status_code)
def test_good_secret_missing_file(self):
with self.app.test_request_context():
secret = self.app.config['ZENCODER_NOTIFICATIONS_SECRET']
resp = self.client.post('/encoding/zencoder/notifications',
data=json.dumps({'job': {'id': 'koro-007'}}),
headers={'X-Zencoder-Notification-Secret': secret,
'Content-Type': 'application/json'})
self.assertEqual(404, resp.status_code)
def test_good_secret_existing_file(self):
self.ensure_file_exists(file_overrides={
'processing': {'backend': 'zencoder',
'job_id': 'koro-007',
'status': 'processing'}
})
with self.app.test_request_context():
secret = self.app.config['ZENCODER_NOTIFICATIONS_SECRET']
resp = self.client.post('/encoding/zencoder/notifications',
data=json.dumps({'job': {'id': 'koro-007',
'state': 'done'},
'outputs': [{
'format': 'jpg',
'width': 2048,
'file_size_in_bytes': 15,
}]}),
headers={'X-Zencoder-Notification-Secret': secret,
'Content-Type': 'application/json'})
# TODO: check that the file in MongoDB is actually updated properly.
self.assertEqual(200, resp.status_code)