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
@@ -5,71 +5,79 @@ Feature: notifications
5
5
 
6
6
  # TODO test across multiple contacts
7
7
 
8
- Scenario: Queue an SMS notification
9
- Given the user wants to receive SMS notifications for entity 'example.com'
10
- When an event notification is generated for entity 'example.com'
11
- Then an SMS notification for entity 'example.com' should be queued for the user
12
- And an email notification for entity 'example.com' should not be queued for the user
8
+ Scenario: Queue an SMS alert
9
+ Given the user wants to receive SMS alerts for check 'example.com:PING'
10
+ When an event notification is generated for check 'example.com:PING'
11
+ Then an SMS alert for check 'example.com:PING' should be queued
12
+ And an email alert for check 'example.com:PING' should not be queued
13
13
 
14
- Scenario: Queue a Nexmo SMS notification
15
- Given the user wants to receive Nexmo SMS notifications for entity 'example.com'
16
- When an event notification is generated for entity 'example.com'
17
- Then a Nexmo SMS notification for entity 'example.com' should be queued for the user
18
- And an email notification for entity 'example.com' should not be queued for the user
19
- And an SMS notification for entity 'example.com' should not be queued for the user
14
+ Scenario: Queue a Nexmo alert
15
+ Given the user wants to receive Nexmo alerts for check 'example.com:PING'
16
+ When an event notification is generated for check 'example.com:PING'
17
+ Then a Nexmo alert for check 'example.com:PING' should be queued
18
+ And an email alert for check 'example.com:PING' should not be queued
19
+ And an SMS alert for check 'example.com:PING' should not be queued
20
20
 
21
- Scenario: Queue an SNS notification
22
- Given the user wants to receive SNS notifications for entity 'example.com'
23
- When an event notification is generated for entity 'example.com'
24
- Then an SNS notification for entity 'example.com' should be queued for the user
25
- And an email notification for entity 'example.com' should not be queued for the user
21
+ Scenario: Queue an SNS alert
22
+ Given the user wants to receive SNS alerts for check 'example.com:PING'
23
+ When an event notification is generated for check 'example.com:PING'
24
+ Then an SNS alert for check 'example.com:PING' should be queued
25
+ And an email alert for check 'example.com:PING' should not be queued
26
26
 
27
- Scenario: Queue an email notification
28
- Given the user wants to receive email notifications for entity 'example.com'
29
- When an event notification is generated for entity 'example.com'
30
- Then an email notification for entity 'example.com' should be queued for the user
31
- And an SMS notification for entity 'example.com' should not be queued for the user
27
+ Scenario: Queue an email alert
28
+ Given the user wants to receive email alerts for check 'example.com:PING'
29
+ When an event notification is generated for check 'example.com:PING'
30
+ Then an email alert for check 'example.com:PING' should be queued
31
+ And an SMS alert for check 'example.com:PING' should not be queued
32
32
 
33
- Scenario: Queue SMS and email notifications
34
- Given the user wants to receive SMS notifications for entity 'example.com' and email notifications for entity 'example2.com'
35
- When an event notification is generated for entity 'example.com'
36
- And an event notification is generated for entity 'example2.com'
37
- Then an SMS notification for entity 'example.com' should be queued for the user
38
- And an SMS notification for entity 'example2.com' should not be queued for the user
39
- Then an email notification for entity 'example.com' should not be queued for the user
40
- And an email notification for entity 'example2.com' should be queued for the user
33
+ Scenario: Queue SMS and email alerts
34
+ Given a user wants to receive SMS alerts for check 'example.com:PING'
35
+ And a user wants to receive email alerts for check 'example2.com:SSH'
36
+ When an event notification is generated for check 'example.com:PING'
37
+ And an event notification is generated for check 'example2.com:SSH'
38
+ Then an SMS alert for check 'example.com:PING' should be queued
39
+ And an SMS alert for check 'example2.com:SSH' should not be queued
40
+ Then an email alert for check 'example.com:PING' should not be queued
41
+ And an email alert for check 'example2.com:SSH' should be queued
41
42
 
42
- Scenario: Send a queued SMS notification
43
- Given a user SMS notification has been queued for entity 'example.com'
44
- When the SMS notification handler runs successfully
45
- Then the user should receive an SMS notification
43
+ Scenario: Send a queued SMS alert
44
+ Given a user wants to receive SMS alerts for check 'example.com:PING'
45
+ And an SMS alert has been queued for check 'example.com:PING'
46
+ When the SMS alert handler runs successfully
47
+ Then the user should receive an SMS alert
46
48
 
47
- Scenario: Send a queued Nexmo SMS notification
48
- Given a user Nexmo SMS notification has been queued for entity 'example.com'
49
- When the Nexmo SMS notification handler runs successfully
50
- Then the user should receive an Nexmo SMS notification
49
+ Scenario: Send a queued Nexmo alert
50
+ Given a user wants to receive Nexmo alerts for check 'example.com:PING'
51
+ And a Nexmo alert has been queued for check 'example.com:PING'
52
+ When the Nexmo alert handler runs successfully
53
+ Then the user should receive a Nexmo alert
51
54
 
52
- Scenario: Send a queued SNS notification
53
- Given a user SNS notification has been queued for entity 'example.com'
54
- When the SNS notification handler runs successfully
55
- Then the user should receive an SNS notification
55
+ Scenario: Send a queued SNS alert
56
+ Given a user wants to receive SNS alerts for check 'example.com:PING'
57
+ And an SNS alert has been queued for check 'example.com:PING'
58
+ When the SNS alert handler runs successfully
59
+ Then the user should receive an SNS alert
56
60
 
57
- Scenario: Handle a failure to send a queued SMS notification
58
- Given a user SMS notification has been queued for entity 'example.com'
59
- When the SMS notification handler fails to send an SMS
60
- Then the user should not receive an SMS notification
61
+ Scenario: Handle a failure to send a queued SMS alert
62
+ Given a user wants to receive SMS alerts for check 'example.com:PING'
63
+ And an SMS alert has been queued for check 'example.com:PING'
64
+ When the SMS alert handler fails to send an SMS
65
+ Then the user should not receive an SMS alert
61
66
 
