cosmos 5.0.2.pre.beta2 → 5.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/cosmos +1 -1
- data/data/config/microservice.yaml +47 -35
- data/data/config/plugins.yaml +3 -150
- data/data/config/target.yaml +70 -0
- data/data/config/tool.yaml +37 -31
- data/lib/cosmos/api/api.rb +1 -25
- data/lib/cosmos/api/cmd_api.rb +17 -6
- data/lib/cosmos/api/config_api.rb +10 -4
- data/lib/cosmos/api/limits_api.rb +1 -1
- data/lib/cosmos/api/settings_api.rb +19 -7
- data/lib/cosmos/api/target_api.rb +2 -2
- data/lib/cosmos/api/tlm_api.rb +69 -41
- data/lib/cosmos/config/config_parser.rb +19 -22
- data/lib/cosmos/config/meta_config_parser.rb +1 -1
- data/lib/cosmos/conversions/generic_conversion.rb +2 -2
- data/lib/cosmos/conversions/polynomial_conversion.rb +5 -8
- data/lib/cosmos/conversions/segmented_polynomial_conversion.rb +26 -9
- data/lib/cosmos/io/json_drb.rb +5 -1
- data/lib/cosmos/logs/log_writer.rb +2 -2
- data/lib/cosmos/microservices/cleanup_microservice.rb +28 -29
- data/lib/cosmos/microservices/decom_microservice.rb +1 -1
- data/lib/cosmos/microservices/interface_microservice.rb +0 -1
- data/lib/cosmos/microservices/microservice.rb +3 -3
- data/lib/cosmos/microservices/reducer_microservice.rb +12 -10
- data/lib/cosmos/models/cvt_model.rb +6 -6
- data/lib/cosmos/models/gem_model.rb +3 -3
- data/lib/cosmos/models/info_model.rb +1 -1
- data/lib/cosmos/models/interface_status_model.rb +1 -1
- data/lib/cosmos/models/metadata_model.rb +42 -216
- data/lib/cosmos/models/metric_model.rb +2 -2
- data/lib/cosmos/models/microservice_model.rb +1 -1
- data/lib/cosmos/models/microservice_status_model.rb +1 -1
- data/lib/cosmos/models/model.rb +16 -16
- data/lib/cosmos/models/note_model.rb +124 -0
- data/lib/cosmos/models/ping_model.rb +2 -1
- data/lib/cosmos/models/plugin_model.rb +1 -1
- data/lib/cosmos/models/process_status_model.rb +1 -1
- data/lib/cosmos/models/scope_model.rb +9 -26
- data/lib/cosmos/models/settings_model.rb +55 -0
- data/lib/cosmos/models/sorted_model.rb +165 -0
- data/lib/cosmos/models/target_model.rb +120 -13
- data/lib/cosmos/models/tool_config_model.rb +38 -0
- data/lib/cosmos/models/tool_model.rb +1 -1
- data/lib/cosmos/models/widget_model.rb +1 -1
- data/lib/cosmos/operators/microservice_operator.rb +2 -1
- data/lib/cosmos/packets/packet.rb +23 -0
- data/lib/cosmos/packets/packet_config.rb +2 -2
- data/lib/cosmos/packets/packet_item.rb +57 -0
- data/lib/cosmos/packets/packet_item_limits.rb +14 -2
- data/lib/cosmos/packets/parsers/packet_item_parser.rb +1 -1
- data/lib/cosmos/packets/parsers/packet_parser.rb +1 -1
- data/lib/cosmos/packets/parsers/xtce_parser.rb +1 -1
- data/lib/cosmos/packets/structure_item.rb +10 -1
- data/lib/cosmos/script/api_shared.rb +30 -25
- data/lib/cosmos/script/calendar.rb +26 -15
- data/lib/cosmos/script/commands.rb +5 -7
- data/lib/cosmos/script/script.rb +19 -39
- data/lib/cosmos/script/storage.rb +92 -105
- data/lib/cosmos/system/system.rb +2 -1
- data/lib/cosmos/tools/table_manager/table_item.rb +1 -1
- data/lib/cosmos/top_level.rb +5 -1
- data/lib/cosmos/topics/autonomic_topic.rb +2 -2
- data/lib/cosmos/topics/calendar_topic.rb +1 -1
- data/lib/cosmos/topics/command_decom_topic.rb +35 -1
- data/lib/cosmos/topics/command_topic.rb +6 -4
- data/lib/cosmos/topics/interface_topic.rb +8 -8
- data/lib/cosmos/topics/limits_event_topic.rb +5 -3
- data/lib/cosmos/topics/notifications_topic.rb +1 -1
- data/lib/cosmos/topics/router_topic.rb +9 -9
- data/lib/cosmos/topics/telemetry_decom_topic.rb +5 -1
- data/lib/cosmos/topics/telemetry_topic.rb +1 -1
- data/lib/cosmos/topics/timeline_topic.rb +1 -1
- data/lib/cosmos/topics/topic.rb +23 -8
- data/lib/cosmos/utilities/logger.rb +4 -3
- data/lib/cosmos/utilities/metric.rb +32 -26
- data/lib/cosmos/utilities/s3.rb +61 -0
- data/lib/cosmos/utilities/s3_file_cache.rb +12 -6
- data/lib/cosmos/utilities/store.rb +1 -0
- data/lib/cosmos/utilities/store_autoload.rb +25 -134
- data/lib/cosmos/version.rb +6 -5
- data/templates/plugin-template/plugin.gemspec +0 -2
- metadata +9 -6
- data/lib/cosmos/models/narrative_model.rb +0 -280
@@ -19,8 +19,6 @@
|
|
19
19
|
|
20
20
|
module Cosmos
|
21
21
|
module Api
|
22
|
-
SETTINGS_KEY = "cosmos__settings"
|
23
|
-
|
24
22
|
WHITELIST ||= []
|
25
23
|
WHITELIST.concat([
|
26
24
|
'list_settings',
|
@@ -31,28 +29,42 @@ module Cosmos
|
|
31
29
|
])
|
32
30
|
|
33
31
|
def list_settings(scope: $cosmos_scope, token: $cosmos_token)
|
34
|
-
|
32
|
+
authorize(permission: 'system', scope: scope, token: token)
|
33
|
+
SettingsModel.names(scope: scope)
|
35
34
|
end
|
36
35
|
|
37
36
|
def get_all_settings(scope: $cosmos_scope, token: $cosmos_token)
|
38
|
-
|
37
|
+
authorize(permission: 'system', scope: scope, token: token)
|
38
|
+
SettingsModel.all(scope: scope)
|
39
39
|
end
|
40
40
|
|
41
41
|
def get_setting(name, scope: $cosmos_scope, token: $cosmos_token)
|
42
|
-
|
42
|
+
authorize(permission: 'system', scope: scope, token: token)
|
43
|
+
setting = SettingsModel.get(name: name, scope: scope)
|
44
|
+
if setting
|
45
|
+
return setting["data"]
|
46
|
+
else
|
47
|
+
return nil
|
48
|
+
end
|
43
49
|
end
|
44
50
|
|
45
51
|
def get_settings(*args, scope: $cosmos_scope, token: $cosmos_token)
|
52
|
+
authorize(permission: 'system', scope: scope, token: token)
|
46
53
|
ret = []
|
47
54
|
args.each do |name|
|
48
|
-
|
55
|
+
setting = SettingsModel.get(name: name, scope: scope)
|
56
|
+
if setting
|
57
|
+
ret << setting["data"]
|
58
|
+
else
|
59
|
+
ret << nil
|
60
|
+
end
|
49
61
|
end
|
50
62
|
return ret
|
51
63
|
end
|
52
64
|
|
53
65
|
def save_setting(name, data, scope: $cosmos_scope, token: $cosmos_token)
|
54
66
|
authorize(permission: 'admin', scope: scope, token: token)
|
55
|
-
|
67
|
+
SettingsModel.set({ name: name, data: data }, scope: scope)
|
56
68
|
end
|
57
69
|
end
|
58
70
|
end
|
@@ -56,12 +56,12 @@ module Cosmos
|
|
56
56
|
cmd_cnt = 0
|
57
57
|
packets = TargetModel.packets(target_name, type: :CMD, scope: scope)
|
58
58
|
packets.each do |packet|
|
59
|
-
cmd_cnt +=
|
59
|
+
cmd_cnt += Topic.get_cnt("#{scope}__COMMAND__{#{target_name}}__#{packet['packet_name']}")
|
60
60
|
end
|
61
61
|
tlm_cnt = 0
|
62
62
|
packets = TargetModel.packets(target_name, type: :TLM, scope: scope)
|
63
63
|
packets.each do |packet|
|
64
|
-
tlm_cnt +=
|
64
|
+
tlm_cnt += Topic.get_cnt("#{scope}__TELEMETRY__{#{target_name}}__#{packet['packet_name']}")
|
65
65
|
end
|
66
66
|
interface_name = ''
|
67
67
|
InterfaceModel.all(scope: scope).each do |name, interface|
|
data/lib/cosmos/api/tlm_api.rb
CHANGED
@@ -19,6 +19,8 @@
|
|
19
19
|
|
20
20
|
require 'cosmos/models/target_model'
|
21
21
|
require 'cosmos/models/cvt_model'
|
22
|
+
require 'cosmos/packets/packet'
|
23
|
+
require 'cosmos/topics/telemetry_topic'
|
22
24
|
require 'cosmos/utilities/s3'
|
23
25
|
|
24
26
|
module Cosmos
|
@@ -38,10 +40,11 @@ module Cosmos
|
|
38
40
|
'get_tlm_packet',
|
39
41
|
'get_tlm_values',
|
40
42
|
'get_all_telemetry',
|
43
|
+
'get_all_telemetry_list',
|
41
44
|
'get_telemetry',
|
42
45
|
'get_item',
|
43
46
|
'subscribe_packets',
|
44
|
-
'
|
47
|
+
'get_packets',
|
45
48
|
'get_all_tlm_info',
|
46
49
|
'get_tlm_cnt',
|
47
50
|
'get_packet_derived_items',
|
@@ -125,19 +128,18 @@ module Cosmos
|
|
125
128
|
# Check that the packet exists ... exceptions are raised if not
|
126
129
|
TargetModel.packet(target_name, packet_name, scope: scope)
|
127
130
|
end
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
inject['type'] = type
|
135
|
-
|
136
|
-
InterfaceModel.all(scope: scope).each do |name, interface|
|
137
|
-
if interface['target_names'].include? target_name
|
138
|
-
Store.write_topic("{#{scope}__CMD}INTERFACE__#{interface['name']}", inject, '*', 100)
|
131
|
+
|
132
|
+
packet_hash = get_telemetry(target_name, packet_name, scope: scope, token: token)
|
133
|
+
packet = Packet.from_json(packet_hash)
|
134
|
+
if item_hash
|
135
|
+
item_hash.each do |name, value|
|
136
|
+
packet.write(name.to_s, value, type)
|
139
137
|
end
|
140
138
|
end
|
139
|
+
packet.received_time = Time.now.sys
|
140
|
+
# TODO: New packet so received_count is not correct
|
141
|
+
packet.received_count += 1
|
142
|
+
TelemetryTopic.write_packet(packet, scope: scope)
|
141
143
|
end
|
142
144
|
|
143
145
|
# Override the current value table such that a particular item always
|
@@ -188,7 +190,7 @@ module Cosmos
|
|
188
190
|
authorize(permission: 'tlm', target_name: target_name, packet_name: packet_name, scope: scope, token: token)
|
189
191
|
TargetModel.packet(target_name, packet_name, scope: scope)
|
190
192
|
topic = "#{scope}__TELEMETRY__{#{target_name}}__#{packet_name}"
|
191
|
-
msg_id, msg_hash =
|
193
|
+
msg_id, msg_hash = Topic.get_newest_message(topic)
|
192
194
|
if msg_id
|
193
195
|
msg_hash['buffer'] = msg_hash['buffer'].b
|
194
196
|
return msg_hash
|
@@ -245,7 +247,17 @@ module Cosmos
|
|
245
247
|
# @return [Array<Hash>] Array of all telemetry packet hashes
|
246
248
|
def get_all_telemetry(target_name, scope: $cosmos_scope, token: $cosmos_token)
|
247
249
|
authorize(permission: 'tlm', target_name: target_name, scope: scope, token: token)
|
248
|
-
TargetModel.packets(target_name, scope: scope)
|
250
|
+
TargetModel.packets(target_name, type: :TLM, scope: scope)
|
251
|
+
end
|
252
|
+
|
253
|
+
# Returns an array of all telemetry packet's name and descriptions
|
254
|
+
#
|
255
|
+
# @since 5.0.3
|
256
|
+
# @param target_name [String] Name of the target
|
257
|
+
# @return [Array<Hash>] Array of all telemetry packet name and descriptions
|
258
|
+
def get_all_telemetry_list(target_name, scope: $cosmos_scope, token: $cosmos_token)
|
259
|
+
authorize(permission: 'tlm', target_name: target_name, scope: scope, token: token)
|
260
|
+
TargetModel.all_packet_name_descriptions(target_name, type: :TLM, scope: scope)
|
249
261
|
end
|
250
262
|
|
251
263
|
# Returns a telemetry packet hash
|
@@ -271,41 +283,53 @@ module Cosmos
|
|
271
283
|
TargetModel.packet_item(target_name, packet_name, item_name, scope: scope)
|
272
284
|
end
|
273
285
|
|
286
|
+
# 2x double underscore since __ is reserved
|
287
|
+
SUBSCRIPTION_DELIMITER = '____'
|
288
|
+
|
274
289
|
# Subscribe to a list of packets. An ID is returned which is passed to
|
275
|
-
#
|
290
|
+
# get_packets(id) to return packets.
|
276
291
|
#
|
277
292
|
# @param packets [Array<Array<String, String>>] Array of arrays consisting of target name, packet name
|
278
|
-
# @return [String] ID which should be passed to
|
293
|
+
# @return [String] ID which should be passed to get_packets
|
279
294
|
def subscribe_packets(packets, scope: $cosmos_scope, token: $cosmos_token)
|
280
295
|
if !packets.is_a?(Array) || !packets[0].is_a?(Array)
|
281
296
|
raise ArgumentError, "packets must be nested array: [['TGT','PKT'],...]"
|
282
297
|
end
|
283
298
|
|
284
|
-
result =
|
299
|
+
result = {}
|
285
300
|
packets.each do |target_name, packet_name|
|
286
301
|
authorize(permission: 'tlm', target_name: target_name, packet_name: packet_name, scope: scope, token: token)
|
287
|
-
|
302
|
+
topic = "#{scope}__DECOM__{#{target_name}}__#{packet_name}"
|
303
|
+
id, _ = Topic.get_newest_message(topic)
|
304
|
+
result[topic] = id ? id : '0-0'
|
288
305
|
end
|
289
|
-
result.join(
|
306
|
+
result.to_a.join(SUBSCRIPTION_DELIMITER)
|
290
307
|
end
|
291
308
|
# Alias the singular as well since that matches COSMOS 4
|
292
309
|
alias subscribe_packet subscribe_packets
|
293
310
|
|
294
|
-
# Get
|
295
|
-
#
|
296
|
-
|
311
|
+
# Get packets based on ID returned from subscribe_packet.
|
312
|
+
# @param id [String] ID returned from subscribe_packets or last call to get_packets
|
313
|
+
# @param block [Integer] Number of milliseconds to block when requesting packets
|
314
|
+
# @param count [Integer] Maximum number of packets to return from EACH packet stream
|
315
|
+
# @return [Array<String, Array<Hash>] Array of the ID and array of all packets found
|
316
|
+
def get_packets(id, block: nil, count: 1000, scope: $cosmos_scope, token: $cosmos_token)
|
297
317
|
authorize(permission: 'tlm', scope: scope, token: token)
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
318
|
+
# Split the list of topic, ID values and turn it into a hash for easy updates
|
319
|
+
lookup = Hash[*id.split(SUBSCRIPTION_DELIMITER)]
|
320
|
+
xread = Topic.read_topics(lookup.keys, lookup.values, block, count)
|
321
|
+
# Return the original ID and nil if we didn't get anything
|
322
|
+
return [id, nil] if xread.empty?
|
323
|
+
packets = []
|
324
|
+
xread.each do |topic, data|
|
325
|
+
data.each do |id, msg_hash|
|
326
|
+
lookup[topic] = id # save the new ID
|
327
|
+
json_hash = JSON.parse(msg_hash['json_data'])
|
328
|
+
msg_hash.delete('json_data')
|
329
|
+
packets << msg_hash.merge(json_hash)
|
330
|
+
end
|
308
331
|
end
|
332
|
+
return [lookup.to_a.join(SUBSCRIPTION_DELIMITER), packets]
|
309
333
|
end
|
310
334
|
|
311
335
|
# Get the receive count for a telemetry packet
|
@@ -316,7 +340,7 @@ module Cosmos
|
|
316
340
|
def get_tlm_cnt(target_name, packet_name, scope: $cosmos_scope, token: $cosmos_token)
|
317
341
|
authorize(permission: 'system', target_name: target_name, packet_name: packet_name, scope: scope, token: token)
|
318
342
|
TargetModel.packet(target_name, packet_name, scope: scope)
|
319
|
-
|
343
|
+
Topic.get_cnt("#{scope}__TELEMETRY__{#{target_name}}__#{packet_name}")
|
320
344
|
end
|
321
345
|
|
322
346
|
# Get information on all telemetry packets
|
@@ -329,14 +353,14 @@ module Cosmos
|
|
329
353
|
TargetModel.packets(target_name, scope: scope).each do | packet |
|
330
354
|
packet_name = packet['packet_name']
|
331
355
|
key = "#{scope}__TELEMETRY__{#{target_name}}__#{packet_name}"
|
332
|
-
result << [target_name, packet_name,
|
356
|
+
result << [target_name, packet_name, Topic.get_cnt(key)]
|
333
357
|
end
|
334
358
|
end
|
335
359
|
['UNKNOWN'].each do | x |
|
336
360
|
key = "#{scope}__TELEMETRY__{#{x}}__#{x}"
|
337
|
-
result << [x, x,
|
361
|
+
result << [x, x, Topic.get_cnt(key)]
|
338
362
|
end
|
339
|
-
# Return the
|
363
|
+
# Return the result sorted by target, packet
|
340
364
|
result.sort_by { |a| [a[0], a[1]] }
|
341
365
|
end
|
342
366
|
|
@@ -358,10 +382,14 @@ module Cosmos
|
|
358
382
|
# Request the path by calling the key method. Returns something like this:
|
359
383
|
# DEFAULT/decom_logs/tlm/INST2/MECH/20220104/20220104165449021942700__20220104170449148642700__DEFAULT__INST2__MECH__rt__decom.bin
|
360
384
|
# Thus we split and take the start date/time part of the filename
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
385
|
+
if list and list[0]
|
386
|
+
start = list[0].key.split('/')[-1].split('__')[0]
|
387
|
+
# Format as YYYY-MM-DD HH:MM:SS for use by the frontend
|
388
|
+
# utc_time = Time.utc(start[0,4], start[4,2], start[6,2], start[8,2], start[10,2], start[12,2])
|
389
|
+
return "#{start[0,4]}-#{start[4,2]}-#{start[6,2]} #{start[8,2]}:#{start[10,2]}:#{start[12,2]}"
|
390
|
+
else
|
391
|
+
return Time.now.utc.to_s[0..18]
|
392
|
+
end
|
365
393
|
end
|
366
394
|
|
367
395
|
# PRIVATE
|
@@ -397,7 +425,7 @@ module Cosmos
|
|
397
425
|
TargetModel.packets(target_name, scope: scope).each do |packet|
|
398
426
|
item = packet['items'].find { |item| item['name'] == item_name }
|
399
427
|
if item
|
400
|
-
_, msg_hash =
|
428
|
+
_, msg_hash = Topic.get_oldest_message("#{scope}__DECOM__{#{target_name}}__#{packet['packet_name']}")
|
401
429
|
if msg_hash && msg_hash['time'] && msg_hash['time'].to_i > latest
|
402
430
|
packet_name = packet['packet_name']
|
403
431
|
latest = msg_hash['time'].to_i
|
@@ -168,7 +168,7 @@ module Cosmos
|
|
168
168
|
path = File.join(File.dirname(@filename), template_name)
|
169
169
|
end
|
170
170
|
Cosmos.set_working_dir(File.dirname(path)) do
|
171
|
-
return ERB.new(File.read(path)).result(b)
|
171
|
+
return ERB.new(File.read(path), trim_mode: "-").result(b)
|
172
172
|
end
|
173
173
|
end
|
174
174
|
|
@@ -238,27 +238,24 @@ module Cosmos
|
|
238
238
|
end
|
239
239
|
end
|
240
240
|
|
241
|
-
# Verifies the indicated parameter
|
242
|
-
# with an underscore
|
243
|
-
#
|
241
|
+
# Verifies the indicated parameter in the config doesn't start or end
|
242
|
+
# with an underscore, doesn't contain a double underscore, doesn't contain
|
243
|
+
# spaces and doesn't start with a close bracket.
|
244
244
|
#
|
245
|
-
# @param [Integer
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
param
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
if param.include? ' '
|
260
|
-
raise Error.new(self, "Parameter #{index} (#{@parameters[index - 1]}) for #{@keyword} cannot contain a space (' ').", usage, @url)
|
261
|
-
end
|
245
|
+
# @param [Integer] index The index of the parameter to check
|
246
|
+
def verify_parameter_naming(index, usage = "")
|
247
|
+
param = @parameters[index - 1]
|
248
|
+
if param.end_with? '_'
|
249
|
+
raise Error.new(self, "Parameter #{index} (#{param}) for #{@keyword} cannot end with an underscore ('_').", usage, @url)
|
250
|
+
end
|
251
|
+
if param.include? '__'
|
252
|
+
raise Error.new(self, "Parameter #{index} (#{param}) for #{@keyword} cannot contain a double underscore ('__').", usage, @url)
|
253
|
+
end
|
254
|
+
if param.include? ' '
|
255
|
+
raise Error.new(self, "Parameter #{index} (#{param}) for #{@keyword} cannot contain a space (' ').", usage, @url)
|
256
|
+
end
|
257
|
+
if param.start_with?('}')
|
258
|
+
raise Error.new(self, "Parameter #{index} (#{param}) for #{@keyword} cannot start with a close bracket ('}').", usage, @url)
|
262
259
|
end
|
263
260
|
end
|
264
261
|
|
@@ -380,7 +377,7 @@ module Cosmos
|
|
380
377
|
output = nil
|
381
378
|
if run_erb
|
382
379
|
Cosmos.set_working_dir(File.dirname(filename)) do
|
383
|
-
output = ERB.new(File.read(filename)).result(binding.set_variables(variables))
|
380
|
+
output = ERB.new(File.read(filename), trim_mode: "-").result(binding.set_variables(variables))
|
384
381
|
end
|
385
382
|
else
|
386
383
|
output = File.read(filename)
|
@@ -29,13 +29,10 @@ module Cosmos
|
|
29
29
|
# Initializes the conversion with the given polynomial coefficients. Sets
|
30
30
|
# the converted_type to :FLOAT and the converted_bit_size to 64.
|
31
31
|
#
|
32
|
-
# @param
|
33
|
-
def initialize(
|
32
|
+
# @param coeffs [Array<Float>] The polynomial coefficients
|
33
|
+
def initialize(*coeffs)
|
34
34
|
super()
|
35
|
-
@coeffs =
|
36
|
-
coeff_array.each do |coeff|
|
37
|
-
@coeffs << coeff.to_f
|
38
|
-
end
|
35
|
+
@coeffs = coeffs.map { |coeff| coeff.to_f }
|
39
36
|
@converted_type = :FLOAT
|
40
37
|
@converted_bit_size = 64
|
41
38
|
end
|
@@ -84,5 +81,5 @@ module Cosmos
|
|
84
81
|
def as_json
|
85
82
|
{ 'class' => self.class.name.to_s, 'params' => @coeffs }
|
86
83
|
end
|
87
|
-
end
|
88
|
-
end
|
84
|
+
end
|
85
|
+
end
|
@@ -23,6 +23,9 @@ module Cosmos
|
|
23
23
|
# Segmented polynomial conversions consist of polynomial conversions that are
|
24
24
|
# applied for a range of values.
|
25
25
|
class SegmentedPolynomialConversion < Conversion
|
26
|
+
# @return [Array<Segment>] Segments which make up this conversion
|
27
|
+
attr_reader :segments
|
28
|
+
|
26
29
|
# A polynomial conversion segment which applies the conversion from the
|
27
30
|
# lower bound (inclusive) until another segment's lower bound is
|
28
31
|
# encountered.
|
@@ -31,6 +34,7 @@ module Cosmos
|
|
31
34
|
# should apply. All values >= to this value will be converted using the
|
32
35
|
# given coefficients.
|
33
36
|
attr_reader :lower_bound
|
37
|
+
|
34
38
|
# @return [Array<Integer>] The polynomial coefficients
|
35
39
|
attr_reader :coeffs
|
36
40
|
|
@@ -57,6 +61,14 @@ module Cosmos
|
|
57
61
|
return other_segment.lower_bound <=> @lower_bound
|
58
62
|
end
|
59
63
|
|
64
|
+
# Implement equality operator primarily for ease of testing
|
65
|
+
#
|
66
|
+
# @param segment [Segment] Other segment
|
67
|
+
def ==(other_segment)
|
68
|
+
@lower_bound == other_segment.lower_bound &&
|
69
|
+
@coeffs == other_segment.coeffs
|
70
|
+
end
|
71
|
+
|
60
72
|
# Perform the polynomial conversion
|
61
73
|
#
|
62
74
|
# @param value [Numeric] The value to convert
|
@@ -71,9 +83,15 @@ module Cosmos
|
|
71
83
|
end
|
72
84
|
|
73
85
|
# Initialize the converted_type to :FLOAT and converted_bit_size to 64.
|
74
|
-
|
86
|
+
#
|
87
|
+
# @param segments [Array] Array of segments typically generated by as_json
|
88
|
+
# Format similar to the following: [[15, [3, 2]], [10, [1, 2]]]
|
89
|
+
# Where each entry is an array with the first value as the lower_bound
|
90
|
+
# and the other entry is an array of the coefficients for that segment.
|
91
|
+
def initialize(segments = [])
|
75
92
|
super()
|
76
93
|
@segments = []
|
94
|
+
segments.each { |lower_bound, coeffs| add_segment(lower_bound, *coeffs) }
|
77
95
|
@converted_type = :FLOAT
|
78
96
|
@converted_bit_size = 64
|
79
97
|
end
|
@@ -95,9 +113,7 @@ module Cosmos
|
|
95
113
|
def call(value, packet, buffer)
|
96
114
|
# Try to find correct segment
|
97
115
|
@segments.each do |segment|
|
98
|
-
if value >= segment.lower_bound
|
99
|
-
return segment.calculate(value)
|
100
|
-
end
|
116
|
+
return segment.calculate(value) if value >= segment.lower_bound
|
101
117
|
end
|
102
118
|
|
103
119
|
# Default to using segment with smallest lower_bound
|
@@ -112,7 +128,7 @@ module Cosmos
|
|
112
128
|
# @return [String] The name of the class followed by a description of all
|
113
129
|
# the polynomial segments.
|
114
130
|
def to_s
|
115
|
-
result =
|
131
|
+
result = ''
|
116
132
|
count = 0
|
117
133
|
@segments.each do |segment|
|
118
134
|
result << "\n" if count > 0
|
@@ -136,7 +152,8 @@ module Cosmos
|
|
136
152
|
def to_config(read_or_write)
|
137
153
|
config = ''
|
138
154
|
@segments.each do |segment|
|
139
|
-
config <<
|
155
|
+
config <<
|
156
|
+
" SEG_POLY_#{read_or_write}_CONVERSION #{segment.lower_bound} #{segment.coeffs.join(' ')}\n"
|
140
157
|
end
|
141
158
|
config
|
142
159
|
end
|
@@ -146,7 +163,7 @@ module Cosmos
|
|
146
163
|
@segments.each do |segment|
|
147
164
|
params << [segment.lower_bound, segment.coeffs]
|
148
165
|
end
|
149
|
-
{ 'class' => self.class.name.to_s, 'params' => params }
|
166
|
+
{ 'class' => self.class.name.to_s, 'params' => [params] }
|
150
167
|
end
|
151
|
-
end
|
152
|
-
end
|
168
|
+
end
|
169
|
+
end
|
data/lib/cosmos/io/json_drb.rb
CHANGED
@@ -269,7 +269,11 @@ module Cosmos
|
|
269
269
|
response = JsonRpcSuccessResponse.new(result, request.id)
|
270
270
|
end
|
271
271
|
rescue Exception => error
|
272
|
-
|
272
|
+
# Filter out the framework stack trace (rails, rack, puma etc)
|
273
|
+
lines = error.formatted.split("\n")
|
274
|
+
i = lines.find_index { |row| row.include?('actionpack') || row.include?('activesupport') }
|
275
|
+
Logger.error lines[0...i].join("\n")
|
276
|
+
|
273
277
|
if request.id
|
274
278
|
if NoMethodError === error
|
275
279
|
error_code = JsonRpcError::ErrorCode::METHOD_NOT_FOUND
|
@@ -19,7 +19,7 @@
|
|
19
19
|
|
20
20
|
require 'thread'
|
21
21
|
require 'cosmos/config/config_parser'
|
22
|
-
require 'cosmos/
|
22
|
+
require 'cosmos/topics/topic'
|
23
23
|
require 'cosmos/utilities/s3'
|
24
24
|
|
25
25
|
module Cosmos
|
@@ -211,7 +211,7 @@ module Cosmos
|
|
211
211
|
S3Utilities.move_log_file_to_s3(@filename, s3_key)
|
212
212
|
# Now that the file is in S3, trim the Redis stream up until the previous file.
|
213
213
|
# This keeps one file worth of data in Redis as a safety buffer
|
214
|
-
|
214
|
+
Topic.trim_topic(@redis_topic, @previous_file_redis_offset) if @redis_topic and @previous_file_redis_offset
|
215
215
|
@previous_file_redis_offset = @last_offset
|
216
216
|
rescue Exception => err
|
217
217
|
Logger.instance.error "Error closing #{@filename} : #{err.formatted}"
|
@@ -17,50 +17,49 @@
|
|
17
17
|
# enterprise edition license of COSMOS if purchased from the
|
18
18
|
# copyright holder
|
19
19
|
|
20
|
+
require 'cosmos/models/target_model'
|
20
21
|
require 'cosmos/microservices/microservice'
|
21
22
|
require 'cosmos/utilities/s3'
|
22
23
|
|
23
24
|
module Cosmos
|
24
25
|
class CleanupMicroservice < Microservice
|
25
26
|
def run
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
when 'SIZE' # Max size to use in S3 in bytes
|
30
|
-
@size = option[1].to_i
|
31
|
-
when 'DELAY' # Delay between size checks
|
32
|
-
@delay = option[1].to_i
|
33
|
-
when 'BUCKET' # Which bucket to monitor
|
34
|
-
@bucket = option[1]
|
35
|
-
when 'PREFIX' # Path into bucket to monitor
|
36
|
-
@prefix = option[1]
|
37
|
-
else
|
38
|
-
Logger.error("Unknown option passed to microservice #{@name}: #{option}")
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
raise "Microservice #{@name} not fully configured" unless @size and @delay and @bucket and @prefix
|
27
|
+
split_name = @name.split("__")
|
28
|
+
target_name = split_name[-1]
|
29
|
+
target = TargetModel.get_model(name: target_name, scope: @scope)
|
43
30
|
|
44
31
|
rubys3_client = Aws::S3::Client.new
|
45
32
|
while true
|
46
33
|
break if @cancel_thread
|
47
34
|
|
48
35
|
@state = 'GETTING_OBJECTS'
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
36
|
+
start_time = Time.now
|
37
|
+
[
|
38
|
+
["#{@scope}/raw_logs/cmd/#{target_name}/", target.cmd_log_retain_time],
|
39
|
+
["#{@scope}/decom_logs/cmd/#{target_name}/", target.cmd_decom_log_retain_time],
|
40
|
+
["#{@scope}/raw_logs/tlm/#{target_name}/", target.tlm_log_retain_time],
|
41
|
+
["#{@scope}/decom_logs/tlm/#{target_name}/", target.tlm_decom_log_retain_time],
|
42
|
+
["#{@scope}/reduced_minute_logs/tlm/#{target_name}/", target.reduced_minute_log_retain_time],
|
43
|
+
["#{@scope}/reduced_hour_logs/tlm/#{target_name}/", target.reduced_hour_log_retain_time],
|
44
|
+
["#{@scope}/reduced_day_logs/tlm/#{target_name}/", target.reduced_day_log_retain_time],
|
45
|
+
].each do |prefix, retain_time|
|
46
|
+
next unless retain_time
|
47
|
+
time = start_time - retain_time
|
48
|
+
total_size, oldest_list = S3Utilities.list_files_before_time('logs', prefix, time)
|
49
|
+
delete_items = []
|
50
|
+
oldest_list.each do |item|
|
51
|
+
delete_items << { :key => item.key }
|
52
|
+
end
|
53
|
+
if delete_items.length > 0
|
54
|
+
@state = 'DELETING_OBJECTS'
|
55
|
+
rubys3_client.delete_objects({ bucket: 'logs', delete: { objects: delete_items } })
|
56
|
+
Logger.info("Deleted #{delete_items.length} #{target_name} log files")
|
57
|
+
end
|
60
58
|
end
|
59
|
+
|
61
60
|
@count += 1
|
62
61
|
@state = 'SLEEPING'
|
63
|
-
break if @microservice_sleeper.sleep(
|
62
|
+
break if @microservice_sleeper.sleep(target.cleanup_poll_time)
|
64
63
|
end
|
65
64
|
end
|
66
65
|
end
|
@@ -143,7 +143,6 @@ module Cosmos
|
|
143
143
|
hazardous, hazardous_description = System.commands.cmd_pkt_hazardous?(command)
|
144
144
|
# Return back the error, description, and the formatted command
|
145
145
|
# This allows the error handler to simply re-send the command
|
146
|
-
# TODO: Should we set target_name, cmd_name, and cmd_params instead?
|
147
146
|
next "HazardousError\n#{hazardous_description}\n#{System.commands.format(command)}" if hazardous
|
148
147
|
end
|
149
148
|
|
@@ -40,7 +40,7 @@ module Cosmos
|
|
40
40
|
attr_accessor :scope
|
41
41
|
|
42
42
|
def self.run
|
43
|
-
microservice = self.new(
|
43
|
+
microservice = self.new(ENV['COSMOS_MICROSERVICE_NAME'])
|
44
44
|
begin
|
45
45
|
MicroserviceStatusModel.set(microservice.as_json, scope: microservice.scope)
|
46
46
|
microservice.state = 'RUNNING'
|
@@ -52,7 +52,7 @@ module Cosmos
|
|
52
52
|
else
|
53
53
|
microservice.error = err
|
54
54
|
microservice.state = 'DIED_ERROR'
|
55
|
-
Logger.fatal("Microservice #{
|
55
|
+
Logger.fatal("Microservice #{ENV['COSMOS_MICROSERVICE_NAME']} dying from exception\n#{err.formatted}")
|
56
56
|
end
|
57
57
|
ensure
|
58
58
|
MicroserviceStatusModel.set(microservice.as_json, scope: microservice.scope)
|
@@ -75,7 +75,7 @@ module Cosmos
|
|
75
75
|
|
76
76
|
@name = name
|
77
77
|
split_name = name.split("__")
|
78
|
-
raise "
|
78
|
+
raise "Name #{name} doesn't match convention of SCOPE__TYPE__NAME" if split_name.length != 3
|
79
79
|
|
80
80
|
@scope = split_name[0]
|
81
81
|
$cosmos_scope = @scope
|