diff --git a/nailgun/nailgun/api/v1/handlers/assignment.py b/nailgun/nailgun/api/v1/handlers/assignment.py index cc36780c76..eb80b5b88a 100644 --- a/nailgun/nailgun/api/v1/handlers/assignment.py +++ b/nailgun/nailgun/api/v1/handlers/assignment.py @@ -19,7 +19,8 @@ Handlers dealing with nodes assignment """ from nailgun.api.v1.handlers.base import BaseHandler -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import validate from nailgun.api.v1.validators.assignment import NodeAssignmentValidator from nailgun.api.v1.validators.assignment import NodeUnassignmentValidator @@ -31,7 +32,8 @@ class NodeAssignmentHandler(BaseHandler): """Node assignment handler""" validator = NodeAssignmentValidator - @content + @handle_errors + @validate def POST(self, cluster_id): """:returns: Empty string @@ -62,7 +64,8 @@ class NodeUnassignmentHandler(BaseHandler): """Node assignment handler""" validator = NodeUnassignmentValidator - @content + @handle_errors + @validate def POST(self, cluster_id): """:returns: Empty string diff --git a/nailgun/nailgun/api/v1/handlers/base.py b/nailgun/nailgun/api/v1/handlers/base.py index ca231c4f5b..1a94997eae 100644 --- a/nailgun/nailgun/api/v1/handlers/base.py +++ b/nailgun/nailgun/api/v1/handlers/base.py @@ -15,12 +15,13 @@ # under the License. from datetime import datetime +from decorator import decorator +from oslo_serialization import jsonutils import six import traceback +import yaml -from decorator import decorator from distutils.version import StrictVersion -from oslo_serialization import jsonutils from sqlalchemy import exc as sa_exc import web @@ -31,7 +32,6 @@ from nailgun.api.v1.validators.orchestrator_graph import \ from nailgun import consts from nailgun.db import db from nailgun import errors -from nailgun.errors.base import NailgunException from nailgun.logger import logger from nailgun import objects from nailgun.objects.serializers.base import BasicSerializer @@ -271,40 +271,25 @@ class BaseHandler(object): else: return default + @staticmethod + def get_requested_mime(): + accept = web.ctx.env.get("HTTP_ACCEPT", "application/json") + accept = accept.strip().split(',')[0] + accept = accept.split(';')[0] + return accept -def content_json(func, cls, *args, **kwargs): - json_resp = lambda data: ( - jsonutils.dumps(data) - if isinstance(data, (dict, list)) or data is None else data - ) - request_validate_needed = True +def json_resp(data): + if isinstance(data, (dict, list)) or data is None: + return jsonutils.dumps(data) + else: + return data - resource_type = "single" - if issubclass( - cls.__class__, - CollectionHandler - ) and not func.func_name == "POST": - resource_type = "collection" - - if ( - func.func_name in ("GET", "DELETE") or - getattr(cls.__class__, 'validator', None) is None or - resource_type == "single" and not cls.validator.single_schema or - resource_type == "collection" and not cls.validator.collection_schema - ): - request_validate_needed = False +@decorator +def handle_errors(func, cls, *args, **kwargs): try: - if request_validate_needed: - BaseHandler.checked_data( - cls.validator.validate_request, - resource_type=resource_type - ) - - resp = func(cls, *args, **kwargs) - except web.notmodified: - raise + return func(cls, *args, **kwargs) except web.HTTPError as http_error: if http_error.status_code != 204: web.header('Content-Type', 'application/json', unique=True) @@ -316,7 +301,7 @@ def content_json(func, cls, *args, **kwargs): else: http_error.data = json_resp(http_error.data) raise - except NailgunException as exc: + except errors.NailgunException as exc: logger.exception('NailgunException occured') http_error = BaseHandler.http(400, exc.message) web.header('Content-Type', 'text/plain') @@ -336,62 +321,66 @@ def content_json(func, cls, *args, **kwargs): web.header('Content-Type', 'text/plain') raise http_error - web.header('Content-Type', 'application/json', unique=True) - return json_resp(resp) + +@decorator +def validate(func, cls, *args, **kwargs): + request_validation_needed = True + + resource_type = "single" + if issubclass( + cls.__class__, + CollectionHandler + ) and not func.func_name == "POST": + resource_type = "collection" + + if ( + func.func_name in ("GET", "DELETE") or + getattr(cls.__class__, 'validator', None) is None or + (resource_type == "single" and not cls.validator.single_schema) or + (resource_type == "collection" and not cls.validator.collection_schema) + ): + request_validation_needed = False + + if request_validation_needed: + BaseHandler.checked_data( + cls.validator.validate_request, + resource_type=resource_type + ) + + return func(cls, *args, **kwargs) -def content(*args, **kwargs): - """Set context-type of response based on Accept header +@decorator +def serialize(func, cls, *args, **kwargs): + """Set context-type of response based on Accept header. This decorator checks Accept header received from client and returns corresponding wrapper (only JSON is currently supported). It can be used as is: - @content - def GET(self): - ... - - Default behavior may be overriden by passing list of - exact mimetypes to decorator: - - @content(["text/plain"]) + @handle_errors + @validate + @serialize def GET(self): ... """ - # TODO(ikutukov): this decorator is not coherent and doing more - # than just a response mimetype setting via type-specific content_json - # method that perform validation. - # Before you start to implement handler business logic ensure that - # @content decorator not already doing what you are planning to write. - # I think that validation routine and common http headers formation not - # depending on each other and should be decoupled. At least they should - # not be under one decorator with abstract name. + accepted_types = ( + "application/json", + "application/x-yaml", + "*/*" + ) + accept = cls.get_requested_mime() + if accept not in accepted_types: + raise BaseHandler.http(415) - exact_mimetypes = None - if len(args) >= 1 and isinstance(args[0], list): - exact_mimetypes = args[0] - - @decorator - def wrapper(func, *args, **kwargs): - accept = web.ctx.env.get("HTTP_ACCEPT", "application/json") - accepted_types = [ - "application/json", - "*/*" - ] - if exact_mimetypes and isinstance(exact_mimetypes, list): - accepted_types = exact_mimetypes - if any(map(lambda m: m in accept, accepted_types)): - return content_json(func, *args, **kwargs) - else: - raise BaseHandler.http(415) - - # case of @content without arguments, meaning arg[0] to be callable - # handler - if len(args) >= 1 and callable(args[0]): - return wrapper(args[0], *args[1:], **kwargs) - - # case of @content(["mimetype"]) with explicit arguments - return wrapper + resp = func(cls, *args, **kwargs) + if accept == 'application/x-yaml': + web.header('Content-Type', 'application/x-yaml', unique=True) + return yaml.dump(resp, default_flow_style=False) + else: + # default is json + web.header('Content-Type', 'application/json', unique=True) + return jsonutils.dumps(resp) class SingleHandler(BaseHandler): @@ -399,7 +388,9 @@ class SingleHandler(BaseHandler): single = None validator = BasicValidator - @content + @handle_errors + @validate + @serialize def GET(self, obj_id): """:returns: JSONized REST object. @@ -407,9 +398,11 @@ class SingleHandler(BaseHandler): * 404 (object not found in db) """ obj = self.get_object_or_404(self.single, obj_id) - return self.single.to_json(obj) + return self.single.to_dict(obj) - @content + @handle_errors + @validate + @serialize def PUT(self, obj_id): """:returns: JSONized REST object. @@ -423,9 +416,10 @@ class SingleHandler(BaseHandler): instance=obj ) self.single.update(obj, data) - return self.single.to_json(obj) + return self.single.to_dict(obj) - @content + @handle_errors + @validate def DELETE(self, obj_id): """:returns: Empty string @@ -452,16 +446,19 @@ class CollectionHandler(BaseHandler): validator = BasicValidator eager = () - @content + @handle_errors + @validate + @serialize def GET(self): """:returns: Collection of JSONized REST objects. :http: * 200 (OK) """ q = self.collection.eager(None, self.eager) - return self.collection.to_json(q) + return self.collection.to_list(q) - @content + @handle_errors + @validate def POST(self): """:returns: JSONized REST object. @@ -495,7 +492,9 @@ class DBSingletonHandler(BaseHandler): return instance - @content + @handle_errors + @validate + @serialize def GET(self): """Get singleton object from DB @@ -504,9 +503,11 @@ class DBSingletonHandler(BaseHandler): """ instance = self.get_one_or_404() - return self.single.to_json(instance) + return self.single.to_dict(instance) - @content + @handle_errors + @validate + @serialize def PUT(self): """Change object in DB @@ -520,9 +521,11 @@ class DBSingletonHandler(BaseHandler): self.single.update(instance, data) - return self.single.to_json(instance) + return self.single.to_dict(instance) - @content + @handle_errors + @validate + @serialize def PATCH(self): """Update object @@ -538,7 +541,7 @@ class DBSingletonHandler(BaseHandler): self.single.serializer.serialize(instance), data )) - return self.single.to_json(instance) + return self.single.to_dict(instance) # TODO(enchantner): rewrite more handlers to inherit from this @@ -557,7 +560,8 @@ class DeferredTaskHandler(BaseHandler): def get_options(cls): return {} - @content + @handle_errors + @validate def PUT(self, cluster_id): """:returns: JSONized Task object. @@ -618,7 +622,9 @@ class OrchestratorDeploymentTasksHandler(SingleHandler): validator = GraphSolverTasksValidator - @content + @handle_errors + @validate + @serialize def GET(self, obj_id): """:returns: Deployment tasks @@ -654,7 +660,9 @@ class OrchestratorDeploymentTasksHandler(SingleHandler): 'name.'.format(e.task_name)) return tasks - @content + @handle_errors + @validate + @serialize def PUT(self, obj_id): """:returns: Deployment tasks diff --git a/nailgun/nailgun/api/v1/handlers/capacity.py b/nailgun/nailgun/api/v1/handlers/capacity.py index ba252c6d40..5c6dab748e 100644 --- a/nailgun/nailgun/api/v1/handlers/capacity.py +++ b/nailgun/nailgun/api/v1/handlers/capacity.py @@ -26,7 +26,9 @@ import web from nailgun import objects from nailgun.api.v1.handlers.base import BaseHandler -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize +from nailgun.api.v1.handlers.base import validate from nailgun.task.manager import GenerateCapacityLogTaskManager @@ -78,14 +80,17 @@ class CapacityLogHandler(BaseHandler): "report" ) - @content + @handle_errors + @validate + @serialize def GET(self): capacity_log = objects.CapacityLog.get_latest() if not capacity_log: raise self.http(404) return self.render(capacity_log) - @content + @handle_errors + @validate def PUT(self): """Starts capacity data generation. diff --git a/nailgun/nailgun/api/v1/handlers/cluster.py b/nailgun/nailgun/api/v1/handlers/cluster.py index 370b507657..2e18ac990d 100644 --- a/nailgun/nailgun/api/v1/handlers/cluster.py +++ b/nailgun/nailgun/api/v1/handlers/cluster.py @@ -23,10 +23,12 @@ import web from nailgun.api.v1.handlers.base import BaseHandler from nailgun.api.v1.handlers.base import CollectionHandler -from nailgun.api.v1.handlers.base import content from nailgun.api.v1.handlers.base import DeferredTaskHandler +from nailgun.api.v1.handlers.base import handle_errors from nailgun.api.v1.handlers.base import OrchestratorDeploymentTasksHandler +from nailgun.api.v1.handlers.base import serialize from nailgun.api.v1.handlers.base import SingleHandler +from nailgun.api.v1.handlers.base import validate from nailgun.api.v1.handlers.deployment_graph import \ RelatedDeploymentGraphCollectionHandler from nailgun.api.v1.handlers.deployment_graph import \ @@ -55,7 +57,9 @@ class ClusterHandler(SingleHandler): single = objects.Cluster validator = ClusterValidator - @content + @handle_errors + @validate + @serialize def PUT(self, obj_id): """:returns: JSONized Cluster object. @@ -79,9 +83,10 @@ class ClusterHandler(SingleHandler): except errors.NetworkTemplateCannotBeApplied as exc: raise self.http(400, exc.message) - return self.single.to_json(obj) + return self.single.to_dict(obj) - @content + @handle_errors + @validate def DELETE(self, obj_id): """:returns: {} @@ -174,7 +179,9 @@ class ClusterAttributesHandler(BaseHandler): validator = ClusterAttributesValidator - @content + @handle_errors + @validate + @serialize def GET(self, cluster_id): """:returns: JSONized Cluster attributes. @@ -206,7 +213,9 @@ class ClusterAttributesHandler(BaseHandler): # entity and PATCH method for changing its parts. return self.PATCH(cluster_id) - @content + @handle_errors + @validate + @serialize def PATCH(self, cluster_id): """:returns: JSONized Cluster attributes. @@ -239,7 +248,9 @@ class ClusterAttributesDefaultsHandler(BaseHandler): "editable", ) - @content + @handle_errors + @validate + @serialize def GET(self, cluster_id): """:returns: JSONized default Cluster attributes. @@ -253,7 +264,9 @@ class ClusterAttributesDefaultsHandler(BaseHandler): raise self.http(500, "No attributes found!") return {"editable": attrs} - @content + @handle_errors + @validate + @serialize def PUT(self, cluster_id): """:returns: JSONized Cluster attributes. @@ -290,7 +303,9 @@ class ClusterAttributesDefaultsHandler(BaseHandler): class ClusterAttributesDeployedHandler(BaseHandler): """Cluster deployed attributes handler""" - @content + @handle_errors + @validate + @serialize def GET(self, cluster_id): """:returns: JSONized deployed Cluster editable attributes with plugins @@ -312,7 +327,9 @@ class ClusterAttributesDeployedHandler(BaseHandler): class ClusterGeneratedData(BaseHandler): """Cluster generated data""" - @content + @handle_errors + @validate + @serialize def GET(self, cluster_id): """:returns: JSONized cluster generated data @@ -333,7 +350,9 @@ class ClusterPluginsDeploymentTasksHandler(BaseHandler): """Handler for cluster plugins merged deployment tasks serialization.""" single = objects.Cluster - @content + @handle_errors + @validate + @serialize def GET(self, obj_id): """:returns: Deployment tasks @@ -351,7 +370,9 @@ class ClusterReleaseDeploymentTasksHandler(BaseHandler): """Handler for cluster release deployment tasks serialization.""" single = objects.Cluster - @content + @handle_errors + @validate + @serialize def GET(self, obj_id): """:returns: Deployment tasks @@ -374,7 +395,9 @@ class VmwareAttributesHandler(BaseHandler): validator = VmwareAttributesValidator - @content + @handle_errors + @validate + @serialize def GET(self, cluster_id): """:returns: JSONized Cluster vmware attributes. @@ -401,7 +424,9 @@ class VmwareAttributesHandler(BaseHandler): return self.render(attributes) - @content + @handle_errors + @validate + @serialize def PUT(self, cluster_id): """:returns: JSONized Cluster vmware attributes. @@ -442,7 +467,9 @@ class VmwareAttributesHandler(BaseHandler): class VmwareAttributesDefaultsHandler(BaseHandler): """Vmware default attributes handler""" - @content + @handle_errors + @validate + @serialize def GET(self, cluster_id): """:returns: JSONized default Cluster vmware attributes. diff --git a/nailgun/nailgun/api/v1/handlers/cluster_plugin_link.py b/nailgun/nailgun/api/v1/handlers/cluster_plugin_link.py index ded80e11e1..66f82a13d1 100644 --- a/nailgun/nailgun/api/v1/handlers/cluster_plugin_link.py +++ b/nailgun/nailgun/api/v1/handlers/cluster_plugin_link.py @@ -15,7 +15,9 @@ # under the License. from nailgun.api.v1.handlers import base -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize +from nailgun.api.v1.handlers.base import validate from nailgun.api.v1.validators import cluster_plugin_link from nailgun import errors from nailgun import objects @@ -26,6 +28,9 @@ class ClusterPluginLinkHandler(base.SingleHandler): validator = cluster_plugin_link.ClusterPluginLinkValidator single = objects.ClusterPluginLink + @handle_errors + @validate + @serialize def GET(self, cluster_id, obj_id): """:returns: JSONized REST object. @@ -35,9 +40,11 @@ class ClusterPluginLinkHandler(base.SingleHandler): self.get_object_or_404(objects.Cluster, cluster_id) obj = self.get_object_or_404(self.single, obj_id) - return self.single.to_json(obj) + return self.single.to_dict(obj) - @content + @handle_errors + @validate + @serialize def PUT(self, cluster_id, obj_id): """:returns: JSONized REST object. @@ -51,7 +58,7 @@ class ClusterPluginLinkHandler(base.SingleHandler): instance=obj ) self.single.update(obj, data) - return self.single.to_json(obj) + return self.single.to_dict(obj) def PATCH(self, cluster_id, obj_id): """:returns: JSONized REST object. @@ -62,7 +69,8 @@ class ClusterPluginLinkHandler(base.SingleHandler): """ return self.PUT(cluster_id, obj_id) - @content + @handle_errors + @validate def DELETE(self, cluster_id, obj_id): """:returns: JSONized REST object. @@ -79,7 +87,9 @@ class ClusterPluginLinkCollectionHandler(base.CollectionHandler): collection = objects.ClusterPluginLinkCollection validator = cluster_plugin_link.ClusterPluginLinkValidator - @content + @handle_errors + @validate + @serialize def GET(self, cluster_id): """:returns: Collection of JSONized ClusterPluginLink objects. @@ -87,11 +97,12 @@ class ClusterPluginLinkCollectionHandler(base.CollectionHandler): * 404 (cluster not found in db) """ self.get_object_or_404(objects.Cluster, cluster_id) - return self.collection.to_json( + return self.collection.to_list( self.collection.get_by_cluster_id(cluster_id) ) - @content + @handle_errors + @validate def POST(self, cluster_id): """:returns: JSONized REST object. diff --git a/nailgun/nailgun/api/v1/handlers/component.py b/nailgun/nailgun/api/v1/handlers/component.py index 10c1f130da..5fb48de5be 100644 --- a/nailgun/nailgun/api/v1/handlers/component.py +++ b/nailgun/nailgun/api/v1/handlers/component.py @@ -14,15 +14,20 @@ # License for the specific language governing permissions and limitations # under the License. -from nailgun.api.v1.handlers import base +from nailgun.api.v1.handlers.base import CollectionHandler +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize +from nailgun.api.v1.handlers.base import validate from nailgun.objects import Release from nailgun.objects.serializers.release import ComponentSerializer -class ComponentCollectionHandler(base.CollectionHandler): +class ComponentCollectionHandler(CollectionHandler): """Component collection handler""" - @base.content + @handle_errors + @validate + @serialize def GET(self, release_id): """:returns: JSONized component data for release and releated plugins. diff --git a/nailgun/nailgun/api/v1/handlers/deployment_graph.py b/nailgun/nailgun/api/v1/handlers/deployment_graph.py index fac04cf1e6..2d6ce06958 100644 --- a/nailgun/nailgun/api/v1/handlers/deployment_graph.py +++ b/nailgun/nailgun/api/v1/handlers/deployment_graph.py @@ -16,8 +16,10 @@ from nailgun.api.v1.handlers.base import BaseHandler from nailgun.api.v1.handlers.base import CollectionHandler -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize from nailgun.api.v1.handlers.base import SingleHandler +from nailgun.api.v1.handlers.base import validate from nailgun.api.v1.validators import deployment_graph as validators from nailgun import errors @@ -35,7 +37,9 @@ class RelatedDeploymentGraphHandler(SingleHandler): single = objects.DeploymentGraph related = None # related should be substituted during handler inheritance - @content + @handle_errors + @validate + @serialize def GET(self, obj_id, graph_type=None): """Get deployment graph. @@ -54,12 +58,14 @@ class RelatedDeploymentGraphHandler(SingleHandler): obj = self.get_object_or_404(self.related, int(obj_id)) deployment_graph = self.single.get_for_model(obj, graph_type) if deployment_graph: - return self.single.to_json(deployment_graph) + return self.single.to_dict(deployment_graph) else: raise self.http(404, "Graph with type: {0} is not defined".format( graph_type)) - @content + @handle_errors + @validate + @serialize def POST(self, obj_id, graph_type=None): """Create deployment graph. @@ -85,9 +91,11 @@ class RelatedDeploymentGraphHandler(SingleHandler): else: deployment_graph = self.single.create_for_model( data, obj, graph_type=graph_type) - return self.single.to_json(deployment_graph) + return self.single.to_dict(deployment_graph) - @content + @handle_errors + @validate + @serialize def PUT(self, obj_id, graph_type=None): """Update deployment graph. @@ -109,12 +117,14 @@ class RelatedDeploymentGraphHandler(SingleHandler): deployment_graph = self.single.get_for_model(obj, graph_type) if deployment_graph: self.single.update(deployment_graph, data) - return self.single.to_json(deployment_graph) + return self.single.to_dict(deployment_graph) else: raise self.http(404, "Graph with type: {0} is not defined".format( graph_type)) - @content + @handle_errors + @validate + @serialize def PATCH(self, obj_id, graph_type=None): """Update deployment graph. @@ -132,6 +142,8 @@ class RelatedDeploymentGraphHandler(SingleHandler): """ return self.PUT(obj_id, graph_type) + @handle_errors + @validate def DELETE(self, obj_id, graph_type=None): """Delete deployment graph. @@ -161,7 +173,9 @@ class RelatedDeploymentGraphCollectionHandler(CollectionHandler): collection = objects.DeploymentGraphCollection related = None # related should be substituted during handler inheritance - @content + @handle_errors + @validate + @serialize def GET(self, obj_id): """Get deployment graphs list for given object. @@ -176,7 +190,7 @@ class RelatedDeploymentGraphCollectionHandler(CollectionHandler): """ related_model = self.get_object_or_404(self.related, int(obj_id)) graphs = self.collection.get_for_model(related_model) - return self.collection.to_json(graphs) + return self.collection.to_list(graphs) class DeploymentGraphHandler(SingleHandler): @@ -185,7 +199,8 @@ class DeploymentGraphHandler(SingleHandler): validator = validators.DeploymentGraphValidator single = objects.DeploymentGraph - @content + @handle_errors + @validate def DELETE(self, obj_id): """Delete deployment graph. @@ -196,7 +211,6 @@ class DeploymentGraphHandler(SingleHandler): self.single.delete(d_e) raise self.http(204) - @content def PATCH(self, obj_id): return self.PUT(obj_id) @@ -210,7 +224,8 @@ class GraphsExecutorHandler(BaseHandler): validator = validators.GraphExecuteParamsValidator - @content + @handle_errors + @validate def POST(self): """:returns: JSONized Task object. diff --git a/nailgun/nailgun/api/v1/handlers/deployment_history.py b/nailgun/nailgun/api/v1/handlers/deployment_history.py index fa0aab8685..7532af7193 100644 --- a/nailgun/nailgun/api/v1/handlers/deployment_history.py +++ b/nailgun/nailgun/api/v1/handlers/deployment_history.py @@ -15,7 +15,9 @@ # under the License. from nailgun.api.v1.handlers import base -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize +from nailgun.api.v1.handlers.base import validate from nailgun.api.v1.validators.deployment_history import \ DeploymentHistoryValidator from nailgun import errors @@ -27,7 +29,9 @@ class DeploymentHistoryCollectionHandler(base.CollectionHandler): collection = objects.DeploymentHistoryCollection validator = DeploymentHistoryValidator - @content + @handle_errors + @validate + @serialize def GET(self, transaction_id): """:returns: Collection of JSONized DeploymentHistory records. diff --git a/nailgun/nailgun/api/v1/handlers/logs.py b/nailgun/nailgun/api/v1/handlers/logs.py index 6e840f27cf..cd8bc9c2c4 100644 --- a/nailgun/nailgun/api/v1/handlers/logs.py +++ b/nailgun/nailgun/api/v1/handlers/logs.py @@ -32,7 +32,9 @@ from nailgun import consts from nailgun import objects from nailgun.api.v1.handlers.base import BaseHandler -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize +from nailgun.api.v1.handlers.base import validate from nailgun.settings import settings from nailgun.task.manager import DumpTaskManager from nailgun.task.task import DumpTask @@ -195,7 +197,9 @@ def read_log( class LogEntryCollectionHandler(BaseHandler): """Log entry collection handler""" - @content + @handle_errors + @validate + @serialize def GET(self): """Receives following parameters: @@ -382,7 +386,8 @@ class LogEntryCollectionHandler(BaseHandler): class LogPackageHandler(BaseHandler): """Log package handler""" - @content + @handle_errors + @validate def PUT(self): """:returns: JSONized Task object. @@ -404,7 +409,9 @@ class LogPackageHandler(BaseHandler): class LogPackageDefaultConfig(BaseHandler): - @content + @handle_errors + @validate + @serialize def GET(self): """Generates default config for snapshot @@ -416,7 +423,7 @@ class LogPackageDefaultConfig(BaseHandler): class LogSourceCollectionHandler(BaseHandler): """Log source collection handler""" - @content + @serialize def GET(self): """:returns: Collection of log sources (from settings) @@ -443,7 +450,9 @@ class SnapshotDownloadHandler(BaseHandler): class LogSourceByNodeCollectionHandler(BaseHandler): """Log source by node collection handler""" - @content + @handle_errors + @validate + @serialize def GET(self, node_id): """:returns: Collection of log sources by node (from settings) diff --git a/nailgun/nailgun/api/v1/handlers/master_node_settings.py b/nailgun/nailgun/api/v1/handlers/master_node_settings.py index a6acf7d4b7..1f3f76f019 100644 --- a/nailgun/nailgun/api/v1/handlers/master_node_settings.py +++ b/nailgun/nailgun/api/v1/handlers/master_node_settings.py @@ -14,8 +14,9 @@ from oslo_serialization import jsonutils -from nailgun.api.v1.handlers.base import content from nailgun.api.v1.handlers.base import DBSingletonHandler +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import validate from nailgun.api.v1.validators.master_node_settings \ import MasterNodeSettingsValidator from nailgun.logger import logger @@ -71,12 +72,14 @@ class MasterNodeSettingsHandler(DBSingletonHandler): self._handle_stats_opt_in(settings_data=jsonutils.loads(result)) return result - @content + @handle_errors + @validate def PUT(self): return self._perform_update( super(MasterNodeSettingsHandler, self).PUT) - @content + @handle_errors + @validate def PATCH(self): return self._perform_update( super(MasterNodeSettingsHandler, self).PATCH) diff --git a/nailgun/nailgun/api/v1/handlers/node.py b/nailgun/nailgun/api/v1/handlers/node.py index eee7e7259e..ac488689c0 100644 --- a/nailgun/nailgun/api/v1/handlers/node.py +++ b/nailgun/nailgun/api/v1/handlers/node.py @@ -24,8 +24,10 @@ import web from nailgun.api.v1.handlers.base import BaseHandler from nailgun.api.v1.handlers.base import CollectionHandler -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize from nailgun.api.v1.handlers.base import SingleHandler +from nailgun.api.v1.handlers.base import validate from nailgun.api.v1.validators import node as node_validators from nailgun import errors @@ -44,7 +46,9 @@ class NodeHandler(SingleHandler): single = objects.Node validator = node_validators.NodeValidator - @content + @handle_errors + @validate + @serialize def PUT(self, obj_id): """:returns: JSONized Node object. @@ -69,9 +73,10 @@ class NodeHandler(SingleHandler): except errors.NetworkTemplateCannotBeApplied as exc: raise self.http(400, exc.message) - return self.single.to_json(obj) + return self.single.to_dict(obj) - @content + @handle_errors + @validate def DELETE(self, obj_id): """Deletes a node from DB and from Cobbler. @@ -100,7 +105,9 @@ class NodeCollectionHandler(CollectionHandler): validator = node_validators.NodeValidator collection = objects.NodeCollection - @content + @handle_errors + @validate + @serialize def GET(self): """May receive cluster_id parameter to filter list of nodes @@ -115,9 +122,11 @@ class NodeCollectionHandler(CollectionHandler): elif cluster_id: nodes = nodes.filter_by(cluster_id=cluster_id) - return self.collection.to_json(nodes) + return self.collection.to_list(nodes) - @content + @handle_errors + @validate + @serialize def PUT(self): """:returns: Collection of JSONized Node objects. @@ -147,9 +156,10 @@ class NodeCollectionHandler(CollectionHandler): self.collection.eager_nodes_handlers(None), nodes_updated ) - return self.collection.to_json(nodes) + return self.collection.to_list(nodes) - @content + @handle_errors + @validate def DELETE(self): """Deletes a batch of nodes. @@ -188,7 +198,9 @@ class NodeAgentHandler(BaseHandler): collection = objects.NodeCollection validator = node_validators.NodeValidator - @content + @handle_errors + @validate + @serialize def PUT(self): """:returns: node id. @@ -227,7 +239,9 @@ class NodeAgentHandler(BaseHandler): class NodesAllocationStatsHandler(BaseHandler): """Node allocation stats handler""" - @content + @handle_errors + @validate + @serialize def GET(self): """:returns: Total and unallocated nodes count. @@ -245,7 +259,9 @@ class NodeAttributesHandler(BaseHandler): validator = node_validators.NodeAttributesValidator - @content + @handle_errors + @validate + @serialize def GET(self, node_id): """:returns: JSONized Node attributes. @@ -256,7 +272,9 @@ class NodeAttributesHandler(BaseHandler): return objects.Node.get_attributes(node) - @content + @handle_errors + @validate + @serialize def PUT(self, node_id): """:returns: JSONized Node attributes. diff --git a/nailgun/nailgun/api/v1/handlers/node_group.py b/nailgun/nailgun/api/v1/handlers/node_group.py index 657372f982..5539a6ce96 100644 --- a/nailgun/nailgun/api/v1/handlers/node_group.py +++ b/nailgun/nailgun/api/v1/handlers/node_group.py @@ -21,9 +21,10 @@ Handlers dealing with node groups import web from nailgun.api.v1.handlers.base import CollectionHandler +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize from nailgun.api.v1.handlers.base import SingleHandler - -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import validate from nailgun.api.v1.validators.node_group import NodeGroupValidator from nailgun import errors @@ -35,7 +36,8 @@ class NodeGroupHandler(SingleHandler): single = objects.NodeGroup validator = NodeGroupValidator - @content + @handle_errors + @validate def DELETE(self, group_id): """:returns: {} @@ -67,7 +69,9 @@ class NodeGroupCollectionHandler(CollectionHandler): collection = objects.NodeGroupCollection validator = NodeGroupValidator - @content + @handle_errors + @validate + @serialize def GET(self): """May receive cluster_id parameter to filter list of groups @@ -78,10 +82,10 @@ class NodeGroupCollectionHandler(CollectionHandler): user_data = web.input(cluster_id=None) if user_data.cluster_id is not None: - return self.collection.to_json( + return self.collection.to_list( self.collection.get_by_cluster_id( user_data.cluster_id ) ) else: - return self.collection.to_json() + return self.collection.to_list() diff --git a/nailgun/nailgun/api/v1/handlers/notifications.py b/nailgun/nailgun/api/v1/handlers/notifications.py index 2991720af8..6113c8fd89 100644 --- a/nailgun/nailgun/api/v1/handlers/notifications.py +++ b/nailgun/nailgun/api/v1/handlers/notifications.py @@ -24,7 +24,9 @@ from nailgun.api.v1.handlers.base import SingleHandler from nailgun import objects -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize +from nailgun.api.v1.handlers.base import validate from nailgun.api.v1.validators.notification import NotificationValidator @@ -40,7 +42,9 @@ class NotificationCollectionHandler(CollectionHandler): collection = objects.NotificationCollection validator = NotificationValidator - @content + @handle_errors + @validate + @serialize def PUT(self): """:returns: Collection of JSONized Notification objects. @@ -54,4 +58,4 @@ class NotificationCollectionHandler(CollectionHandler): notif = self.collection.single.get_by_uid(nd["id"]) self.collection.single.update(notif, nd) notifications_updated.append(notif) - return self.collection.to_json(notifications_updated) + return self.collection.to_list(notifications_updated) diff --git a/nailgun/nailgun/api/v1/handlers/openstack_config.py b/nailgun/nailgun/api/v1/handlers/openstack_config.py index 8a95e9f04f..7cd89d1483 100644 --- a/nailgun/nailgun/api/v1/handlers/openstack_config.py +++ b/nailgun/nailgun/api/v1/handlers/openstack_config.py @@ -18,8 +18,10 @@ import six import web from nailgun.api.v1.handlers.base import BaseHandler -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize from nailgun.api.v1.handlers.base import SingleHandler +from nailgun.api.v1.handlers.base import validate from nailgun.api.v1.validators.openstack_config import OpenstackConfigValidator from nailgun import errors from nailgun.logger import logger @@ -31,7 +33,9 @@ class OpenstackConfigCollectionHandler(BaseHandler): validator = OpenstackConfigValidator - @content + @handle_errors + @validate + @serialize def GET(self): """Returns list of filtered config objects. @@ -48,7 +52,8 @@ class OpenstackConfigCollectionHandler(BaseHandler): configs, 'node_id', node_ids) return objects.OpenstackConfigCollection.to_list(configs) - @content + @handle_errors + @validate def POST(self): """Creates new config object. @@ -72,7 +77,8 @@ class OpenstackConfigHandler(SingleHandler): single = objects.OpenstackConfig validator = OpenstackConfigValidator - @content + @handle_errors + @validate def PUT(self, obj_id): """Update an existing configuration is not allowed @@ -80,7 +86,8 @@ class OpenstackConfigHandler(SingleHandler): """ raise self.http(405) - @content + @handle_errors + @validate def DELETE(self, obj_id): """:returns: Empty string @@ -111,7 +118,8 @@ class OpenstackConfigExecuteHandler(BaseHandler): validator = OpenstackConfigValidator task_manager = OpenstackConfigTaskManager - @content + @handle_errors + @validate def PUT(self): """Executes update tasks for specified resources. diff --git a/nailgun/nailgun/api/v1/handlers/orchestrator.py b/nailgun/nailgun/api/v1/handlers/orchestrator.py index bf2d66a0e3..c26a403f04 100644 --- a/nailgun/nailgun/api/v1/handlers/orchestrator.py +++ b/nailgun/nailgun/api/v1/handlers/orchestrator.py @@ -20,7 +20,9 @@ import six import web from nailgun.api.v1.handlers.base import BaseHandler -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize +from nailgun.api.v1.handlers.base import validate from nailgun.api.v1.validators.cluster import ProvisionSelectedNodesValidator from nailgun.api.v1.validators.node import DeploySelectedNodesValidator from nailgun.api.v1.validators.node import NodeDeploymentValidator @@ -79,7 +81,9 @@ class DefaultOrchestratorInfo(NodesFilterMixin, BaseHandler): Need to redefine serializer variable """ - @content + @handle_errors + @validate + @serialize def GET(self, cluster_id): """:returns: JSONized default data which will be passed to orchestrator @@ -110,7 +114,9 @@ class OrchestratorInfo(BaseHandler): """Method should override data which will be passed to orchestrator""" raise NotImplementedError('Please Implement this method') - @content + @handle_errors + @validate + @serialize def GET(self, cluster_id): """:returns: JSONized data which will be passed to orchestrator @@ -120,7 +126,9 @@ class OrchestratorInfo(BaseHandler): cluster = self.get_object_or_404(objects.Cluster, cluster_id) return self.get_orchestrator_info(cluster) - @content + @handle_errors + @validate + @serialize def PUT(self, cluster_id): """:returns: JSONized data which will be passed to orchestrator @@ -136,7 +144,8 @@ class OrchestratorInfo(BaseHandler): .format(cluster_id)) return data - @content + @handle_errors + @validate def DELETE(self, cluster_id): """:returns: {} @@ -235,7 +244,8 @@ class SelectedNodesBase(NodesFilterMixin, BaseHandler): self.raise_task(task) - @content + @handle_errors + @validate def PUT(self, cluster_id): """:returns: JSONized Task object. @@ -257,7 +267,8 @@ class ProvisionSelectedNodes(SelectedNodesBase): def get_default_nodes(self, cluster): return TaskHelper.nodes_to_provision(cluster) - @content + @handle_errors + @validate def PUT(self, cluster_id): """:returns: JSONized Task object. @@ -303,7 +314,8 @@ class BaseDeploySelectedNodes(SelectedNodesBase): class DeploySelectedNodes(BaseDeploySelectedNodes, DryRunMixin): """Handler for deployment selected nodes.""" - @content + @handle_errors + @validate def PUT(self, cluster_id): """:returns: JSONized Task object. @@ -324,7 +336,8 @@ class DeploySelectedNodesWithTasks(BaseDeploySelectedNodes, DryRunMixin): validator = NodeDeploymentValidator - @content + @handle_errors + @validate def PUT(self, cluster_id): """:returns: JSONized Task object. @@ -353,6 +366,8 @@ class TaskDeployGraph(BaseHandler): validator = GraphSolverVisualizationValidator + @handle_errors + @validate def GET(self, cluster_id): """:returns: DOT representation of deployment graph. @@ -407,7 +422,9 @@ class SerializedTasksHandler(NodesFilterMixin, BaseHandler): return objects.Cluster.get_nodes_not_for_deletion(cluster).all() return TaskHelper.nodes_to_deploy(cluster) - @content + @handle_errors + @validate + @serialize def GET(self, cluster_id): """:returns: serialized tasks in json format diff --git a/nailgun/nailgun/api/v1/handlers/plugin.py b/nailgun/nailgun/api/v1/handlers/plugin.py index 14c0348c34..f41f58905d 100644 --- a/nailgun/nailgun/api/v1/handlers/plugin.py +++ b/nailgun/nailgun/api/v1/handlers/plugin.py @@ -17,7 +17,8 @@ import six from nailgun.api.v1.handlers import base -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import validate from nailgun.api.v1.handlers.deployment_graph import \ RelatedDeploymentGraphCollectionHandler from nailgun.api.v1.handlers.deployment_graph import \ @@ -39,7 +40,8 @@ class PluginCollectionHandler(base.CollectionHandler): collection = objects.PluginCollection validator = plugin.PluginValidator - @content + @handle_errors + @validate def POST(self): """:returns: JSONized REST object. @@ -59,7 +61,8 @@ class PluginSyncHandler(base.BaseHandler): validator = plugin.PluginSyncValidator - @content + @handle_errors + @validate def POST(self): """:returns: JSONized REST object. diff --git a/nailgun/nailgun/api/v1/handlers/plugin_link.py b/nailgun/nailgun/api/v1/handlers/plugin_link.py index a51c579485..2cd97d8cdd 100644 --- a/nailgun/nailgun/api/v1/handlers/plugin_link.py +++ b/nailgun/nailgun/api/v1/handlers/plugin_link.py @@ -15,7 +15,9 @@ # under the License. from nailgun.api.v1.handlers import base -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize +from nailgun.api.v1.handlers.base import validate from nailgun.api.v1.validators import plugin_link from nailgun import errors from nailgun import objects @@ -36,6 +38,9 @@ class PluginLinkHandler(base.SingleHandler): "Plugin with id {0} not found".format(plugin_id) ) + @handle_errors + @validate + @serialize def GET(self, plugin_id, obj_id): """:returns: JSONized REST object. @@ -43,9 +48,11 @@ class PluginLinkHandler(base.SingleHandler): * 404 (dashboard entry not found in db) """ obj = self._get_plugin_link_object(plugin_id, obj_id) - return self.single.to_json(obj) + return self.single.to_dict(obj) - @content + @handle_errors + @validate + @serialize def PUT(self, plugin_id, obj_id): """:returns: JSONized REST object. @@ -58,7 +65,7 @@ class PluginLinkHandler(base.SingleHandler): self.validator.validate_update, instance=obj) self.single.update(obj, data) - return self.single.to_json(obj) + return self.single.to_dict(obj) def PATCH(self, plugin_id, obj_id): """:returns: JSONized REST object. @@ -69,7 +76,8 @@ class PluginLinkHandler(base.SingleHandler): """ return self.PUT(plugin_id, obj_id) - @content + @handle_errors + @validate def DELETE(self, plugin_id, obj_id): """:returns: JSONized REST object. @@ -86,7 +94,8 @@ class PluginLinkCollectionHandler(base.CollectionHandler): collection = objects.PluginLinkCollection validator = plugin_link.PluginLinkValidator - @content + @handle_errors + @validate def GET(self, plugin_id): """:returns: Collection of JSONized PluginLink objects. @@ -94,11 +103,12 @@ class PluginLinkCollectionHandler(base.CollectionHandler): * 404 (plugin not found in db) """ self.get_object_or_404(objects.Plugin, plugin_id) - return self.collection.to_json( + return self.collection.to_list( self.collection.get_by_plugin_id(plugin_id) ) - @content + @handle_errors + @validate def POST(self, plugin_id): """:returns: JSONized REST object. diff --git a/nailgun/nailgun/api/v1/handlers/release.py b/nailgun/nailgun/api/v1/handlers/release.py index 94efdcc5f9..155b97e0e5 100644 --- a/nailgun/nailgun/api/v1/handlers/release.py +++ b/nailgun/nailgun/api/v1/handlers/release.py @@ -19,9 +19,11 @@ Handlers dealing with releases """ from nailgun.api.v1.handlers.base import CollectionHandler -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors from nailgun.api.v1.handlers.base import OrchestratorDeploymentTasksHandler +from nailgun.api.v1.handlers.base import serialize from nailgun.api.v1.handlers.base import SingleHandler +from nailgun.api.v1.handlers.base import validate from nailgun.api.v1.handlers.deployment_graph import \ RelatedDeploymentGraphCollectionHandler from nailgun.api.v1.handlers.deployment_graph import \ @@ -47,7 +49,9 @@ class ReleaseAttributesMetadataHandler(SingleHandler): single = Release validator = ReleaseAttributesMetadataValidator - @content + @handle_errors + @validate + @serialize def GET(self, obj_id): """:returns: JSONized Release attributes metadata. @@ -57,7 +61,9 @@ class ReleaseAttributesMetadataHandler(SingleHandler): release = self.get_object_or_404(self.single, obj_id) return release['attributes_metadata'] - @content + @handle_errors + @validate + @serialize def PUT(self, obj_id): """:returns: JSONized Release attributes metadata. @@ -77,14 +83,16 @@ class ReleaseCollectionHandler(CollectionHandler): validator = ReleaseValidator collection = ReleaseCollection - @content + @handle_errors + @validate + @serialize def GET(self): """:returns: Sorted releases' collection in JSON format :http: * 200 (OK) """ q = sorted(self.collection.all(), reverse=True) - return self.collection.to_json(q) + return self.collection.to_list(q) class ReleaseNetworksHandler(SingleHandler): @@ -93,7 +101,9 @@ class ReleaseNetworksHandler(SingleHandler): single = Release validator = ReleaseNetworksValidator - @content + @handle_errors + @validate + @serialize def GET(self, obj_id): """Read release networks metadata @@ -105,7 +115,9 @@ class ReleaseNetworksHandler(SingleHandler): obj = self.get_object_or_404(self.single, obj_id) return obj['networks_metadata'] - @content + @handle_errors + @validate + @serialize def PUT(self, obj_id): """Updates release networks metadata diff --git a/nailgun/nailgun/api/v1/handlers/removed.py b/nailgun/nailgun/api/v1/handlers/removed.py index cadbbf15a9..cae367d5fe 100644 --- a/nailgun/nailgun/api/v1/handlers/removed.py +++ b/nailgun/nailgun/api/v1/handlers/removed.py @@ -17,7 +17,9 @@ Handlers for removed resources """ from nailgun.api.v1.handlers.base import BaseHandler -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize +from nailgun.api.v1.handlers.base import validate class BaseRemovedInHandler(BaseHandler): @@ -27,7 +29,9 @@ class BaseRemovedInHandler(BaseHandler): def fuel_version(self): raise NotImplementedError - @content + @handle_errors + @validate + @serialize def GET(self): """A stub for the request. Always returns 410 with removed message. diff --git a/nailgun/nailgun/api/v1/handlers/role.py b/nailgun/nailgun/api/v1/handlers/role.py index 4e2cb4f9d0..382517776f 100644 --- a/nailgun/nailgun/api/v1/handlers/role.py +++ b/nailgun/nailgun/api/v1/handlers/role.py @@ -17,7 +17,9 @@ import six from nailgun.api.v1.handlers import base -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize +from nailgun.api.v1.handlers.base import validate from nailgun.api.v1.validators.role import RoleValidator from nailgun import errors from nailgun import objects @@ -37,7 +39,9 @@ class RoleHandler(base.SingleHandler): release=release_id, name=role_name)) return role - @content + @handle_errors + @validate + @serialize def GET(self, release_id, role_name): """Retrieve role @@ -48,7 +52,9 @@ class RoleHandler(base.SingleHandler): release = self.get_object_or_404(objects.Release, release_id) return RoleSerializer.serialize_from_release(release, role_name) - @content + @handle_errors + @validate + @serialize def PUT(self, release_id, role_name): """Update role @@ -85,7 +91,8 @@ class RoleCollectionHandler(base.CollectionHandler): validator = RoleValidator - @content + @handle_errors + @validate def POST(self, release_id): """Create role for release @@ -110,7 +117,9 @@ class RoleCollectionHandler(base.CollectionHandler): raise self.http( 201, RoleSerializer.serialize_from_release(release, role_name)) - @content + @handle_errors + @validate + @serialize def GET(self, release_id): release = self.get_object_or_404(objects.Release, release_id) role_names = six.iterkeys(release.roles_metadata) @@ -125,7 +134,9 @@ class ClusterRolesHandler(base.BaseHandler): if role_name not in available_roles: raise self.http(404, 'Role is not found for the cluster') - @content + @handle_errors + @validate + @serialize def GET(self, cluster_id, role_name): """:returns: JSON-ed metadata for the role @@ -140,7 +151,9 @@ class ClusterRolesHandler(base.BaseHandler): class ClusterRolesCollectionHandler(base.BaseHandler): - @content + @handle_errors + @validate + @serialize def GET(self, cluster_id): """:returns: collection of JSON-ed cluster roles metadata diff --git a/nailgun/nailgun/api/v1/handlers/tasks.py b/nailgun/nailgun/api/v1/handlers/tasks.py index 695a015826..5268592e5f 100644 --- a/nailgun/nailgun/api/v1/handlers/tasks.py +++ b/nailgun/nailgun/api/v1/handlers/tasks.py @@ -18,7 +18,9 @@ import web from nailgun.api.v1.handlers.base import CollectionHandler from nailgun.api.v1.handlers.base import SingleHandler -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize +from nailgun.api.v1.handlers.base import validate from nailgun.api.v1.validators.task import TaskValidator from nailgun import errors @@ -38,7 +40,8 @@ class TaskHandler(SingleHandler): single = objects.Task validator = TaskValidator - @content + @handle_errors + @validate def DELETE(self, obj_id): """:returns: Empty string @@ -68,7 +71,9 @@ class TaskCollectionHandler(CollectionHandler): collection = objects.TaskCollection validator = TaskValidator - @content + @handle_errors + @validate + @serialize def GET(self): """May receive cluster_id parameter to filter list of tasks @@ -79,8 +84,8 @@ class TaskCollectionHandler(CollectionHandler): cluster_id = web.input(cluster_id=None).cluster_id if cluster_id is not None: - return self.collection.to_json( + return self.collection.to_list( self.collection.get_by_cluster_id(cluster_id) ) else: - return self.collection.to_json(self.collection.all_not_deleted()) + return self.collection.to_list(self.collection.all_not_deleted()) diff --git a/nailgun/nailgun/api/v1/handlers/transactions.py b/nailgun/nailgun/api/v1/handlers/transactions.py index 2ebf223284..703fe17e1a 100644 --- a/nailgun/nailgun/api/v1/handlers/transactions.py +++ b/nailgun/nailgun/api/v1/handlers/transactions.py @@ -18,7 +18,9 @@ import web from nailgun.api.v1.handlers.base import CollectionHandler from nailgun.api.v1.handlers.tasks import TaskHandler -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize +from nailgun.api.v1.handlers.base import validate from nailgun.api.v1.validators.transaction import TransactionValidator from nailgun import errors @@ -42,7 +44,9 @@ class TransactionCollectionHandler(CollectionHandler): collection = objects.TransactionCollection validator = TransactionValidator - @content + @handle_errors + @validate + @serialize def GET(self): """May receive cluster_id parameter to filter list of tasks @@ -60,7 +64,7 @@ class TransactionCollectionHandler(CollectionHandler): except errors.InvalidData as exc: raise self.http(400, exc.message) - return self.collection.to_json( + return self.collection.to_list( self.collection.get_transactions( cluster_id=cluster_id, statuses=statuses, @@ -72,7 +76,9 @@ class BaseTransactionDataHandler(TransactionHandler): get_data = None - @content + @handle_errors + @validate + @serialize def GET(self, transaction_id): """:returns: Collection of JSONized DeploymentInfo objects. diff --git a/nailgun/nailgun/api/v1/handlers/version.py b/nailgun/nailgun/api/v1/handlers/version.py index 975678abc0..5b21a11a3a 100644 --- a/nailgun/nailgun/api/v1/handlers/version.py +++ b/nailgun/nailgun/api/v1/handlers/version.py @@ -19,14 +19,18 @@ Product info handlers """ from nailgun.api.v1.handlers.base import BaseHandler -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize +from nailgun.api.v1.handlers.base import validate from nailgun.settings import settings class VersionHandler(BaseHandler): """Version info handler""" - @content + @handle_errors + @validate + @serialize def GET(self): """:returns: FUEL/FUELWeb commit SHA, release version. diff --git a/nailgun/nailgun/api/v1/handlers/vms.py b/nailgun/nailgun/api/v1/handlers/vms.py index 1022ce7b14..5a7d0551c0 100644 --- a/nailgun/nailgun/api/v1/handlers/vms.py +++ b/nailgun/nailgun/api/v1/handlers/vms.py @@ -20,7 +20,9 @@ import six import web from nailgun.api.v1.handlers.base import BaseHandler -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize +from nailgun.api.v1.handlers.base import validate from nailgun.api.v1.validators import node as validators from nailgun.logger import logger @@ -72,7 +74,8 @@ class SpawnVmsHandler(BaseHandler): else: raise self.http(400, "No VMs to spawn") - @content + @handle_errors + @validate def PUT(self, cluster_id): """:returns: JSONized Task object. @@ -93,7 +96,9 @@ class NodeVMsHandler(BaseHandler): validator = validators.NodeVMsValidator - @content + @handle_errors + @validate + @serialize def GET(self, node_id): """:returns: JSONized node vms_conf. @@ -104,7 +109,9 @@ class NodeVMsHandler(BaseHandler): node_vms = node.vms_conf return {"vms_conf": node_vms} - @content + @handle_errors + @validate + @serialize def PUT(self, node_id): """:returns: JSONized node vms_conf. diff --git a/nailgun/nailgun/extensions/network_manager/handlers/network_configuration.py b/nailgun/nailgun/extensions/network_manager/handlers/network_configuration.py index afb257f69c..21b0c5bf2f 100644 --- a/nailgun/nailgun/extensions/network_manager/handlers/network_configuration.py +++ b/nailgun/nailgun/extensions/network_manager/handlers/network_configuration.py @@ -19,7 +19,9 @@ Handlers dealing with network configurations """ from ..task.manager import UpdateDnsmasqTaskManager from nailgun.api.v1.handlers.base import BaseHandler -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize +from nailgun.api.v1.handlers.base import validate from nailgun.extensions.network_manager.objects.serializers.\ network_configuration import NeutronNetworkConfigurationSerializer @@ -71,7 +73,9 @@ class ProviderHandler(BaseHandler): cluster=cluster, networks_required=False) return cluster, data - @content + @handle_errors + @validate + @serialize def GET(self, cluster_id): """:returns: JSONized network configuration for cluster. @@ -91,7 +95,9 @@ class ProviderHandler(BaseHandler): logger.exception('Serialization failed') raise - @content + @handle_errors + @validate + @serialize def PUT(self, cluster_id): """:returns: JSONized network configuration for cluster. @@ -153,7 +159,9 @@ class TemplateNetworkConfigurationHandler(BaseHandler): raise self.http(403, "Network template cannot be changed " "during deployment and after upgrade.") - @content + @handle_errors + @validate + @serialize def GET(self, cluster_id): """:returns: network template for cluster (json format) @@ -163,7 +171,8 @@ class TemplateNetworkConfigurationHandler(BaseHandler): cluster = self.get_object_or_404(objects.Cluster, cluster_id) return cluster.network_config.configuration_template - @content + @handle_errors + @validate def PUT(self, cluster_id): """:returns: {} @@ -202,7 +211,8 @@ class NetworkConfigurationVerifyHandler(ProviderHandler): validator = NetworkConfigurationValidator - @content + @handle_errors + @validate def PUT(self, cluster_id): """:IMPORTANT: this method should be rewritten to be more RESTful @@ -252,7 +262,9 @@ class NeutronNetworkConfigurationVerifyHandler( class NetworkAttributesDeployedHandler(BaseHandler): """Cluster deployed network attributes handler""" - @content + @handle_errors + @validate + @serialize def GET(self, cluster_id): """:returns: JSONized deployed Cluster network configuration. diff --git a/nailgun/nailgun/extensions/network_manager/handlers/network_group.py b/nailgun/nailgun/extensions/network_manager/handlers/network_group.py index 27189e8b0f..55c3700bfe 100644 --- a/nailgun/nailgun/extensions/network_manager/handlers/network_group.py +++ b/nailgun/nailgun/extensions/network_manager/handlers/network_group.py @@ -15,8 +15,10 @@ # under the License. from nailgun.api.v1.handlers.base import CollectionHandler -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize from nailgun.api.v1.handlers.base import SingleHandler +from nailgun.api.v1.handlers.base import validate from nailgun.extensions.network_manager.validators.network import \ NetworkGroupValidator @@ -38,7 +40,9 @@ class NetworkGroupHandler(SingleHandler): validator = NetworkGroupValidator single = objects.NetworkGroup - @content + @handle_errors + @validate + @serialize def PUT(self, group_id): """:returns: JSONized Network Group object. @@ -57,9 +61,10 @@ class NetworkGroupHandler(SingleHandler): ) self.single.update(ng, data) - return self.single.to_json(ng) + return self.single.to_dict(ng) - @content + @handle_errors + @validate def DELETE(self, group_id): """Remove Network Group @@ -87,7 +92,8 @@ class NetworkGroupCollectionHandler(CollectionHandler): collection = objects.NetworkGroupCollection validator = NetworkGroupValidator - @content + @handle_errors + @validate def POST(self): """:returns: JSONized Network Group object. diff --git a/nailgun/nailgun/extensions/network_manager/handlers/nic.py b/nailgun/nailgun/extensions/network_manager/handlers/nic.py index 586c879efa..38028a62f7 100644 --- a/nailgun/nailgun/extensions/network_manager/handlers/nic.py +++ b/nailgun/nailgun/extensions/network_manager/handlers/nic.py @@ -21,7 +21,9 @@ Handlers dealing with nodes import web from nailgun.api.v1.handlers.base import BaseHandler -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize +from nailgun.api.v1.handlers.base import validate from nailgun.extensions.network_manager.validators.network import \ NetAssignmentValidator @@ -42,7 +44,9 @@ class NodeNICsHandler(BaseHandler): validator = NetAssignmentValidator serializer = NodeInterfacesSerializer - @content + @handle_errors + @validate + @serialize def GET(self, node_id): """:returns: Collection of JSONized Node interfaces. @@ -52,7 +56,9 @@ class NodeNICsHandler(BaseHandler): node = self.get_object_or_404(objects.Node, node_id) return map(self.render, node.interfaces) - @content + @handle_errors + @validate + @serialize def PUT(self, node_id): """:returns: Collection of JSONized Node objects. @@ -79,7 +85,9 @@ class NodeCollectionNICsHandler(BaseHandler): validator = NetAssignmentValidator serializer = NodeInterfacesSerializer - @content + @handle_errors + @validate + @serialize def PUT(self): """:returns: Collection of JSONized Node objects. @@ -107,7 +115,9 @@ class NodeCollectionNICsHandler(BaseHandler): class NodeNICsDefaultHandler(BaseHandler): """Node default network interfaces handler""" - @content + @handle_errors + @validate + @serialize def GET(self, node_id): """:returns: Collection of default JSONized interfaces for node. @@ -129,7 +139,9 @@ class NodeCollectionNICsDefaultHandler(NodeNICsDefaultHandler): validator = NetAssignmentValidator - @content + @handle_errors + @validate + @serialize def GET(self): """May receive cluster_id parameter to filter list of nodes diff --git a/nailgun/nailgun/extensions/network_manager/handlers/vip.py b/nailgun/nailgun/extensions/network_manager/handlers/vip.py index 61b063b927..f46d38132e 100644 --- a/nailgun/nailgun/extensions/network_manager/handlers/vip.py +++ b/nailgun/nailgun/extensions/network_manager/handlers/vip.py @@ -18,7 +18,9 @@ import web from nailgun.api.v1.handlers import base -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize +from nailgun.api.v1.handlers.base import validate from nailgun.extensions.network_manager.validators import ip_addr from nailgun import objects @@ -51,7 +53,9 @@ class ClusterVIPHandler(base.SingleHandler): else: return obj - @content + @handle_errors + @validate + @serialize def GET(self, cluster_id, ip_addr_id): """Get VIP record. @@ -68,9 +72,11 @@ class ClusterVIPHandler(base.SingleHandler): """ obj = self._get_vip_from_cluster_or_http_error( int(cluster_id), int(ip_addr_id)) - return self.single.to_json(obj) + return self.single.to_dict(obj) - @content + @handle_errors + @validate + @serialize def PUT(self, cluster_id, ip_addr_id): """Update VIP record. @@ -94,7 +100,7 @@ class ClusterVIPHandler(base.SingleHandler): existing_obj=obj ) self.single.update(obj, data) - return self.single.to_json(obj) + return self.single.to_dict(obj) def PATCH(self, cluster_id, ip_addr_id): """Update VIP record. @@ -126,7 +132,9 @@ class ClusterVIPCollectionHandler(base.CollectionHandler): collection = objects.IPAddrCollection validator = ip_addr.IPAddrValidator - @content + @handle_errors + @validate + @serialize def GET(self, cluster_id): """Get VIPs collection optionally filtered by network or network role. @@ -141,7 +149,7 @@ class ClusterVIPCollectionHandler(base.CollectionHandler): network_role = web.input(network_role=None).network_role self.get_object_or_404(objects.Cluster, int(cluster_id)) - return self.collection.to_json( + return self.collection.to_list( self.collection.get_vips_by_cluster_id( int(cluster_id), network_id, @@ -149,7 +157,8 @@ class ClusterVIPCollectionHandler(base.CollectionHandler): ) ) - @content + @handle_errors + @validate def POST(self, cluster_id): """Create (allocate) VIP @@ -174,7 +183,9 @@ class ClusterVIPCollectionHandler(base.CollectionHandler): raise self.http(200, self.collection.single.to_json(vip)) - @content + @handle_errors + @validate + @serialize def PUT(self, cluster_id): """Update VIPs collection. @@ -191,7 +202,7 @@ class ClusterVIPCollectionHandler(base.CollectionHandler): cluster_id=int(cluster_id) ) - return self.collection.to_json( + return self.collection.to_list( self.collection.update_vips(update_data) ) diff --git a/nailgun/nailgun/extensions/volume_manager/handlers/disks.py b/nailgun/nailgun/extensions/volume_manager/handlers/disks.py index 1a6597cecf..079be485c8 100644 --- a/nailgun/nailgun/extensions/volume_manager/handlers/disks.py +++ b/nailgun/nailgun/extensions/volume_manager/handlers/disks.py @@ -22,7 +22,9 @@ from ..manager import DisksFormatConvertor from ..manager import VolumeManager from ..validators.disks import NodeDisksValidator from nailgun.api.v1.handlers.base import BaseHandler -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize +from nailgun.api.v1.handlers.base import validate from nailgun import objects @@ -30,7 +32,9 @@ class NodeDisksHandler(BaseHandler): validator = NodeDisksValidator - @content + @handle_errors + @validate + @serialize def GET(self, node_id): """:returns: JSONized node disks. @@ -43,7 +47,9 @@ class NodeDisksHandler(BaseHandler): node_volumes = VolumeObject.get_volumes(node) return DisksFormatConvertor.format_disks_to_simple(node_volumes) - @content + @handle_errors + @validate + @serialize def PUT(self, node_id): """:returns: JSONized node disks. @@ -75,7 +81,9 @@ class NodeDisksHandler(BaseHandler): class NodeDefaultsDisksHandler(BaseHandler): - @content + @handle_errors + @validate + @serialize def GET(self, node_id): """:returns: JSONized node disks. @@ -92,7 +100,9 @@ class NodeDefaultsDisksHandler(BaseHandler): class NodeVolumesInformationHandler(BaseHandler): - @content + @handle_errors + @validate + @serialize def GET(self, node_id): """:returns: JSONized volumes info for node. diff --git a/nailgun/nailgun/fake_keystone/handlers.py b/nailgun/nailgun/fake_keystone/handlers.py index 535dfd0f44..41e528cb81 100644 --- a/nailgun/nailgun/fake_keystone/handlers.py +++ b/nailgun/nailgun/fake_keystone/handlers.py @@ -15,7 +15,9 @@ # under the License. from nailgun.api.v1.handlers.base import BaseHandler -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize +from nailgun.api.v1.handlers.base import validate from nailgun.fake_keystone import generate_token from nailgun.fake_keystone import validate_password_credentials from nailgun.fake_keystone import validate_token @@ -24,7 +26,9 @@ from nailgun.settings import settings class TokensHandler(BaseHandler): - @content + @handle_errors + @validate + @serialize def POST(self): data = self.checked_data() try: @@ -73,7 +77,9 @@ class TokensHandler(BaseHandler): class VersionHandler(BaseHandler): - @content + @handle_errors + @validate + @serialize def GET(self): keystone_href = 'http://{ip_addr}:{port}/keystone/v2.0/'.format( ip_addr=settings.LISTEN_ADDRESS, port=settings.LISTEN_PORT) @@ -107,7 +113,9 @@ class VersionHandler(BaseHandler): class ServicesHandler(BaseHandler): - @content + @handle_errors + @validate + @serialize def GET(self): return { 'OS-KSADM:services': [{'type': 'ostf', 'enabled': True, @@ -127,7 +135,9 @@ class ServicesHandler(BaseHandler): class EndpointsHandler(BaseHandler): - @content + @handle_errors + @validate + @serialize def GET(self): keystone_href = 'http://{ip_addr}:{port}/keystone/v2.0'.format( ip_addr=settings.AUTH['auth_host'], port=settings.LISTEN_PORT) diff --git a/nailgun/nailgun/test/integration/test_graph_related_handlers.py b/nailgun/nailgun/test/integration/test_graph_related_handlers.py index 218ad69415..f9aa4b430e 100644 --- a/nailgun/nailgun/test/integration/test_graph_related_handlers.py +++ b/nailgun/nailgun/test/integration/test_graph_related_handlers.py @@ -636,6 +636,8 @@ class TestStartEndTaskPassedCorrectly(BaseGraphTasksTests): def assert_passed_correctly(self, url, **kwargs): with mock.patch.object(GraphSolver, 'find_subgraph') as mfind_subgraph: + mfind_subgraph.return_value.node.values.return_value = {} + resp = self.app.get( url, params=kwargs, diff --git a/nailgun/nailgun/test/unit/test_handlers.py b/nailgun/nailgun/test/unit/test_handlers.py index 2f6e02add5..428ac1760a 100644 --- a/nailgun/nailgun/test/unit/test_handlers.py +++ b/nailgun/nailgun/test/unit/test_handlers.py @@ -19,10 +19,9 @@ import urllib import web -from mock import patch - from nailgun.api.v1.handlers.base import BaseHandler -from nailgun.api.v1.handlers.base import content +from nailgun.api.v1.handlers.base import handle_errors +from nailgun.api.v1.handlers.base import serialize from nailgun.test.base import BaseIntegrationTest from nailgun.utils import reverse @@ -97,15 +96,15 @@ class TestHandlers(BaseIntegrationTest): def test_content_decorator(self): - class FakeHandler(object): + class FakeHandler(BaseHandler): - @content + @serialize def GET(self): return {} - @content(["text/plain"]) + @serialize def POST(self): - return "Plain Text" + return {} web.ctx.headers = [] web.ctx.env = {"HTTP_ACCEPT": "text/html"} @@ -116,18 +115,7 @@ class TestHandlers(BaseIntegrationTest): fake_handler.GET ) - web.ctx.env = {"HTTP_ACCEPT": "application/json"} - - with patch("nailgun.api.v1.handlers.base.content_json") as cj: - fake_handler.GET() - self.assertEqual(cj.call_count, 1) - web.ctx.env = {"HTTP_ACCEPT": "*/*"} - - with patch("nailgun.api.v1.handlers.base.content_json") as cj: - fake_handler.GET() - self.assertEqual(cj.call_count, 1) - web.ctx.headers = [] fake_handler.GET() self.assertIn( @@ -136,7 +124,7 @@ class TestHandlers(BaseIntegrationTest): ) web.ctx.headers = [] - web.ctx.env = {"HTTP_ACCEPT": "text/plain"} + web.ctx.env = {"HTTP_ACCEPT": "application/json"} fake_handler.POST() self.assertIn( # we don't have plain/text serializer right now @@ -144,6 +132,20 @@ class TestHandlers(BaseIntegrationTest): web.ctx.headers ) + def test_invalid_handler_output(self): + + class FakeHandler(object): + + @handle_errors + @serialize + def GET(self): + return {set([1, 2, 3])} + + fake_handler = FakeHandler() + web.ctx.env = {"HTTP_ACCEPT": "*/*"} + web.ctx.headers = [] + self.assertRaises(web.HTTPError, fake_handler.GET) + def test_get_param_as_set(self): urls = ("/hello", "hello") @@ -160,3 +162,26 @@ class TestHandlers(BaseIntegrationTest): self.assertEqual(set(json.loads(resp.data)), set(['1', '4', '777', 'x'])) + + def check_get_requested_mime(self, headers, expected_mime): + urls = ("/hello", "hello") + + class hello(object): + def GET(self_inner): + web.header('Content-Type', 'text/plain') + return BaseHandler.get_requested_mime() + + app = web.application(urls, {'hello': hello}) + resp = app.request('/hello', headers=headers) + + self.assertEqual(resp.data, expected_mime) + + def test_get_requested_mime1(self): + self.check_get_requested_mime({'ACCEPT': 'text/html'}, 'text/html') + + def test_get_requested_mime2(self): + self.check_get_requested_mime( + {'ACCEPT': 'text/plain;q=0.7, text/html;level=1,'}, 'text/plain') + + def test_get_requested_default(self): + self.check_get_requested_mime({}, 'application/json')