62
- Scenario: Handle a failure to send a queued SNS notification
63
- Given a user SNS notification has been queued for entity 'example.com'
64
- When the SNS notification handler fails to send an SMS
65
- Then the user should not receive an SNS notification
67
+ Scenario: Handle a failure to send a queued SNS alert
68
+ Given a user wants to receive SNS alerts for check 'example.com:PING'
69
+ And an SNS alert has been queued for check 'example.com:PING'
70
+ When the SNS alert handler fails to send an SMS
71
+ Then the user should not receive an SNS alert
66
72
 
67
- Scenario: Send a queued email notification
68
- Given a user email notification has been queued for entity 'example.com'
69
- When the email notification handler runs successfully
70
- Then the user should receive an email notification
73
+ Scenario: Send a queued email alert
74
+ Given a user wants to receive email alerts for check 'example.com:PING'
75
+ And an email alert has been queued for check 'example.com:PING'
76
+ When the email alert handler runs successfully
77
+ Then the user should receive an email alert
71
78
 
72
- Scenario: Handle a failure to send a queued email notification
73
- Given a user email notification has been queued for entity 'example.com'
74
- When the email notification handler fails to send an email
75
- Then the user should not receive an email notification
79
+ Scenario: Handle a failure to send a queued email alert
80
+ Given a user wants to receive email alerts for check 'example.com:PING'
81
+ And an email alert has been queued for check 'example.com:PING'
82
+ When the email alert handler fails to send an email
83
+ Then the user should not receive an email alert
@@ -1,27 +1,27 @@
1
- @rollup @notification_rules @processor @notifier @events
1
+ @rollup @notification_rules @resque @processor @notifier @events
2
2
  Feature: Rollup on a per contact, per media basis
3
3
 
4
4
  Background:
5
- Given the following users exist:
6
- | id | first_name | last_name | email | sms | timezone |
7
- | 1 | Malak | Al-Musawi | malak@example.com | +61400000001 | Asia/Baghdad |
5
+ Given the following contacts exist:
6
+ | id | name | timezone |
7
+ | 7f96a216-76aa-45fc-a88e-7431cd6d7aac | Malak Al-Musawi | Asia/Baghdad |
8
8
 
9
- And the following entities exist:
10
- | id | name | contacts |
11
- | 1 | foo | 1 |
12
- | 2 | baz | 1 |
9
+ And the following media exist:
10
+ | id | contact_id | transport | address | interval | rollup_threshold |
11
+ | 28032dbf-388d-4f52-91b2-dc5e5be2becc | 7f96a216-76aa-45fc-a88e-7431cd6d7aac | email | malak@example.com | 15 | 1 |
12
+ | 73e2803f-948e-467a-a707-37b9f53ee21a | 7f96a216-76aa-45fc-a88e-7431cd6d7aac | sms | +61400000001 | 15 | 2 |
13
13
 
14
- And user 1 has the following notification intervals:
15
- | email | sms |
16
- | 15 | 15 |
14
+ And the following checks exist:
15
+ | id | name | tags |
16
+ | 56c13ce2-f246-4bc6-adfa-2206789c3ced | foo:ping | foo,ping |
17
+ | d1a39575-0480-4f65-a7f7-64c90db93731 | baz:ping | baz,ping |
17
18
 
18
- And user 1 has the following notification rollup thresholds:
19
- | email | sms |
20
- | 1 | 2 |
21
-
22
- And user 1 has the following notification rules:
23
- | entities | unknown_media | warning_media | critical_media |
24
- | | | email | sms,email |
19
+ And the following rules exist:
20
+ | id | contact_id | blackhole | strategy | tags | condition | time_restriction | media_ids |
21
+ | b0c8deb9-b8c8-4fdd-acc4-72493852ca15 | 7f96a216-76aa-45fc-a88e-7431cd6d7aac | false | all_tags | foo,ping | critical | | 28032dbf-388d-4f52-91b2-dc5e5be2becc,73e2803f-948e-467a-a707-37b9f53ee21a |
22
+ | b18e9f48-59e7-4c25-b94c-d4ebd4a6559a | 7f96a216-76aa-45fc-a88e-7431cd6d7aac | false | all_tags | foo,ping | warning | | 28032dbf-388d-4f52-91b2-dc5e5be2becc |
23
+ | 2df6bbc4-d6a4-4f23-b6e5-5c4a07c6e686 | 7f96a216-76aa-45fc-a88e-7431cd6d7aac | false | all_tags | baz,ping | critical | | 28032dbf-388d-4f52-91b2-dc5e5be2becc,73e2803f-948e-467a-a707-37b9f53ee21a |
24
+ | f163bf33-b53e-4138-ab27-1dd89f2d6fdd | 7f96a216-76aa-45fc-a88e-7431cd6d7aac | false | all_tags | baz,ping | warning | | 28032dbf-388d-4f52-91b2-dc5e5be2becc |
25
25
 
26
26
  @time
27
27
  Scenario: Rollup threshold of 1 means first alert is a rollup
@@ -140,7 +140,8 @@ Feature: Rollup on a per contact, per media basis
140
140
  Scenario: Unscheduled maintenance ending promotes rollup
141
141
  Given check 'ping' for entity 'foo' is in unscheduled maintenance
142
142
  And check 'ping' for entity 'baz' is in an ok state
143
- When a critical event is received for check 'ping' on entity 'foo'
143
+ When 1 minute passes
144
+ And a critical event is received for check 'ping' on entity 'foo'
144
145
  And 1 minute passes
145
146
  And a critical event is received for check 'ping' on entity 'foo'
146
147
  Then 0 sms alerts should be queued for +61400000001
@@ -155,26 +156,6 @@ Feature: Rollup on a per contact, per media basis
155
156
  Then 1 sms alert of type problem and rollup problem should be queued for +61400000001
156
157
  And 2 sms alerts should be queued for +61400000001
157
158
 
