openc3 5.0.8 → 5.0.10
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.
Potentially problematic release.
This version of openc3 might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/bin/openc3cli +128 -95
- data/data/config/_id_items.yaml +2 -1
- data/data/config/_id_params.yaml +2 -1
- data/data/config/_items.yaml +2 -1
- data/data/config/_params.yaml +2 -1
- data/data/config/command_modifiers.yaml +30 -0
- data/data/config/item_modifiers.yaml +10 -0
- data/data/config/microservice.yaml +12 -0
- data/data/config/param_item_modifiers.yaml +10 -0
- data/data/config/plugins.yaml +0 -9
- data/data/config/telemetry_modifiers.yaml +10 -0
- data/data/config/widgets.yaml +49 -73
- data/ext/openc3/ext/packet/packet.c +20 -2
- data/ext/openc3/ext/structure/structure.c +12 -17
- data/lib/openc3/accessors/accessor.rb +71 -0
- data/lib/openc3/accessors/binary_accessor.rb +1226 -0
- data/lib/openc3/accessors/cbor_accessor.rb +83 -0
- data/lib/openc3/accessors/html_accessor.rb +28 -0
- data/lib/openc3/accessors/json_accessor.rb +131 -0
- data/lib/openc3/accessors/xml_accessor.rb +67 -0
- data/lib/openc3/accessors.rb +23 -0
- data/lib/openc3/api/cmd_api.rb +5 -2
- data/lib/openc3/api/interface_api.rb +15 -0
- data/lib/openc3/api/limits_api.rb +3 -3
- data/lib/openc3/config/config_parser.rb +10 -4
- data/lib/openc3/core_ext/file.rb +5 -0
- data/lib/openc3/core_ext/tempfile.rb +20 -0
- data/lib/openc3/io/json_rpc.rb +3 -3
- data/lib/openc3/microservices/cleanup_microservice.rb +7 -5
- data/lib/openc3/models/cvt_model.rb +1 -10
- data/lib/openc3/models/interface_model.rb +41 -0
- data/lib/openc3/models/microservice_model.rb +33 -1
- data/lib/openc3/models/plugin_model.rb +1 -1
- data/lib/openc3/models/target_model.rb +85 -68
- data/lib/openc3/packets/binary_accessor.rb +2 -1207
- data/lib/openc3/packets/packet.rb +106 -6
- data/lib/openc3/packets/packet_config.rb +30 -7
- data/lib/openc3/packets/parsers/limits_response_parser.rb +1 -3
- data/lib/openc3/packets/parsers/processor_parser.rb +1 -2
- data/lib/openc3/packets/parsers/xtce_parser.rb +68 -3
- data/lib/openc3/packets/structure.rb +39 -14
- data/lib/openc3/packets/structure_item.rb +15 -1
- data/lib/openc3/script/storage.rb +19 -1
- data/lib/openc3/utilities/local_mode.rb +521 -0
- data/lib/openc3/utilities/simulated_target.rb +3 -2
- data/lib/openc3/utilities/target_file.rb +146 -0
- data/lib/openc3/version.rb +5 -5
- data/lib/openc3.rb +1 -0
- metadata +45 -7
@@ -0,0 +1,83 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
# Copyright 2022 OpenC3, Inc.
|
4
|
+
# All Rights Reserved.
|
5
|
+
#
|
6
|
+
# This program is free software; you can modify and/or redistribute it
|
7
|
+
# under the terms of the GNU Affero General Public License
|
8
|
+
# as published by the Free Software Foundation; version 3 with
|
9
|
+
# attribution addendums as found in the LICENSE.txt
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
|
16
|
+
require 'cbor'
|
17
|
+
require 'openc3/accessors/json_accessor'
|
18
|
+
|
19
|
+
module OpenC3
|
20
|
+
class CborAccessor < JsonAccessor
|
21
|
+
def self.read_item(item, buffer)
|
22
|
+
return nil if item.data_type == :DERIVED
|
23
|
+
if String === buffer
|
24
|
+
parsed = CBOR.decode(buffer)
|
25
|
+
else
|
26
|
+
parsed = buffer
|
27
|
+
end
|
28
|
+
return super(item, parsed)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.write_item(item, value, buffer)
|
32
|
+
return nil if item.data_type == :DERIVED
|
33
|
+
|
34
|
+
# Convert to ruby objects
|
35
|
+
if String === buffer
|
36
|
+
decoded = CBOR.decode(buffer)
|
37
|
+
else
|
38
|
+
decoded = buffer
|
39
|
+
end
|
40
|
+
|
41
|
+
# Write the value
|
42
|
+
write_item_internal(item, value, decoded)
|
43
|
+
|
44
|
+
# Update buffer
|
45
|
+
if String === buffer
|
46
|
+
buffer.replace(decoded.to_cbor)
|
47
|
+
end
|
48
|
+
|
49
|
+
return buffer
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.read_items(items, buffer)
|
53
|
+
# Prevent JsonPath from decoding every call
|
54
|
+
if String === buffer
|
55
|
+
decoded = CBOR.decode(buffer)
|
56
|
+
else
|
57
|
+
decoded = buffer
|
58
|
+
end
|
59
|
+
super(items, decoded)
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.write_items(items, values, buffer)
|
63
|
+
# Convert to ruby objects
|
64
|
+
if String === buffer
|
65
|
+
decoded = CBOR.decode(buffer)
|
66
|
+
else
|
67
|
+
decoded = buffer
|
68
|
+
end
|
69
|
+
|
70
|
+
items.each_with_index do |item, index|
|
71
|
+
write_item_internal(item, values[index], decoded)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Update buffer
|
75
|
+
if String === buffer
|
76
|
+
buffer.replace(decoded.to_cbor)
|
77
|
+
end
|
78
|
+
|
79
|
+
return buffer
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
# Copyright 2022 OpenC3, Inc.
|
4
|
+
# All Rights Reserved.
|
5
|
+
#
|
6
|
+
# This program is free software; you can modify and/or redistribute it
|
7
|
+
# under the terms of the GNU Affero General Public License
|
8
|
+
# as published by the Free Software Foundation; version 3 with
|
9
|
+
# attribution addendums as found in the LICENSE.txt
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
|
16
|
+
require 'openc3/accessors/xml_accessor'
|
17
|
+
|
18
|
+
module OpenC3
|
19
|
+
class HtmlAccessor < XmlAccessor
|
20
|
+
def self.buffer_to_doc(buffer)
|
21
|
+
Nokogiri.HTML(buffer)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.doc_to_buffer(doc)
|
25
|
+
doc.to_html
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
# Copyright 2022 OpenC3, Inc.
|
4
|
+
# All Rights Reserved.
|
5
|
+
#
|
6
|
+
# This program is free software; you can modify and/or redistribute it
|
7
|
+
# under the terms of the GNU Affero General Public License
|
8
|
+
# as published by the Free Software Foundation; version 3 with
|
9
|
+
# attribution addendums as found in the LICENSE.txt
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
|
16
|
+
require 'json'
|
17
|
+
require 'jsonpath'
|
18
|
+
require 'openc3/accessors/accessor'
|
19
|
+
|
20
|
+
module OpenC3
|
21
|
+
class JsonAccessor < Accessor
|
22
|
+
def self.read_item(item, buffer)
|
23
|
+
return nil if item.data_type == :DERIVED
|
24
|
+
return JsonPath.on(buffer, item.key).first
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.write_item(item, value, buffer)
|
28
|
+
return nil if item.data_type == :DERIVED
|
29
|
+
|
30
|
+
# Convert to ruby objects
|
31
|
+
if String === buffer
|
32
|
+
decoded = JSON.parse(buffer, :allow_nan => true)
|
33
|
+
else
|
34
|
+
decoded = buffer
|
35
|
+
end
|
36
|
+
|
37
|
+
# Write the value
|
38
|
+
write_item_internal(item, value, decoded)
|
39
|
+
|
40
|
+
# Update buffer
|
41
|
+
if String === buffer
|
42
|
+
buffer.replace(JSON.generate(decoded, :allow_nan => true))
|
43
|
+
end
|
44
|
+
|
45
|
+
return buffer
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.read_items(items, buffer)
|
49
|
+
# Prevent JsonPath from decoding every call
|
50
|
+
if String === buffer
|
51
|
+
decoded = JSON.parse(buffer)
|
52
|
+
else
|
53
|
+
decoded = buffer
|
54
|
+
end
|
55
|
+
super(items, decoded)
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.write_items(items, values, buffer)
|
59
|
+
# Start with an empty object if no buffer
|
60
|
+
buffer.replace("{}") if buffer.length == 0 or buffer[0] == "\x00"
|
61
|
+
|
62
|
+
# Convert to ruby objects
|
63
|
+
if String === buffer
|
64
|
+
decoded = JSON.parse(buffer, :allow_nan => true)
|
65
|
+
else
|
66
|
+
decoded = buffer
|
67
|
+
end
|
68
|
+
|
69
|
+
items.each_with_index do |item, index|
|
70
|
+
write_item_internal(item, values[index], decoded)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Update buffer
|
74
|
+
if String === buffer
|
75
|
+
buffer.replace(JSON.generate(decoded, :allow_nan => true))
|
76
|
+
end
|
77
|
+
|
78
|
+
return buffer
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.write_item_internal(item, value, decoded)
|
82
|
+
return nil if item.data_type == :DERIVED
|
83
|
+
|
84
|
+
# Save traversal state
|
85
|
+
parent_node = nil
|
86
|
+
parent_key = nil
|
87
|
+
node = decoded
|
88
|
+
|
89
|
+
# Parse the JsonPath
|
90
|
+
json_path = JsonPath.new(item.key)
|
91
|
+
|
92
|
+
# Handle each token
|
93
|
+
json_path.path.each do |token|
|
94
|
+
case token
|
95
|
+
when '$'
|
96
|
+
# Ignore start - it is implied
|
97
|
+
next
|
98
|
+
when /\[.*\]/
|
99
|
+
# Array or Hash Index
|
100
|
+
if token.index("'") # Hash index
|
101
|
+
key = token[2..-3]
|
102
|
+
if not (Hash === node)
|
103
|
+
node = {}
|
104
|
+
parent_node[parent_key] = node
|
105
|
+
end
|
106
|
+
parent_node = node
|
107
|
+
parent_key = key
|
108
|
+
node = node[key]
|
109
|
+
else # Array index
|
110
|
+
key = token[1..-2].to_i
|
111
|
+
if not (Array === node)
|
112
|
+
node = []
|
113
|
+
parent_node[parent_key] = node
|
114
|
+
end
|
115
|
+
parent_node = node
|
116
|
+
parent_key = key
|
117
|
+
node = node[key]
|
118
|
+
end
|
119
|
+
else
|
120
|
+
raise "Unsupported key/token: #{item.key} - #{token}"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
if parent_node
|
124
|
+
parent_node[parent_key] = value
|
125
|
+
else
|
126
|
+
decoded.replace(value)
|
127
|
+
end
|
128
|
+
return decoded
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
# Copyright 2022 OpenC3, Inc.
|
4
|
+
# All Rights Reserved.
|
5
|
+
#
|
6
|
+
# This program is free software; you can modify and/or redistribute it
|
7
|
+
# under the terms of the GNU Affero General Public License
|
8
|
+
# as published by the Free Software Foundation; version 3 with
|
9
|
+
# attribution addendums as found in the LICENSE.txt
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
|
16
|
+
require 'nokogiri'
|
17
|
+
require 'openc3/accessors/accessor'
|
18
|
+
|
19
|
+
module OpenC3
|
20
|
+
class XmlAccessor < Accessor
|
21
|
+
def self.read_item(item, buffer)
|
22
|
+
return nil if item.data_type == :DERIVED
|
23
|
+
doc = buffer_to_doc(buffer)
|
24
|
+
return convert_to_type(doc.xpath(item.key).first.to_s, item)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.write_item(item, value, buffer)
|
28
|
+
return nil if item.data_type == :DERIVED
|
29
|
+
doc = buffer_to_doc(buffer)
|
30
|
+
node = doc.xpath(item.key).first
|
31
|
+
node.content = value.to_s
|
32
|
+
buffer.replace(doc_to_buffer(doc))
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.read_items(items, buffer)
|
36
|
+
doc = buffer_to_doc(buffer)
|
37
|
+
result = {}
|
38
|
+
items.each do |item|
|
39
|
+
if item.data_type == :DERIVED
|
40
|
+
result[item.name] = nil
|
41
|
+
else
|
42
|
+
result[item.name] = convert_to_type(doc.xpath(item.key).first.to_s, item)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
return result
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.write_items(items, values, buffer)
|
49
|
+
doc = buffer_to_doc(buffer)
|
50
|
+
items.each_with_index do |item, index|
|
51
|
+
next if item.data_type == :DERIVED
|
52
|
+
node = doc.xpath(item.key).first
|
53
|
+
node.content = values[index].to_s
|
54
|
+
end
|
55
|
+
buffer.replace(doc_to_buffer(doc))
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.buffer_to_doc(buffer)
|
59
|
+
Nokogiri.XML(buffer)
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.doc_to_buffer(doc)
|
63
|
+
doc.to_xml
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
# Copyright 2022 OpenC3, Inc.
|
4
|
+
# All Rights Reserved.
|
5
|
+
#
|
6
|
+
# This program is free software; you can modify and/or redistribute it
|
7
|
+
# under the terms of the GNU Affero General Public License
|
8
|
+
# as published by the Free Software Foundation; version 3 with
|
9
|
+
# attribution addendums as found in the LICENSE.txt
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
|
16
|
+
module OpenC3
|
17
|
+
autoload(:Accessor, 'openc3/accessors/accessor.rb')
|
18
|
+
autoload(:BinaryAccessor, 'openc3/accessors/binary_accessor.rb')
|
19
|
+
autoload(:CborAccessor, 'openc3/accessors/cbor_accessor.rb')
|
20
|
+
autoload(:HtmlAccessor, 'openc3/accessors/html_accessor.rb')
|
21
|
+
autoload(:JsonAccessor, 'openc3/accessors/json_accessor.rb')
|
22
|
+
autoload(:XmlAccessor, 'openc3/accessors/xml_accessor.rb')
|
23
|
+
end
|
data/lib/openc3/api/cmd_api.rb
CHANGED
@@ -281,9 +281,12 @@ module OpenC3
|
|
281
281
|
|
282
282
|
# States are an array of the name followed by a hash of 'value' and sometimes 'hazardous'
|
283
283
|
item['states'].each do |name, hash|
|
284
|
+
param_name = params[item['name']]
|
285
|
+
# Remove quotes from string parameters
|
286
|
+
param_name = param_name.gsub('"', '').gsub("'", '') if param_name.is_a?(String)
|
284
287
|
# To be hazardous the state must be marked hazardous
|
285
288
|
# Check if either the state name or value matches the param passed
|
286
|
-
if hash['hazardous'] && (name ==
|
289
|
+
if hash['hazardous'] && (name == param_name || hash['value'] == param_name)
|
287
290
|
return true
|
288
291
|
end
|
289
292
|
end
|
@@ -396,7 +399,7 @@ module OpenC3
|
|
396
399
|
'hazardous_check' => hazardous_check,
|
397
400
|
'raw' => raw
|
398
401
|
}
|
399
|
-
Logger.info
|
402
|
+
Logger.info(build_cmd_output_string(target_name, cmd_name, cmd_params, packet, raw), scope: scope) if !packet["messages_disabled"]
|
400
403
|
CommandTopic.send_command(command, scope: scope)
|
401
404
|
end
|
402
405
|
|
@@ -32,6 +32,7 @@ module OpenC3
|
|
32
32
|
'start_raw_logging_interface',
|
33
33
|
'stop_raw_logging_interface',
|
34
34
|
'get_all_interface_info',
|
35
|
+
'map_target_to_interface',
|
35
36
|
])
|
36
37
|
|
37
38
|
# Get information about an interface
|
@@ -113,5 +114,19 @@ module OpenC3
|
|
113
114
|
info.sort! { |a, b| a[0] <=> b[0] }
|
114
115
|
info
|
115
116
|
end
|
117
|
+
|
118
|
+
# Associates a target and all its commands and telemetry with a particular
|
119
|
+
# interface. All the commands will go out over and telemetry be received
|
120
|
+
# from that interface.
|
121
|
+
#
|
122
|
+
# @param target_name [String] The name of the target
|
123
|
+
# @param interface_name (see #connect_interface)
|
124
|
+
def map_target_to_interface(target_name, interface_name, scope: $openc3_scope, token: $openc3_token)
|
125
|
+
authorize(permission: 'system_set', interface_name: interface_name, scope: scope, token: token)
|
126
|
+
new_interface = InterfaceModel.get_model(name: interface_name, scope: scope)
|
127
|
+
new_interface.map_target(target_name)
|
128
|
+
Logger.info("Target #{target_name} mapped to Interface #{interface_name}", scope: scope)
|
129
|
+
nil
|
130
|
+
end
|
116
131
|
end
|
117
132
|
end
|
@@ -260,7 +260,7 @@ module OpenC3
|
|
260
260
|
message = "Setting '#{target_name} #{packet_name} #{item_name}' limits to #{red_low} #{yellow_low} #{yellow_high} #{red_high}"
|
261
261
|
message << " #{green_low} #{green_high}" if green_low && green_high
|
262
262
|
message << " in set #{limits_set} with persistence #{persistence} as enabled #{enabled}"
|
263
|
-
Logger.info(message)
|
263
|
+
Logger.info(message, scope: scope)
|
264
264
|
|
265
265
|
TargetModel.set_packet(target_name, packet_name, packet, scope: scope)
|
266
266
|
|
@@ -307,7 +307,7 @@ module OpenC3
|
|
307
307
|
def set_limits_set(limits_set, scope: $openc3_scope, token: $openc3_token)
|
308
308
|
authorize(permission: 'tlm_set', scope: scope, token: token)
|
309
309
|
message = "Setting Limits Set: #{limits_set}"
|
310
|
-
Logger.info(message)
|
310
|
+
Logger.info(message, scope: scope)
|
311
311
|
LimitsEventTopic.write({ type: :LIMITS_SET, set: limits_set.to_s,
|
312
312
|
time_nsec: Time.now.to_nsec_from_epoch, message: message }, scope: scope)
|
313
313
|
end
|
@@ -343,7 +343,7 @@ module OpenC3
|
|
343
343
|
group = get_limits_groups()[group_name]
|
344
344
|
raise "LIMITS_GROUP #{group_name} undefined. Ensure your telemetry definition contains the line: LIMITS_GROUP #{group_name}" unless group
|
345
345
|
|
346
|
-
Logger.info("Disabling Limits Group: #{group_name}")
|
346
|
+
Logger.info("Disabling Limits Group: #{group_name}", scope: scope)
|
347
347
|
last_target_name = nil
|
348
348
|
last_packet_name = nil
|
349
349
|
packet = nil
|
@@ -161,14 +161,20 @@ module OpenC3
|
|
161
161
|
if options[:locals]
|
162
162
|
options[:locals].each { |key, value| b.local_variable_set(key, value) }
|
163
163
|
end
|
164
|
+
|
165
|
+
return ERB.new(read_file(template_name), trim_mode: "-").result(b)
|
166
|
+
end
|
167
|
+
|
168
|
+
# Can be called during parsing to read a referenced file
|
169
|
+
def read_file(filename)
|
164
170
|
# Assume the file is there. If not we raise a pretty obvious error
|
165
|
-
if File.expand_path(
|
166
|
-
path =
|
171
|
+
if File.expand_path(filename) == filename # absolute path
|
172
|
+
path = filename
|
167
173
|
else # relative to the current @filename
|
168
|
-
path = File.join(File.dirname(@filename),
|
174
|
+
path = File.join(File.dirname(@filename), filename)
|
169
175
|
end
|
170
176
|
OpenC3.set_working_dir(File.dirname(path)) do
|
171
|
-
return
|
177
|
+
return File.read(path)
|
172
178
|
end
|
173
179
|
end
|
174
180
|
|
data/lib/openc3/core_ext/file.rb
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
# Copyright 2022 OpenC3, Inc.
|
4
|
+
# All Rights Reserved.
|
5
|
+
#
|
6
|
+
# This program is free software; you can modify and/or redistribute it
|
7
|
+
# under the terms of the GNU Affero General Public License
|
8
|
+
# as published by the Free Software Foundation; version 3 with
|
9
|
+
# attribution addendums as found in the LICENSE.txt
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
|
16
|
+
require 'tempfile'
|
17
|
+
|
18
|
+
class Tempfile
|
19
|
+
attr_accessor :filename
|
20
|
+
end
|
data/lib/openc3/io/json_rpc.rb
CHANGED
@@ -80,9 +80,9 @@ class Float
|
|
80
80
|
end
|
81
81
|
|
82
82
|
def as_json(options = nil)
|
83
|
-
return { "json_class" => Float, "raw" => "Infinity" } if self.infinite? == 1
|
84
|
-
return { "json_class" => Float, "raw" => "-Infinity" } if self.infinite? == -1
|
85
|
-
return { "json_class" => Float, "raw" => "NaN" } if self.nan?
|
83
|
+
return { "json_class" => "Float", "raw" => "Infinity" } if self.infinite? == 1
|
84
|
+
return { "json_class" => "Float", "raw" => "-Infinity" } if self.infinite? == -1
|
85
|
+
return { "json_class" => "Float", "raw" => "NaN" } if self.nan?
|
86
86
|
|
87
87
|
return self
|
88
88
|
end
|
@@ -35,9 +35,9 @@ module OpenC3
|
|
35
35
|
@state = 'GETTING_OBJECTS'
|
36
36
|
start_time = Time.now
|
37
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],
|
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
41
|
["#{@scope}/decom_logs/tlm/#{target_name}/", target.tlm_decom_log_retain_time],
|
42
42
|
["#{@scope}/reduced_minute_logs/tlm/#{target_name}/", target.reduced_minute_log_retain_time],
|
43
43
|
["#{@scope}/reduced_hour_logs/tlm/#{target_name}/", target.reduced_hour_log_retain_time],
|
@@ -52,8 +52,10 @@ module OpenC3
|
|
52
52
|
end
|
53
53
|
if delete_items.length > 0
|
54
54
|
@state = 'DELETING_OBJECTS'
|
55
|
-
|
56
|
-
|
55
|
+
delete_items.each_slice(1000) do |delete_slice|
|
56
|
+
rubys3_client.delete_objects({ bucket: 'logs', delete: { objects: delete_slice } })
|
57
|
+
Logger.info("Deleted #{delete_slice.length} #{target_name} log files")
|
58
|
+
end
|
57
59
|
end
|
58
60
|
end
|
59
61
|
|
@@ -26,16 +26,7 @@ module OpenC3
|
|
26
26
|
@overrides = {}
|
27
27
|
|
28
28
|
def self.build_json_from_packet(packet)
|
29
|
-
|
30
|
-
packet.sorted_items.each do |item|
|
31
|
-
json_hash[item.name] = packet.read_item(item, :RAW)
|
32
|
-
json_hash["#{item.name}__C"] = packet.read_item(item, :CONVERTED) if item.read_conversion or item.states
|
33
|
-
json_hash["#{item.name}__F"] = packet.read_item(item, :FORMATTED) if item.format_string
|
34
|
-
json_hash["#{item.name}__U"] = packet.read_item(item, :WITH_UNITS) if item.units
|
35
|
-
limits_state = item.limits.state
|
36
|
-
json_hash["#{item.name}__L"] = limits_state if limits_state
|
37
|
-
end
|
38
|
-
json_hash
|
29
|
+
packet.decom
|
39
30
|
end
|
40
31
|
|
41
32
|
# Delete the current value table for a target
|
@@ -277,5 +277,46 @@ module OpenC3
|
|
277
277
|
end
|
278
278
|
status_model.destroy if status_model
|
279
279
|
end
|
280
|
+
|
281
|
+
def unmap_target(target_name)
|
282
|
+
target_name = target_name.to_s.upcase
|
283
|
+
|
284
|
+
# Remove from this interface
|
285
|
+
@target_names.delete(target_name)
|
286
|
+
update()
|
287
|
+
|
288
|
+
# Respawn the microservice
|
289
|
+
type = self.class._get_type
|
290
|
+
microservice_name = "#{@scope}__#{type}__#{@name}"
|
291
|
+
microservice = MicroserviceModel.get_model(name: microservice_name, scope: scope)
|
292
|
+
microservice.target_names.delete(target_name)
|
293
|
+
microservice.update
|
294
|
+
end
|
295
|
+
|
296
|
+
def map_target(target_name)
|
297
|
+
target_name = target_name.to_s.upcase
|
298
|
+
|
299
|
+
# Remove from old interface
|
300
|
+
all_interfaces = InterfaceModel.all(scope: scope)
|
301
|
+
old_interface = nil
|
302
|
+
all_interfaces.each do |old_interface_name, old_interface_details|
|
303
|
+
if old_interface_details['target_names'].include?(target_name)
|
304
|
+
old_interface = InterfaceModel.from_json(old_interface_details, scope: scope)
|
305
|
+
break
|
306
|
+
end
|
307
|
+
end
|
308
|
+
old_interface.unmap_target(target_name) if old_interface
|
309
|
+
|
310
|
+
# Add to this interface
|
311
|
+
@target_names << target_name unless @target_names.include?(target_name)
|
312
|
+
update()
|
313
|
+
|
314
|
+
# Respawn the microservice
|
315
|
+
type = self.class._get_type
|
316
|
+
microservice_name = "#{@scope}__#{type}__#{@name}"
|
317
|
+
microservice = MicroserviceModel.get_model(name: microservice_name, scope: scope)
|
318
|
+
microservice.target_names << target_name unless microservice.target_names.include?(target_name)
|
319
|
+
microservice.update
|
320
|
+
end
|
280
321
|
end
|
281
322
|
end
|
@@ -26,8 +26,15 @@ module OpenC3
|
|
26
26
|
PRIMARY_KEY = 'openc3_microservices'
|
27
27
|
|
28
28
|
attr_accessor :cmd
|
29
|
-
attr_accessor :
|
29
|
+
attr_accessor :container
|
30
|
+
attr_accessor :env
|
31
|
+
attr_accessor :folder_name
|
30
32
|
attr_accessor :needs_dependencies
|
33
|
+
attr_accessor :options
|
34
|
+
attr_accessor :target_names
|
35
|
+
attr_accessor :topics
|
36
|
+
attr_accessor :work_dir
|
37
|
+
attr_accessor :ports
|
31
38
|
|
32
39
|
# NOTE: The following three class methods are used by the ModelController
|
33
40
|
# and are reimplemented to enable various Model class methods to work
|
@@ -75,6 +82,7 @@ module OpenC3
|
|
75
82
|
folder_name: nil,
|
76
83
|
cmd: [],
|
77
84
|
work_dir: '.',
|
85
|
+
ports: [],
|
78
86
|
env: {},
|
79
87
|
topics: [],
|
80
88
|
target_names: [],
|
@@ -97,6 +105,7 @@ module OpenC3
|
|
97
105
|
@folder_name = folder_name
|
98
106
|
@cmd = cmd
|
99
107
|
@work_dir = work_dir
|
108
|
+
@ports = ports
|
100
109
|
@env = env
|
101
110
|
@topics = topics
|
102
111
|
@target_names = target_names
|
@@ -111,6 +120,7 @@ module OpenC3
|
|
111
120
|
'folder_name' => @folder_name,
|
112
121
|
'cmd' => @cmd,
|
113
122
|
'work_dir' => @work_dir,
|
123
|
+
'ports' => @ports,
|
114
124
|
'env' => @env,
|
115
125
|
'topics' => @topics,
|
116
126
|
'target_names' => @target_names,
|
@@ -126,6 +136,9 @@ module OpenC3
|
|
126
136
|
result = "MICROSERVICE #{@folder_name ? @folder_name : 'nil'} #{@name.split("__")[-1]}\n"
|
127
137
|
result << " CMD #{@cmd.join(' ')}\n"
|
128
138
|
result << " WORK_DIR \"#{@work_dir}\"\n"
|
139
|
+
@ports.each do |port|
|
140
|
+
result << " PORT #{port}\n"
|
141
|
+
end
|
129
142
|
@topics.each do |topic_name|
|
130
143
|
result << " TOPIC #{topic_name}\n"
|
131
144
|
end
|
@@ -150,6 +163,25 @@ module OpenC3
|
|
150
163
|
when 'WORK_DIR'
|
151
164
|
parser.verify_num_parameters(1, 1, "#{keyword} <Dir>")
|
152
165
|
@work_dir = parameters[0]
|
166
|
+
when 'PORT'
|
167
|
+
usage = "PORT <Number> <Protocol (Optional)"
|
168
|
+
parser.verify_num_parameters(1, 2, usage)
|
169
|
+
begin
|
170
|
+
@ports << [Integer(parameters[0])]
|
171
|
+
rescue => err # In case Integer fails
|
172
|
+
raise ConfigParser::Error.new(parser, "Port must be an integer: #{parameters[0]}", usage)
|
173
|
+
end
|
174
|
+
protocol = ConfigParser.handle_nil(parameters[1])
|
175
|
+
if protocol
|
176
|
+
# Per https://kubernetes.io/docs/concepts/services-networking/service/#protocol-support
|
177
|
+
if %w(TCP UDP SCTP HTTP SCTP).include?(protocol.upcase)
|
178
|
+
@ports[-1] << protocol.upcase
|
179
|
+
else
|
180
|
+
raise ConfigParser::Error.new(parser, "Unknown port protocol: #{parameters[1]}", usage)
|
181
|
+
end
|
182
|
+
else
|
183
|
+
@ports[-1] << 'TCP'
|
184
|
+
end
|
153
185
|
when 'TOPIC'
|
154
186
|
parser.verify_num_parameters(1, 1, "#{keyword} <Topic Name>")
|
155
187
|
@topics << parameters[0]
|
@@ -251,7 +251,7 @@ module OpenC3
|
|
251
251
|
end
|
252
252
|
|
253
253
|
def create(update: false, force: false)
|
254
|
-
@name = @name + "__#{Time.now.utc.strftime("%Y%m%d%H%M%S")}"
|
254
|
+
@name = @name + "__#{Time.now.utc.strftime("%Y%m%d%H%M%S")}" if not update and not @name.index("__")
|
255
255
|
super(update: update, force: force)
|
256
256
|
end
|
257
257
|
|