cosmos 5.0.2.pre.beta2 → 5.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/bin/cosmos +1 -1
  3. data/data/config/microservice.yaml +47 -35
  4. data/data/config/plugins.yaml +3 -150
  5. data/data/config/target.yaml +70 -0
  6. data/data/config/tool.yaml +37 -31
  7. data/lib/cosmos/api/api.rb +1 -25
  8. data/lib/cosmos/api/cmd_api.rb +17 -6
  9. data/lib/cosmos/api/config_api.rb +10 -4
  10. data/lib/cosmos/api/limits_api.rb +1 -1
  11. data/lib/cosmos/api/settings_api.rb +19 -7
  12. data/lib/cosmos/api/target_api.rb +2 -2
  13. data/lib/cosmos/api/tlm_api.rb +69 -41
  14. data/lib/cosmos/config/config_parser.rb +19 -22
  15. data/lib/cosmos/config/meta_config_parser.rb +1 -1
  16. data/lib/cosmos/conversions/generic_conversion.rb +2 -2
  17. data/lib/cosmos/conversions/polynomial_conversion.rb +5 -8
  18. data/lib/cosmos/conversions/segmented_polynomial_conversion.rb +26 -9
  19. data/lib/cosmos/io/json_drb.rb +5 -1
  20. data/lib/cosmos/logs/log_writer.rb +2 -2
  21. data/lib/cosmos/microservices/cleanup_microservice.rb +28 -29
  22. data/lib/cosmos/microservices/decom_microservice.rb +1 -1
  23. data/lib/cosmos/microservices/interface_microservice.rb +0 -1
  24. data/lib/cosmos/microservices/microservice.rb +3 -3
  25. data/lib/cosmos/microservices/reducer_microservice.rb +12 -10
  26. data/lib/cosmos/models/cvt_model.rb +6 -6
  27. data/lib/cosmos/models/gem_model.rb +3 -3
  28. data/lib/cosmos/models/info_model.rb +1 -1
  29. data/lib/cosmos/models/interface_status_model.rb +1 -1
  30. data/lib/cosmos/models/metadata_model.rb +42 -216
  31. data/lib/cosmos/models/metric_model.rb +2 -2
  32. data/lib/cosmos/models/microservice_model.rb +1 -1
  33. data/lib/cosmos/models/microservice_status_model.rb +1 -1
  34. data/lib/cosmos/models/model.rb +16 -16
  35. data/lib/cosmos/models/note_model.rb +124 -0
  36. data/lib/cosmos/models/ping_model.rb +2 -1
  37. data/lib/cosmos/models/plugin_model.rb +1 -1
  38. data/lib/cosmos/models/process_status_model.rb +1 -1
  39. data/lib/cosmos/models/scope_model.rb +9 -26
  40. data/lib/cosmos/models/settings_model.rb +55 -0
  41. data/lib/cosmos/models/sorted_model.rb +165 -0
  42. data/lib/cosmos/models/target_model.rb +120 -13
  43. data/lib/cosmos/models/tool_config_model.rb +38 -0
  44. data/lib/cosmos/models/tool_model.rb +1 -1
  45. data/lib/cosmos/models/widget_model.rb +1 -1
  46. data/lib/cosmos/operators/microservice_operator.rb +2 -1
  47. data/lib/cosmos/packets/packet.rb +23 -0
  48. data/lib/cosmos/packets/packet_config.rb +2 -2
  49. data/lib/cosmos/packets/packet_item.rb +57 -0
  50. data/lib/cosmos/packets/packet_item_limits.rb +14 -2
  51. data/lib/cosmos/packets/parsers/packet_item_parser.rb +1 -1
  52. data/lib/cosmos/packets/parsers/packet_parser.rb +1 -1
  53. data/lib/cosmos/packets/parsers/xtce_parser.rb +1 -1
  54. data/lib/cosmos/packets/structure_item.rb +10 -1
  55. data/lib/cosmos/script/api_shared.rb +30 -25
  56. data/lib/cosmos/script/calendar.rb +26 -15
  57. data/lib/cosmos/script/commands.rb +5 -7
  58. data/lib/cosmos/script/script.rb +19 -39
  59. data/lib/cosmos/script/storage.rb +92 -105
  60. data/lib/cosmos/system/system.rb +2 -1
  61. data/lib/cosmos/tools/table_manager/table_item.rb +1 -1
  62. data/lib/cosmos/top_level.rb +5 -1
  63. data/lib/cosmos/topics/autonomic_topic.rb +2 -2
  64. data/lib/cosmos/topics/calendar_topic.rb +1 -1
  65. data/lib/cosmos/topics/command_decom_topic.rb +35 -1
  66. data/lib/cosmos/topics/command_topic.rb +6 -4
  67. data/lib/cosmos/topics/interface_topic.rb +8 -8
  68. data/lib/cosmos/topics/limits_event_topic.rb +5 -3
  69. data/lib/cosmos/topics/notifications_topic.rb +1 -1
  70. data/lib/cosmos/topics/router_topic.rb +9 -9
  71. data/lib/cosmos/topics/telemetry_decom_topic.rb +5 -1
  72. data/lib/cosmos/topics/telemetry_topic.rb +1 -1
  73. data/lib/cosmos/topics/timeline_topic.rb +1 -1
  74. data/lib/cosmos/topics/topic.rb +23 -8
  75. data/lib/cosmos/utilities/logger.rb +4 -3
  76. data/lib/cosmos/utilities/metric.rb +32 -26
  77. data/lib/cosmos/utilities/s3.rb +61 -0
  78. data/lib/cosmos/utilities/s3_file_cache.rb +12 -6
  79. data/lib/cosmos/utilities/store.rb +1 -0
  80. data/lib/cosmos/utilities/store_autoload.rb +25 -134
  81. data/lib/cosmos/version.rb +6 -5
  82. data/templates/plugin-template/plugin.gemspec +0 -2
  83. metadata +9 -6
  84. data/lib/cosmos/models/narrative_model.rb +0 -280
