Pass request data as an argument to API methods

This commit generalises the approach taken by filtered_context; the
methods no longer access the request data directly but instead receive
it as an argument.

This change helps to standardise the code base. Also, by automatically
supplying the data as an argument, it reduces the likelihood that the
validation process will be bypassed when any new functionality is added.
In earlier version, some parts of the API were directly accessing the
raw request data via 'request.json' instead of the validated data that
was in 'g.json'.

Change-Id: Icba9612ef5fa968de706ede610cce111ec9723c1
Related-Bug: 1623095
This commit is contained in:
git-harry 2017-01-13 18:48:44 +00:00
parent 3fd67e5002
commit a894913ae6
9 changed files with 92 additions and 97 deletions

View File

@ -41,12 +41,11 @@ def filtered_context():
objname = f.__qualname__.split('.')[0].rstrip('s').lower()
@functools.wraps(f)
def method_wrapper(self, context):
query_filters = flask.g.args
def method_wrapper(self, context, request_args):
inspect.getmodule(f).LOG.info(
"Getting all %s objects that match filters %s" % (
objname, query_filters))
return f(self, context, **query_filters)
objname, request_args))
return f(self, context, request_args)
return method_wrapper
return decorator

View File

@ -1,5 +1,4 @@
from collections import OrderedDict
from flask import g
from operator import attrgetter
from oslo_serialization import jsonutils
from oslo_log import log
@ -81,9 +80,9 @@ class AnsibleInventory(base.Resource):
}
return inventory
def get(self, context):
region_id = g.args["region_id"]
cell_id = g.args["cell_id"]
def get(self, context, request_args):
region_id = request_args["region_id"]
cell_id = request_args["cell_id"]
filters = {}
if region_id:

View File

@ -1,4 +1,3 @@
from flask import g
from oslo_serialization import jsonutils
from oslo_log import log
@ -14,15 +13,15 @@ class Cells(base.Resource):
@base.http_codes
@base.filtered_context()
def get(self, context, **filters):
def get(self, context, request_args):
"""Get all cells, with optional filtering."""
cells_obj = dbapi.cells_get_all(context, filters)
cells_obj = dbapi.cells_get_all(context, request_args)
return jsonutils.to_primitive(cells_obj), 200, None
@base.http_codes
def post(self, context):
def post(self, context, request_data):
"""Create a new cell."""
json = util.copy_project_id_into_json(context, g.json)
json = util.copy_project_id_into_json(context, request_data)
cell_obj = dbapi.cells_create(context, json)
cell = jsonutils.to_primitive(cell_obj)
if 'variables' in json:
@ -41,9 +40,9 @@ class CellById(base.Resource):
cell['variables'] = jsonutils.to_primitive(cell_obj.variables)
return cell, 200, None
def put(self, context, id):
def put(self, context, id, request_data):
"""Update existing cell."""
cell_obj = dbapi.cells_update(context, id, g.json)
cell_obj = dbapi.cells_update(context, id, request_data)
return jsonutils.to_primitive(cell_obj), 200, None
@base.http_codes
@ -63,20 +62,20 @@ class CellsVariables(base.Resource):
return resp, 200, None
@base.http_codes
def put(self, context, id):
def put(self, context, id, request_data):
"""
Update existing cell variables, or create if it does
not exist.
"""
obj = dbapi.cells_variables_update(context, id, g.json)
obj = dbapi.cells_variables_update(context, id, request_data)
resp = {"variables": jsonutils.to_primitive(obj.variables)}
return resp, 200, None
@base.http_codes
def delete(self, context, id):
def delete(self, context, id, request_data):
"""Delete cell variables."""
# NOTE(sulo): this is not that great. Find a better way to do this.
# We can pass multiple keys suchs as key1=one key2=two etc. but not
# the best way to do this.
dbapi.cells_variables_delete(context, id, g.json)
dbapi.cells_variables_delete(context, id, request_data)
return None, 204, None

View File

