summaryrefslogtreecommitdiff
path: root/res/res_ari_asterisk.c
diff options
context:
space:
mode:
authorMatt Jordan <mjordan@digium.com>2015-07-08 16:39:35 -0500
committerMatt Jordan <mjordan@digium.com>2015-07-16 20:38:57 -0500
commit254d07b15b6f6a741c1293cf9d26a2a235e795ed (patch)
tree0a1d7d9e98f5bd166fd74f575ea6d46c8ddf2b53 /res/res_ari_asterisk.c
parentaf9ee2910d4f791243fa9c6ef98dd53264acc445 (diff)
ARI: Add support for push configuration of dynamic object
This patch adds support for push configuration of dynamic, i.e., sorcery, objects in Asterisk. It adds three new REST API calls to the 'asterisk' resource: * GET /asterisk/{configClass}/{objectType}/{id}: retrieve the current object given its ID. This returns back a list of ConfigTuples, which define the fields and their present values that make up the object. * PUT /asterisk/{configClass}/{objectType}/{id}: create or update an object. A body may be passed with the request that contains fields to populate in the object. The same format as what is retrieved using the GET operation is used for the body, save that we specify that the list of fields to update are contained in the "fields" attribute. * DELETE /asterisk/{configClass}/{objectType}/{id}: remove a dynamic object from its backing storage. Note that the success/failure of these operations is somewhat configuration dependent, i.e., you must be using a sorcery wizard that supports the operation in question. If a sorcery wizard does not support the create or delete mechanisms, then the REST API call will fail with a 403 forbidden. ASTERISK-25238 #close Change-Id: I28cd5c7bf6f67f8e9e437ff097f8fd171d30ff5c
Diffstat (limited to 'res/res_ari_asterisk.c')
-rw-r--r--res/res_ari_asterisk.c272
1 files changed, 270 insertions, 2 deletions
diff --git a/res/res_ari_asterisk.c b/res/res_ari_asterisk.c
index 7d938a0a4..671af59da 100644
--- a/res/res_ari_asterisk.c
+++ b/res/res_ari_asterisk.c
@@ -52,6 +52,228 @@ ASTERISK_REGISTER_FILE()
#define MAX_VALS 128
+/*!
+ * \brief Parameter parsing callback for /asterisk/config/dynamic/{configClass}/{objectType}/{id}.
+ * \param get_params GET parameters in the HTTP request.
+ * \param path_vars Path variables extracted from the request.
+ * \param headers HTTP headers.
+ * \param[out] response Response to the HTTP request.
+ */
+static void ast_ari_asterisk_get_object_cb(
+ struct ast_tcptls_session_instance *ser,
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct ast_ari_response *response)
+{
+ struct ast_ari_asterisk_get_object_args args = {};
+ struct ast_variable *i;
+ RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
+ for (i = path_vars; i; i = i->next) {
+ if (strcmp(i->name, "configClass") == 0) {
+ args.config_class = (i->value);
+ } else
+ if (strcmp(i->name, "objectType") == 0) {
+ args.object_type = (i->value);
+ } else
+ if (strcmp(i->name, "id") == 0) {
+ args.id = (i->value);
+ } else
+ {}
+ }
+ ast_ari_asterisk_get_object(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 0: /* Implementation is still a stub, or the code wasn't set */
+ is_valid = response->message == NULL;
+ break;
+ case 500: /* Internal Server Error */
+ case 501: /* Not Implemented */
+ case 404: /* {configClass|objectType|id} not found */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ast_ari_validate_list(response->message,
+ ast_ari_validate_config_tuple_fn());
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/config/dynamic/{configClass}/{objectType}/{id}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /asterisk/config/dynamic/{configClass}/{objectType}/{id}\n");
+ ast_ari_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+ return;
+}
+int ast_ari_asterisk_update_object_parse_body(
+ struct ast_json *body,
+ struct ast_ari_asterisk_update_object_args *args)
+{
+ /* Parse query parameters out of it */
+ return 0;
+}
+
+/*!
+ * \brief Parameter parsing callback for /asterisk/config/dynamic/{configClass}/{objectType}/{id}.
+ * \param get_params GET parameters in the HTTP request.
+ * \param path_vars Path variables extracted from the request.
+ * \param headers HTTP headers.
+ * \param[out] response Response to the HTTP request.
+ */
+static void ast_ari_asterisk_update_object_cb(
+ struct ast_tcptls_session_instance *ser,
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct ast_ari_response *response)
+{
+ struct ast_ari_asterisk_update_object_args args = {};
+ struct ast_variable *i;
+ RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
+ for (i = path_vars; i; i = i->next) {
+ if (strcmp(i->name, "configClass") == 0) {
+ args.config_class = (i->value);
+ } else
+ if (strcmp(i->name, "objectType") == 0) {
+ args.object_type = (i->value);
+ } else
+ if (strcmp(i->name, "id") == 0) {
+ args.id = (i->value);
+ } else
+ {}
+ }
+ /* Look for a JSON request entity */
+ body = ast_http_get_json(ser, headers);
+ if (!body) {
+ switch (errno) {
+ case EFBIG:
+ ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
+ goto fin;
+ case ENOMEM:
+ ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
+ goto fin;
+ case EIO:
+ ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
+ goto fin;
+ }
+ }
+ args.fields = body;
+ ast_ari_asterisk_update_object(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 0: /* Implementation is still a stub, or the code wasn't set */
+ is_valid = response->message == NULL;
+ break;
+ case 500: /* Internal Server Error */
+ case 501: /* Not Implemented */
+ case 400: /* Bad request body */
+ case 403: /* Could not create or update object */
+ case 404: /* {configClass|objectType} not found */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ast_ari_validate_list(response->message,
+ ast_ari_validate_config_tuple_fn());
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/config/dynamic/{configClass}/{objectType}/{id}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /asterisk/config/dynamic/{configClass}/{objectType}/{id}\n");
+ ast_ari_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+ return;
+}
+/*!
+ * \brief Parameter parsing callback for /asterisk/config/dynamic/{configClass}/{objectType}/{id}.
+ * \param get_params GET parameters in the HTTP request.
+ * \param path_vars Path variables extracted from the request.
+ * \param headers HTTP headers.
+ * \param[out] response Response to the HTTP request.
+ */
+static void ast_ari_asterisk_delete_object_cb(
+ struct ast_tcptls_session_instance *ser,
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct ast_ari_response *response)
+{
+ struct ast_ari_asterisk_delete_object_args args = {};
+ struct ast_variable *i;
+ RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
+ for (i = path_vars; i; i = i->next) {
+ if (strcmp(i->name, "configClass") == 0) {
+ args.config_class = (i->value);
+ } else
+ if (strcmp(i->name, "objectType") == 0) {
+ args.object_type = (i->value);
+ } else
+ if (strcmp(i->name, "id") == 0) {
+ args.id = (i->value);
+ } else
+ {}
+ }
+ ast_ari_asterisk_delete_object(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 0: /* Implementation is still a stub, or the code wasn't set */
+ is_valid = response->message == NULL;
+ break;
+ case 500: /* Internal Server Error */
+ case 501: /* Not Implemented */
+ case 403: /* Could not delete object */
+ case 404: /* {configClass|objectType|id} not found */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ast_ari_validate_void(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/config/dynamic/{configClass}/{objectType}/{id}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /asterisk/config/dynamic/{configClass}/{objectType}/{id}\n");
+ ast_ari_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+ return;
+}
int ast_ari_asterisk_get_info_parse_body(
struct ast_json *body,
struct ast_ari_asterisk_get_info_args *args)
@@ -690,6 +912,52 @@ fin: __attribute__((unused))
}
/*! \brief REST handler for /api-docs/asterisk.{format} */
+static struct stasis_rest_handlers asterisk_config_dynamic_configClass_objectType_id = {
+ .path_segment = "id",
+ .is_wildcard = 1,
+ .callbacks = {
+ [AST_HTTP_GET] = ast_ari_asterisk_get_object_cb,
+ [AST_HTTP_PUT] = ast_ari_asterisk_update_object_cb,
+ [AST_HTTP_DELETE] = ast_ari_asterisk_delete_object_cb,
+ },
+ .num_children = 0,
+ .children = { }
+};
+/*! \brief REST handler for /api-docs/asterisk.{format} */
+static struct stasis_rest_handlers asterisk_config_dynamic_configClass_objectType = {
+ .path_segment = "objectType",
+ .is_wildcard = 1,
+ .callbacks = {
+ },
+ .num_children = 1,
+ .children = { &asterisk_config_dynamic_configClass_objectType_id, }
+};
+/*! \brief REST handler for /api-docs/asterisk.{format} */
+static struct stasis_rest_handlers asterisk_config_dynamic_configClass = {
+ .path_segment = "configClass",
+ .is_wildcard = 1,
+ .callbacks = {
+ },
+ .num_children = 1,
+ .children = { &asterisk_config_dynamic_configClass_objectType, }
+};
+/*! \brief REST handler for /api-docs/asterisk.{format} */
+static struct stasis_rest_handlers asterisk_config_dynamic = {
+ .path_segment = "dynamic",
+ .callbacks = {
+ },
+ .num_children = 1,
+ .children = { &asterisk_config_dynamic_configClass, }
+};
+/*! \brief REST handler for /api-docs/asterisk.{format} */
+static struct stasis_rest_handlers asterisk_config = {
+ .path_segment = "config",
+ .callbacks = {
+ },
+ .num_children = 1,
+ .children = { &asterisk_config_dynamic, }
+};
+/*! \brief REST handler for /api-docs/asterisk.{format} */
static struct stasis_rest_handlers asterisk_info = {
.path_segment = "info",
.callbacks = {
@@ -735,8 +1003,8 @@ static struct stasis_rest_handlers asterisk = {
.path_segment = "asterisk",
.callbacks = {
},
- .num_children = 3,
- .children = { &asterisk_info,&asterisk_modules,&asterisk_variable, }
+ .num_children = 4,
+ .children = { &asterisk_config,&asterisk_info,&asterisk_modules,&asterisk_variable, }
};
static int load_module(void)