@@ -300,10 +300,10 @@ module Cosmos
300
300
  #
301
301
  # @param args [String|Array<String>] See the description for calling style
302
302
  # @param type [Symbol] Telemetry type, :RAW, :CONVERTED (default), :FORMATTED, or :WITH_UNITS
303
- def wait_check(*args, type: :CONVERTED, scope: $cosmos_scope, token: $cosmos_token)
303
+ def wait_check(*args, type: :CONVERTED, scope: $cosmos_scope, token: $cosmos_token, &block)
304
304
  target_name, packet_name, item_name, comparison_to_eval, timeout, polling_rate = _wait_check_process_args(args, scope: scope, token: token)
305
305
  start_time = Time.now.sys
306
- success, value = cosmos_script_wait_implementation(target_name, packet_name, item_name, type, comparison_to_eval, timeout, polling_rate, scope: scope, token: token)
306
+ success, value = cosmos_script_wait_implementation(target_name, packet_name, item_name, type, comparison_to_eval, timeout, polling_rate, scope: scope, token: token, &block)
307
307
  time = Time.now.sys - start_time
308
308
  check_str = "CHECK: #{_upcase(target_name, packet_name, item_name)} #{comparison_to_eval}"
309
309
  with_value_str = "with value == #{value} after waiting #{time} seconds"
@@ -321,8 +321,8 @@ module Cosmos
321
321
  end
322
322
 
323
323
  # @deprecated use wait_check with type: :RAW
324
- def wait_check_raw(*args, scope: $cosmos_scope, token: $cosmos_token)
325
- wait_check(*args, type: :RAW, scope: scope, token: token)
324
+ def wait_check_raw(*args, scope: $cosmos_scope, token: $cosmos_token, &block)
325
+ wait_check(*args, type: :RAW, scope: scope, token: token, &block)
326
326
  end
327
327
 
328
328
  # Wait for the value of a telmetry item to be within a tolerance of a value
@@ -334,7 +334,7 @@ module Cosmos
334
334
  #
335
335
  # @param args [String|Array<String>] See the description for calling style
336
336
  # @param type [Symbol] Telemetry type, :RAW or :CONVERTED (default)
337
- def wait_check_tolerance(*args, type: :CONVERTED, scope: $cosmos_scope, token: $cosmos_token)
337
+ def wait_check_tolerance(*args, type: :CONVERTED, scope: $cosmos_scope, token: $cosmos_token, &block)
338
338
  raise "Invalid type '#{type}' for wait_check_tolerance" unless %i(RAW CONVERTED).include?(type)
339
339
 
340
340
  target_name, packet_name, item_name, expected_value, tolerance, timeout, polling_rate = _wait_tolerance_process_args(args, scope: scope, token: token)
@@ -343,7 +343,7 @@ module Cosmos
343
343
  if value.is_a?(Array)
344
344
  expected_value, tolerance = array_tolerance_process_args(value.size, expected_value, tolerance, 'wait_check_tolerance', scope: scope, token: token)
345
345
 
346
- success, value = cosmos_script_wait_implementation_array_tolerance(value.size, target_name, packet_name, item_name, type, expected_value, tolerance, timeout, polling_rate, scope: scope, token: token)
346
+ success, value = cosmos_script_wait_implementation_array_tolerance(value.size, target_name, packet_name, item_name, type, expected_value, tolerance, timeout, polling_rate, scope: scope, token: token, &block)
347
347
  time = Time.now.sys - start_time
