openc3 6.2.1 → 6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d2295b17b1ccf8843872f9bc809c460eee9a5e1c8ddf193f7169afaed5e4e561
4
- data.tar.gz: 1f2fbbdeb1d81708df2ba9046ac1958ba3d254b7bb7560b5142dd2404e954e05
3
+ metadata.gz: 80ec07f72b5f3b98e988b0e8b4bee1b1ccf94e734f738ff33dc209249966a7e3
4
+ data.tar.gz: 9367191aab4bae678ef63b0db5f22bfa8a91a5518ec9e056c49c76e099744fd0
5
5
  SHA512:
6
- metadata.gz: 8004c092a51faa75b6a3336affc5939fe0f45da6fb4827ef3fb729249f96cb95a8bcb54cfff606b6952dd25d2404a6f97758e3429f279b3536324408c13c06f5
7
- data.tar.gz: cb6d29d2bfde3f76d4963d0b86d96aaada4d0814f71a968e05e2e59aa469e04c6ba8ab6544ad03c7eab2972267f689af17a8f03a84d889d6f38dec234d8fb437
6
+ metadata.gz: 7a90b63db9e9e3e085249fb2bc8ae00e0733b26c040f30a9dd23b430255228a928ffe13b2b59e8219a7c908f5e94f1f6c44932569c3b1aadf12d297b2d920a7b
7
+ data.tar.gz: 2b8e39ae3eee3028faf0a06719ae98c5a958c71afc989fb4da981e53dc8aa22cdcd4cb89f9d07cdbcc6e671360a9cfaab6f0b33854718aa21e731a8c01b80efc
data/Gemfile CHANGED
@@ -2,12 +2,11 @@
2
2
 
3
3
  source ENV['RUBYGEMS_URL'] || "https://rubygems.org"
4
4
 
5
- gem 'ruby-termios', '>= 0.9' if RbConfig::CONFIG['target_os'] !~ /mswin|mingw|cygwin/i and RUBY_ENGINE == 'ruby'
6
-
7
5
  gemspec :name => 'openc3'
8
6
 
9
7
  # Include the rails gems for the convenience of custom microservice plugins
10
8
  gem 'bootsnap', '>= 1.9.3', require: false
11
9
  gem 'rack-cors', '~> 2.0'
12
- gem 'rails', '~> 7.1.0'
10
+ gem 'rails', '~> 7.2.0'
13
11
  gem 'tzinfo-data'
12
+ gem 'ruby-termios', '>= 1.0'
data/bin/openc3cli CHANGED
@@ -50,7 +50,7 @@ $redis_url = "redis://#{ENV['OPENC3_REDIS_HOSTNAME']}:#{ENV['OPENC3_REDIS_PORT']
50
50
 
51
51
  ERROR_CODE = 1
52
52
 
53
- CLI_SCRIPT_ACTIONS = %w(help list run spawn)
53
+ CLI_SCRIPT_ACTIONS = %w(help list run spawn init)
54
54
  $script_interrupt_text = ''
55
55
  trap('INT') do
56
56
  abort("Interrupted at console; exiting.#{$script_interrupt_text}")
@@ -66,6 +66,7 @@ def print_usage
66
66
  puts " cli script spawn NAME SCOPE variable1=value1 variable2=value2 # Starts named script remotely"
67
67
  puts " cli script run NAME SCOPE variable1=value1 variable2=value2 # Starts named script, monitoring status on console,\
68
68
  by default until error or exit"
69
+ puts " cli script init # initialize running scripts (Enterprise Only)"
69
70
  puts " PARAMETERS name-value pairs to form the script's runtime environment"
70
71
  puts " OPTIONS: --wait 0 seconds to monitor status before detaching from the running script; ie --wait 100"
71
72
  puts " --disconnect run the script in disconnect mode"
@@ -79,7 +80,7 @@ def print_usage
79
80
  puts " cli bridgesetup CONFIG_FILENAME # Create a default config file"
80
81
  puts " cli pkginstall PKGFILENAME SCOPE # Install loaded package (Ruby gem or python package)"
81
82
  puts " cli pkguninstall PKGFILENAME SCOPE # Uninstall loaded package (Ruby gem or python package)"