@ -1,4 +1,3 @@
from flask import g
from oslo_serialization import jsonutils
from oslo_log import log
@ -14,15 +13,15 @@ class Hosts(base.Resource):
@base.http_codes
@base.filtered_context()
def get(self, context, **filters):
def get(self, context, request_args):
"""Get all hosts for region, with optional filtering."""
hosts_obj = dbapi.hosts_get_all(context, filters)
hosts_obj = dbapi.hosts_get_all(context, request_args)
return jsonutils.to_primitive(hosts_obj), 200, None
@base.http_codes
def post(self, context):
def post(self, context, request_data):
"""Create a new host."""
json = util.copy_project_id_into_json(context, g.json)
json = util.copy_project_id_into_json(context, request_data)
host_obj = dbapi.hosts_create(context, json)
host = jsonutils.to_primitive(host_obj)
if 'variables' in json:
@ -44,17 +43,17 @@ def format_variables(args, obj):
class HostById(base.Resource):
@base.http_codes
def get(self, context, id):
def get(self, context, id, request_args):
"""Get host by given id"""
host_obj = dbapi.hosts_get_by_id(context, id)
host_obj = format_variables(g.args, host_obj)
host_obj = format_variables(request_args, host_obj)
host = jsonutils.to_primitive(host_obj)
host['variables'] = jsonutils.to_primitive(host_obj.vars)
return host, 200, None
def put(self, context, id):
def put(self, context, id, request_data):
"""Update existing host data, or create if it does not exist."""
host_obj = dbapi.hosts_update(context, id, g.json)
host_obj = dbapi.hosts_update(context, id, request_data)
return jsonutils.to_primitive(host_obj), 200, None
@base.http_codes
@ -67,27 +66,27 @@ class HostById(base.Resource):
class HostsVariables(base.Resource):
@base.http_codes
def get(self, context, id):
def get(self, context, id, request_args):
"""Get variables for given host."""
obj = dbapi.hosts_get_by_id(context, id)
obj = format_variables(g.args, obj)
obj = format_variables(request_args, obj)
response = {"variables": jsonutils.to_primitive(obj.vars)}
return response, 200, None
@base.http_codes
def put(self, context, id):
def put(self, context, id, request_data):
"""Update existing host variables, or create if it does not exist."""
obj = dbapi.hosts_variables_update(context, id, g.json)
obj = dbapi.hosts_variables_update(context, id, request_data)
response = {"variables": jsonutils.to_primitive(obj.variables)}
return response, 200, None
@base.http_codes
def delete(self, context, id):
def delete(self, context, id, request_data):
"""Delete host variables."""
# NOTE(sulo): this is not that great. Find a better way to do this.
# We can pass multiple keys suchs as key1=one key2=two etc. but not
# the best way to do this.
dbapi.hosts_variables_delete(context, id, g.json)
dbapi.hosts_variables_delete(context, id, request_data)
return None, 204, None
@ -101,17 +100,17 @@ class HostsLabels(base.Resource):
return response, 200, None
@base.http_codes
def put(self, context, id):
def put(self, context, id, request_data):
"""
Update existing device label entirely, or add if it does
not exist.
"""
resp = dbapi.hosts_labels_update(context, id, g.json)
resp = dbapi.hosts_labels_update(context, id, request_data)
response = {"labels": list(resp.labels)}
return response, 200, None
@base.http_codes
def delete(self, context, id):
def delete(self, context, id, request_data):
"""Delete device label entirely."""
dbapi.hosts_labels_delete(context, id, g.json)
dbapi.hosts_labels_delete(context, id, request_data)
return None, 204, None

View File

