flapjack 1.6.0 → 2.0.0b1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -6
  3. data/.gitmodules +1 -1
  4. data/.rspec +1 -1
  5. data/.ruby-version +1 -1
  6. data/.travis.yml +12 -13
  7. data/CHANGELOG.md +2 -9
  8. data/CONTRIBUTING.md +7 -2
  9. data/Gemfile +4 -13
  10. data/LICENCE +1 -0
  11. data/README.md +8 -2
  12. data/Rakefile +2 -2
  13. data/bin/flapjack +3 -12
  14. data/build.sh +4 -2
  15. data/etc/flapjack_config.toml.example +273 -0
  16. data/features/ack_after_sched_maint.feature +18 -21
  17. data/features/cli.feature +11 -71
  18. data/features/cli_flapjack-feed-events.feature +14 -15
  19. data/features/cli_flapjack-nagios-receiver.feature +12 -41
  20. data/features/cli_flapper.feature +12 -41
  21. data/features/cli_purge.feature +5 -6
  22. data/features/cli_receive-events.feature +6 -7
  23. data/features/cli_simulate-failed-check.feature +5 -6
  24. data/features/events.feature +206 -181
  25. data/features/events_check_names.feature +4 -7
  26. data/features/notification_rules.feature +144 -223
  27. data/features/notifications.feature +65 -57
  28. data/features/rollup.feature +45 -47
  29. data/features/steps/cli_steps.rb +4 -5
  30. data/features/steps/events_steps.rb +163 -373
  31. data/features/steps/notifications_steps.rb +408 -264
  32. data/features/steps/packaging-lintian_steps.rb +0 -4
  33. data/features/steps/time_travel_steps.rb +0 -26
  34. data/features/support/daemons.rb +6 -31
  35. data/features/support/env.rb +65 -74
  36. data/flapjack.gemspec +22 -24
  37. data/lib/flapjack.rb +14 -7
  38. data/lib/flapjack/cli/flapper.rb +74 -173
  39. data/lib/flapjack/cli/maintenance.rb +278 -109
  40. data/lib/flapjack/cli/migrate.rb +950 -0
  41. data/lib/flapjack/cli/purge.rb +19 -22
  42. data/lib/flapjack/cli/receiver.rb +150 -326
  43. data/lib/flapjack/cli/server.rb +8 -235
  44. data/lib/flapjack/cli/simulate.rb +42 -57
  45. data/lib/flapjack/configuration.rb +51 -37
  46. data/lib/flapjack/coordinator.rb +138 -129
  47. data/lib/flapjack/data/acknowledgement.rb +177 -0
  48. data/lib/flapjack/data/alert.rb +97 -158
  49. data/lib/flapjack/data/check.rb +611 -0
  50. data/lib/flapjack/data/condition.rb +70 -0
  51. data/lib/flapjack/data/contact.rb +226 -456
  52. data/lib/flapjack/data/event.rb +96 -184
  53. data/lib/flapjack/data/extensions/associations.rb +59 -0
  54. data/lib/flapjack/data/extensions/short_name.rb +25 -0
  55. data/lib/flapjack/data/medium.rb +428 -0
  56. data/lib/flapjack/data/metrics.rb +194 -0
  57. data/lib/flapjack/data/notification.rb +22 -281
  58. data/lib/flapjack/data/rule.rb +473 -0
  59. data/lib/flapjack/data/scheduled_maintenance.rb +244 -0
  60. data/lib/flapjack/data/state.rb +221 -0
  61. data/lib/flapjack/data/statistic.rb +112 -0
  62. data/lib/flapjack/data/tag.rb +277 -0
  63. data/lib/flapjack/data/test_notification.rb +182 -0
  64. data/lib/flapjack/data/unscheduled_maintenance.rb +159 -0
  65. data/lib/flapjack/data/validators/id_validator.rb +20 -0
  66. data/lib/flapjack/exceptions.rb +6 -0
  67. data/lib/flapjack/filters/acknowledgement.rb +23 -16
  68. data/lib/flapjack/filters/base.rb +0 -5
  69. data/lib/flapjack/filters/delays.rb +53 -43
  70. data/lib/flapjack/filters/ok.rb +23 -14
  71. data/lib/flapjack/filters/scheduled_maintenance.rb +3 -3
  72. data/lib/flapjack/filters/unscheduled_maintenance.rb +12 -3
  73. data/lib/flapjack/gateways/aws_sns.rb +65 -49
  74. data/lib/flapjack/gateways/aws_sns/alert.text.erb +2 -2
  75. data/lib/flapjack/gateways/aws_sns/alert_subject.text.erb +2 -2
  76. data/lib/flapjack/gateways/aws_sns/rollup_subject.text.erb +1 -1
  77. data/lib/flapjack/gateways/email.rb +107 -90
  78. data/lib/flapjack/gateways/email/alert.html.erb +19 -18
  79. data/lib/flapjack/gateways/email/alert.text.erb +20 -14
  80. data/lib/flapjack/gateways/email/alert_subject.text.erb +2 -1
  81. data/lib/flapjack/gateways/email/rollup.html.erb +14 -13
  82. data/lib/flapjack/gateways/email/rollup.text.erb +13 -10
  83. data/lib/flapjack/gateways/jabber.rb +679 -671
  84. data/lib/flapjack/gateways/jabber/alert.text.erb +9 -6
  85. data/lib/flapjack/gateways/jsonapi.rb +164 -350
  86. data/lib/flapjack/gateways/jsonapi/data/join_descriptor.rb +44 -0
  87. data/lib/flapjack/gateways/jsonapi/data/method_descriptor.rb +21 -0
  88. data/lib/flapjack/gateways/jsonapi/helpers/headers.rb +63 -0
  89. data/lib/flapjack/gateways/jsonapi/helpers/miscellaneous.rb +136 -0
  90. data/lib/flapjack/gateways/jsonapi/helpers/resources.rb +227 -0
  91. data/lib/flapjack/gateways/jsonapi/helpers/serialiser.rb +313 -0
  92. data/lib/flapjack/gateways/jsonapi/helpers/swagger_docs.rb +322 -0
  93. data/lib/flapjack/gateways/jsonapi/methods/association_delete.rb +115 -0
  94. data/lib/flapjack/gateways/jsonapi/methods/association_get.rb +288 -0
  95. data/lib/flapjack/gateways/jsonapi/methods/association_patch.rb +178 -0
  96. data/lib/flapjack/gateways/jsonapi/methods/association_post.rb +116 -0
  97. data/lib/flapjack/gateways/jsonapi/methods/metrics.rb +71 -0
  98. data/lib/flapjack/gateways/jsonapi/methods/resource_delete.rb +119 -0
  99. data/lib/flapjack/gateways/jsonapi/methods/resource_get.rb +186 -0
  100. data/lib/flapjack/gateways/jsonapi/methods/resource_patch.rb +239 -0
  101. data/lib/flapjack/gateways/jsonapi/methods/resource_post.rb +197 -0
  102. data/lib/flapjack/gateways/jsonapi/middleware/array_param_fixer.rb +27 -0
  103. data/lib/flapjack/gateways/jsonapi/{rack → middleware}/json_params_parser.rb +7 -6
  104. data/lib/flapjack/gateways/jsonapi/middleware/request_timestamp.rb +18 -0
  105. data/lib/flapjack/gateways/oobetet.rb +222 -170
  106. data/lib/flapjack/gateways/pager_duty.rb +388 -0
  107. data/lib/flapjack/gateways/pager_duty/alert.text.erb +13 -0
  108. data/lib/flapjack/gateways/slack.rb +56 -48
  109. data/lib/flapjack/gateways/slack/alert.text.erb +1 -1
  110. data/lib/flapjack/gateways/slack/rollup.text.erb +1 -1
  111. data/lib/flapjack/gateways/sms_aspsms.rb +155 -0
  112. data/lib/flapjack/gateways/sms_aspsms/alert.text.erb +7 -0
  113. data/lib/flapjack/gateways/sms_aspsms/rollup.text.erb +2 -0
  114. data/lib/flapjack/gateways/sms_messagenet.rb +77 -57
  115. data/lib/flapjack/gateways/sms_messagenet/alert.text.erb +3 -2
  116. data/lib/flapjack/gateways/sms_nexmo.rb +53 -51
  117. data/lib/flapjack/gateways/sms_nexmo/alert.text.erb +2 -2
  118. data/lib/flapjack/gateways/sms_nexmo/rollup.text.erb +1 -1
  119. data/lib/flapjack/gateways/sms_twilio.rb +79 -62
  120. data/lib/flapjack/gateways/sms_twilio/alert.text.erb +3 -2
  121. data/lib/flapjack/gateways/web.rb +437 -345
  122. data/lib/flapjack/gateways/web/middleware/request_timestamp.rb +18 -0
  123. data/lib/flapjack/gateways/web/public/css/bootstrap.css +3793 -4340
  124. data/lib/flapjack/gateways/web/public/css/bootstrap.css.map +1 -0
  125. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.eot +0 -0
  126. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.svg +273 -214
  127. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.ttf +0 -0
  128. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.woff +0 -0
  129. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.woff2 +0 -0
  130. data/lib/flapjack/gateways/web/public/js/bootstrap.js +1637 -1607
  131. data/lib/flapjack/gateways/web/public/js/self_stats.js +1 -2
  132. data/lib/flapjack/gateways/web/views/_pagination.html.erb +19 -0
  133. data/lib/flapjack/gateways/web/views/check.html.erb +159 -121
  134. data/lib/flapjack/gateways/web/views/checks.html.erb +82 -41
  135. data/lib/flapjack/gateways/web/views/contact.html.erb +59 -71
  136. data/lib/flapjack/gateways/web/views/contacts.html.erb +32 -8
  137. data/lib/flapjack/gateways/web/views/index.html.erb +2 -2
  138. data/lib/flapjack/gateways/web/views/{layout.erb → layout.html.erb} +7 -23
  139. data/lib/flapjack/gateways/web/views/self_stats.html.erb +32 -33
  140. data/lib/flapjack/gateways/web/views/tag.html.erb +32 -0
  141. data/lib/flapjack/gateways/web/views/tags.html.erb +51 -0
  142. data/lib/flapjack/logger.rb +34 -3
  143. data/lib/flapjack/notifier.rb +180 -112
  144. data/lib/flapjack/patches.rb +8 -63
  145. data/lib/flapjack/pikelet.rb +185 -143
  146. data/lib/flapjack/processor.rb +323 -191
  147. data/lib/flapjack/record_queue.rb +33 -0
  148. data/lib/flapjack/redis_proxy.rb +66 -0
  149. data/lib/flapjack/utility.rb +21 -15
  150. data/lib/flapjack/version.rb +2 -1
  151. data/libexec/httpbroker.go +218 -14
  152. data/libexec/oneoff.go +13 -10
  153. data/spec/lib/flapjack/configuration_spec.rb +286 -0
  154. data/spec/lib/flapjack/coordinator_spec.rb +103 -157
  155. data/spec/lib/flapjack/data/check_spec.rb +175 -0
  156. data/spec/lib/flapjack/data/contact_spec.rb +26 -349
  157. data/spec/lib/flapjack/data/event_spec.rb +76 -291
  158. data/spec/lib/flapjack/data/medium_spec.rb +19 -0
  159. data/spec/lib/flapjack/data/rule_spec.rb +43 -0
  160. data/spec/lib/flapjack/data/scheduled_maintenance_spec.rb +976 -0
  161. data/spec/lib/flapjack/data/unscheduled_maintenance_spec.rb +34 -0
  162. data/spec/lib/flapjack/gateways/aws_sns_spec.rb +111 -60
  163. data/spec/lib/flapjack/gateways/email_spec.rb +194 -161
  164. data/spec/lib/flapjack/gateways/jabber_spec.rb +961 -162
  165. data/spec/lib/flapjack/gateways/jsonapi/methods/check_links_spec.rb +155 -0
  166. data/spec/lib/flapjack/gateways/jsonapi/methods/checks_spec.rb +426 -0
  167. data/spec/lib/flapjack/gateways/jsonapi/methods/contact_links_spec.rb +217 -0
  168. data/spec/lib/flapjack/gateways/jsonapi/methods/contacts_spec.rb +425 -0
  169. data/spec/lib/flapjack/gateways/jsonapi/methods/events_spec.rb +271 -0
  170. data/spec/lib/flapjack/gateways/jsonapi/methods/media_spec.rb +257 -0
  171. data/spec/lib/flapjack/gateways/jsonapi/methods/medium_links_spec.rb +163 -0
  172. data/spec/lib/flapjack/gateways/jsonapi/methods/metrics_spec.rb +8 -0
  173. data/spec/lib/flapjack/gateways/jsonapi/methods/rule_links_spec.rb +212 -0
  174. data/spec/lib/flapjack/gateways/jsonapi/methods/rules_spec.rb +289 -0
  175. data/spec/lib/flapjack/gateways/jsonapi/methods/scheduled_maintenance_links_spec.rb +49 -0
  176. data/spec/lib/flapjack/gateways/jsonapi/methods/scheduled_maintenances_spec.rb +242 -0
  177. data/spec/lib/flapjack/gateways/jsonapi/methods/tag_links_spec.rb +274 -0
  178. data/spec/lib/flapjack/gateways/jsonapi/methods/tags_spec.rb +302 -0
  179. data/spec/lib/flapjack/gateways/jsonapi/methods/unscheduled_maintenance_links_spec.rb +49 -0
  180. data/spec/lib/flapjack/gateways/jsonapi/methods/unscheduled_maintenances_spec.rb +339 -0
  181. data/spec/lib/flapjack/gateways/jsonapi_spec.rb +1 -1
  182. data/spec/lib/flapjack/gateways/oobetet_spec.rb +151 -79
  183. data/spec/lib/flapjack/gateways/pager_duty_spec.rb +353 -0
  184. data/spec/lib/flapjack/gateways/slack_spec.rb +53 -53
  185. data/spec/lib/flapjack/gateways/sms_aspsms_spec.rb +106 -0
  186. data/spec/lib/flapjack/gateways/sms_messagenet_spec.rb +111 -54
  187. data/spec/lib/flapjack/gateways/sms_nexmo_spec.rb +50 -51
  188. data/spec/lib/flapjack/gateways/sms_twilio_spec.rb +108 -48
  189. data/spec/lib/flapjack/gateways/web_spec.rb +144 -216
  190. data/spec/lib/flapjack/notifier_spec.rb +132 -1
  191. data/spec/lib/flapjack/pikelet_spec.rb +111 -50
  192. data/spec/lib/flapjack/processor_spec.rb +210 -40
  193. data/spec/lib/flapjack/redis_proxy_spec.rb +45 -0
  194. data/spec/lib/flapjack/utility_spec.rb +11 -15
  195. data/spec/service_consumers/fixture_data.rb +547 -0
  196. data/spec/service_consumers/pact_helper.rb +21 -32
  197. data/spec/service_consumers/pacts/flapjack-diner_v2.0.json +4652 -0
  198. data/spec/service_consumers/provider_states_for_flapjack-diner.rb +279 -322
  199. data/spec/service_consumers/provider_support.rb +8 -0
  200. data/spec/spec_helper.rb +34 -44
  201. data/spec/support/erb_view_helper.rb +1 -1
  202. data/spec/support/factories.rb +58 -0
  203. data/spec/support/jsonapi_helper.rb +15 -26
  204. data/spec/support/mock_logger.rb +43 -0
  205. data/spec/support/xmpp_comparable.rb +24 -0
  206. data/src/flapjack/transport_test.go +30 -1
  207. data/tasks/dump_keys.rake +82 -0
  208. data/tasks/events.rake +7 -7
  209. data/tasks/support/flapjack_config_benchmark.toml +28 -0
  210. data/tasks/support/flapjack_config_benchmark.yaml +0 -2
  211. metadata +175 -222
  212. data/Guardfile +0 -14
  213. data/etc/flapjack_config.yaml.example +0 -477
  214. data/features/cli_flapjack-populator.feature +0 -90
  215. data/features/support/silent_system.rb +0 -4
  216. data/lib/flapjack/cli/import.rb +0 -108
  217. data/lib/flapjack/data/entity.rb +0 -652
  218. data/lib/flapjack/data/entity_check.rb +0 -1044
  219. data/lib/flapjack/data/message.rb +0 -56
  220. data/lib/flapjack/data/migration.rb +0 -234
  221. data/lib/flapjack/data/notification_rule.rb +0 -425
  222. data/lib/flapjack/data/semaphore.rb +0 -44
  223. data/lib/flapjack/data/tagged.rb +0 -48
  224. data/lib/flapjack/gateways/jsonapi/check_methods.rb +0 -206
  225. data/lib/flapjack/gateways/jsonapi/check_presenter.rb +0 -221
  226. data/lib/flapjack/gateways/jsonapi/contact_methods.rb +0 -186
  227. data/lib/flapjack/gateways/jsonapi/entity_methods.rb +0 -223
  228. data/lib/flapjack/gateways/jsonapi/medium_methods.rb +0 -185
  229. data/lib/flapjack/gateways/jsonapi/metrics_methods.rb +0 -132
  230. data/lib/flapjack/gateways/jsonapi/notification_rule_methods.rb +0 -141
  231. data/lib/flapjack/gateways/jsonapi/pagerduty_credential_methods.rb +0 -139
  232. data/lib/flapjack/gateways/jsonapi/report_methods.rb +0 -146
  233. data/lib/flapjack/gateways/pagerduty.rb +0 -318
  234. data/lib/flapjack/gateways/pagerduty/alert.text.erb +0 -10
  235. data/lib/flapjack/gateways/web/public/css/select2-bootstrap.css +0 -87
  236. data/lib/flapjack/gateways/web/public/css/select2.css +0 -615
  237. data/lib/flapjack/gateways/web/public/css/tablesort.css +0 -67
  238. data/lib/flapjack/gateways/web/public/img/select2-spinner.gif +0 -0
  239. data/lib/flapjack/gateways/web/public/img/select2.png +0 -0
  240. data/lib/flapjack/gateways/web/public/img/select2x2.png +0 -0
  241. data/lib/flapjack/gateways/web/public/js/backbone.js +0 -1581
  242. data/lib/flapjack/gateways/web/public/js/backbone.jsonapi.js +0 -322
  243. data/lib/flapjack/gateways/web/public/js/flapjack.js +0 -82
  244. data/lib/flapjack/gateways/web/public/js/jquery.tablesorter.js +0 -1640
  245. data/lib/flapjack/gateways/web/public/js/jquery.tablesorter.widgets.js +0 -1390
  246. data/lib/flapjack/gateways/web/public/js/modules/contact.js +0 -520
  247. data/lib/flapjack/gateways/web/public/js/modules/entity.js +0 -28
  248. data/lib/flapjack/gateways/web/public/js/modules/medium.js +0 -40
  249. data/lib/flapjack/gateways/web/public/js/select2.js +0 -3397
  250. data/lib/flapjack/gateways/web/public/js/tablesort.js +0 -44
  251. data/lib/flapjack/gateways/web/public/js/underscore.js +0 -1276
  252. data/lib/flapjack/gateways/web/views/edit_contacts.html.erb +0 -173
  253. data/lib/flapjack/gateways/web/views/entities.html.erb +0 -30
  254. data/lib/flapjack/gateways/web/views/entity.html.erb +0 -51
  255. data/lib/flapjack/rack_logger.rb +0 -47
  256. data/lib/flapjack/redis_pool.rb +0 -42
  257. data/spec/lib/flapjack/data/entity_check_spec.rb +0 -1418
  258. data/spec/lib/flapjack/data/entity_spec.rb +0 -872
  259. data/spec/lib/flapjack/data/message_spec.rb +0 -30
  260. data/spec/lib/flapjack/data/migration_spec.rb +0 -104
  261. data/spec/lib/flapjack/data/notification_rule_spec.rb +0 -232
  262. data/spec/lib/flapjack/data/notification_spec.rb +0 -53
  263. data/spec/lib/flapjack/data/semaphore_spec.rb +0 -24
  264. data/spec/lib/flapjack/filters/acknowledgement_spec.rb +0 -6
  265. data/spec/lib/flapjack/filters/delays_spec.rb +0 -6
  266. data/spec/lib/flapjack/filters/ok_spec.rb +0 -6
  267. data/spec/lib/flapjack/filters/scheduled_maintenance_spec.rb +0 -6
  268. data/spec/lib/flapjack/filters/unscheduled_maintenance_spec.rb +0 -6
  269. data/spec/lib/flapjack/gateways/jsonapi/check_methods_spec.rb +0 -315
  270. data/spec/lib/flapjack/gateways/jsonapi/check_presenter_spec.rb +0 -223
  271. data/spec/lib/flapjack/gateways/jsonapi/contact_methods_spec.rb +0 -131
  272. data/spec/lib/flapjack/gateways/jsonapi/entity_methods_spec.rb +0 -389
  273. data/spec/lib/flapjack/gateways/jsonapi/medium_methods_spec.rb +0 -231
  274. data/spec/lib/flapjack/gateways/jsonapi/notification_rule_methods_spec.rb +0 -169
  275. data/spec/lib/flapjack/gateways/jsonapi/pagerduty_credential_methods_spec.rb +0 -114
  276. data/spec/lib/flapjack/gateways/jsonapi/report_methods_spec.rb +0 -590
  277. data/spec/lib/flapjack/gateways/pagerduty_spec.rb +0 -249
  278. data/spec/lib/flapjack/gateways/web/views/check.html.erb_spec.rb +0 -21
  279. data/spec/lib/flapjack/gateways/web/views/contact.html.erb_spec.rb +0 -24
  280. data/spec/lib/flapjack/gateways/web/views/index.html.erb_spec.rb +0 -16
  281. data/spec/lib/flapjack/redis_pool_spec.rb +0 -29
  282. data/spec/service_consumers/pacts/flapjack-diner_v1.0.json +0 -4702
  283. data/tasks/entities.rake +0 -151
  284. data/tasks/profile.rake +0 -282
  285. data/tmp/acknowledge.rb +0 -13
  286. data/tmp/create_config_yaml.rb +0 -16
  287. data/tmp/create_event_ok.rb +0 -30
  288. data/tmp/create_event_unknown.rb +0 -30
  289. data/tmp/create_events_failure.rb +0 -34
  290. data/tmp/create_events_ok.rb +0 -32
  291. data/tmp/create_events_ok_fail_ack_ok.rb +0 -53
  292. data/tmp/create_events_ok_failure.rb +0 -41
  293. data/tmp/create_events_ok_failure_ack.rb +0 -53
  294. data/tmp/dummy_contacts.json +0 -43
  295. data/tmp/dummy_entities.json +0 -37
  296. data/tmp/generate_nagios_test_hosts.rb +0 -16
  297. data/tmp/notification_rules.rb +0 -73
  298. data/tmp/parse_config_yaml.rb +0 -7
  299. data/tmp/redis_find_spurious_unknown_states.rb +0 -52
  300. data/tmp/test_json_post.rb +0 -19
  301. data/tmp/test_notification_rules_api.rb +0 -171