82
- puts " cli rubysloc # Counts Ruby SLOC recursively. Run with --help for more info."
83
+ puts " cli rubysloc # DEPRECATED: Please use scc (https://github.com/boyter/scc)"
83
84
  puts " cli xtce_converter # Convert to and from the XTCE format. Run with --help for more info."
84
85
  puts " cli cstol_converter # Converts CSTOL files (.prc) to COSMOS. Run with --help for more info."
85
86
  puts ""
@@ -699,6 +700,12 @@ def cli_script_spawn(disconnect=false, environment={}, args=[])
699
700
  return ret_code
700
701
  end
701
702
 
703
+ def cli_script_init
704
+ require 'openc3/script'
705
+ initialize_offline_access()
706
+ return 0
707
+ end
708
+
702
709
  ## cli_script(args) turns an ARGV of [spawn|run] <--wait 123...> <--disconnect> SCRIPT <scope> <ENV_A=1 ENV_B=2 ...>
703
710
  # into function calls and tidied parameters to remote-control a script via RunningScriptWebSocketApi
704
711
  def cli_script(args=[])
@@ -739,6 +746,8 @@ def cli_script(args=[])
739
746
  ret_code = cli_script_spawn(discon, environ, args)
740
747
  when 'run'
741
748
  ret_code = cli_script_run(discon, environ, args)
749
+ when 'init'
750
+ ret_code = cli_script_init()
742
751
  else
743
752
  abort 'openc3cli internal error: parsing arguments'
744
753
  end
@@ -756,7 +765,7 @@ if not ARGV[0].nil? # argument(s) given
756
765
 
757
766
  when 'script'
758
767
  case ARGV[1]
759
- when 'list', 'run', 'spawn'
768
+ when 'list', 'run', 'spawn', 'init'
760
769
  cli_script(ARGV[1..-1])
761
770
  else
762
771
  # invalid actions, misplaced and malformed leading options and 'help' come here
@@ -34,6 +34,7 @@ Layout Widgets:
34
34
  values: .*
35
35
  example: |
36
36
  VERTICALBOX Info
37
+ SUBSETTING 1 RAW border "1px dashed green"
37
38
  LABEL "TEST"
38
39
  LABEL "SCREEN"
39
40
  END
@@ -64,6 +65,8 @@ Layout Widgets:
64
65
  values: .*
65
66
  example: |
66
67
  HORIZONTALBOX Info 10
68
+ SUBSETTING 0 RAW text-align CENTER
69
+ SUBSETTING 1 RAW border "1px solid blue"
67
70
  LABEL "TEST"
68
71
  LABEL "SCREEN"
69
72
  END
@@ -19,6 +19,9 @@
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
+ #
23
+ # A portion of this file was funded by Blue Origin Enterprises, L.P.
24
+ # See https://github.com/OpenC3/cosmos/pull/1963
22
25
 
23
26
  require 'openc3/api/interface_api'
24
27
  require 'openc3/models/target_model'
@@ -387,7 +390,7 @@ module OpenC3
387
390
  target_name, command_name = _extract_target_command_names('get_cmd_cnt', *args)
388
391
  authorize(permission: 'system', target_name: target_name, packet_name: command_name, manual: manual, scope: scope, token: token)
389
392
  TargetModel.packet(target_name, command_name, type: :CMD, scope: scope)
390
- Topic.get_cnt("#{scope}__COMMAND__{#{target_name}}__#{command_name}")
393
+ return TargetModel.get_command_count(target_name, command_name, scope: scope)
391
394
  end
392
395
 
393
396
  # Get the transmit counts for command packets
@@ -399,13 +402,7 @@ module OpenC3
399
402
  unless target_commands.is_a?(Array) and target_commands[0].is_a?(Array)
400
403
  raise "get_cmd_cnts takes an array of arrays containing target, packet_name, e.g. [['INST', 'COLLECT'], ['INST', 'ABORT']]"
401
404
  end
402
- counts = []
403
- target_commands.each do |target_name, command_name|
404
- target_name = target_name.upcase
405
- command_name = command_name.upcase
406
- counts << Topic.get_cnt("#{scope}__COMMAND__{#{target_name}}__#{command_name}")
407
- end
408
- counts
405
+ return TargetModel.get_command_counts(target_commands, scope: scope)
409
406
  end
410
407
 
411
408
  ###########################################################################
@@ -111,15 +111,19 @@ module OpenC3
111
111
  # Get information about all interfaces
112
112
  #
