openc3 5.2.0 → 5.4.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of openc3 might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/bin/openc3cli +108 -105
- data/data/config/interface_modifiers.yaml +22 -4
- data/data/config/item_modifiers.yaml +4 -2
- data/data/config/microservice.yaml +18 -0
- data/data/config/table_manager.yaml +2 -2
- data/data/config/tool.yaml +1 -1
- data/ext/openc3/ext/config_parser/config_parser.c +17 -2
- data/lib/openc3/api/api.rb +1 -0
- data/lib/openc3/api/interface_api.rb +12 -0
- data/lib/openc3/api/metrics_api.rb +97 -0
- data/lib/openc3/api/router_api.rb +14 -2
- data/lib/openc3/api/target_api.rb +24 -3
- data/lib/openc3/api/tlm_api.rb +5 -4
- data/lib/openc3/config/config_parser.rb +29 -4
- data/lib/openc3/core_ext/time.rb +6 -1
- data/lib/openc3/interfaces/interface.rb +27 -26
- data/lib/openc3/interfaces/mqtt_interface.rb +240 -0
- data/lib/openc3/interfaces/protocols/override_protocol.rb +2 -61
- data/lib/openc3/interfaces/protocols/protocol.rb +6 -1
- data/lib/openc3/interfaces/simulated_target_interface.rb +1 -3
- data/lib/openc3/interfaces/tcpip_server_interface.rb +0 -11
- data/lib/openc3/interfaces.rb +2 -3
- data/lib/openc3/logs/buffered_packet_log_reader.rb +2 -2
- data/lib/openc3/microservices/cleanup_microservice.rb +17 -1
- data/lib/openc3/microservices/decom_microservice.rb +12 -9
- data/lib/openc3/microservices/interface_microservice.rb +93 -9
- data/lib/openc3/microservices/log_microservice.rb +11 -5
- data/lib/openc3/microservices/microservice.rb +10 -9
- data/lib/openc3/microservices/periodic_microservice.rb +7 -0
- data/lib/openc3/microservices/reaction_microservice.rb +0 -33
- data/lib/openc3/microservices/reducer_microservice.rb +14 -10
- data/lib/openc3/microservices/text_log_microservice.rb +12 -3
- data/lib/openc3/microservices/timeline_microservice.rb +0 -6
- data/lib/openc3/microservices/trigger_group_microservice.rb +0 -20
- data/lib/openc3/models/cvt_model.rb +103 -47
- data/lib/openc3/models/interface_model.rb +23 -0
- data/lib/openc3/models/metric_model.rb +53 -6
- data/lib/openc3/models/microservice_model.rb +15 -1
- data/lib/openc3/models/model.rb +1 -1
- data/lib/openc3/models/plugin_model.rb +6 -1
- data/lib/openc3/models/secret_model.rb +53 -0
- data/lib/openc3/models/target_model.rb +2 -2
- data/lib/openc3/models/tool_model.rb +17 -8
- data/lib/openc3/operators/microservice_operator.rb +25 -0
- data/lib/openc3/operators/operator.rb +5 -1
- data/lib/openc3/packets/packet.rb +21 -7
- data/lib/openc3/packets/packet_item.rb +3 -2
- data/lib/openc3/script/api_shared.rb +18 -2
- data/lib/openc3/script/script.rb +8 -0
- data/lib/openc3/script/script_runner.rb +1 -2
- data/lib/openc3/script/storage.rb +2 -1
- data/lib/openc3/script/suite.rb +15 -11
- data/lib/openc3/system/system.rb +6 -3
- data/lib/openc3/topics/interface_topic.rb +17 -1
- data/lib/openc3/topics/router_topic.rb +17 -1
- data/lib/openc3/utilities/aws_bucket.rb +20 -3
- data/lib/openc3/utilities/bucket.rb +1 -1
- data/lib/openc3/utilities/bucket_file_cache.rb +1 -1
- data/lib/openc3/utilities/bucket_utilities.rb +1 -1
- data/lib/openc3/utilities/local_mode.rb +1 -0
- data/lib/openc3/utilities/metric.rb +77 -101
- data/lib/openc3/utilities/redis_secrets.rb +46 -0
- data/lib/openc3/utilities/s3_autoload.rb +19 -9
- data/lib/openc3/utilities/secrets.rb +63 -0
- data/lib/openc3/utilities/target_file.rb +3 -1
- data/lib/openc3/version.rb +5 -5
- data/templates/plugin-template/LICENSE.txt +7 -0
- data/templates/plugin-template/README.md +4 -3
- data/templates/plugin-template/plugin.gemspec +4 -4
- metadata +22 -3
- data/data/config/_interfaces.yaml.err +0 -1017
data/lib/openc3/interfaces.rb
CHANGED
@@ -17,11 +17,12 @@
|
|
17
17
|
# All changes Copyright 2022, OpenC3, Inc.
|
18
18
|
# All Rights Reserved
|
19
19
|
#
|
20
|
-
# This file may also be used under the terms of a commercial license
|
20
|
+
# This file may also be used under the terms of a commercial license
|
21
21
|
# if purchased from OpenC3, Inc.
|
22
22
|
|
23
23
|
module OpenC3
|
24
24
|
autoload(:Interface, 'openc3/interfaces/interface.rb')
|
25
|
+
autoload(:MqttInterface, 'openc3/interfaces/mqtt_interface.rb')
|
25
26
|
autoload(:StreamInterface, 'openc3/interfaces/stream_interface.rb')
|
26
27
|
autoload(:SerialInterface, 'openc3/interfaces/serial_interface.rb')
|
27
28
|
autoload(:SimulatedTargetInterface, 'openc3/interfaces/simulated_target_interface.rb')
|
@@ -31,7 +32,6 @@ module OpenC3
|
|
31
32
|
autoload(:LincInterface, 'openc3/interfaces/linc_interface.rb')
|
32
33
|
autoload(:LincHandshakeCommand, 'openc3/interfaces/linc_interface.rb')
|
33
34
|
autoload(:LincHandshake, 'openc3/interfaces/linc_interface.rb')
|
34
|
-
autoload(:DartStatusInterface, 'openc3/interfaces/dart_status_interface.rb')
|
35
35
|
|
36
36
|
autoload(:Protocol, 'openc3/interfaces/protocols/protocol.rb')
|
37
37
|
autoload(:BurstProtocol, 'openc3/interfaces/protocols/burst_protocol.rb')
|
@@ -41,7 +41,6 @@ module OpenC3
|
|
41
41
|
autoload(:TemplateProtocol, 'openc3/interfaces/protocols/template_protocol.rb')
|
42
42
|
autoload(:TerminatedProtocol, 'openc3/interfaces/protocols/terminated_protocol.rb')
|
43
43
|
|
44
|
-
autoload(:OverrideProtocol, 'openc3/interfaces/protocols/override_protocol.rb')
|
45
44
|
autoload(:CrcProtocol, 'openc3/interfaces/protocols/crc_protocol.rb')
|
46
45
|
autoload(:IgnorePacketProtocol, 'openc3/interfaces/protocols/ignore_packet_protocol.rb')
|
47
46
|
end
|
@@ -31,8 +31,8 @@ module OpenC3
|
|
31
31
|
@buffer_depth = buffer_depth
|
32
32
|
end
|
33
33
|
|
34
|
-
def next_packet_time
|
35
|
-
fill_buffer()
|
34
|
+
def next_packet_time(identify_and_define = true)
|
35
|
+
fill_buffer(identify_and_define)
|
36
36
|
packet = @buffer[0]
|
37
37
|
return packet.packet_time if packet
|
38
38
|
return nil
|
@@ -27,6 +27,14 @@ require 'openc3/utilities/bucket_utilities'
|
|
27
27
|
|
28
28
|
module OpenC3
|
29
29
|
class CleanupMicroservice < Microservice
|
30
|
+
def initialize(*args)
|
31
|
+
super(*args)
|
32
|
+
@metric.set(name: 'cleanup_total', value: @count, type: 'counter')
|
33
|
+
@delete_count = 0
|
34
|
+
@metric.set(name: 'cleanup_delete_total', value: @delete_count, type: 'counter')
|
35
|
+
@sleeper = Sleeper.new
|
36
|
+
end
|
37
|
+
|
30
38
|
def run
|
31
39
|
split_name = @name.split("__")
|
32
40
|
target_name = split_name[-1]
|
@@ -55,15 +63,23 @@ module OpenC3
|
|
55
63
|
oldest_list.each_slice(1000) do |slice|
|
56
64
|
bucket.delete_objects(bucket: ENV['OPENC3_LOGS_BUCKET'], keys: slice)
|
57
65
|
@logger.info("Deleted #{slice.length} #{target_name} log files")
|
66
|
+
@delete_count += slice.length
|
67
|
+
@metric.set(name: 'cleanup_delete_total', value: @delete_count, type: 'counter')
|
58
68
|
end
|
59
69
|
end
|
60
70
|
end
|
61
71
|
|
62
72
|
@count += 1
|
73
|
+
@metric.set(name: 'cleanup_total', value: @count, type: 'counter')
|
63
74
|
@state = 'SLEEPING'
|
64
|
-
break if @
|
75
|
+
break if @sleeper.sleep(target.cleanup_poll_time)
|
65
76
|
end
|
66
77
|
end
|
78
|
+
|
79
|
+
def shutdown
|
80
|
+
@sleeper.cancel
|
81
|
+
super()
|
82
|
+
end
|
67
83
|
end
|
68
84
|
end
|
69
85
|
|
@@ -28,15 +28,14 @@ require 'openc3/models/notification_model'
|
|
28
28
|
|
29
29
|
module OpenC3
|
30
30
|
class DecomMicroservice < Microservice
|
31
|
-
DECOM_METRIC_NAME = "decom_packet_duration_seconds"
|
32
|
-
LIMIT_METRIC_NAME = "limits_change_callback_duration_seconds"
|
33
|
-
NS_PER_MSEC = 1000000
|
34
|
-
|
35
31
|
def initialize(*args)
|
36
32
|
super(*args)
|
37
33
|
Topic.update_topic_offsets(@topics)
|
38
34
|
System.telemetry.limits_change_callback = method(:limits_change_callback)
|
39
35
|
LimitsEventTopic.sync_system(scope: @scope)
|
36
|
+
@error_count = 0
|
37
|
+
@metric.set(name: 'decom_total', value: @count, type: 'counter')
|
38
|
+
@metric.set(name: 'decom_error_total', value: @error_count, type: 'counter')
|
40
39
|
end
|
41
40
|
|
42
41
|
def run
|
@@ -50,18 +49,25 @@ module OpenC3
|
|
50
49
|
|
51
50
|
decom_packet(topic, msg_id, msg_hash, redis)
|
52
51
|
@count += 1
|
52
|
+
@metric.set(name: 'decom_total', value: @count, type: 'counter')
|
53
53
|
end
|
54
54
|
end
|
55
55
|
LimitsEventTopic.sync_system_thread_body(scope: @scope)
|
56
56
|
rescue => e
|
57
|
+
@error_count += 1
|
58
|
+
@metric.set(name: 'decom_error_total', value: @error_count, type: 'counter')
|
57
59
|
@error = e
|
58
60
|
@logger.error("Decom error: #{e.formatted}")
|
59
61
|
end
|
60
62
|
end
|
61
63
|
end
|
62
64
|
|
63
|
-
def decom_packet(topic,
|
65
|
+
def decom_packet(topic, msg_id, msg_hash, _redis)
|
64
66
|
OpenC3.in_span("decom_packet") do
|
67
|
+
msgid_seconds_from_epoch = msg_id.split('-')[0].to_i / 1000.0
|
68
|
+
delta = Time.now.to_f - msgid_seconds_from_epoch
|
69
|
+
@metric.set(name: 'decom_topic_delta_seconds', value: delta, type: 'gauge', unit: 'seconds', help: 'Delta time between data written to stream and decom start')
|
70
|
+
|
65
71
|
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
66
72
|
target_name = msg_hash["target_name"]
|
67
73
|
packet_name = msg_hash["packet_name"]
|
@@ -75,8 +81,7 @@ module OpenC3
|
|
75
81
|
|
76
82
|
TelemetryDecomTopic.write_packet(packet, scope: @scope)
|
77
83
|
diff = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start # seconds as a float
|
78
|
-
|
79
|
-
@metric.add_sample(name: DECOM_METRIC_NAME, value: diff, labels: metric_labels)
|
84
|
+
@metric.set(name: 'decom_duration_seconds', value: diff, type: 'gauge', unit: 'seconds')
|
80
85
|
end
|
81
86
|
end
|
82
87
|
|
@@ -133,8 +138,6 @@ module OpenC3
|
|
133
138
|
end
|
134
139
|
|
135
140
|
diff = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start # seconds as a float
|
136
|
-
labels = { "packet" => packet.packet_name, "target" => packet.target_name }
|
137
|
-
@metric.add_sample(name: LIMIT_METRIC_NAME, value: diff, labels: labels)
|
138
141
|
end
|
139
142
|
end
|
140
143
|
end
|
@@ -33,12 +33,17 @@ require 'openc3/topics/router_topic'
|
|
33
33
|
|
34
34
|
module OpenC3
|
35
35
|
class InterfaceCmdHandlerThread
|
36
|
-
def initialize(interface, tlm, logger: nil, scope:)
|
36
|
+
def initialize(interface, tlm, logger: nil, metric: nil, scope:)
|
37
37
|
@interface = interface
|
38
38
|
@tlm = tlm
|
39
39
|
@scope = scope
|
40
40
|
@logger = logger
|
41
41
|
@logger = Logger unless @logger
|
42
|
+
@metric = metric
|
43
|
+
@count = 0
|
44
|
+
@directive_count = 0
|
45
|
+
@metric.set(name: 'interface_directive_total', value: @directive_count, type: 'counter') if @metric
|
46
|
+
@metric.set(name: 'interface_cmd_total', value: @count, type: 'counter') if @metric
|
42
47
|
end
|
43
48
|
|
44
49
|
def start
|
@@ -59,10 +64,16 @@ module OpenC3
|
|
59
64
|
end
|
60
65
|
|
61
66
|
def run
|
62
|
-
InterfaceTopic.receive_commands(@interface, scope: @scope) do |topic, msg_hash|
|
67
|
+
InterfaceTopic.receive_commands(@interface, scope: @scope) do |topic, msg_id, msg_hash, redis|
|
63
68
|
OpenC3.with_context(msg_hash) do
|
69
|
+
msgid_seconds_from_epoch = msg_id.split('-')[0].to_i / 1000.0
|
70
|
+
delta = Time.now.to_f - msgid_seconds_from_epoch
|
71
|
+
@metric.set(name: 'interface_topic_delta_seconds', value: delta, type: 'gauge', unit: 'seconds', help: 'Delta time between data written to stream and interface cmd start') if @metric
|
72
|
+
|
64
73
|
# Check for a raw write to the interface
|
65
74
|
if topic =~ /CMD}INTERFACE/
|
75
|
+
@directive_count += 1
|
76
|
+
@metric.set(name: 'interface_directive_total', value: @directive_count, type: 'counter') if @metric
|
66
77
|
if msg_hash['shutdown']
|
67
78
|
@logger.info "#{@interface.name}: Shutdown requested"
|
68
79
|
return
|
@@ -107,6 +118,28 @@ module OpenC3
|
|
107
118
|
end
|
108
119
|
next 'SUCCESS'
|
109
120
|
end
|
121
|
+
if msg_hash.key?('interface_cmd')
|
122
|
+
params = JSON.parse(msg_hash['interface_cmd'], allow_nan: true, create_additions: true)
|
123
|
+
begin
|
124
|
+
@logger.info "#{@interface.name}: interface_cmd: #{params['cmd_name']} #{params['cmd_params'].join(' ')}"
|
125
|
+
@interface.interface_cmd(params['cmd_name'], params['cmd_params'])
|
126
|
+
rescue => e
|
127
|
+
@logger.error "#{@interface.name}: interface_cmd: #{e.formatted}"
|
128
|
+
next e.message
|
129
|
+
end
|
130
|
+
next 'SUCCESS'
|
131
|
+
end
|
132
|
+
if msg_hash.key?('protocol_cmd')
|
133
|
+
params = JSON.parse(msg_hash['protocol_cmd'], allow_nan: true, create_additions: true)
|
134
|
+
begin
|
135
|
+
@logger.info "#{@interface.name}: protocol_cmd: #{params['cmd_name']} #{params['cmd_params'].join(' ')} read_write: #{params['read_write']} index: #{params['index']}"
|
136
|
+
@interface.protocol_cmd(params['cmd_name'], params['cmd_params'], read_write: params['read_write'], index: params['index'])
|
137
|
+
rescue => e
|
138
|
+
@logger.error "#{@interface.name}: protocol_cmd: #{e.formatted}"
|
139
|
+
next e.message
|
140
|
+
end
|
141
|
+
next 'SUCCESS'
|
142
|
+
end
|
110
143
|
end
|
111
144
|
|
112
145
|
target_name = msg_hash['target_name']
|
@@ -158,6 +191,9 @@ module OpenC3
|
|
158
191
|
|
159
192
|
begin
|
160
193
|
if @interface.connected?
|
194
|
+
@count += 1
|
195
|
+
@metric.set(name: 'interface_cmd_total', value: @count, type: 'counter') if @metric
|
196
|
+
|
161
197
|
@interface.write(command)
|
162
198
|
CommandTopic.write_packet(command, scope: @scope)
|
163
199
|
CommandDecomTopic.write_packet(command, scope: @scope)
|
@@ -180,12 +216,17 @@ module OpenC3
|
|
180
216
|
end
|
181
217
|
|
182
218
|
class RouterTlmHandlerThread
|
183
|
-
def initialize(router, tlm, logger: nil, scope:)
|
219
|
+
def initialize(router, tlm, logger: nil, metric: nil, scope:)
|
184
220
|
@router = router
|
185
221
|
@tlm = tlm
|
186
222
|
@scope = scope
|
187
223
|
@logger = logger
|
188
224
|
@logger = Logger unless @logger
|
225
|
+
@metric = metric
|
226
|
+
@count = 0
|
227
|
+
@directive_count = 0
|
228
|
+
@metric.set(name: 'router_directive_total', value: @directive_count, type: 'counter') if @metric
|
229
|
+
@metric.set(name: 'router_tlm_total', value: @count, type: 'counter') if @metric
|
189
230
|
end
|
190
231
|
|
191
232
|
def start
|
@@ -206,9 +247,16 @@ module OpenC3
|
|
206
247
|
end
|
207
248
|
|
208
249
|
def run
|
209
|
-
RouterTopic.receive_telemetry(@router, scope: @scope) do |topic, msg_hash|
|
250
|
+
RouterTopic.receive_telemetry(@router, scope: @scope) do |topic, msg_id, msg_hash, redis|
|
251
|
+
msgid_seconds_from_epoch = msg_id.split('-')[0].to_i / 1000.0
|
252
|
+
delta = Time.now.to_f - msgid_seconds_from_epoch
|
253
|
+
@metric.set(name: 'router_topic_delta_seconds', value: delta, type: 'gauge', unit: 'seconds', help: 'Delta time between data written to stream and router tlm start') if @metric
|
254
|
+
|
210
255
|
# Check for commands to the router itself
|
211
256
|
if /CMD}ROUTER/.match?(topic)
|
257
|
+
@directive_count += 1
|
258
|
+
@metric.set(name: 'router_directive_total', value: @directive_count, type: 'counter') if @metric
|
259
|
+
|
212
260
|
if msg_hash['shutdown']
|
213
261
|
@logger.info "#{@router.name}: Shutdown requested"
|
214
262
|
return
|
@@ -234,10 +282,35 @@ module OpenC3
|
|
234
282
|
@router.stop_raw_logging
|
235
283
|
end
|
236
284
|
end
|
285
|
+
if msg_hash.key?('router_cmd')
|
286
|
+
params = JSON.parse(msg_hash['router_cmd'], allow_nan: true, create_additions: true)
|
287
|
+
begin
|
288
|
+
@logger.info "#{@router.name}: router_cmd: #{params['cmd_name']} #{params['cmd_params'].join(' ')}"
|
289
|
+
@router.interface_cmd(params['cmd_name'], params['cmd_params'])
|
290
|
+
rescue => e
|
291
|
+
@logger.error "#{@router.name}: router_cmd: #{e.formatted}"
|
292
|
+
next e.message
|
293
|
+
end
|
294
|
+
next 'SUCCESS'
|
295
|
+
end
|
296
|
+
if msg_hash.key?('protocol_cmd')
|
297
|
+
params = JSON.parse(msg_hash['protocol_cmd'], allow_nan: true, create_additions: true)
|
298
|
+
begin
|
299
|
+
@logger.info "#{@router.name}: protocol_cmd: #{params['cmd_name']} #{params['cmd_params'].join(' ')} read_write: #{params['read_write']} index: #{params['index']}"
|
300
|
+
@router.protocol_cmd(params['cmd_name'], params['cmd_params'], read_write: params['read_write'], index: params['index'])
|
301
|
+
rescue => e
|
302
|
+
@logger.error "#{@router.name}: protoco_cmd: #{e.formatted}"
|
303
|
+
next e.message
|
304
|
+
end
|
305
|
+
next 'SUCCESS'
|
306
|
+
end
|
237
307
|
next 'SUCCESS'
|
238
308
|
end
|
239
309
|
|
240
310
|
if @router.connected?
|
311
|
+
@count += 1
|
312
|
+
@metric.set(name: 'router_tlm_total', value: @count, type: 'counter') if @metric
|
313
|
+
|
241
314
|
target_name = msg_hash["target_name"]
|
242
315
|
packet_name = msg_hash["packet_name"]
|
243
316
|
|
@@ -264,7 +337,14 @@ module OpenC3
|
|
264
337
|
UNKNOWN_BYTES_TO_PRINT = 16
|
265
338
|
|
266
339
|
def initialize(name)
|
340
|
+
@mutex = Mutex.new
|
267
341
|
super(name)
|
342
|
+
if @interface_or_router == 'INTERFACE'
|
343
|
+
@metric.set(name: 'interface_tlm_total', value: @count, type: 'counter')
|
344
|
+
else
|
345
|
+
@metric.set(name: 'router_cmd_total', value: @count, type: 'counter')
|
346
|
+
end
|
347
|
+
|
268
348
|
@interface_or_router = self.class.name.to_s.split("Microservice")[0].upcase.split("::")[-1]
|
269
349
|
@scope = name.split("__")[0]
|
270
350
|
interface_name = name.split("__")[2]
|
@@ -307,11 +387,10 @@ module OpenC3
|
|
307
387
|
@cancel_thread = false
|
308
388
|
@connection_failed_messages = []
|
309
389
|
@connection_lost_messages = []
|
310
|
-
@mutex = Mutex.new
|
311
390
|
if @interface_or_router == 'INTERFACE'
|
312
|
-
@handler_thread = InterfaceCmdHandlerThread.new(@interface, self, logger: @logger, scope: @scope)
|
391
|
+
@handler_thread = InterfaceCmdHandlerThread.new(@interface, self, logger: @logger, metric: @metric, scope: @scope)
|
313
392
|
else
|
314
|
-
@handler_thread = RouterTlmHandlerThread.new(@interface, self, logger: @logger, scope: @scope)
|
393
|
+
@handler_thread = RouterTlmHandlerThread.new(@interface, self, logger: @logger, metric: @metric, scope: @scope)
|
315
394
|
end
|
316
395
|
@handler_thread.start
|
317
396
|
end
|
@@ -382,6 +461,11 @@ module OpenC3
|
|
382
461
|
if packet
|
383
462
|
handle_packet(packet)
|
384
463
|
@count += 1
|
464
|
+
if @interface_or_router == 'INTERFACE'
|
465
|
+
@metric.set(name: 'interface_tlm_total', value: @count, type: 'counter')
|
466
|
+
else
|
467
|
+
@metric.set(name: 'router_cmd_total', value: @count, type: 'counter')
|
468
|
+
end
|
385
469
|
else
|
386
470
|
@logger.info "#{@interface.name}: Internal disconnect requested (returned nil)"
|
387
471
|
handle_connection_lost()
|
@@ -560,7 +644,7 @@ module OpenC3
|
|
560
644
|
|
561
645
|
# Disconnect from the interface and stop the thread
|
562
646
|
def stop
|
563
|
-
@logger.info "#{@interface.name}: stop requested"
|
647
|
+
@logger.info "#{@interface ? @interface.name : @name}: stop requested"
|
564
648
|
@mutex.synchronize do
|
565
649
|
# Need to make sure that @cancel_thread is set and the interface disconnected within
|
566
650
|
# mutex to ensure that connect() is not called when we want to stop()
|
@@ -578,7 +662,7 @@ module OpenC3
|
|
578
662
|
end
|
579
663
|
|
580
664
|
def shutdown(sig = nil)
|
581
|
-
@logger.info "#{@interface.name}: shutdown requested"
|
665
|
+
@logger.info "#{@interface ? @interface.name : @name}: shutdown requested"
|
582
666
|
stop()
|
583
667
|
super()
|
584
668
|
end
|
@@ -55,6 +55,9 @@ module OpenC3
|
|
55
55
|
@cycle_size = 50_000_000 unless @cycle_size # ~50 MB
|
56
56
|
|
57
57
|
@buffer_depth = DEFAULT_BUFFER_DEPTH unless @buffer_depth
|
58
|
+
@error_count = 0
|
59
|
+
@metric.set(name: 'log_total', value: @count, type: 'counter')
|
60
|
+
@metric.set(name: 'log_error_total', value: @error_count, type: 'counter')
|
58
61
|
end
|
59
62
|
|
60
63
|
def run
|
@@ -65,6 +68,8 @@ module OpenC3
|
|
65
68
|
Topic.read_topics(@topics) do |topic, msg_id, msg_hash, redis|
|
66
69
|
break if @cancel_thread
|
67
70
|
log_data(topic, msg_id, msg_hash, redis)
|
71
|
+
@count += 1
|
72
|
+
@metric.set(name: 'log_total', value: @count, type: 'counter')
|
68
73
|
end
|
69
74
|
end
|
70
75
|
end
|
@@ -88,7 +93,10 @@ module OpenC3
|
|
88
93
|
end
|
89
94
|
|
90
95
|
def log_data(topic, msg_id, msg_hash, redis)
|
91
|
-
|
96
|
+
msgid_seconds_from_epoch = msg_id.split('-')[0].to_i / 1000.0
|
97
|
+
delta = Time.now.to_f - msgid_seconds_from_epoch
|
98
|
+
@metric.set(name: 'log_topic_delta_seconds', value: delta, type: 'gauge', unit: 'seconds', help: 'Delta time between data written to stream and log start')
|
99
|
+
|
92
100
|
topic_split = topic.gsub(/{|}/, '').split("__") # Remove the redis hashtag curly braces
|
93
101
|
target_name = topic_split[2]
|
94
102
|
packet_name = topic_split[3]
|
@@ -103,13 +111,11 @@ module OpenC3
|
|
103
111
|
data_key = "json_data"
|
104
112
|
end
|
105
113
|
@plws[target_name][rt_or_stored].buffered_write(packet_type, @cmd_or_tlm, target_name, packet_name, msg_hash["time"].to_i, rt_or_stored == :STORED, msg_hash[data_key], nil, topic, msg_id)
|
106
|
-
@count += 1
|
107
|
-
diff = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start # seconds as a float
|
108
|
-
metric_labels = { "packet" => packet_name, "target" => target_name, "raw_or_decom" => @raw_or_decom.to_s, "cmd_or_tlm" => @cmd_or_tlm.to_s }
|
109
|
-
@metric.add_sample(name: "log_duration_seconds", value: diff, labels: metric_labels)
|
110
114
|
rescue => err
|
111
115
|
@error = err
|
112
116
|
@logger.error("#{@name} error: #{err.formatted}")
|
117
|
+
@error_count += 1
|
118
|
+
@metric.set(name: 'log_error_total', value: @error_count, type: 'counter')
|
113
119
|
end
|
114
120
|
|
115
121
|
def shutdown
|
@@ -27,6 +27,7 @@ OpenC3.require_file 'fileutils'
|
|
27
27
|
OpenC3.require_file 'openc3/utilities/zip'
|
28
28
|
OpenC3.require_file 'openc3/utilities/store'
|
29
29
|
OpenC3.require_file 'openc3/utilities/bucket'
|
30
|
+
OpenC3.require_file 'openc3/utilities/secrets'
|
30
31
|
OpenC3.require_file 'openc3/utilities/sleeper'
|
31
32
|
OpenC3.require_file 'openc3/utilities/open_telemetry'
|
32
33
|
OpenC3.require_file 'openc3/models/microservice_model'
|
@@ -43,6 +44,7 @@ module OpenC3
|
|
43
44
|
attr_accessor :custom
|
44
45
|
attr_accessor :scope
|
45
46
|
attr_accessor :logger
|
47
|
+
attr_accessor :secrets
|
46
48
|
|
47
49
|
def self.run(name = nil)
|
48
50
|
name = ENV['OPENC3_MICROSERVICE_NAME'] unless name
|
@@ -93,6 +95,7 @@ module OpenC3
|
|
93
95
|
@logger = Logger.new
|
94
96
|
@logger.scope = @scope
|
95
97
|
@logger.microservice_name = @name
|
98
|
+
@secrets = Secrets.getClient
|
96
99
|
|
97
100
|
OpenC3.setup_open_telemetry(@name, false)
|
98
101
|
|
@@ -104,6 +107,9 @@ module OpenC3
|
|
104
107
|
if @config
|
105
108
|
@topics = @config['topics']
|
106
109
|
@plugin = @config['plugin']
|
110
|
+
if @config['secrets']
|
111
|
+
@secrets.setup(@config['secrets'])
|
112
|
+
end
|
107
113
|
else
|
108
114
|
@config = {}
|
109
115
|
@plugin = nil
|
@@ -125,7 +131,6 @@ module OpenC3
|
|
125
131
|
@error = nil
|
126
132
|
@custom = nil
|
127
133
|
@state = 'INITIALIZED'
|
128
|
-
metric_name = "metric_output_duration_seconds"
|
129
134
|
@work_dir = @config["work_dir"]
|
130
135
|
|
131
136
|
if is_plugin
|
@@ -174,16 +179,12 @@ module OpenC3
|
|
174
179
|
end
|
175
180
|
end
|
176
181
|
else
|
177
|
-
@
|
182
|
+
@microservice_status_sleeper = Sleeper.new
|
178
183
|
@microservice_status_period_seconds = 5
|
179
184
|
@microservice_status_thread = Thread.new do
|
180
185
|
until @cancel_thread
|
181
|
-
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
182
|
-
@metric.output
|
183
|
-
diff = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start # seconds as a float
|
184
|
-
@metric.add_sample(name: metric_name, value: diff, labels: {})
|
185
186
|
MicroserviceStatusModel.set(as_json(:allow_nan => true), scope: @scope) unless @cancel_thread
|
186
|
-
break if @
|
187
|
+
break if @microservice_status_sleeper.sleep(@microservice_status_period_seconds)
|
187
188
|
end
|
188
189
|
rescue Exception => err
|
189
190
|
@logger.error "#{@name} status thread died: #{err.formatted}"
|
@@ -200,10 +201,10 @@ module OpenC3
|
|
200
201
|
def shutdown
|
201
202
|
@logger.info("Shutting down microservice: #{@name}")
|
202
203
|
@cancel_thread = true
|
203
|
-
@
|
204
|
+
@microservice_status_sleeper.cancel if @microservice_status_sleeper
|
204
205
|
MicroserviceStatusModel.set(as_json(:allow_nan => true), scope: @scope)
|
205
206
|
FileUtils.remove_entry(@temp_dir) if File.exist?(@temp_dir)
|
206
|
-
@metric.
|
207
|
+
@metric.shutdown
|
207
208
|
@logger.info("Shutting down microservice complete: #{@name}")
|
208
209
|
end
|
209
210
|
end
|
@@ -24,6 +24,11 @@ module OpenC3
|
|
24
24
|
STARTUP_DELAY_SECONDS = 2 * 60 # Two Minutes
|
25
25
|
SLEEP_PERIOD_SECONDS = 24 * 60 * 60 # Run once per day
|
26
26
|
|
27
|
+
def initialize(*args)
|
28
|
+
super(*args)
|
29
|
+
@metric.set(name: 'periodic_total', value: @count, type: 'counter')
|
30
|
+
end
|
31
|
+
|
27
32
|
def run
|
28
33
|
@run_sleeper = Sleeper.new
|
29
34
|
return if @run_sleeper.sleep(STARTUP_DELAY_SECONDS)
|
@@ -43,6 +48,8 @@ module OpenC3
|
|
43
48
|
model.update
|
44
49
|
end
|
45
50
|
end
|
51
|
+
@count += 1
|
52
|
+
@metric.set(name: 'periodic_total', value: @count, type: 'counter')
|
46
53
|
break if @cancel_thread
|
47
54
|
break if @run_sleeper.sleep(SLEEP_PERIOD_SECONDS)
|
48
55
|
end
|
@@ -222,8 +222,6 @@ module OpenC3
|
|
222
222
|
# queues a trigger to evaluate against the reactions. The worker will check
|
223
223
|
# the reactions to see if it needs to fire any reactions.
|
224
224
|
class ReactionWorker
|
225
|
-
REACTION_METRIC_NAME = 'reaction_duration_seconds'.freeze
|
226
|
-
|
227
225
|
attr_reader :name, :scope, :share
|
228
226
|
|
229
227
|
def initialize(name:, logger:, scope:, share:, ident:)
|
@@ -232,8 +230,6 @@ module OpenC3
|
|
232
230
|
@scope = scope
|
233
231
|
@share = share
|
234
232
|
@ident = ident
|
235
|
-
@metric_output_time = 0
|
236
|
-
@metric = Metric.new(microservice: @name, scope: @scope)
|
237
233
|
end
|
238
234
|
|
239
235
|
def get_token(username)
|
@@ -269,10 +265,6 @@ module OpenC3
|
|
269
265
|
process_enabled_trigger(data: data)
|
270
266
|
end
|
271
267
|
current_time = Time.now.to_i
|
272
|
-
if @metric_output_time < current_time
|
273
|
-
@metric.output
|
274
|
-
@metric_output_time = current_time + 120
|
275
|
-
end
|
276
268
|
rescue StandardError => e
|
277
269
|
@logger.error "ReactionWorker-#{@ident} failed to evaluate kind: #{kind} data: #{data}\n#{e.formatted}"
|
278
270
|
end
|
@@ -281,24 +273,16 @@ module OpenC3
|
|
281
273
|
end
|
282
274
|
|
283
275
|
def process_enabled_trigger(data:)
|
284
|
-
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
285
276
|
@share.reaction_base.get_reactions(trigger_name: data['name']).each do | reaction |
|
286
277
|
run_reaction(reaction: reaction)
|
287
278
|
end
|
288
|
-
diff = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start # seconds as a float
|
289
|
-
metric_labels = { 'type' => 'trigger', 'thread' => "worker-#{@ident}" }
|
290
|
-
@metric.add_sample(name: REACTION_METRIC_NAME, value: diff, labels: metric_labels)
|
291
279
|
end
|
292
280
|
|
293
281
|
def run_reaction(reaction:)
|
294
|
-
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
295
282
|
reaction.actions.each do |action|
|
296
283
|
run_action(reaction: reaction, action: action)
|
297
284
|
end
|
298
285
|
@share.reaction_base.sleep(name: reaction.name)
|
299
|
-
diff = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start # seconds as a float
|
300
|
-
metric_labels = { 'type' => 'reaction', 'thread' => "worker-#{@ident}" }
|
301
|
-
@metric.add_sample(name: REACTION_METRIC_NAME, value: diff, labels: metric_labels)
|
302
286
|
end
|
303
287
|
|
304
288
|
def run_action(reaction:, action:)
|
@@ -354,8 +338,6 @@ module OpenC3
|
|
354
338
|
# The reaction snooze manager starts a thread pool and keeps track of when a
|
355
339
|
# reaction is activated and to evalute triggers when the snooze is complete.
|
356
340
|
class ReactionSnoozeManager
|
357
|
-
SNOOZE_METRIC_NAME = 'snooze_manager_duration_seconds'.freeze
|
358
|
-
|
359
341
|
attr_reader :name, :scope, :share, :thread_pool
|
360
342
|
|
361
343
|
def initialize(name:, logger:, scope:, share:)
|
@@ -366,8 +348,6 @@ module OpenC3
|
|
366
348
|
@worker_count = 3
|
367
349
|
@thread_pool = nil
|
368
350
|
@cancel_thread = false
|
369
|
-
@metric = Metric.new(microservice: @name, scope: @scope)
|
370
|
-
@metric_output_time = 0
|
371
351
|
end
|
372
352
|
|
373
353
|
def generate_thread_pool()
|
@@ -385,15 +365,7 @@ module OpenC3
|
|
385
365
|
loop do
|
386
366
|
begin
|
387
367
|
current_time = Time.now.to_i
|
388
|
-
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
389
368
|
manage_snoozed_reactions(current_time: current_time)
|
390
|
-
diff = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start # seconds as a float
|
391
|
-
metric_labels = { 'type' => 'snooze', 'thread' => "manager" }
|
392
|
-
@metric.add_sample(name: SNOOZE_METRIC_NAME, value: diff, labels: metric_labels)
|
393
|
-
if @metric_output_time < current_time
|
394
|
-
@metric.output
|
395
|
-
@metric_output_time = current_time + 120
|
396
|
-
end
|
397
369
|
rescue StandardError => e
|
398
370
|
@logger.error "ReactionSnoozeManager failed to snooze reactions.\n#{e.formatted}"
|
399
371
|
end
|
@@ -443,8 +415,6 @@ module OpenC3
|
|
443
415
|
# reactions and triggers from redis. It then monitors the
|
444
416
|
# AutonomicTopic for changes.
|
445
417
|
class ReactionMicroservice < Microservice
|
446
|
-
ACTION_METRIC_NAME = 'reactions_duration_seconds'.freeze
|
447
|
-
|
448
418
|
attr_reader :name, :scope, :share, :manager, :manager_thread
|
449
419
|
|
450
420
|
def initialize(*args)
|
@@ -459,11 +429,8 @@ module OpenC3
|
|
459
429
|
@logger.info "ReactionMicroservice running"
|
460
430
|
@manager_thread = Thread.new { @manager.run }
|
461
431
|
loop do
|
462
|
-
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
463
432
|
reactions = ReactionModel.all(scope: @scope)
|
464
433
|
@share.reaction_base.setup(reactions: reactions)
|
465
|
-
diff = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start # seconds as a float
|
466
|
-
@metric.add_sample(name: ACTION_METRIC_NAME, value: diff, labels: { 'thread' => 'microservice' })
|
467
434
|
break if @cancel_thread
|
468
435
|
|
469
436
|
block_for_updates()
|
@@ -73,9 +73,9 @@ module OpenC3
|
|
73
73
|
end
|
74
74
|
|
75
75
|
class ReducerMicroservice < Microservice
|
76
|
-
MINUTE_METRIC = '
|
77
|
-
HOUR_METRIC = '
|
78
|
-
DAY_METRIC = '
|
76
|
+
MINUTE_METRIC = 'reducer_minute_processing_seconds'
|
77
|
+
HOUR_METRIC = 'reducer_hour_processing_seconds'
|
78
|
+
DAY_METRIC = 'reducer_day_processing_seconds'
|
79
79
|
|
80
80
|
# How long to wait for any currently running jobs to complete before killing them
|
81
81
|
SHUTDOWN_DELAY_SECS = 5
|
@@ -105,6 +105,10 @@ module OpenC3
|
|
105
105
|
@buffer_depth = 10 unless @buffer_depth
|
106
106
|
@target_name = name.split('__')[-1]
|
107
107
|
@packet_logs = {}
|
108
|
+
|
109
|
+
@error_count = 0
|
110
|
+
@metric.set(name: 'reducer_total', value: @count, type: 'counter')
|
111
|
+
@metric.set(name: 'reducer_error_total', value: @error_count, type: 'counter')
|
108
112
|
end
|
109
113
|
|
110
114
|
def run
|
@@ -148,13 +152,7 @@ module OpenC3
|
|
148
152
|
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
149
153
|
yield
|
150
154
|
elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start # seconds as a float
|
151
|
-
@metric.
|
152
|
-
name: name,
|
153
|
-
value: elapsed,
|
154
|
-
labels: {
|
155
|
-
'target' => @target_name,
|
156
|
-
},
|
157
|
-
)
|
155
|
+
@metric.set(name: name, value: elapsed, type: 'gauge', unit: 'seconds')
|
158
156
|
end
|
159
157
|
|
160
158
|
def reduce_minute
|
@@ -366,6 +364,10 @@ module OpenC3
|
|
366
364
|
file.delete # Remove the local copy
|
367
365
|
|
368
366
|
write_all_entries(reducer_state, plw, type, target_name, stored)
|
367
|
+
|
368
|
+
@count += 1
|
369
|
+
@metric.set(name: 'reducer_total', value: @count, type: 'counter')
|
370
|
+
|
369
371
|
true
|
370
372
|
rescue => e
|
371
373
|
if file.local_path and File.exist?(file.local_path)
|
@@ -373,6 +375,8 @@ module OpenC3
|
|
373
375
|
else
|
374
376
|
@logger.error("Reducer Error: #{filename}: \n#{e.formatted}")
|
375
377
|
end
|
378
|
+
@error_count += 1
|
379
|
+
@metric.set(name: 'reducer_error_total', value: @error_count, type: 'counter')
|
376
380
|
false
|
377
381
|
end
|
378
382
|
|