Ravn::Tactical::

Kit module

Kit-level operations API

Constants

DEFAULT_HEADERS

Headers to add to every request

SERVICE_PATH

The base path of the infrastructure services

URI_PROTOCOL

The type of URI to use for requests

Public Class Methods

add_node( node )

Add a new node to the kit. Raises an exception on failure.

   # File lib/ravn/tactical/kit.rb
51 def self::add_node( node )
52     self.log.info "Requesting that %p consider this node its control." % [ node ]
53 
54     # Need an unfrozen copy to save
55     node = node.dup
56 
57     Ravn::Tactical::Node.db.transaction do
58         node.save
59         self.request( node, :put, '/kit/control', {device_id: Ravn.device_id} )
60     end
61 
62     return node
63 end
archive_mission( mission ) { || ... }

Archive the specified mission (which must be the current mission) across the whole kit. If a block is given, it is yielded to before resetting Helios and starting the download of the resulting archives.

    # File lib/ravn/tactical/kit.rb
220 def self::archive_mission( mission )
221     raise "Only the current mission may be archived." unless mission.current?
222 
223     self.log.info "Archiving mission %s" % [ mission.id ]
224 
225     mission.archive # Archive the Control's data.
226 
227     # If the Control is alone, we're done.
228     if mission.all_nodes_archived?
229         self.log.debug "Mission archive is already ready to be finished."
230         mission.finish_archive
231         Ravn::Executor.exec( :reset_helios )
232         return true
233     end
234 
235     mission.queue_change( :archive_mission, mission_id: mission.id )
236 
237     yield if block_given?
238 
239     Ravn::Executor.exec( :reset_helios )
240     mission.queue_change( :download_mission_archive, mission_id: mission.id )
241 
242     return true
243 end
create_mission( name, template: nil )

Create a new mission with the specified name for the current kit’s nodes, optionally using one of the template missions.

    # File lib/ravn/tactical/kit.rb
 84 def self::create_mission( name, template: nil )
 85     self.log.info "Creating a new mission %p%s" %
 86         [ name, template ? " using the #{template} template" : '' ]
 87 
 88 
 89     if template
 90         new_mission = Ravn::Tactical::Mission.fetch_template( template ) or
 91             raise "Couldn't fetch the %s template" % [ template ]
 92         new_mission.name = name
 93     else
 94         new_mission = Ravn::Tactical::Mission.create( name )
 95     end
 96 
 97     if Ravn::Tactical::BoltPackage.exists?
 98         package = Ravn::Tactical::BoltPackage.load
 99         new_mission.segments = package.role_segments_hash.merge( new_mission.segments )
100     end
101 
102     new_mission.callsigns = Ravn::Tactical::Node.callsigns_hash
103 
104     return new_mission
105 end
make_authorization_token( node, method, uri )

Return an authorization header value from the current node to the given node for the specified method and uri.

    # File lib/ravn/tactical/kit.rb
163 def self::make_authorization_token( node, method, uri )
164     control_data = uri.request_uri
165     req = "%s %s HTTP/1.0" % [ method.to_s.upcase, control_data ]
166     self.log.debug "req claim is: %p" % [ req ]
167     pubkey = node.public_key or raise "%p has no public key" % [ node ]
168     device_id = Ravn.device_id
169 
170     token = Ravn::Tactical::Auth.create_token( pubkey, req: )
171 
172     return "%s.%s" % [ device_id, token ]
173 end
make_mission_current( new_mission )

Make a new_mission the current one across the whole kit. If it’s already the current one, just update it.

    # File lib/ravn/tactical/kit.rb
209 def self::make_mission_current( new_mission )
210     self.log.info "Activating mission %s" % [ new_mission.id ]
211     new_mission.queue_change( :set_mission, mission: new_mission.fields )
212     new_mission.make_current unless new_mission.current?
213     Ravn::Executor.exec( :restart_helios )
214 end
purge_mission( mission )

Permanently remove a previously archived mission from disk.

    # File lib/ravn/tactical/kit.rb
247 def self::purge_mission( mission )
248     mission.archive_directory_path.rmtree
249     mission.filepath.unlink
250     return true
251 end
replace_mission( current_mission, new_mission )

