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
@@ -19,7 +19,6 @@ class Arborist::Manager::TreeAPI < ZMQ::Handler
|
|
19
19
|
### Create the TreeAPI handler that will read requests from the specified +pollable+
|
20
20
|
### and call into the +manager+ to respond to them.
|
21
21
|
def initialize( pollable, manager )
|
22
|
-
self.log.debug "Setting up a %p" % [ self.class ]
|
23
22
|
@pollitem = pollable
|
24
23
|
@enabled = true
|
25
24
|
@manager = manager
|
@@ -41,8 +40,6 @@ class Arborist::Manager::TreeAPI < ZMQ::Handler
|
|
41
40
|
|
42
41
|
### Handle the specified +raw_request+ and return a response.
|
43
42
|
def handle_request( raw_request )
|
44
|
-
self.log.debug "Handling request: %p" % [ raw_request ]
|
45
|
-
|
46
43
|
raise "Manager is shutting down" unless self.enabled?
|
47
44
|
|
48
45
|
header, body = self.parse_request( raw_request )
|
@@ -68,13 +65,11 @@ class Arborist::Manager::TreeAPI < ZMQ::Handler
|
|
68
65
|
### Attempt to dispatch a request given its +header+ and +body+, and return the
|
69
66
|
### serialized response.
|
70
67
|
def dispatch_request( header, body )
|
71
|
-
self.log.debug "Dispatching request %p -> %p" % [ header, body ]
|
72
68
|
handler = self.lookup_request_action( header ) or
|
73
69
|
raise Arborist::RequestError, "No such action '%s'" % [ header['action'] ]
|
74
70
|
|
75
71
|
response = handler.call( header, body )
|
76
72
|
|
77
|
-
self.log.debug "Returning response: %p" % [ response ]
|
78
73
|
return response
|
79
74
|
end
|
80
75
|
|
@@ -96,7 +91,6 @@ class Arborist::Manager::TreeAPI < ZMQ::Handler
|
|
96
91
|
msg = [
|
97
92
|
{ category: category, reason: reason, success: false, version: 1 }
|
98
93
|
]
|
99
|
-
self.log.debug "Returning error response: %p" % [ msg ]
|
100
94
|
return MessagePack.pack( msg )
|
101
95
|
end
|
102
96
|
|
@@ -107,7 +101,6 @@ class Arborist::Manager::TreeAPI < ZMQ::Handler
|
|
107
101
|
{ success: true, version: 1 },
|
108
102
|
body
|
109
103
|
]
|
110
|
-
self.log.debug "Returning successful response: %p" % [ msg ]
|
111
104
|
return MessagePack.pack( msg )
|
112
105
|
end
|
113
106
|
|
@@ -120,8 +113,6 @@ class Arborist::Manager::TreeAPI < ZMQ::Handler
|
|
120
113
|
raise Arborist::RequestError, err.message
|
121
114
|
end
|
122
115
|
|
123
|
-
self.log.debug "Parsed request: %p" % [ tuple ]
|
124
|
-
|
125
116
|
raise Arborist::RequestError, 'not a tuple' unless tuple.is_a?( Array )
|
126
117
|
raise Arborist::RequestError, 'incorrect length' if tuple.length.zero? || tuple.length > 2
|
127
118
|
|
@@ -158,7 +149,13 @@ class Arborist::Manager::TreeAPI < ZMQ::Handler
|
|
158
149
|
self.log.debug "SUBSCRIBE: %p" % [ header ]
|
159
150
|
event_type = header[ 'event_type' ]
|
160
151
|
node_identifier = header[ 'identifier' ]
|
161
|
-
|
152
|
+
|
153
|
+
body = [ body ] unless body.is_a?( Array )
|
154
|
+
positive = body.shift
|
155
|
+
negative = body.shift || {}
|
156
|
+
|
157
|
+
subscription = @manager.
|
158
|
+
create_subscription( node_identifier, event_type, positive, negative )
|
162
159
|
|
163
160
|
return successful_response([ subscription.id ])
|
164
161
|
end
|
@@ -225,6 +222,10 @@ class Arborist::Manager::TreeAPI < ZMQ::Handler
|
|
225
222
|
def handle_update_request( header, body )
|
226
223
|
self.log.debug "UPDATE: %p" % [ header ]
|
227
224
|
|
225
|
+
unless body.respond_to?( :each )
|
226
|
+
return error_response( 'client', 'Malformed update: body does not respond to #each' )
|
227
|
+
end
|
228
|
+
|
228
229
|
body.each do |identifier, properties|
|
229
230
|
@manager.update_node( identifier, properties )
|
230
231
|
end
|
data/lib/arborist/monitor.rb
CHANGED
@@ -301,14 +301,14 @@ class Arborist::Monitor
|
|
301
301
|
### Specify that the monitor should include the specified +criteria+ when searching
|
302
302
|
### for nodes it will run against.
|
303
303
|
def match( criteria )
|
304
|
-
|
304
|
+
self.positive_criteria.merge!( criteria )
|
305
305
|
end
|
306
306
|
|
307
307
|
|
308
308
|
### Specify that the monitor should exclude nodes which match the specified
|
309
309
|
### +criteria+ when searching for nodes it will run against.
|
310
310
|
def exclude( criteria )
|
311
|
-
|
311
|
+
self.negative_criteria.merge!( criteria )
|
312
312
|
end
|
313
313
|
|
314
314
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# -*- ruby -*-
|
2
2
|
#encoding: utf-8
|
3
3
|
|
4
|
+
require 'time'
|
4
5
|
require 'loggability'
|
5
6
|
require 'timeout'
|
6
7
|
require 'socket'
|
@@ -118,10 +119,9 @@ module Arborist::Monitor::Socket
|
|
118
119
|
# Now wait for connections to complete
|
119
120
|
wait_seconds = timeout_at - Time.now
|
120
121
|
until connections.empty? || wait_seconds <= 0
|
121
|
-
self.log.debug "Waiting on %d connections for %0.
|
122
|
+
self.log.debug "Waiting on %d connections for %0.3fs..." %
|
122
123
|
[ connections.values.length, wait_seconds ]
|
123
124
|
|
124
|
-
# :FIXME: Race condition: errors if timeout_at - Time.now is 0
|
125
125
|
_, ready, _ = IO.select( nil, connections.keys, nil, wait_seconds )
|
126
126
|
|
127
127
|
now = Time.now
|
@@ -129,14 +129,18 @@ module Arborist::Monitor::Socket
|
|
129
129
|
identifier, sockaddr = *connections.delete( sock )
|
130
130
|
|
131
131
|
begin
|
132
|
-
sock.
|
133
|
-
|
132
|
+
res = sock.getpeername
|
133
|
+
self.log.debug "connected to %s" % [ identifier ]
|
134
134
|
results[ identifier ] = {
|
135
|
-
tcp_socket_connect: { time: now.
|
135
|
+
tcp_socket_connect: { time: now.iso8601, duration: now - start }
|
136
136
|
}
|
137
137
|
rescue SocketError, SystemCallError => err
|
138
|
-
|
139
|
-
|
138
|
+
begin
|
139
|
+
sock.read( 1 )
|
140
|
+
rescue => err
|
141
|
+
self.log.debug "read: %p: %s" % [ err.class, err.message ]
|
142
|
+
results[ identifier ] = { error: err.message }
|
143
|
+
end
|
140
144
|
ensure
|
141
145
|
sock.close
|
142
146
|
end
|
@@ -257,7 +261,7 @@ module Arborist::Monitor::Socket
|
|
257
261
|
if ready.nil?
|
258
262
|
now = Time.now
|
259
263
|
results[ identifier ] = {
|
260
|
-
udp_socket_connect: { time: now.
|
264
|
+
udp_socket_connect: { time: now.iso8601, duration: now - start }
|
261
265
|
}
|
262
266
|
self.log.debug " connection successful"
|
263
267
|
else
|
data/lib/arborist/node.rb
CHANGED
@@ -33,6 +33,21 @@ class Arborist::Node
|
|
33
33
|
# Regex to match a valid identifier
|
34
34
|
VALID_IDENTIFIER = /^\w[\w\-]*$/
|
35
35
|
|
36
|
+
# The attributes of a node which are used in the operation of the system
|
37
|
+
OPERATIONAL_ATTRIBUTES = %i[
|
38
|
+
type
|
39
|
+
status
|
40
|
+
tags
|
41
|
+
parent
|
42
|
+
description
|
43
|
+
dependencies
|
44
|
+
status_changed
|
45
|
+
last_contacted
|
46
|
+
ack
|
47
|
+
error
|
48
|
+
quieted_reasons
|
49
|
+
config
|
50
|
+
]
|
36
51
|
|
37
52
|
autoload :Root, 'arborist/node/root'
|
38
53
|
autoload :Ack, 'arborist/node/ack'
|
@@ -98,15 +113,14 @@ class Arborist::Node
|
|
98
113
|
:quieted
|
99
114
|
|
100
115
|
event :update do
|
116
|
+
transition [:up, :unknown] => :disabled, if: :ack_set?
|
101
117
|
transition [:down, :unknown, :acked] => :up, if: :last_contact_successful?
|
102
118
|
transition [:up, :unknown] => :down, unless: :last_contact_successful?
|
103
119
|
transition :down => :acked, if: :ack_set?
|
104
|
-
transition [:unknown, :up] => :disabled, if: :ack_set?
|
105
120
|
transition :disabled => :unknown, unless: :ack_set?
|
106
121
|
end
|
107
122
|
|
108
123
|
event :handle_event do
|
109
|
-
transition :unknown => :acked, if: :ack_and_error_set?
|
110
124
|
transition any - [:disabled, :quieted, :acked] => :quieted, if: :has_quieted_reason?
|
111
125
|
transition :quieted => :unknown, unless: :has_quieted_reason?
|
112
126
|
end
|
@@ -541,7 +555,15 @@ class Arborist::Node
|
|
541
555
|
|
542
556
|
|
543
557
|
### Returns +true+ if the specified search +criteria+ all match this node.
|
544
|
-
def matches?( criteria )
|
558
|
+
def matches?( criteria, if_empty: true )
|
559
|
+
|
560
|
+
# Omit 'delta' criteria from matches; delta matching is done separately.
|
561
|
+
criteria = criteria.dup
|
562
|
+
criteria.delete( 'delta' )
|
563
|
+
|
564
|
+
self.log.debug "Node matching %p (%p if empty)" % [ criteria, if_empty ]
|
565
|
+
return if_empty if criteria.empty?
|
566
|
+
|
545
567
|
self.log.debug "Matching %p against criteria: %p" % [ self, criteria ]
|
546
568
|
return criteria.all? do |key, val|
|
547
569
|
self.match_criteria?( key, val )
|
@@ -552,8 +574,6 @@ class Arborist::Node
|
|
552
574
|
### Returns +true+ if the node matches the specified +key+ and +val+ criteria.
|
553
575
|
def match_criteria?( key, val )
|
554
576
|
return case key
|
555
|
-
when 'delta'
|
556
|
-
true
|
557
577
|
when 'status'
|
558
578
|
self.status == val
|
559
579
|
when 'type'
|
@@ -574,6 +594,7 @@ class Arborist::Node
|
|
574
594
|
def fetch_values( value_spec=nil )
|
575
595
|
state = self.properties.merge( self.operational_values )
|
576
596
|
state = stringify_keys( state )
|
597
|
+
state = make_serializable( state )
|
577
598
|
|
578
599
|
if value_spec
|
579
600
|
self.log.debug "Eliminating all values except: %p (from keys: %p)" %
|
@@ -588,12 +609,9 @@ class Arborist::Node
|
|
588
609
|
### Return a Hash of the operational values that are included with the node's
|
589
610
|
### monitor state.
|
590
611
|
def operational_values
|
591
|
-
values = {
|
592
|
-
|
593
|
-
|
594
|
-
tags: self.tags
|
595
|
-
}
|
596
|
-
values[:ack] = self.ack.to_h if self.ack
|
612
|
+
values = OPERATIONAL_ATTRIBUTES.each_with_object( {} ) do |key, hash|
|
613
|
+
hash[ key ] = self.send( key )
|
614
|
+
end
|
597
615
|
|
598
616
|
return values
|
599
617
|
end
|
@@ -644,11 +662,19 @@ class Arborist::Node
|
|
644
662
|
def handle_event( event )
|
645
663
|
self.log.debug "Handling %p" % [ event ]
|
646
664
|
handler_name = "handle_%s_event" % [ event.type.gsub('.', '_') ]
|
665
|
+
|
647
666
|
if self.respond_to?( handler_name )
|
648
667
|
self.log.debug "Handling a %s event." % [ event.type ]
|
649
668
|
self.method( handler_name ).call( event )
|
669
|
+
else
|
670
|
+
self.log.debug "No handler for a %s event!" % [ event.type ]
|
650
671
|
end
|
672
|
+
|
651
673
|
super # to state-machine
|
674
|
+
|
675
|
+
self.publish_events( event, *self.pending_update_events )
|
676
|
+
ensure
|
677
|
+
self.pending_update_events.clear
|
652
678
|
end
|
653
679
|
|
654
680
|
|
@@ -688,6 +714,21 @@ class Arborist::Node
|
|
688
714
|
end
|
689
715
|
|
690
716
|
|
717
|
+
def handle_node_disabled_event( event )
|
718
|
+
self.log.debug "Got a node.disabled event: %p" % [ event ]
|
719
|
+
self.dependencies.mark_down( event.node.identifier )
|
720
|
+
|
721
|
+
if self.dependencies_down?
|
722
|
+
self.quieted_reasons[ :secondary ] = "Secondary dependencies not met: %s" %
|
723
|
+
[ self.dependencies.down_reason ]
|
724
|
+
end
|
725
|
+
|
726
|
+
if event.node.identifier == self.parent
|
727
|
+
self.quieted_reasons[ :primary ] = "Parent disabled: %s" % [ self.parent ]
|
728
|
+
end
|
729
|
+
end
|
730
|
+
|
731
|
+
|
691
732
|
### Handle a 'node.quieted' event received via broadcast.
|
692
733
|
def handle_node_quieted_event( event )
|
693
734
|
self.log.debug "Got a node.quieted event: %p" % [ event ]
|
@@ -947,12 +988,6 @@ class Arborist::Node
|
|
947
988
|
end
|
948
989
|
|
949
990
|
|
950
|
-
### Returns +true+ if the node has been acked and also has an error set.
|
951
|
-
def ack_and_error_set?
|
952
|
-
return self.error && self.ack_set?
|
953
|
-
end
|
954
|
-
|
955
|
-
|
956
991
|
#
|
957
992
|
# :section: State Callbacks
|
958
993
|
#
|
@@ -1056,4 +1091,26 @@ class Arborist::Node
|
|
1056
1091
|
end
|
1057
1092
|
|
1058
1093
|
|
1094
|
+
### Turn any non-msgpack-able objects in the values of a copy of +hash+ to
|
1095
|
+
### values that can be serialized and return the copy.
|
1096
|
+
def make_serializable( hash )
|
1097
|
+
new_hash = hash.dup
|
1098
|
+
new_hash.keys.each do |key|
|
1099
|
+
val = new_hash[ key ]
|
1100
|
+
case val
|
1101
|
+
when Hash
|
1102
|
+
new_hash[ key ] = make_serializable( val )
|
1103
|
+
|
1104
|
+
when Arborist::Dependency,
|
1105
|
+
Arborist::Node::Ack
|
1106
|
+
new_hash[ key ] = val.to_h
|
1107
|
+
|
1108
|
+
when Time
|
1109
|
+
new_hash[ key ] = val.iso8601
|
1110
|
+
end
|
1111
|
+
end
|
1112
|
+
|
1113
|
+
return new_hash
|
1114
|
+
end
|
1115
|
+
|
1059
1116
|
end # class Arborist::Node
|
data/lib/arborist/observer.rb
CHANGED
@@ -107,8 +107,8 @@ class Arborist::Observer
|
|
107
107
|
### on::
|
108
108
|
### the identifier of the node to subscribe on, defaults to the root node
|
109
109
|
## which receives all node events.
|
110
|
-
def subscribe( to: nil, where: {}, on: nil )
|
111
|
-
@subscriptions << { criteria: where, identifier: on, event_type: to }
|
110
|
+
def subscribe( to: nil, where: {}, exclude: {}, on: nil )
|
111
|
+
@subscriptions << { criteria: where, exclude: exclude, identifier: on, event_type: to }
|
112
112
|
end
|
113
113
|
|
114
114
|
|
@@ -20,11 +20,14 @@ class Arborist::Subscription
|
|
20
20
|
|
21
21
|
### Instantiate a new Subscription object given an +event+ pattern
|
22
22
|
### and event +criteria+.
|
23
|
-
def initialize( event_type=nil, criteria={}, &callback )
|
23
|
+
def initialize( event_type=nil, criteria={}, negative_criteria={}, &callback )
|
24
24
|
raise LocalJumpError, "requires a callback block" unless callback
|
25
|
+
|
25
26
|
@callback = callback
|
26
27
|
@event_type = event_type
|
27
28
|
@criteria = stringify_keys( criteria )
|
29
|
+
@negative_criteria = stringify_keys( negative_criteria )
|
30
|
+
|
28
31
|
@id = self.generate_id
|
29
32
|
end
|
30
33
|
|
@@ -42,9 +45,19 @@ class Arborist::Subscription
|
|
42
45
|
# The Arborist event pattern that this subscription handles.
|
43
46
|
attr_reader :event_type
|
44
47
|
|
45
|
-
# Node selection attributes to
|
48
|
+
# Node selection attributes to require
|
46
49
|
attr_reader :criteria
|
47
50
|
|
51
|
+
# Node selection attributes to exclude
|
52
|
+
attr_reader :negative_criteria
|
53
|
+
|
54
|
+
|
55
|
+
### Add the given +criteria+ hash to the #negative_criteria.
|
56
|
+
def exclude( criteria )
|
57
|
+
criteria = stringify_keys( criteria )
|
58
|
+
self.negative_criteria.merge!( criteria )
|
59
|
+
end
|
60
|
+
|
48
61
|
|
49
62
|
### Create an identifier for this subscription object.
|
50
63
|
def generate_id
|
@@ -65,21 +78,24 @@ class Arborist::Subscription
|
|
65
78
|
|
66
79
|
### Returns +true+ if the receiver is interested in publishing the specified +event+.
|
67
80
|
def interested_in?( event )
|
68
|
-
self.log.debug "Testing %p against type = %p and criteria = %p" %
|
69
|
-
[ event, self.event_type, self.criteria ]
|
70
|
-
|
81
|
+
self.log.debug "Testing %p against type = %p and criteria = %p but not %p" %
|
82
|
+
[ event, self.event_type, self.criteria, self.negative_criteria ]
|
83
|
+
rval = event.match( self )
|
84
|
+
self.log.debug " event %s match." % [ rval ? "did" : "did NOT" ]
|
85
|
+
return rval
|
71
86
|
end
|
72
87
|
alias_method :is_interested_in?, :interested_in?
|
73
88
|
|
74
89
|
|
75
90
|
### Return a String representation of the object suitable for debugging.
|
76
91
|
def inspect
|
77
|
-
return "#<%p:%#x [%s] for %s events matching: %p -> %p>" % [
|
92
|
+
return "#<%p:%#x [%s] for %s events matching: %p %s-> %p>" % [
|
78
93
|
self.class,
|
79
94
|
self.object_id * 2,
|
80
95
|
self.id,
|
81
96
|
self.event_type,
|
82
97
|
self.criteria,
|
98
|
+
self.negative_criteria.empty? ? '' : "(but not #{self.negative_criteria.inspect}",
|
83
99
|
self.callback,
|
84
100
|
]
|
85
101
|
end
|
@@ -321,7 +321,7 @@ describe Arborist::Dependency do
|
|
321
321
|
|
322
322
|
it "can describe the reason it's down" do
|
323
323
|
dep.mark_down( 'node2' )
|
324
|
-
expect( dep.down_reason ).to match( /node2 is
|
324
|
+
expect( dep.down_reason ).to match( /node2 is unavailable as of/i )
|
325
325
|
end
|
326
326
|
|
327
327
|
|
@@ -329,7 +329,7 @@ describe Arborist::Dependency do
|
|
329
329
|
dep.mark_down( 'node1' )
|
330
330
|
dep.mark_down( 'node2' )
|
331
331
|
# :FIXME: Does order matter in the 'all' case? This assumes no.
|
332
|
-
expect( dep.down_reason ).to match( /node(1|2) \(and 1 other\) are
|
332
|
+
expect( dep.down_reason ).to match( /node(1|2) \(and 1 other\) are unavailable as of/i )
|
333
333
|
end
|
334
334
|
|
335
335
|
end
|
@@ -364,7 +364,8 @@ describe Arborist::Dependency do
|
|
364
364
|
dep.mark_down( 'node2' )
|
365
365
|
dep.mark_down( 'node1' )
|
366
366
|
|
367
|
-
expect( dep.down_reason ).to match( /are all
|
367
|
+
expect( dep.down_reason ).to match( /are all unavailable as of/i ).
|
368
|
+
and( include('node1', 'node2') )
|
368
369
|
end
|
369
370
|
|
370
371
|
end
|
@@ -59,6 +59,14 @@ describe Arborist::Event::NodeDelta do
|
|
59
59
|
end
|
60
60
|
|
61
61
|
|
62
|
+
it "doesn't match a subscription with matching negative criteria" do
|
63
|
+
sub = Arborist::Subscription.new( 'node.delta', 'type' => node.type ) {}
|
64
|
+
sub.exclude( 'delta' => {status: ['up', 'down']} )
|
65
|
+
event = described_class.new( node, 'status' => ['up', 'down'] )
|
66
|
+
|
67
|
+
expect( event ).to_not match( sub )
|
68
|
+
end
|
69
|
+
|
62
70
|
end
|
63
71
|
|
64
72
|
|
@@ -393,17 +393,22 @@ describe Arborist::Manager::TreeAPI, :testing_manager do
|
|
393
393
|
expect( hdr ).to include( 'success' => true )
|
394
394
|
end
|
395
395
|
|
396
|
+
it "fails with a client error if the body is invalid" do
|
397
|
+
msg = pack_message( :update, nil )
|
398
|
+
sock.send( msg )
|
399
|
+
resmsg = sock.recv
|
400
|
+
|
401
|
+
hdr, body = unpack_message( resmsg )
|
402
|
+
expect( hdr ).to include( 'success' => false )
|
403
|
+
expect( hdr['reason'] ).to match( /respond to #each/ )
|
404
|
+
end
|
396
405
|
end
|
397
406
|
|
398
407
|
|
399
408
|
describe "subscribe" do
|
400
409
|
|
401
410
|
it "adds a subscription for all event types to the root node by default" do
|
402
|
-
|
403
|
-
type: 'host'
|
404
|
-
}
|
405
|
-
|
406
|
-
msg = pack_message( :subscribe, criteria )
|
411
|
+
msg = pack_message( :subscribe, [{}, {}] )
|
407
412
|
|
408
413
|
resmsg = nil
|
409
414
|
expect {
|
@@ -422,11 +427,7 @@ describe Arborist::Manager::TreeAPI, :testing_manager do
|
|
422
427
|
|
423
428
|
|
424
429
|
it "adds a subscription to the specified node if an identifier is specified" do
|
425
|
-
|
426
|
-
type: 'host'
|
427
|
-
}
|
428
|
-
|
429
|
-
msg = pack_message( :subscribe, {identifier: 'sidonie'}, criteria )
|
430
|
+
msg = pack_message( :subscribe, {identifier: 'sidonie'}, [{}, {}] )
|
430
431
|
|
431
432
|
resmsg = nil
|
432
433
|
expect {
|
@@ -444,12 +445,49 @@ describe Arborist::Manager::TreeAPI, :testing_manager do
|
|
444
445
|
end
|
445
446
|
|
446
447
|
|
447
|
-
it "adds a subscription for
|
448
|
-
|
449
|
-
|
450
|
-
|
448
|
+
it "adds a subscription for particular event types if one is specified" do
|
449
|
+
msg = pack_message( :subscribe, {event_type: 'node.acked'}, [{}, {}] )
|
450
|
+
|
451
|
+
resmsg = nil
|
452
|
+
expect {
|
453
|
+
sock.send( msg )
|
454
|
+
resmsg = sock.recv
|
455
|
+
}.to change { manager.subscriptions.length }.by( 1 ).and(
|
456
|
+
change { manager.root.subscriptions.length }.by( 1 )
|
457
|
+
)
|
458
|
+
hdr, body = unpack_message( resmsg )
|
459
|
+
node = manager.subscriptions[ body.first ]
|
460
|
+
sub = node.subscriptions[ body.first ]
|
461
|
+
|
462
|
+
expect( sub.event_type ).to eq( 'node.acked' )
|
463
|
+
end
|
464
|
+
|
465
|
+
|
466
|
+
it "adds a subscription for events which match a pattern if one is specified" do
|
467
|
+
criteria = { type: 'host' }
|
468
|
+
|
469
|
+
msg = pack_message( :subscribe, [criteria, {}] )
|
470
|
+
|
471
|
+
resmsg = nil
|
472
|
+
expect {
|
473
|
+
sock.send( msg )
|
474
|
+
resmsg = sock.recv
|
475
|
+
}.to change { manager.subscriptions.length }.by( 1 ).and(
|
476
|
+
change { manager.root.subscriptions.length }.by( 1 )
|
477
|
+
)
|
478
|
+
hdr, body = unpack_message( resmsg )
|
479
|
+
node = manager.subscriptions[ body.first ]
|
480
|
+
sub = node.subscriptions[ body.first ]
|
481
|
+
|
482
|
+
expect( sub.event_type ).to be_nil
|
483
|
+
expect( sub.criteria ).to eq({ 'type' => 'host' })
|
484
|
+
end
|
485
|
+
|
486
|
+
|
487
|
+
it "adds a subscription for events which don't match a pattern if an exclusion pattern is given" do
|
488
|
+
criteria = { type: 'host' }
|
451
489
|
|
452
|
-
msg = pack_message( :subscribe, {
|
490
|
+
msg = pack_message( :subscribe, [{}, criteria] )
|
453
491
|
|
454
492
|
resmsg = nil
|
455
493
|
expect {
|
@@ -462,7 +500,8 @@ describe Arborist::Manager::TreeAPI, :testing_manager do
|
|
462
500
|
node = manager.subscriptions[ body.first ]
|
463
501
|
sub = node.subscriptions[ body.first ]
|
464
502
|
|
465
|
-
expect( sub.event_type ).to
|
503
|
+
expect( sub.event_type ).to be_nil
|
504
|
+
expect( sub.negative_criteria ).to eq({ 'type' => 'host' })
|
466
505
|
end
|
467
506
|
|
468
507
|
end
|