lib/arborist/node.rb in arborist-0.0.1.pre20160106113421 vs lib/arborist/node.rb in arborist-0.0.1.pre20160128152542
- old
+ new
@@ -27,15 +27,11 @@
##
# The key for the thread local that is used to track instances as they're
# loaded.
LOADED_INSTANCE_KEY = :loaded_node_instances
- ##
- # The glob pattern to use for searching for node
- NODE_FILE_PATTERN = '**/*.rb'
-
##
# The struct for the 'ack' operational property
ACK = Struct.new( 'ArboristNodeACK', :message, :via, :sender, :time )
##
@@ -55,23 +51,30 @@
state_machine( :status, initial: :unknown ) do
state :unknown,
:up,
:down,
- :acked
+ :acked,
+ :disabled
event :update do
- transition any - [:acked] => :acked, if: :ack_set?
- transition any - [:up] => :up, if: :last_contact_successful?
- transition any - [:down, :acked] => :down, unless: :last_contact_successful?
+ transition [:down, :unknown, :acked] => :up, if: :last_contact_successful?
+ transition [:up, :unknown] => :down, unless: :last_contact_successful?
+ transition :down => :acked, if: :ack_set?
+ transition [:unknown, :up] => :disabled, if: :ack_set?
+ transition :disabled => :unknown, unless: :ack_set?
end
after_transition any => :acked, do: :on_ack
after_transition :acked => :up, do: :on_ack_cleared
after_transition :down => :up, do: :on_node_up
after_transition [:unknown, :up] => :down, do: :on_node_down
+ after_transition [:unknown, :up] => :disabled, do: :on_node_disabled
+ after_transition :disabled => :unknown, do: :on_node_enabled
+ after_transition any => any, do: :log_transition
+
after_transition do: :add_status_to_update_delta
end
### Return a curried Proc for the ::create method for the specified +type+.
@@ -98,10 +101,12 @@
### Record a new loaded instance if the Thread-local variable is set up to track
### them.
def self::add_loaded_instance( new_instance )
instances = Thread.current[ LOADED_INSTANCE_KEY ] or return
+ self.log.debug "Adding new instance %p to loaded instances %p" %
+ [ new_instance, instances ]
instances << new_instance
end
### Inheritance hook -- add a DSL declarative function for the given +subclass+.
@@ -135,28 +140,13 @@
ensure
Thread.current[ LOADED_INSTANCE_KEY ] = nil
end
- ### Return an iterator for all the node files in the specified +directory+.
- def self::each_in( directory )
- path = Pathname( directory )
- paths = if path.directory?
- Pathname.glob( directory + NODE_FILE_PATTERN )
- else
- [ path ]
- end
-
- return paths.flat_map do |file|
- file_url = "file://%s" % [ file.expand_path ]
- nodes = self.load( file )
- self.log.debug "Loaded nodes %p..." % [ nodes ]
- nodes.each do |node|
- node.source = file_url
- end
- nodes
- end
+ ### Return an iterator for all the nodes supplied by the specified +loader+.
+ def self::each_in( loader )
+ return loader.nodes
end
### Create a new Node with the specified +identifier+, which must be unique to the
### loaded tree.
@@ -321,12 +311,15 @@
def update( new_properties )
new_properties = stringify_keys( new_properties )
self.log.debug "Updated: %p" % [ new_properties ]
self.last_contacted = Time.now
- self.error = new_properties.delete( 'error' )
- self.ack = new_properties.delete( 'ack' ) if new_properties.key?( 'ack' )
+ if new_properties.key?( 'ack' )
+ self.ack = new_properties.delete( 'ack' )
+ else
+ self.error = new_properties.delete( 'error' )
+ end
self.properties.merge!( new_properties, &self.method(:merge_and_record_delta) )
compact_hash( self.properties )
# Super to the state machine event method
@@ -502,10 +495,12 @@
case self.status
when 'up', 'down'
return "%s as of %s" % [ self.status.upcase, self.last_contacted ]
when 'acked'
return "ACKed by %s %s" % [ self.ack.sender, self.ack.time.as_delta ]
+ when 'disabled'
+ return "disabled by %s %s" % [ self.ack.sender, self.ack.time.as_delta ]
else
return "in an unknown state"
end
end
@@ -605,21 +600,25 @@
protected
#########
### Ack the node with the specified +ack_data+, which should contain
def ack=( ack_data )
- self.log.debug "ACKed with data: %p" % [ ack_data ]
+ if ack_data
+ self.log.info "Node %s ACKed with data: %p" % [ self.identifier, ack_data ]
+ ack_data['time'] ||= Time.now
+ ack_values = ack_data.values_at( *Arborist::Node::ACK.members.map(&:to_s) )
+ new_ack = Arborist::Node::ACK.new( *ack_values )
- ack_data['time'] ||= Time.now
- ack_values = ack_data.values_at( *Arborist::Node::ACK.members.map(&:to_s) )
- new_ack = Arborist::Node::ACK.new( *ack_values )
+ if missing = ACK_REQUIRED_PROPERTIES.find {|prop| new_ack[prop].nil? }
+ raise "Missing required ACK attribute %s" % [ missing ]
+ end
- if missing = ACK_REQUIRED_PROPERTIES.find {|prop| new_ack[prop].nil? }
- raise "Missing required ACK attribute %s" % [ missing ]
+ @ack = new_ack
+ else
+ self.log.info "Node %s ACK cleared explicitly" % [ self.identifier ]
+ @ack = nil
end
-
- @ack = new_ack
end
### State machine guard predicate -- Returns +true+ if the node has an ACK status set.
def ack_set?
@@ -640,33 +639,54 @@
#
# :section: State Callbacks
#
+ ### Log every status transition
+ def log_transition( transition )
+ self.log.debug "Transitioned %s from %s to %s" %
+ [ self.identifier, transition.from, transition.to ]
+ end
+
+
### Callback for when an acknowledgement is set.
def on_ack( transition )
self.log.warn "ACKed: %s" % [ self.status_description ]
self.pending_update_events <<
Arborist::Event.create( 'node_acked', self.fetch_values, self.ack.to_h )
end
### Callback for when an acknowledgement is cleared.
def on_ack_cleared( transition )
+ self.error = nil
self.log.warn "ACK cleared for %s" % [ self.identifier ]
end
### Callback for when a node goes from down to up
def on_node_up( transition )
+ self.error = nil
self.log.warn "%s is %s" % [ self.identifier, self.status_description ]
end
### 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[ 'error' ] = [ nil, self.error ]
+ end
+
+
+ ### Callback for when a node goes from up to disabled
+ def on_node_disabled( transition )
+ self.log.warn "%s is %s" % [ self.identifier, self.status_description ]
+ end
+
+
+ ### Callback for when a node goes from disabled to unknown
+ def on_node_enabled( transition )
+ self.log.warn "%s is %s" % [ self.identifier, self.status_description ]
end
### Add the transition from one state to another to the data used to build
### deltas for the #update event.