openc3 5.3.0 → 5.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/bin/openc3cli +108 -105
  3. data/data/config/item_modifiers.yaml +4 -2
  4. data/data/config/table_manager.yaml +2 -2
  5. data/data/config/tool.yaml +1 -1
  6. data/ext/openc3/ext/config_parser/config_parser.c +17 -2
  7. data/lib/openc3/api/api.rb +1 -0
  8. data/lib/openc3/api/metrics_api.rb +97 -0
  9. data/lib/openc3/api/tlm_api.rb +2 -1
  10. data/lib/openc3/config/config_parser.rb +29 -4
  11. data/lib/openc3/core_ext/time.rb +6 -1
  12. data/lib/openc3/microservices/cleanup_microservice.rb +17 -1
  13. data/lib/openc3/microservices/decom_microservice.rb +12 -9
  14. data/lib/openc3/microservices/interface_microservice.rb +46 -6
  15. data/lib/openc3/microservices/log_microservice.rb +11 -5
  16. data/lib/openc3/microservices/microservice.rb +4 -9
  17. data/lib/openc3/microservices/periodic_microservice.rb +7 -0
  18. data/lib/openc3/microservices/reaction_microservice.rb +0 -33
  19. data/lib/openc3/microservices/reducer_microservice.rb +14 -10
  20. data/lib/openc3/microservices/text_log_microservice.rb +12 -3
  21. data/lib/openc3/microservices/timeline_microservice.rb +0 -6
  22. data/lib/openc3/microservices/trigger_group_microservice.rb +0 -20
  23. data/lib/openc3/models/metric_model.rb +53 -6
  24. data/lib/openc3/models/microservice_model.rb +8 -1
  25. data/lib/openc3/models/plugin_model.rb +6 -1
  26. data/lib/openc3/models/target_model.rb +2 -2
  27. data/lib/openc3/models/tool_model.rb +17 -8
  28. data/lib/openc3/operators/operator.rb +5 -1
  29. data/lib/openc3/packets/packet.rb +21 -7
  30. data/lib/openc3/packets/packet_item.rb +3 -2
  31. data/lib/openc3/script/script.rb +8 -0
  32. data/lib/openc3/script/script_runner.rb +1 -2
  33. data/lib/openc3/script/storage.rb +2 -1
  34. data/lib/openc3/script/suite.rb +22 -13
  35. data/lib/openc3/script/suite_runner.rb +5 -4
  36. data/lib/openc3/system/system.rb +6 -3
  37. data/lib/openc3/topics/interface_topic.rb +1 -1
  38. data/lib/openc3/topics/router_topic.rb +1 -1
  39. data/lib/openc3/utilities/aws_bucket.rb +20 -3
  40. data/lib/openc3/utilities/bucket.rb +1 -1
  41. data/lib/openc3/utilities/bucket_file_cache.rb +1 -1
  42. data/lib/openc3/utilities/bucket_utilities.rb +1 -1
  43. data/lib/openc3/utilities/local_mode.rb +1 -0
  44. data/lib/openc3/utilities/metric.rb +77 -101
  45. data/lib/openc3/utilities/s3_autoload.rb +19 -9
  46. data/lib/openc3/utilities/target_file.rb +3 -1
  47. data/lib/openc3/version.rb +6 -6
  48. data/templates/plugin-template/LICENSE.txt +7 -0
  49. data/templates/plugin-template/plugin.gemspec +4 -4
  50. metadata +4 -3
  51. data/data/config/_interfaces.yaml.err +0 -1017
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 883789b740b96ae3fac34c78b5a643a2fa1fb087d601a0f87c46d0062eec3dec
4
- data.tar.gz: 510b9f4c8f98735f033f6dd6d31ebd86ffaeb8df0664d77720e15a3df3df6dcb
3
+ metadata.gz: ba92696b60117db745207ad94efe543da2db11f25212f70269a6305cb8445295
4
+ data.tar.gz: ac3d2cc21a962434b478f708644bb33b702858c770a4c93c0017529bcb5b7b05
5
5
  SHA512:
6
- metadata.gz: 999476145415b7f6b160319fee0f67174ad2cdf415ef3a87628177964e37bf690e5c368bf3da9c6a08ca663679999b71b3e7d4c176c2a302724073b7c5c8faca
7
- data.tar.gz: 206852353795f779b2d8481f68bcf881c465ceaf3c6a48b852a61dab34275b7736249def97edd7932e7fa9286d71f07f210ca340c0363dbce30839504d548640
6
+ metadata.gz: cca2d57593526f75888406d0b7946f22ce53823d6e2a45e5204a0856948b6b752b9a7a9612f417d973a6a50c55bf46b16800f4e9295cbeb451d48600d1ae71d0
7
+ data.tar.gz: 37cb6cf7247cc6956172641d95755145e409ef09ee35dc08d7bae7650e422961c7d17caf83ee7affb428da84057a94625c4484e5b11165bf50db7d692d72a0f2
data/bin/openc3cli CHANGED
@@ -322,14 +322,14 @@ ensure
322
322
  exit(result)
323
323
  end
324
324
 
325
- def update_plugin(plugin_file_path, plugin_name, variables: nil, plugin_txt_lines: nil, scope:, existing_plugin_name:)
325
+ def update_plugin(plugin_file_path, plugin_name, variables: nil, plugin_txt_lines: nil, scope:, existing_plugin_name:, force: false)
326
326
  new_gem = File.basename(plugin_file_path)
327
327
  old_gem = existing_plugin_name.split("__")[0]
328
328
  puts "Updating existing plugin: #{existing_plugin_name} with #{File.basename(plugin_file_path)}"
329
329
  plugin_model = OpenC3::PluginModel.get_model(name: existing_plugin_name, scope: scope)
330
330
  begin
331
331
  # Only update if something has changed
332
- if (new_gem != old_gem) or (variables and variables != plugin_model.variables) or (plugin_txt_lines and plugin_txt_lines != plugin_model.plugin_txt_lines)
332
+ if force or (new_gem != old_gem) or (variables and variables != plugin_model.variables) or (plugin_txt_lines and plugin_txt_lines != plugin_model.plugin_txt_lines)
333
333
  puts "Gem version change detected - New: #{new_gem}, Old: #{old_gem}" if new_gem != old_gem
334
334
  if variables and variables != plugin_model.variables
335
335
  pp_variables = ""
@@ -360,7 +360,7 @@ end
360
360
  # This code is used from the command line and is the same code that gets called if you
361
361
  # edit/upgrade or install a new plugin from the Admin interface
362
362
  #
363
- # Usage: cli load gemfile_path [scope] [plugin_hash_file_path]
363
+ # Usage: cli load gemfile_path [scope] [plugin_hash_file_path] [force]
364
364
  #
365
365
  # With just gemfile_path and/or scope: Will do nothing if any plugin
366
366
  # with the same gem file already exists
@@ -370,7 +370,10 @@ end
370
370
  # Otherwise, it will be assumed that the plugin is intentionally being installed for a second
371
371
  # time
372
372
  #
373
- def load_plugin(plugin_file_path, scope:, plugin_hash_file: nil)
373
+ # Pass true as the last argument to force install even if a plugin with
374
+ # the same version number exists
375
+ #
376
+ def load_plugin(plugin_file_path, scope:, plugin_hash_file: nil, force: false)
374
377
  scope ||= 'DEFAULT'
375
378
  # Only create the scope if it doesn't already exist
376
379
  unless OpenC3::ScopeModel.names.include?(scope)
@@ -403,7 +406,7 @@ def load_plugin(plugin_file_path, scope:, plugin_hash_file: nil)
403
406
  found = true
404
407
  # Upgrade if version changed else do nothing
405
408
  if file_full_name != full_name
406
- update_plugin(plugin_file_path, plugin_name, scope: scope, existing_plugin_name: plugin_name)
409
+ update_plugin(plugin_file_path, plugin_name, scope: scope, existing_plugin_name: plugin_name, force: force)
407
410
  else
408
411
  puts "No version change detected for: #{plugin_name}"
409
412
  end
@@ -430,15 +433,16 @@ def load_plugin(plugin_file_path, scope:, plugin_hash_file: nil)
430
433
 
431
434
  if existing_plugin_hash
432
435
  # Upgrade or Edit
