flapjack 1.0.0rc3 → 1.0.0rc5
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 +1 -2
- data/.ruby-version +1 -0
- data/CHANGELOG.md +20 -0
- data/CONTRIBUTING.md +2 -2
- data/Gemfile +1 -1
- data/README.md +6 -16
- data/build.sh +13 -1
- data/etc/flapjack_config.yaml.example +98 -12
- data/features/cli.feature +8 -8
- data/features/cli_flapjack-nagios-receiver.feature +29 -37
- data/features/cli_flapper.feature +24 -12
- data/features/cli_simulate-failed-check.feature +2 -2
- data/features/notifications.feature +18 -1
- data/features/steps/cli_steps.rb +2 -2
- data/features/steps/notifications_steps.rb +71 -0
- data/features/support/env.rb +7 -6
- data/flapjack.gemspec +3 -1
- data/lib/flapjack/cli/flapper.rb +74 -25
- data/lib/flapjack/cli/import.rb +3 -4
- data/lib/flapjack/cli/maintenance.rb +182 -0
- data/lib/flapjack/cli/receiver.rb +110 -121
- data/lib/flapjack/cli/server.rb +30 -26
- data/lib/flapjack/cli/simulate.rb +2 -3
- data/lib/flapjack/data/contact.rb +1 -1
- data/lib/flapjack/data/entity.rb +425 -32
- data/lib/flapjack/data/entity_check.rb +212 -14
- data/lib/flapjack/data/event.rb +1 -1
- data/lib/flapjack/gateways/aws_sns.rb +134 -0
- data/lib/flapjack/gateways/aws_sns/alert.text.erb +5 -0
- data/lib/flapjack/gateways/aws_sns/rollup.text.erb +2 -0
- data/lib/flapjack/gateways/jabber.rb +2 -2
- data/lib/flapjack/gateways/jsonapi/check_methods.rb +1 -1
- data/lib/flapjack/gateways/jsonapi/contact_methods.rb +1 -1
- data/lib/flapjack/gateways/jsonapi/entity_methods.rb +15 -1
- data/lib/flapjack/gateways/jsonapi/metrics_methods.rb +4 -3
- data/lib/flapjack/gateways/jsonapi/report_methods.rb +1 -1
- data/lib/flapjack/gateways/web.rb +35 -16
- data/lib/flapjack/gateways/web/public/css/tablesort.css +0 -16
- data/lib/flapjack/gateways/web/public/js/backbone.jsonapi.js +1 -1
- data/lib/flapjack/gateways/web/public/js/jquery.tablesorter.widgets.js +0 -45
- data/lib/flapjack/gateways/web/public/js/modules/contact.js +2 -2
- data/lib/flapjack/gateways/web/public/js/modules/entity.js +2 -2
- data/lib/flapjack/gateways/web/public/js/modules/medium.js +4 -4
- data/lib/flapjack/gateways/web/public/js/self_stats.js +1 -1
- data/lib/flapjack/gateways/web/views/check.html.erb +10 -10
- data/lib/flapjack/gateways/web/views/checks.html.erb +1 -1
- data/lib/flapjack/gateways/web/views/contact.html.erb +5 -1
- data/lib/flapjack/gateways/web/views/edit_contacts.html.erb +3 -4
- data/lib/flapjack/gateways/web/views/entities.html.erb +1 -1
- data/lib/flapjack/gateways/web/views/index.html.erb +2 -2
- data/lib/flapjack/gateways/web/views/layout.erb +3 -3
- data/lib/flapjack/gateways/web/views/self_stats.html.erb +5 -6
- data/lib/flapjack/notifier.rb +4 -1
- data/lib/flapjack/patches.rb +8 -2
- data/lib/flapjack/pikelet.rb +3 -1
- data/lib/flapjack/version.rb +1 -1
- data/libexec/httpbroker.go +1 -1
- data/spec/lib/flapjack/coordinator_spec.rb +3 -3
- data/spec/lib/flapjack/data/contact_spec.rb +2 -2
- data/spec/lib/flapjack/data/entity_check_spec.rb +805 -53
- data/spec/lib/flapjack/data/entity_spec.rb +661 -0
- data/spec/lib/flapjack/gateways/aws_sns_spec.rb +123 -0
- data/spec/lib/flapjack/gateways/jabber_spec.rb +1 -1
- data/spec/lib/flapjack/gateways/jsonapi/check_methods_spec.rb +1 -1
- data/spec/lib/flapjack/gateways/jsonapi/entity_methods_spec.rb +2 -2
- data/spec/lib/flapjack/gateways/pagerduty_spec.rb +1 -1
- data/spec/lib/flapjack/gateways/web_spec.rb +11 -11
- data/spec/support/profile_all_formatter.rb +10 -10
- data/spec/support/uncolored_doc_formatter.rb +66 -4
- data/src/flapjack/event.go +1 -1
- data/tasks/benchmarks.rake +24 -20
- data/tasks/entities.rake +148 -0
- data/tmp/dummy_contacts.json +43 -0
- data/tmp/dummy_entities.json +37 -1
- metadata +43 -7
- data/tmp/test_entities.json +0 -1
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'flapjack/gateways/aws_sns'
|
3
|
+
|
4
|
+
describe Flapjack::Gateways::AwsSns, :logger => true do
|
5
|
+
|
6
|
+
let(:lock) { double(Monitor) }
|
7
|
+
|
8
|
+
let(:time) { Time.new(2013, 10, 31, 13, 45) }
|
9
|
+
|
10
|
+
let(:time_str) { Time.at(time).strftime('%-d %b %H:%M') }
|
11
|
+
|
12
|
+
let(:config) { {'region' => 'us-east-1',
|
13
|
+
'access_key' => 'AKIAIOSFODNN7EXAMPLE',
|
14
|
+
'secret_key' => 'secret'
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
let(:message) { {'notification_type' => 'recovery',
|
19
|
+
'contact_first_name' => 'John',
|
20
|
+
'contact_last_name' => 'Smith',
|
21
|
+
'state' => 'ok',
|
22
|
+
'summary' => 'smile',
|
23
|
+
'last_state' => 'problem',
|
24
|
+
'last_summary' => 'frown',
|
25
|
+
'time' => time.to_i,
|
26
|
+
'address' => 'arn:aws:sns:us-east-1:698519295917:My-Topic',
|
27
|
+
'event_id' => 'example.com:ping',
|
28
|
+
'id' => '123456789',
|
29
|
+
'duration' => 55,
|
30
|
+
'state_duration' => 23
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
it "sends an SMS message" do
|
35
|
+
req = stub_request(:post, "http://sns.us-east-1.amazonaws.com/").
|
36
|
+
with(:query => hash_including({'Action' => 'Publish',
|
37
|
+
'AWSAccessKeyId' => config['access_key'],
|
38
|
+
'TopicArn' => message['address'],
|
39
|
+
'SignatureVersion' => '2',
|
40
|
+
'SignatureMethod' => 'HmacSHA256'})).
|
41
|
+
to_return(:status => 200)
|
42
|
+
|
43
|
+
EM.synchrony do
|
44
|
+
Flapjack::Gateways::AwsSns.instance_variable_set('@config', config)
|
45
|
+
Flapjack::Gateways::AwsSns.instance_variable_set('@logger', @logger)
|
46
|
+
Flapjack::Gateways::AwsSns.start
|
47
|
+
Flapjack::Gateways::AwsSns.perform(message)
|
48
|
+
EM.stop
|
49
|
+
end
|
50
|
+
expect(req).to have_been_requested
|
51
|
+
end
|
52
|
+
|
53
|
+
it "does not send an SMS message with an invalid config" do
|
54
|
+
EM.synchrony do
|
55
|
+
Flapjack::Gateways::AwsSns.instance_variable_set('@config', config.reject {|k, v| k == 'secret_key'})
|
56
|
+
Flapjack::Gateways::AwsSns.instance_variable_set('@logger', @logger)
|
57
|
+
Flapjack::Gateways::AwsSns.start
|
58
|
+
Flapjack::Gateways::AwsSns.perform(message)
|
59
|
+
EM.stop
|
60
|
+
end
|
61
|
+
|
62
|
+
expect(WebMock).not_to have_requested(:get, "http://sns.us-east-1.amazonaws.com/")
|
63
|
+
end
|
64
|
+
|
65
|
+
context "#string_to_sign" do
|
66
|
+
|
67
|
+
let(:method) { 'post' }
|
68
|
+
|
69
|
+
let(:host) { 'sns.us-east-1.AmazonAWS.com' }
|
70
|
+
|
71
|
+
let(:uri) { '/' }
|
72
|
+
|
73
|
+
let(:query) { {'TopicArn' => 'HelloWorld',
|
74
|
+
'Action' => 'Publish'} }
|
75
|
+
|
76
|
+
let(:string_to_sign) { Flapjack::Gateways::AwsSns.string_to_sign(method, host, uri, query) }
|
77
|
+
|
78
|
+
let(:lines) { string_to_sign.split(/\n/) }
|
79
|
+
|
80
|
+
it 'should put the method on the first line' do
|
81
|
+
expect(lines[0]).to eq("POST")
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should put the downcased hostname on the second line' do
|
85
|
+
expect(lines[1]).to eq("sns.us-east-1.amazonaws.com")
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should put the URI on the third line' do
|
89
|
+
expect(lines[2]).to eq("/")
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should put the encoded, sorted query-string on the fourth line' do
|
93
|
+
expect(lines[3]).to eq("Action=Publish&TopicArn=HelloWorld")
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
context "#get_signature" do
|
99
|
+
let(:method) { 'GET' }
|
100
|
+
|
101
|
+
let(:host) { 'elasticmapreduce.amazonaws.com' }
|
102
|
+
|
103
|
+
let(:uri) { '/' }
|
104
|
+
|
105
|
+
let(:query) { {'AWSAccessKeyId' => 'AKIAIOSFODNN7EXAMPLE',
|
106
|
+
'Action' => 'DescribeJobFlows',
|
107
|
+
'SignatureMethod' => 'HmacSHA256',
|
108
|
+
'SignatureVersion' => '2',
|
109
|
+
'Timestamp' => '2011-10-03T15:19:30',
|
110
|
+
'Version' => '2009-03-31'} }
|
111
|
+
|
112
|
+
let(:secret_key) { 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY' }
|
113
|
+
|
114
|
+
let(:string_to_sign) { Flapjack::Gateways::AwsSns.string_to_sign(method, host, uri, query) }
|
115
|
+
|
116
|
+
let(:signature) { Flapjack::Gateways::AwsSns.get_signature(secret_key, string_to_sign) }
|
117
|
+
|
118
|
+
it 'should HMAC-SHA256 and base64 encode the signature' do
|
119
|
+
expect(signature).to eq("i91nKc4PWAt0JJIdXwz9HxZCJDdiy6cf/Mj6vPxyYIs=")
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
@@ -174,7 +174,7 @@ describe Flapjack::Gateways::Jabber, :logger => true do
|
|
174
174
|
|
175
175
|
expect(EventMachine::Synchrony).to receive(:sleep).with(5).exactly(1).times
|
176
176
|
expect(EventMachine::Synchrony).to receive(:sleep).with(2).exactly(3).times
|
177
|
-
expect(fj).to receive(:connect).exactly(4).times
|
177
|
+
expect(fj).to receive(:connect).exactly(4).times {
|
178
178
|
attempts +=1
|
179
179
|
raise StandardError.new unless attempts > 3
|
180
180
|
}
|
@@ -22,7 +22,7 @@ describe 'Flapjack::Gateways::JSONAPI::CheckMethods', :sinatra => true, :logger
|
|
22
22
|
expect(entity_check).to receive(:entity).and_return(entity)
|
23
23
|
expect(entity_check).to receive(:key).twice.and_return('PING')
|
24
24
|
expect(entity_check).to receive(:to_jsonapi).and_return(check_data.to_json)
|
25
|
-
expect(Flapjack::Data::EntityCheck).to receive(:
|
25
|
+
expect(Flapjack::Data::EntityCheck).to receive(:find_current).with(:redis => redis).
|
26
26
|
and_return([entity_check])
|
27
27
|
|
28
28
|
aget '/checks'
|
@@ -22,7 +22,7 @@ describe 'Flapjack::Gateways::JSONAPI::EntityMethods', :sinatra => true, :logger
|
|
22
22
|
expect(Flapjack::Data::Entity).to receive(:contact_ids_for).
|
23
23
|
with([entity_core['id']], :redis => redis).and_return({})
|
24
24
|
expect(entity).to receive(:to_jsonapi).and_return(entity_core.to_json)
|
25
|
-
expect(Flapjack::Data::Entity).to receive(:all).with(:redis => redis).
|
25
|
+
expect(Flapjack::Data::Entity).to receive(:all).with(:enabled => nil, :redis => redis).
|
26
26
|
and_return([entity])
|
27
27
|
|
28
28
|
aget '/entities'
|
@@ -38,7 +38,7 @@ describe 'Flapjack::Gateways::JSONAPI::EntityMethods', :sinatra => true, :logger
|
|
38
38
|
with([entity_core['id']], :redis => redis).and_return({})
|
39
39
|
expect(entity).to receive(:to_jsonapi).and_return(entity_core.to_json)
|
40
40
|
expect(idless_entity).not_to receive(:to_jsonapi)
|
41
|
-
expect(Flapjack::Data::Entity).to receive(:all).with(:redis => redis).
|
41
|
+
expect(Flapjack::Data::Entity).to receive(:all).with(:enabled => nil, :redis => redis).
|
42
42
|
and_return([entity, idless_entity])
|
43
43
|
|
44
44
|
aget '/entities'
|
@@ -7,7 +7,7 @@ describe Flapjack::Gateways::Web, :sinatra => true, :logger => true do
|
|
7
7
|
Flapjack::Gateways::Web
|
8
8
|
end
|
9
9
|
|
10
|
-
let(:entity_name) { 'example.com'}
|
10
|
+
let(:entity_name) { 'foo-app-01.example.com'}
|
11
11
|
let(:entity_name_esc) { CGI.escape(entity_name) }
|
12
12
|
let(:check) { 'ping' }
|
13
13
|
|
@@ -30,20 +30,20 @@ describe Flapjack::Gateways::Web, :sinatra => true, :logger => true do
|
|
30
30
|
expect(redis).to receive(:hgetall).twice.and_return({'all' => '8001', 'ok' => '8002'},
|
31
31
|
{'all' => '9001', 'ok' => '9002'})
|
32
32
|
expect(redis).to receive(:llen).with('events')
|
33
|
-
expect(
|
34
|
-
|
33
|
+
expect(Flapjack::Data::EntityCheck).to receive(:find_all_split_by_freshness).
|
34
|
+
and_return(30 => 3)
|
35
35
|
end
|
36
36
|
|
37
37
|
def expect_check_stats
|
38
|
-
expect(Flapjack::Data::EntityCheck).to receive(:
|
38
|
+
expect(Flapjack::Data::EntityCheck).to receive(:count_current).
|
39
39
|
with(:redis => redis).and_return(1)
|
40
|
-
expect(Flapjack::Data::EntityCheck).to receive(:
|
40
|
+
expect(Flapjack::Data::EntityCheck).to receive(:count_current_failing).
|
41
41
|
with(:redis => redis).and_return(1)
|
42
42
|
end
|
43
43
|
|
44
44
|
def expect_entity_stats
|
45
|
-
expect(Flapjack::Data::Entity).to receive(:
|
46
|
-
with(:redis => redis).and_return([entity_name])
|
45
|
+
expect(Flapjack::Data::Entity).to receive(:all).
|
46
|
+
with(:enabled => true, :redis => redis).and_return([entity_name])
|
47
47
|
expect(Flapjack::Data::Entity).to receive(:find_all_with_failing_checks).
|
48
48
|
with(:redis => redis).and_return([entity_name])
|
49
49
|
end
|
@@ -87,7 +87,6 @@ describe Flapjack::Gateways::Web, :sinatra => true, :logger => true do
|
|
87
87
|
logo_image_tag = '<img alt="Flapjack" class="logo" src="/img/branding.png">'
|
88
88
|
|
89
89
|
aget '/self_stats'
|
90
|
-
|
91
90
|
expect( last_response.body ).to include(logo_image_tag)
|
92
91
|
end
|
93
92
|
|
@@ -121,14 +120,14 @@ describe Flapjack::Gateways::Web, :sinatra => true, :logger => true do
|
|
121
120
|
|
122
121
|
it "shows a page listing all checks" do
|
123
122
|
#redis.should_receive(:keys).with('*:*:states').and_return(["#{entity_name}:#{check}"])
|
124
|
-
expect(Flapjack::Data::EntityCheck).to receive(:
|
123
|
+
expect(Flapjack::Data::EntityCheck).to receive(:find_current_by_entity).
|
125
124
|
with(:redis => redis).and_return({entity_name => [check]})
|
126
125
|
expect_check_stats
|
127
126
|
|
128
127
|
expect_entity_check_status(entity_check)
|
129
128
|
|
130
129
|
expect(Flapjack::Data::Entity).to receive(:find_by_name).
|
131
|
-
with(entity_name, :redis => redis).and_return(entity)
|
130
|
+
with(entity_name, hash_including(:redis => redis)).twice.and_return(entity)
|
132
131
|
|
133
132
|
expect(Flapjack::Data::EntityCheck).to receive(:for_entity).
|
134
133
|
with(entity, 'ping', :redis => redis).and_return(entity_check)
|
@@ -147,7 +146,7 @@ describe Flapjack::Gateways::Web, :sinatra => true, :logger => true do
|
|
147
146
|
expect(Flapjack::Data::Entity).to receive(:find_by_name).
|
148
147
|
with(entity_name, :redis => redis).and_return(entity)
|
149
148
|
|
150
|
-
expect(Flapjack::Data::EntityCheck).to receive(:
|
149
|
+
expect(Flapjack::Data::EntityCheck).to receive(:find_current_failing_by_entity).
|
151
150
|
with(:redis => redis).and_return({entity_name => [check]})
|
152
151
|
|
153
152
|
expect(Flapjack::Data::EntityCheck).to receive(:for_entity).
|
@@ -164,6 +163,7 @@ describe Flapjack::Gateways::Web, :sinatra => true, :logger => true do
|
|
164
163
|
expect_entity_stats
|
165
164
|
|
166
165
|
aget '/self_stats'
|
166
|
+
# p @logger.messages
|
167
167
|
expect(last_response).to be_ok
|
168
168
|
end
|
169
169
|
|
@@ -2,32 +2,32 @@ require 'rspec/core/formatters/base_formatter'
|
|
2
2
|
|
3
3
|
class ProfileAllFormatter < RSpec::Core::Formatters::BaseFormatter
|
4
4
|
|
5
|
+
RSpec::Core::Formatters.register self,
|
6
|
+
:example_started, :example_passed, :start_dump
|
7
|
+
|
5
8
|
def initialize(output)
|
6
9
|
super(output)
|
7
10
|
@example_times = []
|
8
11
|
end
|
9
12
|
|
10
|
-
def start(
|
11
|
-
super(
|
13
|
+
def start(notification)
|
14
|
+
super(notification)
|
12
15
|
@output.puts "Profiling enabled."
|
13
16
|
end
|
14
17
|
|
15
|
-
def example_started(
|
16
|
-
super(example)
|
18
|
+
def example_started(notification)
|
17
19
|
@time = ((Time.respond_to?(:zone) && Time.zone) ? Time.zone.now : Time.now)
|
18
20
|
end
|
19
21
|
|
20
|
-
def example_passed(
|
22
|
+
def example_passed(notification)
|
21
23
|
@example_times << [
|
22
|
-
example_group.description,
|
23
|
-
example.description,
|
24
|
+
notification.example.example_group.description,
|
25
|
+
notification.example.description,
|
24
26
|
((Time.respond_to?(:zone) && Time.zone) ? Time.zone.now : Time.now) - @time
|
25
27
|
]
|
26
|
-
super(example)
|
27
28
|
end
|
28
29
|
|
29
|
-
def start_dump
|
30
|
-
super
|
30
|
+
def start_dump(notification)
|
31
31
|
@output.puts "\n\nExample times:\n"
|
32
32
|
|
33
33
|
@example_times = @example_times.sort_by do |description, example, time|
|
@@ -1,9 +1,71 @@
|
|
1
|
-
require 'rspec/core/formatters/
|
1
|
+
require 'rspec/core/formatters/base_text_formatter'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
def color(text, color_code)
|
3
|
+
module NoColorizer
|
4
|
+
def self.wrap(text, color)
|
6
5
|
text
|
7
6
|
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class UncoloredDocFormatter < RSpec::Core::Formatters::BaseTextFormatter
|
10
|
+
RSpec::Core::Formatters.register self, :example_group_started, :example_group_finished,
|
11
|
+
:example_passed, :example_pending, :example_failed,
|
12
|
+
:dump_failures, :dump_pending, :dump_summary
|
13
|
+
|
14
|
+
def initialize(output)
|
15
|
+
super
|
16
|
+
@group_level = 0
|
17
|
+
end
|
18
|
+
|
19
|
+
def example_group_started(notification)
|
20
|
+
output.puts if @group_level == 0
|
21
|
+
output.puts "#{current_indentation}#{notification.group.description.strip}"
|
22
|
+
|
23
|
+
@group_level += 1
|
24
|
+
end
|
25
|
+
|
26
|
+
def example_group_finished(notification)
|
27
|
+
@group_level -= 1
|
28
|
+
end
|
29
|
+
|
30
|
+
def example_passed(passed)
|
31
|
+
output.puts "#{current_indentation}#{passed.example.description.strip}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def example_pending(pending)
|
35
|
+
output.puts "#{current_indentation}#{pending.example.description.strip} (PENDING: #{pending.example.execution_result.pending_message})"
|
36
|
+
end
|
37
|
+
|
38
|
+
def example_failed(failure)
|
39
|
+
output.puts "#{current_indentation}#{failure.example.description.strip} (FAILED - #{next_failure_index})"
|
40
|
+
end
|
41
|
+
|
42
|
+
def dump_failures(notification)
|
43
|
+
return if notification.failure_notifications.empty?
|
44
|
+
output.puts notification.fully_formatted_failed_examples(NoColorizer)
|
45
|
+
end
|
46
|
+
|
47
|
+
def dump_pending(notification)
|
48
|
+
return if notification.pending_examples.empty?
|
49
|
+
output.puts notification.fully_formatted_pending_examples(NoColorizer)
|
50
|
+
end
|
51
|
+
|
52
|
+
def dump_summary(notification)
|
53
|
+
output.puts notification.fully_formatted(NoColorizer)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def next_failure_index
|
59
|
+
@next_failure_index ||= 0
|
60
|
+
@next_failure_index += 1
|
61
|
+
end
|
62
|
+
|
63
|
+
def current_indentation
|
64
|
+
' ' * @group_level
|
65
|
+
end
|
66
|
+
|
67
|
+
def example_group_chain
|
68
|
+
example_group.parent_groups.reverse
|
69
|
+
end
|
8
70
|
|
9
71
|
end
|
data/src/flapjack/event.go
CHANGED
@@ -3,7 +3,7 @@ package flapjack
|
|
3
3
|
import "errors"
|
4
4
|
|
5
5
|
// Event is a basic representation of a Flapjack event.
|
6
|
-
// Find more at
|
6
|
+
// Find more at http://flapjack.io/docs/1.0/development/DATA_STRUCTURES
|
7
7
|
type Event struct {
|
8
8
|
Entity string `json:"entity"`
|
9
9
|
Check string `json:"check"`
|
data/tasks/benchmarks.rake
CHANGED
@@ -2,36 +2,40 @@ require 'redis'
|
|
2
2
|
require 'oj'
|
3
3
|
require 'time'
|
4
4
|
|
5
|
+
# add lib to the default include path
|
6
|
+
unless $:.include?(File.dirname(__FILE__) + '/../lib/')
|
7
|
+
$: << File.dirname(__FILE__) + '/../lib'
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'flapjack/configuration'
|
11
|
+
require 'flapjack/data/event'
|
12
|
+
require 'flapjack/data/entity_check'
|
13
|
+
require 'flapjack/version'
|
14
|
+
|
5
15
|
namespace :benchmarks do
|
6
16
|
|
7
|
-
|
8
|
-
|
9
|
-
$: << File.dirname(__FILE__) + '/../lib'
|
17
|
+
def redis
|
18
|
+
@redis ||= Redis.new(@redis_config)
|
10
19
|
end
|
11
20
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
require 'flapjack/version'
|
21
|
+
task :setup do
|
22
|
+
FLAPJACK_ENV = 'test'
|
23
|
+
config_file = File.join('tasks', 'support', 'flapjack_config_benchmark.yaml')
|
16
24
|
|
17
|
-
|
18
|
-
|
25
|
+
config = Flapjack::Configuration.new
|
26
|
+
config.load( config_file )
|
19
27
|
|
20
|
-
|
21
|
-
|
28
|
+
@config_env = config.all
|
29
|
+
@redis_config = config.for_redis
|
22
30
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
puts "No config data for environment '#{FLAPJACK_ENV}' found in '#{config_file}'"
|
28
|
-
exit(false)
|
31
|
+
if @config_env.nil? || @config_env.empty?
|
32
|
+
puts "No config data for environment '#{FLAPJACK_ENV}' found in '#{config_file}'"
|
33
|
+
exit(false)
|
34
|
+
end
|
29
35
|
end
|
30
36
|
|
31
|
-
redis = Redis.new(@redis_config)
|
32
|
-
|
33
37
|
desc "nukes the redis db, generates the events, runs and shuts down flapjack, generates perftools reports"
|
34
|
-
task :run => [:reset_redis, :benchmark, :run_flapjack, :reports] do
|
38
|
+
task :run => [:setup, :reset_redis, :benchmark, :run_flapjack, :reports] do
|
35
39
|
puts Oj.dump(@benchmark_data, :indent => 2)
|
36
40
|
end
|
37
41
|
|
data/tasks/entities.rake
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'csv'
|
2
|
+
require 'securerandom'
|
3
|
+
|
4
|
+
require 'redis'
|
5
|
+
|
6
|
+
require 'flapjack/configuration'
|
7
|
+
require 'flapjack/data/entity'
|
8
|
+
|
9
|
+
FLAPJACK_ENV = ENV['FLAPJACK_ENV'] || 'production'
|
10
|
+
|
11
|
+
namespace :entities do
|
12
|
+
|
13
|
+
def redis
|
14
|
+
@redis ||= Redis.new(@redis_config)
|
15
|
+
end
|
16
|
+
|
17
|
+
def orphaned_entity_names
|
18
|
+
current_names = Flapjack::Data::Entity.all(:redis => redis).map(&:name)
|
19
|
+
|
20
|
+
all_entity_names = redis.keys("check:*:*").inject([]) do |memo, ck|
|
21
|
+
if ck =~ /^check:([^:]+):.+$/
|
22
|
+
memo << $1
|
23
|
+
end
|
24
|
+
|
25
|
+
memo
|
26
|
+
end
|
27
|
+
|
28
|
+
all_entity_names - current_names
|
29
|
+
end
|
30
|
+
|
31
|
+
task :setup do
|
32
|
+
config_file = File.join('etc', 'flapjack_config.yaml')
|
33
|
+
|
34
|
+
config = Flapjack::Configuration.new
|
35
|
+
config.load( config_file )
|
36
|
+
|
37
|
+
@config_env = config.all
|
38
|
+
@redis_config = config.for_redis
|
39
|
+
|
40
|
+
if @config_env.nil? || @config_env.empty?
|
41
|
+
puts "No config data for environment '#{FLAPJACK_ENV}' found in '#{config_file}'"
|
42
|
+
exit(false)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "lists current entity names and their ids"
|
47
|
+
task :current => [:setup] do
|
48
|
+
puts CSV.generate(:headers => :first_row, :write_headers => true, :row_sep => "\r\n") {|csv|
|
49
|
+
csv << ['id', 'name']
|
50
|
+
Flapjack::Data::Entity.all(:redis => redis).each do |entity|
|
51
|
+
csv << [entity.id, entity.name]
|
52
|
+
end
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
desc "lists entities with data orphaned by entity renames, or created without ids, prior to v1.0"
|
57
|
+
task :orphaned => [:setup] do
|
58
|
+
orph = orphaned_entity_names
|
59
|
+
|
60
|
+
puts CSV.generate(:headers => :first_row, :write_headers => true, :row_sep => "\r\n") {|csv|
|
61
|
+
csv << ['name']
|
62
|
+
orph.each {|orp| csv << [orp]}
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
desc "reparent entity names from a CSV file on input"
|
67
|
+
task :reparent => [:setup] do
|
68
|
+
|
69
|
+
# The CSV should be in the form 'id', 'name', 'old_name'
|
70
|
+
# If more than one old name exists, another row should be used with
|
71
|
+
# the first two values repeated. The id is there as a sanity check
|
72
|
+
# against current data.
|
73
|
+
|
74
|
+
entities = {}
|
75
|
+
old_entities = {}
|
76
|
+
|
77
|
+
CSV.new($stdin, :headers => :first_row, :return_headers => false) {|csv|
|
78
|
+
csv.each {|row|
|
79
|
+
|
80
|
+
id = row['id']
|
81
|
+
name = row['name']
|
82
|
+
old_name = row['old_name']
|
83
|
+
|
84
|
+
if entities.has_key?(id)
|
85
|
+
unless entities[id].eql?(name)
|
86
|
+
raise "Different names for entity id 'id': '#{name}', '#{old_name}'"
|
87
|
+
end
|
88
|
+
else
|
89
|
+
entities[id] = name
|
90
|
+
end
|
91
|
+
|
92
|
+
old_entities[id] ||= []
|
93
|
+
old_entities[id] << old_name
|
94
|
+
}
|
95
|
+
|
96
|
+
old_entities.each_pair do |id, old_entities_for_id|
|
97
|
+
old_entities_for_id.each do |old_entity|
|
98
|
+
puts "Re-parenting '#{old_entity}' data to '#{entities[id]}'"
|
99
|
+
Flapjack::Data::Entity.merge(old_entity, entities[id], :redis => redis)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
}
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
# Checks sent by monitoring data before the related entity had been imported,
|
107
|
+
# before 1.0, had autogenerated entities saved without ids, and these entities
|
108
|
+
# were not re-integrated later. This task will detect and fix any such data.
|
109
|
+
desc "give an identity to entities that never had one"
|
110
|
+
task :repatriate => [:setup] do
|
111
|
+
|
112
|
+
orph = orphaned_entity_names
|
113
|
+
|
114
|
+
CSV.new($stdin, :headers => :first_row, :return_headers => false) {|csv|
|
115
|
+
csv.each {|row|
|
116
|
+
|
117
|
+
name = row['name']
|
118
|
+
id = row['id']
|
119
|
+
|
120
|
+
if !orph.include?(name)
|
121
|
+
puts "'#{name}' is not an orphaned entity."
|
122
|
+
next
|
123
|
+
end
|
124
|
+
|
125
|
+
entity = id.nil? ? nil : Flapjack::Data::Entity.find_by_id(id)
|
126
|
+
|
127
|
+
if id.nil? || entity.nil?
|
128
|
+
id ||= SecureRandom.uuid
|
129
|
+
redis.multi
|
130
|
+
redis.set("entity_id:#{name}", id)
|
131
|
+
redis.hset("entity:#{id}", 'name', name)
|
132
|
+
redis.exec
|
133
|
+
puts "Set id '#{id}' for entity #{name}'"
|
134
|
+
elsif entity.name.eql?(name)
|
135
|
+
puts "'#{name}' entity already exists with the provided id"
|
136
|
+
else
|
137
|
+
# entity exists, name doesn't match -- merge old data
|
138
|
+
Flapjack::Data::Entity.merge(name, entity.name, :redis => redis)
|
139
|
+
puts "Merged data for entity '#{name}' into entity #{entity.name}' with id '#{id}'"
|
140
|
+
end
|
141
|
+
|
142
|
+
}
|
143
|
+
|
144
|
+
}
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|