flapjack 1.6.0 → 2.0.0b1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -6
  3. data/.gitmodules +1 -1
  4. data/.rspec +1 -1
  5. data/.ruby-version +1 -1
  6. data/.travis.yml +12 -13
  7. data/CHANGELOG.md +2 -9
  8. data/CONTRIBUTING.md +7 -2
  9. data/Gemfile +4 -13
  10. data/LICENCE +1 -0
  11. data/README.md +8 -2
  12. data/Rakefile +2 -2
  13. data/bin/flapjack +3 -12
  14. data/build.sh +4 -2
  15. data/etc/flapjack_config.toml.example +273 -0
  16. data/features/ack_after_sched_maint.feature +18 -21
  17. data/features/cli.feature +11 -71
  18. data/features/cli_flapjack-feed-events.feature +14 -15
  19. data/features/cli_flapjack-nagios-receiver.feature +12 -41
  20. data/features/cli_flapper.feature +12 -41
  21. data/features/cli_purge.feature +5 -6
  22. data/features/cli_receive-events.feature +6 -7
  23. data/features/cli_simulate-failed-check.feature +5 -6
  24. data/features/events.feature +206 -181
  25. data/features/events_check_names.feature +4 -7
  26. data/features/notification_rules.feature +144 -223
  27. data/features/notifications.feature +65 -57
  28. data/features/rollup.feature +45 -47
  29. data/features/steps/cli_steps.rb +4 -5
  30. data/features/steps/events_steps.rb +163 -373
  31. data/features/steps/notifications_steps.rb +408 -264
  32. data/features/steps/packaging-lintian_steps.rb +0 -4
  33. data/features/steps/time_travel_steps.rb +0 -26
  34. data/features/support/daemons.rb +6 -31
  35. data/features/support/env.rb +65 -74
  36. data/flapjack.gemspec +22 -24
  37. data/lib/flapjack.rb +14 -7
  38. data/lib/flapjack/cli/flapper.rb +74 -173
  39. data/lib/flapjack/cli/maintenance.rb +278 -109
  40. data/lib/flapjack/cli/migrate.rb +950 -0
  41. data/lib/flapjack/cli/purge.rb +19 -22
  42. data/lib/flapjack/cli/receiver.rb +150 -326
  43. data/lib/flapjack/cli/server.rb +8 -235
  44. data/lib/flapjack/cli/simulate.rb +42 -57
  45. data/lib/flapjack/configuration.rb +51 -37
  46. data/lib/flapjack/coordinator.rb +138 -129
  47. data/lib/flapjack/data/acknowledgement.rb +177 -0
  48. data/lib/flapjack/data/alert.rb +97 -158
  49. data/lib/flapjack/data/check.rb +611 -0
  50. data/lib/flapjack/data/condition.rb +70 -0
  51. data/lib/flapjack/data/contact.rb +226 -456
  52. data/lib/flapjack/data/event.rb +96 -184
  53. data/lib/flapjack/data/extensions/associations.rb +59 -0
  54. data/lib/flapjack/data/extensions/short_name.rb +25 -0
  55. data/lib/flapjack/data/medium.rb +428 -0
  56. data/lib/flapjack/data/metrics.rb +194 -0
  57. data/lib/flapjack/data/notification.rb +22 -281
  58. data/lib/flapjack/data/rule.rb +473 -0
  59. data/lib/flapjack/data/scheduled_maintenance.rb +244 -0
  60. data/lib/flapjack/data/state.rb +221 -0
  61. data/lib/flapjack/data/statistic.rb +112 -0
  62. data/lib/flapjack/data/tag.rb +277 -0
  63. data/lib/flapjack/data/test_notification.rb +182 -0
  64. data/lib/flapjack/data/unscheduled_maintenance.rb +159 -0
  65. data/lib/flapjack/data/validators/id_validator.rb +20 -0
  66. data/lib/flapjack/exceptions.rb +6 -0
  67. data/lib/flapjack/filters/acknowledgement.rb +23 -16
  68. data/lib/flapjack/filters/base.rb +0 -5
  69. data/lib/flapjack/filters/delays.rb +53 -43
  70. data/lib/flapjack/filters/ok.rb +23 -14
  71. data/lib/flapjack/filters/scheduled_maintenance.rb +3 -3
  72. data/lib/flapjack/filters/unscheduled_maintenance.rb +12 -3
  73. data/lib/flapjack/gateways/aws_sns.rb +65 -49
  74. data/lib/flapjack/gateways/aws_sns/alert.text.erb +2 -2
  75. data/lib/flapjack/gateways/aws_sns/alert_subject.text.erb +2 -2
  76. data/lib/flapjack/gateways/aws_sns/rollup_subject.text.erb +1 -1
  77. data/lib/flapjack/gateways/email.rb +107 -90
  78. data/lib/flapjack/gateways/email/alert.html.erb +19 -18
  79. data/lib/flapjack/gateways/email/alert.text.erb +20 -14
  80. data/lib/flapjack/gateways/email/alert_subject.text.erb +2 -1
  81. data/lib/flapjack/gateways/email/rollup.html.erb +14 -13
  82. data/lib/flapjack/gateways/email/rollup.text.erb +13 -10
  83. data/lib/flapjack/gateways/jabber.rb +679 -671
  84. data/lib/flapjack/gateways/jabber/alert.text.erb +9 -6
  85. data/lib/flapjack/gateways/jsonapi.rb +164 -350
  86. data/lib/flapjack/gateways/jsonapi/data/join_descriptor.rb +44 -0
  87. data/lib/flapjack/gateways/jsonapi/data/method_descriptor.rb +21 -0
  88. data/lib/flapjack/gateways/jsonapi/helpers/headers.rb +63 -0
  89. data/lib/flapjack/gateways/jsonapi/helpers/miscellaneous.rb +136 -0
  90. data/lib/flapjack/gateways/jsonapi/helpers/resources.rb +227 -0
  91. data/lib/flapjack/gateways/jsonapi/helpers/serialiser.rb +313 -0
  92. data/lib/flapjack/gateways/jsonapi/helpers/swagger_docs.rb +322 -0
  93. data/lib/flapjack/gateways/jsonapi/methods/association_delete.rb +115 -0
  94. data/lib/flapjack/gateways/jsonapi/methods/association_get.rb +288 -0
  95. data/lib/flapjack/gateways/jsonapi/methods/association_patch.rb +178 -0
  96. data/lib/flapjack/gateways/jsonapi/methods/association_post.rb +116 -0
  97. data/lib/flapjack/gateways/jsonapi/methods/metrics.rb +71 -0
  98. data/lib/flapjack/gateways/jsonapi/methods/resource_delete.rb +119 -0
  99. data/lib/flapjack/gateways/jsonapi/methods/resource_get.rb +186 -0
  100. data/lib/flapjack/gateways/jsonapi/methods/resource_patch.rb +239 -0
  101. data/lib/flapjack/gateways/jsonapi/methods/resource_post.rb +197 -0
  102. data/lib/flapjack/gateways/jsonapi/middleware/array_param_fixer.rb +27 -0
  103. data/lib/flapjack/gateways/jsonapi/{rack → middleware}/json_params_parser.rb +7 -6
  104. data/lib/flapjack/gateways/jsonapi/middleware/request_timestamp.rb +18 -0
  105. data/lib/flapjack/gateways/oobetet.rb +222 -170
  106. data/lib/flapjack/gateways/pager_duty.rb +388 -0
  107. data/lib/flapjack/gateways/pager_duty/alert.text.erb +13 -0
  108. data/lib/flapjack/gateways/slack.rb +56 -48
  109. data/lib/flapjack/gateways/slack/alert.text.erb +1 -1
  110. data/lib/flapjack/gateways/slack/rollup.text.erb +1 -1
  111. data/lib/flapjack/gateways/sms_aspsms.rb +155 -0
  112. data/lib/flapjack/gateways/sms_aspsms/alert.text.erb +7 -0
  113. data/lib/flapjack/gateways/sms_aspsms/rollup.text.erb +2 -0
  114. data/lib/flapjack/gateways/sms_messagenet.rb +77 -57
  115. data/lib/flapjack/gateways/sms_messagenet/alert.text.erb +3 -2
  116. data/lib/flapjack/gateways/sms_nexmo.rb +53 -51
  117. data/lib/flapjack/gateways/sms_nexmo/alert.text.erb +2 -2
  118. data/lib/flapjack/gateways/sms_nexmo/rollup.text.erb +1 -1
  119. data/lib/flapjack/gateways/sms_twilio.rb +79 -62
  120. data/lib/flapjack/gateways/sms_twilio/alert.text.erb +3 -2
  121. data/lib/flapjack/gateways/web.rb +437 -345
  122. data/lib/flapjack/gateways/web/middleware/request_timestamp.rb +18 -0
  123. data/lib/flapjack/gateways/web/public/css/bootstrap.css +3793 -4340
  124. data/lib/flapjack/gateways/web/public/css/bootstrap.css.map +1 -0
  125. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.eot +0 -0
  126. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.svg +273 -214
  127. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.ttf +0 -0
  128. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.woff +0 -0
  129. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.woff2 +0 -0
  130. data/lib/flapjack/gateways/web/public/js/bootstrap.js +1637 -1607
  131. data/lib/flapjack/gateways/web/public/js/self_stats.js +1 -2
  132. data/lib/flapjack/gateways/web/views/_pagination.html.erb +19 -0
  133. data/lib/flapjack/gateways/web/views/check.html.erb +159 -121
  134. data/lib/flapjack/gateways/web/views/checks.html.erb +82 -41
  135. data/lib/flapjack/gateways/web/views/contact.html.erb +59 -71
  136. data/lib/flapjack/gateways/web/views/contacts.html.erb +32 -8
  137. data/lib/flapjack/gateways/web/views/index.html.erb +2 -2
  138. data/lib/flapjack/gateways/web/views/{layout.erb → layout.html.erb} +7 -23
  139. data/lib/flapjack/gateways/web/views/self_stats.html.erb +32 -33
  140. data/lib/flapjack/gateways/web/views/tag.html.erb +32 -0
  141. data/lib/flapjack/gateways/web/views/tags.html.erb +51 -0
  142. data/lib/flapjack/logger.rb +34 -3
  143. data/lib/flapjack/notifier.rb +180 -112
  144. data/lib/flapjack/patches.rb +8 -63
  145. data/lib/flapjack/pikelet.rb +185 -143
  146. data/lib/flapjack/processor.rb +323 -191
  147. data/lib/flapjack/record_queue.rb +33 -0
  148. data/lib/flapjack/redis_proxy.rb +66 -0
  149. data/lib/flapjack/utility.rb +21 -15
  150. data/lib/flapjack/version.rb +2 -1
  151. data/libexec/httpbroker.go +218 -14
  152. data/libexec/oneoff.go +13 -10
  153. data/spec/lib/flapjack/configuration_spec.rb +286 -0
  154. data/spec/lib/flapjack/coordinator_spec.rb +103 -157
  155. data/spec/lib/flapjack/data/check_spec.rb +175 -0
  156. data/spec/lib/flapjack/data/contact_spec.rb +26 -349
  157. data/spec/lib/flapjack/data/event_spec.rb +76 -291
  158. data/spec/lib/flapjack/data/medium_spec.rb +19 -0
  159. data/spec/lib/flapjack/data/rule_spec.rb +43 -0
  160. data/spec/lib/flapjack/data/scheduled_maintenance_spec.rb +976 -0
  161. data/spec/lib/flapjack/data/unscheduled_maintenance_spec.rb +34 -0
  162. data/spec/lib/flapjack/gateways/aws_sns_spec.rb +111 -60
  163. data/spec/lib/flapjack/gateways/email_spec.rb +194 -161
  164. data/spec/lib/flapjack/gateways/jabber_spec.rb +961 -162
  165. data/spec/lib/flapjack/gateways/jsonapi/methods/check_links_spec.rb +155 -0
  166. data/spec/lib/flapjack/gateways/jsonapi/methods/checks_spec.rb +426 -0
  167. data/spec/lib/flapjack/gateways/jsonapi/methods/contact_links_spec.rb +217 -0
  168. data/spec/lib/flapjack/gateways/jsonapi/methods/contacts_spec.rb +425 -0
  169. data/spec/lib/flapjack/gateways/jsonapi/methods/events_spec.rb +271 -0
  170. data/spec/lib/flapjack/gateways/jsonapi/methods/media_spec.rb +257 -0
  171. data/spec/lib/flapjack/gateways/jsonapi/methods/medium_links_spec.rb +163 -0
  172. data/spec/lib/flapjack/gateways/jsonapi/methods/metrics_spec.rb +8 -0
  173. data/spec/lib/flapjack/gateways/jsonapi/methods/rule_links_spec.rb +212 -0
  174. data/spec/lib/flapjack/gateways/jsonapi/methods/rules_spec.rb +289 -0
  175. data/spec/lib/flapjack/gateways/jsonapi/methods/scheduled_maintenance_links_spec.rb +49 -0
  176. data/spec/lib/flapjack/gateways/jsonapi/methods/scheduled_maintenances_spec.rb +242 -0
  177. data/spec/lib/flapjack/gateways/jsonapi/methods/tag_links_spec.rb +274 -0
  178. data/spec/lib/flapjack/gateways/jsonapi/methods/tags_spec.rb +302 -0
  179. data/spec/lib/flapjack/gateways/jsonapi/methods/unscheduled_maintenance_links_spec.rb +49 -0
  180. data/spec/lib/flapjack/gateways/jsonapi/methods/unscheduled_maintenances_spec.rb +339 -0
  181. data/spec/lib/flapjack/gateways/jsonapi_spec.rb +1 -1
  182. data/spec/lib/flapjack/gateways/oobetet_spec.rb +151 -79
  183. data/spec/lib/flapjack/gateways/pager_duty_spec.rb +353 -0
  184. data/spec/lib/flapjack/gateways/slack_spec.rb +53 -53
  185. data/spec/lib/flapjack/gateways/sms_aspsms_spec.rb +106 -0
  186. data/spec/lib/flapjack/gateways/sms_messagenet_spec.rb +111 -54
  187. data/spec/lib/flapjack/gateways/sms_nexmo_spec.rb +50 -51
  188. data/spec/lib/flapjack/gateways/sms_twilio_spec.rb +108 -48
  189. data/spec/lib/flapjack/gateways/web_spec.rb +144 -216
  190. data/spec/lib/flapjack/notifier_spec.rb +132 -1
  191. data/spec/lib/flapjack/pikelet_spec.rb +111 -50
  192. data/spec/lib/flapjack/processor_spec.rb +210 -40
  193. data/spec/lib/flapjack/redis_proxy_spec.rb +45 -0
  194. data/spec/lib/flapjack/utility_spec.rb +11 -15
  195. data/spec/service_consumers/fixture_data.rb +547 -0
  196. data/spec/service_consumers/pact_helper.rb +21 -32
  197. data/spec/service_consumers/pacts/flapjack-diner_v2.0.json +4652 -0
  198. data/spec/service_consumers/provider_states_for_flapjack-diner.rb +279 -322
  199. data/spec/service_consumers/provider_support.rb +8 -0
  200. data/spec/spec_helper.rb +34 -44
  201. data/spec/support/erb_view_helper.rb +1 -1
  202. data/spec/support/factories.rb +58 -0
  203. data/spec/support/jsonapi_helper.rb +15 -26
  204. data/spec/support/mock_logger.rb +43 -0
  205. data/spec/support/xmpp_comparable.rb +24 -0
  206. data/src/flapjack/transport_test.go +30 -1
  207. data/tasks/dump_keys.rake +82 -0
  208. data/tasks/events.rake +7 -7
  209. data/tasks/support/flapjack_config_benchmark.toml +28 -0
  210. data/tasks/support/flapjack_config_benchmark.yaml +0 -2
  211. metadata +175 -222
  212. data/Guardfile +0 -14
  213. data/etc/flapjack_config.yaml.example +0 -477
  214. data/features/cli_flapjack-populator.feature +0 -90
  215. data/features/support/silent_system.rb +0 -4
  216. data/lib/flapjack/cli/import.rb +0 -108
  217. data/lib/flapjack/data/entity.rb +0 -652
  218. data/lib/flapjack/data/entity_check.rb +0 -1044
  219. data/lib/flapjack/data/message.rb +0 -56
  220. data/lib/flapjack/data/migration.rb +0 -234
  221. data/lib/flapjack/data/notification_rule.rb +0 -425
  222. data/lib/flapjack/data/semaphore.rb +0 -44
  223. data/lib/flapjack/data/tagged.rb +0 -48
  224. data/lib/flapjack/gateways/jsonapi/check_methods.rb +0 -206
  225. data/lib/flapjack/gateways/jsonapi/check_presenter.rb +0 -221
  226. data/lib/flapjack/gateways/jsonapi/contact_methods.rb +0 -186
  227. data/lib/flapjack/gateways/jsonapi/entity_methods.rb +0 -223
  228. data/lib/flapjack/gateways/jsonapi/medium_methods.rb +0 -185
  229. data/lib/flapjack/gateways/jsonapi/metrics_methods.rb +0 -132
  230. data/lib/flapjack/gateways/jsonapi/notification_rule_methods.rb +0 -141
  231. data/lib/flapjack/gateways/jsonapi/pagerduty_credential_methods.rb +0 -139
  232. data/lib/flapjack/gateways/jsonapi/report_methods.rb +0 -146
  233. data/lib/flapjack/gateways/pagerduty.rb +0 -318
  234. data/lib/flapjack/gateways/pagerduty/alert.text.erb +0 -10
  235. data/lib/flapjack/gateways/web/public/css/select2-bootstrap.css +0 -87
  236. data/lib/flapjack/gateways/web/public/css/select2.css +0 -615
  237. data/lib/flapjack/gateways/web/public/css/tablesort.css +0 -67
  238. data/lib/flapjack/gateways/web/public/img/select2-spinner.gif +0 -0
  239. data/lib/flapjack/gateways/web/public/img/select2.png +0 -0
  240. data/lib/flapjack/gateways/web/public/img/select2x2.png +0 -0
  241. data/lib/flapjack/gateways/web/public/js/backbone.js +0 -1581
  242. data/lib/flapjack/gateways/web/public/js/backbone.jsonapi.js +0 -322
  243. data/lib/flapjack/gateways/web/public/js/flapjack.js +0 -82
  244. data/lib/flapjack/gateways/web/public/js/jquery.tablesorter.js +0 -1640
  245. data/lib/flapjack/gateways/web/public/js/jquery.tablesorter.widgets.js +0 -1390
  246. data/lib/flapjack/gateways/web/public/js/modules/contact.js +0 -520
  247. data/lib/flapjack/gateways/web/public/js/modules/entity.js +0 -28
  248. data/lib/flapjack/gateways/web/public/js/modules/medium.js +0 -40
  249. data/lib/flapjack/gateways/web/public/js/select2.js +0 -3397
  250. data/lib/flapjack/gateways/web/public/js/tablesort.js +0 -44
  251. data/lib/flapjack/gateways/web/public/js/underscore.js +0 -1276
  252. data/lib/flapjack/gateways/web/views/edit_contacts.html.erb +0 -173
  253. data/lib/flapjack/gateways/web/views/entities.html.erb +0 -30
  254. data/lib/flapjack/gateways/web/views/entity.html.erb +0 -51
  255. data/lib/flapjack/rack_logger.rb +0 -47
  256. data/lib/flapjack/redis_pool.rb +0 -42
  257. data/spec/lib/flapjack/data/entity_check_spec.rb +0 -1418
  258. data/spec/lib/flapjack/data/entity_spec.rb +0 -872
  259. data/spec/lib/flapjack/data/message_spec.rb +0 -30
  260. data/spec/lib/flapjack/data/migration_spec.rb +0 -104
  261. data/spec/lib/flapjack/data/notification_rule_spec.rb +0 -232
  262. data/spec/lib/flapjack/data/notification_spec.rb +0 -53
  263. data/spec/lib/flapjack/data/semaphore_spec.rb +0 -24
  264. data/spec/lib/flapjack/filters/acknowledgement_spec.rb +0 -6
  265. data/spec/lib/flapjack/filters/delays_spec.rb +0 -6
  266. data/spec/lib/flapjack/filters/ok_spec.rb +0 -6
  267. data/spec/lib/flapjack/filters/scheduled_maintenance_spec.rb +0 -6
  268. data/spec/lib/flapjack/filters/unscheduled_maintenance_spec.rb +0 -6
  269. data/spec/lib/flapjack/gateways/jsonapi/check_methods_spec.rb +0 -315
  270. data/spec/lib/flapjack/gateways/jsonapi/check_presenter_spec.rb +0 -223
  271. data/spec/lib/flapjack/gateways/jsonapi/contact_methods_spec.rb +0 -131
  272. data/spec/lib/flapjack/gateways/jsonapi/entity_methods_spec.rb +0 -389
  273. data/spec/lib/flapjack/gateways/jsonapi/medium_methods_spec.rb +0 -231
  274. data/spec/lib/flapjack/gateways/jsonapi/notification_rule_methods_spec.rb +0 -169
  275. data/spec/lib/flapjack/gateways/jsonapi/pagerduty_credential_methods_spec.rb +0 -114
  276. data/spec/lib/flapjack/gateways/jsonapi/report_methods_spec.rb +0 -590
  277. data/spec/lib/flapjack/gateways/pagerduty_spec.rb +0 -249
  278. data/spec/lib/flapjack/gateways/web/views/check.html.erb_spec.rb +0 -21
  279. data/spec/lib/flapjack/gateways/web/views/contact.html.erb_spec.rb +0 -24
  280. data/spec/lib/flapjack/gateways/web/views/index.html.erb_spec.rb +0 -16
  281. data/spec/lib/flapjack/redis_pool_spec.rb +0 -29
  282. data/spec/service_consumers/pacts/flapjack-diner_v1.0.json +0 -4702
  283. data/tasks/entities.rake +0 -151
  284. data/tasks/profile.rake +0 -282
  285. data/tmp/acknowledge.rb +0 -13
  286. data/tmp/create_config_yaml.rb +0 -16
  287. data/tmp/create_event_ok.rb +0 -30
  288. data/tmp/create_event_unknown.rb +0 -30
  289. data/tmp/create_events_failure.rb +0 -34
  290. data/tmp/create_events_ok.rb +0 -32
  291. data/tmp/create_events_ok_fail_ack_ok.rb +0 -53
  292. data/tmp/create_events_ok_failure.rb +0 -41
  293. data/tmp/create_events_ok_failure_ack.rb +0 -53
  294. data/tmp/dummy_contacts.json +0 -43
  295. data/tmp/dummy_entities.json +0 -37
  296. data/tmp/generate_nagios_test_hosts.rb +0 -16
  297. data/tmp/notification_rules.rb +0 -73
  298. data/tmp/parse_config_yaml.rb +0 -7
  299. data/tmp/redis_find_spurious_unknown_states.rb +0 -52
  300. data/tmp/test_json_post.rb +0 -19
  301. data/tmp/test_notification_rules_api.rb +0 -171
