health_cmdapi.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. //
  3. // Created by Christopher on 11/12/18.
  4. //
  5. #include "health_cmdapi.h"
  6. /**
  7. * Free Silencers
  8. *
  9. * Clean the silencer structure
  10. *
  11. * @param t is the structure that will be cleaned.
  12. */
  13. void free_silencers(SILENCER *t) {
  14. if (!t) return;
  15. if (t->next) free_silencers(t->next);
  16. netdata_log_debug(D_HEALTH, "HEALTH command API: Freeing silencer %s:%s:%s:%s", t->alarms,
  17. t->charts, t->contexts, t->hosts);
  18. simple_pattern_free(t->alarms_pattern);
  19. simple_pattern_free(t->charts_pattern);
  20. simple_pattern_free(t->contexts_pattern);
  21. simple_pattern_free(t->hosts_pattern);
  22. freez(t->alarms);
  23. freez(t->charts);
  24. freez(t->contexts);
  25. freez(t->hosts);
  26. freez(t);
  27. return;
  28. }
  29. /**
  30. * Silencers to JSON Entry
  31. *
  32. * Fill the buffer with the other values given.
  33. *
  34. * @param wb a pointer to the output buffer
  35. * @param var the json variable
  36. * @param val the json value
  37. * @param hasprev has it a previous value?
  38. *
  39. * @return
  40. */
  41. int health_silencers2json_entry(BUFFER *wb, char* var, char* val, int hasprev) {
  42. if (val) {
  43. buffer_sprintf(wb, "%s\n\t\t\t\"%s\": \"%s\"", (hasprev)?",":"", var, val);
  44. return 1;
  45. } else {
  46. return hasprev;
  47. }
  48. }
  49. /**
  50. * Silencer to JSON
  51. *
  52. * Write the silencer values using JSON format inside a buffer.
  53. *
  54. * @param wb is the buffer to write the silencers.
  55. */
  56. void health_silencers2json(BUFFER *wb) {
  57. buffer_sprintf(wb, "{\n\t\"all\": %s,"
  58. "\n\t\"type\": \"%s\","
  59. "\n\t\"silencers\": [",
  60. (silencers->all_alarms)?"true":"false",
  61. (silencers->stype == STYPE_NONE)?"None":((silencers->stype == STYPE_DISABLE_ALARMS)?"DISABLE":"SILENCE"));
  62. SILENCER *silencer;
  63. int i = 0, j = 0;
  64. for(silencer = silencers->silencers; silencer ; silencer = silencer->next) {
  65. if(likely(i)) buffer_strcat(wb, ",");
  66. buffer_strcat(wb, "\n\t\t{");
  67. j=health_silencers2json_entry(wb, HEALTH_ALARM_KEY, silencer->alarms, j);
  68. j=health_silencers2json_entry(wb, HEALTH_CHART_KEY, silencer->charts, j);
  69. j=health_silencers2json_entry(wb, HEALTH_CONTEXT_KEY, silencer->contexts, j);
  70. j=health_silencers2json_entry(wb, HEALTH_HOST_KEY, silencer->hosts, j);
  71. j=0;
  72. buffer_strcat(wb, "\n\t\t}");
  73. i++;
  74. }
  75. if(likely(i)) buffer_strcat(wb, "\n\t");
  76. buffer_strcat(wb, "]\n}\n");
  77. }
  78. /**
  79. * Silencer to FILE
  80. *
  81. * Write the silencer buffer to a file.
  82. * @param wb
  83. */
  84. void health_silencers2file(BUFFER *wb) {
  85. if (wb->len == 0) return;
  86. FILE *fd = fopen(silencers_filename, "wb");
  87. if(fd) {
  88. size_t written = (size_t)fprintf(fd, "%s", wb->buffer) ;
  89. if (written == wb->len ) {
  90. netdata_log_info("Silencer changes written to %s", silencers_filename);
  91. }
  92. fclose(fd);
  93. return;
  94. }
  95. netdata_log_error("Silencer changes could not be written to %s. Error %s", silencers_filename, strerror(errno));
  96. }
  97. /**
  98. * Request V1 MGMT Health
  99. *
  100. * Function called by api to management the health.
  101. *
  102. * @param host main structure with client information!
  103. * @param w is the structure with all information of the client request.
  104. * @param url is the url that netdata is working
  105. *
  106. * @return It returns 200 on success and another code otherwise.
  107. */
  108. int web_client_api_request_v1_mgmt_health(RRDHOST *host, struct web_client *w, char *url) {
  109. int ret;
  110. (void) host;
  111. BUFFER *wb = w->response.data;
  112. buffer_flush(wb);
  113. wb->content_type = CT_TEXT_PLAIN;
  114. buffer_flush(w->response.data);
  115. //Local instance of the silencer
  116. SILENCER *silencer = NULL;
  117. int config_changed = 1;
  118. if (!w->auth_bearer_token) {
  119. buffer_strcat(wb, HEALTH_CMDAPI_MSG_AUTHERROR);
  120. ret = HTTP_RESP_FORBIDDEN;
  121. } else {
  122. netdata_log_debug(D_HEALTH, "HEALTH command API: Comparing secret '%s' to '%s'", w->auth_bearer_token, api_secret);
  123. if (strcmp(w->auth_bearer_token, api_secret)) {
  124. buffer_strcat(wb, HEALTH_CMDAPI_MSG_AUTHERROR);
  125. ret = HTTP_RESP_FORBIDDEN;
  126. } else {
  127. while (url) {
  128. char *value = strsep_skip_consecutive_separators(&url, "&");
  129. if (!value || !*value) continue;
  130. char *key = strsep_skip_consecutive_separators(&value, "=");
  131. if (!key || !*key) continue;
  132. if (!value || !*value) continue;
  133. netdata_log_debug(D_WEB_CLIENT, "%llu: API v1 health query param '%s' with value '%s'", w->id, key, value);
  134. // name and value are now the parameters
  135. if (!strcmp(key, "cmd")) {
  136. if (!strcmp(value, HEALTH_CMDAPI_CMD_SILENCEALL)) {
  137. silencers->all_alarms = 1;
  138. silencers->stype = STYPE_SILENCE_NOTIFICATIONS;
  139. buffer_strcat(wb, HEALTH_CMDAPI_MSG_SILENCEALL);
  140. } else if (!strcmp(value, HEALTH_CMDAPI_CMD_DISABLEALL)) {
  141. silencers->all_alarms = 1;
  142. silencers->stype = STYPE_DISABLE_ALARMS;
  143. buffer_strcat(wb, HEALTH_CMDAPI_MSG_DISABLEALL);
  144. } else if (!strcmp(value, HEALTH_CMDAPI_CMD_SILENCE)) {
  145. silencers->stype = STYPE_SILENCE_NOTIFICATIONS;
  146. buffer_strcat(wb, HEALTH_CMDAPI_MSG_SILENCE);
  147. } else if (!strcmp(value, HEALTH_CMDAPI_CMD_DISABLE)) {
  148. silencers->stype = STYPE_DISABLE_ALARMS;
  149. buffer_strcat(wb, HEALTH_CMDAPI_MSG_DISABLE);
  150. } else if (!strcmp(value, HEALTH_CMDAPI_CMD_RESET)) {
  151. silencers->all_alarms = 0;
  152. silencers->stype = STYPE_NONE;
  153. free_silencers(silencers->silencers);
  154. silencers->silencers = NULL;
  155. buffer_strcat(wb, HEALTH_CMDAPI_MSG_RESET);
  156. } else if (!strcmp(value, HEALTH_CMDAPI_CMD_LIST)) {
  157. w->response.data->content_type = CT_APPLICATION_JSON;
  158. health_silencers2json(wb);
  159. config_changed=0;
  160. }
  161. } else {
  162. silencer = health_silencers_addparam(silencer, key, value);
  163. }
  164. }
  165. if (likely(silencer)) {
  166. health_silencers_add(silencer);
  167. buffer_strcat(wb, HEALTH_CMDAPI_MSG_ADDED);
  168. if (silencers->stype == STYPE_NONE) {
  169. buffer_strcat(wb, HEALTH_CMDAPI_MSG_STYPEWARNING);
  170. }
  171. }
  172. if (unlikely(silencers->stype != STYPE_NONE && !silencers->all_alarms && !silencers->silencers)) {
  173. buffer_strcat(wb, HEALTH_CMDAPI_MSG_NOSELECTORWARNING);
  174. }
  175. ret = HTTP_RESP_OK;
  176. }
  177. }
  178. w->response.data = wb;
  179. buffer_no_cacheable(w->response.data);
  180. if (ret == HTTP_RESP_OK && config_changed) {
  181. BUFFER *jsonb = buffer_create(200, &netdata_buffers_statistics.buffers_health);
  182. health_silencers2json(jsonb);
  183. health_silencers2file(jsonb);
  184. buffer_free(jsonb);
  185. }
  186. return ret;
  187. }