cosmos 5.0.2.pre.beta2 → 5.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|