openc3 5.0.8 → 5.0.9
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 +128 -95
- data/data/config/widgets.yaml +49 -73
- 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/core_ext/file.rb +5 -0
- data/lib/openc3/io/json_rpc.rb +3 -3
- data/lib/openc3/microservices/cleanup_microservice.rb +7 -5
- data/lib/openc3/models/interface_model.rb +41 -0
- data/lib/openc3/models/microservice_model.rb +7 -1
- data/lib/openc3/models/plugin_model.rb +1 -1
- data/lib/openc3/models/target_model.rb +85 -68
- data/lib/openc3/packets/parsers/xtce_parser.rb +68 -3
- data/lib/openc3/script/storage.rb +18 -1
- data/lib/openc3/utilities/local_mode.rb +518 -0
- data/lib/openc3/utilities/target_file.rb +146 -0
- data/lib/openc3/version.rb +5 -5
- metadata +9 -7
@@ -24,6 +24,7 @@ require 'openc3/models/microservice_model'
|
|
24
24
|
require 'openc3/topics/limits_event_topic'
|
25
25
|
require 'openc3/topics/config_topic'
|
26
26
|
require 'openc3/system'
|
27
|
+
require 'openc3/utilities/local_mode'
|
27
28
|
require 'openc3/utilities/s3'
|
28
29
|
require 'openc3/utilities/zip'
|
29
30
|
require 'fileutils'
|
@@ -87,29 +88,36 @@ module OpenC3
|
|
87
88
|
targets = self.all(scope: scope)
|
88
89
|
targets.each { |target_name, target| target['modified'] = false }
|
89
90
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
91
|
+
if ENV['OPENC3_LOCAL_MODE']
|
92
|
+
modified_targets = OpenC3::LocalMode.modified_targets(scope: scope)
|
93
|
+
modified_targets.each do |target_name|
|
94
|
+
targets[target_name]['modified'] = true if targets[target_name]
|
95
|
+
end
|
96
|
+
else
|
97
|
+
rubys3_client = Aws::S3::Client.new
|
98
|
+
token = nil
|
99
|
+
while true
|
100
|
+
resp = rubys3_client.list_objects_v2({
|
101
|
+
bucket: 'config',
|
102
|
+
max_keys: 1000,
|
103
|
+
# The trailing slash is important!
|
104
|
+
prefix: "#{scope}/targets_modified/",
|
105
|
+
delimiter: '/',
|
106
|
+
continuation_token: token
|
107
|
+
})
|
108
|
+
resp.common_prefixes.each do |item|
|
109
|
+
# Results look like DEFAULT/targets_modified/INST/
|
110
|
+
# so split on '/' and pull out the last value
|
111
|
+
target_name = item.prefix.split('/')[-1]
|
112
|
+
# A target could have been deleted without removing the modified files
|
113
|
+
# Thus we have to check for the existance of the target_name key
|
114
|
+
if targets.has_key?(target_name)
|
115
|
+
targets[target_name]['modified'] = true
|
116
|
+
end
|
109
117
|
end
|
118
|
+
break unless resp.is_truncated
|
119
|
+
token = resp.next_continuation_token
|
110
120
|
end
|
111
|
-
break unless resp.is_truncated
|
112
|
-
token = resp.next_continuation_token
|
113
121
|
end
|
114
122
|
# Sort (which turns hash to array) and return hash
|
115
123
|
# This enables a consistent listing of the targets
|
@@ -117,31 +125,41 @@ module OpenC3
|
|
117
125
|
end
|
118
126
|
|
119
127
|
# Given target's modified file list
|
120
|
-
def self.modified_files(
|
128
|
+
def self.modified_files(target_name, scope:)
|
121
129
|
modified = []
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
130
|
+
|
131
|
+
if ENV['OPENC3_LOCAL_MODE']
|
132
|
+
modified = OpenC3::LocalMode.modified_files(target_name, scope: scope)
|
133
|
+
else
|
134
|
+
rubys3_client = Aws::S3::Client.new
|
135
|
+
token = nil
|
136
|
+
while true
|
137
|
+
resp = rubys3_client.list_objects_v2({
|
138
|
+
bucket: 'config',
|
139
|
+
max_keys: 1000,
|
140
|
+
# The trailing slash is important!
|
141
|
+
prefix: "#{scope}/targets_modified/#{target_name}/",
|
142
|
+
continuation_token: token
|
143
|
+
})
|
144
|
+
resp.contents.each do |item|
|
145
|
+
# Results look like DEFAULT/targets_modified/INST/procedures/new.rb
|
146
|
+
# so split on '/' and ignore the first two values
|
147
|
+
modified << item.key.split('/')[2..-1].join('/')
|
148
|
+
end
|
149
|
+
break unless resp.is_truncated
|
150
|
+
token = resp.next_continuation_token
|
136
151
|
end
|
137
|
-
break unless resp.is_truncated
|
138
|
-
token = resp.next_continuation_token
|
139
152
|
end
|
140
153
|
# Sort to enable a consistent listing of the modified files
|
141
154
|
modified.sort
|
142
155
|
end
|
143
156
|
|
144
|
-
def self.delete_modified(
|
157
|
+
def self.delete_modified(target_name, scope:)
|
158
|
+
if ENV['OPENC3_LOCAL_MODE']
|
159
|
+
OpenC3::LocalMode.delete_modified(target_name, scope: scope)
|
160
|
+
end
|
161
|
+
|
162
|
+
# Delete the remote files as well
|
145
163
|
rubys3_client = Aws::S3::Client.new
|
146
164
|
token = nil
|
147
165
|
while true
|
@@ -149,7 +167,7 @@ module OpenC3
|
|
149
167
|
bucket: 'config',
|
150
168
|
max_keys: 1000,
|
151
169
|
# The trailing slash is important!
|
152
|
-
prefix: "#{scope}/targets_modified/#{
|
170
|
+
prefix: "#{scope}/targets_modified/#{target_name}/",
|
153
171
|
continuation_token: token
|
154
172
|
})
|
155
173
|
resp.contents.each do |item|
|
@@ -158,41 +176,40 @@ module OpenC3
|
|
158
176
|
break unless resp.is_truncated
|
159
177
|
token = resp.next_continuation_token
|
160
178
|
end
|
161
|
-
# rubys3_client = Aws::S3::Client.new
|
162
|
-
# prefix = "#{scope}/targets_modified/#{name}/"
|
163
|
-
# rubys3_client.list_objects(bucket: 'config', prefix: prefix).contents.each do |object|
|
164
|
-
# rubys3_client.delete_object(bucket: 'config', key: object.key)
|
165
|
-
# end
|
166
179
|
end
|
167
180
|
|
168
|
-
def self.download(
|
181
|
+
def self.download(target_name, scope:)
|
169
182
|
tmp_dir = Dir.mktmpdir
|
170
|
-
zip_filename = File.join(tmp_dir, "#{
|
183
|
+
zip_filename = File.join(tmp_dir, "#{target_name}.zip")
|
171
184
|
Zip.continue_on_exists_proc = true
|
172
185
|
zip = Zip::File.open(zip_filename, Zip::File::CREATE)
|
173
186
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
187
|
+
if ENV['OPENC3_LOCAL_MODE']
|
188
|
+
OpenC3::LocalMode.zip_target(target_name, zip, scope: scope)
|
189
|
+
else
|
190
|
+
rubys3_client = Aws::S3::Client.new
|
191
|
+
token = nil
|
192
|
+
# The trailing slash is important!
|
193
|
+
prefix = "#{scope}/targets_modified/#{target_name}/"
|
194
|
+
while true
|
195
|
+
resp = rubys3_client.list_objects_v2({
|
196
|
+
bucket: 'config',
|
197
|
+
max_keys: 1000,
|
198
|
+
prefix: prefix,
|
199
|
+
continuation_token: token
|
200
|
+
})
|
201
|
+
resp.contents.each do |item|
|
202
|
+
# item.key looks like DEFAULT/targets_modified/INST/screens/blah.txt
|
203
|
+
base_path = item.key.sub(prefix, '') # remove prefix
|
204
|
+
local_path = File.join(tmp_dir, base_path)
|
205
|
+
# Ensure dir structure exists, get_object fails if not
|
206
|
+
FileUtils.mkdir_p(File.dirname(local_path))
|
207
|
+
rubys3_client.get_object(bucket: 'config', key: item.key, response_target: local_path)
|
208
|
+
zip.add(base_path, local_path)
|
209
|
+
end
|
210
|
+
break unless resp.is_truncated
|
211
|
+
token = resp.next_continuation_token
|
193
212
|
end
|
194
|
-
break unless resp.is_truncated
|
195
|
-
token = resp.next_continuation_token
|
196
213
|
end
|
197
214
|
zip.close
|
198
215
|
|
@@ -178,14 +178,40 @@ module OpenC3
|
|
178
178
|
when 'ParameterTypeSet', 'EnumerationList', 'ParameterSet', 'ContainerSet',
|
179
179
|
'EntryList', 'DefaultCalibrator', 'DefaultAlarm', 'RestrictionCriteria',
|
180
180
|
'ComparisonList', 'MetaCommandSet', 'ArgumentTypeSet', 'ArgumentList',
|
181
|
-
'ArgumentAssignmentList', 'LocationInContainerInBits'
|
181
|
+
'ArgumentAssignmentList', 'LocationInContainerInBits', 'ReferenceTime'
|
182
182
|
# Do Nothing
|
183
183
|
|
184
|
+
when 'ErrorDetectCorrect'
|
185
|
+
# TODO: Setup an algorithm to calculate the CRC
|
186
|
+
exponents = []
|
187
|
+
xtce_recurse_element(element) do |crc_element|
|
188
|
+
if crc_element.name == 'CRC'
|
189
|
+
xtce_recurse_element(crc_element) do |poly_element|
|
190
|
+
if poly_element['Polynomial']
|
191
|
+
xtce_recurse_element(poly_element) do |term_element|
|
192
|
+
if term_element['Term']
|
193
|
+
exponents << term_element['exponent'].to_i
|
194
|
+
end
|
195
|
+
true
|
196
|
+
end
|
197
|
+
end
|
198
|
+
true
|
199
|
+
end
|
200
|
+
end
|
201
|
+
true
|
202
|
+
end
|
203
|
+
@current_type.xtce_encoding = 'IntegerDataEncoding'
|
204
|
+
@current_type.signed = 'false'
|
205
|
+
return false # Already recursed
|
206
|
+
|
184
207
|
when 'EnumeratedParameterType', 'EnumeratedArgumentType',
|
185
208
|
'IntegerParameterType', 'IntegerArgumentType',
|
186
209
|
'FloatParameterType', 'FloatArgumentType',
|
187
210
|
'StringParameterType', 'StringArgumentType',
|
188
|
-
'BinaryParameterType', 'BinaryArgumentType'
|
211
|
+
'BinaryParameterType', 'BinaryArgumentType',
|
212
|
+
'BooleanParameterType', 'BooleanArgumentType',
|
213
|
+
'AbsoluteTimeParameterType', 'AbsoluteTimeArgumentType',
|
214
|
+
'RelativeTimeParameterType', 'RelativeTimeArgumentType'
|
189
215
|
@current_type = create_new_type(element)
|
190
216
|
@current_type.endianness = :BIG_ENDIAN
|
191
217
|
|
@@ -204,6 +230,20 @@ module OpenC3
|
|
204
230
|
when 'BinaryParameterType', 'BinaryArgumentType'
|
205
231
|
@current_type.xtce_encoding = 'BinaryDataEncoding'
|
206
232
|
@current_type.sizeInBits = 8 # This is undocumented but appears to be the design
|
233
|
+
when 'BooleanParameterType', 'BooleanArgumentType'
|
234
|
+
@current_type.xtce_encoding = 'StringDataEncoding'
|
235
|
+
@current_type.sizeInBits = 8 # This is undocumented but appears to be the design
|
236
|
+
@current_type.states ||= {}
|
237
|
+
if element.attributes['zeroStringValue'] && element.attributes['oneStringValue']
|
238
|
+
@current_type.states[element.attributes['zeroStringValue'].value] = 0
|
239
|
+
@current_type.states[element.attributes['oneStringValue'].value] = 1
|
240
|
+
else
|
241
|
+
@current_type.states['FALSE'] = 0
|
242
|
+
@current_type.states['TRUE'] = 1
|
243
|
+
end
|
244
|
+
# No defaults for the time types
|
245
|
+
# when 'AbsoluteTimeParameterType', 'AbsoluteTimeArgumentType',
|
246
|
+
# when'RelativeTimeParameterType', 'RelativeTimeArgumentType'
|
207
247
|
end
|
208
248
|
|
209
249
|
when 'ArrayParameterType', 'ArrayArgumentType'
|
@@ -251,7 +291,7 @@ module OpenC3
|
|
251
291
|
|
252
292
|
return false # Already recursed
|
253
293
|
|
254
|
-
when
|
294
|
+
when 'SizeInBits'
|
255
295
|
xtce_recurse_element(element) do |block_element|
|
256
296
|
if block_element.name == 'FixedValue'
|
257
297
|
@current_type.sizeInBits = Integer(block_element.text)
|
@@ -326,6 +366,26 @@ module OpenC3
|
|
326
366
|
@current_type.states ||= {}
|
327
367
|
@current_type.states[element['label']] = Integer(element['value'])
|
328
368
|
|
369
|
+
when 'Encoding'
|
370
|
+
if element.attributes['units']
|
371
|
+
@current_type.units_full = element.attributes['units'].value
|
372
|
+
# Could do a better job mapping units to abbreviations
|
373
|
+
@current_type.units = element.attributes['units'].value[0]
|
374
|
+
end
|
375
|
+
# TODO: Not sure if this is correct
|
376
|
+
# if @current_type.attributes['scale'] || @current_type.attributes['offset']
|
377
|
+
# @current_type.conversion ||= PolynomialConversion.new()
|
378
|
+
# if @current_type.attributes['offset']
|
379
|
+
# @current_type.conversion.coeffs[0] = @current_type.attributes['offset']
|
380
|
+
# end
|
381
|
+
# if @current_type.attributes['scale']
|
382
|
+
# @current_type.conversion.coeffs[1] = @current_type.attributes['scale']
|
383
|
+
# end
|
384
|
+
# end
|
385
|
+
|
386
|
+
when 'Epoch'
|
387
|
+
# TODO: How to handle this ... it affects the conversion applied
|
388
|
+
|
329
389
|
when 'IntegerDataEncoding', 'FloatDataEncoding', 'StringDataEncoding', 'BinaryDataEncoding'
|
330
390
|
@current_type.xtce_encoding = element.name
|
331
391
|
element.attributes.each do |att_name, att|
|
@@ -340,6 +400,11 @@ module OpenC3
|
|
340
400
|
@current_type.endianness = :LITTLE_ENDIAN
|
341
401
|
end
|
342
402
|
|
403
|
+
# Ensure if the encoding is a string we convert state values to strings
|
404
|
+
if @current_type.xtce_encoding == 'StringDataEncoding' && @current_type.states
|
405
|
+
@current_type.states.transform_values!(&:to_s)
|
406
|
+
end
|
407
|
+
|
343
408
|
when 'Parameter'
|
344
409
|
@current_parameter = OpenStruct.new
|
345
410
|
element.attributes.each do |att_name, att|
|
@@ -34,7 +34,7 @@ module OpenC3
|
|
34
34
|
OpenC3::Logger.info "Deleting #{delete_path}"
|
35
35
|
response = $api_server.request('delete', endpoint, query: {bucket: 'config'}, scope: scope)
|
36
36
|
if response.nil? || response.code != 200
|
37
|
-
raise "Failed to delete #{delete_path}
|
37
|
+
raise "Failed to delete #{delete_path}"
|
38
38
|
end
|
39
39
|
rescue => error
|
40
40
|
raise "Failed deleting #{path} due to #{error.message}"
|
@@ -48,7 +48,13 @@ module OpenC3
|
|
48
48
|
# @param io_or_string [Io or String] IO object
|
49
49
|
def put_target_file(path, io_or_string, scope: $openc3_scope)
|
50
50
|
raise "Disallowed path modifier '..' found in #{path}" if path.include?('..')
|
51
|
+
|
51
52
|
upload_path = "#{scope}/targets_modified/#{path}"
|
53
|
+
|
54
|
+
if ENV['OPENC3_LOCAL_MODE'] and $openc3_in_cluster
|
55
|
+
OpenC3::LocalMode.put_target_file(upload_path, io_or_string, scope: scope)
|
56
|
+
end
|
57
|
+
|
52
58
|
endpoint = "/openc3-api/storage/upload/#{upload_path}"
|
53
59
|
OpenC3::Logger.info "Writing #{upload_path}"
|
54
60
|
result = _get_presigned_request(endpoint, scope: scope)
|
@@ -86,6 +92,17 @@ module OpenC3
|
|
86
92
|
# Loop to allow redo when switching from modified to original
|
87
93
|
loop do
|
88
94
|
begin
|
95
|
+
if part == "targets_modified" and ENV['OPENC3_LOCAL_MODE']
|
96
|
+
local_file = OpenC3::LocalMode.open_local_file(path, scope: scope)
|
97
|
+
if local_file
|
98
|
+
file = Tempfile.new('target', binmode: true)
|
99
|
+
file.write(local_file.read)
|
100
|
+
local_file.close
|
101
|
+
file.rewind
|
102
|
+
return file if local_file
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
89
106
|
return _get_storage_file("#{part}/#{path}", scope: scope)
|
90
107
|
rescue => error
|
91
108
|
if part == "targets_modified"
|