348
348
 
349
349
  message = ""
@@ -388,8 +388,8 @@ module Cosmos
388
388
  end
389
389
 
390
390
  # @deprecated Use wait_check_tolerance with type: :RAW
391
- def wait_check_tolerance_raw(*args, scope: $cosmos_scope, token: $cosmos_token)
392
- wait_check_tolerance(*args, type: :RAW, scope: scope, token: token)
391
+ def wait_check_tolerance_raw(*args, scope: $cosmos_scope, token: $cosmos_token, &block)
392
+ wait_check_tolerance(*args, type: :RAW, scope: scope, token: token, &block)
393
393
  end
394
394
 
395
395
  # Wait on an expression to be true. On a timeout, the script will pause.
@@ -397,12 +397,12 @@ module Cosmos
397
397
  timeout,
398
398
  polling_rate = DEFAULT_TLM_POLLING_RATE,
399
399
  context = nil,
400
- scope: $cosmos_scope, token: $cosmos_token)
400
+ scope: $cosmos_scope, token: $cosmos_token, &block)
401
401
  start_time = Time.now.sys
402
402
  success = cosmos_script_wait_implementation_expression(exp_to_eval,
403
403
  timeout,
404
404
  polling_rate,
405
- context, scope: scope, token: token)
405
+ context, scope: scope, token: token, &block)
406
406
  time = Time.now.sys - start_time
407
407
  if success
408
408
  Logger.info "CHECK: #{exp_to_eval} is TRUE after waiting #{time} seconds"
@@ -691,15 +691,20 @@ module Cosmos
691
691
  return [target_name, packet_name, item_name, comparison_to_eval, timeout, polling_rate]
692
692
  end
693
693
 
694
- def _cosmos_script_wait_implementation(target_name, packet_name, item_name, value_type, timeout, polling_rate, scope: $cosmos_scope, token: $cosmos_token)
694
+ def _cosmos_script_wait_implementation(target_name, packet_name, item_name, value_type, timeout, polling_rate, exp_to_eval, scope: $cosmos_scope, token: $cosmos_token, &block)
695
695
  end_time = Time.now.sys + timeout
696
- exp_to_eval = yield
697
696
 
698
697
  while true
699
698
  work_start = Time.now.sys
700
699
  value = tlm(target_name, packet_name, item_name, type: value_type, scope: scope, token: token)
701
- if eval(exp_to_eval)
702
- return true, value
700
+ if not block.nil?
701
+ if block.call(value)
702
+ return true, value
703
+ end
704
+ else
705
+ if eval(exp_to_eval)
706
+ return true, value
707
+ end
703
708
  end
704
709
  break if Time.now.sys >= end_time
705
710
 
@@ -724,25 +729,25 @@ module Cosmos
724
729
  end
725
730
 
726
731
  # Wait for a converted telemetry item to pass a comparison
727
- def cosmos_script_wait_implementation(target_name, packet_name, item_name, value_type, comparison_to_eval, timeout, polling_rate = DEFAULT_TLM_POLLING_RATE, scope: $cosmos_scope, token: $cosmos_token)
728
- _cosmos_script_wait_implementation(target_name, packet_name, item_name, value_type, timeout, polling_rate, scope: scope, token: token) do
729
- "value " + comparison_to_eval
732
+ def cosmos_script_wait_implementation(target_name, packet_name, item_name, value_type, comparison_to_eval, timeout, polling_rate = DEFAULT_TLM_POLLING_RATE, scope: $cosmos_scope, token: $cosmos_token, &block)
733
+ if comparison_to_eval
734
+ exp_to_eval = "value " + comparison_to_eval
735
+ else
736
+ exp_to_eval = nil
730
737
  end
738
+ _cosmos_script_wait_implementation(target_name, packet_name, item_name, value_type, timeout, polling_rate, exp_to_eval, scope: scope, token: token, &block)
731
739
  end
732
740
 
733
- def cosmos_script_wait_implementation_tolerance(target_name, packet_name, item_name, value_type, expected_value, tolerance, timeout, polling_rate = DEFAULT_TLM_POLLING_RATE, scope: $cosmos_scope, token: $cosmos_token)
734
- _cosmos_script_wait_implementation(target_name, packet_name, item_name, value_type, timeout, polling_rate, scope: scope, token: token) do
735
- "((#{expected_value} - #{tolerance})..(#{expected_value} + #{tolerance})).include? value"
736
- end
741
+ def cosmos_script_wait_implementation_tolerance(target_name, packet_name, item_name, value_type, expected_value, tolerance, timeout, polling_rate = DEFAULT_TLM_POLLING_RATE, scope: $cosmos_scope, token: $cosmos_token, &block)
742
+ exp_to_eval = "((#{expected_value} - #{tolerance})..(#{expected_value} + #{tolerance})).include? value"
743
+ _cosmos_script_wait_implementation(target_name, packet_name, item_name, value_type, timeout, polling_rate, exp_to_eval, scope: scope, token: token, &block)
737
744
  end