@@ -1,147 +1,110 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'digest'
4
-
5
3
  require 'active_support/inflector'
4
+
5
+ require 'zermelo/records/redis'
6
+
6
7
  require 'flapjack/utility'
7
8
 
9
+ require 'flapjack/data/condition'
10
+ require 'flapjack/data/state'
11
+
8
12
  # Alert is the object ready to send to someone, complete with an address and all
9
13
  # the data with which to render the text of the alert in the appropriate gateway
10
- #
11
- # It should possibly be renamed AlertPresenter
12
14
 
13
15
  module Flapjack
14
16
  module Data
15
17
  class Alert
16
18
 
17
- # from Flapjack::Data::Notification
18
- attr_reader :event_id,
19
- :state,
20
- :summary,
21
- :acknowledgement_duration,
22
- :last_state,
23
- :last_summary,
24
- :state_duration,
25
- :details,
26
- :time,
27
- :notification_type,
28
- :event_count,
29
- :tags
30
-
31
- # from Flapjack::Data::Message
32
- # :id,
33
- attr_reader :media,
34
- :address,
35
- :rollup,
36
- :contact_id,
37
- :contact_first_name,
38
- :contact_last_name
39
-
40
- # from Flapjack::Notifier
41
- attr_reader :rollup_threshold,
42
- :rollup_alerts,
43
- :in_scheduled_maintenance,
44
- :in_unscheduled_maintenance
45
-
46
- # from self
47
- attr_reader :entity,
48
- :check,
49
- :notification_id,
50
- :event_hash
51
-
52
19
  include Flapjack::Utility
