From ac90968afdccb214cfa73ae7ea2cada5cb8dd37e Mon Sep 17 00:00:00 2001 From: sungtae kim <sungtae@messagebird.com> Date: Tue, 29 Jan 2019 00:21:28 +0100 Subject: [PATCH] Added ARI resource /ari/asterisk/ping Added ARI resource. GET /ari/asterisk/ping : It returns "pong" message with timestamp and asterisk id. It would be useful for simple heath check. Change-Id: I8d24e1dcc96f60f73437c68d9463ed746f688b29 --- res/ari/ari_model_validators.c | 70 +++++++++++++++++++++++++++++++++ res/ari/ari_model_validators.h | 22 +++++++++++ res/ari/resource_asterisk.c | 18 +++++++++ res/ari/resource_asterisk.h | 11 ++++++ res/res_ari_asterisk.c | 63 ++++++++++++++++++++++++++++- rest-api/api-docs/asterisk.json | 33 ++++++++++++++++ 6 files changed, 215 insertions(+), 2 deletions(-) diff --git a/res/ari/ari_model_validators.c b/res/ari/ari_model_validators.c index ea5a885995..a06a1f5e59 100644 --- a/res/ari/ari_model_validators.c +++ b/res/ari/ari_model_validators.c @@ -91,6 +91,76 @@ ari_validator ast_ari_validate_asterisk_info_fn(void) return ast_ari_validate_asterisk_info; } +int ast_ari_validate_asterisk_ping(struct ast_json *json) +{ + int res = 1; + struct ast_json_iter *iter; + int has_asterisk_id = 0; + int has_ping = 0; + int has_timestamp = 0; + + for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) { + if (strcmp("asterisk_id", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_asterisk_id = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI AsteriskPing field asterisk_id failed validation\n"); + res = 0; + } + } else + if (strcmp("ping", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_ping = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI AsteriskPing field ping failed validation\n"); + res = 0; + } + } else + if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_timestamp = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI AsteriskPing field timestamp failed validation\n"); + res = 0; + } + } else + { + ast_log(LOG_ERROR, + "ARI AsteriskPing has undocumented field %s\n", + ast_json_object_iter_key(iter)); + res = 0; + } + } + + if (!has_asterisk_id) { + ast_log(LOG_ERROR, "ARI AsteriskPing missing required field asterisk_id\n"); + res = 0; + } + + if (!has_ping) { + ast_log(LOG_ERROR, "ARI AsteriskPing missing required field ping\n"); + res = 0; + } + + if (!has_timestamp) { + ast_log(LOG_ERROR, "ARI AsteriskPing missing required field timestamp\n"); + res = 0; + } + + return res; +} + +ari_validator ast_ari_validate_asterisk_ping_fn(void) +{ + return ast_ari_validate_asterisk_ping; +} + int ast_ari_validate_build_info(struct ast_json *json) { int res = 1; diff --git a/res/ari/ari_model_validators.h b/res/ari/ari_model_validators.h index 3c501cf712..ab0b2f60b0 100644 --- a/res/ari/ari_model_validators.h +++ b/res/ari/ari_model_validators.h @@ -169,6 +169,24 @@ int ast_ari_validate_asterisk_info(struct ast_json *json); */ ari_validator ast_ari_validate_asterisk_info_fn(void); +/*! + * \brief Validator for AsteriskPing. + * + * Asterisk ping information + * + * \param json JSON object to validate. + * \returns True (non-zero) if valid. + * \returns False (zero) if invalid. + */ +int ast_ari_validate_asterisk_ping(struct ast_json *json); + +/*! + * \brief Function pointer to ast_ari_validate_asterisk_ping(). + * + * See \ref ast_ari_model_validators.h for more details. + */ +ari_validator ast_ari_validate_asterisk_ping_fn(void); + /*! * \brief Validator for BuildInfo. * @@ -1391,6 +1409,10 @@ ari_validator ast_ari_validate_application_fn(void); * - config: ConfigInfo * - status: StatusInfo * - system: SystemInfo + * AsteriskPing + * - asterisk_id: string (required) + * - ping: string (required) + * - timestamp: string (required) * BuildInfo * - date: string (required) * - kernel: string (required) diff --git a/res/ari/resource_asterisk.c b/res/ari/resource_asterisk.c index 5c6a35af6c..4e3dea721f 100644 --- a/res/ari/resource_asterisk.c +++ b/res/ari/resource_asterisk.c @@ -631,6 +631,24 @@ void ast_ari_asterisk_reload_module(struct ast_variable *headers, ast_ari_response_no_content(response); } +void ast_ari_asterisk_ping(struct ast_variable *headers, + struct ast_ari_asterisk_ping_args *args, + struct ast_ari_response *response) +{ + struct ast_json *json; + char eid[20]; + + ast_assert(response != NULL); + + json = ast_json_pack("{s: s, s: o, s: s}", + "ping", "pong", + "timestamp", ast_json_timeval(ast_tvnow(), NULL), + "asterisk_id", ast_eid_to_str(eid, sizeof(eid), &ast_eid_default) + ); + + ast_ari_response_ok(response, json); +} + /*! * \brief Process logger information and append to a json array * \param channel Resource logger channel name path diff --git a/res/ari/resource_asterisk.h b/res/ari/resource_asterisk.h index a4a7da0806..5b2d494433 100644 --- a/res/ari/resource_asterisk.h +++ b/res/ari/resource_asterisk.h @@ -131,6 +131,17 @@ int ast_ari_asterisk_get_info_parse_body( * \param[out] response HTTP response */ void ast_ari_asterisk_get_info(struct ast_variable *headers, struct ast_ari_asterisk_get_info_args *args, struct ast_ari_response *response); +/*! Argument struct for ast_ari_asterisk_ping() */ +struct ast_ari_asterisk_ping_args { +}; +/*! + * \brief Response pong message. + * + * \param headers HTTP headers + * \param args Swagger parameters + * \param[out] response HTTP response + */ +void ast_ari_asterisk_ping(struct ast_variable *headers, struct ast_ari_asterisk_ping_args *args, struct ast_ari_response *response); /*! Argument struct for ast_ari_asterisk_list_modules() */ struct ast_ari_asterisk_list_modules_args { }; diff --git a/res/res_ari_asterisk.c b/res/res_ari_asterisk.c index e143a7f6ad..a077548c0d 100644 --- a/res/res_ari_asterisk.c +++ b/res/res_ari_asterisk.c @@ -395,6 +395,56 @@ fin: __attribute__((unused)) ast_free(args.only); return; } +/*! + * \brief Parameter parsing callback for /asterisk/ping. + * \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_ping_cb( + struct ast_tcptls_session_instance *ser, + struct ast_variable *get_params, struct ast_variable *path_vars, + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) +{ + struct ast_ari_asterisk_ping_args args = {}; +#if defined(AST_DEVMODE) + int is_valid; + int code; +#endif /* AST_DEVMODE */ + + ast_ari_asterisk_ping(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 */ + is_valid = 1; + break; + default: + if (200 <= code && code <= 299) { + is_valid = ast_ari_validate_asterisk_ping( + response->message); + } else { + ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/ping\n", code); + is_valid = 0; + } + } + + if (!is_valid) { + ast_log(LOG_ERROR, "Response validation failed for /asterisk/ping\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/modules. * \param get_params GET parameters in the HTTP request. @@ -1142,6 +1192,15 @@ static struct stasis_rest_handlers asterisk_info = { .children = { } }; /*! \brief REST handler for /api-docs/asterisk.json */ +static struct stasis_rest_handlers asterisk_ping = { + .path_segment = "ping", + .callbacks = { + [AST_HTTP_GET] = ast_ari_asterisk_ping_cb, + }, + .num_children = 0, + .children = { } +}; +/*! \brief REST handler for /api-docs/asterisk.json */ static struct stasis_rest_handlers asterisk_modules_moduleName = { .path_segment = "moduleName", .is_wildcard = 1, @@ -1207,8 +1266,8 @@ static struct stasis_rest_handlers asterisk = { .path_segment = "asterisk", .callbacks = { }, - .num_children = 5, - .children = { &asterisk_config,&asterisk_info,&asterisk_modules,&asterisk_logging,&asterisk_variable, } + .num_children = 6, + .children = { &asterisk_config,&asterisk_info,&asterisk_ping,&asterisk_modules,&asterisk_logging,&asterisk_variable, } }; static int unload_module(void) diff --git a/rest-api/api-docs/asterisk.json b/rest-api/api-docs/asterisk.json index f40bf5c6b7..841e6cd8fd 100644 --- a/rest-api/api-docs/asterisk.json +++ b/rest-api/api-docs/asterisk.json @@ -178,6 +178,18 @@ } ] }, + { + "path": "/asterisk/ping", + "description": "Asterisk ping", + "operations": [ + { + "httpMethod": "GET", + "summary": "Response pong message.", + "nickname": "ping", + "responseClass": "AsteriskPing" + } + ] + }, { "path": "/asterisk/modules", "description": "Asterisk modules", @@ -604,6 +616,27 @@ } } }, + "AsteriskPing": { + "id": "AsteriskPing", + "description": "Asterisk ping information", + "properties": { + "asterisk_id": { + "required": true, + "type": "string", + "description": "Asterisk id info" + }, + "ping": { + "required": true, + "type": "string", + "description": "Always string value is pong" + }, + "timestamp": { + "required": true, + "type": "string", + "description": "The timestamp string of request received time" + } + } + }, "Module": { "id": "Module", "description": "Details of an Asterisk module", -- GitLab