Ravn::Tactical::
Change
class
Compute pack change queue item class.
Instances of this class are changes that should be applied to nodes in a kit. It specifies an Operation (the name of a Ravn::Tactical::Operation
), a Node (Ravn::Tactical::Node
), and a (potentially nil) set of options to pass to the Operation.
- config RW
The Hash of configuration options the Operation uses when it runs.
- created_at RW
The timestamp when the Change
was created
- id RW
The unique ID of the change
- node RW
The Ravn::Tactical::Node
this change applies to
- node_id RW
The ID of the node the Change
will be run on
- type RW
The name of the Ravn::Tactical::Operation
that will be run for this change
create_for_all_nodes( type, include_local: false, **config, &block )
Create a new Change
for all undeleted Nodes in the current Kit of the specified type
and config
.
118 def self::create_for_all_nodes( type, include_local: false, **config, &block )
119 nodes = Ravn::Tactical::Node.undeleted
120 nodes = nodes.except_local unless include_local
121
122 return self.create_for_nodes( type, nodes, **config, &block )
123 end
create_for_nodes( type, nodes, **config, &block )
Create a new Change
for each of the given nodes
of the specified type
and config
.
106 def self::create_for_nodes( type, nodes, **config, &block )
107
108 self.db.transaction do
109 return Array( nodes ).flatten.map do |node|
110 self.create( type:, node:, config:, &block )
111 end
112 end
113 end
Set up some instance variables on creation.
131 def initialize( ... )
132 super
133
134 @config = nil
135 end
Group the dataset by node.
69 def by_node
70 return self.group( :node )
71 end
Set the config options for the Operation.
184 def config=( new_config )
185 new_config = symbolify_keys( new_config )
186 return if new_config == self.config
187
188 @config = deep_freeze( new_config )
189
190 self.will_change_column( :config )
191 self[:config] = Yajl::Encoder.encode( @config )
192 end
Return a naked dataset that contains just the IDs of the latest change per node.
82 def earliest_changes
83 return self.select {
84 first_value( :id ).
85 over( partition: :node_id, order: :created_at ).
86 as( :id )
87 }.distinct.naked
88 end
Return a dataset that yields only the earliest Change
for each node.
92 def earliest_for_each_node
93 return self.with( :earliest_changes, self.earliest_changes ).
94 where( id: self.db[:earliest_changes].select(:id) )
95 end
Limit the dataset to entries for the given node
.
62 def for_nodes( *nodes )
63 return self.where( node: nodes.flatten )
64 end
Get a single config
value specified by key_path
.
221 def get_config( key_path )
222 keys = split_key_path( key_path )
223 return self.config.dig( *keys )
224 end
Ravn::Inspection API – Return the details of the change in a human-readable format suitable for debugging.
247 def inspect_details
248 return "[%d] %s operation on %s (%s), created: %s" % [
249 self.id || -1,
250 self.type,
251 self.node ? self.node.device_id : "an unspecified node",
252 self.config&.keys&.join(', '),
253 self.created_at ? self.created_at.rfc2822 : '-',
254 ]
255 end
Returns the dataset sorted by time of creation.
75 def older_first
76 return self.order( :created_at )
77 end
set_config( key_path, value )
Set a single config
value, marking the object as modified if the config was changed. This method will auto-vivify Hashes for any missing branches, but can also traverse Arrays (ala dig).
198 def set_config( key_path, value )
199 keys = split_key_path( key_path )
200 self.log.debug "Setting config %p: %p" % [ keys, value ]
201
202 changed_config = deep_copy( self.config )
203 leaf_branch = keys[ 0..-2 ].inject( changed_config ) do |section, idx|
204 if (subsection = section[idx])
205 self.log.debug " found existing subsection %p" % [ idx ]
206 subsection
207 else
208 self.log.debug " adding subsection %p" % [ idx ]
209 section[ idx ] = {}
210 end
211 end
212
213 self.log.debug " leaf branch is: %p" % [ leaf_branch ]
214 leaf_branch[ keys.last ] = value
215
216 self.config = changed_config
217 end
Sequel::Model API – Validate the object before saving.
228 def validate
229 super
230
231 self.validate_node
232 end
Ensure the associated node is present and valid.
236 def validate_node
237 if self.node
238 self.validate_associated_object( self.model.association_reflection(:node), self.node )
239 else
240 self.errors.add( :node, "is not set" )
241 end
242 end