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,29 +1,11 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'eventmachine'
4
3
  require 'socket'
5
- require 'dante'
6
4
 
7
5
  module Flapjack
8
6
  module CLI
9
7
  class Flapper
10
8
 
11
- def self.local_ip
12
- # turn off reverse DNS resolution temporarily
13
- orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true
14
-
15
- begin
16
- UDPSocket.open do |s|
17
- s.connect '64.233.187.99', 1
18
- s.addr.last
19
- end
20
- rescue Errno::ENETUNREACH => e
21
- '127.0.0.1'
22
- end
23
- ensure
24
- Socket.do_not_reverse_lookup = orig
25
- end
26
-
27
9
  def initialize(global_options, options)
28
10
  @global_options = global_options
29
11
  @options = options
@@ -38,79 +20,16 @@ module Flapjack
38
20
  @config_env = @config.all
39
21
 
40
22
  if @config_env.nil? || @config_env.empty?
41
- exit_now! "No config data for environment '#{FLAPJACK_ENV}' found in '#{global_options[:config]}'"
42
- end
43
-
44
- @pidfile = case
45
- when !@options[:pidfile].nil?
46
- @options[:pidfile]
47
- when !@config_env['pid_dir'].nil?
48
- File.join(@config_env['pid_dir'], 'flapper.pid')
49
- else
50
- "/var/run/flapjack/flapper.pid"
51
- end
52
-
53
- @logfile = case
54
- when !@options[:logfile].nil?
55
- @options[:logfile]
56
- when !@config_env['log_dir'].nil?
57
- File.join(@config_env['log_dir'], 'flapper.log')
58
- else
59
- "/var/run/flapjack/flapper.log"
23
+ exit_now! "No config data found in '#{global_options[:config]}'"
60
24
  end
61
25
  end
62
26
 
63
27
  def start
64
- if runner.daemon_running?
65
- puts "flapper is already running."
66
- else
67
- print "flapper starting..."
68
- main_umask = nil
69
- if @options[:daemonize]
70
- main_umask = File.umask
71
- else
72
- print "\n"
73
- end
74
- runner.execute(:daemonize => @options[:daemonize]) do
75
- File.umask(main_umask) if @options[:daemonize]
76
- main(@options['bind-ip'] || Flapjack::CLI::Flapper.local_ip, @options['bind-port'].to_i, @options[:frequency])
77
- end
78
- puts " done."
79
- end
80
- end
81
-
82
- def stop
83
- pid = get_pid
84
- if runner.daemon_running?
85
- print "flapper stopping..."
86
- runner.execute(:kill => true)
87
- puts " done."
88
- else
89
- puts "flapper is not running."
90
- end
91
- exit_now! unless wait_pid_gone(pid)
92
- end
93
-
94
- def restart
95
- print "flapper restarting..."
96
- main_umask = File.umask
97
- runner.execute(:daemonize => true, :restart => true) do
98
- File.umask(main_umask)
99
- main(@options['bind-ip'], @options['bind-port'].to_i, @options[:frequency])
100
- end
28
+ puts "flapper starting..."
29
+ main(@options['bind-ip'] || Flapjack::CLI::Flapper.local_ip, @options['bind-port'].to_i, @options[:frequency])
101
30
  puts " done."
102
31
  end
103
32
 
104
- def status
105
- if runner.daemon_running?
106
- pid = get_pid
107
- uptime = Time.now - File.stat(@pidfile).ctime
108
- puts "flapper is running: pid #{pid}, uptime #{uptime}"
109
- else
110
- exit_now! "flapper is not running"
111
- end
112
- end
113
-
114
33
  private
115
34
 
116
35
  module Receiver
@@ -120,36 +39,77 @@ module Flapjack
120
39
  end
121
40
  end
122
41
 
123
- def runner
124
- return @runner if @runner
42
+ def self.local_ip
43
+ # turn off reverse DNS resolution temporarily
44
+ orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true
125
45
 
126
- @runner = Dante::Runner.new('flapper', :pid_path => @pidfile,
127
- :log_path => @logfile)
128
- @runner
46
+ begin
47
+ UDPSocket.open do |s|
48
+ s.connect '64.233.187.99', 1
49
+ s.addr.last
50
+ end
51
+ rescue Errno::ENETUNREACH => e
52
+ '127.0.0.1'
53
+ end
54
+ ensure
55
+ Socket.do_not_reverse_lookup = orig
129
56
  end