158
- @time
159
- Scenario: Scheduled maintenance ending promotes rollup
160
- Given check 'ping' for entity 'foo' is in an ok state
161
- Given check 'ping' for entity 'foo' is in scheduled maintenance for 4 hours
162
- And check 'ping' for entity 'baz' is in an ok state
163
- When a critical event is received for check 'ping' on entity 'foo'
164
- And 1 minute passes
165
- And a critical event is received for check 'ping' on entity 'foo'
166
- Then 0 sms alerts should be queued for +61400000001
167
- When 5 minutes passes
168
- And a critical event is received for check 'ping' on entity 'baz'
169
- And 1 minute passes
170
- And a critical event is received for check 'ping' on entity 'baz'
171
- Then 1 sms alert of type problem and rollup none should be queued for +61400000001
172
- And 1 sms alerts should be queued for +61400000001
173
- When 4 hours passes
174
- And a critical event is received for check 'ping' on entity 'foo'
175
- Then 2 sms alerts should be queued for +61400000001
176
- And 1 sms alert of type problem and rollup problem should be queued for +61400000001
177
-
178
159
  @time
179
160
  Scenario: Disabling a failing check suppresses rollup
180
161
  Given check 'ping' for entity 'foo' is in an ok state
@@ -209,20 +190,38 @@ Feature: Rollup on a per contact, per media basis
209
190
  And a critical event is received for check 'ping' on entity 'baz'
210
191
  And 1 minute passes
211
192
  And a critical event is received for check 'ping' on entity 'baz'
212
- Then 2 sms alerts should be queued for +61400000001
193
+ Then 1 sms alerts should be queued for +61400000001
213
194
  Then 1 sms alert of type problem and rollup none should be queued for +61400000001
214
- Then 1 sms alert of type problem and rollup recovery should be queued for +61400000001
215
195
  When 1 hour passes
216
196
  And check 'ping' on entity 'foo' is enabled
217
197
  And 5 minutes passes
218
198
  And a critical event is received for check 'ping' on entity 'foo'
219
- Then 3 sms alerts should be queued for +61400000001
199
+ Then 2 sms alerts should be queued for +61400000001
220
200
  Then 1 sms alert of type problem and rollup none should be queued for +61400000001
221
- Then 1 sms alert of type problem and rollup recovery should be queued for +61400000001
222
201
  And 1 sms alert of type problem and rollup problem should be queued for +61400000001
223
202
 
224
203
  @time
225
- Scenario: Contact ceases to be a contact on an entity that they were being alerted for
204
+ Scenario: Scheduled maintenance ending promotes rollup
205
+ Given check 'ping' for entity 'foo' is in an ok state
206
+ Given check 'ping' for entity 'foo' is in scheduled maintenance for 4 hours
207
+ And check 'ping' for entity 'baz' is in an ok state
208
+ When a critical event is received for check 'ping' on entity 'foo'
209
+ And 1 minute passes
210
+ And a critical event is received for check 'ping' on entity 'foo'
211
+ Then 0 sms alerts should be queued for +61400000001
212
+ When 5 minutes passes
213
+ And a critical event is received for check 'ping' on entity 'baz'
214
+ And 1 minute passes
215
+ And a critical event is received for check 'ping' on entity 'baz'
216
+ Then 1 sms alert of type problem and rollup none should be queued for +61400000001
217
+ And 1 sms alerts should be queued for +61400000001
218
+ When 4 hours passes
219
+ And a critical event is received for check 'ping' on entity 'foo'
220
+ Then 2 sms alerts should be queued for +61400000001
221
+ And 1 sms alert of type problem and rollup problem should be queued for +61400000001
222
+
223
+ @time
224
+ Scenario: Contact removes a rule matching on a check
226
225
  Given check 'ping' for entity 'foo' is in an ok state
227
226
  And check 'ping' for entity 'baz' is in an ok state
228
227
  When a critical event is received for check 'ping' on entity 'foo'
@@ -237,7 +236,7 @@ Feature: Rollup on a per contact, per media basis
237
236
  And 1 sms alerts of type problem and rollup none should be queued for +61400000001
238
237
  And 2 sms alerts should be queued for +61400000001
239
238
  When 20 minute passes
240
- And user 1 ceases to be a contact of entity 'foo'
239
+ And the rule with id 'b0c8deb9-b8c8-4fdd-acc4-72493852ca15' is removed
241
240
  And a critical event is received for check 'ping' on entity 'baz'
242
241
  Then 1 sms alert of rollup recovery should be queued for +61400000001
243
242
 
@@ -249,9 +248,8 @@ Feature: Rollup on a per contact, per media basis
249
248
  And 1 minute passes
250
249
  And a critical event is received for check 'ping' on entity 'foo'
251
250
  Then 1 sms alert of type problem and rollup none should be queued for +61400000001
252
- And 1 sms alert should be queued for +61400000001
253
251
  When 1 minute passes
254
- And a test event is received for check 'sausage' on entity 'foo'
252
+ And a test event is received for check 'ping' on entity 'foo'
255
253
  Then 1 sms alert of type problem and rollup none should be queued for +61400000001
256
254
  And 1 sms alert of type test and rollup none should be queued for +61400000001
257
255
  And 2 sms alerts should be queued for +61400000001
@@ -11,20 +11,19 @@ Given /^a fifo named "([^"]*)" exists$/ do |fifo_name|
11
11
  create_fifo(fifo_name)
12
12
  end
13
13
 
14
- When /^I ((?:re)?start|stop) (\S+)( \(daemonised\))?( \(via bundle exec\))? with `(.+)`$/ do |start_stop_restart, exe, daemonise, bundle_exec, cmd|
14
+ When /^I ((?:re)?start|stop) (\S+)( \(via bundle exec\))? with `(.+)`$/ do |start_stop_restart, exe, bundle_exec, cmd|
15
15
  @daemons_output ||= []
16
16
  @daemons_exit_status ||= []
17
17
 
18
18
  @root = Pathname.new(File.dirname(__FILE__)).parent.parent.expand_path
19
19
  command = "#{bundle_exec ? 'bundle exec ' : ''}#{@root.join('bin')}/#{cmd}"
20
20
 
21
- # enable debugging output from spawn_process etc
22
- #@debug = true
21
+ # # enable debugging output from spawn_process etc
22
+ # @debug = true
23
23
 
24
24
  case start_stop_restart
25
25
  when 'start'