433
- update_plugin(plugin_file_path, plugin_hash['name'], variables: plugin_hash['variables'], plugin_txt_lines: plugin_hash['plugin_txt_lines'], scope: scope, existing_plugin_name: existing_plugin_hash['name'])
436
+ update_plugin(plugin_file_path, plugin_hash['name'], variables: plugin_hash['variables'], scope: scope,
437
+ plugin_txt_lines: plugin_hash['plugin_txt_lines'], existing_plugin_name: existing_plugin_hash['name'], force: force)
434
438
  else
435
439
  # New Install
436
440
  puts "Loading new plugin: #{plugin_file_path}\n#{plugin_hash}"
437
441
  plugin_hash = OpenC3::PluginModel.install_phase2(plugin_hash, scope: scope)
438
442
  OpenC3::LocalMode.update_local_plugin(plugin_file_path, plugin_hash, scope: scope)
439
443
  end
440
- rescue => err
441
- abort("Error installing plugin: #{scope}: #{plugin_file_path}: #{err.formatted}")
444
+ rescue => error
445
+ abort("Error installing plugin: #{scope}: #{plugin_file_path}\n#{error.message}")
442
446
  end
443
447
  end
444
448
 
@@ -517,129 +521,128 @@ def run_migrations(folder)
517
521
  end
518
522
  end
519
523
 
520
- if __FILE__ == $0
521
- if not ARGV[0].nil? # argument(s) given
524
+ if not ARGV[0].nil? # argument(s) given
522
525
 
523
- # Handle each task
524
- case ARGV[0].downcase
526
+ # Handle each task
527
+ case ARGV[0].downcase
525
528
 
526
- when 'rake'
527
- puts `rake #{ARGV[1..-1].join(' ')}`
529
+ when 'rake'
530
+ puts `rake #{ARGV[1..-1].join(' ')}`
528
531
 
529
- when 'validate'
530
- validate_plugin(ARGV[1], scope: ARGV[2], variables_file: ARGV[3])
532
+ when 'validate'
533
+ validate_plugin(ARGV[1], scope: ARGV[2], variables_file: ARGV[3])
531
534
 
532
- when 'load'
533
- load_plugin(ARGV[1], scope: ARGV[2], plugin_hash_file: ARGV[3])
535
+ when 'load'
536
+ # force is a boolean so if they pass 'force' it is true
537
+ # See plugins_controller.rb install for usage
538
+ load_plugin(ARGV[1], scope: ARGV[2], plugin_hash_file: ARGV[3], force: ARGV[4] == 'force')
534
539
 
535
- when 'unload'
536
- unload_plugin(ARGV[1], scope: ARGV[2])
540
+ when 'unload'
541
+ unload_plugin(ARGV[1], scope: ARGV[2])
537
542
 
538
- when 'geminstall'
539
- gem_install(ARGV[1], scope: ARGV[2])
543
+ when 'geminstall'
544
+ gem_install(ARGV[1], scope: ARGV[2])
540
545
 
541
- when 'generate'
542
- generate(ARGV[1..-1])
546
+ when 'generate'
547
+ generate(ARGV[1..-1])
543
548
 
544
- when 'migrate'
545
- migrate(ARGV[1..-1])
549
+ when 'migrate'
550
+ migrate(ARGV[1..-1])
546
551
 
547
- when 'rubysloc'
548
- puts `ruby /openc3/bin/rubysloc #{ARGV[1..-1].join(' ')}`
552
+ when 'rubysloc'
553
+ puts `ruby /openc3/bin/rubysloc #{ARGV[1..-1].join(' ')}`
549
554
 
550
- when 'cstol_converter'
551
- puts `ruby /openc3/bin/cstol_converter #{ARGV[1..-1].join(' ')}`
555
+ when 'cstol_converter'
556
+ puts `ruby /openc3/bin/cstol_converter #{ARGV[1..-1].join(' ')}`
552
557
 
553
- when 'xtce_converter'
554
- xtce_converter(ARGV[1..-1])
558
+ when 'xtce_converter'
559
+ xtce_converter(ARGV[1..-1])
555
560
 