130
57
 
131
58
  def main(bind_ip, bind_port, frequency)
132
- raise "bind_port must be an integer" unless bind_port.is_a?(Integer) && (bind_port > 0)
59
+ raise "bind_port must be an integer" unless bind_port.is_a?(Integer)
133
60
  start_every = frequency
134
- stop_after = frequency.to_f / 2
135
-
136
- EM.run do
61
+ stop_after = frequency.to_f / 2
137
62
 
138
- puts "#{Time.now}: starting server on #{bind_ip}:#{bind_port}"
139
- server_init = EM.start_server bind_ip, bind_port, Flapjack::CLI::Flapper::Receiver
140
- EM.add_timer(stop_after) do
141
- puts "#{Time.now}: stopping server"
142
- EM.stop_server(server_init)
143
- end
144
-
145
- EM.add_periodic_timer(start_every) do
146
- puts "#{Time.now}: starting server on #{bind_ip}:#{bind_port}"
147
- server = EM.start_server bind_ip, bind_port, Flapjack::CLI::Flapper::Receiver
148
- EM.add_timer(stop_after) do
63
+ begin
64
+ loop do
65
+ begin
66
+ fds = []
67
+ Timeout::timeout(stop_after) do
68
+ puts "#{Time.now}: starting server"
69
+
70
+ acceptor = TCPServer.open(bind_ip, bind_port)
71
+ fds = [acceptor]
72
+
73
+ while true
74
+ if ios = select(fds, [], [], 10)
75
+ reads = ios.first
76
+ reads.each do |client|
77
+ if client == acceptor
78
+ puts 'Someone connected to server. Adding socket to fds.'
79
+ client, sockaddr = acceptor.accept
80
+ fds << client
81
+ elsif client.eof?
82
+ puts "Client disconnected"
83
+ fds.delete(client)
84
+ client.close
85
+ else
86
+ # Perform a blocking-read until new-line is encountered.
87
+ # We know the client is writing, so as long as it adheres to the
88
+ # new-line protocol, we shouldn't block for very long.
89
+ data = client.gets("\n")
90
+ if data =~ /quit/i
91
+ fds.delete(client)
92
+ client.close
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ rescue Timeout::Error
149
100
  puts "#{Time.now}: stopping server"
150
- EM.stop_server(server)
101
+ ensure
102
+ # should trigger even for an Interrupt
103
+ puts "Cleaning up"
104
+ fds.each {|c| c.close}
151
105
  end
106
+
107
+ sleep_for = start_every - stop_after
108
+ puts "sleeping for #{sleep_for}"
109
+ sleep(sleep_for)
152
110
  end
111
+ rescue Interrupt
112
+ puts "interrupted"
153
113
  end
154
114
  end
155
115
 
@@ -182,83 +142,24 @@ module Flapjack
182
142
  pid = nil
183
143
  end
184
144
 
185
-
186
145
  end
187
146
  end
188
147
  end
189
148
 
190
-
191
- desc 'Artificial service that oscillates up and down, for use in http://flapjack.io/docs/1.0/usage/oobetet'
149
+ desc 'Artificial service that oscillates up and down, for use in http://flapjack.io/docs/2.0/usage/oobetet'
192
150
  command :flapper do |flapper|
193
151
 
194
- flapper.desc 'start flapper'
195
- flapper.command :start do |start|
196
-
197
- start.switch [:d, 'daemonize'], :desc => 'Daemonize',
198
- :default_value => true
199
-
200
- start.flag [:p, 'pidfile'], :desc => 'PATH of the pidfile to write to'
201
-
202
- start.flag [:l, 'logfile'], :desc => 'PATH of the logfile to write to'
203
-
204
- start.flag [:b, 'bind-ip'], :desc => 'Override ADDRESS (IPv4 or IPv6) for flapper to bind to'
205
-
206
- start.flag [:P, 'bind-port'], :desc => 'PORT for flapper to bind to (default: 12345)',
207
- :default_value => '12345'
208
-
209
- start.flag [:f, 'frequency'], :desc => 'oscillate with a frequency of SECONDS [120]',
210
- :default_value => '120.0'
152
+ flapper.flag [:b, 'bind-ip'], :desc => 'Override ADDRESS (IPv4 or IPv6) for flapper to bind to'
211
153
 
