From 5114e4fc0ba896c91344c1c766740e8f7c661813 Mon Sep 17 00:00:00 2001 From: "David M. Lee" Date: Fri, 2 Aug 2013 14:46:21 +0000 Subject: [PATCH] ARI - GET /ari/asterisk/info This patch adds basic system information access to ARI. The results are roughly what you get from 'core show settings', with a few minor differences. * Data is structured, with 'build', 'system', 'config' and 'status' sub-objects. * Each sub-object is selectable, using the ?only= parameter. A comma separated list can be provided to select multiple sections. * A few config options are numeric, for which 0 means 'unlimited'. Instead of having a special interpretation of those fields, they are simply omitted if they're 0. * The information is limited to what might be useful to building external applications. (closes issue ASTERISK-21575) Review: https://reviewboard.asterisk.org/r/2702/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@396125 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- res/ari/ari_model_validators.c | 413 ++++++++++++++++++++++++++++++++ res/ari/ari_model_validators.h | 117 +++++++++ res/ari/resource_asterisk.c | 107 ++++++++- rest-api/api-docs/asterisk.json | 143 ++++++++++- 4 files changed, 776 insertions(+), 4 deletions(-) diff --git a/res/ari/ari_model_validators.c b/res/ari/ari_model_validators.c index 1894ddb9af..6932cf5ac7 100644 --- a/res/ari/ari_model_validators.c +++ b/res/ari/ari_model_validators.c @@ -41,6 +41,42 @@ int ast_ari_validate_asterisk_info(struct ast_json *json) struct ast_json_iter *iter; for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) { + if (strcmp("build", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + prop_is_valid = ast_ari_validate_build_info( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI AsteriskInfo field build failed validation\n"); + res = 0; + } + } else + if (strcmp("config", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + prop_is_valid = ast_ari_validate_config_info( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI AsteriskInfo field config failed validation\n"); + res = 0; + } + } else + if (strcmp("status", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + prop_is_valid = ast_ari_validate_status_info( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI AsteriskInfo field status failed validation\n"); + res = 0; + } + } else + if (strcmp("system", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + prop_is_valid = ast_ari_validate_system_info( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI AsteriskInfo field system failed validation\n"); + res = 0; + } + } else { ast_log(LOG_ERROR, "ARI AsteriskInfo has undocumented field %s\n", @@ -57,6 +93,383 @@ ari_validator ast_ari_validate_asterisk_info_fn(void) return ast_ari_validate_asterisk_info; } +int ast_ari_validate_build_info(struct ast_json *json) +{ + int res = 1; + struct ast_json_iter *iter; + int has_date = 0; + int has_kernel = 0; + int has_machine = 0; + int has_options = 0; + int has_os = 0; + int has_user = 0; + + for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) { + if (strcmp("date", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_date = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI BuildInfo field date failed validation\n"); + res = 0; + } + } else + if (strcmp("kernel", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_kernel = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI BuildInfo field kernel failed validation\n"); + res = 0; + } + } else + if (strcmp("machine", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_machine = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI BuildInfo field machine failed validation\n"); + res = 0; + } + } else + if (strcmp("options", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_options = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI BuildInfo field options failed validation\n"); + res = 0; + } + } else + if (strcmp("os", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_os = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI BuildInfo field os failed validation\n"); + res = 0; + } + } else + if (strcmp("user", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_user = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI BuildInfo field user failed validation\n"); + res = 0; + } + } else + { + ast_log(LOG_ERROR, + "ARI BuildInfo has undocumented field %s\n", + ast_json_object_iter_key(iter)); + res = 0; + } + } + + if (!has_date) { + ast_log(LOG_ERROR, "ARI BuildInfo missing required field date\n"); + res = 0; + } + + if (!has_kernel) { + ast_log(LOG_ERROR, "ARI BuildInfo missing required field kernel\n"); + res = 0; + } + + if (!has_machine) { + ast_log(LOG_ERROR, "ARI BuildInfo missing required field machine\n"); + res = 0; + } + + if (!has_options) { + ast_log(LOG_ERROR, "ARI BuildInfo missing required field options\n"); + res = 0; + } + + if (!has_os) { + ast_log(LOG_ERROR, "ARI BuildInfo missing required field os\n"); + res = 0; + } + + if (!has_user) { + ast_log(LOG_ERROR, "ARI BuildInfo missing required field user\n"); + res = 0; + } + + return res; +} + +ari_validator ast_ari_validate_build_info_fn(void) +{ + return ast_ari_validate_build_info; +} + +int ast_ari_validate_config_info(struct ast_json *json) +{ + int res = 1; + struct ast_json_iter *iter; + int has_default_language = 0; + int has_name = 0; + int has_setid = 0; + + for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) { + if (strcmp("default_language", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_default_language = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI ConfigInfo field default_language failed validation\n"); + res = 0; + } + } else + if (strcmp("max_channels", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + prop_is_valid = ast_ari_validate_int( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI ConfigInfo field max_channels failed validation\n"); + res = 0; + } + } else + if (strcmp("max_load", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + prop_is_valid = ast_ari_validate_double( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI ConfigInfo field max_load failed validation\n"); + res = 0; + } + } else + if (strcmp("max_open_files", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + prop_is_valid = ast_ari_validate_int( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI ConfigInfo field max_open_files failed validation\n"); + res = 0; + } + } else + if (strcmp("name", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_name = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI ConfigInfo field name failed validation\n"); + res = 0; + } + } else + if (strcmp("setid", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_setid = 1; + prop_is_valid = ast_ari_validate_set_id( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI ConfigInfo field setid failed validation\n"); + res = 0; + } + } else + { + ast_log(LOG_ERROR, + "ARI ConfigInfo has undocumented field %s\n", + ast_json_object_iter_key(iter)); + res = 0; + } + } + + if (!has_default_language) { + ast_log(LOG_ERROR, "ARI ConfigInfo missing required field default_language\n"); + res = 0; + } + + if (!has_name) { + ast_log(LOG_ERROR, "ARI ConfigInfo missing required field name\n"); + res = 0; + } + + if (!has_setid) { + ast_log(LOG_ERROR, "ARI ConfigInfo missing required field setid\n"); + res = 0; + } + + return res; +} + +ari_validator ast_ari_validate_config_info_fn(void) +{ + return ast_ari_validate_config_info; +} + +int ast_ari_validate_set_id(struct ast_json *json) +{ + int res = 1; + struct ast_json_iter *iter; + int has_group = 0; + int has_user = 0; + + for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) { + if (strcmp("group", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_group = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI SetId field group failed validation\n"); + res = 0; + } + } else + if (strcmp("user", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_user = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI SetId field user failed validation\n"); + res = 0; + } + } else + { + ast_log(LOG_ERROR, + "ARI SetId has undocumented field %s\n", + ast_json_object_iter_key(iter)); + res = 0; + } + } + + if (!has_group) { + ast_log(LOG_ERROR, "ARI SetId missing required field group\n"); + res = 0; + } + + if (!has_user) { + ast_log(LOG_ERROR, "ARI SetId missing required field user\n"); + res = 0; + } + + return res; +} + +ari_validator ast_ari_validate_set_id_fn(void) +{ + return ast_ari_validate_set_id; +} + +int ast_ari_validate_status_info(struct ast_json *json) +{ + int res = 1; + struct ast_json_iter *iter; + int has_last_reload_time = 0; + int has_startup_time = 0; + + for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) { + if (strcmp("last_reload_time", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_last_reload_time = 1; + prop_is_valid = ast_ari_validate_date( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI StatusInfo field last_reload_time failed validation\n"); + res = 0; + } + } else + if (strcmp("startup_time", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_startup_time = 1; + prop_is_valid = ast_ari_validate_date( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI StatusInfo field startup_time failed validation\n"); + res = 0; + } + } else + { + ast_log(LOG_ERROR, + "ARI StatusInfo has undocumented field %s\n", + ast_json_object_iter_key(iter)); + res = 0; + } + } + + if (!has_last_reload_time) { + ast_log(LOG_ERROR, "ARI StatusInfo missing required field last_reload_time\n"); + res = 0; + } + + if (!has_startup_time) { + ast_log(LOG_ERROR, "ARI StatusInfo missing required field startup_time\n"); + res = 0; + } + + return res; +} + +ari_validator ast_ari_validate_status_info_fn(void) +{ + return ast_ari_validate_status_info; +} + +int ast_ari_validate_system_info(struct ast_json *json) +{ + int res = 1; + struct ast_json_iter *iter; + int has_entity_id = 0; + int has_version = 0; + + for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) { + if (strcmp("entity_id", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_entity_id = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI SystemInfo field entity_id failed validation\n"); + res = 0; + } + } else + if (strcmp("version", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_version = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI SystemInfo field version failed validation\n"); + res = 0; + } + } else + { + ast_log(LOG_ERROR, + "ARI SystemInfo has undocumented field %s\n", + ast_json_object_iter_key(iter)); + res = 0; + } + } + + if (!has_entity_id) { + ast_log(LOG_ERROR, "ARI SystemInfo missing required field entity_id\n"); + res = 0; + } + + if (!has_version) { + ast_log(LOG_ERROR, "ARI SystemInfo missing required field version\n"); + res = 0; + } + + return res; +} + +ari_validator ast_ari_validate_system_info_fn(void) +{ + return ast_ari_validate_system_info; +} + int ast_ari_validate_variable(struct ast_json *json) { int res = 1; diff --git a/res/ari/ari_model_validators.h b/res/ari/ari_model_validators.h index c5e74d21a7..e8ef8e2106 100644 --- a/res/ari/ari_model_validators.h +++ b/res/ari/ari_model_validators.h @@ -161,6 +161,96 @@ int ast_ari_validate_asterisk_info(struct ast_json *json); */ ari_validator ast_ari_validate_asterisk_info_fn(void); +/*! + * \brief Validator for BuildInfo. + * + * Info about how Asterisk was built + * + * \param json JSON object to validate. + * \returns True (non-zero) if valid. + * \returns False (zero) if invalid. + */ +int ast_ari_validate_build_info(struct ast_json *json); + +/*! + * \brief Function pointer to ast_ari_validate_build_info(). + * + * See \ref ast_ari_model_validators.h for more details. + */ +ari_validator ast_ari_validate_build_info_fn(void); + +/*! + * \brief Validator for ConfigInfo. + * + * Info about Asterisk configuration + * + * \param json JSON object to validate. + * \returns True (non-zero) if valid. + * \returns False (zero) if invalid. + */ +int ast_ari_validate_config_info(struct ast_json *json); + +/*! + * \brief Function pointer to ast_ari_validate_config_info(). + * + * See \ref ast_ari_model_validators.h for more details. + */ +ari_validator ast_ari_validate_config_info_fn(void); + +/*! + * \brief Validator for SetId. + * + * Effective user/group id + * + * \param json JSON object to validate. + * \returns True (non-zero) if valid. + * \returns False (zero) if invalid. + */ +int ast_ari_validate_set_id(struct ast_json *json); + +/*! + * \brief Function pointer to ast_ari_validate_set_id(). + * + * See \ref ast_ari_model_validators.h for more details. + */ +ari_validator ast_ari_validate_set_id_fn(void); + +/*! + * \brief Validator for StatusInfo. + * + * Info about Asterisk status + * + * \param json JSON object to validate. + * \returns True (non-zero) if valid. + * \returns False (zero) if invalid. + */ +int ast_ari_validate_status_info(struct ast_json *json); + +/*! + * \brief Function pointer to ast_ari_validate_status_info(). + * + * See \ref ast_ari_model_validators.h for more details. + */ +ari_validator ast_ari_validate_status_info_fn(void); + +/*! + * \brief Validator for SystemInfo. + * + * Info about Asterisk + * + * \param json JSON object to validate. + * \returns True (non-zero) if valid. + * \returns False (zero) if invalid. + */ +int ast_ari_validate_system_info(struct ast_json *json); + +/*! + * \brief Function pointer to ast_ari_validate_system_info(). + * + * See \ref ast_ari_model_validators.h for more details. + */ +ari_validator ast_ari_validate_system_info_fn(void); + /*! * \brief Validator for Variable. * @@ -785,6 +875,33 @@ ari_validator ast_ari_validate_stasis_start_fn(void); * JSON models * * AsteriskInfo + * - build: BuildInfo + * - config: ConfigInfo + * - status: StatusInfo + * - system: SystemInfo + * BuildInfo + * - date: string (required) + * - kernel: string (required) + * - machine: string (required) + * - options: string (required) + * - os: string (required) + * - user: string (required) + * ConfigInfo + * - default_language: string (required) + * - max_channels: int + * - max_load: double + * - max_open_files: int + * - name: string (required) + * - setid: SetId (required) + * SetId + * - group: string (required) + * - user: string (required) + * StatusInfo + * - last_reload_time: Date (required) + * - startup_time: Date (required) + * SystemInfo + * - entity_id: string (required) + * - version: string (required) * Variable * - value: string (required) * Endpoint diff --git a/res/ari/resource_asterisk.c b/res/ari/resource_asterisk.c index dac45714ff..88f8d35cdd 100644 --- a/res/ari/resource_asterisk.c +++ b/res/ari/resource_asterisk.c @@ -31,12 +31,113 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") -#include "resource_asterisk.h" +#include "asterisk/ast_version.h" +#include "asterisk/buildinfo.h" +#include "asterisk/paths.h" #include "asterisk/pbx.h" +#include "resource_asterisk.h" -void ast_ari_get_asterisk_info(struct ast_variable *headers, struct ast_get_asterisk_info_args *args, struct ast_ari_response *response) +void ast_ari_get_asterisk_info(struct ast_variable *headers, + struct ast_get_asterisk_info_args *args, + struct ast_ari_response *response) { - ast_log(LOG_ERROR, "TODO: ari_get_asterisk_info\n"); + RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); + int show_all = args->only_count == 0; + int show_build = show_all; + int show_system = show_all; + int show_config = show_all; + int show_status = show_all; + size_t i; + int res = 0; + + for (i = 0; i < args->only_count; ++i) { + if (strcasecmp("build", args->only[i]) == 0) { + show_build = 1; + } else if (strcasecmp("system", args->only[i]) == 0) { + show_system = 1; + } else if (strcasecmp("config", args->only[i]) == 0) { + show_config = 1; + } else if (strcasecmp("status", args->only[i]) == 0) { + show_status = 1; + } else { + ast_log(LOG_WARNING, "Unrecognized info section '%s'\n", + args->only[i]); + } + } + + json = ast_json_object_create(); + + if (show_build) { + res |= ast_json_object_set(json, "build", + ast_json_pack( + "{ s: s, s: s, s: s," + " s: s, s: s, s: s }", + + "os", ast_build_os, + "kernel", ast_build_kernel, + "machine", ast_build_machine, + + "options", AST_BUILDOPTS, + "date", ast_build_date, + "user", ast_build_user)); + } + + if (show_system) { + char eid_str[128]; + + ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default); + + res |= ast_json_object_set(json, "system", + ast_json_pack("{ s: s, s: s }", + "version", ast_get_version(), + "entity_id", eid_str)); + } + + if (show_config) { + struct ast_json *config = ast_json_pack( + "{ s: s, s: s," + " s: { s: s, s: s } }", + + "name", ast_config_AST_SYSTEM_NAME, + "default_language", defaultlanguage, + + "setid", + "user", ast_config_AST_RUN_USER, + "group", ast_config_AST_RUN_GROUP); + + res |= ast_json_object_set(json, "config", config); + + if (option_maxcalls) { + res |= ast_json_object_set(config, "max_channels", + ast_json_integer_create(option_maxcalls)); + } + + if (option_maxfiles) { + res |= ast_json_object_set(config, "max_open_files", + ast_json_integer_create(option_maxfiles)); + } + + if (option_maxload) { + res |= ast_json_object_set(config, "max_load", + ast_json_real_create(option_maxload)); + } + } + + if (show_status) { + res |= ast_json_object_set(json, "status", + ast_json_pack("{ s: o, s: o }", + "startup_time", + ast_json_timeval(ast_startuptime, NULL), + "last_reload_time", + ast_json_timeval(ast_lastreloadtime, NULL))); + } + + if (res != 0) { + ast_ari_response_alloc_failed(response); + return; + } + + ast_ari_response_ok(response, ast_json_ref(json)); } void ast_ari_get_global_var(struct ast_variable *headers, struct ast_get_global_var_args *args, struct ast_ari_response *response) diff --git a/rest-api/api-docs/asterisk.json b/rest-api/api-docs/asterisk.json index 8bc8874857..cbed1895cf 100644 --- a/rest-api/api-docs/asterisk.json +++ b/rest-api/api-docs/asterisk.json @@ -85,10 +85,151 @@ } ], "models": { + "BuildInfo": { + "id": "BuildInfo", + "description": "Info about how Asterisk was built", + "properties": { + "os": { + "required": true, + "type": "string", + "description": "OS Asterisk was built on." + }, + "kernel": { + "required": true, + "type": "string", + "description": "Kernel version Asterisk was built on." + }, + "options": { + "required": true, + "type": "string", + "description": "Compile time options, or empty string if default." + }, + "machine": { + "required": true, + "type": "string", + "description": "Machine architecture (x86_64, i686, ppc, etc.)" + }, + "date": { + "required": true, + "type": "string", + "description": "Date and time when Asterisk was built." + }, + "user": { + "required": true, + "type": "string", + "description": "Username that build Asterisk" + } + } + }, + "SystemInfo": { + "id": "SystemInfo", + "description": "Info about Asterisk", + "properties": { + "version": { + "required": true, + "type": "string", + "description": "Asterisk version." + }, + "entity_id": { + "required": true, + "type": "string", + "description": "" + } + } + }, + "SetId": { + "id": "SetId", + "description": "Effective user/group id", + "properties": { + "user": { + "required": true, + "type": "string", + "description": "Effective user id." + }, + "group": { + "required": true, + "type": "string", + "description": "Effective group id." + } + } + }, + "ConfigInfo": { + "id": "ConfigInfo", + "description": "Info about Asterisk configuration", + "properties": { + "name": { + "required": true, + "type": "string", + "description": "Asterisk system name." + }, + "default_language": { + "required": true, + "type": "string", + "description": "Default language for media playback." + }, + "max_channels": { + "required": false, + "type": "int", + "description": "Maximum number of simultaneous channels." + }, + "max_open_files": { + "required": false, + "type": "int", + "description": "Maximum number of open file handles (files, sockets)." + }, + "max_load": { + "required": false, + "type": "double", + "description": "Maximum load avg on system." + }, + "setid": { + "required": true, + "type": "SetId", + "description": "Effective user/group id for running Asterisk." + } + } + }, + "StatusInfo": { + "id": "StatusInfo", + "description": "Info about Asterisk status", + "properties": { + "startup_time": { + "required": true, + "type": "Date", + "description": "Time when Asterisk was started." + }, + "last_reload_time": { + "required": true, + "type": "Date", + "description": "Time when Asterisk was last reloaded." + } + } + }, "AsteriskInfo": { "id": "AsteriskInfo", "description": "Asterisk system information", - "properties": {} + "properties": { + "build": { + "required": false, + "type": "BuildInfo", + "description": "Info about how Asterisk was built" + }, + "system": { + "required": false, + "type": "SystemInfo", + "description": "Info about the system running Asterisk" + }, + "config": { + "required": false, + "type": "ConfigInfo", + "description": "Info about Asterisk configuration" + }, + "status": { + "required": false, + "type": "StatusInfo", + "description": "Info about Asterisk status" + } + } }, "Variable": { "id": "Variable",