lib/arborist/node.rb in arborist-0.4.0 vs lib/arborist/node.rb in arborist-0.5.0
- old
+ new
@@ -37,10 +37,11 @@
VALID_IDENTIFIER = /^\w[\w\-]*$/
# The attributes of a node which are used in the operation of the system
OPERATIONAL_ATTRIBUTES = %i[
type
+ family
status
tags
parent
description
dependencies
@@ -442,10 +443,17 @@
def source=( source )
@source = URI( source )
end
+ ### Return the node family, so observers can know ancestry after
+ ### serialization for custom node types that inherit from this class.
+ def family
+ return :node
+ end
+
+
### Set one or more node +attributes+. This should be overridden by subclasses which
### wish to allow their operational attributes to be set/updated via the Tree API
### (+modify+ and +graft+). Supported attributes are: +parent+, +description+,
### +tags+, and +config+.
def modify( attributes )
@@ -620,15 +628,53 @@
self.log.debug "Updated via a %s monitor: %p" % [ monitor_key, new_properties ]
self.update_errors( monitor_key, new_properties.delete('error') )
self.update_warnings( monitor_key, new_properties.delete('warning') )
- self.properties.merge!( new_properties, &self.method(:merge_and_record_delta) )
- compact_hash( self.properties )
+ self.merge_new_properties( new_properties )
end
+ ### Merge the specified Hash of +new_properties+ with the node's current property
+ ### Hash.
+ def merge_new_properties( new_properties )
+ props = self.properties.dup
+ updated_properties, properties_delta = self.merge_and_record_delta( props, new_properties )
+
+ compact_hash( updated_properties )
+ self.properties.replace( updated_properties )
+
+ self.update_delta['properties'] = properties_delta unless properties_delta.empty?
+ end
+
+
+ ### Merge the specified +newval+ into the node's properties at the given +key+, recording
+ ### each change in the node's #update_delta if the +oldval+ is different.
+ def merge_and_record_delta( properties, new_properties )
+ delta = {}
+ new_properties.each_key do |key|
+ newval = new_properties[ key ]
+ oldval = properties[ key ]
+ subdelta = nil
+
+ # Merge them (recursively) if they're both merge-able
+ if oldval.respond_to?( :merge! ) && newval.respond_to?( :merge! )
+ newval, subdelta = self.merge_and_record_delta( oldval, newval )
+
+ # Otherwise just directly compare them and record any changes
+ elsif oldval != newval
+ subdelta = [ oldval, newval ]
+ end
+
+ properties[ key ] = newval
+ delta[ key ] = subdelta if subdelta
+ end
+
+ return properties, delta
+ end
+
+
### Update the errors hash for the specified +monitor_key+ to +value+.
def update_errors( monitor_key, value=nil )
if value
self.errors[ monitor_key ] = value
else
@@ -681,39 +727,10 @@
ensure
self.clear_transition_temp_vars
end
- ### Merge the specified +new_properties+ into the node's properties, recording
- ### each change in the node's #update_delta.
- def merge_and_record_delta( key, oldval, newval, prefixes=[] )
- self.log.debug "Merging property %s: %p -> %p" % [
- (prefixes + [key]).join('.'),
- oldval,
- newval
- ]
-
- # Merge them (recursively) if they're both merge-able
- if oldval.respond_to?( :merge! ) && newval.respond_to?( :merge! )
- return oldval.merge( newval ) do |ikey, ioldval, inewval|
- self.merge_and_record_delta( ikey, ioldval, inewval, prefixes + [key] )
- end
-
- # Otherwise just directly compare them and record any changes
- else
- unless oldval == newval
- prefixed_delta = prefixes.inject( self.update_delta ) do |hash, key|
- hash[ key ]
- end
- prefixed_delta[ key ] = [ oldval, newval ]
- end
-
- return newval
- end
- end
-
-
### Clear out the state used during a transition to track changes.
def clear_transition_temp_vars
self.previous_ack = nil
self.update_delta.clear
self.pending_change_events.clear
@@ -763,10 +780,12 @@
return case key
when 'status'
array_val.include?( self.status )
when 'type'
array_val.include?( self.type )
+ when 'family'
+ array_val.include?( self.family.to_s )
when 'parent'
array_val.include?( self.parent )
when 'tag' then @tags.include?( val.to_s )
when 'tags' then array_val.all? {|tag| @tags.include?(tag) }
when 'identifier'
@@ -834,11 +853,11 @@
### Send an event to this node's immediate children.
def broadcast_events( *events )
events.flatten!
results = self.children.flat_map do |identifier, child|
- self.log.debug "Broadcasting %d events to %p" % [ events.length, identifier ]
+ self.log.debug "Broadcasting events to %p: %p" % [ identifier, events ]
events.flat_map do |event|
child.handle_event( event )
end
end
@@ -847,32 +866,32 @@
### Handle the specified +event+, delivered either via broadcast or secondary
### dependency subscription.
def handle_event( event )
- self.log.debug "Handling %p" % [ event ]
+ self.log.debug "Handling event %p" % [ event ]
handler_name = "handle_%s_event" % [ event.type.gsub('.', '_') ]
if self.respond_to?( handler_name )
self.log.debug "Handling a %s event." % [ event.type ]
self.method( handler_name ).call( event )
else
self.log.debug "No handler for a %s event!" % [ event.type ]
end
# Don't transition on informational events
- return if event.informational?
+ return [] if event.informational?
super # to state-machine
results = self.pending_change_events.clone
self.log.debug ">>> Pending change events after: %p" % [ results ]
results << self.make_delta_event unless self.update_delta.empty?
child_results = self.broadcast_events( *results )
results.concat( child_results )
- self.publish_events( *results )
+ self.publish_events( *results ) unless results.empty?
return results
ensure
self.clear_transition_temp_vars
end
@@ -1104,11 +1123,10 @@
@properties = old_node.properties.dup
@ack = old_node.ack.dup if old_node.ack
@last_contacted = old_node.last_contacted
@status_changed = old_node.status_changed
@status_history = old_node.status_history
- @status_history_size = old_node.status_history_size
@flapping = old_node.flapping?
@errors = old_node.errors
@warnings = old_node.warnings
@quieted_reasons = old_node.quieted_reasons
@status_last_changed = old_node.status_last_changed
@@ -1126,21 +1144,21 @@
def to_h( depth: 0 )
hash = {
identifier: self.identifier,
type: self.class.name.to_s.sub( /.+::/, '' ).downcase,
parent: self.parent,
+ family: self.family,
description: self.description,
tags: self.tags,
config: self.config,
status: self.status,
properties: self.properties.dup,
ack: self.ack ? self.ack.to_h : nil,
last_contacted: self.last_contacted ? self.last_contacted.iso8601 : nil,
status_changed: self.status_changed ? self.status_changed.iso8601 : nil,
status_last_changed: self.status_last_changed ? self.status_last_changed.iso8601 : nil,
status_history: self.status_history,
- status_history_size: self.status_history_size,
flapping: self.flapping?,
errors: self.errors,
warnings: self.warnings,
dependencies: self.dependencies.to_h,
quieted_reasons: self.quieted_reasons,
@@ -1180,11 +1198,10 @@
@status = hash[:status]
@status_changed = Time.parse( hash[:status_changed] )
@status_last_changed = Time.parse( hash[:status_last_changed] )
@status_history = hash[:status_history]
- @status_history_size = hash[:status_history_size]
@flapping = hash[:flapping]
@ack = Arborist::Node::Ack.from_hash( hash[:ack] ) if hash[:ack]
@errors = hash[:errors]
@warnings = hash[:warnings]
@@ -1381,18 +1398,18 @@
### Callback for when a node goes from up to down
def on_node_down( transition )
self.log.error "%s is %s" % [ self.identifier, self.status_description ]
- self.update_delta[ 'errors' ] = [ nil, self.errors_description ]
+ self.update_delta[ 'errors' ] = [ nil, self.errors ]
end
### Callback for when a node goes from up to warn
def on_node_warn( transition )
self.log.error "%s is %s" % [ self.identifier, self.status_description ]
- self.update_delta[ 'warnings' ] = [ nil, self.warnings_description ]
+ self.update_delta[ 'warnings' ] = [ nil, self.warnings ]
end
### Callback for when a node goes from up to disabled
def on_node_disabled( transition )
@@ -1435,10 +1452,10 @@
end
### Retain the status in the node's history.
###
- def record_status_history
+ def record_status_history( transition )
retain = self.status_history_size
return if retain.zero?
pre_state = self.flapping?
self.status_history << self.status