26
- @process_h = spawn_process(command,
27
- :daemon_pidfile => (daemonise.nil? || daemonise.empty?) ? nil : "tmp/cucumber_cli/#{exe}.pid")
26
+ @process_h = spawn_process(command)
28
27
  when 'stop', 'restart'
29
28
  @daemons_output << `#{command}`
30
29
  @daemons_exit_status << $?
@@ -1,466 +1,256 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  def drain_events
4
- loop do
5
- event = Flapjack::Data::Event.next('events', :block => false,
6
- :redis => @redis)
7
- break unless event
4
+ @processor.send(:foreach_on_queue, 'events') do |event|
8
5
  @processor.send(:process_event, event)
9
6
  end
10
7
  drain_notifications
11
8
  end
12
9
 
13
10
  def drain_notifications
14
- return unless @notifier_redis
15
- loop do
16
- notification = Flapjack::Data::Notification.next('notifications',
17
- :block => false, :redis => @notifier_redis)
18
- break unless notification
11
+ return unless @notifier
12
+ @notifier.instance_variable_get('@queue').send(:foreach) do |notification|
19
13
  @notifier.send(:process_notification, notification)
20
14
  end
21
15
  end
22
16
 
23
- def drain_alerts(queue, gateway)
24
- return unless @notifier_redis
25
- loop do
26
- alert = Flapjack::Data::Alert.next(queue, :block => false,
27
- :redis => @notifier_redis, :logger => @logger)
28
- break unless alert
29
- gateway.send(:deliver, alert)
30
- end
31
- end
17
+ def set_scheduled_maintenance(entity_name, check_name, duration)
18
+ check = Flapjack::Data::Check.intersect(:name => "#{entity_name}:#{check_name}").all.first
19
+ expect(check).not_to be_nil
32
20
 
33
- def submit_event(event)
34
- @redis.rpush('events', Flapjack.dump_json(event))
21
+ t = Time.now
22
+ sched_maint = Flapjack::Data::ScheduledMaintenance.new(:start_time => Time.at(t.to_i - 60),
23
+ :end_time => Time.at(t.to_i + duration), :summary => 'upgrading everything')
24
+ expect(sched_maint.save).to be true
25
+ check.scheduled_maintenances << sched_maint
35
26
  end
36
27
 
37
- def set_scheduled_maintenance(entity, check, duration)
38
- entity_check = Flapjack::Data::EntityCheck.for_entity_name(entity, check, :redis => @redis)
39
- t = Time.now.to_i
40
- entity_check.create_scheduled_maintenance(t, duration, :summary => "upgrading everything")
41
- @redis.setex("#{entity}:#{check}:scheduled_maintenance", duration, t)
42
- end
28
+ def remove_scheduled_maintenance(entity_name, check_name)
29
+ check = Flapjack::Data::Check.intersect(:name => "#{entity_name}:#{check_name}").all.first
30
+ expect(check).not_to be_nil
43
31
 
44
- def remove_scheduled_maintenance(entity, check)
45
- entity_check = Flapjack::Data::EntityCheck.for_entity_name(entity, check, :redis => @redis)
46
- sm = entity_check.maintenances(nil, nil, :scheduled => true)
47
- sm.each do |m|
48
- entity_check.end_scheduled_maintenance(m[:start_time])
32
+ t = Time.now
33
+ check.scheduled_maintenances.each do |sm|
34
+ check.end_scheduled_maintenance(sm, t)
35
+ sched_maint.destroy
49
36
  end
50
37
  end
51
38
 
52
- def remove_unscheduled_maintenance(entity, check)
53
- # end any unscheduled downtime
54
- event_id = entity + ":" + check
55
- if (um_start = @redis.get("#{event_id}:unscheduled_maintenance"))
56
- @redis.del("#{event_id}:unscheduled_maintenance")
57
- duration = Time.now.to_i - um_start.to_i
58
- @redis.zadd("#{event_id}:unscheduled_maintenances", duration, um_start)
59
- end
60
- end
39
+ def set_unscheduled_maintenance(entity_name, check_name, duration)
40
+ check = Flapjack::Data::Check.intersect(:name => "#{entity_name}:#{check_name}").all.first
41
+ expect(check).not_to be_nil
61
42
 
62
- def remove_notifications(entity, check)
63
- event_id = entity + ":" + check
64
- @redis.del("#{event_id}:last_problem_notification")
65
- @redis.del("#{event_id}:last_recovery_notification")
66
- @redis.del("#{event_id}:last_acknowledgement_notification")
43
+ t = Time.now
44
+ unsched_maint = Flapjack::Data::UnscheduledMaintenance.new(:start_time => t,
45
+ :end_time => Time.at(t.to_i + duration), :summary => 'fixing now')
46
+ expect(unsched_maint.save).to be true
47
+ check.set_unscheduled_maintenance(unsched_maint)
67
48
  end
68
49
 
69
- def set_ok_state(entity, check)
70
- entity_check = Flapjack::Data::EntityCheck.for_entity_name(entity, check, :redis => @redis)
71
- entity_check.update_state(Flapjack::Data::EntityCheck::STATE_OK,
72
- :timestamp => (Time.now.to_i - (60*60*24)))
73
- end
50
+ def clear_unscheduled_maintenance(entity_name, check_name)
51
+ check = Flapjack::Data::Check.intersect(:name => "#{entity_name}:#{check_name}").all.first
52
+ expect(check).not_to be_nil
74
53
 
75
- def set_critical_state(entity, check)
76
- entity_check = Flapjack::Data::EntityCheck.for_entity_name(entity, check, :redis => @redis)
77
- entity_check.update_state(Flapjack::Data::EntityCheck::STATE_CRITICAL,
78
- :timestamp => (Time.now.to_i - (60*60*24)))
54
+ check.clear_unscheduled_maintenance(Time.now)
79
55
  end
80
56
 
81
- def set_warning_state(entity, check)
82
- entity_check = Flapjack::Data::EntityCheck.for_entity_name(entity, check, :redis => @redis)
83
- entity_check.update_state(Flapjack::Data::EntityCheck::STATE_WARNING,
84
- :timestamp => (Time.now.to_i - (60*60*24)))
85
- end
57
+ def set_state(entity_name, check_name, condition, last_update = Time.now)
58
+ check = Flapjack::Data::Check.intersect(:name => "#{entity_name}:#{check_name}").all.first
59
+ expect(check).not_to be_nil
86
60
 