@ -1,4 +1,3 @@
from flask import g
from oslo_serialization import jsonutils
from oslo_log import log
@ -15,15 +14,15 @@ class Networks(base.Resource):
@base.http_codes
@base.filtered_context()
def get(self, context, **filters):
def get(self, context, request_args):
"""Get all networks, with optional filtering."""
networks_obj = dbapi.networks_get_all(context, filters)
networks_obj = dbapi.networks_get_all(context, request_args)
return jsonutils.to_primitive(networks_obj), 200, None
@base.http_codes
def post(self, context):
def post(self, context, request_data):
"""Create a new network."""
json = util.copy_project_id_into_json(context, g.json)
json = util.copy_project_id_into_json(context, request_data)
network_obj = dbapi.networks_create(context, json)
return jsonutils.to_primitive(network_obj), 200, None
@ -39,9 +38,9 @@ class NetworkById(base.Resource):
device['variables'] = jsonutils.to_primitive(obj.variables)
return device, 200, None
def put(self, context, id):
def put(self, context, id, request_data):
"""Update existing network values."""
net_obj = dbapi.networks_update(context, id, g.json)
net_obj = dbapi.networks_update(context, id, request_data)
return jsonutils.to_primitive(net_obj), 200, None
@base.http_codes
@ -62,16 +61,16 @@ class NetworksVariables(base.Resource):
return resp, 200, None
@base.http_codes
def put(self, context, id):
def put(self, context, id, request_data):
""""Update existing variables, or create if it does not exist."""
obj = dbapi.networks_variables_update(context, id, g.json)
obj = dbapi.networks_variables_update(context, id, request_data)
resp = {"variables": jsonutils.to_primitive(obj.variables)}
return resp, 200, None
@base.http_codes
def delete(self, context, id):
def delete(self, context, id, request_data):
"""Delete networks variables."""
dbapi.networks_variables_delete(context, id, g.json)
dbapi.networks_variables_delete(context, id, request_data)
return None, 204, None
@ -80,15 +79,15 @@ class NetworkDevices(base.Resource):
@base.http_codes
@base.filtered_context()
def get(self, context, **filters):
def get(self, context, request_args):
"""Get all network devices."""
devices_obj = dbapi.network_devices_get_all(context, filters)
devices_obj = dbapi.network_devices_get_all(context, request_args)
return jsonutils.to_primitive(devices_obj), 200, None
@base.http_codes
def post(self, context):
def post(self, context, request_data):
"""Create a new network device."""
json = util.copy_project_id_into_json(context, g.json)
json = util.copy_project_id_into_json(context, request_data)
obj = dbapi.network_devices_create(context, json)
device = jsonutils.to_primitive(obj)
return device, 200, None
@ -98,9 +97,9 @@ class NetworkDeviceById(base.Resource):
"""Controller for Network Devices by ID."""
@base.http_codes
def get(self, context, id):
def get(self, context, id, request_args):
"""Get network device by given id"""
resolved_values = g.args["resolved-values"]
resolved_values = request_args["resolved-values"]
obj = dbapi.network_devices_get_by_id(context, id)
if resolved_values:
obj.vars = obj.resolved
@ -110,9 +109,9 @@ class NetworkDeviceById(base.Resource):
device['variables'] = jsonutils.to_primitive(obj.vars)
return device, 200, None
def put(self, context, id):
def put(self, context, id, request_data):
"""Update existing device values."""
net_obj = dbapi.network_devices_update(context, id, g.json)
net_obj = dbapi.network_devices_update(context, id, request_data)
return jsonutils.to_primitive(net_obj), 200, None
@base.http_codes
@ -133,16 +132,16 @@ class NetworkDevicesVariables(base.Resource):
return resp, 200, None
@base.http_codes
def put(self, context, id):
def put(self, context, id, request_data):
""""Update device variables, or create if it does not exist."""
obj = dbapi.network_devices_variables_update(context, id, g.json)
obj = dbapi.network_devices_variables_update(context, id, request_data)
resp = {"variables": jsonutils.to_primitive(obj.variables)}
return resp, 200, None
@base.http_codes
def delete(self, context, id):
def delete(self, context, id, request_data):
"""Delete network device variables."""
dbapi.network_devices_variables_delete(context, id, g.json)
dbapi.network_devices_variables_delete(context, id, request_data)
return None, 204, None
@ -157,9 +156,9 @@ class NetworkDeviceLabels(base.Resource):
return response, 200, None
@base.http_codes
def put(self, context, id):
def put(self, context, id, request_data):
"""Update existing device label. Adds if it does not exist."""
resp = dbapi.network_devices_labels_update(context, id, g.json)
resp = dbapi.network_devices_labels_update(context, id, request_data)
response = {"labels": list(resp.labels)}
return response, 200, None
@ -175,15 +174,17 @@ class NetworkInterfaces(base.Resource):
@base.http_codes
@base.filtered_context()
def get(self, context, **filters):
def get(self, context, request_args):
"""Get all network interfaces."""
interfaces_obj = dbapi.network_interfaces_get_all(context, filters)
interfaces_obj = dbapi.network_interfaces_get_all(
context, request_args
)
return jsonutils.to_primitive(interfaces_obj), 200, None
@base.http_codes
def post(self, context):
def post(self, context, request_data):
"""Create a new network interface."""
json = util.copy_project_id_into_json(context, g.json)
json = util.copy_project_id_into_json(context, request_data)
obj = dbapi.network_interfaces_create(context, json)
interface = jsonutils.to_primitive(obj)
return interface, 200, None
@ -199,9 +200,9 @@ class NetworkInterfaceById(base.Resource):
interface['variables'] = jsonutils.to_primitive(obj.variables)
return interface, 200, None
def put(self, context, id):
def put(self, context, id, request_data):
"""Update existing network interface values."""
net_obj = dbapi.network_interfaces_update(context, id, g.json)
net_obj = dbapi.network_interfaces_update(context, id, request_data)
return jsonutils.to_primitive(net_obj), 200, None
@base.http_codes

View File