738
745
 
739
- def cosmos_script_wait_implementation_array_tolerance(array_size, target_name, packet_name, item_name, value_type, expected_value, tolerance, timeout, polling_rate = DEFAULT_TLM_POLLING_RATE, scope: $cosmos_scope, token: $cosmos_token)
746
+ def cosmos_script_wait_implementation_array_tolerance(array_size, target_name, packet_name, item_name, value_type, expected_value, tolerance, timeout, polling_rate = DEFAULT_TLM_POLLING_RATE, scope: $cosmos_scope, token: $cosmos_token, &block)
740
747
  statements = []
741
748
  array_size.times { |i| statements << "(((#{expected_value[i]} - #{tolerance[i]})..(#{expected_value[i]} + #{tolerance[i]})).include? value[#{i}])" }
742
749
  exp_to_eval = statements.join(" && ")
743
- _cosmos_script_wait_implementation(target_name, packet_name, item_name, value_type, timeout, polling_rate, scope: scope, token: token) do
744
- exp_to_eval
745
- end
750
+ _cosmos_script_wait_implementation(target_name, packet_name, item_name, value_type, timeout, polling_rate, exp_to_eval, scope: scope, token: token, &block)
746
751
  end
747
752
 
748
753
  # Wait on an expression to be true.
@@ -18,6 +18,7 @@
18
18
  # copyright holder
19
19
 
20
20
  require 'cosmos/script/extract'
21
+ require 'time'
21
22
 
22
23
  module Cosmos
23
24
  module Script
@@ -25,38 +26,48 @@ module Cosmos
25
26
 
26
27
  private
27
28
 
28
- # Sets the metadata value for a target
29
+ # Gets the current metadata
29
30
  #
30
- # @param target [String] Target to set metadata on
31
31
  # @return The result of the method call.
32
- def get_metadata(target)
33
- endpoint = "/cosmos-api/metadata/_get/#{target}"
34
- response = $api_server.request('get', endpoint)
32
+ def get_metadata()
33
+ response = $api_server.request('get', "/cosmos-api/metadata/latest")
35
34
  return nil if response.nil? || response.code != 200
36
35
  return JSON.parse(response.body)
37
36
  end
38
37
 
39
- # Sets the metadata value for a target
38
+ # Sets the metadata
40
39
  #
41
- # @param target [String] Target to set metadata on
42
40
  # @param metadata [Hash<Symbol, Variable>] A hash of metadata
43
- # @param color [String] Events color to show on Calendar tool
44
- # @param start (optional) [String] Metadata time value if nil will default to current time
41
+ # @param color [String] Events color to show on Calendar tool, if nil will be blue
42
+ # @param start [Time] Metadata time value, if nil will be current time
45
43
  # @return The result of the method call.
46
- def set_metadata(target, metadata, color: nil, start: nil)
44
+ def set_metadata(metadata, color: nil, start: nil)
47
45
  color = color.nil? ? '#003784' : color
48
- data = {:color => color, :metadata => metadata, :target => target}
49
- data[:start] = start unless start.nil?
46
+ data = { color: color, metadata: metadata }
47
+ data[:start] = start.iso8601 unless start.nil?
50
48
  response = $api_server.request('post', '/cosmos-api/metadata', data: data, json: true)
51
49
  return nil if response.nil? || response.code != 201
52
50
  return JSON.parse(response.body)
53
51
  end
54
52
 
55
- # Requests the metadata from the user for a target
53
+ # Updates the metadata
56
54
  #
57
- def input_metadata(*args, **kwargs)
58
- rasie StandardError "can only be used in script-runner"
55
+ # @param start [Integer] Metadata time value as integer seconds from epoch
56
+ # @param metadata [Hash<Symbol, Variable>] A hash of metadata
57
+ # @param color [String] Events color to show on Calendar tool, if nil will be blue
58
+ # @return The result of the method call.
59
+ def update_metadata(start, metadata, color: nil)
60
+ color = color.nil? ? '#003784' : color
61
+ data = { :color => color, :metadata => metadata }
62
+ data[:start] = Time.at(start).iso8601
63
+ response = $api_server.request('put', "/cosmos-api/metadata/#{start}", data: data, json: true)
64
+ return nil if response.nil? || response.code != 201
65
+ return JSON.parse(response.body)
59
66
  end
60
67
 
68
+ # Requests the metadata from the user for a target
69
+ def input_metadata(*args, **kwargs)
70
+ raise StandardError "can only be used in Script Runner"
71
+ end
61
72
  end