87
- def end_unscheduled_maintenance(entity, check)
88
- entity_check = Flapjack::Data::EntityCheck.for_entity_name(entity, check, :redis => @redis)
89
- entity_check.end_unscheduled_maintenance(Time.now.to_i)
61
+ state = Flapjack::Data::State.new(:created_at => last_update, :updated_at => last_update,
62
+ :condition => condition)
63
+ state.save
64
+ check.states << state
90
65
  end
91
66
 
92
- def submit_ok(entity, check)
93
- event = {
94
- 'type' => 'service',
95
- 'state' => 'ok',
96
- 'summary' => '0% packet loss',
97
- 'entity' => entity,
98
- 'check' => check
99
- }
100
- submit_event(event)
101
- end
102
-
103
- def submit_warning(entity, check)
104
- event = {
105
- 'type' => 'service',
106
- 'state' => 'warning',
107
- 'summary' => '25% packet loss',
108
- 'entity' => entity,
109
- 'check' => check
110
- }
111
- submit_event(event)
112
- end
113
-
114
- def submit_critical(entity, check)
115
- event = {
116
- 'type' => 'service',
117
- 'state' => 'critical',
118
- 'summary' => '100% packet loss',
119
- 'entity' => entity,
120
- 'check' => check
121
- }
122
- submit_event(event)
123
- end
124
-
125
- def submit_unknown(entity, check)
67
+ def submit_event(condition, entity_name, check_name, opts = {})
68
+ err_rate = case condition
69
+ when 'ok'
70
+ '0'
71
+ when 'warning'
72
+ '25'
73
+ when 'critical'
74
+ '100'
75
+ end
126
76
  event = {
127
77
  'type' => 'service',
128
- 'state' => 'unknown',
129
- 'summary' => 'check execution error',
130
- 'entity' => entity,
131
- 'check' => check
78
+ 'state' => condition,
79
+ 'summary' => "#{err_rate}% packet loss",
80
+ 'entity' => entity_name,
81
+ 'check' => check_name,
132
82
  }
133
- submit_event(event)
83
+ ['initial', 'repeat'].each do |delay_type|
84
+ delay_key = "#{delay_type}_failure_delay".to_sym
85
+ event.update(delay_key => opts[delay_key]) unless opts[delay_key].nil?
86
+ end
87
+ Flapjack.redis.rpush('events', Flapjack.dump_json(event))
134
88
  end
135
89
 
136
- def submit_acknowledgement(entity, check)
90
+ def submit_acknowledgement(entity_name, check_name)
137
91
  event = {
138
- 'type' => 'action',
139
- 'state' => 'acknowledgement',
140
- 'summary' => "I'll have this fixed in a jiffy, saw the same thing yesterday",
141
- 'entity' => entity,
142
- 'check' => check
92
+ 'type' => 'action',
93
+ 'state' => 'acknowledgement',
94
+ 'summary' => "I'll have this fixed in a jiffy, saw the same thing yesterday",
95
+ 'entity' => entity_name,
96
+ 'check' => check_name,
143
97
  }
144
- submit_event(event)
98
+ Flapjack.redis.rpush('events', Flapjack.dump_json(event))
145
99
  end
146
100
 
147
- def submit_test(entity, check)
101
+ def submit_test(entity_name, check_name)
148
102
  event = {
149
- 'type' => 'action',
150
- 'state' => 'test_notifications',
151
- 'summary' => "test notification for all contacts interested in #{entity}",
152
- 'entity' => entity,
153
- 'check' => check
154
- }
155
- submit_event(event)
156
- end
157
-
158
- def icecube_schedule_to_time_restriction(sched, time_zone)
159
- tr = sched.to_hash
160
- tr[:start_time] = {:time => time_zone.utc_to_local(tr[:start_time][:time]).strftime("%Y-%m-%d %H:%M:%S"), :zone => time_zone}
161
- tr[:end_time] = {:time => time_zone.utc_to_local(tr[:end_time][:time]).strftime("%Y-%m-%d %H:%M:%S"), :zone => time_zone}
162
-
163
- # rewrite IceCube::WeeklyRule to Weekly, etc
164
- tr[:rrules].each {|rrule|
165
- rrule[:rule_type] = /^.*\:\:(.*)Rule$/.match(rrule[:rule_type])[1]
103
+ 'type' => 'action',
104
+ 'state' => 'test_notifications',
105
+ 'summary' => "test notification for all contacts interested in #{entity_name}",
106
+ 'entity' => entity_name,
107
+ 'check' => check_name,
166
108
  }
167
-
168
- tr
169
- end
170
-
171
- Given /^an entity '([\w\.\-]+)' exists$/ do |entity|
172
- Flapjack::Data::Entity.add({'id' => '5000',
173
- 'name' => entity},
174
- :redis => @redis )
175
- end
176
-
177
- Given /^the check is check '(.*)' on entity '([\w\.\-]+)'$/ do |check, entity|
178
- @check = check
179
- @entity = entity
109
+ Flapjack.redis.rpush('events', Flapjack.dump_json(event))
180
110
  end
181
111
 
182
- Given /^(?:the check|check '([\w\.\-]+)' for entity '([\w\.\-]+)') has no state$/ do |check, entity|
183
- check ||= @check
184
- entity ||= @entity
185
- remove_unscheduled_maintenance(entity, check)
186
- remove_scheduled_maintenance(entity, check)
187
- remove_notifications(entity, check)
188
- @redis.hdel("check:#{@key}", 'state')
112
+ def stringify(obj)
113
+ return obj.inject({}){|memo,(k,v)| memo[k.to_s] = stringify(v); memo} if obj.is_a?(Hash)
114
+ return obj.inject([]){|memo,v | memo << stringify(v); memo} if obj.is_a?(Array)
115
+ obj
189
116
  end
190
117
 
