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,33 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module Flapjack
4
+
5
+ class RecordQueue
6
+
7
+ def initialize(queue, object_klass)
8
+ @queue = queue
9
+ @object_klass = object_klass
10
+ end
11
+
12
+ def push(object)
13
+ Flapjack.redis.multi do
14
+ Flapjack.redis.lpush(@queue, object.id)
15
+ Flapjack.redis.lpush("#{@queue}_actions", "+")
16
+ end
17
+ end
18
+
19
+ def foreach(options = {})
20
+ while object_id = Flapjack.redis.rpop(@queue)
21
+ next unless object = @object_klass.find_by_id(object_id)
22
+ yield object if block_given?
23
+ object.destroy unless options[:keep]
24
+ end
25
+ end
26
+
27
+ def wait
28
+ Flapjack.redis.brpop("#{@queue}_actions")
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # defer initialisation for Redis connections until they're used.
4
+ require 'redis'
5
+ require 'redis/connection/hiredis'
6
+ require 'zermelo'
7
+
8
+ module Flapjack
9
+
10
+ class << self
11
+ # Thread and fiber-local
12
+ def redis
13
+ redis_cxn = Thread.current[:flapjack_redis]
14
+ return redis_cxn unless redis_cxn.nil?
15
+ Thread.current[:flapjack_redis] = Flapjack::RedisProxy.new
16
+ end
17
+ end
18
+
19
+ class RedisProxy
20
+
21
+ class << self
22
+ attr_accessor :config
23
+ end
24
+
25
+ def initialize
26
+ @proxied_connection = nil
27
+ @connection_failed = nil
28
+ end
29
+
30
+ # need to override Kernel.exec
31
+ def exec
32
+ proxied_connection.exec
33
+ end
34
+
35
+ def quit
36
+ @proxied_connection.quit unless @connection_failed || @proxied_connection.nil?
37
+ end
38
+
39
+ def respond_to?(name, include_private = false)
40
+ proxied_connection.respond_to?(name, include_private)
41
+ end
42
+
43
+ def method_missing(name, *args, &block)
44
+ proxied_connection.send(name, *args, &block)
45
+ end
46
+
47
+ private
48
+
49
+ REQUIRED_VERSION = '2.6.12'
50
+
51
+ def proxied_connection
52
+ return @proxied_connection unless @proxied_connection.nil?
53
+ @proxied_connection = ::Redis.new(self.class.config)
54
+ redis_version = @proxied_connection.info['redis_version']
55
+ return @proxied_connection if redis_version.nil? ||
56
+ ((redis_version.split('.') <=> REQUIRED_VERSION.split('.')) >= 0)
57
+ raise("Redis too old - Flapjack requires #{REQUIRED_VERSION} but " \
58
+ "#{redis_version} is running")
59
+ rescue Redis::CannotConnectError, Errno::EINVAL
60
+ @connection_failed = true
61
+ raise
62
+ end
63
+
64
+ end
65
+
66
+ end
@@ -15,21 +15,21 @@ module Flapjack
15
15
  end
16
16
 
17
17
  # Returns relative time in words referencing the given date
18
- # relative_time_ago(Time.now) => 'about a minute ago'
19
- def relative_time_ago(from_time)
20
- distance_in_minutes = (((Time.now - from_time.to_time).abs)/60).round
18
+ # relative_time_ago(Time.now, Time.now - 1) => 'about a minute ago'
19
+ def relative_time_ago(from_time, to_time)
20
+ distance_in_minutes = (((from_time.to_time - to_time.to_time).abs)/60).round
21
21
  case distance_in_minutes