113
113
  # @return [Array<Array<String, Numeric, Numeric, Numeric, Numeric, Numeric,
114
- # Numeric, Numeric>>] Array of Arrays containing \[name, state, num clients,
114
+ # Numeric, Numeric, Boolean>>] Array of Arrays containing \[name, state, num clients,
115
115
  # TX queue size, RX queue size, TX bytes, RX bytes, Command count,
116
- # Telemetry count] for all interfaces
116
+ # Telemetry count, disable_disconnect] for all interfaces
117
117
  def get_all_interface_info(manual: false, scope: $openc3_scope, token: $openc3_token)
118
118
  authorize(permission: 'system', manual: manual, scope: scope, token: token)
119
119
  info = []
120
- InterfaceStatusModel.all(scope: scope).each do |_int_name, int|
120
+ InterfaceStatusModel.all(scope: scope).each do |int_name, int|
121
+ # Get the interface configuration to access disable_disconnect
122
+ interface_model = InterfaceModel.get(name: int_name, scope: scope)
123
+ disable_disconnect = interface_model && interface_model['disable_disconnect'] ? true : false
124
+
121
125
  info << [int['name'], int['state'], int['clients'], int['txsize'], int['rxsize'],
122
- int['txbytes'], int['rxbytes'], int['txcnt'], int['rxcnt']]
126
+ int['txbytes'], int['rxbytes'], int['txcnt'], int['rxcnt'], disable_disconnect]
123
127
  end
124
128
  info.sort! { |a, b| a[0] <=> b[0] }
125
129
  info
@@ -19,6 +19,12 @@
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
+ #
23
+ # A portion of this file was funded by Blue Origin Enterprises, L.P.
24
+ # See https://github.com/OpenC3/cosmos/pull/1963
25
+
26
+ # A portion of this file was funded by Blue Origin Enterprises, L.P.
27
+ # See https://github.com/OpenC3/cosmos/pull/1957
22
28
 
23
29
  require 'openc3/models/target_model'
24
30
  require 'openc3/models/cvt_model'
@@ -48,6 +54,7 @@ module OpenC3
48
54
  'get_all_telemetry', # DEPRECATED
49
55
  'get_all_tlm_names',
50
56
  'get_all_telemetry_names', # DEPRECATED
57
+ 'get_all_tlm_item_names',
51
58
  'get_tlm',
52
59
  'get_telemetry', # DEPRECATED
53
60
  'get_item',
@@ -314,6 +321,20 @@ module OpenC3
314
321
  end
315
322
  alias get_all_telemetry_names get_all_tlm_names
316
323
 
324
+ # Returns an array of all the item names for every packet in a target
325
+ #
326
+ # @param target_name [String] Name of the taret
327
+ # @return [Array<String>] Array of all telemetry item names
328
+ def get_all_tlm_item_names(target_name, manual: false, scope: $openc3_scope, token: $openc3_token)
329
+ authorize(permission: 'tlm', target_name: target_name, manual: manual, scope: scope, token: token)
330
+ begin
331
+ items = TargetModel.all_item_names(target_name, scope: scope)
332
+ rescue RuntimeError
333
+ items = []
334
+ end
335
+ return items
336
+ end
337
+
317
338
  # Returns a telemetry packet hash
318
339
  #
319
340
  # @since 5.0.0
@@ -400,7 +421,7 @@ module OpenC3
400
421
  target_name, packet_name = _extract_target_packet_names('get_tlm_cnt', *args)
401
422
  authorize(permission: 'system', target_name: target_name, packet_name: packet_name, manual: manual, scope: scope, token: token)
402
423
  TargetModel.packet(target_name, packet_name, scope: scope)
403
- Topic.get_cnt("#{scope}__TELEMETRY__{#{target_name}}__#{packet_name}")
424
+ return TargetModel.get_telemetry_count(target_name, packet_name, scope: scope)
404
425
  end
405
426
 
406
427
  # Get the transmit counts for telemetry packets
@@ -409,13 +430,7 @@ module OpenC3
409
430
  # @return [Array<Numeric>] Receive count for the telemetry packets
410
431
  def get_tlm_cnts(target_packets, manual: false, scope: $openc3_scope, token: $openc3_token)
411
432
  authorize(permission: 'system', manual: manual, scope: scope, token: token)
