diff options
author | Benjamin Ford <bford@digium.com> | 2015-07-13 10:54:51 -0500 |
---|---|---|
committer | Benjamin Ford <bford@digium.com> | 2015-07-13 14:27:40 -0500 |
commit | 73e35d20deb57281874939f553fea9fdced2e260 (patch) | |
tree | dcc9e909115d4d97759a30a416ca275a826db29c | |
parent | 5c491a629586ab7036107ae79935a39bcf793a0a (diff) |
ARI: Added new functionality to get information on a single module.
An http request can be sent to retrieve information on a single
module, including the resource name, description, use count, status,
and support level.
The command "curl -v -u user:pass -X GET 'http://localhost:8088/ari
/asterisk/modules/{moduleName}'" (or something similar, depending on
configuration) can be run in the terminal to access this new
functionality.
For more information, see:
https://wiki.asterisk.org/wiki.display/~bford/Asterisk+ARI+Resource
* Added new ARI functionality
* Information on a single module can now be retrieved
ASTERISK-25173
Change-Id: Ibce5a94e70ecdf4e90329cf0ba66c33a62d37463
-rw-r--r-- | CHANGES | 3 | ||||
-rw-r--r-- | include/asterisk/module.h | 19 | ||||
-rw-r--r-- | main/loader.c | 28 | ||||
-rw-r--r-- | res/ari/resource_asterisk.c | 73 | ||||
-rw-r--r-- | res/ari/resource_asterisk.h | 13 | ||||
-rw-r--r-- | res/res_ari_asterisk.c | 74 | ||||
-rw-r--r-- | rest-api/api-docs/asterisk.json | 32 |
7 files changed, 239 insertions, 3 deletions
@@ -23,7 +23,8 @@ AMI ARI ------------------ * A new feature has been added that enables the retrieval of modules and - module information through an HTTP request. + module information through an HTTP request. Information on a single module + can be also be retrieved. res_pjsip ------------------ diff --git a/include/asterisk/module.h b/include/asterisk/module.h index 0d1eb4eb6..d201aacc8 100644 --- a/include/asterisk/module.h +++ b/include/asterisk/module.h @@ -179,6 +179,25 @@ int ast_update_module_list_data(int (*modentry)(const char *module, const char * const char *like, void *data); /*! + * \brief Ask for a list of modules, descriptions, use counts and status. + * \param modentry A callback to an updater function + * \param like + * \param data Data passed into the callback for manipulation + * \param condition The condition to meet + * + * For each of the modules loaded, modentry will be executed with the resource, + * description, and usecount values of each particular module. + * + * \return the number of conditions met + * \since 13.5.0 + */ +int ast_update_module_list_condition(int (*modentry)(const char *module, const char *description, + int usecnt, const char *status, const char *like, + enum ast_module_support_level support_level, + void *data, const char *condition), + const char *like, void *data, const char *condition); + +/*! * \brief Check if module with the name given is loaded * \param name Module name, like "chan_sip.so" * \retval 1 if true diff --git a/main/loader.c b/main/loader.c index 55fed7063..940b53edb 100644 --- a/main/loader.c +++ b/main/loader.c @@ -1451,6 +1451,34 @@ int ast_update_module_list_data(int (*modentry)(const char *module, const char * return total_mod_loaded; } +int ast_update_module_list_condition(int (*modentry)(const char *module, const char *description, + int usecnt, const char *status, + const char *like, + enum ast_module_support_level support_level, + void *data, const char *condition), + const char *like, void *data, const char *condition) +{ + struct ast_module *cur; + int conditions_met = 0; + AST_LIST_HEAD_NOLOCK(, ast_module) alpha_module_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE; + + AST_DLLIST_LOCK(&module_list); + + AST_DLLIST_TRAVERSE(&module_list, cur, entry) { + AST_LIST_INSERT_SORTALPHA(&alpha_module_list, cur, list_entry, resource); + } + + while ((cur = AST_LIST_REMOVE_HEAD(&alpha_module_list, list_entry))) { + conditions_met += modentry(cur->resource, cur->info->description, cur->usecount, + cur->flags.running? "Running" : "Not Running", like, cur->info->support_level, data, + condition); + } + + AST_DLLIST_UNLOCK(&module_list); + + return conditions_met; +} + /*! \brief Check if module exists */ int ast_module_check(const char *name) { diff --git a/res/ari/resource_asterisk.c b/res/ari/resource_asterisk.c index c81bdb384..06ccee7c4 100644 --- a/res/ari/resource_asterisk.c +++ b/res/ari/resource_asterisk.c @@ -185,6 +185,79 @@ void ast_ari_asterisk_list_modules(struct ast_variable *headers, ast_ari_response_ok(response, json); } +/*! + * \brief Identify module by name and process resource information + * \param module Resource name + * \param description Resource description + * \param usecnt Resource use count + * \param status Resource running status + * \param like + * \param support_level Resource support level + * \param data JSON body for resource + * \param condition Name to match resource to + * + * \retval 0 if no resource exists + * \retval 1 if resource exists + */ +static int identify_module(const char *module, const char *description, int usecnt, + const char *status, const char *like, + enum ast_module_support_level support_level, void *data, + const char *condition) +{ + int json_obj_set = 0; + + if (strcmp(condition, module) != 0) { + return 0; + } + + json_obj_set += ast_json_object_set(data, "name", ast_json_string_create(module)); + json_obj_set += ast_json_object_set(data, "description", ast_json_string_create(description)); + json_obj_set += ast_json_object_set(data, "use_count", ast_json_integer_create(usecnt)); + json_obj_set += ast_json_object_set(data, "status", ast_json_string_create(status)); + json_obj_set += ast_json_object_set(data, "support_level", ast_json_string_create( + ast_module_support_level_to_string(support_level))); + + if (json_obj_set != 0) { + return 0; + } + + return 1; +} + +void ast_ari_asterisk_get_module(struct ast_variable *headers, + struct ast_ari_asterisk_get_module_args *args, + struct ast_ari_response *response) +{ + struct ast_json *json; + int module_retrieved = 0; + + ast_assert(response != NULL); + + if (!ast_module_check(args->module_name)) { + ast_ari_response_error( + response, 404, "Not Found", + "Module could not be found in running modules"); + return; + } + + json = ast_json_object_create(); + if (!json) { + ast_ari_response_alloc_failed(response); + return; + } + + module_retrieved = ast_update_module_list_condition(&identify_module, NULL, json, + args->module_name); + if (!module_retrieved) { + ast_ari_response_error( + response, 409, "Conflict", + "Module information could not be retrieved"); + return; + } + + ast_ari_response_ok(response, json); +} + void ast_ari_asterisk_get_global_var(struct ast_variable *headers, struct ast_ari_asterisk_get_global_var_args *args, struct ast_ari_response *response) diff --git a/res/ari/resource_asterisk.h b/res/ari/resource_asterisk.h index b09d2715a..8689f3ec1 100644 --- a/res/ari/resource_asterisk.h +++ b/res/ari/resource_asterisk.h @@ -78,6 +78,19 @@ struct ast_ari_asterisk_list_modules_args { * \param[out] response HTTP response */ void ast_ari_asterisk_list_modules(struct ast_variable *headers, struct ast_ari_asterisk_list_modules_args *args, struct ast_ari_response *response); +/*! Argument struct for ast_ari_asterisk_get_module() */ +struct ast_ari_asterisk_get_module_args { + /*! Module's name */ + const char *module_name; +}; +/*! + * \brief Get Asterisk module information. + * + * \param headers HTTP headers + * \param args Swagger parameters + * \param[out] response HTTP response + */ +void ast_ari_asterisk_get_module(struct ast_variable *headers, struct ast_ari_asterisk_get_module_args *args, struct ast_ari_response *response); /*! Argument struct for ast_ari_asterisk_get_global_var() */ struct ast_ari_asterisk_get_global_var_args { /*! The variable to get */ diff --git a/res/res_ari_asterisk.c b/res/res_ari_asterisk.c index 85bf78e06..dfe4b7061 100644 --- a/res/res_ari_asterisk.c +++ b/res/res_ari_asterisk.c @@ -260,6 +260,66 @@ static void ast_ari_asterisk_list_modules_cb( fin: __attribute__((unused)) return; } +/*! + * \brief Parameter parsing callback for /asterisk/modules/{moduleName}. + * \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_module_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_module_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, "moduleName") == 0) { + args.module_name = (i->value); + } else + {} + } + ast_ari_asterisk_get_module(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: /* Module could not be found in running modules. */ + case 409: /* Module information could not be retrieved. */ + is_valid = 1; + break; + default: + if (200 <= code && code <= 299) { + is_valid = ast_ari_validate_module( + response->message); + } else { + ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/modules/{moduleName}\n", code); + is_valid = 0; + } + } + + if (!is_valid) { + ast_log(LOG_ERROR, "Response validation failed for /asterisk/modules/{moduleName}\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_global_var_parse_body( struct ast_json *body, struct ast_ari_asterisk_get_global_var_args *args) @@ -460,13 +520,23 @@ static struct stasis_rest_handlers asterisk_info = { .children = { } }; /*! \brief REST handler for /api-docs/asterisk.{format} */ +static struct stasis_rest_handlers asterisk_modules_moduleName = { + .path_segment = "moduleName", + .is_wildcard = 1, + .callbacks = { + [AST_HTTP_GET] = ast_ari_asterisk_get_module_cb, + }, + .num_children = 0, + .children = { } +}; +/*! \brief REST handler for /api-docs/asterisk.{format} */ static struct stasis_rest_handlers asterisk_modules = { .path_segment = "modules", .callbacks = { [AST_HTTP_GET] = ast_ari_asterisk_list_modules_cb, }, - .num_children = 0, - .children = { } + .num_children = 1, + .children = { &asterisk_modules_moduleName, } }; /*! \brief REST handler for /api-docs/asterisk.{format} */ static struct stasis_rest_handlers asterisk_variable = { diff --git a/rest-api/api-docs/asterisk.json b/rest-api/api-docs/asterisk.json index ade5938c9..76c834e45 100644 --- a/rest-api/api-docs/asterisk.json +++ b/rest-api/api-docs/asterisk.json @@ -51,6 +51,38 @@ ] }, { + "path": "/asterisk/modules/{moduleName}", + "description": "Asterisk module", + "operations": [ + { + "httpMethod": "GET", + "summary": "Get Asterisk module information.", + "nickname": "getModule", + "responseClass": "Module", + "parameters": [ + { + "name": "moduleName", + "description": "Module's name", + "paramType": "path", + "required": true, + "allowMultiple": false, + "dataType": "string" + } + ], + "errorResponses": [ + { + "code": 404, + "reason": "Module could not be found in running modules." + }, + { + "code": 409, + "reason": "Module information could not be retrieved." + } + ] + } + ] + }, + { "path": "/asterisk/variable", "description": "Global variables", "operations": [ |