556
- when 'bridge'
557
- ENV['OPENC3_NO_STORE'] = '1'
558
- filename = ARGV[1]
559
- filename = 'bridge.txt' unless filename
560
- bridge = OpenC3::Bridge.new(filename)
561
- begin
562
- while true
563
- sleep(1)
564
- end
565
- rescue Interrupt
566
- exit(0)
561
+ when 'bridge'
562
+ ENV['OPENC3_NO_STORE'] = '1'
563
+ filename = ARGV[1]
564
+ filename = 'bridge.txt' unless filename
565
+ bridge = OpenC3::Bridge.new(filename)
566
+ begin
567
+ while true
568
+ sleep(1)
567
569
  end
570
+ rescue Interrupt
571
+ exit(0)
572
+ end
568
573
 
569
- when 'bridgesetup'
570
- ENV['OPENC3_NO_STORE'] = '1'
571
- filename = ARGV[1]
572
- filename = 'bridge.txt' unless filename
573
- unless File.exist?(filename)
574
- OpenC3::BridgeConfig.generate_default(filename)
575
- end
574
+ when 'bridgesetup'
575
+ ENV['OPENC3_NO_STORE'] = '1'
576
+ filename = ARGV[1]
577
+ filename = 'bridge.txt' unless filename
578
+ unless File.exist?(filename)
579
+ OpenC3::BridgeConfig.generate_default(filename)
580
+ end
576
581
 
577
- when 'help'
578
- print_usage()
579
-
580
- when 'redis'
581
- case (ARGV[1])
582
- when 'keys'
583
- get_redis_keys()
584
- when 'hget'
585
- redis = Redis.new(url: $redis_url, username: ENV['OPENC3_REDIS_USERNAME'], password: ENV['OPENC3_REDIS_PASSWORD'])
586
- puts JSON.parse(redis.hget(ARGV[2], ARGV[3]), :allow_nan => true, :create_additions => true)
587
- else
588
- puts "Unknown redis task: #{ARGV[1]}\n"
589
- puts "Valid redis tasks: keys, hget"
590
- end
582
+ when 'help'
583
+ print_usage()
591
584
 
592
- when 'removebase'
593
- # Used to remove tool base to better support enterprise upgrade
594
- scopes = OpenC3::ScopeModel.all
595
- scopes.each do |scope_name, scope|
596
- plugins = OpenC3::PluginModel.all(scope: scope_name)
597
- plugins.each do |plugin_name, plugin|
598
- if plugin["name"] =~ /tool-base/ and plugin["name"] !~ /enterprise/
599
- unload_plugin(plugin_name, scope: scope_name)
600
- end
601
- if plugin["name"] =~ /tool-admin/ and plugin["name"] !~ /enterprise/
602
- unload_plugin(plugin_name, scope: scope_name)
603
- end
585
+ when 'redis'
586
+ case (ARGV[1])
587
+ when 'keys'
588
+ get_redis_keys()
589
+ when 'hget'
590
+ redis = Redis.new(url: $redis_url, username: ENV['OPENC3_REDIS_USERNAME'], password: ENV['OPENC3_REDIS_PASSWORD'])
591
+ puts JSON.parse(redis.hget(ARGV[2], ARGV[3]), :allow_nan => true, :create_additions => true)
592
+ else
593
+ puts "Unknown redis task: #{ARGV[1]}\n"
594
+ puts "Valid redis tasks: keys, hget"
595
+ end
596
+
597
+ when 'removebase'
598
+ # Used to remove tool base to better support enterprise upgrade
599
+ scopes = OpenC3::ScopeModel.all
600
+ scopes.each do |scope_name, scope|
601
+ plugins = OpenC3::PluginModel.all(scope: scope_name)
602
+ plugins.each do |plugin_name, plugin|
603
+ if plugin["name"] =~ /tool-base/ and plugin["name"] !~ /enterprise/
604
+ unload_plugin(plugin_name, scope: scope_name)
605
+ end
606
+ if plugin["name"] =~ /tool-admin/ and plugin["name"] !~ /enterprise/
607
+ unload_plugin(plugin_name, scope: scope_name)
604
608
  end
605
609
  end
610
+ end
606
611
 
