sqlite_health.c 72 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "sqlite_health.h"
  3. #include "sqlite_functions.h"
  4. #include "sqlite_db_migration.h"
  5. #include "health/health_internals.h"
  6. #define MAX_HEALTH_SQL_SIZE 2048
  7. #define SQLITE3_BIND_STRING_OR_NULL(res, param, key) \
  8. ((key) ? sqlite3_bind_text((res), (param), string2str(key), -1, SQLITE_STATIC) : sqlite3_bind_null((res), (param)))
  9. #define SQLITE3_COLUMN_STRINGDUP_OR_NULL(res, param) \
  10. ({ \
  11. int _param = (param); \
  12. sqlite3_column_type((res), (_param)) != SQLITE_NULL ? \
  13. string_strdupz((char *)sqlite3_column_text((res), (_param))) : \
  14. NULL; \
  15. })
  16. /* Health related SQL queries
  17. Updates an entry in the table
  18. */
  19. #define SQL_UPDATE_HEALTH_LOG \
  20. "UPDATE health_log_detail SET updated_by_id = @updated_by, flags = @flags, exec_run_timestamp = @exec_time, " \
  21. "exec_code = @exec_code WHERE unique_id = @unique_id AND alarm_id = @alarm_id AND transition_id = @transaction"
  22. static void sql_health_alarm_log_update(RRDHOST *host, ALARM_ENTRY *ae)
  23. {
  24. static __thread sqlite3_stmt *res = NULL;
  25. int rc;
  26. REQUIRE_DB(db_meta);
  27. if (!PREPARE_COMPILED_STATEMENT(db_meta, SQL_UPDATE_HEALTH_LOG, &res))
  28. return;
  29. int param = 0;
  30. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64) ae->updated_by_id));
  31. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64) ae->flags));
  32. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64) ae->exec_run_timestamp));
  33. SQLITE_BIND_FAIL(done, sqlite3_bind_int(res, ++param, ae->exec_code));
  34. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64) ae->unique_id));
  35. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64) ae->alarm_id));
  36. SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, &ae->transition_id, sizeof(ae->transition_id), SQLITE_STATIC));
  37. param = 0;
  38. rc = execute_insert(res);
  39. if (unlikely(rc != SQLITE_DONE)) {
  40. error_report("HEALTH [%s]: Failed to update health log, rc = %d", rrdhost_hostname(host), rc);
  41. }
  42. done:
  43. REPORT_BIND_FAIL(res, param);
  44. SQLITE_RESET(res);
  45. }
  46. /* Health related SQL queries
  47. *
  48. * Inserts an entry in the tables
  49. * alert_queue
  50. * health_log
  51. * health_log_detail
  52. *
  53. */
  54. int calculate_delay(RRDCALC_STATUS old_status, RRDCALC_STATUS new_status)
  55. {
  56. int delay = ALERT_TRANSITION_DELAY_NONE;
  57. switch(old_status) {
  58. case RRDCALC_STATUS_REMOVED:
  59. switch (new_status) {
  60. case RRDCALC_STATUS_UNINITIALIZED:
  61. delay = ALERT_TRANSITION_DELAY_LONG;
  62. break;
  63. case RRDCALC_STATUS_CLEAR:
  64. delay = ALERT_TRANSITION_DELAY_SHORT;
  65. break;
  66. default:
  67. delay = ALERT_TRANSITION_DELAY_NONE;
  68. break;
  69. }
  70. break;
  71. case RRDCALC_STATUS_UNDEFINED:
  72. case RRDCALC_STATUS_UNINITIALIZED:
  73. switch (new_status) {
  74. case RRDCALC_STATUS_REMOVED:
  75. case RRDCALC_STATUS_UNINITIALIZED:
  76. case RRDCALC_STATUS_UNDEFINED:
  77. delay = ALERT_TRANSITION_DELAY_LONG;
  78. break;
  79. case RRDCALC_STATUS_CLEAR:
  80. delay = ALERT_TRANSITION_DELAY_SHORT;
  81. break;
  82. default:
  83. delay = ALERT_TRANSITION_DELAY_NONE;
  84. break;
  85. }
  86. break;
  87. case RRDCALC_STATUS_CLEAR:
  88. switch (new_status) {
  89. case RRDCALC_STATUS_REMOVED:
  90. case RRDCALC_STATUS_UNINITIALIZED:
  91. case RRDCALC_STATUS_UNDEFINED:
  92. delay = ALERT_TRANSITION_DELAY_LONG;
  93. break;
  94. case RRDCALC_STATUS_WARNING:
  95. case RRDCALC_STATUS_CRITICAL:
  96. default:
  97. delay = ALERT_TRANSITION_DELAY_NONE;
  98. break;
  99. }
  100. break;
  101. case RRDCALC_STATUS_WARNING:
  102. case RRDCALC_STATUS_CRITICAL:
  103. switch (new_status) {
  104. case RRDCALC_STATUS_REMOVED:
  105. case RRDCALC_STATUS_UNINITIALIZED:
  106. case RRDCALC_STATUS_UNDEFINED:
  107. delay = ALERT_TRANSITION_DELAY_LONG;
  108. break;
  109. case RRDCALC_STATUS_CLEAR:
  110. delay = ALERT_TRANSITION_DELAY_SHORT;
  111. break;
  112. default:
  113. delay = ALERT_TRANSITION_DELAY_NONE;
  114. break;
  115. }
  116. break;
  117. default:
  118. delay = ALERT_TRANSITION_DELAY_NONE;
  119. break;
  120. }
  121. return delay;
  122. }
  123. #define SQL_INSERT_ALERT_PENDING_QUEUE \
  124. "INSERT INTO alert_queue (host_id, health_log_id, unique_id, alarm_id, status, date_scheduled)" \
  125. " VALUES (@host_id, @health_log_id, @unique_id, @alarm_id, @new_status, UNIXEPOCH() + @delay)" \
  126. " ON CONFLICT (host_id, health_log_id, alarm_id)" \
  127. " DO UPDATE SET status = excluded.status, unique_id = excluded.unique_id, " \
  128. " date_scheduled = MIN(date_scheduled, excluded.date_scheduled)"
  129. static void insert_alert_queue(
  130. RRDHOST *host,
  131. uint64_t health_log_id,
  132. int64_t unique_id,
  133. uint32_t alarm_id,
  134. RRDCALC_STATUS old_status,
  135. RRDCALC_STATUS new_status)
  136. {
  137. static __thread sqlite3_stmt *res = NULL;
  138. int rc;
  139. if (!host->aclk_config)
  140. return;
  141. if (!PREPARE_COMPILED_STATEMENT(db_meta, SQL_INSERT_ALERT_PENDING_QUEUE, &res))
  142. return;
  143. int submit_delay = calculate_delay(old_status, new_status);
  144. int param = 0;
  145. SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, &host->host_id.uuid, sizeof(host->host_id.uuid), SQLITE_STATIC));
  146. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64)health_log_id));
  147. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, unique_id));
  148. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, alarm_id));
  149. SQLITE_BIND_FAIL(done, sqlite3_bind_int(res, ++param, new_status));
  150. SQLITE_BIND_FAIL(done, sqlite3_bind_int(res, ++param, submit_delay));
  151. param = 0;
  152. rc = execute_insert(res);
  153. if (rc != SQLITE_DONE)
  154. error_report(
  155. "HEALTH [%s]: Failed to execute insert_alert_queue, rc = %d", rrdhost_hostname(host), rc);
  156. done:
  157. REPORT_BIND_FAIL(res, param);
  158. SQLITE_RESET(res);
  159. }
  160. #define SQL_INSERT_HEALTH_LOG_DETAIL \
  161. "INSERT INTO health_log_detail (health_log_id, unique_id, alarm_id, alarm_event_id, " \
  162. "updated_by_id, updates_id, when_key, duration, non_clear_duration, flags, exec_run_timestamp, delay_up_to_timestamp, " \
  163. "info, exec_code, new_status, old_status, delay, new_value, old_value, last_repeat, transition_id, global_id, summary) " \
  164. " VALUES (@health_log_id,@unique_id,@alarm_id,@alarm_event_id,@updated_by_id,@updates_id,@when_key,@duration," \
  165. "@non_clear_duration,@flags,@exec_run_timestamp,@delay_up_to_timestamp, @info,@exec_code,@new_status,@old_status," \
  166. "@delay,@new_value,@old_value,@last_repeat,@transition_id,@global_id,@summary)"
  167. static void sql_health_alarm_log_insert_detail(RRDHOST *host, uint64_t health_log_id, ALARM_ENTRY *ae)
  168. {
  169. static __thread sqlite3_stmt *res = NULL;
  170. int rc;
  171. if (!PREPARE_COMPILED_STATEMENT(db_meta, SQL_INSERT_HEALTH_LOG_DETAIL, &res))
  172. return;
  173. int param = 0;
  174. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64)health_log_id));
  175. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64)ae->unique_id));
  176. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64)ae->alarm_id));
  177. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64)ae->alarm_event_id));
  178. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64)ae->updated_by_id));
  179. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64)ae->updates_id));
  180. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64)ae->when));
  181. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64)ae->duration));
  182. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64)ae->non_clear_duration));
  183. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64)ae->flags));
  184. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64)ae->exec_run_timestamp));
  185. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64)ae->delay_up_to_timestamp));
  186. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ae->info));
  187. SQLITE_BIND_FAIL(done, sqlite3_bind_int(res, ++param, ae->exec_code));
  188. SQLITE_BIND_FAIL(done, sqlite3_bind_int(res, ++param, ae->new_status));
  189. SQLITE_BIND_FAIL(done, sqlite3_bind_int(res, ++param, ae->old_status));
  190. SQLITE_BIND_FAIL(done, sqlite3_bind_int(res, ++param, ae->delay));
  191. SQLITE_BIND_FAIL(done, sqlite3_bind_double(res, ++param, ae->new_value));
  192. SQLITE_BIND_FAIL(done, sqlite3_bind_double(res, ++param, ae->old_value));
  193. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64)ae->last_repeat));
  194. SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, &ae->transition_id, sizeof(ae->transition_id), SQLITE_STATIC));
  195. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64)ae->global_id));
  196. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ae->summary));
  197. param = 0;
  198. rc = execute_insert(res);
  199. if (rc == SQLITE_DONE)
  200. ae->flags |= HEALTH_ENTRY_FLAG_SAVED;
  201. else
  202. error_report(
  203. "HEALTH [%s]: Failed to execute SQL_INSERT_HEALTH_LOG_DETAIL, rc = %d", rrdhost_hostname(host), rc);
  204. done:
  205. REPORT_BIND_FAIL(res, param);
  206. SQLITE_RESET(res);
  207. }
  208. #define SQL_INSERT_HEALTH_LOG \
  209. "INSERT INTO health_log (host_id, alarm_id, " \
  210. "config_hash_id, name, chart, exec, recipient, units, chart_context, last_transition_id, chart_name) " \
  211. "VALUES (@host_id,@alarm_id, @config_hash_id,@name,@chart,@exec,@recipient,@units,@chart_context," \
  212. "@last_transition_id,@chart_name) ON CONFLICT (host_id, alarm_id) DO UPDATE " \
  213. "SET last_transition_id = excluded.last_transition_id, chart_name = excluded.chart_name, " \
  214. "config_hash_id=excluded.config_hash_id RETURNING health_log_id"
  215. static void sql_health_alarm_log_insert(RRDHOST *host, ALARM_ENTRY *ae)
  216. {
  217. static __thread sqlite3_stmt *res = NULL;
  218. int rc;
  219. uint64_t health_log_id;
  220. REQUIRE_DB(db_meta);
  221. if (!PREPARE_COMPILED_STATEMENT(db_meta, SQL_INSERT_HEALTH_LOG, &res))
  222. return;
  223. int param = 0;
  224. SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, &host->host_id.uuid, sizeof(host->host_id.uuid), SQLITE_STATIC));
  225. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64) ae->alarm_id));
  226. SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, &ae->config_hash_id, sizeof(ae->config_hash_id), SQLITE_STATIC));
  227. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ae->name));
  228. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ae->chart));
  229. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ae->exec));
  230. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ae->recipient));
  231. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ae->units));
  232. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ae->chart_context));
  233. SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, &ae->transition_id, sizeof(ae->transition_id), SQLITE_STATIC));
  234. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ae->chart_name));
  235. param = 0;
  236. rc = sqlite3_step_monitored(res);
  237. if (rc == SQLITE_ROW) {
  238. health_log_id = (size_t)sqlite3_column_int64(res, 0);
  239. sql_health_alarm_log_insert_detail(host, health_log_id, ae);
  240. insert_alert_queue(
  241. host, health_log_id, (int64_t)ae->unique_id, (int64_t)ae->alarm_id, ae->old_status, ae->new_status);
  242. } else
  243. error_report("HEALTH [%s]: Failed to execute SQL_INSERT_HEALTH_LOG, rc = %d", rrdhost_hostname(host), rc);
  244. done:
  245. REPORT_BIND_FAIL(res, param);
  246. SQLITE_RESET(res);
  247. }
  248. void sql_health_alarm_log_save(RRDHOST *host, ALARM_ENTRY *ae)
  249. {
  250. if (ae->flags & HEALTH_ENTRY_FLAG_SAVED)
  251. sql_health_alarm_log_update(host, ae);
  252. else
  253. sql_health_alarm_log_insert(host, ae);
  254. }
  255. /*
  256. *
  257. * Health related SQL queries
  258. * Cleans up the health_log_detail table on a non-claimed or claimed host
  259. *
  260. */
  261. #define SQL_CLEANUP_HEALTH_LOG_DETAIL \
  262. "DELETE FROM health_log_detail WHERE health_log_id IN " \
  263. " (SELECT health_log_id FROM health_log WHERE host_id = @host_id) AND when_key < UNIXEPOCH() - @history " \
  264. " AND updated_by_id <> 0 AND transition_id NOT IN " \
  265. " (SELECT last_transition_id FROM health_log hl WHERE hl.host_id = @host_id)"
  266. void sql_health_alarm_log_cleanup(RRDHOST *host)
  267. {
  268. sqlite3_stmt *res = NULL;
  269. int rc;
  270. if (!PREPARE_STATEMENT(db_meta, SQL_CLEANUP_HEALTH_LOG_DETAIL, &res))
  271. return;
  272. int param = 0;
  273. SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, &host->host_id.uuid, sizeof(host->host_id.uuid), SQLITE_STATIC));
  274. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64)host->health_log.health_log_retention_s));
  275. param = 0;
  276. rc = sqlite3_step_monitored(res);
  277. if (unlikely(rc != SQLITE_DONE))
  278. error_report("Failed to cleanup health log detail table, rc = %d", rc);
  279. done:
  280. REPORT_BIND_FAIL(res, param);
  281. SQLITE_FINALIZE(res);
  282. }
  283. #define SQL_UPDATE_TRANSITION_IN_HEALTH_LOG \
  284. "UPDATE health_log SET last_transition_id = @transition WHERE alarm_id = @alarm_id AND " \
  285. " last_transition_id = @prev_trans AND host_id = @host_id"
  286. bool sql_update_transition_in_health_log(RRDHOST *host, uint32_t alarm_id, nd_uuid_t *transition_id, nd_uuid_t *last_transition)
  287. {
  288. int rc = 0;
  289. sqlite3_stmt *res;
  290. if (!PREPARE_STATEMENT(db_meta, SQL_UPDATE_TRANSITION_IN_HEALTH_LOG, &res))
  291. return false;
  292. int param = 0;
  293. SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, transition_id, sizeof(*transition_id), SQLITE_STATIC));
  294. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64)alarm_id));
  295. SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, last_transition, sizeof(*last_transition), SQLITE_STATIC));
  296. SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, &host->host_id.uuid, sizeof(host->host_id.uuid), SQLITE_STATIC));
  297. param = 0;
  298. rc = execute_insert(res);
  299. if (unlikely(rc != SQLITE_DONE))
  300. error_report("HEALTH [N/A]: Failed to execute SQL_INJECT_REMOVED_UPDATE_DETAIL, rc = %d", rc);
  301. done:
  302. REPORT_BIND_FAIL(res, param);
  303. SQLITE_FINALIZE(res);
  304. return (param == 0 && rc == SQLITE_DONE);
  305. }
  306. #define SQL_SET_UPDATED_BY_IN_HEALTH_LOG_DETAIL \
  307. "UPDATE health_log_detail SET flags = flags | @flag, updated_by_id = @updated_by WHERE" \
  308. " unique_id = @unique_id AND transition_id = @transition_id"
  309. bool sql_set_updated_by_in_health_log_detail(uint32_t unique_id, uint32_t max_unique_id, nd_uuid_t *prev_transition_id)
  310. {
  311. int rc = 0;
  312. sqlite3_stmt *res;
  313. if (!PREPARE_STATEMENT(db_meta, SQL_SET_UPDATED_BY_IN_HEALTH_LOG_DETAIL, &res))
  314. return false;
  315. int param = 0;
  316. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64) HEALTH_ENTRY_FLAG_UPDATED));
  317. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64) max_unique_id));
  318. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64) unique_id));
  319. SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, prev_transition_id, sizeof(*prev_transition_id), SQLITE_STATIC));
  320. param = 0;
  321. rc = execute_insert(res);
  322. if (unlikely(rc != SQLITE_DONE))
  323. error_report("HEALTH [N/A]: Failed to execute SQL_INJECT_REMOVED_UPDATE_DETAIL, rc = %d", rc);
  324. done:
  325. REPORT_BIND_FAIL(res, param);
  326. SQLITE_FINALIZE(res);
  327. return (param == 0 && rc == SQLITE_DONE);
  328. }
  329. #define SQL_INJECT_REMOVED \
  330. "INSERT INTO health_log_detail (health_log_id, unique_id, alarm_id, alarm_event_id, updated_by_id, updates_id, when_key, " \
  331. "duration, non_clear_duration, flags, exec_run_timestamp, delay_up_to_timestamp, info, exec_code, new_status, old_status, " \
  332. "delay, new_value, old_value, last_repeat, transition_id, global_id, summary) " \
  333. "SELECT health_log_id, @max_unique_id, @alarm_id, @alarm_event_id, 0, @unique_id, UNIXEPOCH(), 0, 0, flags, " \
  334. " exec_run_timestamp, UNIXEPOCH(), info, exec_code, -2, " \
  335. " new_status, delay, NULL, new_value, 0, @transition_id, NOW_USEC(0), summary FROM health_log_detail " \
  336. " WHERE unique_id = @unique_id AND transition_id = @last_transition_id RETURNING health_log_id, old_status"
  337. static void sql_inject_removed_status(
  338. RRDHOST *host,
  339. uint32_t alarm_id,
  340. uint32_t alarm_event_id,
  341. uint32_t unique_id,
  342. uint32_t max_unique_id,
  343. nd_uuid_t *last_transition)
  344. {
  345. if (!alarm_id || !alarm_event_id || !unique_id || !max_unique_id)
  346. return;
  347. sqlite3_stmt *res = NULL;
  348. if (!PREPARE_STATEMENT(db_meta, SQL_INJECT_REMOVED, &res))
  349. return;
  350. nd_uuid_t transition_id;
  351. uuid_generate_random(transition_id);
  352. int param = 0;
  353. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64) max_unique_id));
  354. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64) alarm_id));
  355. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64) alarm_event_id + 1));
  356. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64) unique_id));
  357. SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, &transition_id, sizeof(transition_id), SQLITE_STATIC));
  358. SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, last_transition, sizeof(*last_transition), SQLITE_STATIC));
  359. param = 0;
  360. //int rc = execute_insert(res);
  361. while (sqlite3_step_monitored(res) == SQLITE_ROW) {
  362. //update the old entry in health_log_detail
  363. sql_set_updated_by_in_health_log_detail(unique_id, max_unique_id, last_transition);
  364. //update the old entry in health_log
  365. sql_update_transition_in_health_log(host, alarm_id, &transition_id, last_transition);
  366. int64_t health_log_id = sqlite3_column_int64(res, 0);
  367. RRDCALC_STATUS old_status = (RRDCALC_STATUS)sqlite3_column_double(res, 1);
  368. insert_alert_queue(
  369. host, health_log_id, (int64_t)max_unique_id, (int64_t)alarm_id, old_status, RRDCALC_STATUS_REMOVED);
  370. }
  371. done:
  372. REPORT_BIND_FAIL(res, param);
  373. SQLITE_FINALIZE(res);
  374. }
  375. #define SQL_SELECT_MAX_UNIQUE_ID \
  376. "SELECT MAX(hld.unique_id) FROM health_log_detail hld, health_log hl " \
  377. "WHERE hl.host_id = @host_id AND hl.health_log_id = hld.health_log_id"
  378. uint32_t sql_get_max_unique_id (RRDHOST *host)
  379. {
  380. uint32_t max_unique_id = 0;
  381. sqlite3_stmt *res = NULL;
  382. if (!PREPARE_STATEMENT(db_meta, SQL_SELECT_MAX_UNIQUE_ID, &res))
  383. return 0;
  384. int param = 0;
  385. SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, &host->host_id.uuid, sizeof(host->host_id.uuid), SQLITE_STATIC));
  386. param = 0;
  387. while (sqlite3_step_monitored(res) == SQLITE_ROW)
  388. max_unique_id = (uint32_t)sqlite3_column_int64(res, 0);
  389. done:
  390. REPORT_BIND_FAIL(res, param);
  391. SQLITE_FINALIZE(res);
  392. return max_unique_id;
  393. }
  394. #define SQL_SELECT_LAST_STATUSES \
  395. "SELECT hld.new_status, hld.unique_id, hld.alarm_id, hld.alarm_event_id, hld.transition_id FROM health_log hl, " \
  396. "health_log_detail hld WHERE hl.host_id = @host_id AND hl.last_transition_id = hld.transition_id"
  397. void sql_check_removed_alerts_state(RRDHOST *host)
  398. {
  399. uint32_t max_unique_id = 0;
  400. sqlite3_stmt *res = NULL;
  401. nd_uuid_t transition_id;
  402. if (!PREPARE_STATEMENT(db_meta, SQL_SELECT_LAST_STATUSES, &res))
  403. return;
  404. int param = 0;
  405. SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, &host->host_id.uuid, sizeof(host->host_id.uuid), SQLITE_STATIC));
  406. param = 0;
  407. while (sqlite3_step_monitored(res) == SQLITE_ROW) {
  408. uint32_t alarm_id, alarm_event_id, unique_id;
  409. RRDCALC_STATUS status;
  410. status = (RRDCALC_STATUS)sqlite3_column_int(res, 0);
  411. unique_id = (uint32_t)sqlite3_column_int64(res, 1);
  412. alarm_id = (uint32_t)sqlite3_column_int64(res, 2);
  413. alarm_event_id = (uint32_t)sqlite3_column_int64(res, 3);
  414. uuid_copy(transition_id, *((nd_uuid_t *)sqlite3_column_blob(res, 4)));
  415. if (unlikely(status != RRDCALC_STATUS_REMOVED)) {
  416. if (unlikely(!max_unique_id))
  417. max_unique_id = sql_get_max_unique_id(host);
  418. sql_inject_removed_status(host, alarm_id, alarm_event_id, unique_id, ++max_unique_id, &transition_id);
  419. }
  420. }
  421. done:
  422. REPORT_BIND_FAIL(res, param);
  423. SQLITE_FINALIZE(res);
  424. }
  425. #define SQL_DELETE_MISSING_CHART_ALERT \
  426. "DELETE FROM health_log WHERE host_id = @host_id AND chart NOT IN " \
  427. "(SELECT type||'.'||id FROM chart WHERE host_id = @host_id)"
  428. static void sql_remove_alerts_from_deleted_charts(RRDHOST *host, nd_uuid_t *host_uuid)
  429. {
  430. sqlite3_stmt *res = NULL;
  431. int ret;
  432. nd_uuid_t *actual_uuid = host ? &host->host_id.uuid : host_uuid;
  433. if (!actual_uuid)
  434. return;
  435. if (!PREPARE_STATEMENT(db_meta, SQL_DELETE_MISSING_CHART_ALERT, &res))
  436. return;
  437. int param = 0;
  438. SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, actual_uuid, sizeof(*actual_uuid), SQLITE_STATIC));
  439. param = 0;
  440. ret = execute_insert(res);
  441. if (ret != SQLITE_DONE)
  442. error_report("Failed to execute command to delete missing charts from health_log");
  443. done:
  444. REPORT_BIND_FAIL(res, param);
  445. SQLITE_FINALIZE(res);
  446. }
  447. static int clean_host_alerts(void *data, int argc, char **argv, char **column)
  448. {
  449. UNUSED(argc);
  450. UNUSED(data);
  451. UNUSED(column);
  452. char guid[UUID_STR_LEN];
  453. uuid_unparse_lower(*(nd_uuid_t *)argv[0], guid);
  454. netdata_log_info("Checking host %s (%s)", guid, (const char *) argv[1]);
  455. sql_remove_alerts_from_deleted_charts(NULL, (nd_uuid_t *)argv[0]);
  456. return 0;
  457. }
  458. #define SQL_HEALTH_CHECK_ALL_HOSTS "SELECT host_id, hostname FROM host"
  459. void sql_alert_cleanup(bool cli)
  460. {
  461. UNUSED(cli);
  462. errno_clear();
  463. if (sql_init_meta_database(DB_CHECK_NONE, 0)) {
  464. netdata_log_error("Failed to open database");
  465. return;
  466. }
  467. netdata_log_info("Alert cleanup running ...");
  468. int rc = sqlite3_exec_monitored(db_meta, SQL_HEALTH_CHECK_ALL_HOSTS, clean_host_alerts, NULL, NULL);
  469. if (rc != SQLITE_OK)
  470. netdata_log_error("Failed to check host alerts");
  471. else
  472. netdata_log_info("Alert cleanup done");
  473. }
  474. /* Health related SQL queries
  475. Load from the health log table
  476. */
  477. #define SQL_LOAD_HEALTH_LOG \
  478. "SELECT hld.unique_id, hld.alarm_id, hld.alarm_event_id, hl.config_hash_id, hld.updated_by_id, " \
  479. "hld.updates_id, hld.when_key, hld.duration, hld.non_clear_duration, hld.flags, hld.exec_run_timestamp, " \
  480. "hld.delay_up_to_timestamp, hl.name, hl.chart, hl.exec, hl.recipient, ah.source, hl.units, " \
  481. "hld.info, hld.exec_code, hld.new_status, hld.old_status, hld.delay, hld.new_value, hld.old_value, " \
  482. "hld.last_repeat, ah.class, ah.component, ah.type, hl.chart_context, hld.transition_id, hld.global_id, " \
  483. "hl.chart_name, hld.summary FROM health_log hl, alert_hash ah, health_log_detail hld " \
  484. "WHERE hl.config_hash_id = ah.hash_id and hl.host_id = @host_id and hl.last_transition_id = hld.transition_id"
  485. void sql_health_alarm_log_load(RRDHOST *host)
  486. {
  487. sqlite3_stmt *res = NULL;
  488. ssize_t errored = 0, loaded = 0;
  489. if (!REQUIRE_DB(db_meta))
  490. return;
  491. sql_check_removed_alerts_state(host);
  492. if (!PREPARE_STATEMENT(db_meta, SQL_LOAD_HEALTH_LOG, &res))
  493. return;
  494. int param = 0;
  495. SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, &host->host_id.uuid, sizeof(host->host_id.uuid), SQLITE_STATIC));
  496. DICTIONARY *all_rrdcalcs = dictionary_create(
  497. DICT_OPTION_NAME_LINK_DONT_CLONE | DICT_OPTION_VALUE_LINK_DONT_CLONE | DICT_OPTION_DONT_OVERWRITE_VALUE);
  498. RRDCALC *rc;
  499. foreach_rrdcalc_in_rrdhost_read(host, rc) {
  500. dictionary_set(all_rrdcalcs, rrdcalc_name(rc), rc, sizeof(*rc));
  501. }
  502. foreach_rrdcalc_in_rrdhost_done(rc);
  503. param = 0;
  504. rw_spinlock_read_lock(&host->health_log.spinlock);
  505. while (sqlite3_step_monitored(res) == SQLITE_ROW) {
  506. ALARM_ENTRY *ae = NULL;
  507. // check that we have valid ids
  508. uint32_t unique_id = (uint32_t) sqlite3_column_int64(res, 0);
  509. if(!unique_id) {
  510. error_report("HEALTH [%s]: Got invalid unique id. Ignoring it.", rrdhost_hostname(host));
  511. errored++;
  512. continue;
  513. }
  514. uint32_t alarm_id = (uint32_t) sqlite3_column_int64(res, 1);
  515. if(!alarm_id) {
  516. error_report("HEALTH [%s]: Got invalid alarm id. Ignoring it.", rrdhost_hostname(host));
  517. errored++;
  518. continue;
  519. }
  520. //need name and chart
  521. if (sqlite3_column_type(res, 12) == SQLITE_NULL) {
  522. error_report("HEALTH [%s]: Got null name field. Ignoring it.", rrdhost_hostname(host));
  523. errored++;
  524. continue;
  525. }
  526. if (sqlite3_column_type(res, 13) == SQLITE_NULL) {
  527. error_report("HEALTH [%s]: Got null chart field. Ignoring it.", rrdhost_hostname(host));
  528. errored++;
  529. continue;
  530. }
  531. // Check if we got last_repeat field
  532. time_t last_repeat = (time_t)sqlite3_column_int64(res, 25);
  533. rc = dictionary_get(all_rrdcalcs, (char *) sqlite3_column_text(res, 13));
  534. if(unlikely(rc)) {
  535. if (rrdcalc_isrepeating(rc)) {
  536. rc->last_repeat = last_repeat;
  537. // We iterate through repeating alarm entries only to
  538. // find the latest last_repeat timestamp. Otherwise,
  539. // there is no need to keep them in memory.
  540. continue;
  541. }
  542. }
  543. ae = callocz(1, sizeof(ALARM_ENTRY));
  544. ae->unique_id = unique_id;
  545. ae->alarm_id = alarm_id;
  546. if (sqlite3_column_type(res, 3) != SQLITE_NULL)
  547. uuid_copy(ae->config_hash_id, *((nd_uuid_t *) sqlite3_column_blob(res, 3)));
  548. ae->alarm_event_id = (uint32_t) sqlite3_column_int64(res, 2);
  549. ae->updated_by_id = (uint32_t) sqlite3_column_int64(res, 4);
  550. ae->updates_id = (uint32_t) sqlite3_column_int64(res, 5);
  551. ae->when = (time_t) sqlite3_column_int64(res, 6);
  552. ae->duration = (time_t) sqlite3_column_int64(res, 7);
  553. ae->non_clear_duration = (time_t) sqlite3_column_int64(res, 8);
  554. ae->flags = (uint32_t) sqlite3_column_int64(res, 9);
  555. ae->flags |= HEALTH_ENTRY_FLAG_SAVED;
  556. ae->exec_run_timestamp = (time_t) sqlite3_column_int64(res, 10);
  557. ae->delay_up_to_timestamp = (time_t) sqlite3_column_int64(res, 11);
  558. ae->name = string_strdupz((char *) sqlite3_column_text(res, 12));
  559. ae->chart = string_strdupz((char *) sqlite3_column_text(res, 13));
  560. ae->exec = SQLITE3_COLUMN_STRINGDUP_OR_NULL(res, 14);
  561. ae->recipient = SQLITE3_COLUMN_STRINGDUP_OR_NULL(res, 15);
  562. ae->source = SQLITE3_COLUMN_STRINGDUP_OR_NULL(res, 16);
  563. ae->units = SQLITE3_COLUMN_STRINGDUP_OR_NULL(res, 17);
  564. ae->info = SQLITE3_COLUMN_STRINGDUP_OR_NULL(res, 18);
  565. ae->exec_code = (int) sqlite3_column_int(res, 19);
  566. ae->new_status = (RRDCALC_STATUS) sqlite3_column_int(res, 20);
  567. ae->old_status = (RRDCALC_STATUS)sqlite3_column_int(res, 21);
  568. ae->delay = (int) sqlite3_column_int(res, 22);
  569. ae->new_value = (NETDATA_DOUBLE) sqlite3_column_double(res, 23);
  570. ae->old_value = (NETDATA_DOUBLE) sqlite3_column_double(res, 24);
  571. ae->last_repeat = last_repeat;
  572. ae->classification = SQLITE3_COLUMN_STRINGDUP_OR_NULL(res, 26);
  573. ae->component = SQLITE3_COLUMN_STRINGDUP_OR_NULL(res, 27);
  574. ae->type = SQLITE3_COLUMN_STRINGDUP_OR_NULL(res, 28);
  575. ae->chart_context = SQLITE3_COLUMN_STRINGDUP_OR_NULL(res, 29);
  576. if (sqlite3_column_type(res, 30) != SQLITE_NULL)
  577. uuid_copy(ae->transition_id, *((nd_uuid_t *)sqlite3_column_blob(res, 30)));
  578. if (sqlite3_column_type(res, 31) != SQLITE_NULL)
  579. ae->global_id = sqlite3_column_int64(res, 31);
  580. ae->chart_name = SQLITE3_COLUMN_STRINGDUP_OR_NULL(res, 32);
  581. ae->summary = SQLITE3_COLUMN_STRINGDUP_OR_NULL(res, 33);
  582. char value_string[100 + 1];
  583. ae->old_value_string = string_strdupz(format_value_and_unit(value_string, 100, ae->old_value, ae_units(ae), -1));
  584. ae->new_value_string = string_strdupz(format_value_and_unit(value_string, 100, ae->new_value, ae_units(ae), -1));
  585. ae->next = host->health_log.alarms;
  586. host->health_log.alarms = ae;
  587. if(unlikely(ae->unique_id > host->health_max_unique_id))
  588. host->health_max_unique_id = ae->unique_id;
  589. if(unlikely(ae->alarm_id >= host->health_max_alarm_id))
  590. host->health_max_alarm_id = ae->alarm_id;
  591. loaded++;
  592. }
  593. rw_spinlock_read_unlock(&host->health_log.spinlock);
  594. dictionary_destroy(all_rrdcalcs);
  595. all_rrdcalcs = NULL;
  596. if (!host->health_max_unique_id)
  597. host->health_max_unique_id = get_uint32_id();
  598. if (!host->health_max_alarm_id)
  599. host->health_max_alarm_id = get_uint32_id();
  600. host->health_log.next_log_id = host->health_max_unique_id + 1;
  601. if (unlikely(!host->health_log.next_alarm_id || host->health_log.next_alarm_id <= host->health_max_alarm_id))
  602. host->health_log.next_alarm_id = host->health_max_alarm_id + 1;
  603. nd_log(NDLS_DAEMON, errored ? NDLP_WARNING : NDLP_DEBUG,
  604. "[%s]: Table health_log, loaded %zd alarm entries, errors in %zd entries.",
  605. rrdhost_hostname(host), loaded, errored);
  606. done:
  607. REPORT_BIND_FAIL(res, param);
  608. SQLITE_FINALIZE(res);
  609. }
  610. /*
  611. * Store an alert config hash in the database
  612. */
  613. #define SQL_STORE_ALERT_CONFIG_HASH \
  614. "INSERT OR REPLACE INTO alert_hash (hash_id, date_updated, alarm, template, " \
  615. "on_key, class, component, type, lookup, every, units, calc, " \
  616. "green, red, warn, crit, exec, to_key, info, delay, options, repeat, host_labels, " \
  617. "p_db_lookup_dimensions, p_db_lookup_method, p_db_lookup_options, p_db_lookup_after, " \
  618. "p_db_lookup_before, p_update_every, source, chart_labels, summary, time_group_condition, " \
  619. "time_group_value, dims_group, data_source) " \
  620. "VALUES (@hash_id,UNIXEPOCH(),@alarm,@template," \
  621. "@on_key,@class,@component,@type,@lookup,@every,@units,@calc," \
  622. "@green,@red,@warn,@crit,@exec,@to_key,@info,@delay,@options,@repeat,@host_labels," \
  623. "@p_db_lookup_dimensions,@p_db_lookup_method,@p_db_lookup_options,@p_db_lookup_after," \
  624. "@p_db_lookup_before,@p_update_every,@source,@chart_labels,@summary, @time_group_condition, " \
  625. "@time_group_value, @dims_group, @data_source)"
  626. void sql_alert_store_config(RRD_ALERT_PROTOTYPE *ap)
  627. {
  628. static __thread sqlite3_stmt *res = NULL;
  629. int param = 0;
  630. if (!PREPARE_COMPILED_STATEMENT(db_meta, SQL_STORE_ALERT_CONFIG_HASH, &res))
  631. return;
  632. CLEAN_BUFFER *buf = buffer_create(128, NULL);
  633. SQLITE_BIND_FAIL(
  634. done, sqlite3_bind_blob(res, ++param, &ap->config.hash_id, sizeof(ap->config.hash_id), SQLITE_STATIC));
  635. if (ap->match.is_template) {
  636. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, NULL));
  637. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ap->config.name));
  638. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ap->match.on.context));
  639. }
  640. else {
  641. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ap->config.name));
  642. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, NULL));
  643. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ap->match.on.chart));
  644. }
  645. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ap->config.classification));
  646. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ap->config.component));
  647. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ap->config.type));
  648. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, NULL)); // lookup
  649. SQLITE_BIND_FAIL(done, sqlite3_bind_int(res, ++param, ap->config.update_every));
  650. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ap->config.units));
  651. if (ap->config.calculation)
  652. SQLITE_BIND_FAIL(done, sqlite3_bind_text(res, ++param, expression_source(ap->config.calculation), -1, SQLITE_STATIC));
  653. else
  654. SQLITE_BIND_FAIL(done,sqlite3_bind_null(res, ++param));
  655. NETDATA_DOUBLE nan_value = NAN;
  656. SQLITE_BIND_FAIL(done, sqlite3_bind_double(res, ++param, nan_value));
  657. SQLITE_BIND_FAIL(done, sqlite3_bind_double(res, ++param, nan_value));
  658. if (ap->config.warning)
  659. SQLITE_BIND_FAIL(done, sqlite3_bind_text(res, ++param, expression_source(ap->config.warning), -1, SQLITE_STATIC));
  660. else
  661. SQLITE_BIND_FAIL(done, sqlite3_bind_null(res, ++param));
  662. if (ap->config.critical)
  663. SQLITE_BIND_FAIL(done, sqlite3_bind_text(res, ++param, expression_source(ap->config.critical), -1, SQLITE_STATIC));
  664. else
  665. SQLITE_BIND_FAIL(done, sqlite3_bind_null(res, ++param));
  666. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ap->config.exec));
  667. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ap->config.recipient));
  668. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ap->config.info));
  669. if (ap->config.delay_up_duration)
  670. buffer_sprintf(buf, "up %ds ", ap->config.delay_up_duration);
  671. if (ap->config.delay_down_duration)
  672. buffer_sprintf(buf, "down %ds ", ap->config.delay_down_duration);
  673. if (ap->config.delay_multiplier)
  674. buffer_sprintf(buf, "multiplier %.1f ", ap->config.delay_multiplier);
  675. if (ap->config.delay_max_duration)
  676. buffer_sprintf(buf, "max %ds", ap->config.delay_max_duration);
  677. // delay
  678. SQLITE_BIND_FAIL(done, sqlite3_bind_text(res, ++param, buffer_tostring(buf), -1, SQLITE_STATIC));
  679. if (ap->config.alert_action_options & ALERT_ACTION_OPTION_NO_CLEAR_NOTIFICATION)
  680. SQLITE_BIND_FAIL(done, sqlite3_bind_text(res, ++param, "no-clear-notification", -1, SQLITE_STATIC));
  681. else
  682. SQLITE_BIND_FAIL(done, sqlite3_bind_null(res, ++param));
  683. char repeat[255];
  684. if (!ap->config.has_custom_repeat_config)
  685. SQLITE_BIND_FAIL(done, sqlite3_bind_null(res, ++param));
  686. else {
  687. snprintfz(repeat, sizeof(repeat) - 1, "warning %us critical %us", ap->config.warn_repeat_every, ap->config.crit_repeat_every);
  688. SQLITE_BIND_FAIL(done, sqlite3_bind_text(res, ++param, repeat, -1, SQLITE_STATIC));
  689. }
  690. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ap->match.host_labels));
  691. if (ap->config.after) {
  692. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ap->config.dimensions));
  693. SQLITE_BIND_FAIL(done, sqlite3_bind_text(res, ++param, time_grouping_id2txt(ap->config.time_group), -1, SQLITE_STATIC));
  694. SQLITE_BIND_FAIL(done, sqlite3_bind_int(res, ++param, (int) RRDR_OPTIONS_REMOVE_OVERLAPPING(ap->config.options)));
  695. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (int) ap->config.after));
  696. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (int) ap->config.before));
  697. } else {
  698. SQLITE_BIND_FAIL(done, sqlite3_bind_null(res, ++param));
  699. SQLITE_BIND_FAIL(done, sqlite3_bind_null(res, ++param));
  700. SQLITE_BIND_FAIL(done, sqlite3_bind_null(res, ++param));
  701. SQLITE_BIND_FAIL(done, sqlite3_bind_null(res, ++param));
  702. SQLITE_BIND_FAIL(done, sqlite3_bind_null(res, ++param));
  703. }
  704. SQLITE_BIND_FAIL(done, sqlite3_bind_int(res, ++param, ap->config.update_every));
  705. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ap->config.source));
  706. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ap->match.chart_labels));
  707. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, ap->config.summary));
  708. SQLITE_BIND_FAIL(done, sqlite3_bind_int(res, ++param, ap->config.time_group_condition));
  709. SQLITE_BIND_FAIL(done, sqlite3_bind_double(res, ++param, ap->config.time_group_value));
  710. SQLITE_BIND_FAIL(done, sqlite3_bind_int(res, ++param, ap->config.dims_group));
  711. SQLITE_BIND_FAIL(done, sqlite3_bind_int(res, ++param, ap->config.data_source));
  712. param = 0;
  713. int rc = execute_insert(res);
  714. if (unlikely(rc != SQLITE_DONE))
  715. error_report("Failed to store alert config, rc = %d", rc);
  716. done:
  717. REPORT_BIND_FAIL(res, param);
  718. SQLITE_RESET(res);
  719. }
  720. #define SQL_SELECT_HEALTH_LAST_EXECUTED_EVENT \
  721. "SELECT hld.new_status FROM health_log hl, health_log_detail hld " \
  722. "WHERE hl.host_id = @host_id AND hl.alarm_id = @alarm_id AND hld.unique_id != @unique_id AND hld.flags & @flags " \
  723. "AND hl.health_log_id = hld.health_log_id ORDER BY hld.unique_id DESC LIMIT 1"
  724. int sql_health_get_last_executed_event(RRDHOST *host, ALARM_ENTRY *ae, RRDCALC_STATUS *last_executed_status)
  725. {
  726. int ret = -1;
  727. sqlite3_stmt *res = NULL;
  728. if (!PREPARE_STATEMENT(db_meta, SQL_SELECT_HEALTH_LAST_EXECUTED_EVENT, &res))
  729. return ret;
  730. int param = 0;
  731. SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, &host->host_id.uuid, sizeof(host->host_id.uuid), SQLITE_STATIC));
  732. SQLITE_BIND_FAIL(done, sqlite3_bind_int(res, ++param, (int) ae->alarm_id));
  733. SQLITE_BIND_FAIL(done, sqlite3_bind_int(res, ++param, (int) ae->unique_id));
  734. SQLITE_BIND_FAIL(done, sqlite3_bind_int(res, ++param, (uint32_t) HEALTH_ENTRY_FLAG_EXEC_RUN));
  735. param = 0;
  736. ret = 0;
  737. while (sqlite3_step_monitored(res) == SQLITE_ROW) {
  738. *last_executed_status = (RRDCALC_STATUS) sqlite3_column_int(res, 0);
  739. ret = 1;
  740. }
  741. done:
  742. REPORT_BIND_FAIL(res, param);
  743. SQLITE_FINALIZE(res);
  744. return ret;
  745. }
  746. #define SQL_SELECT_HEALTH_LOG \
  747. "SELECT hld.unique_id, hld.alarm_id, hld.alarm_event_id, hl.config_hash_id, hld.updated_by_id, hld.updates_id, " \
  748. "hld.when_key, hld.duration, hld.non_clear_duration, hld.flags, hld.exec_run_timestamp, " \
  749. "hld.delay_up_to_timestamp, hl.name, hl.chart, hl.exec, hl.recipient, ah.source, " \
  750. "hl.units, hld.info, hld.exec_code, hld.new_status, hld.old_status, hld.delay, hld.new_value, hld.old_value, " \
  751. "hld.last_repeat, ah.class, ah.component, ah.type, hl.chart_context, hld.transition_id, hld.summary " \
  752. "FROM health_log hl, alert_hash ah, health_log_detail hld WHERE hl.config_hash_id = ah.hash_id and " \
  753. "hl.health_log_id = hld.health_log_id and hl.host_id = @host_id AND hld.unique_id > @after "
  754. void sql_health_alarm_log2json(RRDHOST *host, BUFFER *wb, time_t after, const char *chart)
  755. {
  756. unsigned int max = host->health_log.max;
  757. static __thread sqlite3_stmt *stmt_no_chart = NULL;
  758. static __thread sqlite3_stmt *stmt_with_chart = NULL;
  759. sqlite3_stmt **active_stmt;
  760. sqlite3_stmt *stmt_query;
  761. int rc;
  762. active_stmt = chart ? &stmt_with_chart : &stmt_no_chart;
  763. if (!*active_stmt) {
  764. BUFFER *command = buffer_create(MAX_HEALTH_SQL_SIZE, NULL);
  765. buffer_sprintf(command, SQL_SELECT_HEALTH_LOG);
  766. if (chart)
  767. buffer_strcat(command, " AND hl.chart = @chart ");
  768. buffer_strcat(command, " ORDER BY hld.unique_id DESC LIMIT @limit");
  769. rc = prepare_statement(db_meta, buffer_tostring(command), active_stmt);
  770. buffer_free(command);
  771. if (unlikely(rc != SQLITE_OK)) {
  772. error_report("Failed to prepare statement SQL_SELECT_HEALTH_LOG");
  773. return;
  774. }
  775. }
  776. stmt_query = *active_stmt;
  777. int param = 0;
  778. rc = sqlite3_bind_blob(stmt_query, ++param, &host->host_id.uuid, sizeof(host->host_id.uuid), SQLITE_STATIC);
  779. if (unlikely(rc != SQLITE_OK)) {
  780. error_report("Failed to bind host_id for SQL_SELECT_HEALTH_LOG.");
  781. goto finish;
  782. }
  783. rc = sqlite3_bind_int64(stmt_query, ++param, after);
  784. if (unlikely(rc != SQLITE_OK)) {
  785. error_report("Failed to bind after for SQL_SELECT_HEALTH_LOG.");
  786. goto finish;
  787. }
  788. if (chart) {
  789. rc = sqlite3_bind_text(stmt_query, ++param, chart, -1, SQLITE_STATIC);
  790. if (unlikely(rc != SQLITE_OK)) {
  791. error_report("Failed to bind after for SQL_SELECT_HEALTH_LOG.");
  792. goto finish;
  793. }
  794. }
  795. rc = sqlite3_bind_int64(stmt_query, ++param, max);
  796. if (unlikely(rc != SQLITE_OK)) {
  797. error_report("Failed to bind max lines for SQL_SELECT_HEALTH_LOG.");
  798. goto finish;
  799. }
  800. buffer_json_initialize(wb, "\"", "\"", 0, false, BUFFER_JSON_OPTIONS_DEFAULT);
  801. buffer_json_member_add_array(wb, NULL);
  802. while (sqlite3_step(stmt_query) == SQLITE_ROW) {
  803. char old_value_string[100 + 1];
  804. char new_value_string[100 + 1];
  805. char config_hash_id[UUID_STR_LEN];
  806. uuid_unparse_lower(*((nd_uuid_t *)sqlite3_column_blob(stmt_query, 3)), config_hash_id);
  807. char transition_id[UUID_STR_LEN] = {0};
  808. if (sqlite3_column_type(stmt_query, 30) != SQLITE_NULL)
  809. uuid_unparse_lower(*((nd_uuid_t *)sqlite3_column_blob(stmt_query, 30)), transition_id);
  810. char *edit_command = sqlite3_column_bytes(stmt_query, 16) > 0 ?
  811. health_edit_command_from_source((char *)sqlite3_column_text(stmt_query, 16)) :
  812. strdupz("UNKNOWN=0=UNKNOWN");
  813. buffer_json_add_array_item_object(wb); // this node
  814. buffer_json_member_add_string_or_empty(wb, "hostname", rrdhost_hostname(host));
  815. buffer_json_member_add_int64(wb, "utc_offset", (int64_t)host->utc_offset);
  816. buffer_json_member_add_string_or_empty(wb, "timezone", rrdhost_abbrev_timezone(host));
  817. buffer_json_member_add_int64(wb, "unique_id", (int64_t) sqlite3_column_int64(stmt_query, 0));
  818. buffer_json_member_add_int64(wb, "alarm_id", (int64_t) sqlite3_column_int64(stmt_query, 1));
  819. buffer_json_member_add_int64(wb, "alarm_event_id", (int64_t) sqlite3_column_int64(stmt_query, 2));
  820. buffer_json_member_add_string_or_empty(wb, "config_hash_id", config_hash_id);
  821. buffer_json_member_add_string_or_empty(wb, "transition_id", transition_id);
  822. buffer_json_member_add_string_or_empty(wb, "name", (const char *) sqlite3_column_text(stmt_query, 12));
  823. buffer_json_member_add_string_or_empty(wb, "chart", (const char *) sqlite3_column_text(stmt_query, 13));
  824. buffer_json_member_add_string_or_empty(wb, "context", (const char *) sqlite3_column_text(stmt_query, 29));
  825. buffer_json_member_add_string_or_empty(wb, "class", sqlite3_column_text(stmt_query, 26) ? (const char *) sqlite3_column_text(stmt_query, 26) : (char *) "Unknown");
  826. buffer_json_member_add_string_or_empty(wb, "component", sqlite3_column_text(stmt_query, 27) ? (const char *) sqlite3_column_text(stmt_query, 27) : (char *) "Unknown");
  827. buffer_json_member_add_string_or_empty(wb, "type", sqlite3_column_text(stmt_query, 28) ? (const char *) sqlite3_column_text(stmt_query, 28) : (char *) "Unknown");
  828. buffer_json_member_add_boolean(wb, "processed", (sqlite3_column_int64(stmt_query, 9) & HEALTH_ENTRY_FLAG_PROCESSED));
  829. buffer_json_member_add_boolean(wb, "updated", (sqlite3_column_int64(stmt_query, 9) & HEALTH_ENTRY_FLAG_UPDATED));
  830. buffer_json_member_add_int64(wb, "exec_run", (int64_t)sqlite3_column_int64(stmt_query, 10));
  831. buffer_json_member_add_boolean(wb, "exec_failed", (sqlite3_column_int64(stmt_query, 9) & HEALTH_ENTRY_FLAG_EXEC_FAILED));
  832. buffer_json_member_add_string_or_empty(wb, "exec", sqlite3_column_text(stmt_query, 14) ? (const char *) sqlite3_column_text(stmt_query, 14) : string2str(host->health.health_default_exec));
  833. buffer_json_member_add_string_or_empty(wb, "recipient", sqlite3_column_text(stmt_query, 15) ? (const char *) sqlite3_column_text(stmt_query, 15) : string2str(host->health.health_default_recipient));
  834. buffer_json_member_add_int64(wb, "exec_code", sqlite3_column_int(stmt_query, 19));
  835. buffer_json_member_add_string_or_empty(wb, "source", sqlite3_column_text(stmt_query, 16) ? (const char *) sqlite3_column_text(stmt_query, 16) : (char *) "Unknown");
  836. buffer_json_member_add_string_or_empty(wb, "command", edit_command);
  837. buffer_json_member_add_string_or_empty(wb, "units", (const char *) sqlite3_column_text(stmt_query, 17));
  838. buffer_json_member_add_int64(wb, "when", (int64_t)sqlite3_column_int64(stmt_query, 6));
  839. buffer_json_member_add_int64(wb, "duration", (int64_t)sqlite3_column_int64(stmt_query, 7));
  840. buffer_json_member_add_int64(wb, "non_clear_duration", (int64_t)sqlite3_column_int64(stmt_query, 8));
  841. buffer_json_member_add_string_or_empty(wb, "status", rrdcalc_status2string(sqlite3_column_int(stmt_query, 20)));
  842. buffer_json_member_add_string_or_empty(wb, "old_status", rrdcalc_status2string(sqlite3_column_int(stmt_query, 21)));
  843. buffer_json_member_add_int64(wb, "delay", sqlite3_column_int(stmt_query, 22));
  844. buffer_json_member_add_int64(wb, "delay_up_to_timestamp",(int64_t)sqlite3_column_int64(stmt_query, 11));
  845. buffer_json_member_add_int64(wb, "updated_by_id", (unsigned int)sqlite3_column_int64(stmt_query, 4));
  846. buffer_json_member_add_int64(wb, "updates_id", (unsigned int)sqlite3_column_int64(stmt_query, 5));
  847. buffer_json_member_add_string_or_empty(wb, "value_string", sqlite3_column_type(stmt_query, 23) == SQLITE_NULL ? "-" :
  848. format_value_and_unit(new_value_string, 100, sqlite3_column_double(stmt_query, 23), (char *) sqlite3_column_text(stmt_query, 17), -1));
  849. buffer_json_member_add_string_or_empty(wb, "old_value_string", sqlite3_column_type(stmt_query, 24) == SQLITE_NULL ? "-" :
  850. format_value_and_unit(old_value_string, 100, sqlite3_column_double(stmt_query, 24), (char *) sqlite3_column_text(stmt_query, 17), -1));
  851. buffer_json_member_add_int64(wb, "last_repeat", (int64_t)sqlite3_column_int64(stmt_query, 25));
  852. buffer_json_member_add_boolean(wb, "silenced", (sqlite3_column_int64(stmt_query, 9) & HEALTH_ENTRY_FLAG_SILENCED));
  853. buffer_json_member_add_string_or_empty(wb, "summary", (const char *) sqlite3_column_text(stmt_query, 31));
  854. buffer_json_member_add_string_or_empty(wb, "info", (const char *) sqlite3_column_text(stmt_query, 18));
  855. buffer_json_member_add_boolean(wb, "no_clear_notification",(sqlite3_column_int64(stmt_query, 9) & HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION));
  856. if (sqlite3_column_type(stmt_query, 23) == SQLITE_NULL)
  857. buffer_json_member_add_string(wb, "value", NULL);
  858. else
  859. buffer_json_member_add_double(wb, "value", sqlite3_column_double(stmt_query, 23));
  860. if (sqlite3_column_type(stmt_query, 24) == SQLITE_NULL)
  861. buffer_json_member_add_string(wb, "old_value", NULL);
  862. else
  863. buffer_json_member_add_double(wb, "old_value", sqlite3_column_double(stmt_query, 23));
  864. freez(edit_command);
  865. buffer_json_object_close(wb);
  866. }
  867. buffer_json_array_close(wb);
  868. buffer_json_finalize(wb);
  869. finish:
  870. SQLITE_RESET(stmt_query);
  871. }
  872. #define SQL_COPY_HEALTH_LOG(table) "INSERT OR IGNORE INTO health_log (host_id, alarm_id, config_hash_id, name, chart, family, exec, recipient, units, chart_context) SELECT ?1, alarm_id, config_hash_id, name, chart, family, exec, recipient, units, chart_context from %s", table
  873. #define SQL_COPY_HEALTH_LOG_DETAIL(table) "INSERT INTO health_log_detail (unique_id, alarm_id, alarm_event_id, updated_by_id, updates_id, when_key, duration, non_clear_duration, flags, exec_run_timestamp, delay_up_to_timestamp, info, exec_code, new_status, old_status, delay, new_value, old_value, last_repeat, transition_id, global_id, host_id) SELECT unique_id, alarm_id, alarm_event_id, updated_by_id, updates_id, when_key, duration, non_clear_duration, flags, exec_run_timestamp, delay_up_to_timestamp, info, exec_code, new_status, old_status, delay, new_value, old_value, last_repeat, transition_id, now_usec(1), ?1 from %s", table
  874. #define SQL_UPDATE_HEALTH_LOG_DETAIL_TRANSITION_ID "update health_log_detail set transition_id = uuid_random() where transition_id is null"
  875. #define SQL_UPDATE_HEALTH_LOG_DETAIL_HEALTH_LOG_ID "update health_log_detail set health_log_id = (select health_log_id from health_log where host_id = ?1 and alarm_id = health_log_detail.alarm_id) where health_log_id is null and host_id = ?2"
  876. #define SQL_UPDATE_HEALTH_LOG_LAST_TRANSITION_ID "update health_log set last_transition_id = (select transition_id from health_log_detail where health_log_id = health_log.health_log_id and alarm_id = health_log.alarm_id group by (alarm_id) having max(alarm_event_id)) where host_id = ?1"
  877. int health_migrate_old_health_log_table(char *table) {
  878. if (!table)
  879. return 0;
  880. //table should contain guid. We need to
  881. //keep it in the new table along with it's data
  882. //health_log_XXXXXXXX_XXXX_XXXX_XXXX_XXXXXXXXXXXX
  883. if (strnlen(table, 46) != 46) {
  884. return 0;
  885. }
  886. char *uuid_from_table = strdupz(table + 11);
  887. nd_uuid_t uuid;
  888. if (uuid_parse_fix(uuid_from_table, uuid)) {
  889. freez(uuid_from_table);
  890. return 0;
  891. }
  892. int rc;
  893. char command[MAX_HEALTH_SQL_SIZE + 1];
  894. sqlite3_stmt *res = NULL;
  895. snprintfz(command, sizeof(command) - 1, SQL_COPY_HEALTH_LOG(table));
  896. rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
  897. if (unlikely(rc != SQLITE_OK)) {
  898. error_report("Failed to prepare statement to copy health log, rc = %d", rc);
  899. freez(uuid_from_table);
  900. return 0;
  901. }
  902. rc = sqlite3_bind_blob(res, 1, &uuid, sizeof(uuid), SQLITE_STATIC);
  903. if (unlikely(rc != SQLITE_OK)) {
  904. SQLITE_FINALIZE(res);
  905. freez(uuid_from_table);
  906. return 0;
  907. }
  908. rc = execute_insert(res);
  909. if (unlikely(rc != SQLITE_DONE)) {
  910. error_report("Failed to execute SQL_COPY_HEALTH_LOG, rc = %d", rc);
  911. SQLITE_FINALIZE(res);
  912. freez(uuid_from_table);
  913. }
  914. //detail
  915. snprintfz(command, sizeof(command) - 1, SQL_COPY_HEALTH_LOG_DETAIL(table));
  916. rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
  917. if (unlikely(rc != SQLITE_OK)) {
  918. error_report("Failed to prepare statement to copy health log detail, rc = %d", rc);
  919. return 0;
  920. }
  921. rc = sqlite3_bind_blob(res, 1, &uuid, sizeof(uuid), SQLITE_STATIC);
  922. if (unlikely(rc != SQLITE_OK)) {
  923. SQLITE_FINALIZE(res);
  924. return 0;
  925. }
  926. rc = execute_insert(res);
  927. if (unlikely(rc != SQLITE_DONE)) {
  928. error_report("Failed to execute SQL_COPY_HEALTH_LOG_DETAIL, rc = %d", rc);
  929. SQLITE_FINALIZE(res);
  930. return 0;
  931. }
  932. //update transition ids
  933. rc = sqlite3_prepare_v2(db_meta, SQL_UPDATE_HEALTH_LOG_DETAIL_TRANSITION_ID, -1, &res, 0);
  934. if (unlikely(rc != SQLITE_OK)) {
  935. error_report("Failed to prepare statement to update health log detail with transition ids, rc = %d", rc);
  936. return 0;
  937. }
  938. rc = execute_insert(res);
  939. if (unlikely(rc != SQLITE_DONE)) {
  940. error_report("Failed to execute SQL_UPDATE_HEALTH_LOG_DETAIL_TRANSITION_ID, rc = %d", rc);
  941. SQLITE_FINALIZE(res);
  942. return 0;
  943. }
  944. //update health_log_id
  945. rc = sqlite3_prepare_v2(db_meta, SQL_UPDATE_HEALTH_LOG_DETAIL_HEALTH_LOG_ID, -1, &res, 0);
  946. if (unlikely(rc != SQLITE_OK)) {
  947. error_report("Failed to prepare statement to update health log detail with health log ids, rc = %d", rc);
  948. return 0;
  949. }
  950. rc = sqlite3_bind_blob(res, 1, &uuid, sizeof(uuid), SQLITE_STATIC);
  951. if (unlikely(rc != SQLITE_OK)) {
  952. SQLITE_FINALIZE(res);
  953. return 0;
  954. }
  955. rc = sqlite3_bind_blob(res, 2, &uuid, sizeof(uuid), SQLITE_STATIC);
  956. if (unlikely(rc != SQLITE_OK)) {
  957. SQLITE_FINALIZE(res);
  958. return 0;
  959. }
  960. rc = execute_insert(res);
  961. if (unlikely(rc != SQLITE_DONE)) {
  962. error_report("Failed to execute SQL_UPDATE_HEALTH_LOG_DETAIL_HEALTH_LOG_ID, rc = %d", rc);
  963. SQLITE_FINALIZE(res);
  964. }
  965. //update last transition id
  966. rc = sqlite3_prepare_v2(db_meta, SQL_UPDATE_HEALTH_LOG_LAST_TRANSITION_ID, -1, &res, 0);
  967. if (unlikely(rc != SQLITE_OK)) {
  968. error_report("Failed to prepare statement to update health log with last transition id, rc = %d", rc);
  969. return 0;
  970. }
  971. rc = sqlite3_bind_blob(res, 1, &uuid, sizeof(uuid), SQLITE_STATIC);
  972. if (unlikely(rc != SQLITE_OK)) {
  973. SQLITE_FINALIZE(res);
  974. return 0;
  975. }
  976. rc = execute_insert(res);
  977. if (unlikely(rc != SQLITE_DONE)) {
  978. error_report("Failed to execute SQL_UPDATE_HEALTH_LOG_LAST_TRANSITION_ID, rc = %d", rc);
  979. SQLITE_FINALIZE(res);
  980. }
  981. return 1;
  982. }
  983. #define SQL_GET_EVENT_ID \
  984. "SELECT MAX(alarm_event_id)+1 FROM health_log_detail WHERE health_log_id = @health_log_id AND alarm_id = @alarm_id"
  985. static uint32_t get_next_alarm_event_id(uint64_t health_log_id, uint32_t alarm_id)
  986. {
  987. int rc;
  988. sqlite3_stmt *res = NULL;
  989. uint32_t next_event_id = alarm_id;
  990. rc = sqlite3_prepare_v2(db_meta, SQL_GET_EVENT_ID, -1, &res, 0);
  991. if (rc != SQLITE_OK) {
  992. error_report("Failed to prepare statement when trying to get an event id");
  993. return alarm_id;
  994. }
  995. int param = 0;
  996. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64) health_log_id));
  997. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64) alarm_id));
  998. param = 0;
  999. while (sqlite3_step_monitored(res) == SQLITE_ROW)
  1000. next_event_id = (uint32_t)sqlite3_column_int64(res, 0);
  1001. done:
  1002. REPORT_BIND_FAIL(res, param);
  1003. SQLITE_FINALIZE(res);
  1004. return next_event_id;
  1005. }
  1006. #define SQL_GET_ALARM_ID \
  1007. "SELECT alarm_id, health_log_id FROM health_log WHERE host_id = @host_id AND chart = @chart AND name = @name"
  1008. uint32_t sql_get_alarm_id(RRDHOST *host, STRING *chart, STRING *name, uint32_t *next_event_id)
  1009. {
  1010. sqlite3_stmt *res = NULL;
  1011. uint32_t alarm_id = 0;
  1012. uint64_t health_log_id = 0;
  1013. if (!PREPARE_STATEMENT(db_meta, SQL_GET_ALARM_ID, &res))
  1014. return alarm_id;
  1015. int param = 0;
  1016. SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, &host->host_id.uuid, sizeof(host->host_id.uuid), SQLITE_STATIC));
  1017. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, chart));
  1018. SQLITE_BIND_FAIL(done, SQLITE3_BIND_STRING_OR_NULL(res, ++param, name));
  1019. param = 0;
  1020. while (sqlite3_step_monitored(res) == SQLITE_ROW) {
  1021. alarm_id = (uint32_t)sqlite3_column_int64(res, 0);
  1022. health_log_id = (uint64_t)sqlite3_column_int64(res, 1);
  1023. }
  1024. if (alarm_id)
  1025. *next_event_id = get_next_alarm_event_id(health_log_id, alarm_id);
  1026. done:
  1027. REPORT_BIND_FAIL(res, param);
  1028. SQLITE_FINALIZE(res);
  1029. return alarm_id;
  1030. }
  1031. #define SQL_GET_ALARM_ID_FROM_TRANSITION_ID \
  1032. "SELECT hld.alarm_id, hl.host_id, hl.chart_context FROM health_log_detail hld, health_log hl " \
  1033. "WHERE hld.transition_id = @transition_id " \
  1034. "AND hld.health_log_id = hl.health_log_id"
  1035. bool sql_find_alert_transition(
  1036. const char *transition,
  1037. void (*cb)(const char *machine_guid, const char *context, time_t alert_id, void *data),
  1038. void *data)
  1039. {
  1040. static __thread sqlite3_stmt *res = NULL;
  1041. char machine_guid[UUID_STR_LEN];
  1042. nd_uuid_t transition_uuid;
  1043. if (uuid_parse(transition, transition_uuid))
  1044. return false;
  1045. if (!PREPARE_COMPILED_STATEMENT(db_meta, SQL_GET_ALARM_ID_FROM_TRANSITION_ID, &res))
  1046. return false;
  1047. bool ok = false;
  1048. int param = 0;
  1049. SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, &transition_uuid, sizeof(transition_uuid), SQLITE_STATIC));
  1050. param = 0;
  1051. while (sqlite3_step_monitored(res) == SQLITE_ROW) {
  1052. ok = true;
  1053. uuid_unparse_lower(*(nd_uuid_t *) sqlite3_column_blob(res, 1), machine_guid);
  1054. cb(machine_guid, (const char *) sqlite3_column_text(res, 2), sqlite3_column_int(res, 0), data);
  1055. }
  1056. done:
  1057. REPORT_BIND_FAIL(res, param);
  1058. SQLITE_RESET(res);
  1059. return ok;
  1060. }
  1061. #define SQL_BUILD_ALERT_TRANSITION "CREATE TEMP TABLE IF NOT EXISTS v_%p (host_id blob)"
  1062. #define SQL_POPULATE_TEMP_ALERT_TRANSITION_TABLE "INSERT INTO v_%p (host_id) VALUES (@host_id)"
  1063. #define SQL_SEARCH_ALERT_TRANSITION_SELECT \
  1064. "SELECT h.host_id, h.alarm_id, h.config_hash_id, h.name, h.chart, h.chart_name, h.family, h.recipient, h.units, h.exec, " \
  1065. "h.chart_context, d.when_key, d.duration, d.non_clear_duration, d.flags, d.delay_up_to_timestamp, " \
  1066. "d.info, d.exec_code, d.new_status, d.old_status, d.delay, d.new_value, d.old_value, d.last_repeat, " \
  1067. "d.transition_id, d.global_id, ah.class, ah.type, ah.component, d.exec_run_timestamp, d.summary"
  1068. #define SQL_SEARCH_ALERT_TRANSITION_COMMON_WHERE "h.config_hash_id = ah.hash_id AND h.health_log_id = d.health_log_id"
  1069. #define SQL_SEARCH_ALERT_TRANSITION \
  1070. SQL_SEARCH_ALERT_TRANSITION_SELECT \
  1071. " FROM health_log h, health_log_detail d, v_%p t, alert_hash ah " \
  1072. " WHERE h.host_id = t.host_id AND " SQL_SEARCH_ALERT_TRANSITION_COMMON_WHERE \
  1073. " AND ( d.new_status > 2 OR d.old_status > 2 ) AND d.global_id BETWEEN @after AND @before "
  1074. #define SQL_SEARCH_ALERT_TRANSITION_DIRECT \
  1075. SQL_SEARCH_ALERT_TRANSITION_SELECT " FROM health_log h, health_log_detail d, alert_hash ah " \
  1076. " WHERE " SQL_SEARCH_ALERT_TRANSITION_COMMON_WHERE \
  1077. " AND transition_id = @transition "
  1078. void sql_alert_transitions(
  1079. DICTIONARY *nodes,
  1080. time_t after,
  1081. time_t before,
  1082. const char *context,
  1083. const char *alert_name,
  1084. const char *transition,
  1085. void (*cb)(struct sql_alert_transition_data *, void *),
  1086. void *data,
  1087. bool debug __maybe_unused)
  1088. {
  1089. nd_uuid_t transition_uuid;
  1090. char sql[512];
  1091. int rc;
  1092. sqlite3_stmt *res = NULL;
  1093. BUFFER *command = NULL;
  1094. if (unlikely(!nodes))
  1095. return;
  1096. int param = 0;
  1097. if (transition) {
  1098. if (uuid_parse(transition, transition_uuid)) {
  1099. error_report("Invalid transition given %s", transition);
  1100. return;
  1101. }
  1102. if (!PREPARE_STATEMENT(db_meta, SQL_SEARCH_ALERT_TRANSITION_DIRECT, &res))
  1103. goto done_only_drop;
  1104. SQLITE_BIND_FAIL(done, sqlite3_bind_blob(res, ++param, &transition_uuid, sizeof(transition_uuid), SQLITE_STATIC));
  1105. goto run_query;
  1106. }
  1107. snprintfz(sql, sizeof(sql) - 1, SQL_BUILD_ALERT_TRANSITION, nodes);
  1108. rc = db_execute(db_meta, sql);
  1109. if (rc)
  1110. return;
  1111. snprintfz(sql, sizeof(sql) - 1, SQL_POPULATE_TEMP_ALERT_TRANSITION_TABLE, nodes);
  1112. // Prepare statement to add things
  1113. rc = sqlite3_prepare_v2(db_meta, sql, -1, &res, 0);
  1114. if (unlikely(rc != SQLITE_OK)) {
  1115. error_report("Failed to prepare statement to INSERT into v_%p", nodes);
  1116. goto done_only_drop;
  1117. }
  1118. void *t;
  1119. dfe_start_read(nodes, t) {
  1120. nd_uuid_t host_uuid;
  1121. uuid_parse( t_dfe.name, host_uuid);
  1122. rc = sqlite3_bind_blob(res, 1, &host_uuid, sizeof(host_uuid), SQLITE_STATIC);
  1123. if (unlikely(rc != SQLITE_OK))
  1124. error_report("Failed to bind host_id parameter.");
  1125. rc = sqlite3_step_monitored(res);
  1126. if (rc != SQLITE_DONE)
  1127. error_report("Error while populating temp table");
  1128. SQLITE_RESET(res);
  1129. }
  1130. dfe_done(t);
  1131. SQLITE_FINALIZE(res);
  1132. command = buffer_create(MAX_HEALTH_SQL_SIZE, NULL);
  1133. buffer_sprintf(command, SQL_SEARCH_ALERT_TRANSITION, nodes);
  1134. if (context)
  1135. buffer_sprintf(command, " AND h.chart_context = @context");
  1136. if (alert_name)
  1137. buffer_sprintf(command, " AND h.name = @alert_name");
  1138. buffer_strcat(command, " ORDER BY d.global_id DESC");
  1139. rc = sqlite3_prepare_v2(db_meta, buffer_tostring(command), -1, &res, 0);
  1140. if (unlikely(rc != SQLITE_OK)) {
  1141. error_report("Failed to prepare statement sql_alert_transitions");
  1142. goto done_only_drop;
  1143. }
  1144. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64)(after * USEC_PER_SEC)));
  1145. SQLITE_BIND_FAIL(done, sqlite3_bind_int64(res, ++param, (sqlite3_int64)(before * USEC_PER_SEC)));
  1146. if (context)
  1147. SQLITE_BIND_FAIL(done, sqlite3_bind_text(res, ++param, context, -1, SQLITE_STATIC));
  1148. if (alert_name)
  1149. SQLITE_BIND_FAIL(done, sqlite3_bind_text(res, ++param, alert_name, -1, SQLITE_STATIC));
  1150. run_query:;
  1151. struct sql_alert_transition_data atd = {0 };
  1152. param = 0;
  1153. while (sqlite3_step(res) == SQLITE_ROW) {
  1154. atd.host_id = (nd_uuid_t *) sqlite3_column_blob(res, 0);
  1155. atd.alarm_id = sqlite3_column_int64(res, 1);
  1156. atd.config_hash_id = (nd_uuid_t *)sqlite3_column_blob(res, 2);
  1157. atd.alert_name = (const char *) sqlite3_column_text(res, 3);
  1158. atd.chart = (const char *) sqlite3_column_text(res, 4);
  1159. atd.chart_name = (const char *) sqlite3_column_text(res, 5);
  1160. atd.family = (const char *) sqlite3_column_text(res, 6);
  1161. atd.recipient = (const char *) sqlite3_column_text(res, 7);
  1162. atd.units = (const char *) sqlite3_column_text(res, 8);
  1163. atd.exec = (const char *) sqlite3_column_text(res, 9);
  1164. atd.chart_context = (const char *) sqlite3_column_text(res, 10);
  1165. atd.when_key = sqlite3_column_int64(res, 11);
  1166. atd.duration = sqlite3_column_int64(res, 12);
  1167. atd.non_clear_duration = sqlite3_column_int64(res, 13);
  1168. atd.flags = sqlite3_column_int64(res, 14);
  1169. atd.delay_up_to_timestamp = sqlite3_column_int64(res, 15);
  1170. atd.info = (const char *) sqlite3_column_text(res, 16);
  1171. atd.exec_code = sqlite3_column_int(res, 17);
  1172. atd.new_status = sqlite3_column_int(res, 18);
  1173. atd.old_status = sqlite3_column_int(res, 19);
  1174. atd.delay = (int) sqlite3_column_int(res, 20);
  1175. atd.new_value = (NETDATA_DOUBLE) sqlite3_column_double(res, 21);
  1176. atd.old_value = (NETDATA_DOUBLE) sqlite3_column_double(res, 22);
  1177. atd.last_repeat = sqlite3_column_int64(res, 23);
  1178. atd.transition_id = (nd_uuid_t *) sqlite3_column_blob(res, 24);
  1179. atd.global_id = sqlite3_column_int64(res, 25);
  1180. atd.classification = (const char *) sqlite3_column_text(res, 26);
  1181. atd.type = (const char *) sqlite3_column_text(res, 27);
  1182. atd.component = (const char *) sqlite3_column_text(res, 28);
  1183. atd.exec_run_timestamp = sqlite3_column_int64(res, 29);
  1184. atd.summary = (const char *) sqlite3_column_text(res, 30);
  1185. cb(&atd, data);
  1186. }
  1187. done:
  1188. REPORT_BIND_FAIL(res, param);
  1189. SQLITE_FINALIZE(res);
  1190. done_only_drop:
  1191. if (likely(!transition)) {
  1192. (void)snprintfz(sql, sizeof(sql) - 1, "DROP TABLE IF EXISTS v_%p", nodes);
  1193. (void)db_execute(db_meta, sql);
  1194. buffer_free(command);
  1195. }
  1196. }
  1197. #define SQL_BUILD_CONFIG_TARGET_LIST "CREATE TEMP TABLE IF NOT EXISTS c_%p (hash_id blob)"
  1198. #define SQL_POPULATE_TEMP_CONFIG_TARGET_TABLE "INSERT INTO c_%p (hash_id) VALUES (@hash_id)"
  1199. #define SQL_SEARCH_CONFIG_LIST \
  1200. "SELECT ah.hash_id, alarm, template, on_key, class, component, type, lookup, every, " \
  1201. " units, calc, families, green, red, warn, crit, " \
  1202. " exec, to_key, info, delay, options, repeat, host_labels, p_db_lookup_dimensions, p_db_lookup_method, " \
  1203. " p_db_lookup_options, p_db_lookup_after, p_db_lookup_before, p_update_every, source, chart_labels, summary, " \
  1204. " time_group_condition, time_group_value, dims_group, data_source " \
  1205. " FROM alert_hash ah, c_%p t where ah.hash_id = t.hash_id"
  1206. int sql_get_alert_configuration(
  1207. DICTIONARY *configs,
  1208. void (*cb)(struct sql_alert_config_data *, void *),
  1209. void *data,
  1210. bool debug __maybe_unused)
  1211. {
  1212. int added = -1;
  1213. char sql[512];
  1214. int rc;
  1215. sqlite3_stmt *res = NULL;
  1216. BUFFER *command = NULL;
  1217. if (unlikely(!configs))
  1218. return added;
  1219. snprintfz(sql, sizeof(sql) - 1, SQL_BUILD_CONFIG_TARGET_LIST, configs);
  1220. rc = db_execute(db_meta, sql);
  1221. if (rc)
  1222. return added;
  1223. snprintfz(sql, sizeof(sql) - 1, SQL_POPULATE_TEMP_CONFIG_TARGET_TABLE, configs);
  1224. // Prepare statement to add things
  1225. rc = sqlite3_prepare_v2(db_meta, sql, -1, &res, 0);
  1226. if (unlikely(rc != SQLITE_OK)) {
  1227. error_report("Failed to prepare statement to INSERT into c_%p", configs);
  1228. goto fail_only_drop;
  1229. }
  1230. void *t;
  1231. dfe_start_read(configs, t) {
  1232. nd_uuid_t hash_id;
  1233. uuid_parse( t_dfe.name, hash_id);
  1234. rc = sqlite3_bind_blob(res, 1, &hash_id, sizeof(hash_id), SQLITE_STATIC);
  1235. if (unlikely(rc != SQLITE_OK))
  1236. error_report("Failed to bind host_id parameter.");
  1237. rc = sqlite3_step_monitored(res);
  1238. if (rc != SQLITE_DONE)
  1239. error_report("Error while populating temp table");
  1240. SQLITE_RESET(res);
  1241. }
  1242. dfe_done(t);
  1243. SQLITE_FINALIZE(res);
  1244. command = buffer_create(MAX_HEALTH_SQL_SIZE, NULL);
  1245. buffer_sprintf(command, SQL_SEARCH_CONFIG_LIST, configs);
  1246. rc = sqlite3_prepare_v2(db_meta, buffer_tostring(command), -1, &res, 0);
  1247. if (unlikely(rc != SQLITE_OK)) {
  1248. error_report("Failed to prepare statement sql_get_alert_configuration");
  1249. goto fail_only_drop;
  1250. }
  1251. struct sql_alert_config_data acd = {0 };
  1252. added = 0;
  1253. int param;
  1254. while (sqlite3_step(res) == SQLITE_ROW) {
  1255. param = 0;
  1256. acd.config_hash_id = (nd_uuid_t *) sqlite3_column_blob(res, param++);
  1257. acd.name = (const char *) sqlite3_column_text(res, param++);
  1258. acd.selectors.on_template = (const char *) sqlite3_column_text(res, param++);
  1259. acd.selectors.on_key = (const char *) sqlite3_column_text(res, param++);
  1260. acd.classification = (const char *) sqlite3_column_text(res, param++);
  1261. acd.component = (const char *) sqlite3_column_text(res, param++);
  1262. acd.type = (const char *) sqlite3_column_text(res, param++);
  1263. acd.value.db.lookup = (const char *) sqlite3_column_text(res, param++);
  1264. acd.value.every = (const char *) sqlite3_column_text(res, param++);
  1265. acd.value.units = (const char *) sqlite3_column_text(res, param++);
  1266. acd.value.calc = (const char *) sqlite3_column_text(res, param++);
  1267. acd.selectors.families = (const char *) sqlite3_column_text(res, param++);
  1268. acd.status.green = (const char *) sqlite3_column_text(res, param++);
  1269. acd.status.red = (const char *) sqlite3_column_text(res, param++);
  1270. acd.status.warn = (const char *) sqlite3_column_text(res, param++);
  1271. acd.status.crit = (const char *) sqlite3_column_text(res, param++);
  1272. acd.notification.exec = (const char *) sqlite3_column_text(res, param++);
  1273. acd.notification.to_key = (const char *) sqlite3_column_text(res, param++);
  1274. acd.info = (const char *) sqlite3_column_text(res, param++);
  1275. acd.notification.delay = (const char *) sqlite3_column_text(res, param++);
  1276. acd.notification.options = (const char *) sqlite3_column_text(res, param++);
  1277. acd.notification.repeat = (const char *) sqlite3_column_text(res, param++);
  1278. acd.selectors.host_labels = (const char *) sqlite3_column_text(res, param++);
  1279. acd.value.db.dimensions = (const char *) sqlite3_column_text(res, param++);
  1280. acd.value.db.method = (const char *) sqlite3_column_text(res, param++);
  1281. acd.value.db.options = (uint32_t) sqlite3_column_int(res, param++);
  1282. acd.value.db.after = (int32_t) sqlite3_column_int(res, param++);
  1283. acd.value.db.before = (int32_t) sqlite3_column_int(res, param++);
  1284. acd.value.update_every = (int32_t) sqlite3_column_int(res, param++);
  1285. acd.source = (const char *) sqlite3_column_text(res, param++);
  1286. acd.selectors.chart_labels = (const char *) sqlite3_column_text(res, param++);
  1287. acd.summary = (const char *) sqlite3_column_text(res, param++);
  1288. acd.value.db.time_group_condition =(int32_t) sqlite3_column_int(res, param++);
  1289. acd.value.db.time_group_value = sqlite3_column_double(res, param++);
  1290. acd.value.db.dims_group = (int32_t) sqlite3_column_int(res, param++);
  1291. acd.value.db.data_source = (int32_t) sqlite3_column_int(res, param++);
  1292. cb(&acd, data);
  1293. added++;
  1294. }
  1295. SQLITE_FINALIZE(res);
  1296. fail_only_drop:
  1297. (void)snprintfz(sql, sizeof(sql) - 1, "DROP TABLE IF EXISTS c_%p", configs);
  1298. (void)db_execute(db_meta, sql);
  1299. buffer_free(command);
  1300. return added;
  1301. }