Marsmallowing destinations (#311)

This commit is contained in:
kevgliss 2016-05-10 13:43:26 -07:00
parent 5e9f1437ad
commit 93791c999d
4 changed files with 124 additions and 149 deletions

View File

@ -0,0 +1,29 @@
"""
.. module: lemur.destinations.schemas
:platform: unix
:copyright: (c) 2015 by Netflix Inc., see AUTHORS for more
:license: Apache, see LICENSE for more details.
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
"""
from marshmallow import fields
from lemur.common.schema import LemurInputSchema, LemurOutputSchema
from lemur.schemas import PluginSchema
class DestinationInputSchema(LemurInputSchema):
label = fields.String(required=True)
options = fields.Dict(required=True)
description = fields.String()
plugin = fields.Nested(PluginSchema, required=True)
class DestinationOutputSchema(LemurOutputSchema):
label = fields.String()
options = fields.Dict(dump_to='destination_options')
description = fields.String()
destination_input_schema = DestinationInputSchema()
destinations_output_schema = DestinationOutputSchema(many=True)
destination_output_schema = DestinationOutputSchema()

View File

@ -86,10 +86,6 @@ def get_all():
def render(args): def render(args):
sort_by = args.pop('sort_by')
sort_dir = args.pop('sort_dir')
page = args.pop('page')
count = args.pop('count')
filt = args.pop('filter') filt = args.pop('filter')
certificate_id = args.pop('certificate_id', None) certificate_id = args.pop('certificate_id', None)
@ -103,12 +99,7 @@ def render(args):
terms = filt.split(';') terms = filt.split(';')
query = database.filter(query, Destination, terms) query = database.filter(query, Destination, terms)
query = database.find_all(query, Destination, args) return database.sort_and_page(query, Destination, args)
if sort_by and sort_dir:
query = database.sort(query, Destination, sort_by, sort_dir)
return database.paginate(query, page, count)
def stats(**kwargs): def stats(**kwargs):

View File

@ -7,34 +7,28 @@
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com> .. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
""" """
from flask import Blueprint from flask import Blueprint
from flask.ext.restful import Api, reqparse, fields from flask.ext.restful import Api, reqparse
from lemur.destinations import service from lemur.destinations import service
from lemur.auth.service import AuthenticatedResource from lemur.auth.service import AuthenticatedResource
from lemur.auth.permissions import admin_permission from lemur.auth.permissions import admin_permission
from lemur.common.utils import paginated_parser, marshal_items from lemur.common.utils import paginated_parser
from lemur.common.schema import validate_schema
from lemur.destinations.schemas import destinations_output_schema, destination_input_schema, destination_output_schema
mod = Blueprint('destinations', __name__) mod = Blueprint('destinations', __name__)
api = Api(mod) api = Api(mod)
FIELDS = {
'description': fields.String,
'destinationOptions': fields.Raw(attribute='options'),
'pluginName': fields.String(attribute='plugin_name'),
'label': fields.String,
'id': fields.Integer,
}
class DestinationsList(AuthenticatedResource): class DestinationsList(AuthenticatedResource):
""" Defines the 'destinations' endpoint """ """ Defines the 'destinations' endpoint """
def __init__(self): def __init__(self):
self.reqparse = reqparse.RequestParser() self.reqparse = reqparse.RequestParser()
super(DestinationsList, self).__init__() super(DestinationsList, self).__init__()
@marshal_items(FIELDS) @validate_schema(None, destinations_output_schema)
def get(self): def get(self):
""" """
.. http:get:: /destinations .. http:get:: /destinations
@ -92,8 +86,8 @@ class DestinationsList(AuthenticatedResource):
return service.render(args) return service.render(args)
@admin_permission.require(http_exception=403) @admin_permission.require(http_exception=403)
@marshal_items(FIELDS) @validate_schema(destination_input_schema, destination_output_schema)
def post(self): def post(self, data=None):
""" """
.. http:post:: /destinations .. http:post:: /destinations
@ -154,12 +148,7 @@ class DestinationsList(AuthenticatedResource):
:reqheader Authorization: OAuth token to authenticate :reqheader Authorization: OAuth token to authenticate
:statuscode 200: no error :statuscode 200: no error
""" """
self.reqparse.add_argument('label', type=str, location='json', required=True) return service.create(data['label'], data['plugin']['slug'], data['plugin']['pluginOptions'], data['description'])
self.reqparse.add_argument('plugin', type=dict, location='json', required=True)
self.reqparse.add_argument('description', type=str, location='json')
args = self.reqparse.parse_args()
return service.create(args['label'], args['plugin']['slug'], args['plugin']['pluginOptions'], args['description'])
class Destinations(AuthenticatedResource): class Destinations(AuthenticatedResource):
@ -167,7 +156,7 @@ class Destinations(AuthenticatedResource):
self.reqparse = reqparse.RequestParser() self.reqparse = reqparse.RequestParser()
super(Destinations, self).__init__() super(Destinations, self).__init__()
@marshal_items(FIELDS) @validate_schema(None, destination_output_schema)
def get(self, destination_id): def get(self, destination_id):
""" """
.. http:get:: /destinations/1 .. http:get:: /destinations/1
@ -213,8 +202,8 @@ class Destinations(AuthenticatedResource):
return service.get(destination_id) return service.get(destination_id)
@admin_permission.require(http_exception=403) @admin_permission.require(http_exception=403)
@marshal_items(FIELDS) @validate_schema(destination_input_schema, destination_output_schema)
def put(self, destination_id): def put(self, destination_id, data=None):
""" """
.. http:put:: /destinations/1 .. http:put:: /destinations/1
@ -276,12 +265,7 @@ class Destinations(AuthenticatedResource):
:reqheader Authorization: OAuth token to authenticate :reqheader Authorization: OAuth token to authenticate
:statuscode 200: no error :statuscode 200: no error
""" """
self.reqparse.add_argument('label', type=str, location='json', required=True) return service.update(destination_id, data['label'], data['plugin']['pluginOptions'], data['description'])
self.reqparse.add_argument('plugin', type=dict, location='json', required=True)
self.reqparse.add_argument('description', type=str, location='json')
args = self.reqparse.parse_args()
return service.update(destination_id, args['label'], args['plugin']['pluginOptions'], args['description'])
@admin_permission.require(http_exception=403) @admin_permission.require(http_exception=403)
def delete(self, destination_id): def delete(self, destination_id):
@ -294,7 +278,7 @@ class CertificateDestinations(AuthenticatedResource):
def __init__(self): def __init__(self):
super(CertificateDestinations, self).__init__() super(CertificateDestinations, self).__init__()
@marshal_items(FIELDS) @validate_schema(None, destination_output_schema)
def get(self, certificate_id): def get(self, certificate_id):
""" """
.. http:get:: /certificates/1/destinations .. http:get:: /certificates/1/destinations

View File

@ -1,134 +1,105 @@
from lemur.destinations.service import * # noqa import pytest
from lemur.destinations.views import * # noqa from lemur.destinations.views import * # noqa
from json import dumps
from .vectors import VALID_ADMIN_HEADER_TOKEN, VALID_USER_HEADER_TOKEN
def test_crud(session): def test_destination_input_schema(client, destination):
destination = create('testdest', 'aws-destination', {}, description='destination1') from lemur.destinations.schemas import DestinationInputSchema
assert destination.id > 0
destination = update(destination.id, 'testdest2', {}, 'destination2') input_data = {
assert destination.label == 'testdest2' 'label': 'destination1',
'options': {},
'description': 'my destination',
'active': True,
'plugin': {
'slug': 'aws-destination'
}
}
assert len(get_all()) == 1 data, errors = DestinationInputSchema().load(input_data)
delete(1) assert not errors
assert len(get_all()) == 0
def test_destination_get(client): @pytest.mark.parametrize("token,status", [
assert client.get(api.url_for(Destinations, destination_id=1)).status_code == 401 (VALID_USER_HEADER_TOKEN, 404),
(VALID_ADMIN_HEADER_TOKEN, 404),
('', 401)
])
def test_destination_get(client, token, status):
assert client.get(api.url_for(Destinations, destination_id=1), headers=token).status_code == status
def test_destination_post(client): @pytest.mark.parametrize("token,status", [
assert client.post(api.url_for(Destinations, destination_id=1), data={}).status_code == 405 (VALID_USER_HEADER_TOKEN, 405),
(VALID_ADMIN_HEADER_TOKEN, 405),
('', 405)
])
def test_destination_post_(client, token, status):
assert client.post(api.url_for(Destinations, destination_id=1), data={}, headers=token).status_code == status
def test_destination_put(client): @pytest.mark.parametrize("token,status", [
assert client.put(api.url_for(Destinations, destination_id=1), data={}).status_code == 401 (VALID_USER_HEADER_TOKEN, 403),
(VALID_ADMIN_HEADER_TOKEN, 400),
('', 401)
])
def test_destination_put(client, token, status):
assert client.put(api.url_for(Destinations, destination_id=1), data={}, headers=token).status_code == status
def test_destination_delete(client): @pytest.mark.parametrize("token,status", [
assert client.delete(api.url_for(Destinations, destination_id=1)).status_code == 401 (VALID_USER_HEADER_TOKEN, 403),
(VALID_ADMIN_HEADER_TOKEN, 200),
('', 401)
])
def test_destination_delete(client, token, status):
assert client.delete(api.url_for(Destinations, destination_id=1), headers=token).status_code == status
def test_destination_patch(client): @pytest.mark.parametrize("token,status", [
assert client.patch(api.url_for(Destinations, destination_id=1), data={}).status_code == 405 (VALID_USER_HEADER_TOKEN, 405),
(VALID_ADMIN_HEADER_TOKEN, 405),
('', 405)
])
def test_destination_patch(client, token, status):
assert client.patch(api.url_for(Destinations, destination_id=1), data={}, headers=token).status_code == status
VALID_USER_HEADER_TOKEN = { @pytest.mark.parametrize("token,status", [
'Authorization': 'Basic ' + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0MzUyMzMzNjksInN1YiI6MSwiZXhwIjoxNTIxNTQ2OTY5fQ.1qCi0Ip7mzKbjNh0tVd3_eJOrae3rNa_9MCVdA4WtQI'} (VALID_USER_HEADER_TOKEN, 403),
(VALID_ADMIN_HEADER_TOKEN, 400),
('', 401)
])
def test_destination_list_post_(client, token, status):
assert client.post(api.url_for(DestinationsList), data={}, headers=token).status_code == status
def test_auth_destination_get(client): @pytest.mark.parametrize("token,status", [
assert client.get(api.url_for(Destinations, destination_id=1), headers=VALID_USER_HEADER_TOKEN).status_code == 200 (VALID_USER_HEADER_TOKEN, 200),
(VALID_ADMIN_HEADER_TOKEN, 200),
('', 401)
])
def test_destination_list_get(client, token, status):
assert client.get(api.url_for(DestinationsList), headers=token).status_code == status
def test_auth_destination_post_(client): @pytest.mark.parametrize("token,status", [
assert client.post(api.url_for(Destinations, destination_id=1), data={}, headers=VALID_USER_HEADER_TOKEN).status_code == 405 (VALID_USER_HEADER_TOKEN, 405),
(VALID_ADMIN_HEADER_TOKEN, 405),
('', 405)
])
def test_destination_list_delete(client, token, status):
assert client.delete(api.url_for(DestinationsList), headers=token).status_code == status
def test_auth_destination_put(client): @pytest.mark.parametrize("token,status", [
assert client.put(api.url_for(Destinations, destination_id=1), data={}, headers=VALID_USER_HEADER_TOKEN).status_code == 403 (VALID_USER_HEADER_TOKEN, 405),
(VALID_ADMIN_HEADER_TOKEN, 405),
('', 405)
def test_auth_destination_delete(client): ])
assert client.delete(api.url_for(Destinations, destination_id=1), headers=VALID_USER_HEADER_TOKEN).status_code == 403 def test_destination_list_patch(client, token, status):
assert client.patch(api.url_for(DestinationsList), data={}, headers=token).status_code == status
def test_auth_destination_patch(client):
assert client.patch(api.url_for(Destinations, destination_id=1), data={}, headers=VALID_USER_HEADER_TOKEN).status_code == 405
VALID_ADMIN_HEADER_TOKEN = {
'Authorization': 'Basic ' + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0MzUyNTAyMTgsInN1YiI6MiwiZXhwIjoxNTIxNTYzODE4fQ.6mbq4-Ro6K5MmuNiTJBB153RDhlM5LGJBjI7GBKkfqA'}
def test_admin_destination_get(client):
assert client.get(api.url_for(Destinations, destination_id=1), headers=VALID_ADMIN_HEADER_TOKEN).status_code == 200
def test_admin_destination_post(client):
assert client.post(api.url_for(Destinations, destination_id=1), data={}, headers=VALID_ADMIN_HEADER_TOKEN).status_code == 405
def test_admin_destination_put(client):
assert client.put(api.url_for(Destinations, destination_id=1), data={}, headers=VALID_ADMIN_HEADER_TOKEN).status_code == 400
def test_admin_destination_delete(client):
assert client.delete(api.url_for(Destinations, destination_id=1), headers=VALID_ADMIN_HEADER_TOKEN).status_code == 200
def test_admin_destination_patch(client):
assert client.patch(api.url_for(Destinations, destination_id=1), data={}, headers=VALID_ADMIN_HEADER_TOKEN).status_code == 405
def test_destinations_get(client):
assert client.get(api.url_for(DestinationsList)).status_code == 401
def test_destinations_post(client):
assert client.post(api.url_for(DestinationsList), data={}).status_code == 401
def test_destinations_put(client):
assert client.put(api.url_for(DestinationsList), data={}).status_code == 405
def test_destinations_delete(client):
assert client.delete(api.url_for(DestinationsList)).status_code == 405
def test_destinations_patch(client):
assert client.patch(api.url_for(DestinationsList), data={}).status_code == 405
def test_auth_destinations_get(client):
assert client.get(api.url_for(DestinationsList), headers=VALID_USER_HEADER_TOKEN).status_code == 200
def test_auth_destinations_post(client):
assert client.post(api.url_for(DestinationsList), data={}, headers=VALID_USER_HEADER_TOKEN).status_code == 403
def test_admin_destinations_get(client):
resp = client.get(api.url_for(DestinationsList), headers=VALID_ADMIN_HEADER_TOKEN)
assert resp.status_code == 200
assert resp.json == {'items': [], 'total': 0}
def test_admin_destinations_crud(client):
assert client.post(api.url_for(DestinationsList), headers=VALID_ADMIN_HEADER_TOKEN).status_code == 400
data = {'plugin': {'slug': 'aws-destination', 'pluginOptions': {}}, 'label': 'test', 'description': 'test'}
resp = client.post(api.url_for(DestinationsList), data=dumps(data), content_type='application/json', headers=VALID_ADMIN_HEADER_TOKEN)
assert resp.status_code == 200
assert client.get(api.url_for(Destinations, destination_id=resp.json['id']), headers=VALID_ADMIN_HEADER_TOKEN).status_code == 200
resp = client.get(api.url_for(DestinationsList), headers=VALID_ADMIN_HEADER_TOKEN)
assert resp.status_code == 200
assert resp.json['items'][0]['description'] == 'test'
assert client.delete(api.url_for(Destinations, destination_id=2), headers=VALID_ADMIN_HEADER_TOKEN).status_code == 200
resp = client.get(api.url_for(DestinationsList), headers=VALID_ADMIN_HEADER_TOKEN)
assert resp.status_code == 200
assert resp.json == {'items': [], 'total': 0}