212
- start.action do |global_options, options, args|
213
- cli_flapper = Flapjack::CLI::Flapper.new(global_options, options)
214
- cli_flapper.start
215
- end
216
- end
217
-
218
- flapper.desc 'stop flapper'
219
- flapper.command :stop do |stop|
154
+ flapper.flag [:P, 'bind-port'], :desc => 'PORT for flapper to bind to (default: 12345)',
155
+ :default_value => '12345'
220
156
 
221
- stop.flag [:p, 'pidfile'], :desc => 'PATH of the pidfile to write to'
157
+ flapper.flag [:f, 'frequency'], :desc => 'oscillate with a frequency of SECONDS [120]',
158
+ :default_value => '120.0'
222
159
 
223
- stop.flag [:l, 'logfile'], :desc => 'PATH of the logfile to write to'
224
-
225
- stop.action do |global_options, options, args|
226
- cli_flapper = Flapjack::CLI::Flapper.new(global_options, options)
227
- cli_flapper.stop
228
- end
160
+ flapper.action do |global_options, options, args|
161
+ cli_flapper = Flapjack::CLI::Flapper.new(global_options, options)
162
+ cli_flapper.start
229
163
  end
230
164
 
231
- flapper.desc 'restart flapper'
232
- flapper.command :restart do |restart|
233
-
234
- restart.flag [:p, 'pidfile'], :desc => 'PATH of the pidfile to write to'
235
-
236
- restart.flag [:l, 'logfile'], :desc => 'PATH of the logfile to write to'
237
-
238
- restart.flag [:b, 'bind-ip'], :desc => 'Override ADDRESS (IPv4 or IPv6) for flapper to bind to'
239
-
240
- restart.flag [:P, 'bind-port'], :desc => 'PORT for flapper to bind to (default: 12345)',
241
- :default_value => 12345
242
-
243
- restart.flag [:f, 'frequency'], :desc => 'oscillate with a frequency of SECONDS [120]',
244
- :default_value => 120.0
245
-
246
- restart.action do |global_options, options, args|
247
- cli_flapper = Flapjack::CLI::Flapper.new(global_options, options)
248
- cli_flapper.restart
249
- end
250
- end
251
-
252
- flapper.desc 'flapper status'
253
- flapper.command :status do |status|
254
-
255
- status.flag [:p, 'pidfile'], :desc => 'PATH of the pidfile to write to'
256
-
257
- status.flag [:l, 'logfile'], :desc => 'PATH of the logfile to write to'
258
-
259
- status.action do |global_options, options, args|
260
- cli_flapper = Flapjack::CLI::Flapper.new(global_options, options)
261
- cli_flapper.status
262
- end
263
- end
264
165
  end
@@ -1,12 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'redis'
4
- require 'hiredis'
5
4
 
6
5
  require 'flapjack/configuration'
7
6
  require 'flapjack/data/event'
8
- require 'flapjack/data/entity_check'
9
- require 'flapjack/data/migration'
7
+ require 'flapjack/data/check'
10
8
  require 'terminal-table'
11
9
 
12
10
  module Flapjack
@@ -27,92 +25,310 @@ module Flapjack
27
25
  @config_env = config.all
28
26
 
29
27
  if @config_env.nil? || @config_env.empty?
30
- exit_now! "No config data for environment '#{FLAPJACK_ENV}' found in '#{global_options[:config]}'"
28
+ exit_now! "No config data found in '#{global_options[:config]}'"
31
29
  end
32
30
 
33
- @redis_options = config.for_redis
34
- @options[:redis] = redis
31
+ Flapjack::RedisProxy.config = config.for_redis
32
+ Zermelo.redis = Flapjack.redis
35
33
  end
36
34
 