191
- Given /^(?:the check|check '([\w\.\-]+)' for entity '([\w\.\-]+)') is in an ok state$/ do |check, entity|
192
- check ||= @check
193
- entity ||= @entity
194
- remove_unscheduled_maintenance(entity, check)
195
- remove_scheduled_maintenance(entity, check)
196
- remove_notifications(entity, check)
197
- set_ok_state(entity, check)
198
- end
118
+ Given /^the check is check '(.*)' on entity '([\w\.\-]+)'$/ do |check_name, entity_name|
119
+ check = Flapjack::Data::Check.intersect(:name => "#{entity_name}:#{check_name}").all.first
120
+ if check.nil?
121
+ check = Flapjack::Data::Check.new(:name => "#{entity_name}:#{check_name}",
122
+ :enabled => true)
123
+ expect(check.save).to be true
124
+ end
199
125
 
200
- Given /^(?:the check|check '([\w\.\-]+)' for entity '([\w\.\-]+)') is in a critical state$/ do |check, entity|
201
- check ||= @check
202
- entity ||= @entity
203
- remove_unscheduled_maintenance(entity, check)
204
- remove_scheduled_maintenance(entity, check)
205
- remove_notifications(entity, check)
206
- set_critical_state(entity, check)
126
+ @check_name = check_name
127
+ @entity_name = entity_name
207
128
  end
208
129
 
209
- Given /^(?:the check|check '([\w\.\-]+)' for entity '([\w\.\-]+)') is in scheduled maintenance(?: for (.+))?$/ do |check, entity, duration|
210
- check ||= @check
211
- entity ||= @entity
212
- durn = duration ? ChronicDuration.parse(duration) : 60*60*2
213
- remove_unscheduled_maintenance(entity, check)
214
- set_scheduled_maintenance(entity, check, durn)
130
+ Given /^(?:the check|check '([\w\.\-]+)' for entity '([\w\.\-]+)') has no state$/ do |check_name, entity_name|
131
+ check_name ||= @check_name
132
+ entity_name ||= @entity_name
215
133
  end
216
134
 
217
- # TODO set the state directly rather than submit & drain
218
- Given /^(?:the check|check '([\w\.\-]+)' for entity '([\w\.\-]+)') is in unscheduled maintenance$/ do |check, entity|
219
- check ||= @check
220
- entity ||= @entity
221
- remove_scheduled_maintenance(entity, check)
222
- set_critical_state(entity, check)
223
- submit_acknowledgement(entity, check)
224
- drain_events # TODO these should only be in When clauses
135
+ Given /^(?:the check|check '([\w\.\-]+)' for entity '([\w\.\-]+)') is in an? (ok|critical) state$/ do |check_name, entity_name, state|
136
+ check_name ||= @check_name
137
+ entity_name ||= @entity_name
138
+ set_state(entity_name, check_name, state, Time.now)
225
139
  end
226
140
 
