arborist 0.0.1.pre20160829140603 → 0.0.1.pre20161005112841
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +1 -0
- data.tar.gz.sig +0 -0
- data/ChangeLog +99 -2
- data/Events.md +15 -0
- data/Protocol.md +3 -0
- data/Rakefile +4 -0
- data/TODO.md +2 -9
- data/lib/arborist/client.rb +46 -36
- data/lib/arborist/command/config.rb +1 -0
- data/lib/arborist/dependency.rb +3 -3
- data/lib/arborist/event.rb +3 -1
- data/lib/arborist/event/node.rb +5 -3
- data/lib/arborist/event/node_delta.rb +12 -5
- data/lib/arborist/manager.rb +8 -5
- data/lib/arborist/manager/tree_api.rb +11 -10
- data/lib/arborist/monitor.rb +2 -2
- data/lib/arborist/monitor/socket.rb +12 -8
- data/lib/arborist/node.rb +74 -17
- data/lib/arborist/observer.rb +2 -2
- data/lib/arborist/subscription.rb +22 -6
- data/spec/arborist/dependency_spec.rb +4 -3
- data/spec/arborist/event/node_delta_spec.rb +8 -0
- data/spec/arborist/event/node_spec.rb +0 -1
- data/spec/arborist/manager/tree_api_spec.rb +55 -16
- data/spec/arborist/manager_spec.rb +3 -3
- data/spec/arborist/monitor/socket_spec.rb +10 -26
- data/spec/arborist/node_spec.rb +23 -4
- data/spec/arborist/observer_spec.rb +33 -0
- data/spec/arborist/subscription_spec.rb +63 -11
- metadata +3 -3
- metadata.gz.sig +0 -0
@@ -164,7 +164,7 @@ describe Arborist::Manager do
|
|
164
164
|
|
165
165
|
|
166
166
|
it "checkpoints the state file periodically if an interval is configured" do
|
167
|
-
described_class.configure(
|
167
|
+
described_class.configure( checkpoint_frequency: 20_000, state_file: 'arb.tree' )
|
168
168
|
|
169
169
|
zloop = instance_double( ZMQ::Loop, register: nil, :verbose= => nil )
|
170
170
|
timer = instance_double( ZMQ::Timer, "checkpoint timer" )
|
@@ -203,12 +203,12 @@ describe Arborist::Manager do
|
|
203
203
|
|
204
204
|
it "errors if configured with a heartbeat of 0" do
|
205
205
|
expect {
|
206
|
-
described_class.configure(
|
206
|
+
described_class.configure( heartbeat_frequency: 0 )
|
207
207
|
}.to raise_error( Arborist::ConfigError, /positive non-zero/i )
|
208
208
|
end
|
209
209
|
|
210
210
|
|
211
|
-
it "is sent at the configured "
|
211
|
+
it "is sent at the configured interval"
|
212
212
|
|
213
213
|
end
|
214
214
|
|
@@ -48,12 +48,11 @@ describe Arborist::Monitor::Socket do
|
|
48
48
|
def make_successful_mock_socket( node )
|
49
49
|
address = Addrinfo.tcp( node.addresses.first.to_s, node.port )
|
50
50
|
socket = instance_double( Socket, "#{node.identifier} socket", remote_address: address )
|
51
|
-
errors = [ IO::EINPROGRESSWaitWritable, Errno::EISCONN ]
|
52
51
|
|
53
|
-
expect( socket ).to receive( :connect_nonblock )
|
54
|
-
|
55
|
-
|
56
|
-
|
52
|
+
expect( socket ).to receive( :connect_nonblock ).with( sockaddr_for(node) ).
|
53
|
+
and_raise( IO::EINPROGRESSWaitWritable )
|
54
|
+
allow( socket ).to receive( :getpeername ).
|
55
|
+
and_return( address.to_sockaddr )
|
57
56
|
|
58
57
|
return socket
|
59
58
|
end
|
@@ -74,12 +73,13 @@ describe Arborist::Monitor::Socket do
|
|
74
73
|
def make_wait_error_mock_socket( node, error_class, message )
|
75
74
|
address = Addrinfo.tcp( node.addresses.first.to_s, node.port )
|
76
75
|
socket = instance_double( Socket, "#{node.identifier} socket", remote_address: address )
|
77
|
-
errors = [ IO::EINPROGRESSWaitWritable, error_class.new(message) ]
|
78
76
|
|
79
|
-
expect( socket ).to receive( :connect_nonblock )
|
80
|
-
|
81
|
-
|
82
|
-
|
77
|
+
expect( socket ).to receive( :connect_nonblock ).with( sockaddr_for(node) ).
|
78
|
+
and_raise( IO::EINPROGRESSWaitWritable )
|
79
|
+
expect( socket ).to receive( :getpeername ).
|
80
|
+
and_raise( Errno::EINVAL.new("Invalid argument - getpeername(2)") )
|
81
|
+
expect( socket ).to receive( :read ).with( 1 ).
|
82
|
+
and_raise( Errno::ECONNREFUSED.new )
|
83
83
|
|
84
84
|
return socket
|
85
85
|
end
|
@@ -167,22 +167,6 @@ describe Arborist::Monitor::Socket do
|
|
167
167
|
end
|
168
168
|
|
169
169
|
|
170
|
-
it "updates nodes with an error on a 'getpeername' error" do
|
171
|
-
socket = make_wait_error_mock_socket( www_service_node, Errno::EINVAL, "getpeername(2)" )
|
172
|
-
allow( Socket ).to receive( :new ).and_return( socket )
|
173
|
-
allow( IO ).to receive( :select ).
|
174
|
-
with( nil, [socket], nil, kind_of(Numeric) ).
|
175
|
-
and_return( [nil, [socket], nil] )
|
176
|
-
allow( socket ).to receive( :close )
|
177
|
-
|
178
|
-
result = described_class.run( 'test-www' => www_service_node.fetch_values )
|
179
|
-
|
180
|
-
expect( result ).to be_a( Hash )
|
181
|
-
expect( result ).to include( 'test-www' )
|
182
|
-
expect( result['test-www'] ).to include( error: 'Invalid argument - getpeername(2)' )
|
183
|
-
end
|
184
|
-
|
185
|
-
|
186
170
|
it "can be instantiated to run with a different timeout" do
|
187
171
|
mon = described_class.new.with_timeout( 30 )
|
188
172
|
expect( mon.timeout ).to eq( 30 )
|
data/spec/arborist/node_spec.rb
CHANGED
@@ -205,6 +205,13 @@ describe Arborist::Node do
|
|
205
205
|
expect( node ).to be_disabled
|
206
206
|
end
|
207
207
|
|
208
|
+
it "transitions to `disabled` from `unknown` status if it's updated with an `ack` property" do
|
209
|
+
node.status = 'unknown'
|
210
|
+
node.update( ack: {message: "Maintenance", sender: 'mahlon'} )
|
211
|
+
|
212
|
+
expect( node ).to be_disabled
|
213
|
+
end
|
214
|
+
|
208
215
|
it "stays `disabled` if it gets an error" do
|
209
216
|
node.status = 'up'
|
210
217
|
node.update( ack: {message: "Maintenance", sender: 'mahlon'} )
|
@@ -804,12 +811,24 @@ describe Arborist::Node do
|
|
804
811
|
end
|
805
812
|
|
806
813
|
|
807
|
-
it "can be declared for
|
808
|
-
|
814
|
+
it "can be declared for all of a group of identifiers" do
|
815
|
+
node.depends_on( 'iscsi', 'memcached', 'ldap', on: 'dmz' )
|
816
|
+
expect( node ).to have_dependencies
|
817
|
+
expect( node.dependencies.behavior ).to eq( :all )
|
818
|
+
expect( node.dependencies.identifiers ).to include( 'dmz-iscsi', 'dmz-memcached', 'dmz-ldap' )
|
819
|
+
end
|
809
820
|
|
810
821
|
|
811
|
-
it "can be declared for
|
812
|
-
|
822
|
+
it "can be declared for any of a group of identifiers" do
|
823
|
+
node.depends_on( node.any_of('memcached', on: %w[blade1 blade2 blade3]) )
|
824
|
+
expect( node ).to have_dependencies
|
825
|
+
expect( node.dependencies.behavior ).to eq( :all )
|
826
|
+
expect( node.dependencies.subdeps.size ).to eq( 1 )
|
827
|
+
subdep = node.dependencies.subdeps.first
|
828
|
+
expect( subdep.behavior ).to eq( :any )
|
829
|
+
expect( subdep.identifiers ).
|
830
|
+
to include( 'blade1-memcached', 'blade2-memcached', 'blade3-memcached' )
|
831
|
+
end
|
813
832
|
|
814
833
|
|
815
834
|
it "cause the node to be quieted when the dependent node goes down" do
|
@@ -43,6 +43,39 @@ describe Arborist::Observer do
|
|
43
43
|
end
|
44
44
|
|
45
45
|
|
46
|
+
it "can specify criteria for events" do
|
47
|
+
observer = described_class.new( "testing observer" ) do
|
48
|
+
subscribe to: 'node.up', where: { type: 'host' }
|
49
|
+
end
|
50
|
+
|
51
|
+
expect( observer.subscriptions ).to be_an( Array )
|
52
|
+
expect( observer.subscriptions ).to include( a_hash_including(criteria: {type: 'host'}) )
|
53
|
+
expect( observer.subscriptions.length ).to eq( 1 )
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
it "can specify negative criteria for events" do
|
58
|
+
observer = described_class.new( "testing observer" ) do
|
59
|
+
subscribe to: 'node.up', exclude: { type: 'host' }
|
60
|
+
end
|
61
|
+
|
62
|
+
expect( observer.subscriptions ).to be_an( Array )
|
63
|
+
expect( observer.subscriptions ).to include( a_hash_including(exclude: {type: 'host'}) )
|
64
|
+
expect( observer.subscriptions.length ).to eq( 1 )
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
it "can specify a subscription node other than the root" do
|
69
|
+
observer = described_class.new( "testing observer" ) do
|
70
|
+
subscribe to: 'node.down', on: 'dmz-gateway'
|
71
|
+
end
|
72
|
+
|
73
|
+
expect( observer.subscriptions ).to be_an( Array )
|
74
|
+
expect( observer.subscriptions ).to include( a_hash_including(identifier: 'dmz-gateway') )
|
75
|
+
expect( observer.subscriptions.length ).to eq( 1 )
|
76
|
+
end
|
77
|
+
|
78
|
+
|
46
79
|
it "can specify an action to run when a subscribed event is received" do
|
47
80
|
observer = described_class.new( "testing observer" ) do
|
48
81
|
action do |event|
|
@@ -18,10 +18,6 @@ describe Arborist::Subscription do
|
|
18
18
|
let( :service_node ) do
|
19
19
|
host_node.service( 'ssh' )
|
20
20
|
end
|
21
|
-
let( :published_events ) {[]}
|
22
|
-
let( :subscription ) do
|
23
|
-
described_class.new( 'node.delta', type: 'host', &published_events.method(:push) )
|
24
|
-
end
|
25
21
|
|
26
22
|
|
27
23
|
it "raises an error if created without a callback block" do
|
@@ -32,34 +28,47 @@ describe Arborist::Subscription do
|
|
32
28
|
|
33
29
|
|
34
30
|
it "generates a unique ID when it's created" do
|
31
|
+
subscription = described_class.new( 'node.delta', type: 'host' ) do |*|
|
32
|
+
# no-op
|
33
|
+
end
|
35
34
|
expect( subscription.id ).to match( /^\S{16,}$/ )
|
36
35
|
end
|
37
36
|
|
38
37
|
|
39
38
|
it "publishes events which are of the desired type and have matching criteria" do
|
40
|
-
|
39
|
+
published_events = []
|
40
|
+
subscription = described_class.new( 'node.delta', type: 'host' ) do |_, event|
|
41
|
+
published_events << event
|
42
|
+
end
|
43
|
+
event = Arborist::Event.create( 'node_delta', host_node, 'status' => ['up', 'down'] )
|
41
44
|
|
42
45
|
subscription.on_events( event )
|
43
46
|
|
44
|
-
expect( published_events ).to eq([
|
47
|
+
expect( published_events ).to eq([ event ])
|
45
48
|
end
|
46
49
|
|
47
50
|
|
48
51
|
it "publishes events which are of any type if the specified type is `nil`" do
|
49
|
-
|
52
|
+
published_events = []
|
53
|
+
subscription = described_class.new( nil, type: 'host' ) do |_, event|
|
54
|
+
published_events << event
|
55
|
+
end
|
56
|
+
|
50
57
|
event1 = Arborist::Event.create( 'node_delta', host_node, status: ['up', 'down'] )
|
51
58
|
event2 = Arborist::Event.create( 'node_update', host_node )
|
52
59
|
|
53
60
|
subscription.on_events( event1, event2 )
|
54
61
|
|
55
|
-
expect( published_events ).to eq([
|
56
|
-
subscription.id, event1,
|
57
|
-
subscription.id, event2
|
58
|
-
])
|
62
|
+
expect( published_events ).to eq([ event1, event2 ])
|
59
63
|
end
|
60
64
|
|
61
65
|
|
62
66
|
it "doesn't publish events which are of the desired type but don't have matching criteria" do
|
67
|
+
published_events = []
|
68
|
+
subscription = described_class.new( 'node.delta', type: 'host' ) do |_, event|
|
69
|
+
published_events << event
|
70
|
+
end
|
71
|
+
|
63
72
|
event = Arborist::Event.create( 'node_delta', service_node, status: ['up', 'down'] )
|
64
73
|
|
65
74
|
subscription.on_events( event )
|
@@ -69,6 +78,11 @@ describe Arborist::Subscription do
|
|
69
78
|
|
70
79
|
|
71
80
|
it "doesn't publish events which have matching criteria but aren't of the desired type" do
|
81
|
+
published_events = []
|
82
|
+
subscription = described_class.new( 'node.delta', type: 'host' ) do |_, event|
|
83
|
+
published_events << event
|
84
|
+
end
|
85
|
+
|
72
86
|
event = Arborist::Event.create( 'node_update', host_node )
|
73
87
|
|
74
88
|
subscription.on_events( event )
|
@@ -76,5 +90,43 @@ describe Arborist::Subscription do
|
|
76
90
|
expect( published_events ).to be_empty
|
77
91
|
end
|
78
92
|
|
93
|
+
|
94
|
+
it "doesn't publish events which have matching negative criteria" do
|
95
|
+
published_events = []
|
96
|
+
subscription = described_class.new( 'node.update', type: 'host' ) do |_, event|
|
97
|
+
Loggability[ Arborist ].warn "Published event: %p" % [ event ]
|
98
|
+
published_events << event
|
99
|
+
end
|
100
|
+
subscription.exclude( 'status' => 'down' )
|
101
|
+
|
102
|
+
events = host_node.update( error: "Angry bees." )
|
103
|
+
subscription.on_events( events )
|
104
|
+
|
105
|
+
events = host_node.update( error: nil )
|
106
|
+
subscription.on_events( events )
|
107
|
+
|
108
|
+
expect( published_events ).to all( be_a Arborist::Event::NodeUpdate )
|
109
|
+
expect( published_events.length ).to eq( 1 )
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
it "doesn't publish delta events which have matching negative criteria" do
|
114
|
+
published_events = []
|
115
|
+
subscription = described_class.new( 'node.delta', type: 'host' ) do |_, event|
|
116
|
+
published_events << event
|
117
|
+
end
|
118
|
+
subscription.exclude( 'delta' => {'status' => ['unknown', 'down']} )
|
119
|
+
|
120
|
+
events = host_node.update( error: "Angry badgers." )
|
121
|
+
subscription.on_events( events )
|
122
|
+
|
123
|
+
events = host_node.update( error: nil )
|
124
|
+
subscription.on_events( events )
|
125
|
+
|
126
|
+
expect( published_events.length ).to eq( 1 )
|
127
|
+
expect( published_events.first ).to be_a( Arborist::Event::NodeDelta )
|
128
|
+
expect( published_events.first.payload['status'] ).to eq( ['down', 'up'] )
|
129
|
+
end
|
130
|
+
|
79
131
|
end
|
80
132
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arborist
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.1.
|
4
|
+
version: 0.0.1.pre20161005112841
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Granger
|
@@ -36,7 +36,7 @@ cert_chain:
|
|
36
36
|
w8aNA5re5+Rt/Vvjxj5AcEnZnZiz5x959NaddQocX32Z1unHw44pzRNUur1GInfW
|
37
37
|
p4vpx2kUSFSAGjtCbDGTNV2AH8w9OU4xEmNz8c5lyoA=
|
38
38
|
-----END CERTIFICATE-----
|
39
|
-
date: 2016-
|
39
|
+
date: 2016-10-05 00:00:00.000000000 Z
|
40
40
|
dependencies:
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: schedulability
|
@@ -413,7 +413,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
413
413
|
version: 1.3.1
|
414
414
|
requirements: []
|
415
415
|
rubyforge_project:
|
416
|
-
rubygems_version: 2.
|
416
|
+
rubygems_version: 2.5.1
|
417
417
|
signing_key:
|
418
418
|
specification_version: 4
|
419
419
|
summary: Arborist is a monitoring toolkit that follows the UNIX philosophy of small
|
metadata.gz.sig
ADDED
Binary file
|