37
- def show
38
- exit_now!("state must be one of 'ok', 'warning', 'critical', 'unknown'") unless @options[:state].nil? || %w(ok warning critical unknown).include?(@options[:state].downcase)
39
- exit_now!("type must be one of 'scheduled', 'unscheduled'") unless %w(scheduled unscheduled).include?(@options[:type].downcase)
40
- %w(started finishing).each do |time|
41
- exit_now!("#{time.capitalize} time must start with 'more than', 'less than', 'on', 'before', 'after' or between") if @options[time] && !@options[time].downcase.start_with?('more than', 'less than', 'on', 'before', 'after', 'between')
35
+ def show(base_time = Time.now)
36
+ state = @options[:state]
37
+
38
+ checks = if @options[:check]
39
+ Flapjack::Data::Check.intersect(:name => Regexp.new(@options[:check])).all
40
+ else
41
+ Flapjack::Data::Check.all
42
+ end
43
+
44
+ start_time_begin, start_time_end = self.class.extract_time_range(
45
+ @options[:started], base_time)
46
+
47
+ start_time_begin = start_time_begin.to_i unless start_time_begin.nil?
48
+ start_time_end = start_time_end.to_i unless start_time_end.nil?
49
+
50
+ finish_time_begin, finish_time_end = self.class.extract_time_range(
51
+ @options[:finishing], base_time)
52
+
53
+ finish_time_begin = finish_time_begin.to_i unless finish_time_begin.nil?
54
+ finish_time_end = finish_time_end.to_i unless finish_time_end.nil?
55
+
56
+ duration_range = @options[:duration] ? self.class.extract_duration_range(
57
+ @options[:duration]) : nil
58
+
59
+ start_time_range = Zermelo::Filters::IndexRange.new(start_time_begin,
60
+ start_time_end, :by_score => true)
61
+ finish_time_range = Zermelo::Filters::IndexRange.new(finish_time_begin,
62
+ finish_time_end, :by_score => true)
63
+
64
+ maintenances = case @options[:type].downcase
65
+ when 'scheduled'
66
+ checks.inject([]) do |memo, check|
67
+
68
+ maints = check.scheduled_maintenances.
69
+ intersect(:start_time => start_time_range, :end_time => finish_time_range).all
70
+
71
+ if !maints.empty?
72
+ filtered = duration_range.nil? ? maints :
73
+ self.class.filter_duration(maints, duration_range)
74
+ memo += filtered
75
+ end
76
+
77
+ memo
78
+ end
79
+ when 'unscheduled'
80
+ checks.inject([]) do |memo, check|
81
+
82
+ maints = check.unscheduled_maintenances.
83
+ intersect(:start_time => start_time_range, :end_time => finish_time_range).all
84
+
85
+ if !maints.empty?
86
+ filtered = duration_range.nil? ? maints :
87
+ self.class.filter_duration(maints, duration_range)
88
+ memo += filtered
89
+ end
90
+
91
+ memo
92
+ end
42
93
  end
43
- @options[:finishing] ||= 'after now'
44
- maintenances = Flapjack::Data::EntityCheck.find_maintenance(@options)
45
- rows = []
46
- maintenances.each do |m|
47
- row = []
48
- # Convert the unix timestamps of the start and end time back into readable times
49
- m.each { |k, v| row.push(k.to_s.end_with?('time') ? Time.at(v) : v) }
50
- rows.push(row)
94
+
95
+ rows = maintenances.collect do |maint|
96
+ [maint.check.name,
97
+ Time.at(maint.start_time), maint.end_time - maint.start_time,
98
+ maint.summary, Time.at(maint.end_time)]
51
99
  end
52
- puts Terminal::Table.new :headings => ['Entity', 'Check', 'State', 'Start', 'Duration (s)', 'Reason', 'End'], :rows => rows
100
+ puts Terminal::Table.new :headings => ['Check',
101
+ 'Start', 'Duration (s)', 'Reason', 'End'], :rows => rows
102
+ puts "Found #{rows.count} maintenances"
53
103
  maintenances
54
104
  end
55
105
 
56
106
  def delete