62
73
  end
@@ -112,13 +112,11 @@ module Cosmos
112
112
  target_name, cmd_name, cmd_params = $api_server.method_missing(cmd, *args)
113
113
  _log_cmd(target_name, cmd_name, cmd_params, raw, no_range, no_hazardous)
114
114
  rescue HazardousError => e
115
- ok_to_proceed = prompt_for_hazardous(e.target_name, e.cmd_name, e.hazardous_description)
116
- if ok_to_proceed
117
- target_name, cmd_name, cmd_params = $api_server.method_missing(cmd_no_hazardous, *args)
118
- _log_cmd(target_name, cmd_name, cmd_params, raw, no_range, no_hazardous)
119
- else
120
- retry unless prompt_for_script_abort()
121
- end
115
+ # This opens a prompt at which point they can cancel and stop the script
116
+ # or say Yes and send the command. Thus we don't care about the return value.
117
+ prompt_for_hazardous(e.target_name, e.cmd_name, e.hazardous_description)
118
+ target_name, cmd_name, cmd_params = $api_server.method_missing(cmd_no_hazardous, *args)
119
+ _log_cmd(target_name, cmd_name, cmd_params, raw, no_range, no_hazardous)
122
120
  end
123
121
  end
124
122
  end
@@ -129,58 +129,38 @@ module Cosmos
129
129
  message_box(string, *items, **options)
130
130
  end
131
131
 
132
- def _file_dialog(message, directory, filter, select_files = true)
132
+ def _file_dialog(title, message, filter:)
133
133
  answer = ''
134
- files = Dir["#{directory}/#{filter}"]
135
- if select_files
136
- files.select! { |f| !File.directory? f }
137
- else
138
- files.select! { |f| File.directory? f }
139
- end
134
+ path = "./*"
135
+ path += filter if filter
136
+ files = Dir[path]
137
+ files.select! { |f| !File.directory? f }
140
138
  while answer.empty?
141
- print message + "\n" + files.join("\n") + "\n<Type file name>:"
139
+ print "#{title}\n#{message}\n#{files.join("\n")}\n<Type file name>:"
142
140
  answer = gets
143
141
  answer.chomp!
144
142
  end
145
143
  return answer
146
144
  end
147
145
 
148
- def save_file_dialog(directory, message = "Save File", filter = "*")
149
- _file_dialog(message, directory, filter)
150
- end
151
-
152
- def open_file_dialog(directory, message = "Open File", filter = "*")
153
- _file_dialog(message, directory, filter)
154
- end
155
-
156
- def open_files_dialog(directory, message = "Open File(s)", filter = "*")
157
- _file_dialog(message, directory, filter)
146
+ def open_file_dialog(title, message = "Open File", filter:)
147
+ _file_dialog(title, message, filter)
158
148
  end
159
149
 
160
- def open_directory_dialog(directory, message = "Open Directory")
161
- _file_dialog(message, directory, "*", false)
150
+ def open_files_dialog(title, message = "Open File(s)", filter:)
151
+ _file_dialog(title, message, filter)
162
152
  end
163
153
 
164
154
  def prompt_for_hazardous(target_name, cmd_name, hazardous_description)
165
- message = "Warning: Command #{target_name} #{cmd_name} is Hazardous. "
166
- message << "\n#{hazardous_description}\n" if hazardous_description
167
- message << "Send? (y,n): "
168
- print message
169
- answer = gets.chomp
170
- if answer.downcase == 'y'
171
- return true
172
- else
173
- return false
174
- end
175
- end
176
-
177
- def prompt_for_script_abort
178
- print "Stop running script? (y,n): "
179
- answer = gets.chomp
180
- if answer.downcase == 'y'
181
- exit
182
- else
183
- return false # Not aborted - Retry
155
+ loop do
156
+ message = "Warning: Command #{target_name} #{cmd_name} is Hazardous. "
157
+ message << "\n#{hazardous_description}\n" if hazardous_description
158
+ message << "Send? (y): "
159
+ print message
160
+ answer = gets.chomp
161
+ if answer.downcase == 'y'
162
+ return true
163
+ end
184
164
  end
185
165
  end
186
166
 
@@ -23,137 +23,124 @@ module Cosmos
23
23
  module Script
24
24
  private
25
25
 