22
- when 0..1 then 'about a minute'
23
- when 2..44 then "#{distance_in_minutes} minutes"
24
- when 45..89 then 'about 1 hour'
25
- when 90..1439 then "about #{(distance_in_minutes.to_f / 60.0).round} hours"
26
- when 1440..2439 then '1 day'
27
- when 2440..2879 then 'about 2 days'
28
- when 2880..43199 then "#{(distance_in_minutes / 1440).round} days"
29
- when 43200..86399 then 'about 1 month'
30
- when 86400..525599 then "#{(distance_in_minutes / 43200).round} months"
31
- when 525600..1051199 then 'about 1 year'
32
- else "over #{(distance_in_minutes / 525600).round} years"
22
+ when 0..1 then 'about a minute'
23
+ when 2..44 then "#{distance_in_minutes} minutes"
24
+ when 45..89 then 'about 1 hour'
25
+ when 90..1439 then "about #{(distance_in_minutes.to_f / 60.0).round} hours"
26
+ when 1440..2439 then '1 day'
27
+ when 2440..2879 then 'about 2 days'
28
+ when 2880..43199 then "#{(distance_in_minutes / 1440).round} days"
29
+ when 43200..86399 then 'about 1 month'
30
+ when 86400..525599 then "#{(distance_in_minutes / 43200).round} months"
31
+ when 525600..1051199 then 'about 1 year'
32
+ else "over #{(distance_in_minutes / 525600).round} years"
33
33
  end
34
34
  end
35
35
 
@@ -47,10 +47,16 @@ module Flapjack
47
47
  Time.utc(time.year, time.month, time.day, time.hour, time.min, time.sec)
48
48
  end
49
49
 
50
+ def stringify(obj)
51
+ return obj.inject({}){|memo,(k,v)| memo[k.to_s] = stringify(v); memo} if obj.is_a?(Hash)
52
+ return obj.inject([]){|memo,v | memo << stringify(v); memo} if obj.is_a?(Array)
53
+ obj
54
+ end
55
+
50
56
  def symbolize(obj)
51
57
  return obj.inject({}){|memo,(k,v)| memo[k.to_sym] = symbolize(v); memo} if obj.is_a? Hash
52
58
  return obj.inject([]){|memo,v | memo << symbolize(v); memo} if obj.is_a? Array
53
- return obj
59
+ obj
54
60
  end
55
61
 
56
62
  # The passed block will be provided each value from the args
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  module Flapjack
4
- VERSION = "1.6.0"
4
+ VERSION = '2.0.0b1'
5
5
  end
6
+
@@ -5,26 +5,130 @@ import (
5
5
  "flapjack"
6
6
  "fmt"
7
7
  "github.com/go-martini/martini"
8
- "gopkg.in/alecthomas/kingpin.v1"
8
+ "gopkg.in/alecthomas/kingpin.v2"
9
9
  "io/ioutil"
10
10
  "log"
11
11
  "net/http"
12
12
  "os"
13
+ "strings"
13
14
  "time"
14
15
  )
15
16
 
17
+ type EventFormat int
18
+
19
+ const (
20
+ Normal EventFormat = 1
21
+ SNS EventFormat = 2
22
+ Newrelic EventFormat = 3
23
+ )
24
+
16
25
  // State is a basic representation of a Flapjack event, with some extra field.
17
26
  // The extra fields handle state expiry.
18
27
  // Find more at http://flapjack.io/docs/1.0/development/DATA_STRUCTURES
28
+ type Tags struct {
29
+ FromBroker string `json:"from_broker"`
30
+ }
19
31
  type State struct {
32
+ flapjack.Event
33
+ TTL int64 `json:"ttl"`
34
+ Tags struct {
35
+ FromBroker string `json:"from_broker"`
36
+ } `json:"tags"`
37
+ }
38
+
39
+ type InputState struct {
20
40
  flapjack.Event
21
41
  TTL int64 `json:"ttl"`
22
42
  }
23
43
 