412
- counts = []
413
- target_packets.each do |target_name, packet_name|
414
- target_name = target_name.upcase
415
- packet_name = packet_name.upcase
416
- counts << Topic.get_cnt("#{scope}__TELEMETRY__{#{target_name}}__#{packet_name}")
417
- end
418
- counts
433
+ return TargetModel.get_telemetry_counts(target_packets, scope: scope)
419
434
  end
420
435
 
421
436
  # Get the list of derived telemetry items for a packet
@@ -57,7 +57,7 @@ module OpenC3
57
57
  # @param url [String] The url of openc3-cosmos-cmd-tlm-api http://openc3-cosmos-cmd-tlm-api:2901
58
58
  # @param timeout [Float] The time to wait before disconnecting 1.0
59
59
  # @param authentication [OpenC3Authentication] The authentication object if nill initialize will generate
60
- def initialize(url: ENV['OPENC3_API_URL'], timeout: 1.0, authentication: nil)
60
+ def initialize(url:, timeout: 1.0, authentication: nil)
61
61
  @http = nil
62
62
  @mutex = Mutex.new
63
63
  @request_data = ""
@@ -43,7 +43,7 @@ module OpenC3
43
43
  # @param url [String] The url of openc3-cosmos-cmd-tlm-api http://openc3-cosmos-cmd-tlm-api:2901
44
44
  # @param timeout [Float] The time to wait before disconnecting 1.0
45
45
  # @param authentication [OpenC3Authentication] The authentication object if nill initialize will generate
46
- def initialize(url: ENV['OPENC3_API_URL'], timeout: 1.0, authentication: nil)
46
+ def initialize(url:, timeout: 1.0, authentication: nil)
47
47
  super(url: url, timeout: timeout, authentication: authentication)
48
48
  @uri = URI("#{url}/openc3-api/api")
49
49
  end
@@ -15,6 +15,9 @@
15
15
  #
16
16
  # This file may also be used under the terms of a commercial license
17
17
  # if purchased from OpenC3, Inc.
18
+ #
19
+ # A portion of this file was funded by Blue Origin Enterprises, L.P.
20
+ # See https://github.com/OpenC3/cosmos/pull/1963
18
21
 
19
22
  require 'openc3/topics/telemetry_topic'
20
23
  require 'openc3/system/system'
@@ -33,8 +36,8 @@ module OpenC3
33
36
  packet.write(name.to_s, value, type)
34
37
  end
35
38
  end
36
- packet.received_count += 1
37
39
  packet.received_time = Time.now.sys
40
+ packet.received_count = TargetModel.increment_telemetry_count(packet.target_name, packet.packet_name, 1, scope: @scope)
38
41
  TelemetryTopic.write_packet(packet, scope: @scope)
39
42
  # If the inject_tlm parameters are bad we rescue so
40
43
  # interface_microservice and decom_microservice can continue
@@ -19,6 +19,9 @@
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
+ #
23
+ # A portion of this file was funded by Blue Origin Enterprises, L.P.
24
+ # See https://github.com/OpenC3/cosmos/pull/1963
22
25
 
23
26
  require 'openc3/microservices/microservice'
24
27
  require 'openc3/microservices/interface_decom_common'
@@ -128,7 +131,7 @@ module OpenC3
128
131
  @logger.info "#{@interface.name}: Write raw"
129
132
  # A raw interface write results in an UNKNOWN packet
130
133
  command = System.commands.packet('UNKNOWN', 'UNKNOWN')
131
- command.received_count += 1
134
+ command.received_count = TargetModel.increment_command_count('UNKNOWN', 'UNKNOWN', 1, scope: @scope)
132
135
  command = command.clone
133
136
  command.buffer = msg_hash['raw']
134
137
  command.received_time = Time.now
@@ -215,14 +218,15 @@ module OpenC3
215
218
  command = System.commands.identify(cmd_buffer, @interface.cmd_target_names)
216
219
  end
217
220
  unless command
218
- command = System.commands.packet('UNKNOWN', 'UNKNOWN')
219
- command.received_count += 1
220
- command = command.clone
221
+ command = System.commands.packet('UNKNOWN', 'UNKNOWN').clone
221
222
  command.buffer = cmd_buffer
222
223
  end
223
224
  else
224
225
  raise "Invalid command received:\n #{msg_hash}"
225
226
  end