53
-
54
- def initialize(contents, opts = {})
55
- raise "no logger supplied" unless @logger = opts[:logger]
56
-
57
- @event_id = contents['event_id']
58
- @event_hash = contents['event_hash'] ||
59
- Digest.hexencode(Digest::SHA1.new.digest(@event_id))[0..7].downcase
60
- @state = contents['state']
61
- @summary = contents['summary']
62
- @acknowledgement_duration = contents['duration'] # SMELLY
63
- @last_state = contents['last_state']
64
- @last_summary = contents['last_summary']
65
- @state_duration = contents['state_duration']
66
- @details = contents['details']
67
- @time = contents['time']
68
- @notification_type = contents['notification_type']
69
- @event_count = contents['event_count']
70
- @tags = contents['tags']
71
-
72
- @media = contents['media']
73
- @address = contents['address']
74
- @rollup = contents['rollup']
75
- @contact_id = contents['contact_id']
76
- @contact_first_name = contents['contact_first_name']
77
- @contact_last_name = contents['contact_last_name']
78
-
79
- @rollup_threshold = contents['rollup_threshold']
80
- @rollup_alerts = contents['rollup_alerts']
81
- @in_scheduled_maintenance = contents['in_scheduled_maintenance']
82
- @in_unscheduled_maintenance = contents['in_unscheduled_maintenance']
83
-
84
- @entity, @check = @event_id.split(':', 2)
85
- @notification_id = contents['id'] || SecureRandom.uuid
86
-
87
- allowed_states = ['ok', 'critical', 'warning', 'unknown', 'test_notifications', 'acknowledgement']
88
- allowed_rollup_states = ['critical', 'warning', 'unknown']
89
- raise "state #{@state.inspect} is invalid" unless
90
- allowed_states.include?(@state)
91
-
92
- if @state_duration
93
- raise "state_duration (#{@state_duration.inspect}) is invalid" unless
94
- @state_duration.is_a?(Integer) && @state_duration >= 0
95
- end
96
-
97
- if @rollup_alerts
98
- raise "rollup_alerts should be nil or a hash" unless @rollup_alerts.is_a?(Hash)
99
- @rollup_alerts.each_pair do |check, details|
100
- raise "duration of rollup_alerts['#{check}'] must be an integer" unless
101
- details['duration'] && details['duration'].is_a?(Integer)
102
- raise "state of rollup_alerts['#{check}'] is invalid" unless
103
- details['state'] && allowed_rollup_states.include?(details['state'])
20
+ include Zermelo::Records::RedisSet
21
+
22
+ define_attributes :condition => :string,
23
+ :action => :string,
24
+ :summary => :string,
25
+ :details => :string,
26
+ :last_condition => :string,
27
+ :last_action => :string,
28
+ :last_summary => :string,
29
+ :event_count => :integer,
30
+ :time => :timestamp,
31
+ :acknowledgement_duration => :integer, # passed in as duration in other code
32
+ :condition_duration => :float,
33
+ :rollup => :string,
34
+ :rollup_states_json => :string,
35
+ :event_hash => :string
36
+
37
+ belongs_to :medium, :class_name => 'Flapjack::Data::Medium', :inverse_of => :alerts
38
+
39
+ belongs_to :check, :class_name => 'Flapjack::Data::Check', :inverse_of => :alerts
40
+
41
+ validates :condition, :unless => proc {|s| !s.action.nil? },
42
+ :inclusion => { :in => Flapjack::Data::Condition.healthy.keys +
43
+ Flapjack::Data::Condition.unhealthy.keys }
44
+
45
+ validates :action, :allow_nil => true, :inclusion => {:in => Flapjack::Data::State::ACTIONS}
46
+
47
+ validates :condition_duration, :presence => true, :allow_nil => true,
48
+ :numericality => {:minimum => 0}, :unless => proc {|n| n.type == 'test'}
49
+
50
+ validates_each :rollup_states_json do |record, att, value|
51
+ unless value.nil?
52
+ states = Flapjack.load_json(value)
53
+ case states
54
+ when Hash
55
+ record.errors.add(att, 'must contain a serialized Hash (String => Array[String])') unless states.all? {|k,v|
56
+ k.is_a?(String) && v.is_a?(Array) && v.all?{|vs| vs.is_a?(String)}
57
+ }
58
+ else
59
+ record.errors.add(att, 'must contain a serialized Hash (String => Array[String])')
104
60
  end