607
- when 'removeenterprise'
608
- # Used to remove enterprise plugins to better support downgrade
609
- scopes = OpenC3::ScopeModel.all
610
- scopes.each do |scope_name, scope|
611
- plugins = OpenC3::PluginModel.all(scope: scope_name)
612
- plugins.each do |plugin_name, plugin|
613
- if plugin["name"] =~ /enterprise/
614
- unload_plugin(plugin_name, scope: scope_name)
615
- end
612
+ when 'removeenterprise'
613
+ # Used to remove enterprise plugins to better support downgrade
614
+ scopes = OpenC3::ScopeModel.all
615
+ scopes.each do |scope_name, scope|
616
+ plugins = OpenC3::PluginModel.all(scope: scope_name)
617
+ plugins.each do |plugin_name, plugin|
618
+ if plugin["name"] =~ /enterprise/
619
+ unload_plugin(plugin_name, scope: scope_name)
616
620
  end
617
621
  end
622
+ end
618
623
 
619
- when 'destroyscope'
620
- scope = OpenC3::ScopeModel.get_model(name: ARGV[1])
621
- scope.destroy
624
+ when 'destroyscope'
625
+ scope = OpenC3::ScopeModel.get_model(name: ARGV[1])
626
+ scope.destroy
622
627
 
623
- when 'localinit'
624
- OpenC3::LocalMode.local_init()
628
+ when 'localinit'
629
+ OpenC3::LocalMode.local_init()
625
630
 
626
- when 'initbuckets'
627
- client = OpenC3::Bucket.getClient()
628
- client.create(ENV['OPENC3_CONFIG_BUCKET'])
629
- client.create(ENV['OPENC3_LOGS_BUCKET'])
630
- client.create(ENV['OPENC3_TOOLS_BUCKET'])
631
- client.ensure_public(ENV['OPENC3_TOOLS_BUCKET'])
631
+ when 'initbuckets'
632
+ client = OpenC3::Bucket.getClient()
633
+ client.create(ENV['OPENC3_CONFIG_BUCKET'])
634
+ client.create(ENV['OPENC3_LOGS_BUCKET'])
635
+ client.create(ENV['OPENC3_TOOLS_BUCKET'])
636
+ client.ensure_public(ENV['OPENC3_TOOLS_BUCKET'])
632
637
 
633
- when 'runmigrations'
634
- run_migrations(ARGV[1])
638
+ when 'runmigrations'
639
+ run_migrations(ARGV[1])
635
640
 
636
- else # Unknown task
637
- print_usage()
638
- abort("Unknown task: #{ARGV[0]}")
639
- end
640
-
641
- else # No arguments given
641
+ else # Unknown task
642
642
  print_usage()
643
+ abort("Unknown task: #{ARGV[0]}")
643
644
  end
644
645
 
645
- end
646
+ else # No arguments given
647
+ print_usage()
648
+ end
@@ -5,11 +5,13 @@ STATE:
5
5
  description: Key value pairs allow for user friendly strings. For example,
6
6
  you might define states for ON = 1 and OFF = 0. This allows the word ON to be
7
7
  used rather than the number 1 when sending the telemetry item and allows
8
- for much greater clarity and less chance for user error.
8
+ for much greater clarity and less chance for user error. A catch all value
9
+ of ANY applies to all other values not already defined as state values.
9
10
  example: |
10
11
  APPEND_ITEM ENABLE 32 UINT "Enable setting"
11
12
  STATE FALSE 0
12
13
  STATE TRUE 1
14
+ STATE ERROR ANY # Match all other values to ERROR
13
15
  APPEND_ITEM STRING 1024 STRING "String"
14
16
  STATE "NOOP" "NOOP" GREEN
15
17
  STATE "ARM LASER" "ARM LASER" YELLOW
@@ -21,7 +23,7 @@ STATE:
21
23
  values: .*
22
24
  - name: Value
23
25
  required: true
24
- description: The numerical state value
26
+ description: The numerical state value or ANY to apply the state to all other values
25
27
  values: .*
26
28
  - name: Color
27
29
  required: false
@@ -80,8 +80,8 @@ SELECT_TABLE:
80
80
  description: The name of the existin table
81
81
  values: .*
