From ca95332d55cf4aa825331f4f7c3e6645797a7415 Mon Sep 17 00:00:00 2001 From: Chris Akritidis <43294513+cakrit@users.noreply.github.com> Date: Thu, 18 Apr 2019 18:17:03 +0300 Subject: Extend netdata info API call (#5889) * Add array of collector plugins-modules to api/v1/info * Add system info to api/v1/info, collect data from separate script, use environment vars in anonymous statistics script --- daemon/Makefile.am | 1 + daemon/anonymous-statistics.sh.in | 180 +++++++++----------------------------- daemon/common.h | 2 + daemon/daemon.h | 1 + daemon/main.c | 42 ++++++++- daemon/system-info.sh | 109 +++++++++++++++++++++++ web/api/formatters/charts2json.c | 41 +++++++++ web/api/formatters/charts2json.h | 11 +++ web/api/web_api_v1.c | 21 ++++- 9 files changed, 268 insertions(+), 140 deletions(-) create mode 100755 daemon/system-info.sh diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 9611f223f7..e020e517b1 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -17,4 +17,5 @@ dist_noinst_DATA = \ dist_plugins_SCRIPTS = \ anonymous-statistics.sh \ + system-info.sh \ $(NULL) diff --git a/daemon/anonymous-statistics.sh.in b/daemon/anonymous-statistics.sh.in index d4622c6d9a..9f548ce969 100755 --- a/daemon/anonymous-statistics.sh.in +++ b/daemon/anonymous-statistics.sh.in @@ -22,117 +22,23 @@ if [ -f "@configdir_POST@/.opt-out-from-anonymous-statistics" ]; then exit 0 fi -# ------------------------------------------------------------------------------------------------- -# detect the operating system - -OS_DETECTION="unknown" -NAME="unknown" -VERSION="unknown" -VERSION_ID="unknown" -ID="unknown" -ID_LIKE="unknown" - -if [ -f "/etc/os-release" ]; then - OS_DETECTION="/etc/os-release" - eval "$(grep -E "^(NAME|ID|ID_LIKE|VERSION|VERSION_ID)=" /dev/null)" ]; then - if [ "${OS_DETECTION}" = "unknown" ]; then OS_DETECTION="lsb_release"; else OS_DETECTION="Mixed"; fi - if [ "${NAME}" = "unknown" ]; then NAME="$(lsb_release -is 2>/dev/null)"; fi - if [ "${VERSION}" = "unknown" ]; then VERSION="$(lsb_release -rs 2>/dev/null)"; fi - if [ "${ID}" = "unknown" ]; then ID="$(lsb_release -cs 2>/dev/null)"; fi - fi -fi - -# ------------------------------------------------------------------------------------------------- -# detect the kernel - -KERNEL_NAME="$(uname -s)" -KERNEL_VERSION="$(uname -r)" -ARCHITECTURE="$(uname -m)" - -# ------------------------------------------------------------------------------------------------- -# detect the virtualization - -VIRTUALIZATION="unknown" -VIRT_DETECTION="none" -CONTAINER="unknown" -CONT_DETECTION="none" - -if [ -n "$(command -v systemd-detect-virt 2>/dev/null)" ]; then - VIRTUALIZATION="$(systemd-detect-virt -v)" - VIRT_DETECTION="systemd-detect-virt" - CONTAINER="$(systemd-detect-virt -c)" - CONT_DETECTION="systemd-detect-virt" -else - if grep -q "^flags.*hypervisor" /proc/cpuinfo 2>/dev/null; then - VIRTUALIZATION="hypervisor" - VIRT_DETECTION="/proc/cpuinfo" - fi -fi - -# ------------------------------------------------------------------------------------------------- -# detect containers with heuristics - -if [ "${CONTAINER}" = "unknown" ]; then - if [ -f /proc/1/sched ] ; then - IFS='(, ' read -r process _ /dev/null 2>&1; then - CONTAINER="container" - CONT_DETECTION="/bin/running-in-container" - fi - - # lxc sets environment variable 'container' - #shellcheck disable=SC2154 - if [ -n "${container}" ]; then - CONTAINER="lxc" - CONT_DETECTION="containerenv" - fi - - # docker creates /.dockerenv - # http://stackoverflow.com/a/25518345 - if [ -f "/.dockerenv" ]; then - CONTAINER="docker" - CONT_DETECTION="dockerenv" - fi -fi - -# ------------------------------------------------------------------------------------------------- -# check netdata version - -if [ -z "${NETDATA_VERSION}" ]; then - NETDATA_VERSION="uknown" - netdata -V >/dev/null 2>&1 && NETDATA_VERSION="$(netdata -V 2>&1 | cut -d ' ' -f 2)" -fi - -# ------------------------------------------------------------------------------------------------- -# check netdata unique id -if [ -z "${NETDATA_REGISTRY_UNIQUE_ID}" ] ; then - if [ -f "@registrydir_POST@/netdata.public.unique.id" ]; then - NETDATA_REGISTRY_UNIQUE_ID="$(cat "@registrydir_POST@/netdata.public.unique.id")" - else - NETDATA_REGISTRY_UNIQUE_ID="unknown" - fi -fi - +echo "&av=${NETDATA_VERSION}\ +&ec=${ACTION}\ +&ea=${ACTION_RESULT}\ +&el=${ACTION_DATA}\ +&cd1=${NETDATA_SYSTEM_OS_NAME}\ +&cd2=${NETDATA_SYSTEM_OS_ID}\ +&cd3=${NETDATA_SYSTEM_OS_ID_LIKE}\ +&cd4=${NETDATA_SYSTEM_OS_VERSION}\ +&cd5=${NETDATA_SYSTEM_OS_VERSION_ID}\ +&cd6=${NETDATA_SYSTEM_OS_DETECTION}\ +&cd7=${NETDATA_SYSTEM_KERNEL_NAME}\ +&cd8=${NETDATA_SYSTEM_KERNEL_VERSION}\ +&cd9=${NETDATA_SYSTEM_ARCHITECTURE}\ +&cd10=${NETDATA_SYSTEM_VIRTUALIZATION}\ +&cd11=${NETDATA_SYSTEM_VIRT_DETECTION}\ +&cd12=${NETDATA_SYSTEM_CONTAINER}\ +&cd13=${NETDATA_SYSTEM_CONTAINER_DETECTION}" >> /tmp/as.log # ------------------------------------------------------------------------------------------------- # send the anonymous statistics to GA @@ -152,19 +58,19 @@ if [ -n "$(command -v curl 2>/dev/null)" ]; then --data-urlencode "ec=${ACTION}" \ --data-urlencode "ea=${ACTION_RESULT}" \ --data-urlencode "el=${ACTION_DATA}" \ - --data-urlencode "cd1=${NAME}" \ - --data-urlencode "cd2=${ID}" \ - --data-urlencode "cd3=${ID_LIKE}" \ - --data-urlencode "cd4=${VERSION}" \ - --data-urlencode "cd5=${VERSION_ID}" \ - --data-urlencode "cd6=${OS_DETECTION}" \ - --data-urlencode "cd7=${KERNEL_NAME}" \ - --data-urlencode "cd8=${KERNEL_VERSION}" \ - --data-urlencode "cd9=${ARCHITECTURE}" \ - --data-urlencode "cd10=${VIRTUALIZATION}" \ - --data-urlencode "cd11=${VIRT_DETECTION}" \ - --data-urlencode "cd12=${CONTAINER}" \ - --data-urlencode "cd13=${CONT_DETECTION}" \ + --data-urlencode "cd1=${NETDATA_SYSTEM_OS_NAME}" \ + --data-urlencode "cd2=${NETDATA_SYSTEM_OS_ID}" \ + --data-urlencode "cd3=${NETDATA_SYSTEM_OS_ID_LIKE}" \ + --data-urlencode "cd4=${NETDATA_SYSTEM_OS_VERSION}" \ + --data-urlencode "cd5=${NETDATA_SYSTEM_OS_DETECTION}" \ + --data-urlencode "cd6=${NETDATA_SYSTEM_OS_DETECTION}" \ + --data-urlencode "cd7=${NETDATA_SYSTEM_KERNEL_NAME}" \ + --data-urlencode "cd8=${NETDATA_SYSTEM_KERNEL_VERSION}" \ + --data-urlencode "cd9=${NETDATA_SYSTEM_ARCHITECTURE}" \ + --data-urlencode "cd10=${NETDATA_SYSTEM_VIRTUALIZATION}" \ + --data-urlencode "cd11=${NETDATA_SYSTEM_VIRT_DETECTION}" \ + --data-urlencode "cd12=${NETDATA_SYSTEM_CONTAINER}" \ + --data-urlencode "cd13=${NETDATA_SYSTEM_CONTAINER_DETECTION}" \ "https://www.google-analytics.com/collect" >/dev/null 2>&1 else wget -q -O - --timeout=1 "https://www.google-analytics.com/collect?\ @@ -181,18 +87,18 @@ else &ec=${ACTION}\ &ea=${ACTION_RESULT}\ &el=${ACTION_DATA}\ -&cd1=${NAME}\ -&cd2=${ID}\ -&cd3=${ID_LIKE}\ -&cd4=${VERSION}\ -&cd5=${VERSION_ID}\ -&cd6=${OS_DETECTION}\ -&cd7=${KERNEL_NAME}\ -&cd8=${KERNEL_VERSION}\ -&cd9=${ARCHITECTURE}\ -&cd10=${VIRTUALIZATION}\ -&cd11=${VIRT_DETECTION}\ -&cd12=${CONTAINER}\ -&cd13=${CONT_DETECTION}\ +&cd1=${NETDATA_SYSTEM_OS_NAME}\ +&cd2=${NETDATA_SYSTEM_OS_ID}\ +&cd3=${NETDATA_SYSTEM_OS_ID_LIKE}\ +&cd4=${NETDATA_SYSTEM_OS_VERSION}\ +&cd5=${NETDATA_SYSTEM_OS_VERSION_ID}\ +&cd6=${NETDATA_SYSTEM_OS_DETECTION}\ +&cd7=${NETDATA_SYSTEM_KERNEL_NAME}\ +&cd8=${NETDATA_SYSTEM_KERNEL_VERSION}\ +&cd9=${NETDATA_SYSTEM_ARCHITECTURE}\ +&cd10=${NETDATA_SYSTEM_VIRTUALIZATION}\ +&cd11=${NETDATA_SYSTEM_VIRT_DETECTION}\ +&cd12=${NETDATA_SYSTEM_CONTAINER}\ +&cd13=${NETDATA_SYSTEM_CONTAINER_DETECTION}\ " > /dev/null 2>&1 fi diff --git a/daemon/common.h b/daemon/common.h index d688d28286..9a55fa3af8 100644 --- a/daemon/common.h +++ b/daemon/common.h @@ -79,4 +79,6 @@ extern char *netdata_configured_host_prefix; extern char *netdata_configured_timezone; extern int netdata_anonymous_statistics_enabled; +int netdata_ready; + #endif /* NETDATA_COMMON_H */ diff --git a/daemon/daemon.h b/daemon/daemon.h index b65d2daa17..5d176341a9 100644 --- a/daemon/daemon.h +++ b/daemon/daemon.h @@ -12,4 +12,5 @@ extern void send_statistics(const char *action, const char *action_result, const extern char pidfile[]; + #endif /* NETDATA_DAEMON_H */ diff --git a/daemon/main.c b/daemon/main.c index ba8d4b4ef6..231ba45f48 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -650,6 +650,43 @@ static int load_netdata_conf(char *filename, char overwrite_used) { return ret; } +int get_system_info () { + char *script; + script = mallocz(sizeof(char) * (strlen(netdata_configured_primary_plugins_dir) + strlen("system-info.sh") + 2)); + sprintf(script, "%s/%s", netdata_configured_primary_plugins_dir, "system-info.sh"); + if (unlikely(access(script, R_OK) != 0)) { + info("System info script %s not found.",script); + freez(script); + return 1; + } + + pid_t command_pid; + + info("Executing %s", script); + + FILE *fp = mypopen(script, &command_pid); + if(fp) { + char buffer[200 + 1]; + while (fgets(buffer, 200, fp) != NULL) { + char *name=buffer; + char *value=buffer; + while (*value && *value != '=') value++; + if (*value=='=') { + *value='\0'; + value++; + char *newline = value + strlen(value) - 1; + (*newline)='\0'; + } + if (name && value && *name && *value) { + info("%s=%s", name, value); + setenv(name, value, 1); + } + } + mypclose(fp, command_pid); + } + freez(script); + return 0; +} void send_statistics( const char *action, const char *action_result, const char *action_data) { static char *as_script; @@ -697,6 +734,7 @@ int main(int argc, char **argv) { int dont_fork = 0; size_t default_stacksize; + netdata_ready=0; // set the name for logging program_name = "netdata"; @@ -1053,7 +1091,7 @@ int main(int argc, char **argv) { // initialize the log files open_all_log_files(); netdata_anonymous_statistics_enabled=-1; - send_statistics("START","-", "-"); + if (get_system_info() == 0) send_statistics("START","-", "-"); #ifdef NETDATA_INTERNAL_CHECKS if(debug_flags != 0) { @@ -1113,7 +1151,7 @@ int main(int argc, char **argv) { } info("netdata initialization completed. Enjoy real-time performance monitoring!"); - + netdata_ready = 1; // ------------------------------------------------------------------------ // unblock signals diff --git a/daemon/system-info.sh b/daemon/system-info.sh new file mode 100755 index 0000000000..e92971efd3 --- /dev/null +++ b/daemon/system-info.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env sh + +# ------------------------------------------------------------------------------------------------- +# detect the operating system + +OS_DETECTION="unknown" +NAME="unknown" +VERSION="unknown" +VERSION_ID="unknown" +ID="unknown" +ID_LIKE="unknown" + +if [ -f "/etc/os-release" ]; then + OS_DETECTION="/etc/os-release" + eval "$(grep -E "^(NAME|ID|ID_LIKE|VERSION|VERSION_ID)=" /dev/null)" ]; then + if [ "${OS_DETECTION}" = "unknown" ]; then OS_DETECTION="lsb_release"; else OS_DETECTION="Mixed"; fi + if [ "${NAME}" = "unknown" ]; then NAME="$(lsb_release -is 2>/dev/null)"; fi + if [ "${VERSION}" = "unknown" ]; then VERSION="$(lsb_release -rs 2>/dev/null)"; fi + if [ "${ID}" = "unknown" ]; then ID="$(lsb_release -cs 2>/dev/null)"; fi + fi +fi + +# ------------------------------------------------------------------------------------------------- +# detect the kernel + +KERNEL_NAME="$(uname -s)" +KERNEL_VERSION="$(uname -r)" +ARCHITECTURE="$(uname -m)" + +# ------------------------------------------------------------------------------------------------- +# detect the virtualization + +VIRTUALIZATION="unknown" +VIRT_DETECTION="none" +CONTAINER="unknown" +CONT_DETECTION="none" + +if [ -n "$(command -v systemd-detect-virt 2>/dev/null)" ]; then + VIRTUALIZATION="$(systemd-detect-virt -v)" + VIRT_DETECTION="systemd-detect-virt" + CONTAINER="$(systemd-detect-virt -c)" + CONT_DETECTION="systemd-detect-virt" +else + if grep -q "^flags.*hypervisor" /proc/cpuinfo 2>/dev/null; then + VIRTUALIZATION="hypervisor" + VIRT_DETECTION="/proc/cpuinfo" + fi +fi + +# ------------------------------------------------------------------------------------------------- +# detect containers with heuristics + +if [ "${CONTAINER}" = "unknown" ]; then + if [ -f /proc/1/sched ] ; then + IFS='(, ' read -r process _ /dev/null 2>&1; then + CONTAINER="container" + CONT_DETECTION="/bin/running-in-container" + fi + + # lxc sets environment variable 'container' + #shellcheck disable=SC2154 + if [ -n "${container}" ]; then + CONTAINER="lxc" + CONT_DETECTION="containerenv" + fi + + # docker creates /.dockerenv + # http://stackoverflow.com/a/25518345 + if [ -f "/.dockerenv" ]; then + CONTAINER="docker" + CONT_DETECTION="dockerenv" + fi +fi + +echo "NETDATA_SYSTEM_OS_NAME=\"${NAME}\"" +echo "NETDATA_SYSTEM_OS_ID=${ID}" +echo "NETDATA_SYSTEM_OS_ID_LIKE=${ID_LIKE}" +echo "NETDATA_SYSTEM_OS_VERSION=${VERSION}" +echo "NETDATA_SYSTEM_OS_VERSION_ID=${VERSION_ID}" +echo "NETDATA_SYSTEM_OS_DETECTION=${OS_DETECTION}" +echo "NETDATA_SYSTEM_KERNEL_NAME=${KERNEL_NAME}" +echo "NETDATA_SYSTEM_KERNEL_VERSION=${KERNEL_VERSION}" +echo "NETDATA_SYSTEM_ARCHITECTURE=${ARCHITECTURE}" +echo "NETDATA_SYSTEM_VIRTUALIZATION=${VIRTUALIZATION}" +echo "NETDATA_SYSTEM_VIRT_DETECTION=${VIRT_DETECTION}" +echo "NETDATA_SYSTEM_CONTAINER=${CONTAINER}" +echo "NETDATA_SYSTEM_CONTAINER_DETECTION=${CONT_DETECTION}" + diff --git a/web/api/formatters/charts2json.c b/web/api/formatters/charts2json.c index 413f1a6d1f..e3dbd40dc3 100644 --- a/web/api/formatters/charts2json.c +++ b/web/api/formatters/charts2json.c @@ -135,3 +135,44 @@ void charts2json(RRDHOST *host, BUFFER *wb) { buffer_sprintf(wb, "\n\t]\n}\n"); } + +int print_collector(void *entry, void *data) { + struct array_printer *ap = (struct array_printer *)data; + BUFFER *wb = ap->wb; + struct collector *col=(struct collector *) entry; + if(ap->c) buffer_strcat(wb, ","); + buffer_strcat(wb, "\n\t\t{\n\t\t\t\"plugin\": \""); + buffer_strcat(wb, col->plugin); + buffer_strcat(wb, "\",\n\t\t\t\"module\": \""); + buffer_strcat(wb, col->module); + buffer_strcat(wb, "\"\n\t\t}"); + (ap->c)++; + return 0; +} + +void chartcollectors2json(RRDHOST *host, BUFFER *wb) { + DICTIONARY *dict = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED); + RRDSET *st; + char name[500]; + + time_t now = now_realtime_sec(); + rrdhost_rdlock(host); + rrdset_foreach_read(st, host) { + if (rrdset_is_available_for_viewers(st)) { + struct collector col = { + .plugin = st->plugin_name ? st->plugin_name : "", + .module = st->module_name ? st->module_name : "" + }; + sprintf(name, "%s:%s", col.plugin, col.module); + dictionary_set(dict, name, &col, sizeof(struct collector)); + st->last_accessed_time = now; + } + } + rrdhost_unlock(host); + struct array_printer ap = { + .c = 0, + .wb = wb + }; + dictionary_get_all(dict, print_collector, &ap); + dictionary_destroy(dict); +} diff --git a/web/api/formatters/charts2json.h b/web/api/formatters/charts2json.h index 5d6d800604..348e736895 100644 --- a/web/api/formatters/charts2json.h +++ b/web/api/formatters/charts2json.h @@ -5,6 +5,17 @@ #include "rrd2json.h" +struct collector { + char *plugin; + char *module; +}; + +struct array_printer { + int c; + BUFFER *wb; +}; + extern void charts2json(RRDHOST *host, BUFFER *wb); +extern void chartcollectors2json(RRDHOST *host, BUFFER *wb); #endif //NETDATA_API_FORMATTER_CHARTS2JSON_H diff --git a/web/api/web_api_v1.c b/web/api/web_api_v1.c index 991a9ec8b3..528794c307 100644 --- a/web/api/web_api_v1.c +++ b/web/api/web_api_v1.c @@ -717,6 +717,7 @@ static inline void web_client_api_request_v1_info_mirrored_hosts(BUFFER *wb) { inline int web_client_api_request_v1_info(RRDHOST *host, struct web_client *w, char *url) { (void)url; + if (!netdata_ready) return 400; BUFFER *wb = w->response.data; buffer_flush(wb); @@ -732,7 +733,25 @@ inline int web_client_api_request_v1_info(RRDHOST *host, struct web_client *w, c buffer_strcat(wb, "\t\"alarms\": {\n"); web_client_api_request_v1_info_summary_alarm_statuses(host, wb); - buffer_strcat(wb, "\t}\n"); + buffer_strcat(wb, "\t},\n"); + + buffer_sprintf(wb, "\t\"os_name\": %s,\n", getenv("NETDATA_SYSTEM_OS_NAME")); + buffer_sprintf(wb, "\t\"os_id\": \"%s\",\n", getenv("NETDATA_SYSTEM_OS_ID")); + buffer_sprintf(wb, "\t\"os_id_like\": \"%s\",\n", getenv("NETDATA_SYSTEM_OS_ID_LIKE")); + buffer_sprintf(wb, "\t\"os_version\": \"%s\",\n", getenv("NETDATA_SYSTEM_OS_VERSION")); + buffer_sprintf(wb, "\t\"os_version_id\": \"%s\",\n", getenv("NETDATA_SYSTEM_OS_VERSION_ID")); + buffer_sprintf(wb, "\t\"os_detection\": \"%s\",\n", getenv("NETDATA_SYSTEM_OS_DETECTION")); + buffer_sprintf(wb, "\t\"kernel_name\": \"%s\",\n", getenv("NETDATA_SYSTEM_KERNEL_NAME")); + buffer_sprintf(wb, "\t\"kernel_version\": \"%s\",\n", getenv("NETDATA_SYSTEM_KERNEL_VERSION")); + buffer_sprintf(wb, "\t\"architecture\": \"%s\",\n", getenv("NETDATA_SYSTEM_ARCHITECTURE")); + buffer_sprintf(wb, "\t\"virtualization\": \"%s\",\n", getenv("NETDATA_SYSTEM_VIRTUALIZATION")); + buffer_sprintf(wb, "\t\"virt_detection\": \"%s\",\n", getenv("NETDATA_SYSTEM_VIRT_DETECTION")); + buffer_sprintf(wb, "\t\"container\": \"%s\",\n", getenv("NETDATA_SYSTEM_CONTAINER")); + buffer_sprintf(wb, "\t\"container_detection\": \"%s\",\n", getenv("NETDATA_SYSTEM_CONTAINER_DETECTION")); + + buffer_strcat(wb, "\t\"collectors\": ["); + chartcollectors2json(host, wb); + buffer_strcat(wb, "\n\t]\n"); buffer_strcat(wb, "}"); return 200; -- cgit v1.2.3