227
+ orig_command = System.commands.packet(command.target_name, command.packet_name)
228
+ orig_command.received_count = TargetModel.increment_command_count(command.target_name, command.packet_name, 1, scope: @scope)
229
+ command.received_count = orig_command.received_count
226
230
  command.received_time = Time.now
227
231
  rescue => e
228
232
  @logger.error "#{@interface.name}: #{msg_hash}"
@@ -504,6 +508,9 @@ module OpenC3
504
508
  end
505
509
 
506
510
  @queued = false
511
+ @sync_packet_count_data = {}
512
+ @sync_packet_count_time = nil
513
+ @sync_packet_count_delay_seconds = 1.0 # Sync packet counts every second
507
514
  @interface.options.each do |option_name, option_values|
508
515
  if option_name.upcase == 'OPTIMIZE_THROUGHPUT'
509
516
  @queued = true
@@ -511,6 +518,9 @@ module OpenC3
511
518
  EphemeralStoreQueued.instance.set_update_interval(update_interval)
512
519
  StoreQueued.instance.set_update_interval(update_interval)
513
520
  end
521
+ if option_name.upcase == 'SYNC_PACKET_COUNT_DELAY_SECONDS'
522
+ @sync_packet_count_delay_seconds = option_values[0].to_f
523
+ end
514
524
  end
515
525
 
516
526
  @interface_thread_sleeper = Sleeper.new
@@ -678,7 +688,7 @@ module OpenC3
678
688
  end
679
689
 
680
690
  # Write to stream
681
- packet.received_count += 1
691
+ sync_tlm_packet_counts(packet)
682
692
  TelemetryTopic.write_packet(packet, queued: @queued, scope: @scope)
683
693
  end
684
694
 
@@ -812,6 +822,59 @@ module OpenC3
812
822
  def graceful_kill
813
823
  # Just to avoid warning
814
824
  end
825
+
826
+ def sync_tlm_packet_counts(packet)
827
+ if @sync_packet_count_delay_seconds <= 0
828
+ # Perfect but slow method
829
+ packet.received_count = TargetModel.increment_telemetry_count(packet.target_name, packet.packet_name, 1, scope: @scope)
830
+ else
831
+ # Eventually consistent method
832
+ # Only sync every period (default 1 second) to avoid hammering Redis
833
+ # This is a trade off between speed and accuracy
834
+ # The packet count is eventually consistent
835
+ @sync_packet_count_data[packet.target_name] ||= {}
836
+ @sync_packet_count_data[packet.target_name][packet.packet_name] ||= 0
837
+ @sync_packet_count_data[packet.target_name][packet.packet_name] += 1
838
+
839
+ # Ensures counters change between syncs
840
+ packet.received_count += 1
841
+
842
+ # Check if we need to sync the packet counts
843
+ if @sync_packet_count_time.nil? or (Time.now - @sync_packet_count_time) > @sync_packet_count_delay_seconds
844
+ @sync_packet_count_time = Time.now
845
+
846
+ inc_count = 0
847
+ # Use pipeline to make this one transaction
848
+ result = Store.redis_pool.pipelined do
849
+ # Increment global counters for packets received
850
+ @sync_packet_count_data.each do |target_name, packet_data|
851
+ packet_data.each do |packet_name, count|
852
+ TargetModel.increment_telemetry_count(target_name, packet_name, count, scope: @scope)
853
+ inc_count += 1
854
+ end
855
+ end
856
+ @sync_packet_count_data = {}
857
+
858
+ # Get all the packet counts with the global counters
859
+ @interface.tlm_target_names.each do |target_name|
860
+ TargetModel.get_all_telemetry_counts(target_name, scope: @scope)
861
+ end
862
+ TargetModel.get_all_telemetry_counts('UNKNOWN', scope: @scope)
863
+ end
864
+ @interface.tlm_target_names.each do |target_name|
865
+ result[inc_count].each do |packet_name, count|
866
+ update_packet = System.telemetry.packet(target_name, packet_name)
867
+ update_packet.received_count = count.to_i
868
+ end
869
+ inc_count += 1
870
+ end
871
+ result[inc_count].each do |packet_name, count|
872
+ update_packet = System.telemetry.packet('UNKNOWN', packet_name)
873
+ update_packet.received_count = count.to_i
874
+ end
875
+ end
876
+ end
877
+ end
815
878
  end