44
+ type SNSSubscribe struct {
45
+ Message string `json:"Message"`
46
+ MessageID string `json:"MessageId"`
47
+ Signature string `json:"Signature"`
48
+ SignatureVersion string `json:"SignatureVersion"`
49
+ SigningCertURL string `json:"SigningCertURL"`
50
+ SubscribeURL string `json:"SubscribeURL"`
51
+ Timestamp string `json:"Timestamp"`
52
+ Token string `json:"Token"`
53
+ TopicArn string `json:"TopicArn"`
54
+ Type string `json:"Type"`
55
+ }
56
+ type SNSNotification struct {
57
+ Message string `json:"Message"`
58
+ MessageID string `json:"MessageId"`
59
+ Signature string `json:"Signature"`
60
+ SignatureVersion string `json:"SignatureVersion"`
61
+ SigningCertURL string `json:"SigningCertURL"`
62
+ Subject string `json:"Subject"`
63
+ Timestamp string `json:"Timestamp"`
64
+ TopicArn string `json:"TopicArn"`
65
+ Type string `json:"Type"`
66
+ UnsubscribeURL string `json:"UnsubscribeURL"`
67
+ }
68
+ type CWAlarm struct {
69
+ AWSAccountID string `json:"AWSAccountId"`
70
+ AlarmDescription interface{} `json:"AlarmDescription"`
71
+ AlarmName string `json:"AlarmName"`
72
+ NewStateReason string `json:"NewStateReason"`
73
+ NewStateValue string `json:"NewStateValue"`
74
+ OldStateValue string `json:"OldStateValue"`
75
+ Region string `json:"Region"`
76
+ StateChangeTime string `json:"StateChangeTime"`
77
+ Time int64 `json:"Time"`
78
+ Trigger struct {
79
+ ComparisonOperator string `json:"ComparisonOperator"`
80
+ Dimensions []struct {
81
+ Name string `json:"name"`
82
+ Value string `json:"value"`
83
+ } `json:"Dimensions"`
84
+ EvaluationPeriods int `json:"EvaluationPeriods"`
85
+ MetricName string `json:"MetricName"`
86
+ Namespace string `json:"Namespace"`
87
+ Period int `json:"Period"`
88
+ Statistic string `json:"Statistic"`
89
+ Threshold float64 `json:"Threshold"`
90
+ Unit interface{} `json:"Unit"`
91
+ } `json:"Trigger"`
92
+ }
93
+
94
+ type NewRelicAlert struct {
95
+ AccountID int `json:"account_id"`
96
+ AccountName string `json:"account_name"`
97
+ ConditionID int `json:"condition_id"`
98
+ ConditionName string `json:"condition_name"`
99
+ CurrentState string `json:"current_state"`
100
+ Details string `json:"details"`
101
+ EventType string `json:"event_type"`
102
+ IncidentAcknowledgeURL string `json:"incident_acknowledge_url"`
103
+ IncidentID int `json:"incident_id"`
104
+ IncidentURL string `json:"incident_url"`
105
+ Owner string `json:"owner"`
106
+ PolicyName string `json:"policy_name"`
107
+ PolicyURL string `json:"policy_url"`
108
+ RunbookURL string `json:"runbook_url"`
109
+ Severity string `json:"severity"`
110
+ Targets []struct {
111
+ ID string `json:"id"`
112
+ Labels struct {
113
+ Label string `json:"label"`
114
+ } `json:"labels"`
115
+ Link string `json:"link"`
116
+ Name string `json:"name"`
117
+ Product string `json:"product"`
118
+ Type string `json:"type"`
119
+ } `json:"targets"`
120
+ Timestamp int `json:"timestamp"`
121
+ }
122
+
24
123
  // handler caches