105
61
  end
106
62
  end
107
63
 
108
- def self.add(queue, alert_data, opts = {})
109
- raise "Redis connection not set" unless redis = opts[:redis]
110
- redis.rpush(queue, Flapjack.dump_json(alert_data))
64
+ # TODO handle JSON exception
65
+ def rollup_states
66
+ if self.rollup_states_json.nil?
67
+ @rollup_states = nil
68
+ return
69
+ end
70
+ @rollup_states = Flapjack.load_json(self.rollup_states_json)
111
71
  end
112
72
 
113
- def self.next(queue, opts = {})
114
- raise "Redis connection not set" unless redis = opts[:redis]
73
+ def rollup_states=(rollup_states)
74
+ @rollup_states = rollup_states
75
+ self.rollup_states_json = rollup_states.nil? ? nil : Flapjack.dump_json(rollup_states)
76
+ end
115
77
 
116
- defaults = { :block => true }
117
- options = defaults.merge(opts)
78
+ def notification_type
79
+ self.class.notification_type(action, condition)
80
+ end
118
81
 
119
- if options[:block]
120
- raw = redis.blpop(queue, 0)[1]
121
- else
122
- raw = redis.lpop(queue)
123
- return unless raw
124
- end
125
- begin
126
- parsed = ::Flapjack.load_json( raw )
127
- rescue Oj::Error => e
128
- if options[:logger]
129
- options[:logger].warn("Error deserialising alert json: #{e}, raw json: #{raw.inspect}")
82
+ def self.notification_type(act, cond)
83
+ case act
84
+ when 'acknowledgement'
85
+ 'acknowledgement'
86
+ when /\Atest_notifications(?:\s+#{Flapjack::Data::Condition.unhealthy.keys.join('|')})?\z/
87
+ 'test'
88
+ when nil
89
+ case cond
90
+ when 'ok'
91
+ 'recovery'
92
+ when 'warning', 'critical', 'unknown'
93
+ 'problem'
94
+ else
95
+ 'unknown'
130
96
  end
131
- return nil
132
97
  end
133
- return if 'shutdown'.eql?(parsed['notification_type'])
134
- self.new( parsed, :logger => opts[:logger] )
135
98
  end
136
99
 
137
100
  def type
138
- case @rollup
101
+ case self.rollup
139
102
  when "problem"
140
103
  "rollup_problem"
141
104
  when "recovery"
142
105
  "rollup_recovery"
143
106
  else
144
- @notification_type
107
+ notification_type
145
108
  end
146
109
  end
147
110
 
@@ -156,61 +119,51 @@ module Flapjack
156
119
  end
157
120
  end
158
121
 
159
- def state_title_case
160
- ['ok'].include?(@state) ? @state.upcase : @state.titleize
122
+ def state
123
+ @state ||= (self.action || self.condition)
161
124
  end
162
125
 
163
- def last_state_title_case
164
- ['ok'].include?(@last_state) ? @last_state.upcase : @last_state.titleize
126
+ def last_state
127
+ @last_state ||= (self.last_action || self.last_condition)
165
128
  end
166
129
 
167
- def rollup_alerts_by_state
168
- ['critical', 'warning', 'unknown'].inject({}) do |memo, state|
169
- alerts = rollup_alerts.find_all {|alert| alert[1]['state'] == state}
170
- memo[state] = alerts
171
- memo
172
- end
130
+ def state_title_case
131
+ ['ok'].include?(state) ? state.upcase : state.titleize
173
132
  end
174
133
 
175
- def rollup_state_counts
176
- rollup_alerts.inject({}) do |memo, alert|
177
- memo[alert[1]['state']] = (memo[alert[1]['state']] || 0) + 1
178
- memo
179
- end
134
+ def last_state_title_case
135
+ ['ok'].include?(last_state) ? last_state.upcase : last_state.titleize
180
136
  end
181
137
 
182
138
  def rollup_states_summary
183
- state_counts = rollup_state_counts
184
- ['critical', 'warning', 'unknown'].inject([]) do |memo, state|
185
- next memo unless rollup_state_counts[state]
186
- memo << "#{state.titleize}: #{state_counts[state]}"
187
- memo
139
+ return '' if rollup_states.nil?
140
+ rollup_states.each_with_object([]) do |(alert_state, alerts), memo|
141
+ memo << "#{alert_state.titleize}: #{alerts.size}"
188
142
  end.join(', ')
189
143
  end
190
144
 
191
145
  # produces a textual list of checks that are failing broken down by state, eg:
192
146
  # Critical: 'PING' on 'foo-app-01.example.com', 'SSH' on 'foo-app-01.example.com';
193
147
  # Warning: 'Disk / Utilisation' on 'foo-app-02.example.com'
194
- def rollup_states_detail_text(opts)
148
+ def rollup_states_detail_text(opts = {})
149
+ return '' if rollup_states.nil?
195
150
  max_checks = opts[:max_checks_per_state]
196
- rollup_alerts_by_state.inject([]) do |memo, state|
197
- state_titleized = state[0].titleize
198
- alerts = max_checks && max_checks > 0 ? state[1][0..(max_checks - 1)] : state[1]
199
- next memo if alerts.empty?
200
- checks = alerts.map {|alert| alert[0]}
201
- checks << '...' if checks.length < rollup_state_counts[state[0]]
202
- memo << "#{state[0].titleize}: #{checks.join(', ')}"
203
- memo
151
+ rollup_states.each_with_object([]) do |(alert_state, alerts), memo|
152
+ alerts = alerts[0..(max_checks - 1)] unless max_checks.nil? || (max_checks <= 0)
153
+ next if alerts.empty?
154
+ alerts << '...' if alerts.size < rollup_states[alert_state].size
155
+ memo << "#{alert_state.titleize}: #{alerts.join(', ')}"
204
156
  end.join('; ')
205
157
  end
206
158
 
207
159
  def to_s
208
- msg = "Alert via #{media}:#{address} to contact #{contact_id} (#{contact_first_name} #{contact_last_name}): "
160
+ contact = medium.contact
161
+ msg = "Alert via #{medium.transport}:#{medium.address} to contact #{contact.id} (#{contact.name}): "
209
162
  msg += type_sentence_case
210
163
  if rollup
211
164
  msg += " - #{rollup_states_summary} (#{rollup_states_detail_text(:max_checks_per_state => 3)})"
212
165
  else
213
- msg += " - '#{check}' on #{entity}"
166
+ msg += " - '#{self.check.name}'"
214
167
  unless ['acknowledgement', 'test'].include?(type)
215
168
  msg += " is #{state_title_case}"
216
169
  end
@@ -223,20 +176,6 @@ module Flapjack
223
176
  end
224
177
  end
225
178
  end
226
-
227
- def record_send_success!
228
- @logger.info "Sent alert successfully: #{to_s}"
229
- end
230
-
231
- # TODO: perhaps move message send failure porting to this method
232
- # to avoid duplication in the gateways, and to more easily allow
233
- # better error reporting on message generation / send failure
234
- #def record_send_failure!(opts)
235
- # exception = opts[:exception]
236
- # message = opts[:message]
237
- # @logger.error "Error sending an alert! #{alert}"
238
- #end
239
-
240
179
  end
241
180
  end
242
181
  end
@@ -0,0 +1,611 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'digest'
4
+
5
+ require 'swagger/blocks'
6
+
7
+ require 'zermelo/records/redis'
8
+
9
+ require 'flapjack/data/extensions/short_name'
10
+ require 'flapjack/data/validators/id_validator'
11
+
12
+ require 'flapjack/data/condition'
13
+ require 'flapjack/data/state'
14
+ require 'flapjack/data/unscheduled_maintenance'
15
+
16
+ require 'flapjack/data/extensions/associations'
17
+ require 'flapjack/data/extensions/short_name'
18
+
19
+ require 'flapjack/gateways/jsonapi/data/join_descriptor'
20
+ require 'flapjack/gateways/jsonapi/data/method_descriptor'
21
+
22
+ module Flapjack
23
+ module Data
24
+ class Check
25
+
26
+ include Zermelo::Records::RedisSet
27
+ include ActiveModel::Serializers::JSON
28
+ self.include_root_in_json = false
29
+ include Swagger::Blocks
30
+
31
+ include Flapjack::Data::Extensions::Associations
32
+ include Flapjack::Data::Extensions::ShortName
33
+
34
+ define_attributes :name => :string,
35
+ :enabled => :boolean,
36
+ :ack_hash => :string,
37
+ :initial_failure_delay => :integer,
38
+ :repeat_failure_delay => :integer,
39
+ :notification_count => :integer,
40
+ :condition => :string,
41
+ :failing => :boolean,
42
+ :alertable => :boolean
43
+
44
+ index_by :enabled, :failing, :alertable
45
+ unique_index_by :name, :ack_hash
46
+
47
+ # TODO validate uniqueness of :name, :ack_hash
48
+
49
+ has_and_belongs_to_many :tags, :class_name => 'Flapjack::Data::Tag',
50
+ :inverse_of => :checks
51
+
52
+ has_sorted_set :scheduled_maintenances,
53
+ :class_name => 'Flapjack::Data::ScheduledMaintenance',
54
+ :key => :start_time, :order => :desc, :inverse_of => :check
55
+
56
+ has_sorted_set :unscheduled_maintenances,
57
+ :class_name => 'Flapjack::Data::UnscheduledMaintenance',
58
+ :key => :start_time, :order => :desc, :inverse_of => :check
59
+
60
+ has_sorted_set :states, :class_name => 'Flapjack::Data::State',
61
+ :key => :created_at, :order => :desc, :inverse_of => :check
62
+
63
+ # shortcut to expose the latest of the above to the API
64
+ has_one :current_state, :class_name => 'Flapjack::Data::State',
65
+ :inverse_of => :current_check
66
+
67
+ has_sorted_set :latest_notifications, :class_name => 'Flapjack::Data::State',
68
+ :key => :created_at, :order => :desc, :inverse_of => :latest_notifications_check,
69
+ :after_remove => :destroy_states
70
+
71
+ def self.destroy_states(check_id, *st_ids)
72
+ # states won't be deleted if still referenced elsewhere -- see the State
73
+ # before_destroy callback
74
+ Flapjack::Data::State.intersect(:id => st_ids).destroy_all
75
+ end
76
+
77
+ # the following associations are used internally, for the notification
78
+ # and alert queue inter-pikelet workflow
79
+ has_one :most_severe, :class_name => 'Flapjack::Data::State',
80
+ :inverse_of => :most_severe_check, :after_clear => :destroy_states
81
+
82
+ has_many :notifications, :class_name => 'Flapjack::Data::Notification',
83
+ :inverse_of => :check
84
+
85
+ has_many :alerts, :class_name => 'Flapjack::Data::Alert',
86
+ :inverse_of => :check
87
+
88
+ # this can be called from the API (with no args) or from notifier.rb
89
+ # (which will pass a severity to use, and an effective time)
90
+ def alerting_media(opts = {})
91
+ time = opts[:time] || Time.now
92
+ severity = opts[:severity] || self.condition
93
+
94
+ # return empty set if disabled, or in a maintenance period (for API only,
95
+ # these will have been checked already in processor if called by notifier)
96
+ if opts.empty?
97
+ unless self.enabled
98
+ return Flapjack::Data::Medium.empty
99
+ end
100
+
101
+ unless self.current_unscheduled_maintenance.nil?
102
+ return Flapjack::Data::Medium.empty
103
+ end
104
+
105
+ start_range = Zermelo::Filters::IndexRange.new(nil, time, :by_score => true)
106
+ end_range = Zermelo::Filters::IndexRange.new(time, nil, :by_score => true)
107
+
108
+ unless self.scheduled_maintenances.
109
+ intersect(:start_time => start_range, :end_time => end_range).empty?
110
+
111
+ return Flapjack::Data::Medium.empty
112
+ end
113
+ end
114
+
115
+ # determine matching acceptors
116
+ tag_ids = self.tags.ids
117
+
118
+ acceptor_ids = matching_rule_ids(tag_ids, :blackhole => false, :severity => severity)
119
+ acceptor_media_ids = Flapjack::Data::Rule.matching_media_ids(acceptor_ids,
120
+ :time => time)
121
+
122
+ return Flapjack::Data::Medium.empty if acceptor_media_ids.empty?
123
+
124
+ # and matching rejectors
125
+ rejector_ids = matching_rule_ids(tag_ids, :blackhole => true, :severity => severity)
126
+ rejector_media_ids = Flapjack::Data::Rule.matching_media_ids(rejector_ids,
127
+ :time => time)
128
+
129
+ unless rejector_media_ids.empty?
130
+ acceptor_media_ids -= rejector_media_ids
131
+ return Flapjack::Data::Medium.empty if acceptor_media_ids.empty?
132
+ end
133
+
134
+ Flapjack::Data::Medium.intersect(:id => acceptor_media_ids)
135
+ end
136
+
137
+ def contacts
138
+ # return empty set if disabled
139
+ return Flapjack::Data::Contact.empty unless self.enabled
140
+
141
+ # determine matching acceptors
142
+ tag_ids = self.tags.ids
143
+ time = Time.now
144
+
145
+ acceptor_ids = matching_rule_ids(tag_ids, :blackhole => false,)
146
+ acceptor_contact_ids = Flapjack::Data::Rule.matching_contact_ids(acceptor_ids,
147
+ :time => time)
148
+ return Flapjack::Data::Contact.empty if acceptor_contact_ids.empty?
149
+
150
+
151
+ # and matching rejectors
152
+ rejector_ids = matching_rule_ids(tag_ids, :blackhole => true)
153
+ rejector_contact_ids = Flapjack::Data::Rule.matching_contact_ids(rejector_ids,
154
+ :time => time)
155
+ unless rejector_contact_ids.empty?
156
+ acceptor_contact_ids -= rejector_contact_ids
157
+ return Flapjack::Data::Contact.empty if acceptor_contact_ids.empty?
158
+ end
159
+
160
+ Flapjack::Data::Contact.intersect(:id => acceptor_contact_ids)
161
+ end
162
+
163
+ def matching_rule_ids(tag_ids, opts = {})
164
+ severity = opts[:severity]
165
+ blackhole = opts[:blackhole]
166
+
167
+ matcher_by_strategy = {
168
+ 'global' => nil,
169
+ 'all_tags' => proc {|rule_tag_ids| (rule_tag_ids - tag_ids).empty? },
170
+ 'any_tag' => proc {|rule_tag_ids| !((rule_tag_ids & tag_ids).empty?) },
171
+ 'no_tag' => proc {|rule_tag_ids| (rule_tag_ids & tag_ids).empty? }
172
+ }
173
+
174
+ matcher_by_strategy.each_with_object(Set.new) do |(strategy, matcher), memo|
175
+ rules = Flapjack::Data::Rule.intersect(:enabled => true,
176
+ :blackhole => blackhole, :strategy => strategy)
177
+ unless severity.nil?
178
+ rules = rules.intersect(:conditions_list => [nil, /(?:^|,)#{severity}(?:,|$)/])
179
+ end
180
+
181
+ if matcher.nil?
182
+ memo.merge(rules.ids)
183
+ next
184
+ end
185
+
186
+ rules.associated_ids_for(:tags).each_pair do |rule_id, rule_tag_ids|
187
+ memo << rule_id if matcher.call(rule_tag_ids)
188
+ end
189
+ end
190
+ end
191
+
192
+ # end internal associations
193
+
194
+ validates :name, :presence => true
195
+ validates :enabled, :inclusion => {:in => [true, false]}
196
+
197
+ validates :condition, :presence => true, :unless => proc {|c| c.failing.nil? }
198
+ validates :failing, :inclusion => {:in => [true, false]},
199
+ :unless => proc {|c| c.condition.nil? }
200
+
201
+ validates :initial_failure_delay, :allow_nil => true,
202
+ :numericality => {:greater_than_or_equal_to => 0, :only_integer => true}
203
+
204
+ validates :repeat_failure_delay, :allow_nil => true,
205
+ :numericality => {:greater_than_or_equal_to => 0, :only_integer => true}
206
+
207
+ before_validation :create_ack_hash
208
+ validates :ack_hash, :presence => true
209
+
210
+ validates_with Flapjack::Data::Validators::IdValidator
211
+
212
+ attr_accessor :count
213
+
214
+ swagger_schema :Check do
215
+ key :required, [:id, :type, :name, :enabled, :initial_failure_delay,
216
+ :repeat_failure_delay, :failing]
217
+ property :id do
218
+ key :type, :string
219
+ key :format, :uuid
220
+ end
221
+ property :type do
222
+ key :type, :string
223
+ key :enum, [Flapjack::Data::Check.short_model_name.singular]
224
+ end
225
+ property :name do
226
+ key :type, :string
227
+ end
228
+ property :enabled do
229
+ key :type, :boolean
230
+ key :enum, [true, false]
231
+ end
232
+ property :initial_failure_delay do
233
+ key :type, :integer
234
+ end
235
+ property :repeat_failure_delay do
236
+ key :type, :integer
237
+ end
238
+ property :failing do
239
+ key :type, :boolean
240
+ key :enum, [true, false]
241
+ end
242
+ property :condition do
243
+ key :type, :string
244
+ key :enum, Flapjack::Data::Condition.healthy.keys +
245
+ Flapjack::Data::Condition.unhealthy.keys
246
+ end
247
+ property :ack_hash do
248
+ key :type, :string
249
+ end
250
+ property :relationships do
251
+ key :"$ref", :CheckLinks
252
+ end
253
+ end
254
+
255
+ swagger_schema :CheckLinks do
256
+ property :alerting_media do
257
+ key :"$ref", :MediaLinkage
258
+ end
259
+ property :contacts do
260
+ key :"$ref", :ContactsLinkage
261
+ end
262
+ property :current_scheduled_maintenances do
263
+ key :"$ref", :ScheduledMaintenancesLinkage
264
+ end
265
+ property :current_state do
266
+ key :"$ref", :StateLinkage
267
+ end
268
+ property :current_unscheduled_maintenance do
269
+ key :"$ref", :UnscheduledMaintenanceLinkage
270
+ end
271
+ property :latest_notifications do
272
+ key :"$ref", :StatesLinkage
273
+ end
274
+ property :scheduled_maintenances do
275
+ key :"$ref", :ScheduledMaintenancesLinkage
276
+ end
277
+ property :states do
278
+ key :"$ref", :StatesLinkage
279
+ end
280
+ property :tags do
281
+ key :"$ref", :TagsLinkage
282
+ end
283
+ property :unscheduled_maintenances do
284
+ key :"$ref", :UnscheduledMaintenancesLinkage
285
+ end
286
+ end
287
+
288
+ swagger_schema :CheckCreate do
289
+ key :required, [:type, :name, :enabled, :initial_failure_delay,
290
+ :repeat_failure_delay]
291
+ property :id do
292
+ key :type, :string
293
+ key :format, :uuid
294
+ end
295
+ property :type do
296
+ key :type, :string
297
+ key :enum, [Flapjack::Data::Check.short_model_name.singular]
298
+ end
299
+ property :name do
300
+ key :type, :string
301
+ end
302
+ property :enabled do
303
+ key :type, :boolean
304
+ key :enum, [true, false]
305
+ end
306
+ property :initial_failure_delay do
307
+ key :type, :integer
308
+ end
309
+ property :repeat_failure_delay do
310
+ key :type, :integer
311
+ end
312
+ property :relationships do
313
+ key :"$ref", :CheckCreateLinks
314
+ end
315
+ end
316
+
317
+ swagger_schema :CheckCreateLinks do
318
+ property :tags do
319
+ key :"$ref", :data_TagsReference
320
+ end
321
+ end
322
+
323
+ swagger_schema :CheckUpdate do
324
+ key :required, [:id, :type]
325
+ property :id do
326
+ key :type, :string
327
+ key :format, :uuid
328
+ end
329
+ property :type do
330
+ key :type, :string
331
+ key :enum, [Flapjack::Data::Check.short_model_name.singular]
332
+ end
333
+ property :name do
334
+ key :type, :string
335
+ end
336
+ property :enabled do
337
+ key :type, :boolean
338
+ key :enum, [true, false]
339
+ end
340
+ property :initial_failure_delay do
341
+ key :type, :integer
342
+ end
343
+ property :repeat_failure_delay do
344
+ key :type, :integer
345
+ end
346
+ property :relationships do
347
+ key :"$ref", :CheckUpdateLinks
348
+ end
349
+ end
350
+
351
+ swagger_schema :CheckUpdateLinks do
352
+ property :tags do
353
+ key :"$ref", :data_TagsReference
354
+ end
355
+ end
356
+
357
+ def self.swagger_included_classes
358
+ # hack -- hardcoding for now
359
+ [
360
+ Flapjack::Data::Check,
361
+ Flapjack::Data::Contact,
362
+ Flapjack::Data::Medium,
363
+ Flapjack::Data::Rule,
364
+ Flapjack::Data::ScheduledMaintenance,
365
+ Flapjack::Data::State,
366
+ Flapjack::Data::Tag,
367
+ Flapjack::Data::UnscheduledMaintenance
368
+ ]
369
+ end
370
+
371
+ def self.jsonapi_methods
372
+ @jsonapi_methods ||= {
373
+ :post => Flapjack::Gateways::JSONAPI::Data::MethodDescriptor.new(
374
+ :attributes => [:name, :enabled, :initial_failure_delay,
375
+ :repeat_failure_delay],
376
+ :descriptions => {
377
+ :singular => "Create a check.",
378
+ :multiple => "Create checks."
379
+ }
380
+ ),
381
+ :get => Flapjack::Gateways::JSONAPI::Data::MethodDescriptor.new(
382
+ :attributes => [:name, :enabled, :initial_failure_delay,
383
+ :repeat_failure_delay, :ack_hash, :failing, :condition],
384
+ :descriptions => {
385
+ :singular => "Returns data for a check.",
386
+ :multiple => "Returns data for multiple check records."
387
+ }
388
+ ),
389
+ :patch => Flapjack::Gateways::JSONAPI::Data::MethodDescriptor.new(
390
+ :attributes => [:name, :enabled, :initial_failure_delay,
391
+ :repeat_failure_delay],
392
+ :descriptions => {
393
+ :singular => "Update a check.",
394
+ :multiple => "Update checks."
395
+ }
396
+ ),
397
+ :delete => Flapjack::Gateways::JSONAPI::Data::MethodDescriptor.new(
398
+ :descriptions => {
399
+ :singular => "Delete a check.",
400
+ :multiple => "Delete checks."
401
+ }
402
+ )
403
+ }
404
+ end
405
+
406
+ def self.jsonapi_associations
407
+ unless instance_variable_defined?('@jsonapi_associations')
408
+ @jsonapi_associations = {
409
+ :alerting_media => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
410
+ :get => true,
411
+ :number => :multiple, :link => true, :includable => true,
412
+ :type => 'medium',
413
+ :klass => Flapjack::Data::Medium,
414
+ :callback_classes => [
415
+ Flapjack::Data::Contact,
416
+ Flapjack::Data::Rule,
417
+ Flapjack::Data::Tag,
418
+ Flapjack::Data::ScheduledMaintenance
419
+ ],
420
+ :descriptions => {
421
+ :get => "While this check is failing, returns media records " \
422
+ "which are receiving notifications during this failure."
423
+ }
424
+ ),
425
+ :contacts => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
426
+ :get => true,
427
+ :number => :multiple, :link => true, :includable => true,
428
+ :type => 'contact',
429
+ :klass => Flapjack::Data::Contact,
430
+ :callback_classes => [
431
+ Flapjack::Data::Rule,
432
+ Flapjack::Data::Tag
433
+ ],
434
+ :descriptions => {
435
+ :get => "Returns contacts whose notification rules will " \
436
+ "allow them to receive notifications for events on " \
437
+ "this check."
438
+ }
439
+ ),
440
+ :current_scheduled_maintenances => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
441
+ :get => true,
442
+ :number => :multiple, :link => true, :includable => true,
443
+ :type => 'scheduled_maintenance',
444
+ :klass => Flapjack::Data::ScheduledMaintenance,
445
+ :descriptions => {
446
+ :get => "Returns scheduled maintenance periods currently in " \
447
+ " effect for this check."
448
+ }
449
+ ),
450
+ :current_state => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
451
+ :get => true,
452
+ :number => :singular, :link => true, :includable => true,
453
+ :descriptions => {
454
+ :get => "Returns the current State record for this check."
455
+ }
456
+ ),
457
+ :current_unscheduled_maintenance => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
458
+ :get => true,
459
+ :number => :singular, :link => true, :includable => true,
460
+ :type => 'unscheduled_maintenance',
461
+ :klass => Flapjack::Data::UnscheduledMaintenance,
462
+ :descriptions => {
463
+ :get => "If the check is currently acknowledged, returns the " \
464
+ "unscheduled maintenance period created for that."
465
+ }
466
+ ),
467
+ :latest_notifications => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
468
+ :get => true,
469
+ :number => :multiple, :link => true, :includable => true,
470
+ :descriptions => {
471
+ :get => "Returns the most recent State records for each " \
472
+ "problem condition that produced notifications."
473
+ }
474
+ ),
475
+ :scheduled_maintenances => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
476
+ :get => true,
477
+ :number => :multiple, :link => true, :includable => false,
478
+ :descriptions => {
479
+ :get => "Returns all scheduled maintenance periods for the " \
480
+ "check; default sort order is newest first."
481
+ }
482
+ ),
483
+ :states => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
484
+ :get => true,
485
+ :number => :multiple, :link => true, :includable => false,
486
+ :descriptions => {
487
+ :get => "Returns all state records for the check; default " \
488
+ "sort order is newest first."
489
+ }
490
+ ),
491
+ :tags => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
492
+ :post => true, :get => true, :patch => true, :delete => true,
493
+ :number => :multiple, :link => true, :includable => true,
494
+ :descriptions => {
495
+ :post => "Associate tags with this check.",
496
+ :get => "Returns all tags linked to this check.",
497
+ :patch => "Update the tags associated with this check.",
498
+ :delete => "Delete associations between tags and this check."
499
+ }
500
+ ),
501
+ :unscheduled_maintenances => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
502
+ :get => true,
503
+ :number => :multiple, :link => true, :includable => false,
504
+ :descriptions => {
505
+ :get => "Returns all unscheduled maintenance periods for the " \
506
+ "check; default sort order is newest first."
507
+ }
508
+ )
509
+ }
510
+ populate_association_data(@jsonapi_associations)
511
+ end
512
+ @jsonapi_associations
513
+ end
514
+
515
+ def in_scheduled_maintenance?(t = Time.now)
516
+ !scheduled_maintenances_at(t).empty?
517
+ end
518
+
519
+ def current_scheduled_maintenances
520
+ scheduled_maintenances_at(Time.now)
521
+ end
522
+
523
+ def in_unscheduled_maintenance?(t = Time.now)
524
+ !unscheduled_maintenances_at(t).empty?
525
+ end
526
+
527
+ def current_unscheduled_maintenance
528
+ unscheduled_maintenances_at(Time.now).all.first
529
+ end
530
+
531
+ # TODO allow summary to be changed as part of the termination
532
+ def end_scheduled_maintenance(sched_maint, at_time)
533
+ at_time = Time.at(at_time) unless at_time.is_a?(Time)
534
+
535
+ if sched_maint.start_time >= at_time
536
+ # the scheduled maintenance period is in the future
537
+ self.scheduled_maintenances.remove(sched_maint)
538
+ sched_maint.destroy
539
+ return true
540
+ elsif sched_maint.end_time >= at_time
541
+ # it spans the current time, so we'll stop it at that point
542
+ sched_maint.end_time = at_time
543
+ sched_maint.save
544
+ return true
545
+ end
546
+
547
+ false
548
+ end
549
+
550
+ def set_unscheduled_maintenance(unsched_maint, options = {})
551
+ current_time = Time.now
552
+
553
+ self.class.lock(Flapjack::Data::UnscheduledMaintenance,
554
+ Flapjack::Data::State) do
555
+
556
+ self.alertable = false
557
+ self.save!
558
+
559
+ # time_remaining
560
+ if (unsched_maint.end_time - current_time) > 0
561
+ self.clear_unscheduled_maintenance(unsched_maint.start_time)
562
+ end
563
+
564
+ self.unscheduled_maintenances << unsched_maint
565
+ end
566
+ end
567
+
568
+ def clear_unscheduled_maintenance(end_time)
569
+ Flapjack::Data::UnscheduledMaintenance.lock do
570
+ t = Time.now
571
+ start_range = Zermelo::Filters::IndexRange.new(nil, t, :by_score => true)
572
+ end_range = Zermelo::Filters::IndexRange.new(t, nil, :by_score => true)
573
+ unsched_maints = self.unscheduled_maintenances.intersect(:start_time => start_range,
574
+ :end_time => end_range)
575
+ unsched_maints_count = unsched_maints.empty?
576
+ unless unsched_maints_count == 0
577
+ # FIXME log warning if count > 1
578
+ unsched_maints.each do |usm|
579
+ usm.end_time = end_time
580
+ usm.save
581
+ end
582
+ end
583
+ end
584
+ end
585
+
586
+ private
587
+
588
+ # would need to be "#{entity.name}:#{name}" to be compatible with v1, but
589
+ # to support name changes it must be something invariant
590
+ def create_ack_hash
591
+ return unless self.ack_hash.nil? # :on => :create isn't working
592
+ self.id = self.class.generate_id if self.id.nil?
593
+ self.ack_hash = Digest.hexencode(Digest::SHA1.new.digest(self.id))[0..7].downcase
594
+ end
595
+
596
+ def scheduled_maintenances_at(t)
597
+ start_range = Zermelo::Filters::IndexRange.new(nil, t, :by_score => true)
598
+ end_range = Zermelo::Filters::IndexRange.new(t, nil, :by_score => true)
599
+ self.scheduled_maintenances.intersect(:start_time => start_range,
600
+ :end_time => end_range)
601
+ end
602
+
603
+ def unscheduled_maintenances_at(t)
604
+ start_range = Zermelo::Filters::IndexRange.new(nil, t, :by_score => true)
605
+ end_range = Zermelo::Filters::IndexRange.new(t, nil, :by_score => true)
606
+ self.unscheduled_maintenances.intersect(:start_time => start_range,
607
+ :end_time => end_range)
608
+ end
609
+ end
610
+ end
611
+ end