57
- maintenances = show
58
- exit_now!('The following maintenances would be deleted. Run this command again with --apply true to remove them.') unless @options[:apply]
59
- errors = Flapjack::Data::EntityCheck.delete_maintenance(@options)
60
- (errors.each { |k, v| puts "#{k}: #{v}" }; exit_now!('Failed to delete maintenances')) if errors.length > 0
61
- puts "The maintenances above have been deleted"
107
+ base_time = Time.now
108
+
109
+ maintenances = show(base_time)
110
+
111
+ unless @options[:apply]
112
+ exit_now!('The following maintenances would be deleted. Run this ' +
113
+ 'command again with --apply true to remove them.')
114
+ end
115
+
116
+ errors = {}
117
+ maintenances.each do |maint|
118
+ check = maint.check
119
+ identifier = "#{check.name}:#{check.start}"
120
+ if maint.end_time < base_time
121
+ errors[identifier] = "Maintenance can't be deleted as it finished in the past"
122
+ else
123
+ success = case @options[:type]
124
+ when 'scheduled'
125
+ check.end_scheduled_maintenance(maint, base_time)
126
+ when 'unscheduled'
127
+ check.clear_unscheduled_maintenance(base_time)
128
+ end
129
+ errors[identifier] = "The following maintenance failed to delete: #{entry}" unless success
130
+ end
131
+ end
132
+
133
+ if errors.empty?
134
+ puts "The maintenances above have been deleted"
135
+ else
136
+ puts(errors.map {|k, v| "#{k}: #{v}" }.join("\n"))
137
+ exit_now!('Failed to delete maintenances')
138
+ end
62
139
  end
63
140
 
64
141
  def create
65
- errors = Flapjack::Data::EntityCheck.create_maintenance(@options)
66
- (errors.each { |k, v| puts "#{k}: #{v}" }; exit_now!('Failed to create maintenances')) if errors.length > 0
67
- puts "The maintenances specified have been created"
142
+ errors = {}
143
+
144
+ check_names = @options[:check].is_a?(String) ? @options[:check].split(',') : @options[:check]
145
+
146
+ started = Chronic.parse(@options[:started])
147
+ raise "Failed to parse start time #{@options[:started]}" if started.nil?
148
+
149
+ duration = ChronicDuration.parse(@options[:duration])
150
+ raise "Failed to parse duration #{@options[:duration]}" if duration.nil?
151
+
152
+ check_names.each do |check_name|
153
+ check = Flapjack::Data::Check.intersect(:name => check_names).all.first
154
+
155
+ if check.nil?
156
+ # Create the check if it doesn't exist, so we can schedule maintenance against it
157
+ check = Flapjack::Data::Check.new(:name => check_name)
158
+ check.save
159
+ end
160
+
161
+ success = case @options[:type]
162
+ when 'scheduled'
163
+
164
+ sched_maint = Flapjack::Data::ScheduledMaintenance.new(:start_time => started,
165
+ :end_time => started + duration, :summary => @options[:reason])
166
+ sched_maint.save
167
+
168
+ check.scheduled_maintenances << sched_maint
169
+ when 'unscheduled'
170
+ unsched_maint = Flapjack::Data::UnscheduledMaintenance.new(:start_time => started,
171
+ :end_time => started + duration, :summary => @options[:reason])
172
+ unsched_maint.save
173
+
174
+ check.set_unscheduled_maintenance(unsched_maint)
175
+ end
176
+ identifier = "#{check_name}:#{started}"
177
+ errors[identifier] = "The following check failed to create: #{identifier}" unless success
178
+ end
179
+
180
+ if errors.empty?
181
+ puts "The maintenances specified have been created"
182
+ else
183
+ puts(errors.map {|k, v| "#{k}: #{v}" }.join("\n"))
184
+ exit_now!('Failed to create maintenances')
185
+ end
68
186
  end
69
187
 
70
188
  private
71
189
 
