arborist 0.0.1.pre20161005182540 → 0.1.0
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 +3 -2
- data.tar.gz.sig +0 -0
- data/ChangeLog +68 -2
- data/History.md +1 -1
- data/Monitors.md +24 -10
- data/Rakefile +3 -3
- data/TODO.md +0 -2
- data/lib/arborist.rb +2 -2
- data/lib/arborist/client.rb +6 -6
- data/lib/arborist/command/watch.rb +2 -2
- data/lib/arborist/manager.rb +1 -3
- data/lib/arborist/mixins.rb +2 -2
- data/lib/arborist/monitor.rb +38 -8
- data/lib/arborist/monitor_runner.rb +6 -0
- data/lib/arborist/node.rb +58 -18
- data/spec/arborist/client_spec.rb +195 -168
- data/spec/arborist/event/node_down_spec.rb +1 -1
- data/spec/arborist/manager_spec.rb +2 -2
- data/spec/arborist/monitor_runner_spec.rb +32 -3
- data/spec/arborist/monitor_spec.rb +93 -17
- data/spec/arborist/node_spec.rb +49 -9
- metadata +21 -21
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cc3ce9e3d25176605f9895778c5654b57e8aa1c0
|
4
|
+
data.tar.gz: 4528bd2bcc17d925a9ea2ce63c475117839e98cd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd351f828f9d9dd9738541d93d852f82a7a12bcda91f1e4a7bda5bd38adedbf3da6fe52e7f729eab2f0d0678f71cd6b953ce449532e1b1cd9da14d18076a49c2
|
7
|
+
data.tar.gz: 3ac9921a9a8fc177ccba6036ab1fa00682cfc6ee892e7fde5aa3db34c5dc2832b32fd5a6e3f59518d8b4a9956b48a36ca39e10a83ff3b57dae895c845c5bf800
|
checksums.yaml.gz.sig
CHANGED
@@ -1,2 +1,3 @@
|
|
1
|
-
a
|
2
|
-
a���
|
1
|
+
bZ_�Ov�97�~��2�+쳦�;鄀 ��#��D5ma��5�PÀ\,�G(� %A3��&���Z!�g��s�x4
|
2
|
+
���ʩ�V�da�oMʡ8��K��:���40�R����t˝&�� 3��/c����"Y�*��w�����N�;Q��#�~xZ��jw��J#�<�_���C\�X������ܘ5)a�$:��gLd)T��&�z)k��T)}�V��Dv��^�&��S�T$(� ��vE���Vn�M,]ST�x��i�OR�L���]�9qn������
|
3
|
+
�=�x=�8@fv~���c�gim))���f�@����ހh!�5^���¼Hp� �o 3ϸ�*�c���ꎛ]�c"�X��
|
data.tar.gz.sig
CHANGED
Binary file
|
data/ChangeLog
CHANGED
@@ -1,9 +1,75 @@
|
|
1
|
+
2016-12-28 Michael Granger <ged@FaerieMUD.org>
|
2
|
+
|
3
|
+
* .gems, Rakefile:
|
4
|
+
Update to latest *ability
|
5
|
+
[09438b7a8aff] [tip]
|
6
|
+
|
7
|
+
2016-10-19 Michael Granger <ged@FaerieMUD.org>
|
8
|
+
|
9
|
+
* lib/arborist/client.rb:
|
10
|
+
Use ** instead of * for client methods that take keyword args
|
11
|
+
[73b6f150a8c1] [github/master]
|
12
|
+
|
13
|
+
* lib/arborist/mixins.rb, lib/arborist/node.rb,
|
14
|
+
spec/arborist/client_spec.rb:
|
15
|
+
Add specs for Client#ack and #unack
|
16
|
+
[819556c743c6]
|
17
|
+
|
18
|
+
2016-10-17 Michael Granger <ged@FaerieMUD.org>
|
19
|
+
|
20
|
+
* TODO.md:
|
21
|
+
Add a note to the TODO list
|
22
|
+
[3de683ee0405]
|
23
|
+
|
24
|
+
2016-10-12 Michael Granger <ged@FaerieMUD.org>
|
25
|
+
|
26
|
+
* spec/arborist/node_spec.rb:
|
27
|
+
Remove accidentally-commited focus
|
28
|
+
[d2cac6a84aaa]
|
29
|
+
|
30
|
+
2016-10-12 Mahlon E. Smith <mahlon@martini.nu>
|
31
|
+
|
32
|
+
* lib/arborist/node.rb, spec/arborist/node_spec.rb:
|
33
|
+
Add matching for 'parent' attribute data.
|
34
|
+
[c50907900b60]
|
35
|
+
|
36
|
+
2016-10-06 Mahlon E. Smith <mahlon@martini.nu>
|
37
|
+
|
38
|
+
* lib/arborist/manager.rb, lib/arborist/monitor.rb,
|
39
|
+
lib/arborist/node.rb, spec/arborist/monitor_spec.rb,
|
40
|
+
spec/arborist/node_spec.rb:
|
41
|
+
Make monitors automatically set #include_down if matching on an
|
42
|
+
unreachable status type.
|
43
|
+
|
44
|
+
- Add reachable? and unreachable? predacates to node
|
45
|
+
- Whitespace fixes
|
46
|
+
[3dcff4c89426]
|
47
|
+
|
48
|
+
2016-10-05 Mahlon E. Smith <mahlon@martini.nu>
|
49
|
+
|
50
|
+
* lib/arborist/node.rb:
|
51
|
+
Reenable event publishing from handle_event().
|
52
|
+
[1918cc1afa1a]
|
53
|
+
|
54
|
+
2016-10-05 Michael Granger <ged@FaerieMUD.org>
|
55
|
+
|
56
|
+
* lib/arborist/node.rb, spec/arborist/node_spec.rb:
|
57
|
+
Fix event broadcasting for deep hierarchies.
|
58
|
+
|
59
|
+
- Refactored event broadcasting so #update and #handle_event share
|
60
|
+
broadcasting code.
|
61
|
+
[9ab8636bb2c5]
|
62
|
+
|
63
|
+
* Rakefile, arborist.gemspec:
|
64
|
+
Update gemspec with Ruby requirements
|
65
|
+
[8ea4314d4dc9]
|
66
|
+
|
1
67
|
2016-10-04 Mahlon E. Smith <mahlon@martini.nu>
|
2
68
|
|
3
69
|
* lib/arborist/node.rb:
|
4
70
|
State transition cleanup: Only nodes in a 'down' state can
|
5
71
|
transition to 'acked'.
|
6
|
-
[eed40468bb5e]
|
72
|
+
[eed40468bb5e]
|
7
73
|
|
8
74
|
2016-10-03 Mahlon E. Smith <mahlon@laika.com>
|
9
75
|
|
@@ -15,7 +81,7 @@
|
|
15
81
|
|
16
82
|
* TODO.md, lib/arborist/node.rb, spec/arborist/node_spec.rb:
|
17
83
|
Fix the unknown => disabled transition when updating with an ACK
|
18
|
-
[30d2548e1308]
|
84
|
+
[30d2548e1308]
|
19
85
|
|
20
86
|
* lib/arborist/manager.rb, spec/arborist/manager_spec.rb:
|
21
87
|
Flatten the config into one namespace
|
data/History.md
CHANGED
data/Monitors.md
CHANGED
@@ -7,7 +7,7 @@ of an Arborist::MonitorRunner object. The `Arborist::Monitor.each_in` method, gi
|
|
7
7
|
|
8
8
|
## Declaration DSL
|
9
9
|
|
10
|
-
To facilitate describing monitors to run, Arborist::Monitor also provides a DSL-like syntax for constructing them.
|
10
|
+
To facilitate describing monitors to run, Arborist::Monitor also provides a DSL-like syntax for constructing them.
|
11
11
|
|
12
12
|
For example, this would declare two monitors, one which pings every 'host' node except those tagged as laptops in the network every 20 seconds, and the other which pings 'host' nodes tagged as laptops every 5 minutes.
|
13
13
|
|
@@ -15,24 +15,38 @@ For example, this would declare two monitors, one which pings every 'host' node
|
|
15
15
|
require 'arborist/monitor'
|
16
16
|
|
17
17
|
Arborist::Monitor 'ping check' do
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
key :pingcheck
|
19
|
+
every 20.seconds
|
20
|
+
match type: 'host'
|
21
|
+
exclude tag: :laptop
|
22
|
+
use :address
|
23
|
+
exec 'fping'
|
23
24
|
end
|
24
25
|
|
25
26
|
Arborist::Monitor 'transient host pings' do
|
26
|
-
|
27
|
-
|
27
|
+
key :pingcheck
|
28
|
+
every 5.minutes
|
29
|
+
match type: 'host', tag: 'laptop'
|
28
30
|
use :address
|
29
|
-
|
31
|
+
exec 'fping'
|
30
32
|
end
|
31
33
|
|
32
34
|
Each monitor is given a human-readable description for use in user interfaces, and one or more attributes that describe which nodes should be monitored, how they should be monitored, and how often the monitor should be run.
|
33
35
|
|
34
36
|
### Monitor Attributes
|
35
37
|
|
38
|
+
#### key
|
39
|
+
|
40
|
+
Declare a namespace for the monitor. The error status for a node is keyed by this value, so that monitors with different keys don't clear each other's errors.
|
41
|
+
|
42
|
+
This attribute is mandatory.
|
43
|
+
|
44
|
+
#### description
|
45
|
+
|
46
|
+
Set a human-readable description for the monitor, for use in interfaces or logs.
|
47
|
+
|
48
|
+
This attribute is mandatory.
|
49
|
+
|
36
50
|
#### every( seconds )
|
37
51
|
|
38
52
|
Declare the interval between runs of the monitor. The monitor will be skewed by a small amount from this value (unless you specify `splay 0`) to prevent many monitors from starting up simultaneously.
|
@@ -45,7 +59,7 @@ Manually set the amount of splay (random offset from the interval) the monitor s
|
|
45
59
|
#### exec {|node_attributes| ... }
|
46
60
|
#### exec( module )
|
47
61
|
|
48
|
-
Specify what should be run to do the actual monitoring. The first form simply `spawn`s the specified command with its STDIN opened to a stream of serialized node data.
|
62
|
+
Specify what should be run to do the actual monitoring. The first form simply `spawn`s the specified command with its STDIN opened to a stream of serialized node data.
|
49
63
|
|
50
64
|
By default, the format of the serialized nodes is one node per line, and each line looks like this:
|
51
65
|
|
data/Rakefile
CHANGED
@@ -16,7 +16,7 @@ Hoe.plugin :signing
|
|
16
16
|
Hoe.plugin :deveiate
|
17
17
|
|
18
18
|
Hoe.plugins.delete :rubyforge
|
19
|
-
|
19
|
+
|
20
20
|
|
21
21
|
hoespec = Hoe.spec 'arborist' do |spec|
|
22
22
|
spec.readme_file = 'README.md'
|
@@ -34,8 +34,8 @@ hoespec = Hoe.spec 'arborist' do |spec|
|
|
34
34
|
spec.developer 'Mahlon E. Smith', 'mahlon@martini.nu'
|
35
35
|
|
36
36
|
spec.dependency 'schedulability', '~> 0.1'
|
37
|
-
spec.dependency 'loggability', '~> 0.
|
38
|
-
spec.dependency 'configurability', '~>
|
37
|
+
spec.dependency 'loggability', '~> 0.12'
|
38
|
+
spec.dependency 'configurability', '~> 3.0'
|
39
39
|
spec.dependency 'pluggability', '~> 0.4'
|
40
40
|
spec.dependency 'state_machines', '~> 0.2'
|
41
41
|
spec.dependency 'msgpack', '~> 0.6'
|
data/TODO.md
CHANGED
data/lib/arborist.rb
CHANGED
@@ -14,10 +14,10 @@ module Arborist
|
|
14
14
|
Configurability
|
15
15
|
|
16
16
|
# Package version
|
17
|
-
VERSION = '0.0
|
17
|
+
VERSION = '0.1.0'
|
18
18
|
|
19
19
|
# Version control revision
|
20
|
-
REVISION = %q$Revision:
|
20
|
+
REVISION = %q$Revision: 02a11882f53b $
|
21
21
|
|
22
22
|
|
23
23
|
# The name of the environment variable which can be used to set the config path
|
data/lib/arborist/client.rb
CHANGED
@@ -92,8 +92,8 @@ class Arborist::Client
|
|
92
92
|
|
93
93
|
|
94
94
|
### Return the manager's current node tree.
|
95
|
-
def list(
|
96
|
-
request = self.make_list_request(
|
95
|
+
def list( **args )
|
96
|
+
request = self.make_list_request( **args )
|
97
97
|
return self.send_tree_api_request( request )
|
98
98
|
end
|
99
99
|
|
@@ -110,8 +110,8 @@ class Arborist::Client
|
|
110
110
|
|
111
111
|
|
112
112
|
### Return the manager's current node tree.
|
113
|
-
def fetch( criteria={},
|
114
|
-
request = self.make_fetch_request( criteria,
|
113
|
+
def fetch( criteria={}, **args )
|
114
|
+
request = self.make_fetch_request( criteria, **args )
|
115
115
|
return self.send_tree_api_request( request )
|
116
116
|
end
|
117
117
|
|
@@ -141,8 +141,8 @@ class Arborist::Client
|
|
141
141
|
|
142
142
|
|
143
143
|
### Add a subscription
|
144
|
-
def subscribe(
|
145
|
-
request = self.make_subscribe_request(
|
144
|
+
def subscribe( **args )
|
145
|
+
request = self.make_subscribe_request( **args )
|
146
146
|
response = self.send_tree_api_request( request )
|
147
147
|
return response.first
|
148
148
|
end
|
@@ -96,12 +96,12 @@ module Arborist::CLI::Watch
|
|
96
96
|
|
97
97
|
case event_type
|
98
98
|
when 'node.update'
|
99
|
-
type, status,
|
99
|
+
type, status, errors = event['data'].values_at( *%w'type status errors' )
|
100
100
|
return "%s updated: %s is %s%s" % [
|
101
101
|
hl( id ).color( :cyan ),
|
102
102
|
type,
|
103
103
|
hl( status ).color( status.to_sym ),
|
104
|
-
|
104
|
+
errors ? " (#{errors})" : ''
|
105
105
|
]
|
106
106
|
when 'node.delta'
|
107
107
|
pairs = diff_pairs( event['data'] )
|
data/lib/arborist/manager.rb
CHANGED
@@ -639,9 +639,7 @@ class Arborist::Manager
|
|
639
639
|
### Yield each node that is not down to the specified +block+, or return
|
640
640
|
### an Enumerator if no block is given.
|
641
641
|
def reachable_nodes( &block )
|
642
|
-
iter = self.enumerator_for( self.root )
|
643
|
-
!(node.down? || node.disabled? || node.quieted?)
|
644
|
-
end
|
642
|
+
iter = self.enumerator_for( self.root ) {|node| node.reachable? }
|
645
643
|
return iter.each( &block ) if block
|
646
644
|
return iter
|
647
645
|
end
|
data/lib/arborist/mixins.rb
CHANGED
@@ -326,7 +326,7 @@ module Arborist
|
|
326
326
|
alias_method :internify_keys, :symbolify_keys
|
327
327
|
|
328
328
|
|
329
|
-
|
329
|
+
### Recursive hash-merge function
|
330
330
|
def merge_recursively( key, oldval, newval )
|
331
331
|
case oldval
|
332
332
|
when Hash
|
@@ -351,7 +351,7 @@ module Arborist
|
|
351
351
|
end
|
352
352
|
|
353
353
|
|
354
|
-
|
354
|
+
### Recursively remove hash pairs in place whose value is nil.
|
355
355
|
def compact_hash( hash )
|
356
356
|
hash.each_key do |k|
|
357
357
|
hash.delete( k ) if hash[ k ].nil?
|
data/lib/arborist/monitor.rb
CHANGED
@@ -35,8 +35,8 @@ class Arborist::Monitor
|
|
35
35
|
DEFAULT_SPLAY = 0
|
36
36
|
|
37
37
|
|
38
|
-
Arborist.add_dsl_constructor( self ) do |description, &block|
|
39
|
-
Arborist::Monitor.new( description, &block )
|
38
|
+
Arborist.add_dsl_constructor( self ) do |description=nil, key=nil, &block|
|
39
|
+
Arborist::Monitor.new( description, key, &block )
|
40
40
|
end
|
41
41
|
|
42
42
|
|
@@ -143,7 +143,8 @@ class Arborist::Monitor
|
|
143
143
|
### Create a new Monitor with the specified +description+. If the +block+ is
|
144
144
|
### given, it will be evaluated in the context of the new Monitor before it's
|
145
145
|
### returned.
|
146
|
-
def initialize( description, &block )
|
146
|
+
def initialize( description=nil, key=nil, &block )
|
147
|
+
@key = key
|
147
148
|
@description = description
|
148
149
|
@interval = DEFAULT_INTERVAL
|
149
150
|
@splay = DEFAULT_SPLAY
|
@@ -160,6 +161,8 @@ class Arborist::Monitor
|
|
160
161
|
@source = nil
|
161
162
|
|
162
163
|
self.instance_exec( &block ) if block
|
164
|
+
|
165
|
+
self.check_config
|
163
166
|
end
|
164
167
|
|
165
168
|
|
@@ -168,8 +171,13 @@ class Arborist::Monitor
|
|
168
171
|
######
|
169
172
|
|
170
173
|
##
|
171
|
-
# The
|
172
|
-
|
174
|
+
# The monitor's key. This key should be shared between monitors that check the
|
175
|
+
# same resources.
|
176
|
+
attr_writer :key
|
177
|
+
|
178
|
+
##
|
179
|
+
# The monitor's (human) description.
|
180
|
+
attr_writer :description
|
173
181
|
|
174
182
|
##
|
175
183
|
# The interval between runs in seconds, as set by `every`.
|
@@ -226,6 +234,26 @@ class Arborist::Monitor
|
|
226
234
|
end
|
227
235
|
|
228
236
|
|
237
|
+
### Check the monitor for sanity, raising an Arborist::ConfigError if it isn't.
|
238
|
+
def check_config
|
239
|
+
raise Arborist::ConfigError, "No description set" unless self.description
|
240
|
+
raise Arborist::ConfigError, "No key set" unless self.key
|
241
|
+
end
|
242
|
+
|
243
|
+
|
244
|
+
### Get/set the description of the monitor.
|
245
|
+
def description( new_value=nil )
|
246
|
+
self.description = new_value if new_value
|
247
|
+
return @description
|
248
|
+
end
|
249
|
+
|
250
|
+
|
251
|
+
### Get/set the key used by the monitor.
|
252
|
+
def key( new_value=nil )
|
253
|
+
self.key = new_value if new_value
|
254
|
+
return @key
|
255
|
+
end
|
256
|
+
|
229
257
|
### Run the monitor
|
230
258
|
def run( nodes )
|
231
259
|
if self.exec_block
|
@@ -252,10 +280,10 @@ class Arborist::Monitor
|
|
252
280
|
parent_err_reader, child_stderr = IO.pipe
|
253
281
|
|
254
282
|
self.log.debug "Spawning command: %s" % [ Shellwords.join(command) ]
|
255
|
-
|
283
|
+
pid = Process.spawn( *command, out: child_stdout, in: child_stdin, err: child_stderr )
|
256
284
|
|
257
|
-
|
258
|
-
|
285
|
+
child_stdout.close
|
286
|
+
child_stdin.close
|
259
287
|
child_stderr.close
|
260
288
|
|
261
289
|
context.exec_input( nodes, parent_writer )
|
@@ -302,6 +330,8 @@ class Arborist::Monitor
|
|
302
330
|
### for nodes it will run against.
|
303
331
|
def match( criteria )
|
304
332
|
self.positive_criteria.merge!( criteria )
|
333
|
+
@include_down = !self.include_down &&
|
334
|
+
Arborist::Node::UNREACHABLE_STATES.include?( self.positive_criteria[:status] )
|
305
335
|
end
|
306
336
|
|
307
337
|
|
@@ -69,6 +69,12 @@ class Arborist::MonitorRunner
|
|
69
69
|
|
70
70
|
self.fetch( positive, include_down, props, negative ) do |nodes|
|
71
71
|
results = monitor.run( nodes )
|
72
|
+
monitor_key = monitor.key
|
73
|
+
|
74
|
+
results.each do |ident, properties|
|
75
|
+
properties['_monitor_key'] = monitor_key
|
76
|
+
end
|
77
|
+
|
72
78
|
self.update( results ) do
|
73
79
|
self.log.debug "Updated %d via the '%s' monitor" %
|
74
80
|
[ results.length, monitor.description ]
|
data/lib/arborist/node.rb
CHANGED
@@ -44,11 +44,19 @@ class Arborist::Node
|
|
44
44
|
status_changed
|
45
45
|
last_contacted
|
46
46
|
ack
|
47
|
-
|
47
|
+
errors
|
48
48
|
quieted_reasons
|
49
49
|
config
|
50
50
|
]
|
51
51
|
|
52
|
+
# Node states that are unreachable by default.
|
53
|
+
UNREACHABLE_STATES = %w[
|
54
|
+
down
|
55
|
+
disabled
|
56
|
+
quieted
|
57
|
+
]
|
58
|
+
|
59
|
+
|
52
60
|
autoload :Root, 'arborist/node/root'
|
53
61
|
autoload :Ack, 'arborist/node/ack'
|
54
62
|
|
@@ -114,8 +122,8 @@ class Arborist::Node
|
|
114
122
|
|
115
123
|
event :update do
|
116
124
|
transition [:up, :unknown] => :disabled, if: :ack_set?
|
117
|
-
transition [:down, :unknown, :acked] => :up,
|
118
|
-
transition [:up, :unknown] => :down,
|
125
|
+
transition [:down, :unknown, :acked] => :up, unless: :has_errors?
|
126
|
+
transition [:up, :unknown, :acked] => :down, if: :has_errors?
|
119
127
|
transition :down => :acked, if: :ack_set?
|
120
128
|
transition :disabled => :unknown, unless: :ack_set?
|
121
129
|
end
|
@@ -274,7 +282,7 @@ class Arborist::Node
|
|
274
282
|
@status_changed = Time.at( 0 )
|
275
283
|
|
276
284
|
# Attributes that govern state
|
277
|
-
@
|
285
|
+
@errors = {}
|
278
286
|
@ack = nil
|
279
287
|
@last_contacted = Time.at( 0 )
|
280
288
|
@quieted_reasons = {}
|
@@ -321,8 +329,9 @@ class Arborist::Node
|
|
321
329
|
attr_accessor :status_changed
|
322
330
|
|
323
331
|
##
|
324
|
-
# The last
|
325
|
-
|
332
|
+
# The Hash of last errors encountered by a monitor attempting to update this
|
333
|
+
# node, keyed by the monitor's `key`.
|
334
|
+
attr_accessor :errors
|
326
335
|
|
327
336
|
##
|
328
337
|
# The acknowledgement currently in effect. Should be an instance of Arborist::Node::ACK
|
@@ -478,13 +487,17 @@ class Arborist::Node
|
|
478
487
|
### Update specified +properties+ for the node.
|
479
488
|
def update( new_properties )
|
480
489
|
new_properties = stringify_keys( new_properties )
|
481
|
-
|
490
|
+
monitor_key = new_properties[ '_monitor_key' ] || '_'
|
482
491
|
|
492
|
+
self.log.debug "Updated via a %s monitor: %p" % [ monitor_key, new_properties ]
|
483
493
|
self.last_contacted = Time.now
|
494
|
+
|
484
495
|
if new_properties.key?( 'ack' )
|
485
496
|
self.ack = new_properties.delete( 'ack' )
|
497
|
+
elsif new_properties['error']
|
498
|
+
self.errors[ monitor_key ] = new_properties.delete( 'error' )
|
486
499
|
else
|
487
|
-
self.
|
500
|
+
self.errors.delete( monitor_key )
|
488
501
|
end
|
489
502
|
|
490
503
|
self.properties.merge!( new_properties, &self.method(:merge_and_record_delta) )
|
@@ -587,6 +600,8 @@ class Arborist::Node
|
|
587
600
|
when 'type'
|
588
601
|
self.log.debug "Checking node type %p against %p" % [ self.type, val ]
|
589
602
|
self.type == val
|
603
|
+
when 'parent'
|
604
|
+
self.parent == val
|
590
605
|
when 'tag' then @tags.include?( val.to_s )
|
591
606
|
when 'tags' then Array(val).all? {|tag| @tags.include?(tag) }
|
592
607
|
when 'identifier' then @identifier == val
|
@@ -680,7 +695,8 @@ class Arborist::Node
|
|
680
695
|
|
681
696
|
super # to state-machine
|
682
697
|
|
683
|
-
|
698
|
+
self.publish_events( event, *self.pending_update_events )
|
699
|
+
self.collect_events
|
684
700
|
end
|
685
701
|
|
686
702
|
|
@@ -792,6 +808,20 @@ class Arborist::Node
|
|
792
808
|
end
|
793
809
|
|
794
810
|
|
811
|
+
### Returns +true+ if the node's status indicates it shouldn't be
|
812
|
+
### included by default when traversing nodes.
|
813
|
+
def unreachable?
|
814
|
+
return UNREACHABLE_STATES.include?( self.status )
|
815
|
+
end
|
816
|
+
|
817
|
+
|
818
|
+
### Returns +true+ if the node's status indicates it is included by
|
819
|
+
### default when traversing nodes.
|
820
|
+
def reachable?
|
821
|
+
return !self.unreachable?
|
822
|
+
end
|
823
|
+
|
824
|
+
|
795
825
|
### Register the specified +node+ as a child of this node, replacing any existing
|
796
826
|
### node with the same identifier.
|
797
827
|
def add_child( node )
|
@@ -880,7 +910,7 @@ class Arborist::Node
|
|
880
910
|
@ack = old_node.ack.dup if old_node.ack
|
881
911
|
@last_contacted = old_node.last_contacted
|
882
912
|
@status_changed = old_node.status_changed
|
883
|
-
@
|
913
|
+
@errors = old_node.errors
|
884
914
|
@quieted_reasons = old_node.quieted_reasons
|
885
915
|
|
886
916
|
# Only merge in downed dependencies.
|
@@ -904,7 +934,7 @@ class Arborist::Node
|
|
904
934
|
ack: self.ack ? self.ack.to_h : nil,
|
905
935
|
last_contacted: self.last_contacted ? self.last_contacted.iso8601 : nil,
|
906
936
|
status_changed: self.status_changed ? self.status_changed.iso8601 : nil,
|
907
|
-
|
937
|
+
errors: self.errors,
|
908
938
|
dependencies: self.dependencies.to_h,
|
909
939
|
quieted_reasons: self.quieted_reasons,
|
910
940
|
}
|
@@ -934,7 +964,7 @@ class Arborist::Node
|
|
934
964
|
@status_changed = Time.parse( hash[:status_changed] )
|
935
965
|
@ack = Arborist::Node::Ack.from_hash( hash[:ack] ) if hash[:ack]
|
936
966
|
|
937
|
-
@
|
967
|
+
@errors = hash[:errors]
|
938
968
|
@properties = hash[:properties] || {}
|
939
969
|
@last_contacted = Time.parse( hash[:last_contacted] )
|
940
970
|
@quieted_reasons = hash[:quieted_reasons] || {}
|
@@ -988,13 +1018,23 @@ class Arborist::Node
|
|
988
1018
|
|
989
1019
|
### State machine guard predicate -- Returns +true+ if the last time the node
|
990
1020
|
### was monitored resulted in an update.
|
991
|
-
def
|
992
|
-
self.
|
993
|
-
|
994
|
-
|
1021
|
+
def has_errors?
|
1022
|
+
has_errors = ! self.errors.empty?
|
1023
|
+
self.log.debug "Checking to see if last contact cleared remaining errors (it %s)" %
|
1024
|
+
[ has_errors ? "did not" : "did" ]
|
1025
|
+
self.log.debug "Errors are: %p" % [ self.errors ]
|
1026
|
+
return has_errors
|
995
1027
|
end
|
996
1028
|
|
997
1029
|
|
1030
|
+
### Return a string describing the errors that are set on the node.
|
1031
|
+
def errors_description
|
1032
|
+
return "No errors" if self.errors.empty?
|
1033
|
+
return self.errors.map do |key, msg|
|
1034
|
+
"%s: %s" % [ key, msg ]
|
1035
|
+
end.join( '; ' )
|
1036
|
+
end
|
1037
|
+
|
998
1038
|
#
|
999
1039
|
# :section: State Callbacks
|
1000
1040
|
#
|
@@ -1035,7 +1075,7 @@ class Arborist::Node
|
|
1035
1075
|
|
1036
1076
|
### Callback for when a node goes from down to up
|
1037
1077
|
def on_node_up( transition )
|
1038
|
-
self.
|
1078
|
+
self.errors.clear
|
1039
1079
|
self.log.warn "%s is %s" % [ self.identifier, self.status_description ]
|
1040
1080
|
end
|
1041
1081
|
|
@@ -1043,7 +1083,7 @@ class Arborist::Node
|
|
1043
1083
|
### Callback for when a node goes from up to down
|
1044
1084
|
def on_node_down( transition )
|
1045
1085
|
self.log.error "%s is %s" % [ self.identifier, self.status_description ]
|
1046
|
-
self.update_delta[ '
|
1086
|
+
self.update_delta[ 'errors' ] = [ nil, self.errors_description ]
|
1047
1087
|
end
|
1048
1088
|
|
1049
1089
|
|