25
124
  func CreateState(updates chan State, w http.ResponseWriter, r *http.Request) {
26
125
  var state State
27
-
126
+ var input_state InputState
127
+ var event_format EventFormat
128
+ var NRAlarm NewRelicAlert
129
+ var SNSData SNSNotification
130
+ var tags Tags
131
+ tags.FromBroker = "httpbroker"
28
132
  body, err := ioutil.ReadAll(r.Body)
29
133
  if err != nil {
30
134
  message := "Error: Couldn't read request body: %s\n"
@@ -33,12 +137,105 @@ func CreateState(updates chan State, w http.ResponseWriter, r *http.Request) {
33
137
  return
34
138
  }
35
139
 
140
+ // Check if its a FJ event
36
141
  err = json.Unmarshal(body, &state)
37
- if err != nil {
38
- message := "Error: Couldn't read request body: %s\n"
39
- log.Println(message, err)
40
- fmt.Fprintf(w, message, err)
41
- return
142
+ if state.Event.Entity != "" {
143
+ message := "Got Flapjack event"
144
+ log.Printf(message)
145
+ event_format = Normal
146
+ }
147
+
148
+ // Check if its a New Relic event
149
+ err = json.Unmarshal(body, &NRAlarm)
150
+ if NRAlarm.ConditionName != "" {
151
+ message := "Got New Relic event"
152
+ log.Printf(message)
153
+ event_format = Newrelic
154
+ }
155
+
156
+ // Check if its a SNS
157
+ err = json.Unmarshal(body, &SNSData)
158
+ if SNSData.SigningCertURL != "" {
159
+ message := "Got SNS event"
160
+ log.Printf(message)
161
+ event_format = SNS
162
+ }
163
+
164
+ switch event_format {
165
+ case Normal:
166
+ err = json.Unmarshal(body, &input_state)
167
+ if err != nil {
168
+ message := "Error: Couldn't read request body: %s\n"
169
+ log.Println(message, err)
170
+ fmt.Fprintf(w, message, err)
171
+ return
172
+ }
173
+ case Newrelic:
174
+ var event_state string
175
+ switch strings.ToLower(NRAlarm.CurrentState) {
176
+ case "alarm":
177
+ event_state = "critical"
178
+ default:
179
+ event_state = "ok"
180
+ }
181
+ new_details := fmt.Sprint("New Relic Alert Received: ", NRAlarm.Details, " Ack the alert using the following URL: ", NRAlarm.IncidentAcknowledgeURL)
182
+ state = State{
183
+ flapjack.Event{
184
+ Entity: NRAlarm.PolicyName,
185
+ Check: NRAlarm.ConditionName,
186
+ // Type: "service", // @TODO: Make this magic
187
+ State: event_state,
188
+ Summary: new_details,
189
+ },
190
+ 0,
191
+ tags,
192
+ }
193
+
194
+ case SNS:
195
+ var sns_subscription SNSSubscribe
196
+ var cw_alarm CWAlarm
197
+
198
+ body, err := ioutil.ReadAll(r.Body)
199
+ if err != nil {
200
+ message := "Error: Couldn't read request body: %s\n"
201
+ log.Printf(message, err)
202
+ fmt.Fprintf(w, message, err)
203
+ return
204
+ }
205
+
206
+ json.Unmarshal(body, &sns_subscription)
207
+ if sns_subscription.SubscribeURL != "" {
208
+ http.Get(sns_subscription.SubscribeURL)
209
+ return
210
+ }
211
+
212
+ input_message := []byte(SNSData.Message)
213
+ err = json.Unmarshal(input_message, &cw_alarm)
214
+ if err != nil {
215
+ message := "Error: Couldn't read request body from the SNS message: %s\n"
216
+ log.Println(message, err)
217
+ fmt.Fprintf(w, message, err)
218
+ return
219
+ }
220
+
221
+ var event_state string
222
+ switch strings.ToLower(cw_alarm.NewStateValue) {
223
+ case "alarm":
224
+ event_state = "critical"
225
+ default:
226
+ event_state = "ok"
227
+ }
228
+
229
+ state = State{
230
+ flapjack.Event{
231
+ Entity: cw_alarm.AlarmName,
232
+ Check: cw_alarm.Trigger.MetricName,
233
+ State: event_state,
234
+ Summary: cw_alarm.NewStateReason,
235
+ },
236
+ 0,
237
+ tags,
238
+ }
42
239
  }
43
240
 
44
241
  // Populate a time if none has been set.
@@ -54,6 +251,10 @@ func CreateState(updates chan State, w http.ResponseWriter, r *http.Request) {
54
251
  state.TTL = 300
55
252
  }
56
253
 
254
+ if state.Tags.FromBroker == "" {
255
+ state.Tags.FromBroker = "httpbroker"
256
+ }
257
+
57
258
  updates <- state
58
259
 
59
260
  json, _ := json.Marshal(state)
@@ -110,11 +311,12 @@ func submitCachedState(states map[string]State, config Config) {
110
311
  }
111
312
 
112
313
  var (
113
- port = kingpin.Flag("port", "Address to bind HTTP server (default 3090)").Default("3090").OverrideDefaultFromEnvar("PORT").String()
114
- server = kingpin.Flag("server", "Redis server to connect to (default localhost:6380)").Default("localhost:6380").String()
115
- database = kingpin.Flag("database", "Redis database to connect to (default 0)").Int() // .Default("13").Int()
116
- interval = kingpin.Flag("interval", "How often to submit events (default 10s)").Default("10s").Duration()
117
- debug = kingpin.Flag("debug", "Enable verbose output (default false)").Bool()
314
+ app = kingpin.New("httpbroker", "Accepts HTTP events for Flapjack.")
315
+ port = app.Flag("port", "Address to bind HTTP server (default 3090)").Default("3090").OverrideDefaultFromEnvar("PORT").String()
316
+ server = app.Flag("server", "Redis server to connect to (default localhost:6380)").Default("localhost:6380").String()
317
+ database = app.Flag("database", "Redis database to connect to (default 0)").Int() // .Default("13").Int()
318
+ interval = app.Flag("interval", "How often to submit events (default 10s)").Default("10s").Duration()
319
+ debug = app.Flag("debug", "Enable verbose output (default false)").Bool()
118
320
  )
119
321
 
120
322
  type Config struct {
@@ -126,8 +328,10 @@ type Config struct {
126
328
  }
127
329
 
128
330
  func main() {
129
- kingpin.Version("0.0.1")
130
- kingpin.Parse()
331
+ app.Version("0.0.1")
332
+ app.Writer(os.Stdout) // direct help to stdout
333
+ kingpin.MustParse(app.Parse(os.Args[1:]))
334
+ app.Writer(os.Stderr) // ... but ensure errors go to stderr
131
335
 
132
336
  config := Config{
133
337
  Server: *server,
@@ -4,25 +4,28 @@ import (
4
4
  "encoding/json"
5
5
  "flapjack"
6
6
  "fmt"
7
- "gopkg.in/alecthomas/kingpin.v1"
7
+ "gopkg.in/alecthomas/kingpin.v2"
8
8
  "os"
9
9
  "strings"
10
10
  "time"
11
11
  )
12
12
 
13
13
  var (
14
- entity = kingpin.Arg("entity", "Entity name").Required().String()
15
- check = kingpin.Arg("check", "Check name").Required().String()
16
- state = kingpin.Arg("state", "Current state").Required().String()
17
- summary = kingpin.Arg("summary", "Summary of event").Required().String()
18
- debug = kingpin.Flag("debug", "Enable verbose output (default false)").Bool()
19
- server = kingpin.Flag("server", "Redis server to connect to (default localhost:6380)").Default("localhost:6380").String()
20
- database = kingpin.Flag("database", "Redis database to connect to (default 0)").Int()
14
+ app = kingpin.New("oneoff", "Submits a single event to Flapjack.")
15
+ entity = app.Arg("entity", "Entity name").Required().String()
16
+ check = app.Arg("check", "Check name").Required().String()
17
+ state = app.Arg("state", "Current state").Required().String()
18
+ summary = app.Arg("summary", "Summary of event").Required().String()
19
+ debug = app.Flag("debug", "Enable verbose output (default false)").Bool()
20
+ server = app.Flag("server", "Redis server to connect to (default localhost:6380)").Default("localhost:6380").String()
21
+ database = app.Flag("database", "Redis database to connect to (default 0)").Int()
21
22
  )
22
23
 
23
24
  func main() {
24
- kingpin.Version("0.0.1")
25
- kingpin.Parse()
25
+ app.Version("0.0.1")
26
+ app.Writer(os.Stdout) // direct help to stdout
27
+ kingpin.MustParse(app.Parse(os.Args[1:]))
28
+ app.Writer(os.Stderr) // ... but ensure errors go to stderr
26
29
 
27
30
  if *debug {
28
31
  fmt.Println("Entity:", *entity)