26
- # Get a handle to access a target file
26
+ # Delete a file on a target
27
+ #
28
+ # @param [String] Path to a file in a target directory
29
+ def delete_target_file(path, scope: $cosmos_scope)
30
+ begin
31
+ # Only delete from the targets_modified
32
+ delete_path = "#{scope}/targets_modified/#{path}"
33
+ endpoint = "/cosmos-api/storage/delete/#{delete_path}"
34
+ Cosmos::Logger.info "Deleting #{delete_path}"
35
+ response = $api_server.request('delete', endpoint, query: {bucket: 'config'})
36
+ if response.nil? || response.code != 200
37
+ raise "Failed to delete #{delete_path}. Note: #{scope}/targets is read-only."
38
+ end
39
+ rescue => error
40
+ raise "Failed deleting #{path} due to #{error.message}"
41
+ end
42
+ nil
43
+ end
44
+
45
+ # Get a handle to write a target file
27
46
  #
28
47
  # @param path [String] Path to a file in a target directory
29
- # @param original [Boolean] Whether to get the original or modified file
30
- # @return [File|nil]
31
- def get_target_file(path, original: false, scope: $cosmos_scope)
32
- # Create Tempfile to store data
33
- file = Tempfile.new('target', binmode: true)
48
+ # @param io_or_string [Io or String] IO object
49
+ def put_target_file(path, io_or_string, scope: $cosmos_scope)
50
+ raise "Disallowed path modifier '..' found in #{path}" if path.include?('..')
51
+ upload_path = "#{scope}/targets_modified/#{path}"
52
+ endpoint = "/cosmos-api/storage/upload/#{upload_path}"
53
+ Cosmos::Logger.info "Writing #{upload_path}"
54
+ result = _get_presigned_request(endpoint)
34
55
 
35
- # Get presigned url
36
- if original
37
- part = "targets"
38
- else
39
- part = "targets_modified"
40
- end
41
- # Loop to allow redo
42
- loop do
43
- endpoint = "/cosmos-api/storage/download/#{scope}/#{part}/#{path}"
44
- Cosmos::Logger.info "Reading #{scope}/#{part}/#{path}"
45
- if $cosmos_in_cluster
46
- response = $api_server.request('get', endpoint, query: {bucket: 'config', internal: true})
47
- else
48
- response = $api_server.request('get', endpoint, query: {bucket: 'config'})
49
- end
50
- if response.nil? || response.code != 201
51
- Cosmos::Logger.error "Failed Get Presigned URL for #{scope}/#{part}/#{path}"
52
- if part == "targets_modified"
53
- part = "targets"
54
- redo
56
+ # Try to put the file
57
+ success = false
58
+ begin
59
+ uri = _get_uri(result['url'])
60
+ Net::HTTP.start(uri.host, uri.port) do |http|
61
+ request = Net::HTTP::Put.new(uri, {'Content-Length' => io_or_string.length.to_s})
62
+ if String === io_or_string
63
+ request.body = io_or_string
55
64
  else
56
- raise "#{path} not found"
65
+ request.body_stream = io_or_string
66
+ end
67
+ result = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
68
+ http.request(request)
57
69
  end
70
+ return result
58
71
  end
59
- result = JSON.parse(response.body)
72
+ rescue => error
73
+ raise "Failed to write #{upload_path}"
74
+ end
75
+ nil
76
+ end
60
77
 
61
- # Try to get the file
78
+ # Get a handle to access a target file
79
+ #
80
+ # @param path [String] Path to a file in a target directory, e.g. "INST/procedures/test.rb"
81
+ # @param original [Boolean] Whether to get the original or modified file
82
+ # @return [File|nil]
83
+ def get_target_file(path, original: false, scope: $cosmos_scope)
84
+ part = "targets"
85
+ part += "_modified" unless original
86
+ # Loop to allow redo when switching from modified to original
87
+ loop do
62
88
  begin
63
- if $cosmos_in_cluster
64
- uri = URI.parse("http://cosmos-minio:9000" + result['url'])
65
- else
66
- uri = URI.parse($api_server.generate_url + result['url'])
67
- end
68
- Net::HTTP.start(uri.host, uri.port) do |http|
69
- request = Net::HTTP::Get.new uri
70
-
71
- http.request request do |response|
72
- response.read_body do |chunk|
73
- puts chunk.length
74
- file.write chunk
75
- end
76
- end
77
- file.rewind
78
- end
79
- return file
89
+ return _get_storage_file("#{part}/#{path}", scope: scope)
80
90
  rescue => error
81
- Cosmos::Logger.info("#{scope}/#{part}/#{path} not found")
82
91
  if part == "targets_modified"
83
92
  part = "targets"
84
93
  redo
85
94
  else
86
- raise "#{path} not found"
95
+ raise error
87
96
  end
88
97
  end
89
98
  break
90
99
  end
91
100
  end
92
101
 