72
- def redis
73
- return @redis unless @redis.nil?
74
- @redis = Redis.new(@redis_options.merge(:driver => :hiredis))
75
- Flapjack::Data::Migration.migrate_entity_check_data_if_required(:redis => @redis)
76
- Flapjack::Data::Migration.clear_orphaned_entity_ids(:redis => @redis)
77
- Flapjack::Data::Migration.validate_scheduled_maintenance_periods(:redis => @redis)
78
- @redis
190
+ def self.filter_duration(maints, duration_range)
191
+ maints.select do |maint|
192
+ dur = maint.duration
193
+ lower = duration_range.first
194
+ upper = duration_range.last
195
+
196
+ (lower.nil? && upper.nil?) || ((lower.nil? || (dur >= lower)) &&
197
+ (upper.nil? || (dur < upper)))
198
+ end
199
+ end
200
+
201
+ def self.extract_duration_range(duration_in_words)
202
+ return nil if duration_in_words.nil?
203
+
204
+ dur_words = duration_in_words.downcase
205
+
206
+ case dur_words
207
+ when /^(?:equal to|less than|more than)/
208
+ cdur_words = dur_words.gsub(/^(equal to|less than|more than) /, '')
209
+ parsed_dur = ChronicDuration.parse(cdur_words)
210
+ case dur_words
211
+ when /^equal to/
212
+ [parsed_dur, parsed_dur + 1]
213
+ when /^less than/
214
+ [nil, parsed_dur]
215
+ when /^more than/
216
+ [parsed_dur, nil]
217
+ end
218
+ when /^between/
219
+ first, second = dur_words.match(/between (.*) and (.*)/).captures
220
+
221
+ # If the first time only contains only a single word, the unit (and past/future) is
222
+ # most likely directly after the first word of the the second time
223
+ # eg between 3 and 4 hours
224
+ suffix = second.match(/\w (.*)/) ? second.match(/\w (.*)/).captures.first : ''
225
+ first = "#{first} #{suffix}" unless / /.match(first)
226
+
227
+ [ChronicDuration.parse(first), ChronicDuration.parse(second)].sort
228
+ end
229
+ end
230
+
231
+ # returns two timestamps, the start and end of the calculated time range. if
232
+ # either one is nil that indicates that the range is unbounded at that end.
233
+ # Start is inclusive of that second, end is exclusive.
234
+ def self.extract_time_range(time_period_in_words, base_time)
235
+ return nil if time_period_in_words.nil?
236
+
237
+ time_words = time_period_in_words.downcase
238
+
239
+ # Chronic can't parse timestamps for strings starting with before, after or in some cases, on.
240
+ # Strip the before or after for the conversion only, but use it for the comparison later
241
+ ctime_words = time_words.gsub(/^(on|before|after) /, '')
242
+
243
+ case time_words
244
+ # Between 3 and 4 hours ago translates to more than 3 hours ago, less than 4 hours ago
245
+ when /^between/
246
+ first, second = time_words.match(/between (.*) and (.*)/).captures
247
+
248
+ # If the first time only contains only a single word, the unit (and past/future) is
249
+ # most likely directly after the first word of the the second time
250
+ # eg between 3 and 4 hours ago
251
+ suffix = second.match(/\w (.*)/) ? second.match(/\w (.*)/).captures.first : ''
252
+ first = "#{first} #{suffix}" unless / /.match(first)
253
+
254
+ [Chronic.parse(first, :now => base_time),
255
+ Chronic.parse(second, :now => base_time)].sort
256
+ when /^on/
257
+ # e.g. On 1/1/15. We use Chronic to work out the minimum and maximum timestamp.
258
+ parsed = Chronic.parse(ctime, :guess => false, :now => base_time)
259
+ [parsed.first, parsed.last]
260
+ when /^(less than|more than|before|after)/
261
+ input_time = Chronic.parse(ctime_words, :keep_zero => true, :now => base_time) ||
262
+ Chronic.parse("#{ctime_words} from now", :keep_zero => true, :now => base_time)
263
+ case time_words
264
+ when /^less than .+ ago$/, /^more than/, /^after/
265
+ [input_time, nil]
266
+ when /^less than/, /^more than .+ ago$/, /^before/
267
+ [nil, input_time]
268
+ end
269
+ end
79
270
  end
80
271
 
81
272
  end
82
273
  end
83
274
  end
84
275
 