227
- When /^an ok event is received(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |check, entity|
228
- check ||= @check
229
- entity ||= @entity
230
- submit_ok(entity, check)
231
- drain_events
141
+ Given /^(?:the check|check '([\w\.\-]+)' for entity '([\w\.\-]+)') is in scheduled maintenance(?: for (.+))?$/ do |check_name, entity_name, duration|
142
+ check_name ||= @check_name
143
+ entity_name ||= @entity_name
144
+ durn = duration ? ChronicDuration.parse(duration) : (6 * 60 *60)
145
+ set_scheduled_maintenance(entity_name, check_name, durn)
232
146
  end
233
147
 
234
- When /^a failure event is received(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |check, entity|
235
- check ||= @check
236
- entity ||= @entity
237
- submit_critical(entity, check)
238
- drain_events
148
+ Given /^(?:the check|check '([\w\.\-]+)' for entity '([\w\.\-]+)') is in unscheduled maintenance$/ do |check_name, entity_name|
149
+ check_name ||= @check_name
150
+ entity_name ||= @entity_name
151
+ set_unscheduled_maintenance(entity_name, check_name, 60*60*2)
239
152
  end
240
153
 
241
- When /^a critical event is received(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |check, entity|
242
- check ||= @check
243
- entity ||= @entity
244
- submit_critical(entity, check)
154
+ When /^an? (ok|failure|critical|warning|unknown) event(?: with an? (initial|repeat) failure delay of (\d+) seconds)? is received(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |condition, init_or_repeat, failure_delay, check_name, entity_name|
155
+ check_name ||= @check_name
156
+ entity_name ||= @entity_name
157
+ opts = case init_or_repeat
158
+ when 'initial'
159
+ {:initial_failure_delay => failure_delay}
160
+ when 'repeat'
161
+ {:repeat_failure_delay => failure_delay}
162
+ else
163
+ {}
164
+ end
165
+ submit_event(condition, entity_name, check_name, opts)
245
166
  drain_events
246
167
  end
247
168
 
248
- When /^a warning event is received(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |check, entity|
249
- check ||= @check
250
- entity ||= @entity
251
- submit_warning(entity, check)
169
+ When /^an acknowledgement .*is received(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |check_name, entity_name|
170
+ check_name ||= @check_name
171
+ entity_name ||= @entity_name
172
+ submit_acknowledgement(entity_name, check_name)
252
173
  drain_events
253
174
  end
254
175
 
255
- When /^an unknown event is received(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |check, entity|
256
- check ||= @check
257
- entity ||= @entity
258
- submit_unknown(entity, check)
176
+ When /^a test .*is received(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |check_name, entity_name|
177
+ check_name ||= @check_name
178
+ entity_name ||= @entity_name
179
+ submit_test(entity_name, check_name)
259
180
  drain_events
260
181
  end
261
182
 
262
- When /^an acknowledgement .*is received(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |check, entity|
263
- check ||= @check
264
- entity ||= @entity
265
- submit_acknowledgement(entity, check)
266
- drain_events
183
+ When /^the unscheduled maintenance is ended(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |check_name, entity_name|
184
+ check_name ||= @check_name
185
+ entity_name ||= @entity_name
186
+ clear_unscheduled_maintenance(entity_name, check_name)
267
187
  end
268
188
 
269
- When /^a test .*is received(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |check, entity|
270
- check ||= @check
271
- entity ||= @entity
272
- submit_test(entity, check)
273
- drain_events
274
- end
189
+ Then /^(no|\d+) notifications? should have been generated(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |count, check_name, entity_name|
190
+ check_name ||= @check_name
191
+ entity_name ||= @entity_name
275
192
 
276
- When /^the unscheduled maintenance is ended(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |check, entity|
277
- check ||= @check
278
- entity ||= @entity
279
- end_unscheduled_maintenance(entity, check)
280
- end
193
+ check = Flapjack::Data::Check.intersect(:name => "#{entity_name}:#{check_name}").all.first
194
+ expect(check).not_to be_nil
281
195
 
282
- When /^check '([\w\.\-]+)' (?:for|on) entity '([\w\.\-]+)' is (dis|en)abled$/ do |check, entity, dis_en|
283
- entity_check = Flapjack::Data::EntityCheck.for_entity_name(entity, check, :redis => @redis)
284
- case dis_en
285
- when 'dis'
286
- entity_check.disable!
287
- when 'en'
288
- entity_check.enable!
196
+ case count
197
+ when 'no', 0
198
+ expect(check.notification_count).to be_nil
199
+ else
200
+ expect(check.notification_count).to eq(count.to_i)
289
201
  end
290
202
  end
291
203
 
292
- # TODO logging is a side-effect, should test for notification generation itself
293
- Then /^a notification should not be generated(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |check, entity|
294
- check ||= @check
295
- entity ||= @entity
296
- message = @logger.messages.find_all {|m| m =~ /enerating notification for event #{entity}:#{check}/ }.last
297
- found = message ? message.match(/Not generating notification/) : false
298
- expect(found).to be_truthy
299
- end
204
+ Then /^(un)?scheduled maintenance should be generated(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |unsched, check_name, entity_name|
205
+ check_name ||= @check_name
206
+ entity_name ||= @entity_name
300
207
 
301
- Then /^a notification should be generated(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |check, entity|
302
- check ||= @check
303
- entity ||= @entity
304
- message = @logger.messages.find_all {|m| m =~ /enerating notification for event #{entity}:#{check}/ }.last
305
- found = message ? message.match(/Generating notification/) : false
306
- expect(found).to be_truthy
307
- end
208
+ check = Flapjack::Data::Check.intersect(:name => "#{entity_name}:#{check_name}").all.first
209
+ expect(check).not_to be_nil
308
210
 
309
- Then /^(un)?scheduled maintenance should be generated(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |unsched, check, entity|
310
- check ||= @check
311
- entity ||= @entity
312
- expect(@redis.get("#{entity}:#{check}:#{unsched || ''}scheduled_maintenance")).not_to be_nil
211
+ expect(check).to (unsched ? be_in_unscheduled_maintenance : be_in_scheduled_maintenance)
313
212
  end
314
213
 
315
214
  Then /^show me the (\w+ )*log$/ do |adjective|
316
215
  puts "the #{adjective}log:"
317
- puts @logger.messages.join("\n")
318
- end
319
-
320
- Then /^dump notification rules for user (\S+)$/ do |contact|
321
- rule_ids = @redis.smembers("contact_notification_rules:#{contact}")
322
- puts "There #{(rule_ids.length == 1) ? 'is' : 'are'} #{rule_ids.length} notification rule#{(rule_ids.length == 1) ? '' : 's'} for user #{contact}:"
323
- rule_ids.each {|rule_id|
324
- rule = Flapjack::Data::NotificationRule.find_by_id(rule_id, :redis => @redis)
325
- puts Flapjack.dump_json(rule)
326
- }
327
- end
328
-
329
- # added for notification rules:
330
- Given /^the following entities exist:$/ do |entities|
331
- entities.hashes.each do |entity|
332
- contacts = entity['contacts'].split(',')
333
- contacts.map! do |contact|
334
- contact.strip
335
- end
336
- Flapjack::Data::Entity.add({'id' => entity['id'],
337
- 'name' => entity['name'],
338
- 'contacts' => contacts},
339
- :redis => @redis )
340
- end
341
- end
342
-
343
- Given /^the following users exist:$/ do |contacts|
344
- contacts.hashes.each do |contact|
345
- media = {}
346
- media['email'] = { 'address' => contact['email'] }
347
- media['sms'] = { 'address' => contact['sms'] }
348
- Flapjack::Data::Contact.add({'id' => contact['id'],
349
- 'first_name' => contact['first_name'],
350
- 'last_name' => contact['last_name'],
351
- 'email' => contact['email'],
352
- 'media' => media},
353
- :redis => @redis ).timezone = contact['timezone']
354
- end
355
- end
356
-
357
- Given /^user (\S+) has the following notification intervals:$/ do |contact_id, intervals|
358
- contact = Flapjack::Data::Contact.find_by_id(contact_id, :redis => @redis)
359
- intervals.hashes.each do |interval|
360
- contact.set_interval_for_media('email', interval['email'].to_i * 60)
361
- contact.set_interval_for_media('sms', interval['sms'].to_i * 60)
362
- end
363
- end
364
-
365
- Given /^user (\S+) has the following notification rollup thresholds:$/ do |contact_id, rollup_thresholds|
366
- contact = Flapjack::Data::Contact.find_by_id(contact_id, :redis => @redis)
367
- rollup_thresholds.hashes.each do |rollup_threshold|
368
- contact.set_rollup_threshold_for_media('email', rollup_threshold['email'].to_i)
369
- contact.set_rollup_threshold_for_media('sms', rollup_threshold['sms'].to_i)
370
- end
371
- end
372
-
373
- Given /^user (\S+) has the following notification rules:$/ do |contact_id, rules|
374
- contact = Flapjack::Data::Contact.find_by_id(contact_id, :redis => @redis)
375
- time_zone = contact.time_zone
376
-
377
- # delete any autogenerated rules, and do it using redis directly so no new
378
- # ones will be created
379
- contact.notification_rules.each do |nr|
380
- @redis.srem("contact_notification_rules:#{contact_id}", nr.id)
381
- @redis.del("notification_rule:#{nr.id}")
382
- end
383
- rules.hashes.each do |rule|
384
- entities = rule['entities'] ? rule['entities'].split(',').map {|x| x.strip } : []
385
- regex_entities = rule['regex_entities'] ? rule['regex_entities'].split(',').map {|x| x.strip } : []
386
- tags = rule['tags'] ? rule['tags'].split(',').map {|x| x.strip } : []
387
- unknown_media = rule['unknown_media'] ? rule['unknown_media'].split(',').map {|x| x.strip } : []
388
- warning_media = rule['warning_media'] ? rule['warning_media'].split(',').map {|x| x.strip } : []
389
- critical_media = rule['critical_media'] ? rule['critical_media'].split(',').map {|x| x.strip } : []
390
- unknown_blackhole = rule['unknown_blackhole'] ? (rule['unknown_blackhole'].downcase == 'true') : false
391
- warning_blackhole = rule['warning_blackhole'] ? (rule['warning_blackhole'].downcase == 'true') : false
392
- critical_blackhole = rule['critical_blackhole'] ? (rule['critical_blackhole'].downcase == 'true') : false
393
- time_restrictions = rule['time_restrictions'] ? rule['time_restrictions'].split(',').map { |x|
394
- x.strip
395
- }.inject([]) { |memo, time_restriction|
396
- case time_restriction
397
- when '8-18 weekdays'
398
- weekdays_8_18 = IceCube::Schedule.new(time_zone.local(2013,2,1,8,0,0), :duration => 60 * 60 * 10)
399
- weekdays_8_18.add_recurrence_rule(IceCube::Rule.weekly.day(:monday, :tuesday, :wednesday, :thursday, :friday))
400
- memo << icecube_schedule_to_time_restriction(weekdays_8_18, time_zone)
401
- end
402
- } : []
403
- rule_data = {:contact_id => contact_id,
404
- :entities => entities,
405
- :regex_entities => regex_entities,
406
- :tags => tags,
407
- :unknown_media => unknown_media,
408
- :warning_media => warning_media,
409
- :critical_media => critical_media,
410
- :unknown_blackhole => unknown_blackhole,
411
- :warning_blackhole => warning_blackhole,
412
- :critical_blackhole => critical_blackhole,
413
- :time_restrictions => time_restrictions}
414
- created_rule = Flapjack::Data::NotificationRule.add(rule_data, :redis => @redis)
415
- unless created_rule.is_a?(Flapjack::Data::NotificationRule)
416
- raise "Error creating notification rule with data: #{rule_data}, errors: #{created_rule.join(', ')}"
417
- end
418
- end
419
- end
420
-
421
- Then /^all alert dropping keys for user (\S+) should have expired$/ do |contact_id|
422
- expect(@redis.keys("drop_alerts_for_contact:#{contact_id}:*")).to be_empty
216
+ puts Flapjack.logger.messages.join("\n")
423
217
  end
424
218
 
425
219
  Then /^(\w+) (\w+) alert(?:s)?(?: of)?(?: type (\w+))?(?: and)?(?: rollup (\w+))? should be queued for (.*)$/ do |num_queued, media, notification_type, rollup, address|
426
- check = check ? check : @check
427
- entity = entity ? entity : @entity
428
220
  case num_queued
429
221
  when 'no'
430
222
  num_queued = 0
431
223
  end
432
- queued = redis_peek("#{media}_notifications", 0, 30)
433
- queued_length = queued.find_all {|n|
434
- type_ok = notification_type ? ( n['notification_type'] == notification_type ) : true
435
- rollup_ok = case rollup
436
- when 'none'
437
- n['rollup'].nil?
438
- when nil, n['rollup']
439
- true
440
- else
441
- false
224
+ queued = redis_peek("#{media}_notifications", Flapjack::Data::Alert, 0, 30)
225
+ queued_length = queued.find_all {|alert|
226
+ type_ok = notification_type ? ( alert.notification_type == notification_type ) : true
227
+ rollup_ok = true
228
+ if rollup
229
+ if rollup == 'none'
230
+ rollup_ok = alert.rollup.nil?
231
+ else
232
+ rollup_ok = (alert.rollup == rollup)
233
+ end
442
234
  end
443
- type_ok && rollup_ok && ( n['address'] == address )
235
+ type_ok && rollup_ok && (alert.medium.address == address)
444
236
  }.length
445
237
  expect(queued_length).to eq(num_queued.to_i)
446
238
  end
447
239
 
448
- When(/^user (\S+) ceases to be a contact of entity '(.*)'$/) do |contact_id, entity|
449
- entity = Flapjack::Data::Entity.find_by_name(entity, :redis => @redis)
450
- @redis.srem("contacts_for:#{entity.id}", contact_id)
451
- end
240
+ When(/^the rule with id '(\S+)' is removed$/) do |rule_id|
241
+ rule = Flapjack::Data::Rule.find_by_id(rule_id)
242
+ expect(rule).not_to be_nil
452
243
 
453
- Then(/^(?:the check|check '([\w\.\-]+)' for entity '([\w\.\-]+)') should not appear in unacknowledged_failing$/) do |check, entity|
454
- check ||= @check
455
- entity ||= @entity
456
- unacknowledged_failing_checks = Flapjack::Data::EntityCheck.unacknowledged_failing(:redis => @redis)
457
- expect(unacknowledged_failing_checks.map {|ec| "#{ec.entity.name}:#{ec.check}"}).to_not include("#{entity}:#{check}")
458
- end
244
+ # # this should happen anyway...
245
+ # rule.contact.rules.remove(rule) unless rule.contact.nil?
459
246
 
460
- Then(/^(?:the check|check '([\w\.\-]+)' for entity '([\w\.\-]+)') should appear in unacknowledged_failing$/) do |check, entity|
461
- check ||= @check
462
- entity ||= @entity
463
- unacknowledged_failing_checks = Flapjack::Data::EntityCheck.unacknowledged_failing(:redis => @redis)
464
- expect(unacknowledged_failing_checks.map {|ec| "#{ec.entity.name}:#{ec.check}"}).to include("#{entity}:#{check}")
247
+ rule.destroy
465
248
  end
466
249
 
250
+ When /^check '([\w\.\-]+)' (?:for|on) entity '([\w\.\-]+)' is (dis|en)abled$/ do |check_name, entity_name, dis_en|
251
+ check = Flapjack::Data::Check.intersect(:name => "#{entity_name}:#{check_name}").all.first
252
+ expect(check).not_to be_nil
253
+
254
+ check.enabled = 'en'.eql?(dis_en)
255
+ check.save!
256
+ end