flapjack 1.6.0 → 2.0.0b1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +4 -6
- data/.gitmodules +1 -1
- data/.rspec +1 -1
- data/.ruby-version +1 -1
- data/.travis.yml +12 -13
- data/CHANGELOG.md +2 -9
- data/CONTRIBUTING.md +7 -2
- data/Gemfile +4 -13
- data/LICENCE +1 -0
- data/README.md +8 -2
- data/Rakefile +2 -2
- data/bin/flapjack +3 -12
- data/build.sh +4 -2
- data/etc/flapjack_config.toml.example +273 -0
- data/features/ack_after_sched_maint.feature +18 -21
- data/features/cli.feature +11 -71
- data/features/cli_flapjack-feed-events.feature +14 -15
- data/features/cli_flapjack-nagios-receiver.feature +12 -41
- data/features/cli_flapper.feature +12 -41
- data/features/cli_purge.feature +5 -6
- data/features/cli_receive-events.feature +6 -7
- data/features/cli_simulate-failed-check.feature +5 -6
- data/features/events.feature +206 -181
- data/features/events_check_names.feature +4 -7
- data/features/notification_rules.feature +144 -223
- data/features/notifications.feature +65 -57
- data/features/rollup.feature +45 -47
- data/features/steps/cli_steps.rb +4 -5
- data/features/steps/events_steps.rb +163 -373
- data/features/steps/notifications_steps.rb +408 -264
- data/features/steps/packaging-lintian_steps.rb +0 -4
- data/features/steps/time_travel_steps.rb +0 -26
- data/features/support/daemons.rb +6 -31
- data/features/support/env.rb +65 -74
- data/flapjack.gemspec +22 -24
- data/lib/flapjack.rb +14 -7
- data/lib/flapjack/cli/flapper.rb +74 -173
- data/lib/flapjack/cli/maintenance.rb +278 -109
- data/lib/flapjack/cli/migrate.rb +950 -0
- data/lib/flapjack/cli/purge.rb +19 -22
- data/lib/flapjack/cli/receiver.rb +150 -326
- data/lib/flapjack/cli/server.rb +8 -235
- data/lib/flapjack/cli/simulate.rb +42 -57
- data/lib/flapjack/configuration.rb +51 -37
- data/lib/flapjack/coordinator.rb +138 -129
- data/lib/flapjack/data/acknowledgement.rb +177 -0
- data/lib/flapjack/data/alert.rb +97 -158
- data/lib/flapjack/data/check.rb +611 -0
- data/lib/flapjack/data/condition.rb +70 -0
- data/lib/flapjack/data/contact.rb +226 -456
- data/lib/flapjack/data/event.rb +96 -184
- data/lib/flapjack/data/extensions/associations.rb +59 -0
- data/lib/flapjack/data/extensions/short_name.rb +25 -0
- data/lib/flapjack/data/medium.rb +428 -0
- data/lib/flapjack/data/metrics.rb +194 -0
- data/lib/flapjack/data/notification.rb +22 -281
- data/lib/flapjack/data/rule.rb +473 -0
- data/lib/flapjack/data/scheduled_maintenance.rb +244 -0
- data/lib/flapjack/data/state.rb +221 -0
- data/lib/flapjack/data/statistic.rb +112 -0
- data/lib/flapjack/data/tag.rb +277 -0
- data/lib/flapjack/data/test_notification.rb +182 -0
- data/lib/flapjack/data/unscheduled_maintenance.rb +159 -0
- data/lib/flapjack/data/validators/id_validator.rb +20 -0
- data/lib/flapjack/exceptions.rb +6 -0
- data/lib/flapjack/filters/acknowledgement.rb +23 -16
- data/lib/flapjack/filters/base.rb +0 -5
- data/lib/flapjack/filters/delays.rb +53 -43
- data/lib/flapjack/filters/ok.rb +23 -14
- data/lib/flapjack/filters/scheduled_maintenance.rb +3 -3
- data/lib/flapjack/filters/unscheduled_maintenance.rb +12 -3
- data/lib/flapjack/gateways/aws_sns.rb +65 -49
- data/lib/flapjack/gateways/aws_sns/alert.text.erb +2 -2
- data/lib/flapjack/gateways/aws_sns/alert_subject.text.erb +2 -2
- data/lib/flapjack/gateways/aws_sns/rollup_subject.text.erb +1 -1
- data/lib/flapjack/gateways/email.rb +107 -90
- data/lib/flapjack/gateways/email/alert.html.erb +19 -18
- data/lib/flapjack/gateways/email/alert.text.erb +20 -14
- data/lib/flapjack/gateways/email/alert_subject.text.erb +2 -1
- data/lib/flapjack/gateways/email/rollup.html.erb +14 -13
- data/lib/flapjack/gateways/email/rollup.text.erb +13 -10
- data/lib/flapjack/gateways/jabber.rb +679 -671
- data/lib/flapjack/gateways/jabber/alert.text.erb +9 -6
- data/lib/flapjack/gateways/jsonapi.rb +164 -350
- data/lib/flapjack/gateways/jsonapi/data/join_descriptor.rb +44 -0
- data/lib/flapjack/gateways/jsonapi/data/method_descriptor.rb +21 -0
- data/lib/flapjack/gateways/jsonapi/helpers/headers.rb +63 -0
- data/lib/flapjack/gateways/jsonapi/helpers/miscellaneous.rb +136 -0
- data/lib/flapjack/gateways/jsonapi/helpers/resources.rb +227 -0
- data/lib/flapjack/gateways/jsonapi/helpers/serialiser.rb +313 -0
- data/lib/flapjack/gateways/jsonapi/helpers/swagger_docs.rb +322 -0
- data/lib/flapjack/gateways/jsonapi/methods/association_delete.rb +115 -0
- data/lib/flapjack/gateways/jsonapi/methods/association_get.rb +288 -0
- data/lib/flapjack/gateways/jsonapi/methods/association_patch.rb +178 -0
- data/lib/flapjack/gateways/jsonapi/methods/association_post.rb +116 -0
- data/lib/flapjack/gateways/jsonapi/methods/metrics.rb +71 -0
- data/lib/flapjack/gateways/jsonapi/methods/resource_delete.rb +119 -0
- data/lib/flapjack/gateways/jsonapi/methods/resource_get.rb +186 -0
- data/lib/flapjack/gateways/jsonapi/methods/resource_patch.rb +239 -0
- data/lib/flapjack/gateways/jsonapi/methods/resource_post.rb +197 -0
- data/lib/flapjack/gateways/jsonapi/middleware/array_param_fixer.rb +27 -0
- data/lib/flapjack/gateways/jsonapi/{rack → middleware}/json_params_parser.rb +7 -6
- data/lib/flapjack/gateways/jsonapi/middleware/request_timestamp.rb +18 -0
- data/lib/flapjack/gateways/oobetet.rb +222 -170
- data/lib/flapjack/gateways/pager_duty.rb +388 -0
- data/lib/flapjack/gateways/pager_duty/alert.text.erb +13 -0
- data/lib/flapjack/gateways/slack.rb +56 -48
- data/lib/flapjack/gateways/slack/alert.text.erb +1 -1
- data/lib/flapjack/gateways/slack/rollup.text.erb +1 -1
- data/lib/flapjack/gateways/sms_aspsms.rb +155 -0
- data/lib/flapjack/gateways/sms_aspsms/alert.text.erb +7 -0
- data/lib/flapjack/gateways/sms_aspsms/rollup.text.erb +2 -0
- data/lib/flapjack/gateways/sms_messagenet.rb +77 -57
- data/lib/flapjack/gateways/sms_messagenet/alert.text.erb +3 -2
- data/lib/flapjack/gateways/sms_nexmo.rb +53 -51
- data/lib/flapjack/gateways/sms_nexmo/alert.text.erb +2 -2
- data/lib/flapjack/gateways/sms_nexmo/rollup.text.erb +1 -1
- data/lib/flapjack/gateways/sms_twilio.rb +79 -62
- data/lib/flapjack/gateways/sms_twilio/alert.text.erb +3 -2
- data/lib/flapjack/gateways/web.rb +437 -345
- data/lib/flapjack/gateways/web/middleware/request_timestamp.rb +18 -0
- data/lib/flapjack/gateways/web/public/css/bootstrap.css +3793 -4340
- data/lib/flapjack/gateways/web/public/css/bootstrap.css.map +1 -0
- data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.eot +0 -0
- data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.svg +273 -214
- data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.woff +0 -0
- data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.woff2 +0 -0
- data/lib/flapjack/gateways/web/public/js/bootstrap.js +1637 -1607
- data/lib/flapjack/gateways/web/public/js/self_stats.js +1 -2
- data/lib/flapjack/gateways/web/views/_pagination.html.erb +19 -0
- data/lib/flapjack/gateways/web/views/check.html.erb +159 -121
- data/lib/flapjack/gateways/web/views/checks.html.erb +82 -41
- data/lib/flapjack/gateways/web/views/contact.html.erb +59 -71
- data/lib/flapjack/gateways/web/views/contacts.html.erb +32 -8
- data/lib/flapjack/gateways/web/views/index.html.erb +2 -2
- data/lib/flapjack/gateways/web/views/{layout.erb → layout.html.erb} +7 -23
- data/lib/flapjack/gateways/web/views/self_stats.html.erb +32 -33
- data/lib/flapjack/gateways/web/views/tag.html.erb +32 -0
- data/lib/flapjack/gateways/web/views/tags.html.erb +51 -0
- data/lib/flapjack/logger.rb +34 -3
- data/lib/flapjack/notifier.rb +180 -112
- data/lib/flapjack/patches.rb +8 -63
- data/lib/flapjack/pikelet.rb +185 -143
- data/lib/flapjack/processor.rb +323 -191
- data/lib/flapjack/record_queue.rb +33 -0
- data/lib/flapjack/redis_proxy.rb +66 -0
- data/lib/flapjack/utility.rb +21 -15
- data/lib/flapjack/version.rb +2 -1
- data/libexec/httpbroker.go +218 -14
- data/libexec/oneoff.go +13 -10
- data/spec/lib/flapjack/configuration_spec.rb +286 -0
- data/spec/lib/flapjack/coordinator_spec.rb +103 -157
- data/spec/lib/flapjack/data/check_spec.rb +175 -0
- data/spec/lib/flapjack/data/contact_spec.rb +26 -349
- data/spec/lib/flapjack/data/event_spec.rb +76 -291
- data/spec/lib/flapjack/data/medium_spec.rb +19 -0
- data/spec/lib/flapjack/data/rule_spec.rb +43 -0
- data/spec/lib/flapjack/data/scheduled_maintenance_spec.rb +976 -0
- data/spec/lib/flapjack/data/unscheduled_maintenance_spec.rb +34 -0
- data/spec/lib/flapjack/gateways/aws_sns_spec.rb +111 -60
- data/spec/lib/flapjack/gateways/email_spec.rb +194 -161
- data/spec/lib/flapjack/gateways/jabber_spec.rb +961 -162
- data/spec/lib/flapjack/gateways/jsonapi/methods/check_links_spec.rb +155 -0
- data/spec/lib/flapjack/gateways/jsonapi/methods/checks_spec.rb +426 -0
- data/spec/lib/flapjack/gateways/jsonapi/methods/contact_links_spec.rb +217 -0
- data/spec/lib/flapjack/gateways/jsonapi/methods/contacts_spec.rb +425 -0
- data/spec/lib/flapjack/gateways/jsonapi/methods/events_spec.rb +271 -0
- data/spec/lib/flapjack/gateways/jsonapi/methods/media_spec.rb +257 -0
- data/spec/lib/flapjack/gateways/jsonapi/methods/medium_links_spec.rb +163 -0
- data/spec/lib/flapjack/gateways/jsonapi/methods/metrics_spec.rb +8 -0
- data/spec/lib/flapjack/gateways/jsonapi/methods/rule_links_spec.rb +212 -0
- data/spec/lib/flapjack/gateways/jsonapi/methods/rules_spec.rb +289 -0
- data/spec/lib/flapjack/gateways/jsonapi/methods/scheduled_maintenance_links_spec.rb +49 -0
- data/spec/lib/flapjack/gateways/jsonapi/methods/scheduled_maintenances_spec.rb +242 -0
- data/spec/lib/flapjack/gateways/jsonapi/methods/tag_links_spec.rb +274 -0
- data/spec/lib/flapjack/gateways/jsonapi/methods/tags_spec.rb +302 -0
- data/spec/lib/flapjack/gateways/jsonapi/methods/unscheduled_maintenance_links_spec.rb +49 -0
- data/spec/lib/flapjack/gateways/jsonapi/methods/unscheduled_maintenances_spec.rb +339 -0
- data/spec/lib/flapjack/gateways/jsonapi_spec.rb +1 -1
- data/spec/lib/flapjack/gateways/oobetet_spec.rb +151 -79
- data/spec/lib/flapjack/gateways/pager_duty_spec.rb +353 -0
- data/spec/lib/flapjack/gateways/slack_spec.rb +53 -53
- data/spec/lib/flapjack/gateways/sms_aspsms_spec.rb +106 -0
- data/spec/lib/flapjack/gateways/sms_messagenet_spec.rb +111 -54
- data/spec/lib/flapjack/gateways/sms_nexmo_spec.rb +50 -51
- data/spec/lib/flapjack/gateways/sms_twilio_spec.rb +108 -48
- data/spec/lib/flapjack/gateways/web_spec.rb +144 -216
- data/spec/lib/flapjack/notifier_spec.rb +132 -1
- data/spec/lib/flapjack/pikelet_spec.rb +111 -50
- data/spec/lib/flapjack/processor_spec.rb +210 -40
- data/spec/lib/flapjack/redis_proxy_spec.rb +45 -0
- data/spec/lib/flapjack/utility_spec.rb +11 -15
- data/spec/service_consumers/fixture_data.rb +547 -0
- data/spec/service_consumers/pact_helper.rb +21 -32
- data/spec/service_consumers/pacts/flapjack-diner_v2.0.json +4652 -0
- data/spec/service_consumers/provider_states_for_flapjack-diner.rb +279 -322
- data/spec/service_consumers/provider_support.rb +8 -0
- data/spec/spec_helper.rb +34 -44
- data/spec/support/erb_view_helper.rb +1 -1
- data/spec/support/factories.rb +58 -0
- data/spec/support/jsonapi_helper.rb +15 -26
- data/spec/support/mock_logger.rb +43 -0
- data/spec/support/xmpp_comparable.rb +24 -0
- data/src/flapjack/transport_test.go +30 -1
- data/tasks/dump_keys.rake +82 -0
- data/tasks/events.rake +7 -7
- data/tasks/support/flapjack_config_benchmark.toml +28 -0
- data/tasks/support/flapjack_config_benchmark.yaml +0 -2
- metadata +175 -222
- data/Guardfile +0 -14
- data/etc/flapjack_config.yaml.example +0 -477
- data/features/cli_flapjack-populator.feature +0 -90
- data/features/support/silent_system.rb +0 -4
- data/lib/flapjack/cli/import.rb +0 -108
- data/lib/flapjack/data/entity.rb +0 -652
- data/lib/flapjack/data/entity_check.rb +0 -1044
- data/lib/flapjack/data/message.rb +0 -56
- data/lib/flapjack/data/migration.rb +0 -234
- data/lib/flapjack/data/notification_rule.rb +0 -425
- data/lib/flapjack/data/semaphore.rb +0 -44
- data/lib/flapjack/data/tagged.rb +0 -48
- data/lib/flapjack/gateways/jsonapi/check_methods.rb +0 -206
- data/lib/flapjack/gateways/jsonapi/check_presenter.rb +0 -221
- data/lib/flapjack/gateways/jsonapi/contact_methods.rb +0 -186
- data/lib/flapjack/gateways/jsonapi/entity_methods.rb +0 -223
- data/lib/flapjack/gateways/jsonapi/medium_methods.rb +0 -185
- data/lib/flapjack/gateways/jsonapi/metrics_methods.rb +0 -132
- data/lib/flapjack/gateways/jsonapi/notification_rule_methods.rb +0 -141
- data/lib/flapjack/gateways/jsonapi/pagerduty_credential_methods.rb +0 -139
- data/lib/flapjack/gateways/jsonapi/report_methods.rb +0 -146
- data/lib/flapjack/gateways/pagerduty.rb +0 -318
- data/lib/flapjack/gateways/pagerduty/alert.text.erb +0 -10
- data/lib/flapjack/gateways/web/public/css/select2-bootstrap.css +0 -87
- data/lib/flapjack/gateways/web/public/css/select2.css +0 -615
- data/lib/flapjack/gateways/web/public/css/tablesort.css +0 -67
- data/lib/flapjack/gateways/web/public/img/select2-spinner.gif +0 -0
- data/lib/flapjack/gateways/web/public/img/select2.png +0 -0
- data/lib/flapjack/gateways/web/public/img/select2x2.png +0 -0
- data/lib/flapjack/gateways/web/public/js/backbone.js +0 -1581
- data/lib/flapjack/gateways/web/public/js/backbone.jsonapi.js +0 -322
- data/lib/flapjack/gateways/web/public/js/flapjack.js +0 -82
- data/lib/flapjack/gateways/web/public/js/jquery.tablesorter.js +0 -1640
- data/lib/flapjack/gateways/web/public/js/jquery.tablesorter.widgets.js +0 -1390
- data/lib/flapjack/gateways/web/public/js/modules/contact.js +0 -520
- data/lib/flapjack/gateways/web/public/js/modules/entity.js +0 -28
- data/lib/flapjack/gateways/web/public/js/modules/medium.js +0 -40
- data/lib/flapjack/gateways/web/public/js/select2.js +0 -3397
- data/lib/flapjack/gateways/web/public/js/tablesort.js +0 -44
- data/lib/flapjack/gateways/web/public/js/underscore.js +0 -1276
- data/lib/flapjack/gateways/web/views/edit_contacts.html.erb +0 -173
- data/lib/flapjack/gateways/web/views/entities.html.erb +0 -30
- data/lib/flapjack/gateways/web/views/entity.html.erb +0 -51
- data/lib/flapjack/rack_logger.rb +0 -47
- data/lib/flapjack/redis_pool.rb +0 -42
- data/spec/lib/flapjack/data/entity_check_spec.rb +0 -1418
- data/spec/lib/flapjack/data/entity_spec.rb +0 -872
- data/spec/lib/flapjack/data/message_spec.rb +0 -30
- data/spec/lib/flapjack/data/migration_spec.rb +0 -104
- data/spec/lib/flapjack/data/notification_rule_spec.rb +0 -232
- data/spec/lib/flapjack/data/notification_spec.rb +0 -53
- data/spec/lib/flapjack/data/semaphore_spec.rb +0 -24
- data/spec/lib/flapjack/filters/acknowledgement_spec.rb +0 -6
- data/spec/lib/flapjack/filters/delays_spec.rb +0 -6
- data/spec/lib/flapjack/filters/ok_spec.rb +0 -6
- data/spec/lib/flapjack/filters/scheduled_maintenance_spec.rb +0 -6
- data/spec/lib/flapjack/filters/unscheduled_maintenance_spec.rb +0 -6
- data/spec/lib/flapjack/gateways/jsonapi/check_methods_spec.rb +0 -315
- data/spec/lib/flapjack/gateways/jsonapi/check_presenter_spec.rb +0 -223
- data/spec/lib/flapjack/gateways/jsonapi/contact_methods_spec.rb +0 -131
- data/spec/lib/flapjack/gateways/jsonapi/entity_methods_spec.rb +0 -389
- data/spec/lib/flapjack/gateways/jsonapi/medium_methods_spec.rb +0 -231
- data/spec/lib/flapjack/gateways/jsonapi/notification_rule_methods_spec.rb +0 -169
- data/spec/lib/flapjack/gateways/jsonapi/pagerduty_credential_methods_spec.rb +0 -114
- data/spec/lib/flapjack/gateways/jsonapi/report_methods_spec.rb +0 -590
- data/spec/lib/flapjack/gateways/pagerduty_spec.rb +0 -249
- data/spec/lib/flapjack/gateways/web/views/check.html.erb_spec.rb +0 -21
- data/spec/lib/flapjack/gateways/web/views/contact.html.erb_spec.rb +0 -24
- data/spec/lib/flapjack/gateways/web/views/index.html.erb_spec.rb +0 -16
- data/spec/lib/flapjack/redis_pool_spec.rb +0 -29
- data/spec/service_consumers/pacts/flapjack-diner_v1.0.json +0 -4702
- data/tasks/entities.rake +0 -151
- data/tasks/profile.rake +0 -282
- data/tmp/acknowledge.rb +0 -13
- data/tmp/create_config_yaml.rb +0 -16
- data/tmp/create_event_ok.rb +0 -30
- data/tmp/create_event_unknown.rb +0 -30
- data/tmp/create_events_failure.rb +0 -34
- data/tmp/create_events_ok.rb +0 -32
- data/tmp/create_events_ok_fail_ack_ok.rb +0 -53
- data/tmp/create_events_ok_failure.rb +0 -41
- data/tmp/create_events_ok_failure_ack.rb +0 -53
- data/tmp/dummy_contacts.json +0 -43
- data/tmp/dummy_entities.json +0 -37
- data/tmp/generate_nagios_test_hosts.rb +0 -16
- data/tmp/notification_rules.rb +0 -73
- data/tmp/parse_config_yaml.rb +0 -7
- data/tmp/redis_find_spurious_unknown_states.rb +0 -52
- data/tmp/test_json_post.rb +0 -19
- 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 |
|
data/lib/flapjack/cli/import.rb
DELETED
|
@@ -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
|
data/lib/flapjack/data/entity.rb
DELETED
|
@@ -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
|