diff --git a/include/villas/api.hpp b/include/villas/api.hpp index 6ab6022cf..304785af0 100644 --- a/include/villas/api.hpp +++ b/include/villas/api.hpp @@ -51,19 +51,34 @@ class Request; class Error : public RuntimeError { public: - Error(int c = HTTP_STATUS_INTERNAL_SERVER_ERROR, const std::string &msg = "Invalid API request") : + + template + Error(int c = HTTP_STATUS_INTERNAL_SERVER_ERROR, const std::string &msg = "Invalid API request", Args&&... args) : + RuntimeError(msg, std::forward(args)...), + code(c), + json(nullptr) + { } + + template + Error(int c = HTTP_STATUS_INTERNAL_SERVER_ERROR, const std::string &msg = "Invalid API request", const char *fmt = nullptr, Args&&... args) : RuntimeError(msg), - code(c) + code(c), + json(fmt + ? json_pack(fmt, std::forward(args)...) + : nullptr + ) { } int code; + json_t *json; }; class BadRequest : public Error { public: - BadRequest(const std::string &msg = "Bad API request") : - Error(HTTP_STATUS_BAD_REQUEST, msg) + template + BadRequest(const std::string &msg = "Bad API request", Args&&... args) : + Error(HTTP_STATUS_BAD_REQUEST, msg, std::forward(args)...) { } }; diff --git a/include/villas/api/node_request.hpp b/include/villas/api/node_request.hpp index 4c48ace3e..457e47973 100644 --- a/include/villas/api/node_request.hpp +++ b/include/villas/api/node_request.hpp @@ -56,16 +56,20 @@ public: if (ret) { node = vlist_lookup_name(nodes, matches[1].str()); if (!node) - throw BadRequest("Unknown node"); + throw BadRequest("Unknown node", "{ s: s }", + "node", matches[1].str().c_str() + ); } else { node = vlist_lookup_uuid(nodes, uuid); if (!node) - throw BadRequest("No node found with with matching UUID"); + throw BadRequest("No node found with with matching UUID", "{ s: s }", + "uuid", matches[1].str().c_str() + ); } } }; } /* namespace api */ } /* namespace node */ -} /* namespace villas */ \ No newline at end of file +} /* namespace villas */ diff --git a/include/villas/api/path_request.hpp b/include/villas/api/path_request.hpp index 6b0b640e8..a66e90ee8 100644 --- a/include/villas/api/path_request.hpp +++ b/include/villas/api/path_request.hpp @@ -52,15 +52,19 @@ public: ret = uuid_parse(matches[1].str().c_str(), uuid); if (ret) - throw BadRequest("Invalid UUID"); + throw BadRequest("Invalid UUID", "{ s: s }", + "uuid", matches[1].str().c_str() + ); auto *paths = session->getSuperNode()->getPaths(); path = vlist_lookup_uuid(paths, uuid); if (!path) - throw BadRequest("No path found with with matching UUID"); + throw BadRequest("No path found with with matching UUID", "{ s: s }", + "uuid", matches[1].str().c_str() + ); } }; } /* namespace api */ } /* namespace node */ -} /* namespace villas */ \ No newline at end of file +} /* namespace villas */ diff --git a/include/villas/api/response.hpp b/include/villas/api/response.hpp index 7ff6e026a..dd52dab0c 100644 --- a/include/villas/api/response.hpp +++ b/include/villas/api/response.hpp @@ -70,18 +70,21 @@ class ErrorResponse : public Response { protected: std::string error; + json_t *json; public: ErrorResponse(Session *s, const RuntimeError &e) : Response(s), - error(e.what()) + error(e.what()), + json(nullptr) { code = 500; } ErrorResponse(Session *s, const Error &e) : Response(s), - error(e.what()) + error(e.what()), + json(e.json) { code = e.code; } diff --git a/lib/api/request.cpp b/lib/api/request.cpp index c8f0f53b2..fe2163abd 100644 --- a/lib/api/request.cpp +++ b/lib/api/request.cpp @@ -45,5 +45,8 @@ Request * RequestFactory::make(Session *s, const std::string &uri, Request::Meth return p; } - throw BadRequest("Unknown API request"); + throw BadRequest("Unknown API request", "{ s: s, s: i }", + "uri", uri.c_str(), + "method", meth + ); } diff --git a/lib/api/requests/node_file.cpp b/lib/api/requests/node_file.cpp index b4bdaf6ed..1e9a11477 100644 --- a/lib/api/requests/node_file.cpp +++ b/lib/api/requests/node_file.cpp @@ -48,7 +48,9 @@ public: struct vnode_type *vt = node_type_lookup("file"); if (node->_vt != vt) - throw BadRequest("This node is not a file node"); + throw BadRequest("This node is not a file node", "{ s: s }", + "type", node->_vt + ); struct file *f = (struct file *) node->_vd; diff --git a/lib/api/requests/node_stats.cpp b/lib/api/requests/node_stats.cpp index 1d342d6cc..6b9cb9124 100644 --- a/lib/api/requests/node_stats.cpp +++ b/lib/api/requests/node_stats.cpp @@ -29,17 +29,17 @@ #include #include #include -#include +#include #include namespace villas { namespace node { namespace api { -class StatsRequest : public Request { +class StatsRequest : public NodeRequest { public: - using Request::Request; + using NodeRequest::NodeRequest; virtual Response * execute() { @@ -49,15 +49,7 @@ public: if (body != nullptr) throw BadRequest("Stats endpoint does not accept any body data"); - const auto &nodeName = matches[1].str(); - - struct vlist *nodes = session->getSuperNode()->getNodes(); - struct vnode *node = vlist_lookup_name(nodes, nodeName.c_str()); - - if (!node) - throw BadRequest("Unknown node"); - - if (!node->stats) + if (node->stats == nullptr) throw BadRequest("The statistics collection for this node is not enabled"); return new Response(session, node->stats->toJson()); diff --git a/lib/api/requests/node_stats_reset.cpp b/lib/api/requests/node_stats_reset.cpp index b1961226b..f33f293e2 100644 --- a/lib/api/requests/node_stats_reset.cpp +++ b/lib/api/requests/node_stats_reset.cpp @@ -29,51 +29,30 @@ #include #include #include -#include +#include #include namespace villas { namespace node { namespace api { -class StatsRequest : public Request { +class StatsRequest : public NodeRequest { public: - using Request::Request; + using NodeRequest::NodeRequest; virtual Response * execute() { - int ret; - json_error_t err; - if (method != Method::POST) throw InvalidMethod(this); if (body != nullptr) throw BadRequest("Stats endpoint does not accept any body data"); + if (node->stats == nullptr) + throw BadRequest("The statistics collection for this node is not enabled"); - char *node = nullptr; - - ret = json_unpack_ex(body, &err, 0, "{ s?: s }", - "node", &node - ); - if (ret < 0) - throw Error(); - - struct vlist *nodes = session->getSuperNode()->getNodes(); - - for (size_t i = 0; i < vlist_length(nodes); i++) { - struct vnode *n = (struct vnode *) vlist_at(nodes, i); - - if (node && strcmp(node, node_name(n))) - continue; - - if (n->stats) { - n->stats->reset(); - info("Stats resetted for node %s", node_name(n)); - } - } + node->stats->reset(); return new Response(session); } diff --git a/lib/api/requests/restart.cpp b/lib/api/requests/restart.cpp index e67b13135..4033f2ddc 100644 --- a/lib/api/requests/restart.cpp +++ b/lib/api/requests/restart.cpp @@ -71,7 +71,7 @@ public: if (body) { ret = json_unpack_ex(body, &err, 0, "{ s?: s }", "config", &cfg); if (ret < 0) - throw Error(); + throw BadRequest("Failed to parse request body"); } /* If no config is provided via request, we will use the previous one */ diff --git a/lib/api/response.cpp b/lib/api/response.cpp index 3f3de59e9..ab5f37b1c 100644 --- a/lib/api/response.cpp +++ b/lib/api/response.cpp @@ -41,7 +41,14 @@ Response::~Response() json_t * ErrorResponse::toJson() { - return json_pack("{ s: s }", + json_t *ret; + + ret = json_pack("{ s: s }", "error", error.c_str() ); + + if (json) + json_object_update(ret, json); + + return ret; }