Replace the current_mission with a new_mission across the whole kit.

    # File lib/ravn/tactical/kit.rb
198 def self::replace_mission( current_mission, new_mission )
199     self.log.info "Replacing mission %s" % [ current_mission.id ]
200     self.archive_mission( current_mission ) do
201         new_mission.make_current
202         new_mission.queue_change( :set_mission, mission: new_mission.fields )
203     end
204 end
request( node, method, resource, request_body=nil, headers: {} )

Build an HTTP request of the specified method and resource for the given node. If parameters are given, they will be encoded as JSON and sent as the request body. Returns the response if it’s successful, or raises a Ravn::Tactical::BackendError if the request fails.

    # File lib/ravn/tactical/kit.rb
116 def self::request( node, method, resource, request_body=nil, headers: {} )
117     uri = self.url_for( node, resource: )
118     self.log.debug "Creating a %s request for %s (node 0x%s)" %
119         [ method.to_s.upcase, uri, node.device_id ]
120 
121     headers = DEFAULT_HEADERS.merge( headers )
122     token = self.make_authorization_token( node, method, uri )
123     session = self.service_client.bearer_auth( token )
124 
125     self.log.debug "Requesting %s from %p" % [ uri, node ]
126     request = if request_body
127             session.build_request( method.to_s.upcase, uri, json: request_body )
128         else
129             session.build_request( method.to_s.upcase, uri )
130         end
131 
132     response = session.request( request )
133 
134     if (error = response.error)
135         self.log.error "Failed: %s (%p)" % [ error.message, error.class ]
136         raise Ravn::Tactical::BackendError, "%s request to <node %s>%s%s failed: %s (%d)" % [
137             method.to_s.upcase,
138             node.id,
139             SERVICE_PATH,
140             resource,
141             error.message,
142             error.status
143         ], error.backtrace
144     else
145         self.log.debug "Success: %p" % [ response ]
146         return response
147     end
148 end
reset()

Reset cached connections/sessions.

   # File lib/ravn/tactical/kit.rb
45 def self::reset
46     @service_client = nil
47 end
run_change( change )

Run the operation on the node indicated by the given change.

   # File lib/ravn/tactical/kit.rb
67 def self::run_change( change )
68     return self.run_operation( change.operation, change.node )
69 end
run_operation( operation, node )

Run the specified operation (a Ravn::Tactical::Operation) on the specified node via the infrastructure API and return the response (HTTPX::Response).

   # File lib/ravn/tactical/kit.rb
74 def self::run_operation( operation, node )
75     self.log.info "Running %p on %p." % [ operation, node ]
76     resource = "/operation/%s" % [ operation.type ]
77 
78     return self.request( node, :post, resource, operation.config )
79 end
service_client()

The Pathname of the infrastructure service

   # File lib/ravn/tactical/kit.rb
35 def self::service_client
36     return @service_client ||= HTTPX.
37         plugin( :auth ).
38         with( base_path: SERVICE_PATH ).
39         with( ssl: {verify_mode: OpenSSL::SSL::VERIFY_NONE} ).
40         accept( 'application/json' )
41 end
set_mission( new_mission )

Set the current mission to the mission with the specified mission_id, archiving any existing current mission.

    # File lib/ravn/tactical/kit.rb
182 def self::set_mission( new_mission )
183     current_mission = Ravn::Tactical::Mission.current
184 
185     self.log.info "Setting the mission to %p" % [ new_mission ]
186 
187     if current_mission && current_mission.id != new_mission.id
188         self.replace_mission( current_mission, new_mission )
189     else
190         self.make_mission_current( new_mission )
191     end
192 
193     return true
194 end
url_for( node, resource: KIT_RESOURCE )

Get a URL for accessing the specified resource of the infrastructure service of the specified node.

    # File lib/ravn/tactical/kit.rb
153 def self::url_for( node, resource: KIT_RESOURCE )
154     host = node.ip&.to_s or raise ArgumentError, "can't get a request for a node with no IP"
155     path = SERVICE_PATH + resource
156 
157     return URI_PROTOCOL.build( host:, path: )
158 end