openc3 5.2.0 → 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/data/config/interface_modifiers.yaml +22 -4
- data/data/config/microservice.yaml +18 -0
- data/lib/openc3/api/interface_api.rb +12 -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 +3 -3
- 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/interface_microservice.rb +47 -3
- data/lib/openc3/microservices/microservice.rb +6 -0
- data/lib/openc3/models/cvt_model.rb +103 -47
- data/lib/openc3/models/interface_model.rb +23 -0
- data/lib/openc3/models/microservice_model.rb +7 -0
- data/lib/openc3/models/model.rb +1 -1
- data/lib/openc3/models/secret_model.rb +53 -0
- data/lib/openc3/operators/microservice_operator.rb +25 -0
- data/lib/openc3/script/api_shared.rb +18 -2
- data/lib/openc3/topics/interface_topic.rb +16 -0
- data/lib/openc3/topics/router_topic.rb +16 -0
- data/lib/openc3/utilities/redis_secrets.rb +46 -0
- data/lib/openc3/utilities/secrets.rb +63 -0
- data/lib/openc3/version.rb +5 -5
- data/templates/plugin-template/README.md +4 -3
- metadata +20 -2
|
@@ -23,8 +23,10 @@
|
|
|
23
23
|
require 'openc3'
|
|
24
24
|
require 'openc3/models/microservice_model'
|
|
25
25
|
require 'openc3/operators/operator'
|
|
26
|
+
require 'openc3/utilities/secrets'
|
|
26
27
|
require 'redis'
|
|
27
28
|
require 'open3'
|
|
29
|
+
require 'fileutils'
|
|
28
30
|
|
|
29
31
|
module OpenC3
|
|
30
32
|
# Creates new OperatorProcess objects based on querying the Redis key value store.
|
|
@@ -34,6 +36,7 @@ module OpenC3
|
|
|
34
36
|
Logger.microservice_name = "MicroserviceOperator"
|
|
35
37
|
super
|
|
36
38
|
|
|
39
|
+
@secrets = Secrets.getClient
|
|
37
40
|
@microservices = {}
|
|
38
41
|
@previous_microservices = {}
|
|
39
42
|
@new_microservices = {}
|
|
@@ -53,6 +56,28 @@ module OpenC3
|
|
|
53
56
|
env['OPENC3_MICROSERVICE_NAME'] = microservice_name
|
|
54
57
|
container = microservice_config["container"]
|
|
55
58
|
scope = microservice_name.split("__")[0]
|
|
59
|
+
|
|
60
|
+
# Setup secrets for microservice
|
|
61
|
+
secrets = microservice_config["secrets"]
|
|
62
|
+
if secrets
|
|
63
|
+
secrets.each do |type, secret_name, env_name_or_path|
|
|
64
|
+
secret_value = @secrets.get(secret_name, scope: scope)
|
|
65
|
+
if secret_value
|
|
66
|
+
case type
|
|
67
|
+
when 'ENV'
|
|
68
|
+
env[env_name_or_path] = secret_value
|
|
69
|
+
when 'FILE'
|
|
70
|
+
FileUtils.mkdir_p(File.dirname(env_name_or_path))
|
|
71
|
+
File.open(env_name_or_path, 'wb') do |file|
|
|
72
|
+
file.write(secret_value)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
else
|
|
76
|
+
Logger.error("Microservice #{microservice_name} references unknown secret: #{secret_name}")
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
56
81
|
return process_definition, work_dir, env, scope, container
|
|
57
82
|
end
|
|
58
83
|
|
|
@@ -17,7 +17,7 @@
|
|
|
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
|
require 'openc3/script/extract'
|
|
@@ -500,7 +500,20 @@ module OpenC3
|
|
|
500
500
|
def load_utility(procedure_name)
|
|
501
501
|
return start(procedure_name)
|
|
502
502
|
end
|
|
503
|
-
|
|
503
|
+
def require_utility(procedure_name)
|
|
504
|
+
@require_utility_cache ||= {}
|
|
505
|
+
if @require_utility_cache[procedure_name]
|
|
506
|
+
return false
|
|
507
|
+
else
|
|
508
|
+
@require_utility_cache[procedure_name] = true
|
|
509
|
+
begin
|
|
510
|
+
return start(procedure_name)
|
|
511
|
+
rescue LoadError
|
|
512
|
+
@require_utility_cache[procedure_name] = false
|
|
513
|
+
raise # reraise the error
|
|
514
|
+
end
|
|
515
|
+
end
|
|
516
|
+
end
|
|
504
517
|
|
|
505
518
|
###########################################################################
|
|
506
519
|
# Private implementation details
|
|
@@ -714,6 +727,7 @@ module OpenC3
|
|
|
714
727
|
|
|
715
728
|
def _openc3_script_wait_implementation(target_name, packet_name, item_name, value_type, timeout, polling_rate, exp_to_eval, scope: $openc3_scope, token: $openc3_token, &block)
|
|
716
729
|
end_time = Time.now.sys + timeout
|
|
730
|
+
raise "Invalid comparison to non-ascii value" unless exp_to_eval.is_printable?
|
|
717
731
|
|
|
718
732
|
while true
|
|
719
733
|
work_start = Time.now.sys
|
|
@@ -792,6 +806,7 @@ module OpenC3
|
|
|
792
806
|
# Wait on an expression to be true.
|
|
793
807
|
def openc3_script_wait_implementation_expression(exp_to_eval, timeout, polling_rate, context, scope: $openc3_scope, token: $openc3_token)
|
|
794
808
|
end_time = Time.now.sys + timeout
|
|
809
|
+
raise "Invalid comparison to non-ascii value" unless exp_to_eval.is_printable?
|
|
795
810
|
|
|
796
811
|
while true
|
|
797
812
|
work_start = Time.now.sys
|
|
@@ -828,6 +843,7 @@ module OpenC3
|
|
|
828
843
|
end
|
|
829
844
|
|
|
830
845
|
def check_eval(target_name, packet_name, item_name, comparison_to_eval, value, scope: $openc3_scope, token: $openc3_token)
|
|
846
|
+
raise "Invalid comparison to non-ascii value" unless comparison_to_eval.is_printable?
|
|
831
847
|
string = "value " + comparison_to_eval
|
|
832
848
|
check_str = "CHECK: #{_upcase(target_name, packet_name, item_name)} #{comparison_to_eval}"
|
|
833
849
|
# Show user the check against a quoted string
|
|
@@ -76,5 +76,21 @@ module OpenC3
|
|
|
76
76
|
sleep 1 # Give some time for the interface to shutdown
|
|
77
77
|
InterfaceTopic.clear_topics(InterfaceTopic.topics(interface, scope: scope))
|
|
78
78
|
end
|
|
79
|
+
|
|
80
|
+
def interface_cmd(interface_name, cmd_name, *cmd_params, scope:)
|
|
81
|
+
data = {}
|
|
82
|
+
data['cmd_name'] = cmd_name
|
|
83
|
+
data['cmd_params'] = cmd_params
|
|
84
|
+
Topic.write_topic("{#{scope}__CMD}INTERFACE__#{interface_name}", { 'interface_cmd' => JSON.generate(data, allow_nan: true) }, '*', 100)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def protocol_cmd(interface_name, cmd_name, *cmd_params, read_write: :READ_WRITE, index: -1, scope:)
|
|
88
|
+
data = {}
|
|
89
|
+
data['cmd_name'] = cmd_name
|
|
90
|
+
data['cmd_params'] = cmd_params
|
|
91
|
+
data['read_write'] = read_write.to_s.upcase
|
|
92
|
+
data['index'] = index
|
|
93
|
+
Topic.write_topic("{#{scope}__CMD}INTERFACE__#{interface_name}", { 'protocol_cmd' => JSON.generate(data, allow_nan: true) }, '*', 100)
|
|
94
|
+
end
|
|
79
95
|
end
|
|
80
96
|
end
|
|
@@ -88,5 +88,21 @@ module OpenC3
|
|
|
88
88
|
sleep 1 # Give some time for the interface to shutdown
|
|
89
89
|
RouterTopic.clear_topics(RouterTopic.topics(router, scope: scope))
|
|
90
90
|
end
|
|
91
|
+
|
|
92
|
+
def router_cmd(router_name, cmd_name, *cmd_params, scope:)
|
|
93
|
+
data = {}
|
|
94
|
+
data['cmd_name'] = cmd_name
|
|
95
|
+
data['cmd_params'] = cmd_params
|
|
96
|
+
Topic.write_topic("{#{scope}__CMD}ROUTER__#{router_name}", { 'router_cmd' => JSON.generate(data, allow_nan: true) }, '*', 100)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def protocol_cmd(router_name, cmd_name, *cmd_params, read_write: :READ_WRITE, index: -1, scope:)
|
|
100
|
+
data = {}
|
|
101
|
+
data['cmd_name'] = cmd_name
|
|
102
|
+
data['cmd_params'] = cmd_params
|
|
103
|
+
data['read_write'] = read_write.to_s.upcase
|
|
104
|
+
data['index'] = index
|
|
105
|
+
Topic.write_topic("{#{scope}__CMD}ROUTER__#{router_name}", { 'protocol_cmd' => JSON.generate(data, allow_nan: true) }, '*', 100)
|
|
106
|
+
end
|
|
91
107
|
end
|
|
92
108
|
end
|
|
@@ -0,0 +1,46 @@
|
|
|
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
|
+
# This file may also be used under the terms of a commercial license
|
|
17
|
+
# if purchased from OpenC3, Inc.
|
|
18
|
+
|
|
19
|
+
require 'openc3/models/secret_model'
|
|
20
|
+
require 'openc3/utilities/secrets'
|
|
21
|
+
|
|
22
|
+
module OpenC3
|
|
23
|
+
class RedisSecrets < Secrets
|
|
24
|
+
def keys(scope:)
|
|
25
|
+
SecretModel.names(scope: scope)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def get(key, scope:)
|
|
29
|
+
data = SecretModel.get(name: key, scope: scope)
|
|
30
|
+
if data
|
|
31
|
+
return data['value']
|
|
32
|
+
else
|
|
33
|
+
return nil
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def set(key, value, scope:)
|
|
38
|
+
SecretModel.set( {name: key, value: value.to_s }, scope: scope)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def delete(key, scope:)
|
|
42
|
+
model = SecretModel.get_model(name: key, scope: scope)
|
|
43
|
+
model.destroy if model
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
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
|
+
# This file may also be used under the terms of a commercial license
|
|
17
|
+
# if purchased from OpenC3, Inc.
|
|
18
|
+
|
|
19
|
+
ENV['OPENC3_SECRET_BACKEND'] ||= 'redis'
|
|
20
|
+
|
|
21
|
+
module OpenC3
|
|
22
|
+
class Secrets
|
|
23
|
+
def initialize
|
|
24
|
+
@local_secrets = {}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.getClient
|
|
28
|
+
raise 'OPENC3_SECRET_BACKEND environment variable is required' unless ENV['OPENC3_SECRET_BACKEND']
|
|
29
|
+
secrets_class = ENV['OPENC3_SECRET_BACKEND'].capitalize + 'Secrets'
|
|
30
|
+
klass = OpenC3.require_class('openc3/utilities/' + secrets_class.class_name_to_filename)
|
|
31
|
+
klass.new
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def keys(scope:)
|
|
35
|
+
raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def get(key, scope:)
|
|
39
|
+
return @local_secrets[key]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def set(key, value, scope:)
|
|
43
|
+
raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def delete(key, scope:)
|
|
47
|
+
raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def setup(secrets)
|
|
51
|
+
secrets.each do |type, key, data|
|
|
52
|
+
case type
|
|
53
|
+
when 'ENV'
|
|
54
|
+
@local_secrets[key] = ENV[data]
|
|
55
|
+
when 'FILE'
|
|
56
|
+
@local_secrets[key] = File.read(data)
|
|
57
|
+
else
|
|
58
|
+
raise "Unknown secret type: #{type}"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
data/lib/openc3/version.rb
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# encoding: ascii-8bit
|
|
2
2
|
|
|
3
|
-
OPENC3_VERSION = '5.
|
|
3
|
+
OPENC3_VERSION = '5.3.0'
|
|
4
4
|
module OpenC3
|
|
5
5
|
module Version
|
|
6
6
|
MAJOR = '5'
|
|
7
|
-
MINOR = '
|
|
7
|
+
MINOR = '3'
|
|
8
8
|
PATCH = '0'
|
|
9
9
|
OTHER = ''
|
|
10
|
-
BUILD = '
|
|
10
|
+
BUILD = 'a6b9f9a0eb9a17783ffe1e614a1da309128de52d'
|
|
11
11
|
end
|
|
12
|
-
VERSION = '5.
|
|
13
|
-
GEM_VERSION = '5.
|
|
12
|
+
VERSION = '5.3.0'
|
|
13
|
+
GEM_VERSION = '5.3.0'
|
|
14
14
|
end
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
# OpenC3
|
|
1
|
+
# OpenC3 COSMOS Plugin
|
|
2
2
|
|
|
3
3
|
See the [OpenC3](https://openc3.com) documentation for all things OpenC3.
|
|
4
4
|
|
|
5
5
|
## Building the plugin
|
|
6
6
|
|
|
7
|
-
1. <Path to
|
|
7
|
+
1. <Path to COSMOS installation>\openc3.bat cli rake build VERSION=X.Y.Z
|
|
8
8
|
- VERSION is required
|
|
9
9
|
- gem file will be built locally
|
|
10
10
|
|
|
@@ -12,4 +12,5 @@ See the [OpenC3](https://openc3.com) documentation for all things OpenC3.
|
|
|
12
12
|
|
|
13
13
|
1. Go to localhost:2900/tools/admin
|
|
14
14
|
1. Click the paperclip icon and choose your plugin.gem file
|
|
15
|
-
1.
|
|
15
|
+
1. Fill out plugin parameters
|
|
16
|
+
1. Click Install
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: openc3
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ryan Melton
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date:
|
|
12
|
+
date: 2023-01-05 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: bundler
|
|
@@ -333,6 +333,20 @@ dependencies:
|
|
|
333
333
|
- - "~>"
|
|
334
334
|
- !ruby/object:Gem::Version
|
|
335
335
|
version: '1.1'
|
|
336
|
+
- !ruby/object:Gem::Dependency
|
|
337
|
+
name: mqtt
|
|
338
|
+
requirement: !ruby/object:Gem::Requirement
|
|
339
|
+
requirements:
|
|
340
|
+
- - "~>"
|
|
341
|
+
- !ruby/object:Gem::Version
|
|
342
|
+
version: '0.5'
|
|
343
|
+
type: :runtime
|
|
344
|
+
prerelease: false
|
|
345
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
346
|
+
requirements:
|
|
347
|
+
- - "~>"
|
|
348
|
+
- !ruby/object:Gem::Version
|
|
349
|
+
version: '0.5'
|
|
336
350
|
- !ruby/object:Gem::Dependency
|
|
337
351
|
name: opentelemetry-sdk
|
|
338
352
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -768,6 +782,7 @@ files:
|
|
|
768
782
|
- lib/openc3/interfaces.rb
|
|
769
783
|
- lib/openc3/interfaces/interface.rb
|
|
770
784
|
- lib/openc3/interfaces/linc_interface.rb
|
|
785
|
+
- lib/openc3/interfaces/mqtt_interface.rb
|
|
771
786
|
- lib/openc3/interfaces/protocols/burst_protocol.rb
|
|
772
787
|
- lib/openc3/interfaces/protocols/crc_protocol.rb
|
|
773
788
|
- lib/openc3/interfaces/protocols/fixed_protocol.rb
|
|
@@ -849,6 +864,7 @@ files:
|
|
|
849
864
|
- lib/openc3/models/router_model.rb
|
|
850
865
|
- lib/openc3/models/router_status_model.rb
|
|
851
866
|
- lib/openc3/models/scope_model.rb
|
|
867
|
+
- lib/openc3/models/secret_model.rb
|
|
852
868
|
- lib/openc3/models/settings_model.rb
|
|
853
869
|
- lib/openc3/models/sorted_model.rb
|
|
854
870
|
- lib/openc3/models/stash_model.rb
|
|
@@ -951,8 +967,10 @@ files:
|
|
|
951
967
|
- lib/openc3/utilities/open_telemetry.rb
|
|
952
968
|
- lib/openc3/utilities/process_manager.rb
|
|
953
969
|
- lib/openc3/utilities/quaternion.rb
|
|
970
|
+
- lib/openc3/utilities/redis_secrets.rb
|
|
954
971
|
- lib/openc3/utilities/ruby_lex_utils.rb
|
|
955
972
|
- lib/openc3/utilities/s3_autoload.rb
|
|
973
|
+
- lib/openc3/utilities/secrets.rb
|
|
956
974
|
- lib/openc3/utilities/simulated_target.rb
|
|
957
975
|
- lib/openc3/utilities/sleeper.rb
|
|
958
976
|
- lib/openc3/utilities/store.rb
|