82
82
  DEFAULT:
83
- summary: Specify default values for a SINGLE row in a multi-column table.
84
- If you have multiple rows you need a DEFAULT line for each row.
83
+ summary: Specify default values for a SINGLE row in a multi-column table
84
+ description: If you have multiple rows you need a DEFAULT line for each row.
85
85
  If all your rows are identical consider using ERB as shown in the OpenC3 demo.
86
86
  parameters:
87
87
  - name: Default values
@@ -47,7 +47,7 @@ TOOL:
47
47
  values: .+
48
48
  CATEGORY:
49
49
  summary: Category for the tool
50
- description: Associates the tool with a category. In a future release this will be able to organize tools into submenus in the Navigation menu.
50
+ description: Associates the tool with a category which becomes a submenu in the Navigation menu.
51
51
  parameters:
52
52
  - name: Category Name
53
53
  required: true
@@ -41,6 +41,7 @@ static ID id_method_scan = 0;
41
41
  static ID id_method_strip = 0;
42
42
  static ID id_method_to_s = 0;
43
43
  static ID id_method_upcase = 0;
44
+ static ID id_method_parse_errors = 0;
44
45
 
45
46
  /*
46
47
  * Removes quotes from the given string if present.
@@ -103,6 +104,7 @@ static VALUE parse_loop(VALUE self, VALUE io, VALUE yield_non_keyword_lines, VAL
103
104
  volatile VALUE ivar_keyword = Qnil;
104
105
  volatile VALUE ivar_parameters = rb_ary_new();
105
106
  volatile VALUE ivar_line = rb_str_new2("");
107
+ volatile VALUE errors = rb_ary_new();
106
108
 
107
109
  rb_ivar_set(self, id_ivar_line_number, INT2FIX(0));
108
110
  rb_ivar_set(self, id_ivar_keyword, ivar_keyword);
@@ -205,7 +207,12 @@ static VALUE parse_loop(VALUE self, VALUE io, VALUE yield_non_keyword_lines, VAL
205
207
  rb_ary_clear(array);
206
208
  rb_ary_push(array, ivar_keyword);
207
209
  rb_ary_push(array, ivar_parameters);
208
- rb_yield(array);
210
+ line = rb_protect(rb_yield, array, &result);
211
+ if (result)
212
+ {
213
+ rb_ary_push(errors, rb_errinfo());
214
+ rb_set_errinfo(Qnil);
215
+ }
209
216
  }
210
217
  ivar_line = rb_str_new2("");
211
218
  rb_ivar_set(self, id_ivar_line, ivar_line);
@@ -247,11 +254,18 @@ static VALUE parse_loop(VALUE self, VALUE io, VALUE yield_non_keyword_lines, VAL
247
254
  rb_ary_clear(array);
248
255
  rb_ary_push(array, ivar_keyword);
249
256
  rb_ary_push(array, ivar_parameters);
250
- rb_yield(array);
257
+ line = rb_protect(rb_yield, array, &result);
258
+ if (result)
259
+ {
260
+ rb_ary_push(errors, rb_errinfo());
261
+ rb_set_errinfo(Qnil);
262
+ }
251
263
  ivar_line = rb_str_new2("");
252
264
  rb_ivar_set(self, id_ivar_line, ivar_line);
253
265
  }
254
266
 
267
+ rb_funcall(self, id_method_parse_errors, 1, errors);
268
+
255
269
  if (RTEST(progress_callback))
256
270
  {
257
271
  rb_funcall(progress_callback, id_method_call, 1, rb_float_new(1.0));
@@ -278,6 +292,7 @@ void Init_config_parser(void)
278
292
  id_method_strip = rb_intern("strip");
279
293
  id_method_to_s = rb_intern("to_s");
280
294
  id_method_upcase = rb_intern("upcase");
295
+ id_method_parse_errors = rb_intern("parse_errors");
281
296
 
282
297
  mOpenC3 = rb_define_module("OpenC3");
283
298
 
@@ -26,6 +26,7 @@ require 'openc3/api/cmd_api'
26
26
  require 'openc3/api/config_api'
27
27
  require 'openc3/api/interface_api'
28
28
  require 'openc3/api/limits_api'
29
+ require 'openc3/api/metrics_api'
29
30
  require 'openc3/api/offline_access_api'
30
31
  require 'openc3/api/router_api'
31
32
  require 'openc3/api/settings_api'
@@ -0,0 +1,97 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2023 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/metric_model'
20
+ require 'openc3/utilities/authentication'
21
+ require 'openc3/utilities/store'
22
+
23
+ module OpenC3
24
+ module Api
25
+ WHITELIST ||= []
26
+ WHITELIST.concat([
27
+ 'get_metrics',
28
+ ])
29
+
30
+ DELAY_METRICS = {}
31
+ DELAY_METRICS['decom_topic_delta_seconds'] = 0.0
32
+ DELAY_METRICS['interface_topic_delta_seconds'] = 0.0
33
+ DELAY_METRICS['log_topic_delta_seconds'] = 0.0
34
+ DELAY_METRICS['router_topic_delta_seconds'] = 0.0
35
+ DELAY_METRICS['text_log_topic_delta_seconds'] = 0.0
36
+
37
+ DURATION_METRICS = {}
38
+ DURATION_METRICS['decom_duration_seconds'] = 0.0
39
+ DURATION_METRICS['reducer_minute_processing_seconds'] = 0
40
+ DURATION_METRICS['reducer_hour_processing_seconds'] = 0
41
+ DURATION_METRICS['reducer_day_processing_seconds'] = 0
42
+
43
+ SUM_METRICS = {}
44
+ SUM_METRICS['cleanup_total'] = 0
45
+ SUM_METRICS['cleanup_delete_total'] = 0
46
+ SUM_METRICS['decom_total'] = 0
47
+ SUM_METRICS['decom_error_total'] = 0
48
+ SUM_METRICS['interface_cmd_total'] = 0
49
+ SUM_METRICS['interface_tlm_total'] = 0
50
+ SUM_METRICS['interface_directive_total'] = 0
51
+ SUM_METRICS['log_total'] = 0
52
+ SUM_METRICS['log_error_total'] = 0
53
+ SUM_METRICS['periodic_total'] = 0
54
+ SUM_METRICS['reducer_total'] = 0
55
+ SUM_METRICS['reducer_error_total'] = 0
56
+ SUM_METRICS['router_cmd_total'] = 0
57
+ SUM_METRICS['router_tlm_total'] = 0
58
+ SUM_METRICS['router_directive_total'] = 0
59
+ SUM_METRICS['text_log_total'] = 0
60
+ SUM_METRICS['text_log_error_total'] = 0
61
+
62
+ def get_metrics(scope: $openc3_scope, token: $openc3_token)
63
+ authorize(permission: 'system', scope: scope, token: token)
64
+
65
+ sum_metrics = SUM_METRICS.dup
66
+ duration_metrics = DURATION_METRICS.dup
67
+ delay_metrics = DELAY_METRICS.dup
68
+
69
+ metrics = MetricModel.all(scope: scope)
70
+ metrics.each do |microservice_name, metrics|
71
+ next unless metrics and metrics['values']
72
+ metrics['values'].each do |metric_name, data|
73
+ value = data['value']
74
+ if sum_metrics[metric_name]
75
+ sum_metrics[metric_name] += value
76
+ elsif duration_metrics[metric_name]
77
+ previous = duration_metrics[metric_name]
78
+ duration_metrics[metric_name] = value if value > previous
79
+ elsif delay_metrics.include?(metric_name)
80
+ previous = delay_metrics[metric_name]
81
+ delay_metrics[metric_name] = value if value > previous
82
+ else
83
+ # Ignore other metrics for now
84
+ end
85
+ end
86
+ end
87
+
88
+ result = delay_metrics
89
+ result.merge!(duration_metrics)
90
+ result.merge!(sum_metrics)
91
+
92
+ result.merge!(MetricModel.redis_metrics)
93
+
94
+ return result
95
+ end
96
+ end
97
+ end
@@ -118,7 +118,8 @@ module OpenC3
118
118
  # @param type [Symbol] Telemetry type, :RAW, :CONVERTED (default), :FORMATTED, or :WITH_UNITS
119
119
  def inject_tlm(target_name, packet_name, item_hash = nil, type: :CONVERTED, scope: $openc3_scope, token: $openc3_token)
120
120
  authorize(permission: 'tlm_set', target_name: target_name, packet_name: packet_name, scope: scope, token: token)
121
- unless CvtModel::VALUE_TYPES.include?(type.intern)
121
+ type = type.to_s.intern
122
+ unless CvtModel::VALUE_TYPES.include?(type)
122
123
  raise "Unknown type '#{type}' for #{target_name} #{packet_name}"
123
124
  end
124
125
 
@@ -219,8 +219,6 @@ module OpenC3
219
219
  size,
220
220
  PARSING_REGEX,
221
221
  &block)
222
- rescue Exception => e # Catch EVERYTHING so we can re-raise with additional info
223
- raise e, "#{e}\n\nParsed output in #{file.path}", e.backtrace
224
222
  ensure
225
223
  file.close unless file.closed?
226
224
  end
@@ -446,6 +444,22 @@ module OpenC3
446
444
  value
447
445
  end
448
446
 
447
+ def parse_errors(errors)
448
+ return if errors.empty?
449
+ message = ''
450
+ errors.each do |error|
451
+ if error.is_a? OpenC3::ConfigParser::Error
452
+ message += "\n#{File.basename(error.filename)}:#{error.line_number}: #{error.line}"
453
+ message += "\nError: #{error.message}"
454
+ message += "\nUsage: #{error.usage}" unless error.usage.empty?
455
+ else
456
+ message += "\n#{error.message}"
457
+ end
458
+ message += "\n"
459
+ end
460
+ raise message
461
+ end
462
+
449
463
  if RUBY_ENGINE != 'ruby' or ENV['OPENC3_NO_EXT']
450
464
  # Iterates over each line of the io object and yields the keyword and parameters
451
465
  def parse_loop(io, yield_non_keyword_lines, remove_quotes, size, rx)
@@ -454,6 +468,7 @@ module OpenC3
454
468
  @keyword = nil
455
469
  @parameters = []
456
470
  @line = ''
471
+ errors = []
457
472
 
458
473
  while true
459
474
  @line_number += 1
@@ -516,7 +531,11 @@ module OpenC3
516
531
  # Ignore lines without keywords: comments and blank lines
517
532
  if @keyword.nil?
518
533
  if yield_non_keyword_lines
519
- yield(@keyword, @parameters)
534
+ begin
535
+ yield(@keyword, @parameters)
536
+ rescue => error
537
+ errors << error
538
+ end
520
539
  end
521
540
  @line = ''
522
541
  next
@@ -545,10 +564,16 @@ module OpenC3
545
564
  end
546
565
  end
547
566
 
548
- yield(@keyword, @parameters)
567
+ begin
568
+ yield(@keyword, @parameters)
569
+ rescue => error
570
+ errors << error
571
+ end
549
572
  @line = ''
550
573
  end
551
574
 
575
+ parse_errors(errors)
576
+
552
577
  @@progress_callback.call(1.0) if @@progress_callback
553
578
 
554
579
  return nil
@@ -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 'date'
@@ -58,6 +58,7 @@ class Time
58
58
  MINUTES_PER_HOUR = 60
59
59
  HOURS_PER_DAY = 24
60
60
  NSEC_PER_SECOND = 1_000_000_000
61
+ NSEC_PER_MSEC = 1_000_000
61
62
  USEC_PER_SECOND = USEC_PER_MSEC * MSEC_PER_SECOND
62
63
  MSEC_PER_MINUTE = 60 * MSEC_PER_SECOND
63
64
  MSEC_PER_HOUR = 60 * MSEC_PER_MINUTE
@@ -508,4 +509,8 @@ class Time
508
509
  nanoseconds = nsec_from_epoch % NSEC_PER_SECOND
509
510
  Time.at(seconds, nanoseconds, :nsec)
510
511
  end
512
+
513
+ def to_msec_from_epoch
514
+ (self.tv_sec * MSEC_PER_SECOND) + (self.tv_nsec / NSEC_PER_MSEC)
515
+ end
511
516
  end
@@ -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 @microservice_sleeper.sleep(target.cleanup_poll_time)
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