93
- # Get a handle to write a target file
94
- #
95
- # @param path [String] Path to a file in a target directory
96
- # @param io_or_string [Io or String] IO object
97
- def put_target_file(path, io_or_string, scope: $cosmos_scope)
98
- # Get presigned url
99
- part = "targets_modified"
100
- begin
101
- endpoint = "/cosmos-api/storage/upload/#{scope}/#{part}/#{path}"
102
- Cosmos::Logger.info "Writing #{scope}/#{part}/#{path}"
103
- if $cosmos_in_cluster
104
- response = $api_server.request('get', endpoint, query: {bucket: 'config', internal: true})
105
- else
106
- response = $api_server.request('get', endpoint, query: {bucket: 'config'})
107
- end
108
- if response.nil? || response.code != 201
109
- Cosmos::Logger.error "Failed Get Presigned URL for #{scope}/#{part}/#{path}"
110
- return nil
111
- end
112
- result = JSON.parse(response.body)
102
+ # These are helper methods ... should not be used directly
113
103
 
114
- # Try to put the file
115
- success = false
116
- begin
117
- if $cosmos_in_cluster
118
- uri = URI.parse("http://cosmos-minio:9000" + result['url'])
119
- else
120
- uri = URI.parse($api_server.generate_url + result['url'])
121
- end
122
- Net::HTTP.start(uri.host, uri.port) do |http|
123
- request = Net::HTTP::Put.new(uri, {'Content-Length' => io_or_string.length.to_s})
124
- if String === io_or_string
125
- request.body = io_or_string
126
- else
127
- request.body_stream = io_or_string
128
- end
129
- result = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
130
- http.request(request)
131
- end
132
- return result
104
+ def _get_storage_file(path, scope: $cosmos_scope)
105
+ # Create Tempfile to store data
106
+ file = Tempfile.new('target', binmode: true)
107
+
108
+ endpoint = "/cosmos-api/storage/download/#{scope}/#{path}"
109
+ Cosmos::Logger.info "Reading #{scope}/#{path}"
110
+ result = _get_presigned_request(endpoint)
111
+
112
+ # Try to get the file
113
+ uri = _get_uri(result['url'])
114
+ Net::HTTP.start(uri.host, uri.port) do |http|
115
+ request = Net::HTTP::Get.new uri
116
+ http.request request do |response|
117
+ response.read_body do |chunk|
118
+ file.write chunk
133
119
  end
134
- rescue => error
135
- raise "Failed to write #{scope}/#{part}/#{path}"
136
120
  end
121
+ file.rewind
137
122
  end
138
- nil
123
+ return file
139
124
  end
140
125
 
141
- # Delete a file on a target
142
- #
143
- # @param [String] Path to a file in a target directory
144
- def delete_target_file(path, scope: $cosmos_scope)
145
- begin
146
- # Only delete from the targets_modified
147
- endpoint = "/cosmos-api/storage/delete/#{scope}/targets_modified/#{path}"
148
- Cosmos::Logger.info "Deleting #{scope}/targets_modified/#{path}"
149
- response = $api_server.request('delete', endpoint, query: {bucket: 'config'})
150
- if response.nil? || response.code != 200
151
- raise "Failed to delete #{scope}/targets_modified/#{path}"
152
- end
153
- rescue => error
154
- raise "Failed deleting #{path} due to #{error.message}"
126
+ def _get_uri(url)
127
+ if $cosmos_in_cluster
128
+ uri = URI.parse("http://cosmos-minio:9000" + url)
129
+ else
130
+ uri = URI.parse($api_server.generate_url + url)
155
131
  end
156
- nil
132
+ end
133
+
134
+ def _get_presigned_request(endpoint)
135
+ if $cosmos_in_cluster
136
+ response = $api_server.request('get', endpoint, query: { bucket: 'config', internal: true })
137
+ else
138
+ response = $api_server.request('get', endpoint, query: { bucket: 'config' })
139
+ end
140
+ if response.nil? || response.code != 201
141
+ raise "Failed to get presigned URL for #{endpoint}"
142
+ end
143
+ JSON.parse(response.body)
157
144
  end
158
145
  end
159
146
  end
@@ -26,6 +26,7 @@ require 'cosmos/packets/limits'
26
26
  require 'cosmos/system/target'
27
27
  require 'cosmos/utilities/s3'
28
28
  require 'cosmos/utilities/zip'
29
+ require 'cosmos/models/scope_model'
29
30
  require 'thread'
30
31
  require 'fileutils'
31
32
 
@@ -54,7 +55,7 @@ module Cosmos
54
55
 
55
56
  # @return [Symbol] The current limits_set of the system returned from Redis
56
57
  def self.limits_set
57
- Store.hget("#{$cosmos_scope}__cosmos_system", 'limits_set').intern
58
+ ScopeModel.limits_set(scope: $cosmos_scope)
58
59
  end
59
60
 
60
61
  def self.setup_targets(target_names, base_dir, scope:)
@@ -80,7 +80,7 @@ module Cosmos
80
80
  alias dup clone
81
81
 