85
- desc 'Show, create and delete maintenance windows'
86
- command :maintenance do |maintenance|
87
-
88
-
89
- maintenance.desc 'Show maintenance windows according to criteria (default: all ongoing maintenance)'
90
- maintenance.command :show do |show|
91
-
92
- show.flag ['entity', :e],
93
- :desc => 'The entity for the maintenance window to occur on. This can be a string, or a ruby regex of the form \'db*\' or \'[[:lower:]]\''
276
+ def common_arguments(cmd_type, gli_cmd)
277
+
278
+ if [:show, :delete, :create].include?(cmd_type)
279
+ gli_cmd.flag ['check', :c],
280
+ :desc => 'The check for the maintenance window to occur on. This can ' +
281
+ 'be a string, or a Ruby regex of the form \'http*\' or \'[[:lower:]]\'',
282
+ :required => :create.eql?(cmd_type)
283
+
284
+ gli_cmd.flag ['reason', :r],
285
+ :desc => 'The reason for the maintenance window to occur. This can ' +
286
+ 'be a string, or a Ruby regex of the form \'Downtime for *\' or ' +
287
+ '\'[[:lower:]]\''
288
+
289
+ gli_cmd.flag ['start', 'started', 'starting', :s],
290
+ :desc => 'The start time for the maintenance window. This should ' +
291
+ 'be prefixed with "more than", "less than", "on", "before", ' +
292
+ 'or "after", or of the form "between T1 and T2"',
293
+ :must_match => /^(?:more than|less than|on|before|after|between)\s+.+$/
294
+
295
+ gli_cmd.flag ['duration', :d],
296
+ :desc => 'The total duration of the maintenance window. This should ' +
297
+ 'be prefixed with "more than", "less than", or "equal to", ' +
298
+ 'or of the form "between M and N hours". This should be an ' +
299
+ ' interval',
300
+ :must_match => /^(?:more than|less than|equal to|between)\s+.+$/
301
+ end
94
302
 
95
- show.flag ['check', :c],
96
- :desc => 'The check for the maintenance window to occur on. This can be a string, or a ruby regex of the form \'http*\' or \'[[:lower:]]\''
303
+ if [:show, :delete].include?(cmd_type)
304
+ gli_cmd.flag ['finish', 'finished', 'finishing', 'remain', 'remained', 'remaining', 'end', :f],
305
+ :desc => 'The finishing time for the maintenance window. This should ' +
306
+ 'prefixed with "more than", "less than", "on", "before", or ' +
307
+ '"after", or of the form "between T1 and T2"' ,
308
+ :must_match => /^(?:more than|less than|on|before|after|between)\s+.+$/
97
309
 
98
- show.flag ['reason', :r],
99
- :desc => 'The reason for the maintenance window to occur. This can be a string, or a ruby regex of the form \'Downtime for *\' or \'[[:lower:]]\''
310
+ gli_cmd.flag ['state', :st],
311
+ :desc => 'The state that the check is currently in',
312
+ :must_match => %w(ok warning critical unknown)
313
+ end
100
314
 
101
- show.flag ['start', 'started', 'starting', :s],
102
- :desc => 'The start time for the maintenance window, eg \'before 10am\'. This should be prefixed with \'more than\', \'less than\', \'on\', \'before\', or \'after\', or of the form \'between times and time\''
315
+ if [:show, :delete, :create].include?(cmd_type)
316
+ gli_cmd.flag ['type', :t],
317
+ :desc => 'The type of maintenance scheduled',
318
+ :required => true,
319
+ :default_value => 'scheduled',
320
+ :must_match => %w(scheduled unscheduled)
321
+ end
103
322
 
104
- show.flag ['duration', :d],
105
- :desc => 'The total duration of the maintenance window, eg \'equal to 5 hours\'. This should be prefixed with \'more than\', \'less than\', \'before, \'after\' or \'equal to\', or or of the form \'between 3 and 4 hours\'. This should be an interval'
323
+ end
106
324
 
107
- show.flag ['finish', 'finished', 'finishing', 'remain', 'remained', 'remaining', 'end', :f],
108
- :desc => 'The finishing time for the maintenance window, eg \'more than 1 year from now\'. This should be prefixed with \'more than\', \'less than\', \'on\', \'before\', or \'after\', or of the form \'between time and time\''
325
+ desc 'Show, create and delete maintenance windows'
326
+ command :maintenance do |maintenance|
109
327
 
110
- show.flag ['state', :st],
111
- :desc => 'The state that the check is currently in'
328
+ maintenance.desc 'Show maintenance windows according to criteria (default: all ongoing maintenance)'
329
+ maintenance.command :show do |show|
112
330
 
