flapjack 1.6.0 → 2.0.0b1

Sign up to get free protection for your applications and to get access to all the features.
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