816
879
  end
817
880
 
@@ -64,6 +64,7 @@ module OpenC3
64
64
  microservice.state = 'DIED_ERROR'
65
65
  Logger.fatal("Microservice #{name} dying from exception\n#{e.formatted}")
66
66
  end
67
+ microservice.shutdown # Dying in crash so should try to shutdown
67
68
  ensure
68
69
  MicroserviceStatusModel.set(microservice.as_json(:allow_nan => true), scope: microservice.scope)
69
70
  end
@@ -25,7 +25,7 @@ module OpenC3
25
25
  def run
26
26
  ARGV.each do |microservice_name|
27
27
  microservice_model = MicroserviceModel.get_model(name: microservice_name, scope: @scope)
28
- if microservice_model.enabled
28
+ if microservice_model and microservice_model.enabled
29
29
  thread = Thread.new do
30
30
  cmd_line = microservice_model.cmd.join(' ')
31
31
  split_cmd_line = cmd_line.split(' ')
@@ -0,0 +1,24 @@
1
+ require 'openc3/utilities/migration'
2
+ require 'openc3/models/scope_model'
3
+ require 'openc3/models/microservice_model'
4
+
5
+ module OpenC3
6
+ class PeriodicOnlyDefault < Migration
7
+ def self.run
8
+ ScopeModel.get_all_models(scope: nil).each do |scope, scope_model|
9
+ next if scope == 'DEFAULT'
10
+ model = MicroserviceModel.get_model(name: "#{scope}__SCOPEMULTI__#{scope}", scope: scope)
11
+ if model
12
+ model.cmd.delete("#{scope}__PERIODIC__#{scope}")
13
+ model.update
14
+ end
15
+ model = MicroserviceModel.get_model(name: "#{scope}__PERIODIC__#{scope}", scope: scope)
16
+ model.destroy if model
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ unless ENV['OPENC3_NO_MIGRATE']
23
+ OpenC3::PeriodicOnlyDefault.run
24
+ end
@@ -19,28 +19,29 @@
19
19
  require 'openc3/models/model'
20
20
 
21
21
  module OpenC3
22
+ # Note: This model is locked to the DEFAULT scope
22
23
  class OfflineAccessModel < Model
23
- PRIMARY_KEY = 'openc3__offline_access'
24
+ PRIMARY_KEY = 'DEFAULT__openc3__offline_access'
24
25
 
25
26
  attr_accessor :offline_access_token
26
27
 
27
28
  # NOTE: The following three class methods are used by the ModelController
28
29
  # and are reimplemented to enable various Model class methods to work
29
30
  def self.get(name:, scope:)
30
- super("#{scope}__#{PRIMARY_KEY}", name: name)
31
+ super(PRIMARY_KEY, name: name)
31
32
  end
32
33
 
33
34
  def self.names(scope:)
34
- super("#{scope}__#{PRIMARY_KEY}")
35
+ super(PRIMARY_KEY)
35
36
  end
36
37
 
37
38
  def self.all(scope:)
38
- super("#{scope}__#{PRIMARY_KEY}")
39
+ super(PRIMARY_KEY)
39
40
  end
40
41
  # END NOTE
41
42
 
42
- def initialize(name:, offline_access_token: nil, updated_at: nil, scope:)
43
- super("#{scope}__#{PRIMARY_KEY}", name: name, scope: scope)
43
+ def initialize(name:, offline_access_token: nil, updated_at: nil, scope: 'DEFAULT')
44
+ super(PRIMARY_KEY, name: name, updated_at: updated_at, scope: 'DEFAULT')
44
45
  @offline_access_token = offline_access_token
45
46
  end
46
47
 
@@ -350,8 +350,11 @@ module OpenC3
350
350
  # UNKNOWN PacketLog Microservice
351
351
  deploy_unknown_packetlog_microservice(gem_path, variables, @parent)
352
352
 
353
- # Periodic Microservice
354
- deploy_periodic_microservice(gem_path, variables, @parent)
353
+ # Only DEFAULT scope
354
+ if @scope == 'DEFAULT'
355
+ # Periodic Microservice
356
+ deploy_periodic_microservice(gem_path, variables, @parent)
357
+ end
355
358
 
356
359
  # Scope Cleanup Microservice
357
360
  deploy_scopecleanup_microservice(gem_path, variables, @parent)