113
- show.flag ['type', :t],
114
- :desc => 'The type of maintenance scheduled',
115
- :default_value => 'scheduled'
331
+ common_arguments(:show, show)
116
332
 
117
333
  show.action do |global_options,options,args|
118
334
  maintenance = Flapjack::CLI::Maintenance.new(global_options, options)
@@ -123,34 +339,11 @@ command :maintenance do |maintenance|
123
339
  maintenance.desc 'Delete maintenance windows according to criteria (default: all ongoing maintenance)'
124
340
  maintenance.command :delete do |delete|
125
341
 
126
- delete.flag ['apply', :a],
342
+ delete.flag [:a, 'apply'],
127
343
  :desc => 'Whether this deletion should occur',
128
344
  :default_value => false
129
345
 
130
- delete.flag ['entity', :e],
131
- :desc => 'The entity for the maintenance window to occur on. This can be a string, or a ruby regex of the form \'db*\' or \'[[:lower:]]\''
132
-
133
- delete.flag ['check', :c],
134
- :desc => 'The check for the maintenance window to occur on. This can be a string, or a ruby regex of the form \'http*\' or \'[[:lower:]]\''
135
-
136
- delete.flag ['reason', :r],
137
- :desc => 'The reason for the maintenance window to occur. This can be a string, or a ruby regex of the form \'Downtime for *\' or \'[[:lower:]]\''
138
-
139
- delete.flag ['start', 'started', 'starting', :s],
140
- :desc => 'The start time for the maintenance window, eg \'before 10am\'. This should be prefixed with \'more than\', \'less than\', \'on\', \'before\', or \'after\', or of the form \'between times and time\''
141
-
142
- delete.flag ['duration', :d],
143
- :desc => 'The total duration of the maintenance window, eg \'equal to 5 hours\'. This should be prefixed with \'more than\', \'less than\', \'before, \'after\' or \'equal to\', or or of the form \'between 3 and 4 hours\'. This should be an interval'
144
-
145
- delete.flag ['finish', 'finished', 'finishing', 'remain', 'remained', 'remaining', 'end', :f],
146
- :desc => 'The finishing time for the maintenance window, eg \'more than 1 year from now\'. This should be prefixed with \'more than\', \'less than\', \'on\', \'before\', or \'after\', or of the form \'between time and time\''
147
-
148
- delete.flag ['state', :st],
149
- :desc => 'The state that the check is currently in'
150
-
151
- delete.flag ['type', :t],
152
- :desc => 'The type of maintenance scheduled',
153
- :default_value => 'scheduled'
346
+ common_arguments(:delete, delete)
154
347
 
155
348
  delete.action do |global_options,options,args|
156
349
  maintenance = Flapjack::CLI::Maintenance.new(global_options, options)
@@ -161,31 +354,7 @@ command :maintenance do |maintenance|
161
354
  maintenance.desc 'Create a maintenance window'
162
355
  maintenance.command :create do |create|
163
356
 
164
- create.flag ['entity', :e],
165
- :desc => 'The entity for the maintenance window to occur on. This can be a comma separated list',
166
- :type => Array,
167
- :required => true
168
-
169
- create.flag ['check', :c],
170
- :desc => 'The check for the maintenance window to occur on. This can be a comma separated list',
171
- :type => Array,
172
- :required => true
173
-
174
- create.flag ['reason', :r],
175
- :desc => 'The reason for the maintenance window to occur',
176
- :required => true
177
-
178
- create.flag ['start', 'started', 'starting', :s],
179
- :desc => 'The start time for the maintenance window, eg \'now\' or \'in 3 hours\'',
180
- :required => true
181
-
182
- create.flag ['duration', :d],
183
- :desc => 'The total duration of the maintenance window, eg \'30 minutes\'. This should be an interval',
184
- :required => true
185
-
186
- create.flag ['type', :t],
187
- :desc => 'The type of maintenance scheduled (\'scheduled\')',
188
- :default_value => 'scheduled'
357
+ common_arguments(:create, create)
189
358
 
190
359
  create.action do |global_options,options,args|
191
360
  maintenance = Flapjack::CLI::Maintenance.new(global_options, options)