82
82
  # Create a hash of this item's attributes
83
- def to_hash
83
+ def as_json
84
84
  hash = super()
85
85
  hash['editable'] = self.editable
86
86
  hash['hidden'] = self.hidden
@@ -37,9 +37,13 @@ class HazardousError < StandardError
37
37
  attr_accessor :cmd_name
38
38
  attr_accessor :cmd_params
39
39
  attr_accessor :hazardous_description
40
+ attr_accessor :formatted # formatted command for use in resending original
40
41
 
41
42
  def to_s
42
- "#{target_name} #{cmd_name} with #{cmd_params} is Hazardous due to #{hazardous_description}"
43
+ string = "#{target_name} #{cmd_name} with #{cmd_params} is Hazardous"
44
+ string << "due to '#{hazardous_description}'" if hazardous_description
45
+ # Pass along the original formatted command so it can be resent
46
+ string << ".\n#{formatted}"
43
47
  end
44
48
  end
45
49
 
@@ -26,7 +26,7 @@ module Cosmos
26
26
  # Notify to the topic
27
27
  #
28
28
  # ```json
29
- # {
29
+ # {
30
30
  # "kind" => "created",
31
31
  # "type" => "trigger",
32
32
  # "data" => {
@@ -46,7 +46,7 @@ module Cosmos
46
46
  # }
47
47
  # ```
48
48
  def self.write_notification(notification, scope:)
49
- Store.write_topic("#{scope}#{PRIMARY_KEY}", notification, '*', 1000)
49
+ Topic.write_topic("#{scope}#{PRIMARY_KEY}", notification, '*', 1000)
50
50
  end
51
51
  end
52
52
  end
@@ -38,7 +38,7 @@ module Cosmos
38
38
  # }
39
39
  # ```
40
40
  def self.write_entry(entry, scope:)
41
- Store.write_topic("#{scope}#{PRIMARY_KEY}", entry, '*', 1000)
41
+ Topic.write_topic("#{scope}#{PRIMARY_KEY}", entry, '*', 1000)
42
42
  end
43
43
  end
44
44
  end
@@ -21,6 +21,10 @@ require 'cosmos/topics/topic'
21
21
 
22
22
  module Cosmos
23
23
  class CommandDecomTopic < Topic
24
+ def self.topics(scope:)
25
+ super(scope, 'DECOMCMD')
26
+ end
27
+
24
28
  def self.write_packet(packet, scope:)
25
29
  topic = "#{scope}__DECOMCMD__{#{packet.target_name}}__#{packet.packet_name}"
26
30
  msg_hash = { time: packet.received_time.to_nsec_from_epoch,
@@ -36,7 +40,37 @@ module Cosmos
36
40
  json_hash[item.name + "__U"] = packet.read_item(item, :WITH_UNITS) if item.units
37
41
  end
38
42
  msg_hash['json_data'] = JSON.generate(json_hash.as_json)
39
- Store.write_topic(topic, msg_hash)
43
+ Topic.write_topic(topic, msg_hash)
44
+ end
45
+
46
+ def self.get_cmd_item(target_name, packet_name, param_name, type: :WITH_UNITS, scope: $cosmos_scope)
47
+ msg_id, msg_hash = Topic.get_newest_message("#{scope}__DECOMCMD__{#{target_name}}__#{packet_name}")
48
+ if msg_id
49
+ # TODO: We now have these reserved items directly on command packets
50
+ # Do we still calculate from msg_hash['time'] or use the times directly?
51
+ #
52
+ # if param_name == 'RECEIVED_TIMESECONDS' || param_name == 'PACKET_TIMESECONDS'
53
+ # Time.from_nsec_from_epoch(msg_hash['time'].to_i).to_f
54
+ # elsif param_name == 'RECEIVED_TIMEFORMATTED' || param_name == 'PACKET_TIMEFORMATTED'
55
+ # Time.from_nsec_from_epoch(msg_hash['time'].to_i).formatted
56
+ if param_name == 'RECEIVED_COUNT'
57
+ msg_hash['received_count'].to_i
58
+ else
59
+ json = msg_hash['json_data']
60
+ hash = JSON.parse(json)
61
+ # Start from the most complex down to the basic raw value
62
+ value = hash["#{param_name}__U"]
63
+ return value if value && type == :WITH_UNITS
64
+
65
+ value = hash["#{param_name}__F"]
66
+ return value if value && (type == :WITH_UNITS || type == :FORMATTED)
67
+
68
+ value = hash["#{param_name}__C"]
69
+ return value if value && (type == :WITH_UNITS || type == :FORMATTED || type == :CONVERTED)
70
+
71
+ return hash[param_name]
72
+ end
73
+ end
40
74
  end
41
75
  end
42
76
  end