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
@@ -0,0 +1,473 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'set'
4
+
5
+ require 'active_support/inflector'
6
+ require 'active_support/core_ext/hash/slice'
7
+
8
+ require 'ice_cube'
9
+ require 'icalendar'
10
+ require 'swagger/blocks'
11
+
12
+ require 'zermelo/records/redis'
13
+
14
+ require 'flapjack/utility'
15
+
16
+ require 'flapjack/data/extensions/short_name'
17
+ require 'flapjack/data/validators/id_validator'
18
+
19
+ require 'flapjack/data/extensions/associations'
20
+ require 'flapjack/gateways/jsonapi/data/join_descriptor'
21
+ require 'flapjack/gateways/jsonapi/data/method_descriptor'
22
+
23
+ module Flapjack
24
+ module Data
25
+ class Rule
26
+
27
+ STRATEGIES = ['global', 'any_tag', 'all_tags', 'no_tag']
28
+
29
+ extend Flapjack::Utility
30
+
31
+ include Zermelo::Records::RedisSet
32
+ include ActiveModel::Serializers::JSON
33
+ self.include_root_in_json = false
34
+ include Swagger::Blocks
35
+
36
+ include Flapjack::Data::Extensions::Associations
37
+ include Flapjack::Data::Extensions::ShortName
38
+
39
+ # regex_* properties have been removed as they encourage loose binding
40
+ # against check names, which may change. Do client-side grouping and
41
+ # create a tag!
42
+
43
+ define_attributes :name => :string,
44
+ :enabled => :boolean,
45
+ :blackhole => :boolean,
46
+ :strategy => :string,
47
+ :conditions_list => :string,
48
+ :has_media => :boolean,
49
+ :time_restriction_ical => :string
50
+
51
+ index_by :name, :enabled, :blackhole, :strategy, :conditions_list, :has_media
52
+
53
+ validates_with Flapjack::Data::Validators::IdValidator
54
+
55
+ validates :enabled, :inclusion => {:in => [true, false]}
56
+ validates :blackhole, :inclusion => {:in => [true, false]}
57
+ validates :strategy, :inclusion => {:in => Flapjack::Data::Rule::STRATEGIES}
58
+
59
+ validates_each :time_restriction_ical do |record, att, value|
60
+ unless record.valid_time_restriction_ical?
61
+ record.errors.add(:time_restriction_ical, 'is not valid ICAL syntax')
62
+ end
63
+ end
64
+
65
+ belongs_to :contact, :class_name => 'Flapjack::Data::Contact',
66
+ :inverse_of => :rules
67
+
68
+ has_and_belongs_to_many :media, :class_name => 'Flapjack::Data::Medium',
69
+ :inverse_of => :rules, :after_add => :media_added,
70
+ :after_remove => :media_removed
71
+
72
+ has_and_belongs_to_many :tags, :class_name => 'Flapjack::Data::Tag',
73
+ :inverse_of => :rules
74
+
75
+ def initialize(attributes = {})
76
+ super
77
+ send(:"attribute=", 'has_media', false)
78
+ end
79
+
80
+ def time_restriction
81
+ return if time_restriction_ical.nil? || !valid_time_restriction_ical?
82
+ IceCube::Schedule.from_ical(time_restriction_ical)
83
+ end
84
+
85
+ def time_restriction=(restriction)
86
+ if restriction.nil?
87
+ self.time_restriction_ical = nil
88
+ return
89
+ end
90
+ unless restriction.is_a?(IceCube::Schedule)
91
+ raise "Invalid data type for time_restriction= (#{restriction.class.name})"
92
+ end
93
+ # ice_cube ignores time zone info when parsing ical, so we'll enforce UTC
94
+ # and cast to the contact's preferred time zone as appropriate when using
95
+ # (this should also handle the case of the user changing her timezone)
96
+ restriction.start_time = restriction.start_time.nil? ? nil : restriction.start_time.utc
97
+ restriction.end_time = restriction.end_time.nil? ? nil : restriction.end_time.utc
98
+ self.time_restriction_ical = restriction.to_ical
99
+ end
100
+
101
+ def valid_time_restriction_ical?
102
+ return true if time_restriction_ical.nil?
103
+ wrapped_value = ['BEGIN:VCALENDAR',
104
+ 'VERSION:2.0',
105
+ 'PRODID:validationid',
106
+ 'CALSCALE:GREGORIAN',
107
+ 'BEGIN:VEVENT',
108
+ time_restriction_ical,
109
+ 'END:VEVENT',
110
+ 'END:VCALENDAR'].join("\n")
111
+
112
+ # icalendar is noisy with errors
113
+ old_icalendar_log_level = ::Icalendar.logger.level
114
+ ::Icalendar.logger.level = ::Logger::FATAL
115
+ icalendar = ::Icalendar.parse(wrapped_value)
116
+ ::Icalendar.logger.level = old_icalendar_log_level
117
+
118
+ !(icalendar.empty? || icalendar.first.events.empty? ||
119
+ !icalendar.first.events.first.valid?)
120
+ end
121
+
122
+ # nil time_restriction matches
123
+ def is_occurring_at?(time, time_zone = Time.zone)
124
+ return true if time_restriction.nil?
125
+ time_restriction.occurring_at?(time.in_time_zone(time_zone))
126
+ end
127
+
128
+ def self.media_added(rule_id, *m_ids)
129
+ rule = self.find_by_id!(rule_id)
130
+ rule.has_media = true
131
+ rule.save!
132
+ end
133
+
134
+ def self.media_removed(rule_id, *m_ids)
135
+ rule = self.find_by_id!(rule_id)
136
+ rule.has_media = rule.media.empty?
137
+ rule.save!
138
+ end
139
+
140
+ # called by medium.checks
141
+ # no global rules in the passed rule data
142
+ # rule_ids will be all acceptors
143
+ # (blackhole == false) or all rejectors (blackhole == true)
144
+ def self.matching_checks(rule_ids)
145
+ m_checks = ['all_tags', 'any_tag', 'no_tag'].inject(nil) do |memo, strategy|
146
+ tag_ids_by_rule_id = self.intersect(:strategy => strategy,
147
+ :id => rule_ids).associated_ids_for(:tags)
148
+
149
+ checks = checks_for_tag_match(strategy, tag_ids_by_rule_id)
150
+
151
+ memo = if memo.nil?
152
+ Flapjack::Data::Check.intersect(:id => checks)
153
+ else
154
+ memo.union(:id => checks)
155
+ end
156
+ end
157
+
158
+ return Flapjack::Data::Check.empty if m_checks.nil?
159
+ m_checks
160
+ end
161
+
162
+ # called by check.contacts, rule_ids will be all acceptors
163
+ # (blackhole == false) or all rejectors (blackhole == true)
164
+ def self.matching_contact_ids(rule_ids, opts = {})
165
+ time = opts[:time] || Time.now
166
+ contact_rules = self.intersect(:id => rule_ids)
167
+
168
+ matching_ids = apply_time_restriction(contact_rules, time).
169
+ map(&:id)
170
+
171
+ self.intersect(:id => matching_ids).
172
+ associated_ids_for(:contact, :inversed => true).keys
173
+ end
174
+
175
+ # called by check.alerting_media, rule_ids will be all acceptors
176
+ # (blackhole == false) or all rejectors (blackhole == true)
177
+ def self.matching_media_ids(rule_ids, opts = {})
178
+ time = opts[:time] || Time.now
179
+
180
+ # if a rule has no media, it's irrelevant here
181
+ media_rules = self.intersect(:id => rule_ids, :has_media => true)
182
+
183
+ matching_ids = apply_time_restriction(media_rules, time).
184
+ map(&:id)
185
+
186
+ self.intersect(:id => matching_ids).
187
+ associated_ids_for(:media).values.reduce(Set.new, :|)
188
+ end
189
+
190
+ swagger_schema :Rule do
191
+ key :required, [:id, :type, :enabled, :blackhole, :strategy]
192
+ property :id do
193
+ key :type, :string
194
+ key :format, :uuid
195
+ end
196
+ property :type do
197
+ key :type, :string
198
+ key :enum, [Flapjack::Data::Rule.short_model_name.singular]
199
+ end
200
+ property :name do
201
+ key :type, :string
202
+ end
203
+ property :enabled do
204
+ key :type, :boolean
205
+ end
206
+ property :blackhole do
207
+ key :type, :boolean
208
+ end
209
+ property :strategy do
210
+ key :type, :string
211
+ key :enum, Flapjack::Data::Rule::STRATEGIES
212
+ end
213
+ property :conditions_list do
214
+ key :type, :string
215
+ end
216
+ property :time_restriction_ical do
217
+ key :type, :string
218
+ end
219
+ property :relationships do
220
+ key :"$ref", :RuleLinks
221
+ end
222
+ end
223
+
224
+ swagger_schema :RuleLinks do
225
+ key :required, [:contact, :media, :tags]
226
+ property :contact do
227
+ key :"$ref", :ContactLinkage
228
+ end
229
+ property :media do
230
+ key :"$ref", :MediaLinkage
231
+ end
232
+ property :tags do
233
+ key :"$ref", :TagsLinkage
234
+ end
235
+ end
236
+
237
+ swagger_schema :RuleCreate do
238
+ key :required, [:type, :enabled, :blackhole, :strategy]
239
+ property :id do
240
+ key :type, :string
241
+ key :format, :uuid
242
+ end
243
+ property :type do
244
+ key :type, :string
245
+ key :enum, [Flapjack::Data::Rule.short_model_name.singular]
246
+ end
247
+ property :name do
248
+ key :type, :string
249
+ end
250
+ property :enabled do
251
+ key :type, :boolean
252
+ end
253
+ property :blackhole do
254
+ key :type, :boolean
255
+ end
256
+ property :strategy do
257
+ key :type, :string
258
+ key :enum, Flapjack::Data::Rule::STRATEGIES
259
+ end
260
+ property :conditions_list do
261
+ key :type, :string
262
+ end
263
+ property :time_restriction_ical do
264
+ key :type, :string
265
+ end
266
+ property :relationships do
267
+ key :"$ref", :RuleCreateLinks
268
+ end
269
+ end
270
+
271
+ swagger_schema :RuleCreateLinks do
272
+ key :required, [:contact]
273
+ property :contact do
274
+ key :"$ref", :data_ContactReference
275
+ end
276
+ property :media do
277
+ key :"$ref", :data_MediaReference
278
+ end
279
+ property :tags do
280
+ key :"$ref", :data_TagsReference
281
+ end
282
+ end
283
+
284
+ swagger_schema :RuleUpdate do
285
+ key :required, [:id, :type]
286
+ property :id do
287
+ key :type, :string
288
+ key :format, :uuid
289
+ end
290
+ property :type do
291
+ key :type, :string
292
+ key :enum, [Flapjack::Data::Rule.short_model_name.singular]
293
+ end
294
+ property :name do
295
+ key :type, :string
296
+ end
297
+ property :enabled do
298
+ key :type, :boolean
299
+ end
300
+ property :blackhole do
301
+ key :type, :boolean
302
+ end
303
+ property :strategy do
304
+ key :type, :string
305
+ key :enum, Flapjack::Data::Rule::STRATEGIES
306
+ end
307
+ property :conditions_list do
308
+ key :type, :string
309
+ end
310
+ property :time_restriction_ical do
311
+ key :type, :string
312
+ end
313
+ property :relationships do
314
+ key :"$ref", :RuleUpdateLinks
315
+ end
316
+ end
317
+
318
+ swagger_schema :RuleUpdateLinks do
319
+ property :media do
320
+ key :"$ref", :data_MediaReference
321
+ end
322
+ property :tags do
323
+ key :"$ref", :data_TagsReference
324
+ end
325
+ end
326
+
327
+ def self.swagger_included_classes
328
+ # hack -- hardcoding for now
329
+ [
330
+ Flapjack::Data::Check,
331
+ Flapjack::Data::Contact,
332
+ Flapjack::Data::Medium,
333
+ Flapjack::Data::Rule,
334
+ Flapjack::Data::ScheduledMaintenance,
335
+ Flapjack::Data::State,
336
+ Flapjack::Data::Tag,
337
+ Flapjack::Data::UnscheduledMaintenance
338
+ ]
339
+ end
340
+
341
+ def self.jsonapi_methods
342
+ @jsonapi_methods ||= {
343
+ :post => Flapjack::Gateways::JSONAPI::Data::MethodDescriptor.new(
344
+ :attributes => [:name, :enabled, :blackhole, :strategy, :conditions_list,
345
+ :time_restriction_ical],
346
+ :descriptions => {
347
+ :singular => "Create a notification rule.",
348
+ :multiple => "Create notification rules."
349
+ }
350
+ ),
351
+ :get => Flapjack::Gateways::JSONAPI::Data::MethodDescriptor.new(
352
+ :attributes => [:name, :enabled, :blackhole, :strategy, :conditions_list,
353
+ :time_restriction_ical],
354
+ :descriptions => {
355
+ :singular => "Get data for a notification rule.",
356
+ :multiple => "Get data for multiple notification rules."
357
+ }
358
+ ),
359
+ :patch => Flapjack::Gateways::JSONAPI::Data::MethodDescriptor.new(
360
+ :attributes => [:name, :enabled, :blackhole, :strategy, :conditions_list,
361
+ :time_restriction_ical],
362
+ :descriptions => {
363
+ :singular => "Update a notification rule.",
364
+ :multiple => "Update notification rules."
365
+ }
366
+ ),
367
+ :delete => Flapjack::Gateways::JSONAPI::Data::MethodDescriptor.new(
368
+ :descriptions => {
369
+ :singular => "Delete a notification rule.",
370
+ :multiple => "Delete notification rules."
371
+ }
372
+ )
373
+ }
374
+ end
375
+
376
+ def self.jsonapi_associations
377
+ unless instance_variable_defined?('@jsonapi_associations')
378
+ @jsonapi_associations = {
379
+ :contact => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
380
+ :post => true, :get => true,
381
+ :number => :singular, :link => true, :includable => true,
382
+ :descriptions => {
383
+ :post => "Set a contact for a rule during rule creation (required).",
384
+ :get => "Get the contact a rule belongs to."
385
+ }
386
+ ),
387
+ :media => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
388
+ :post => true, :get => true, :patch => true, :delete => true,
389
+ :number => :multiple, :link => true, :includable => true,
390
+ :descriptions => {
391
+ :post => "Associate this rule with media on rule creation.",
392
+ :get => "Get the media this rule is associated with.",
393
+ :patch => "Update the media this rule is associated with.",
394
+ :delete => "Delete associations between this rule and media."
395
+ }
396
+ ),
397
+ :tags => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
398
+ :post => true, :get => true, :patch => true, :delete => true,
399
+ :number => :multiple, :link => true, :includable => true,
400
+ :descriptions => {
401
+ :post => "Associate tags with this rule.",
402
+ :get => "Returns all tags linked to this rule.",
403
+ :patch => "Update the tags associated with this rule.",
404
+ :delete => "Delete associations between tags and this rule."
405
+ }
406
+ )
407
+ }
408
+ populate_association_data(@jsonapi_associations)
409
+ end
410
+ @jsonapi_associations
411
+ end
412
+
413
+ protected
414
+
415
+ def self.apply_time_restriction(rules, time)
416
+ # filter the rules by time restriction
417
+ rule_ids_by_contact_id = rules.associated_ids_for(:contact, :inversed => true)
418
+
419
+ rule_contacts = rule_ids_by_contact_id.empty? ? [] :
420
+ Flapjack::Data::Contact.find_by_ids(*rule_ids_by_contact_id.keys)
421
+
422
+ time_zones_by_rule_id = rule_contacts.each_with_object({}) do |c, memo|
423
+ rule_ids_by_contact_id[c.id].each do |r_id|
424
+ memo[r_id] = c.time_zone
425
+ end
426
+ end
427
+
428
+ rules.select do |rule|
429
+ rule.is_occurring_at?(time, time_zones_by_rule_id[rule.id])
430
+ end
431
+ end
432
+
433
+ private
434
+
435
+ def self.checks_for_tag_match(strategy, tag_ids_by_rule_id)
436
+ tag_ids_by_rule_id.values.inject(nil) do |memo, tag_ids|
437
+ assocs = Flapjack::Data::Tag.intersect(:id => tag_ids).
438
+ associations_for(:checks).values
439
+ next memo if assocs.empty?
440
+
441
+ checks = case strategy
442
+ when 'all_tags'
443
+ assocs.inject(Flapjack::Data::Check) do |c_memo, ca|
444
+ c_memo = c_memo.intersect(:id => ca)
445
+ c_memo
446
+ end
447
+ when 'any_tag'
448
+ assocs.inject(nil) do |c_memo, ca|
449
+ if c_memo.nil?
450
+ Flapjack::Data::Check.intersect(:id => ca)
451
+ else
452
+ c_memo.union(:id => ca)
453
+ end
454
+ end
455
+ when 'no_tag'
456
+ assocs.inject(Flapjack::Data::Check) do |c_memo, ca|
457
+ c_memo = c_memo.diff(:id => ca)
458
+ c_memo
459
+ end
460
+ end
461
+
462
+ memo = if memo.nil?
463
+ Flapjack::Data::Check.intersect(:id => checks)
464
+ else
465
+ memo.union(:id => checks)
466
+ end
467
+ memo
468
+ end
469
+ end
470
+ end
471
+ end
472
+ end
473
+