@ -1,4 +1,3 @@
from flask import g
from oslo_serialization import jsonutils
from oslo_log import log
@ -14,16 +13,16 @@ class Regions(base.Resource):
@base.http_codes
@base.filtered_context()
def get(self, context, **filters):
def get(self, context, request_args):
"""Get region(s) for the project. Get region details if
for a particular region.
"""
region_id = filters.get("id")
region_name = filters.get("name")
region_id = request_args.get("id")
region_name = request_args.get("name")
if not region_id and not region_name:
# Get all regions for this tenant
regions_obj = dbapi.regions_get_all(context, filters)
regions_obj = dbapi.regions_get_all(context, request_args)
return jsonutils.to_primitive(regions_obj), 200, None
if region_name:
@ -37,9 +36,9 @@ class Regions(base.Resource):
return jsonutils.to_primitive([region_obj]), 200, None
@base.http_codes
def post(self, context):
def post(self, context, request_data):
"""Create a new region."""
json = util.copy_project_id_into_json(context, g.json)
json = util.copy_project_id_into_json(context, request_data)
region_obj = dbapi.regions_create(context, json)
region = jsonutils.to_primitive(region_obj)
if 'variables' in json:
@ -58,9 +57,9 @@ class RegionsById(base.Resource):
region['variables'] = jsonutils.to_primitive(region_obj.variables)
return region, 200, None
def put(self, context, id):
def put(self, context, id, request_data):
"""Update existing region."""
region_obj = dbapi.regions_update(context, id, g.json)
region_obj = dbapi.regions_update(context, id, request_data)
return jsonutils.to_primitive(region_obj), 200, None
@base.http_codes
@ -80,17 +79,17 @@ class RegionsVariables(base.Resource):
return response, 200, None
@base.http_codes
def put(self, context, id):
def put(self, context, id, request_data):
"""
Update existing region variables, or create if it does
not exist.
"""
obj = dbapi.regions_variables_update(context, id, g.json)
obj = dbapi.regions_variables_update(context, id, request_data)
response = {"variables": jsonutils.to_primitive(obj.variables)}
return response, 200, None
@base.http_codes
def delete(self, context, id):
def delete(self, context, id, request_data):
"""Delete region variables."""
dbapi.regions_variables_delete(context, id, g.json)
dbapi.regions_variables_delete(context, id, request_data)
return None, 204, None

View File

@ -1,4 +1,3 @@
from flask import g
from oslo_serialization import jsonutils
from oslo_log import log
@ -12,10 +11,10 @@ LOG = log.getLogger(__name__)
class Projects(base.Resource):
@base.http_codes
def get(self, context):
def get(self, context, request_args):
"""Get all projects. Requires super admin privileges."""
project_id = g.args["id"]
project_name = g.args["name"]
project_id = request_args["id"]
project_name = request_args["name"]
if project_name:
project_obj = dbapi.projects_get_by_name(context, project_name)
@ -29,9 +28,9 @@ class Projects(base.Resource):
return jsonutils.to_primitive(projects_obj), 200, None
@base.http_codes
def post(self, context):
def post(self, context, request_data):
"""Create a new project. Requires super admin privileges."""
project_obj = dbapi.projects_create(context, g.json)
project_obj = dbapi.projects_create(context, request_data)
return jsonutils.to_primitive(project_obj), 200, None

View File

@ -1,4 +1,3 @@
from flask import g
from oslo_serialization import jsonutils
from oslo_log import log
from oslo_utils import uuidutils
@ -14,10 +13,10 @@ LOG = log.getLogger(__name__)
class Users(base.Resource):
@base.http_codes
def get(self, context):
def get(self, context, request_args):
"""Get all users. Requires project admin privileges."""
user_id = g.args["id"]
user_name = g.args["name"]
user_id = request_args["id"]
user_name = request_args["name"]
if user_name:
user_obj = dbapi.users_get_by_name(context, user_name)
@ -33,13 +32,13 @@ class Users(base.Resource):
return jsonutils.to_primitive(users_obj), 200, None
@base.http_codes
def post(self, context):
def post(self, context, request_data):
"""Create a new user. Requires project admin privileges."""
json = util.copy_project_id_into_json(context, g.json)
json = util.copy_project_id_into_json(context, request_data)
project_id = json["project_id"]
dbapi.projects_get_by_id(context, project_id)
api_key = uuidutils.generate_uuid()
g.json["api_key"] = api_key
request_data["api_key"] = api_key
user_obj = dbapi.users_create(context, json)
return jsonutils.to_primitive(user_obj), 200, None

View File

@ -5,7 +5,7 @@ from datetime import date
from functools import wraps
from werkzeug.datastructures import MultiDict, Headers
from flask import request, g, current_app, json
from flask import request, current_app, json
from flask_restful import abort
from flask_restful.utils import unpack
from jsonschema import Draft4Validator
@ -231,11 +231,12 @@ def request_validate(view):
if method == 'HEAD':
method = 'GET'
locations = validators.get((endpoint, method), {})
data_type = {"json": "request_data", "args": "request_args"}
for location, schema in locations.items():
value = getattr(request, location, MultiDict())
validator = FlaskValidatorAdaptor(schema)
result = validator.validate(value)
setattr(g, location, result)
kwargs[data_type[location]] = result
context = request.environ['context']
return view(*args, context=context, **kwargs)