@@ -1,90 +0,0 @@
1
- @process
2
- Feature: flapjack-populator command line
3
- As a systems administrator
4
- I should be able to use flapjack-populator
5
- From the command line
6
-
7
- Background:
8
- Given a file named "flapjack-populator.yaml" with:
9
- """
10
- test:
11
- redis:
12
- db: 14
13
- driver: ruby
14
- """
15
- And a file named "flapjack-populator-contacts.json" with:
16
- """
17
- [
18
- {
19
- "id": "21",
20
- "first_name": "Ada",
21
- "last_name": "Lovelace",
22
- "email": "ada@example.com",
23
- "media": {
24
- "sms": {
25
- "address": "+61412345678",
26
- "interval": "3600",
27
- "rollup_threshold": "5"
28
- },
29
- "email": {
30
- "address": "ada@example.com",
31
- "interval": "7200",
32
- "rollup_threshold": null
33
- }
34
- },
35
- "tags": [
36
- "legend",
37
- "first computer programmer"
38
- ]
39
- }
40
- ]
41
- """
42
- And a file named "flapjack-populator-entities.json" with:
43
- """
44
- [
45
- {
46
- "id": "10001",
47
- "name": "clientx-app-01",
48
- "contacts": [
49
- "362",
50
- "363",
51
- "364"
52
- ],
53
- "tags": [
54
- "source:titanium",
55
- "foo"
56
- ]
57
- }
58
- ]
59
- """
60
-
61
- Scenario: Running with --help shows usage information
62
- When I run `bundle exec bin/flapjack import --help`
63
- Then the exit status should be 0
64
- And the output should contain "Bulk import data from an external source"
65
- And the output should contain "import contacts"
66
- And the output should contain "import entities"
67
- And the output should contain "[-f arg|--from arg]"
68
-
69
- Scenario: Running flapjack-populator with no arguments exits uncleanly and shows usage
70
- When I run `bundle exec bin/flapjack import`
71
- Then the exit status should not be 0
72
- And the output should contain "Bulk import data from an external source"
73
-
74
- Scenario: Importing contacts
75
- When I run `bundle exec bin/flapjack -n test --config tmp/cucumber_cli/flapjack-populator.yaml import contacts --from tmp/cucumber_cli/flapjack-populator-contacts.json`
76
- Then the exit status should be 0
77
-
78
- Scenario: Importing entities
79
- When I run `bundle exec bin/flapjack -n test --config tmp/cucumber_cli/flapjack-populator.yaml import entities --from tmp/cucumber_cli/flapjack-populator-entities.json`
80
- Then the exit status should be 0
81
-
82
- Scenario Outline: Running an flapjack-populator import command with a missing '--from' exits uncleanly and shows usage
83
- When I run `bundle exec bin/flapjack -n test --config tmp/cucumber_cli/flapjack-populator.yaml import <Type> example.json`
84
- Then the exit status should not be 0
85
- And the output should contain "error: f is required"
86
- And the output should contain "Bulk import data from an external source"
87
- Examples:
88
- | Type |
89
- | entities |
90
- | contacts |
@@ -1,4 +0,0 @@
1
- def silent_system(cmd)
2
- #silent_cmd = cmd + " 2>&1 > /dev/null"
3
- @output = `#{cmd}`
4
- end
@@ -1,108 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'redis'
4
-
5
- require 'flapjack/configuration'
6
- require 'flapjack/data/contact'
7
- require 'flapjack/data/entity'
8
- require 'flapjack/data/migration'
9
-
10
- module Flapjack
11
- module CLI
12
- class Import
13
-
14
- def initialize(global_options, options)
15
- @global_options = global_options
16
- @options = options
17
-
18
- if @global_options[:'force-utf8']
19
- Encoding.default_external = 'UTF-8'
20
- Encoding.default_internal = 'UTF-8'
21
- end
22
-
23
- config = Flapjack::Configuration.new
24
- config.load(global_options[:config])
25
- @config_env = config.all
26
-
27
- if @config_env.nil? || @config_env.empty?
28
- exit_now! "No config data for environment '#{FLAPJACK_ENV}' found in '#{global_options[:config]}'"
29
- end
30
-
31
- @redis_options = config.for_redis
32
- end
33
-
34
- # TODO should these be similar to JSONAPI structures? e.g.
35
- # {'contacts' => [CONTACT_HASH, ...]}
36
-
37
- def contacts
38
- conts = Flapjack.load_json(File.new(@options[:from]))
39
-
40
- if conts && conts.is_a?(Enumerable) && conts.any? {|e| !e['id'].nil?}
41
- conts.each do |contact|
42
- unless contact['id']
43
- puts "Contact not imported as it has no id: " + contact.inspect
44
- next
45
- end
46
- Flapjack::Data::Contact.add(contact, :redis => redis)
47
- end
48
- end
49
-
50
- end
51
-
52
- def entities
53
- ents = Flapjack.load_json(File.new(@options[:from]))
54
-
55
- if ents && ents.is_a?(Enumerable) && ents.any? {|e| !e['id'].nil?}
56
- ents.each do |entity|
57
- unless entity['id']
58
- puts "Entity not imported as it has no id: " + entity.inspect
59
- next
60
- end
61
- Flapjack::Data::Entity.add(entity, :redis => redis)
62
- end
63
- end
64
-
65
- end
66
-
67
- private
68
-
69
- def redis
70
- return @redis unless @redis.nil?
71
- @redis = Redis.new(@redis_options.merge(:driver => :hiredis))
72
- Flapjack::Data::Migration.migrate_entity_check_data_if_required(:redis => @redis)
73
- Flapjack::Data::Migration.clear_orphaned_entity_ids(:redis => @redis)
74
- @redis
75
- end
76
-
77
- end
78
- end
79
- end
80
-
81
- desc 'Bulk import data from an external source, reading from JSON formatted data files'
82
- command :import do |import|
83
-
84
- import.desc 'Import contacts'
85
- import.command :contacts do |contacts|
86
-
87
- contacts.flag [:f, 'from'], :desc => 'PATH of the contacts JSON file to import',
88
- :required => true
89
-
90
- contacts.action do |global_options,options,args|
91
- import = Flapjack::CLI::Import.new(global_options, options)
92
- import.contacts
93
- end
94
- end
95
-
96
- import.desc 'Import entities'
97
- import.command :entities do |entities|
98
-
99
- entities.flag [:f, 'from'], :desc => 'PATH of the entities JSON file to import',
100
- :required => true
101
-
102
- entities.action do |global_options,options,args|
103
- import = Flapjack::CLI::Import.new(global_options, options)
104
- import.entities
105
- end
106
- end
107
-
108
- end
@@ -1,652 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'securerandom'
4
-
5
- require 'flapjack/data/contact'
6
- require 'flapjack/data/tagged'
7
-
8
- module Flapjack
9
-
10
- module Data
11
-
12
- class Entity
13
-
14
- attr_accessor :name, :id
15
-
16
- include Tagged
17
-
18
- def self.all(options = {})
19
- raise "Redis connection not set" unless redis = options[:redis]
20
-
21
- current_entity_names = (options.has_key?(:enabled) && !options[:enabled].nil?) ?
22
- Flapjack::Data::Entity.current_names(:redis => redis) : nil
23
-
24
- all_entity_names_by_id = redis.hgetall("all_entity_names_by_id")
25
- return [] if all_entity_names_by_id.empty?
26
-
27
- all_entity_names_by_id.inject([]) {|memo, (eid, ename)|
28
- if options[:enabled].nil? ||
29
- (options[:enabled].is_a?(TrueClass) && current_entity_names.include?(ename) ) ||
30
- (options[:enabled].is_a?(FalseClass) && !current_entity_names.include?(ename))
31
-
32
- memo << self.new(:name => ename, :id => eid, :redis => redis)
33
- end
34
- memo
35
- }.sort_by(&:name)
36
- end
37
-
38
- # no way to lock all data operations, so hit & hope... at least the renames
39
- # should be atomic
40
- def self.rename(existing_name, entity_name, options = {})
41
- raise "Redis connection not set" unless redis = options[:redis]
42
-
43
- check_state_keys = redis.keys("check:#{existing_name}:*")
44
-
45
- check_history_keys = redis.keys("#{existing_name}:*:states") +
46
- redis.keys("#{existing_name}:*:state") +
47
- redis.keys("#{existing_name}:*:sorted_state_timestamps")
48
-
49
- action_keys = redis.keys("#{existing_name}:*:actions")
50
-
51
- maint_keys = redis.keys("#{existing_name}:*:*scheduled_maintenance*")
52
-
53
- all_summary_keys = redis.keys("#{existing_name}:*:summary")
54
- maint_summary_keys = redis.keys("#{existing_name}:*:*scheduled_maintenance:summary")
55
- check_summary_keys = all_summary_keys - maint_summary_keys
56
-
57
- check_history_keys += check_summary_keys
58
-
59
- notif_keys = redis.keys("#{existing_name}:*:last_*_notification") +
60
- redis.keys("#{existing_name}:*:*_notifications")
61
-
62
- alerting_check_keys = redis.keys("contact_alerting_checks:*")
63
-
64
- all_checks = {}
65
- failed_checks = {}
66
- hashes_to_remove = []
67
- hashes_to_add = {}
68
-
69
- alerting_to_remove = {}
70
- alerting_to_add = {}
71
-
72
- sha1 = Digest::SHA1.new
73
-
74
- checks = check_state_keys.collect do |state_key|
75
- state_key =~ /^check:#{Regexp.escape(existing_name)}:(.+)$/
76
- $1
77
- end
78
-
79
- checks.each do |ch|
80
- existing_check = "#{existing_name}:#{ch}"
81
- new_check = "#{entity_name}:#{ch}"
82
-
83
- ch_all_score = redis.zscore("all_checks", existing_check)
84
- all_checks[ch] = ch_all_score unless ch_all_score.nil?
85
-
86
- ch_fail_score = redis.zscore("failed_checks", existing_check)
87
- failed_checks[ch] = ch_fail_score unless ch_fail_score.nil?
88
-
89
- hashes_to_remove << Digest.hexencode(sha1.digest(existing_check))[0..7].downcase
90
- hashes_to_add[Digest.hexencode(sha1.digest(new_check))[0..7].downcase] = new_check
91
-
92
- alerting_check_keys.each do |ack|
93
- ack_score = redis.zscore(ack, existing_check)
94
- unless ack_score.nil?
95
- alerting_to_remove[ack] ||= []
96
- alerting_to_remove[ack] << existing_check
97
-
98
- alerting_to_add[ack] ||= {}
99
- alerting_to_add[ack][new_check] = ack_score
100
- end
101
- end
102
- end
103
-
104
- current_score = redis.zscore('current_entities', existing_name)
105
-
106
- block_keys = redis.keys("drop_alerts_for_contact:*:*:#{existing_name}:*:*")
107
-
108
- rename_all_checks = redis.exists("all_checks:#{existing_name}")
109
- rename_current_checks = redis.exists("current_checks:#{existing_name}")
110
-
111
- redis.multi do |multi|
112
-
113
- yield(multi) if block_given? # entity id -> name update from add()
114
-
115
- check_state_keys.each do |csk|
116
- multi.rename(csk, csk.sub(/^check:#{Regexp.escape(existing_name)}:/, "check:#{entity_name}:"))
117
- end
118
-
119
- (check_history_keys + action_keys + maint_keys + notif_keys).each do |chk|
120
- multi.rename(chk, chk.sub(/^#{Regexp.escape(existing_name)}:/, "#{entity_name}:"))
121
- end
122
-
123
- all_checks.each_pair do |ch, score|
124
- multi.zrem('all_checks', "#{existing_name}:#{ch}")
125
- multi.zadd('all_checks', score, "#{entity_name}:#{ch}")
126
- end
127
-
128
- # currently failing checks
129
- failed_checks.each_pair do |ch, score|
130
- multi.zrem('failed_checks', "#{existing_name}:#{ch}")
131
- multi.zadd('failed_checks', score, "#{entity_name}:#{ch}")
132
- end
133
-
134
- if rename_all_checks
135
- multi.rename("all_checks:#{existing_name}", "all_checks:#{entity_name}")
136
- end
137
-
138
- if rename_current_checks
139
- multi.rename("current_checks:#{existing_name}", "current_checks:#{entity_name}")
140
- end
141
-
142
- unless current_score.nil?
143
- multi.zrem('current_entities', existing_name)
144
- multi.zadd('current_entities', current_score, entity_name)
145
- end
146
-
147
- block_keys.each do |blk|
148
- multi.rename(blk, blk.sub(/^drop_alerts_for_contact:(.+):([^:]+):#{Regexp.escape(existing_name)}:(.+):([^:]+)$/,
149
- "drop_alerts_for_contact:\\1:\\2:#{entity_name}:\\3:\\4"))
150
- end
151
-
152
- hashes_to_remove.each {|hash| multi.hdel('checks_by_hash', hash) }
153
- hashes_to_add.each_pair {|hash, chk| multi.hset('checks_by_hash', hash, chk)}
154
-
155
- alerting_to_remove.each_pair do |alerting, chks|
156
- chks.each {|chk| multi.zrem(alerting, chk)}
157
- end
158
-
159
- alerting_to_add.each_pair do |alerting, chks|
160
- chks.each_pair {|chk, score| multi.zadd(alerting, score, chk)}
161
- end
162
- end
163
- end
164
-
165
- # NB only used by the 'entities:reparent' Rake task, but kept in this
166
- # class to be more easily testable
167
- def self.merge(old_name, current_name, options = {})
168
- raise "Redis connection not set" unless redis = options[:redis]
169
-
170
- check_state_keys = redis.keys("check:#{old_name}:*")
171
-
172
- checks = check_state_keys.collect do |state_key|
173
- state_key =~ /^check:#{Regexp.escape(old_name)}:(.+)$/
174
- $1
175
- end
176
-
177
- alerting_check_keys = redis.keys("contact_alerting_checks:*")
178
-
179
- keys_to_delete = []
180
- keys_to_rename = {}
181
-
182
- all_checks_to_remove = []
183
- all_checks_to_add = {}
184
-
185
- failed_checks_to_remove = []
186
- failed_checks_to_add = {}
187
-
188
- action_data = {}
189
-
190
- notification_types = ['problem', 'unknown', 'warning', 'critical',
191
- 'recovery', 'acknowledgement']
192
-
193
- alerting_check_keys = redis.keys("contact_alerting_checks:*")
194
-
195
- alerting_to_remove = {}
196
- alerting_to_add = {}
197
-
198
- block_keys = redis.keys("drop_alerts_for_contact:*:*:#{old_name}:*:*")
199
-
200
- checks.each do |ch|
201
- old_check = "#{old_name}:#{ch}"
202
- current_check = "#{current_name}:#{ch}"
203
-
204
- old_states = "#{old_check}:states"
205
- new_states = "#{current_check}:states"
206
-
207
- all_checks_to_remove << old_check
208
- failed_checks_to_remove << old_check
209
-
210
- if redis.exists("check:#{current_check}")
211
- keys_to_delete << "check:#{old_check}"
212
-
213
- loop do
214
- # pop from tail, append at head, matches ordering in EntityCheck#update_state
215
- break if redis.rpoplpush(old_states, new_states).nil?
216
- end
217
-
218
- keys_to_delete << old_states
219
- else
220
-
221
- ch_all_score = redis.zscore("all_checks", old_check)
222
- all_checks_to_add[current_check] = ch_all_score unless ch_all_score.nil?
223
-
224
- # can move a failing checks entry over, if it exists
225
- ch_fail_score = redis.zscore("failed_checks", old_check)
226
- failed_checks_to_add[current_check] = ch_fail_score unless ch_fail_score.nil?
227
-
228
- if redis.exists("check:#{old_check}")
229
- keys_to_rename["check:#{old_check}"] = "check:#{current_check}"
230
- end
231
- if redis.exists(old_states)
232
- keys_to_rename[old_states] = new_states
233
- end
234
- end
235
-
236
- notification_types.each do |notif|
237
-
238
- old_notif = "#{old_check}:#{notif}_notifications"
239
- new_notif = "#{current_check}:#{notif}_notifications"
240
-
241
- if redis.exists(new_notif)
242
- loop do
243
- # pop from tail, append at head
244
- break if redis.rpoplpush(old_notif, new_notif).nil?
245
- end
246
-
247
- keys_to_delete << old_notif
248
- elsif redis.exists(old_notif)
249
- keys_to_rename[old_notif] = new_notif
250
- end
251
- end
252
-
253
- alerting_check_keys.each do |ack|
254
- old_score = redis.zscore(ack, old_check)
255
- new_score = redis.zscore(ack, current_check)
256
-
257
- alerting_to_remove[ack] ||= []
258
- alerting_to_remove[ack] << old_check
259
-
260
- # nil.to_i == 0, which is good for a missing value
261
- if !old_score.nil? && new_score.nil? &&
262
- (redis.lindex("#{old_check}:problem_notifications", -1).to_i >
263
- [redis.lindex("#{current_check}:recovery_notifications", -1).to_i,
264
- redis.lindex("#{current_check}:acknowledgement_notifications", -1).to_i].max)
265
-
266
- alerting_to_add[ack] ||= {}
267
- alerting_to_add[ack][current_check] = old_score
268
- end
269
- end
270
-
271
- end
272
-
273
- # TODO all_checks sorted set -- merge/rename entries
274
-
275
- if redis.exists("all_checks:#{current_name}")
276
- keys_to_delete << "all_checks:#{old_name}"
277
- elsif redis.exists("all_checks:#{old_name}")
278
- keys_to_rename["all_checks:#{old_name}"] = "all_checks:#{current_name}"
279
- end
280
-
281
- if redis.exists("current_checks:#{current_name}")
282
- keys_to_delete << "current_checks:#{old_name}"
283
- elsif redis.exists("current_checks:#{old_name}")
284
- keys_to_rename["current_checks:#{old_name}"] = "current_checks:#{current_name}"
285
- end
286
-
287
- current_score = redis.zscore('current_entities', current_name)
288
- old_score = nil
289
-
290
- if current_score.nil?
291
- old_score = redis.zscore('current_entities', old_name)
292
- end
293
-
294
- check_timestamps_keys = redis.keys("#{old_name}:*:sorted_state_timestamps")
295
- keys_to_delete += check_timestamps_keys
296
-
297
- check_history_keys = redis.keys("#{old_name}:*:state") +
298
- redis.keys("#{old_name}:*:summary")
299
-
300
- action_keys = redis.keys("#{old_name}:*:actions")
301
-
302
- action_keys.each do |old_actions|
303
-
304
- old_actions =~ /^#{Regexp.escape(old_name)}:(.+):actions$/
305
- current_actions = "#{current_name}:#{$1}:actions"
306
-
307
- if redis.exists(current_actions)
308
- action_data[current_actions] = redis.hgetall(old_actions)
309
- keys_to_delete << old_actions
310
- elsif redis.exists(old_actions)
311
- keys_to_rename[old_actions] = current_actions
312
- end
313
- end
314
-
315
- maint_keys = redis.keys("#{old_name}:*:*scheduled_maintenance")
316
-
317
- maints_to_delete = []
318
- maints_to_set = {}
319
-
320
- maint_keys.each do |maint_key|
321
- maint_key =~ /^#{Regexp.escape(old_name)}:(.+):((?:un)?scheduled_maintenance)$/
322
- maint_check = $1
323
- maint_type = $2
324
-
325
- new_maint_key = "#{current_name}:#{maint_check}:#{maint_type}"
326
-
327
- # as keys are expiring, check all steps in case they have
328
- old_time, new_time = redis.mget(maint_key, new_maint_key).map(&:to_i)
329
-
330
- old_ttl = (old_time <= 0) ? -1 : redis.ttl(maint_key)
331
- new_ttl = (new_time <= 0) ? -1 : redis.ttl(new_maint_key)
332
-
333
- # TTL < 0 is a redis error code -- key not present, etc.
334
- if (old_ttl >= 0) && ((new_ttl < 0) ||
335
- ((old_time + old_ttl) > (new_time + new_ttl)))
336
- keys_to_rename[maint_key] = new_maint_key if redis.exists(maint_key)
337
- maints_to_set[new_maint_key] = redis.zscore("#{maint_key}s", old_time)
338
- end
339
-
340
- keys_to_delete << maint_key
341
- end
342
-
343
- blocks_to_set = {}
344
-
345
- block_keys.each do |block_key|
346
- block_key =~ /^drop_alerts_for_contact:(.+):([^:]+):#{Regexp.escape(old_name)}:(.+):([^:]+)$/
347
- new_block_key = "drop_alerts_for_contact:#{$1}:#{$2}:#{current_name}:#{$3}:#{$4}"
348
-
349
- # as keys may expire, check whether they have
350
- old_start_ttl, new_start_ttl = redis.mget(block_key, new_block_key).map(&:to_i)
351
-
352
- old_ttl = (old_start_ttl <= 0) ? -1 : redis.ttl(block_key)
353
- new_ttl = (new_start_ttl <= 0) ? -1 : redis.ttl(new_block_key)
354
-
355
- # TTL < 0 is a redis error code -- key not present, etc.
356
- if (old_ttl >= 0) && ((new_ttl < 0) || (old_ttl > new_ttl))
357
- blocks_to_set[new_block_key] = [Time.now.to_i + old_ttl, old_start_ttl]
358
- end
359
-
360
- keys_to_delete << block_key
361
- end
362
-
363
- stored_maint_keys = redis.keys("#{old_name}:*:*scheduled_maintenances") +
364
- redis.keys("#{old_name}:*:sorted_*scheduled_maintenance_timestamps")
365
- keys_to_delete += stored_maint_keys
366
-
367
- notif_keys = redis.keys("#{old_name}:*:last_*_notification")
368
-
369
- redis.multi do |multi|
370
-
371
- check_history_keys.each do |chk|
372
- multi.renamenx(chk, chk.sub(/^#{Regexp.escape(old_name)}:/, "#{current_name}:"))
373
- end
374
-
375
- check_timestamps_keys.each do |ctk|
376
- dest = ctk.sub(/^#{Regexp.escape(old_name)}:/, "#{current_name}:")
377
- multi.zunionstore(dest, [ctk, dest], :aggregate => :max)
378
- end
379
-
380
- all_checks_to_remove.each do |actr|
381
- multi.zrem('all_checks', actr)
382
- end
383
-
384
- all_checks_to_add.each_pair do |acta, score|
385
- multi.zadd('all_checks', score, acta)
386
- end
387
-
388
- failed_checks_to_remove.each do |fctr|
389
- multi.zrem('failed_checks', fctr)
390
- end
391
-
392
- failed_checks_to_add.each_pair do |fcta, score|
393
- multi.zadd('failed_checks', score, fcta)
394
- end
395
-
396
- action_data.each_pair do |action_key, data|
397
- data.each_pair do |k, v|
398
- multi.hsetnx(action_key, k, v)
399
- end
400
- end
401
-
402
- multi.zunionstore("current_checks:#{current_name}",
403
- ["current_checks:#{old_name}", "current_checks:#{current_name}"],
404
- :aggregate => :max)
405
-
406
- multi.zrem('current_entities', old_name)
407
- unless old_score.nil?
408
- multi.zadd('current_entities', old_score, current_name)
409
- end
410
-
411
- maints_to_set.each_pair do |maint_key, score|
412
- multi.zadd("#{maint_key}s", score, current_name)
413
- end
414
-
415
- stored_maint_keys.each do |stored_maint_key|
416
- new_stored_maint_key = stored_maint_key.sub(/^#{Regexp.escape(old_name)}:/, "#{current_name}:")
417
- multi.zunionstore(new_stored_maint_key,
418
- [stored_maint_key, new_stored_maint_key],
419
- :aggregate => :max)
420
- end
421
-
422
- notif_keys.each do |nk|
423
- dest = nk.sub(/^#{Regexp.escape(old_name)}:/, "#{current_name}:")
424
- multi.renamenx(nk, dest)
425
- multi.del(nk)
426
- end
427
-
428
- alerting_to_remove.each_pair do |alerting, chks|
429
- chks.each {|chk| multi.zrem(alerting, chk)}
430
- end
431
-
432
- alerting_to_add.each_pair do |alerting, chks|
433
- chks.each_pair {|chk, score| multi.zadd(alerting, score, chk)}
434
- end
435
-
436
- blocks_to_set.each_pair do |block_key, (timestamp, value)|
437
- multi.setex(block_key, (timestamp - Time.now.to_i), value)
438
- end
439
-
440
- keys_to_rename.each_pair do |old_key, new_key|
441
- multi.rename(old_key, new_key)
442
- end
443
-
444
- multi.del(*keys_to_delete) unless keys_to_delete.empty?
445
- end
446
- end
447
-
448
- # NB: If entities are renamed in imported data before they are
449
- # renamed in monitoring sources, data for old entities may still
450
- # arrive and be stored under those names.
451
- def self.add(entity, options = {})
452
- raise "Redis connection not set" unless redis = options[:redis]
453
- entity_name = entity['name']
454
- raise "Entity name not provided" if entity_name.nil? || entity_name.empty?
455
-
456
- entity_id = entity['id']
457
-
458
- if entity_id.nil?
459
- # likely to be from monitoring data
460
-
461
- # if an entity exists with the same name as the incoming data,
462
- # use its id; failing that allocate a random one
463
- entity_id = redis.hget('all_entity_ids_by_name', entity_name)
464
-
465
- if entity_id.nil? || entity_id.empty?
466
- entity_id = SecureRandom.uuid
467
- redis.hset('all_entity_ids_by_name', entity_name, entity_id)
468
- redis.hset('all_entity_names_by_id', entity_id, entity_name)
469
- end
470
- else
471
- # most likely from API import
472
- this_id_original_name = redis.hget('all_entity_names_by_id', entity_id)
473
-
474
- # if there's an entity with a matching name, this will change its
475
- # id; if no entity exists it creates a new one
476
-
477
- this_name_original_id = redis.hget('all_entity_ids_by_name', entity_name)
478
-
479
- if this_id_original_name.nil?
480
- # no entity exists with a matching id
481
- redis.hset('all_entity_ids_by_name', entity_name, entity_id)
482
- redis.hset('all_entity_names_by_id', entity_id, entity_name)
483
-
484
- unless this_name_original_id.nil?
485
- # an entity existed with a matching name but a different id
486
- redis.hdel('all_entity_names_by_id', this_name_original_id)
487
- end
488
- elsif this_id_original_name != entity_name
489
- # a record exists with the provided id but a different name
490
- if this_name_original_id.nil?
491
- # there shouldn't be any entity records left without ids (due to
492
- # the migration code) so this code may not be needed now
493
- rename(this_id_original_name, entity_name, :redis => redis) {|multi|
494
- multi.hdel('all_entity_ids_by_name', this_id_original_name)
495
- multi.hset('all_entity_ids_by_name', entity_name, entity_id)
496
- multi.hset('all_entity_names_by_id', entity_id, entity_name)
497
- }
498
- else
499
- merge(this_id_original_name, entity_name, :redis => redis)
500
- end
501
- end
502
- end
503
-
504
- redis.del("contacts_for:#{entity_id}")
505
- if entity['contacts'] && entity['contacts'].respond_to?(:each)
506
- entity['contacts'].each {|contact_id|
507
- next if Flapjack::Data::Contact.find_by_id(contact_id, :redis => redis).nil?
508
- redis.sadd("contacts_for:#{entity_id}", contact_id)
509
- }
510
- end
511
-
512
- e = self.new(:name => entity_name,
513
- :id => entity_id,
514
- :redis => redis)
515
- if entity['tags'] && entity['tags'].respond_to?(:each)
516
- e.add_tags(*entity['tags'])
517
- end
518
- e
519
- end
520
-
521
- def self.find_by_name(entity_name, options = {})
522
- raise "Redis connection not set" unless redis = options[:redis]
523
- entity_id = redis.hget("all_entity_ids_by_name", entity_name)
524
- if entity_id.nil? || entity_id.empty?
525
- # key doesn't exist
526
- return unless options[:create]
527
- # add returns an instantiated Entity
528
- self.add({'name' => entity_name}, :redis => redis)
529
- else
530
- self.new(:name => entity_name, :id => entity_id, :redis => redis)
531
- end
532
- end
533
-
534
- def self.find_by_id(entity_id, options = {})
535
- raise "Redis connection not set" unless redis = options[:redis]
536
- entity_name = redis.hget("all_entity_names_by_id", entity_id)
537
- return if entity_name.nil? || entity_name.empty?
538
- self.new(:name => entity_name, :id => entity_id, :redis => redis)
539
- end
540
-
541
- def self.find_by_ids(entity_ids, options = {})
542
- raise "Redis connection not set" unless redis = options[:redis]
543
- logger = options[:logger]
544
-
545
- entity_ids.map do |id|
546
- self.find_by_id(id, options)
547
- end
548
- end
549
-
550
- # NB: if we're worried about user input, https://github.com/mudge/re2
551
- # has bindings for a non-backtracking RE engine that runs in linear
552
- # time
553
- def self.find_all_name_matching(pattern, options = {})
554
- raise "Redis connection not set" unless redis = options[:redis]
555
- regexp = nil
556
- begin
557
- regexp = Regexp.new(pattern)
558
- rescue => e
559
- if @logger
560
- @logger.info("Jabber#self.find_all_name_matching - unable to use /#{pattern}/ as a regex pattern: #{e}")
561
- end
562
- regexp = nil
563
- end
564
- return if regexp.nil?
565
- redis.hkeys('all_entity_ids_by_name').select {|en| regexp === en }.sort
566
- end
567
-
568
- def self.current_names(options = {})
569
- raise "Redis connection not set" unless redis = options[:redis]
570
- redis.zrange('current_entities', 0, -1)
571
- end
572
-
573
- def self.find_all_names_with_failing_checks(options)
574
- raise "Redis connection not set" unless redis = options[:redis]
575
- Flapjack::Data::EntityCheck.find_current_names_failing_by_entity(:redis => redis).keys
576
- end
577
-
578
- def contacts
579
- contact_ids = @redis.smembers("contacts_for:#{id}") +
580
- @redis.smembers("contacts_for:ALL")
581
-
582
- if @logger
583
- @logger.debug("#{contact_ids.length} contact(s) for #{id} (#{name}): " +
584
- contact_ids.length)
585
- end
586
-
587
- contact_ids.collect {|c_id|
588
- Flapjack::Data::Contact.find_by_id(c_id, :redis => @redis)
589
- }.compact
590
- end
591
-
592
- def self.contact_ids_for(entity_ids, options = {})
593
- raise "Redis connection not set" unless redis = options[:redis]
594
-
595
- entity_ids.inject({}) do |memo, entity_id|
596
- memo[entity_id] = redis.smembers("contacts_for:#{entity_id}")
597
- memo
598
- end
599
- end
600
-
601
- def self.check_ids_for(entity_ids, options = {})
602
- raise "Redis connection not set" unless redis = options[:redis]
603
-
604
- entity_ids.inject({}) do |memo, entity_id|
605
- entity_name = redis.hget('all_entity_names_by_id', entity_id)
606
- next memo if entity_name.nil? || entity_name.empty?
607
- en = Regexp.escape(entity_name)
608
- check_names = redis.zrange("all_checks:#{entity_name}", 0, -1) |
609
- Flapjack::Data::EntityCheck.find_current_names_for_entity_name(entity_name, :redis => redis)
610
- memo[entity_id] = check_names.map {|cn| "#{entity_name}:#{cn}"}
611
- memo
612
- end
613
- end
614
-
615
- def check_list
616
- @redis.zrange("current_checks:#{@name}", 0, -1)
617
- end
618
-
619
- def check_count
620
- checks = check_list
621
- return if checks.nil?
622
- checks.length
623
- end
624
-
625
- def to_jsonapi(opts = {})
626
- json_data = {
627
- "id" => self.id,
628
- "name" => self.name,
629
- "links" => {
630
- :contacts => opts[:contact_ids] || [],
631
- :checks => opts[:check_ids] || [],
632
- }
633
- }
634
- Flapjack.dump_json(json_data)
635
- end
636
-
637
- private
638
-
639
- # NB: initializer should not be used directly -- instead one of the finder methods
640
- # above will call it
641
- def initialize(options = {})
642
- raise "Redis connection not set" unless @redis = options[:redis]
643
- raise "Entity name not set" unless @name = options[:name]
644
- @id = options[:id]
645
- @logger = options[:logger]
646
- end
647
-
648
- end
649
-
650
- end
651
-
652
- end