cosmos 5.0.2 → 5.0.3

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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/data/config/microservice.yaml +47 -35
  3. data/data/config/plugins.yaml +3 -150
  4. data/data/config/target.yaml +70 -0
  5. data/data/config/tool.yaml +37 -31
  6. data/lib/cosmos/api/cmd_api.rb +11 -0
  7. data/lib/cosmos/api/tlm_api.rb +56 -32
  8. data/lib/cosmos/config/config_parser.rb +17 -20
  9. data/lib/cosmos/conversions/generic_conversion.rb +2 -2
  10. data/lib/cosmos/conversions/polynomial_conversion.rb +5 -8
  11. data/lib/cosmos/conversions/segmented_polynomial_conversion.rb +26 -9
  12. data/lib/cosmos/io/json_drb.rb +5 -1
  13. data/lib/cosmos/microservices/cleanup_microservice.rb +28 -29
  14. data/lib/cosmos/microservices/microservice.rb +1 -1
  15. data/lib/cosmos/models/gem_model.rb +1 -1
  16. data/lib/cosmos/models/scope_model.rb +0 -20
  17. data/lib/cosmos/models/target_model.rb +110 -3
  18. data/lib/cosmos/packets/packet.rb +23 -0
  19. data/lib/cosmos/packets/packet_config.rb +2 -2
  20. data/lib/cosmos/packets/packet_item.rb +57 -0
  21. data/lib/cosmos/packets/packet_item_limits.rb +14 -2
  22. data/lib/cosmos/packets/parsers/packet_item_parser.rb +1 -1
  23. data/lib/cosmos/packets/parsers/packet_parser.rb +1 -1
  24. data/lib/cosmos/packets/parsers/xtce_parser.rb +1 -1
  25. data/lib/cosmos/packets/structure_item.rb +10 -1
  26. data/lib/cosmos/script/api_shared.rb +30 -25
  27. data/lib/cosmos/script/commands.rb +5 -7
  28. data/lib/cosmos/script/script.rb +19 -39
  29. data/lib/cosmos/script/storage.rb +92 -105
  30. data/lib/cosmos/tools/table_manager/table_item.rb +1 -1
  31. data/lib/cosmos/topics/command_decom_topic.rb +4 -0
  32. data/lib/cosmos/topics/telemetry_decom_topic.rb +4 -0
  33. data/lib/cosmos/topics/topic.rb +10 -0
  34. data/lib/cosmos/utilities/logger.rb +1 -0
  35. data/lib/cosmos/utilities/s3.rb +61 -0
  36. data/lib/cosmos/utilities/store_autoload.rb +0 -10
  37. data/lib/cosmos/version.rb +5 -4
  38. data/templates/plugin-template/plugin.gemspec +0 -2
  39. metadata +3 -3
@@ -238,27 +238,24 @@ module Cosmos
238
238
  end
239
239
  end
240
240
 
241
- # Verifies the indicated parameter(s) in the config don't start or end
242
- # with an underscore and don't contain a double underscore. Raises an
243
- # Error if they do.
241
+ # Verifies the indicated parameter in the config doesn't start or end
242
+ # with an underscore, doesn't contain a double underscore, doesn't contain
243
+ # spaces and doesn't start with a close bracket.
244
244
  #
245
- # @param [Integer|Range<Integer>|Array<Integer>] indeces_to_check The
246
- # indeces of the parameters that must follow underscore rules
247
- def verify_parameters_underscores(indeces_to_check, usage = "")
248
- indeces_to_check = (1..@parameters.length) if indeces_to_check.nil?
249
- indeces_to_check = [indeces_to_check] unless indeces_to_check.respond_to? 'each'
250
-
251
- indeces_to_check.each do |index|
252
- param = @parameters[index - 1]
253
- if param.end_with? '_'
254
- raise Error.new(self, "Parameter #{index} (#{@parameters[index - 1]}) for #{@keyword} cannot end with an underscore ('_').", usage, @url)
255
- end
256
- if param.include? '__'
257
- raise Error.new(self, "Parameter #{index} (#{@parameters[index - 1]}) for #{@keyword} cannot contain a double underscore ('__').", usage, @url)
258
- end
259
- if param.include? ' '
260
- raise Error.new(self, "Parameter #{index} (#{@parameters[index - 1]}) for #{@keyword} cannot contain a space (' ').", usage, @url)
261
- end
245
+ # @param [Integer] index The index of the parameter to check
246
+ def verify_parameter_naming(index, usage = "")
247
+ param = @parameters[index - 1]
248
+ if param.end_with? '_'
249
+ raise Error.new(self, "Parameter #{index} (#{param}) for #{@keyword} cannot end with an underscore ('_').", usage, @url)
250
+ end
251
+ if param.include? '__'
252
+ raise Error.new(self, "Parameter #{index} (#{param}) for #{@keyword} cannot contain a double underscore ('__').", usage, @url)
253
+ end
254
+ if param.include? ' '
255
+ raise Error.new(self, "Parameter #{index} (#{param}) for #{@keyword} cannot contain a space (' ').", usage, @url)
256
+ end
257
+ if param.start_with?('}')
258
+ raise Error.new(self, "Parameter #{index} (#{param}) for #{@keyword} cannot start with a close bracket ('}').", usage, @url)
262
259
  end
263
260
  end
264
261
 
@@ -73,5 +73,5 @@ module Cosmos
73
73
  def as_json
74
74
  { 'class' => self.class.name.to_s, 'params' => [@code_to_eval, @converted_type, @converted_bit_size] }
75
75
  end
76
- end # class GenericConversion
77
- end # module Cosmos
76
+ end
77
+ end
@@ -29,13 +29,10 @@ module Cosmos
29
29
  # Initializes the conversion with the given polynomial coefficients. Sets
30
30
  # the converted_type to :FLOAT and the converted_bit_size to 64.
31
31
  #
32
- # @param coeff_array [Array<Float>] The polynomial coefficients
33
- def initialize(coeff_array)
32
+ # @param coeffs [Array<Float>] The polynomial coefficients
33
+ def initialize(*coeffs)
34
34
  super()
35
- @coeffs = []
36
- coeff_array.each do |coeff|
37
- @coeffs << coeff.to_f
38
- end
35
+ @coeffs = coeffs.map { |coeff| coeff.to_f }
39
36
  @converted_type = :FLOAT
40
37
  @converted_bit_size = 64
41
38
  end
@@ -84,5 +81,5 @@ module Cosmos
84
81
  def as_json
85
82
  { 'class' => self.class.name.to_s, 'params' => @coeffs }
86
83
  end
87
- end # class PolynomialConversion
88
- end # module Cosmos
84
+ end
85
+ end
@@ -23,6 +23,9 @@ module Cosmos
23
23
  # Segmented polynomial conversions consist of polynomial conversions that are
24
24
  # applied for a range of values.
25
25
  class SegmentedPolynomialConversion < Conversion
26
+ # @return [Array<Segment>] Segments which make up this conversion
27
+ attr_reader :segments
28
+
26
29
  # A polynomial conversion segment which applies the conversion from the
27
30
  # lower bound (inclusive) until another segment's lower bound is
28
31
  # encountered.
@@ -31,6 +34,7 @@ module Cosmos
31
34
  # should apply. All values >= to this value will be converted using the
32
35
  # given coefficients.
33
36
  attr_reader :lower_bound
37
+
34
38
  # @return [Array<Integer>] The polynomial coefficients
35
39
  attr_reader :coeffs
36
40
 
@@ -57,6 +61,14 @@ module Cosmos
57
61
  return other_segment.lower_bound <=> @lower_bound
58
62
  end
59
63
 
64
+ # Implement equality operator primarily for ease of testing
65
+ #
66
+ # @param segment [Segment] Other segment
67
+ def ==(other_segment)
68
+ @lower_bound == other_segment.lower_bound &&
69
+ @coeffs == other_segment.coeffs
70
+ end
71
+
60
72
  # Perform the polynomial conversion
61
73
  #
62
74
  # @param value [Numeric] The value to convert
@@ -71,9 +83,15 @@ module Cosmos
71
83
  end
72
84
 
73
85
  # Initialize the converted_type to :FLOAT and converted_bit_size to 64.
74
- def initialize
86
+ #
87
+ # @param segments [Array] Array of segments typically generated by as_json
88
+ # Format similar to the following: [[15, [3, 2]], [10, [1, 2]]]
89
+ # Where each entry is an array with the first value as the lower_bound
90
+ # and the other entry is an array of the coefficients for that segment.
91
+ def initialize(segments = [])
75
92
  super()
76
93
  @segments = []
94
+ segments.each { |lower_bound, coeffs| add_segment(lower_bound, *coeffs) }
77
95
  @converted_type = :FLOAT
78
96
  @converted_bit_size = 64
79
97
  end
@@ -95,9 +113,7 @@ module Cosmos
95
113
  def call(value, packet, buffer)
96
114
  # Try to find correct segment
97
115
  @segments.each do |segment|
98
- if value >= segment.lower_bound
99
- return segment.calculate(value)
100
- end
116
+ return segment.calculate(value) if value >= segment.lower_bound
101
117
  end
102
118
 
103
119
  # Default to using segment with smallest lower_bound
@@ -112,7 +128,7 @@ module Cosmos
112
128
  # @return [String] The name of the class followed by a description of all
113
129
  # the polynomial segments.
114
130
  def to_s
115
- result = ""
131
+ result = ''
116
132
  count = 0
117
133
  @segments.each do |segment|
118
134
  result << "\n" if count > 0
@@ -136,7 +152,8 @@ module Cosmos
136
152
  def to_config(read_or_write)
137
153
  config = ''
138
154
  @segments.each do |segment|
139
- config << " SEG_POLY_#{read_or_write}_CONVERSION #{segment.lower_bound} #{segment.coeffs.join(' ')}\n"
155
+ config <<
156
+ " SEG_POLY_#{read_or_write}_CONVERSION #{segment.lower_bound} #{segment.coeffs.join(' ')}\n"
140
157
  end
141
158
  config
142
159
  end
@@ -146,7 +163,7 @@ module Cosmos
146
163
  @segments.each do |segment|
147
164
  params << [segment.lower_bound, segment.coeffs]
148
165
  end
149
- { 'class' => self.class.name.to_s, 'params' => params }
166
+ { 'class' => self.class.name.to_s, 'params' => [params] }
150
167
  end
151
- end # class SegmentedPolynomialConversion
152
- end # module Cosmos
168
+ end
169
+ end
@@ -269,7 +269,11 @@ module Cosmos
269
269
  response = JsonRpcSuccessResponse.new(result, request.id)
270
270
  end
271
271
  rescue Exception => error
272
- Logger.error error.formatted
272
+ # Filter out the framework stack trace (rails, rack, puma etc)
273
+ lines = error.formatted.split("\n")
274
+ i = lines.find_index { |row| row.include?('actionpack') || row.include?('activesupport') }
275
+ Logger.error lines[0...i].join("\n")
276
+
273
277
  if request.id
274
278
  if NoMethodError === error
275
279
  error_code = JsonRpcError::ErrorCode::METHOD_NOT_FOUND
@@ -17,50 +17,49 @@
17
17
  # enterprise edition license of COSMOS if purchased from the
18
18
  # copyright holder
19
19
 
20
+ require 'cosmos/models/target_model'
20
21
  require 'cosmos/microservices/microservice'
21
22
  require 'cosmos/utilities/s3'
22
23
 
23
24
  module Cosmos
24
25
  class CleanupMicroservice < Microservice
25
26
  def run
26
- # Update settings from config
27
- @config['options'].each do |option|
28
- case option[0].upcase
29
- when 'SIZE' # Max size to use in S3 in bytes
30
- @size = option[1].to_i
31
- when 'DELAY' # Delay between size checks
32
- @delay = option[1].to_i
33
- when 'BUCKET' # Which bucket to monitor
34
- @bucket = option[1]
35
- when 'PREFIX' # Path into bucket to monitor
36
- @prefix = option[1]
37
- else
38
- Logger.error("Unknown option passed to microservice #{@name}: #{option}")
39
- end
40
- end
41
-
42
- raise "Microservice #{@name} not fully configured" unless @size and @delay and @bucket and @prefix
27
+ split_name = @name.split("__")
28
+ target_name = split_name[-1]
29
+ target = TargetModel.get_model(name: target_name, scope: @scope)
43
30
 
44
31
  rubys3_client = Aws::S3::Client.new
45
32
  while true
46
33
  break if @cancel_thread
47
34
 
48
35
  @state = 'GETTING_OBJECTS'
49
- total_size, oldest_list = S3Utilities.get_total_size_and_oldest_list(@bucket, @prefix)
50
- delete_items = []
51
- oldest_list.each do |item|
52
- break if total_size <= @size
53
-
54
- delete_items << { :key => item.key }
55
- total_size -= item.size
56
- end
57
- if delete_items.length > 0
58
- @state = 'DELETING_OBJECTS'
59
- rubys3_client.delete_objects({ bucket: @bucket, delete: { objects: delete_items } })
36
+ start_time = Time.now
37
+ [
38
+ ["#{@scope}/raw_logs/cmd/#{target_name}/", target.cmd_log_retain_time],
39
+ ["#{@scope}/decom_logs/cmd/#{target_name}/", target.cmd_decom_log_retain_time],
40
+ ["#{@scope}/raw_logs/tlm/#{target_name}/", target.tlm_log_retain_time],
41
+ ["#{@scope}/decom_logs/tlm/#{target_name}/", target.tlm_decom_log_retain_time],
42
+ ["#{@scope}/reduced_minute_logs/tlm/#{target_name}/", target.reduced_minute_log_retain_time],
43
+ ["#{@scope}/reduced_hour_logs/tlm/#{target_name}/", target.reduced_hour_log_retain_time],
44
+ ["#{@scope}/reduced_day_logs/tlm/#{target_name}/", target.reduced_day_log_retain_time],
45
+ ].each do |prefix, retain_time|
46
+ next unless retain_time
47
+ time = start_time - retain_time
48
+ total_size, oldest_list = S3Utilities.list_files_before_time('logs', prefix, time)
49
+ delete_items = []
50
+ oldest_list.each do |item|
51
+ delete_items << { :key => item.key }
52
+ end
53
+ if delete_items.length > 0
54
+ @state = 'DELETING_OBJECTS'
55
+ rubys3_client.delete_objects({ bucket: 'logs', delete: { objects: delete_items } })
56
+ Logger.info("Deleted #{delete_items.length} #{target_name} log files")
57
+ end
60
58
  end
59
+
61
60
  @count += 1
62
61
  @state = 'SLEEPING'
63
- break if @microservice_sleeper.sleep(@delay)
62
+ break if @microservice_sleeper.sleep(target.cleanup_poll_time)
64
63
  end
65
64
  end
66
65
  end
@@ -75,7 +75,7 @@ module Cosmos
75
75
 
76
76
  @name = name
77
77
  split_name = name.split("__")
78
- raise "Microservice names should be scope, type, and then name" if split_name.length != 3
78
+ raise "Name #{name} doesn't match convention of SCOPE__TYPE__NAME" if split_name.length != 3
79
79
 
80
80
  @scope = split_name[0]
81
81
  $cosmos_scope = @scope
@@ -84,7 +84,7 @@ module Cosmos
84
84
  rubygems_url = get_setting('rubygems_url')
85
85
  Gem.sources = [rubygems_url] if rubygems_url
86
86
  Gem.done_installing_hooks.clear
87
- Gem.install(gem_file_path, {:build_args => '--no-document'})
87
+ Gem.install(gem_file_path, "> 0.pre", :build_args => ['--no-document'], :prerelease => true)
88
88
  rescue => err
89
89
  message = "Gem file #{gem_file_path} error installing to /gems\n#{err.formatted}"
90
90
  Logger.error message
@@ -51,24 +51,6 @@ module Cosmos
51
51
  def deploy(gem_path, variables)
52
52
  seed_database()
53
53
 
54
- # Cleanup Microservice
55
- microservice_name = "#{@scope}__CLEANUP__S3"
56
- microservice = MicroserviceModel.new(
57
- name: microservice_name,
58
- cmd: ["ruby", "cleanup_microservice.rb", microservice_name],
59
- work_dir: '/cosmos/lib/cosmos/microservices',
60
- options: [
61
- ["SIZE", "20_000_000_000"], # Max Size to keep in S3
62
- ["DELAY", "300"], # Delay between size checks
63
- ["BUCKET", "logs"], # Bucket to monitor
64
- ["PREFIX", @scope + "/"], # Path into bucket to monitor
65
- ],
66
- scope: @scope
67
- )
68
- microservice.create
69
- microservice.deploy(gem_path, variables)
70
- Logger.info "Configured microservice #{microservice_name}"
71
-
72
54
  # COSMOS Log Microservice
73
55
  microservice_name = "#{@scope}__COSMOS__LOG"
74
56
  microservice = MicroserviceModel.new(
@@ -146,8 +128,6 @@ module Cosmos
146
128
  end
147
129
 
148
130
  def undeploy
149
- model = MicroserviceModel.get_model(name: "#{@scope}__CLEANUP__S3", scope: @scope)
150
- model.destroy if model
151
131
  model = MicroserviceModel.get_model(name: "#{@scope}__COSMOS__LOG", scope: @scope)
152
132
  model.destroy if model
153
133
  model = MicroserviceModel.get_model(name: "#{@scope}__NOTIFICATION__LOG", scope: @scope)
@@ -51,12 +51,20 @@ module Cosmos
51
51
  attr_accessor :id
52
52
  attr_accessor :cmd_log_cycle_time
53
53
  attr_accessor :cmd_log_cycle_size
54
+ attr_accessor :cmd_log_retain_time
54
55
  attr_accessor :cmd_decom_log_cycle_time
55
56
  attr_accessor :cmd_decom_log_cycle_size
57
+ attr_accessor :cmd_decom_log_retain_time
56
58
  attr_accessor :tlm_log_cycle_time
57
59
  attr_accessor :tlm_log_cycle_size
60
+ attr_accessor :tlm_log_retain_time
58
61
  attr_accessor :tlm_decom_log_cycle_time
59
62
  attr_accessor :tlm_decom_log_cycle_size
63
+ attr_accessor :tlm_decom_log_retain_time
64
+ attr_accessor :reduced_minute_log_retain_time
65
+ attr_accessor :reduced_hour_log_retain_time
66
+ attr_accessor :reduced_day_log_retain_time
67
+ attr_accessor :cleanup_poll_time
60
68
  attr_accessor :needs_dependencies
61
69
 
62
70
  # NOTE: The following three class methods are used by the ModelController
@@ -97,6 +105,11 @@ module Cosmos
97
105
  result
98
106
  end
99
107
 
108
+ # @return [Array>Hash>] All packet hashes under the target_name
109
+ def self.all_packet_name_descriptions(target_name, type: :TLM, scope:)
110
+ self.packets(target_name, type: type, scope: scope).map! { |hash| hash.slice("packet_name", "description") }
111
+ end
112
+
100
113
  def self.set_packet(target_name, packet_name, packet, type: :TLM, scope:)
101
114
  raise "Unknown type #{type} for #{target_name} #{packet_name}" unless VALID_TYPES.include?(type)
102
115
 
@@ -113,7 +126,6 @@ module Cosmos
113
126
  packet = packet(target_name, packet_name, type: type, scope: scope)
114
127
  item = packet['items'].find { |item| item['name'] == item_name.to_s }
115
128
  raise "Item '#{packet['target_name']} #{packet['packet_name']} #{item_name}' does not exist" unless item
116
-
117
129
  item
118
130
  end
119
131
 
@@ -149,7 +161,7 @@ module Cosmos
149
161
  when 'TARGET'
150
162
  usage = "#{keyword} <TARGET FOLDER NAME> <TARGET NAME>"
151
163
  parser.verify_num_parameters(2, 2, usage)
152
- parser.verify_parameters_underscores(2) # Target name is the 2nd parameter
164
+ parser.verify_parameter_naming(2) # Target name is the 2nd parameter
153
165
  return self.new(name: parameters[1].to_s.upcase, folder_name: parameters[0].to_s.upcase, plugin: plugin, scope: scope)
154
166
  else
155
167
  raise ConfigParser::Error.new(parser, "Unknown keyword and parameters for Target: #{keyword} #{parameters.join(" ")}")
@@ -171,20 +183,35 @@ module Cosmos
171
183
  plugin: nil,
172
184
  cmd_log_cycle_time: 600,
173
185
  cmd_log_cycle_size: 50_000_000,
186
+ cmd_log_retain_time: nil,
174
187
  cmd_decom_log_cycle_time: 600,
175
188
  cmd_decom_log_cycle_size: 50_000_000,
189
+ cmd_decom_log_retain_time: nil,
176
190
  tlm_log_cycle_time: 600,
177
191
  tlm_log_cycle_size: 50_000_000,
192
+ tlm_log_retain_time: nil,
178
193
  tlm_decom_log_cycle_time: 600,
179
194
  tlm_decom_log_cycle_size: 50_000_000,
195
+ tlm_decom_log_retain_time: nil,
196
+ reduced_minute_log_retain_time: nil,
197
+ reduced_hour_log_retain_time: nil,
198
+ reduced_day_log_retain_time: nil,
199
+ cleanup_poll_time: 900,
180
200
  needs_dependencies: false,
181
201
  scope:
182
202
  )
183
203
  super("#{scope}__#{PRIMARY_KEY}", name: name, plugin: plugin, updated_at: updated_at,
184
204
  cmd_log_cycle_time: cmd_log_cycle_time, cmd_log_cycle_size: cmd_log_cycle_size,
205
+ cmd_log_retain_time: cmd_log_retain_time,
185
206
  cmd_decom_log_cycle_time: cmd_decom_log_cycle_time, cmd_decom_log_cycle_size: cmd_decom_log_cycle_size,
207
+ cmd_decom_log_retain_time: cmd_decom_log_retain_time,
186
208
  tlm_log_cycle_time: tlm_log_cycle_time, tlm_log_cycle_size: tlm_log_cycle_size,
209
+ tlm_log_retain_time: tlm_log_retain_time,
187
210
  tlm_decom_log_cycle_time: tlm_decom_log_cycle_time, tlm_decom_log_cycle_size: tlm_decom_log_cycle_size,
211
+ tlm_decom_log_retain_time: tlm_decom_log_retain_time,
212
+ reduced_minute_log_retain_time: reduced_minute_log_retain_time,
213
+ reduced_hour_log_retain_time: reduced_hour_log_retain_time, reduced_day_log_retain_time: reduced_day_log_retain_time,
214
+ cleanup_poll_time: cleanup_poll_time, needs_dependencies: needs_dependencies,
188
215
  scope: scope)
189
216
  @folder_name = folder_name
190
217
  @requires = requires
@@ -197,12 +224,20 @@ module Cosmos
197
224
  @id = id
198
225
  @cmd_log_cycle_time = cmd_log_cycle_time
199
226
  @cmd_log_cycle_size = cmd_log_cycle_size
227
+ @cmd_log_retain_time = cmd_log_retain_time
200
228
  @cmd_decom_log_cycle_time = cmd_decom_log_cycle_time
201
229
  @cmd_decom_log_cycle_size = cmd_decom_log_cycle_size
230
+ @cmd_decom_log_retain_time = cmd_decom_log_retain_time
202
231
  @tlm_log_cycle_time = tlm_log_cycle_time
203
232
  @tlm_log_cycle_size = tlm_log_cycle_size
233
+ @tlm_log_retain_time = tlm_log_retain_time
204
234
  @tlm_decom_log_cycle_time = tlm_decom_log_cycle_time
205
235
  @tlm_decom_log_cycle_size = tlm_decom_log_cycle_size
236
+ @tlm_decom_log_retain_time = tlm_decom_log_retain_time
237
+ @reduced_minute_log_retain_time = reduced_minute_log_retain_time
238
+ @reduced_hour_log_retain_time = reduced_hour_log_retain_time
239
+ @reduced_day_log_retain_time = reduced_day_log_retain_time
240
+ @cleanup_poll_time = cleanup_poll_time
206
241
  @needs_dependencies = needs_dependencies
207
242
  end
208
243
 
@@ -222,12 +257,20 @@ module Cosmos
222
257
  'plugin' => @plugin,
223
258
  'cmd_log_cycle_time' => @cmd_log_cycle_time,
224
259
  'cmd_log_cycle_size' => @cmd_log_cycle_size,
260
+ 'cmd_log_retain_time' => @cmd_log_retain_time,
225
261
  'cmd_decom_log_cycle_time' => @cmd_decom_log_cycle_time,
226
262
  'cmd_decom_log_cycle_size' => @cmd_decom_log_cycle_size,
263
+ 'cmd_decom_log_retain_time' => @cmd_decom_log_retain_time,
227
264
  'tlm_log_cycle_time' => @tlm_log_cycle_time,
228
265
  'tlm_log_cycle_size' => @tlm_log_cycle_size,
266
+ 'tlm_log_retain_time' => @tlm_log_retain_time,
229
267
  'tlm_decom_log_cycle_time' => @tlm_decom_log_cycle_time,
230
268
  'tlm_decom_log_cycle_size' => @tlm_decom_log_cycle_size,
269
+ 'tlm_decom_log_retain_time' => @tlm_decom_log_retain_time,
270
+ 'reduced_minute_log_retain_time' => @reduced_minute_log_retain_time,
271
+ 'reduced_hour_log_retain_time' => @reduced_hour_log_retain_time,
272
+ 'reduced_day_log_retain_time' => @reduced_day_log_retain_time,
273
+ 'cleanup_poll_time' => @cleanup_poll_time,
231
274
  'needs_dependencies' => @needs_dependencies,
232
275
  }
233
276
  end
@@ -245,24 +288,72 @@ module Cosmos
245
288
  when 'CMD_LOG_CYCLE_SIZE'
246
289
  parser.verify_num_parameters(1, 1, "#{keyword} <Maximum file size in bytes>")
247
290
  @cmd_log_cycle_size = parameters[0].to_i
291
+ when 'CMD_LOG_RETAIN_TIME'
292
+ parser.verify_num_parameters(1, 1, "#{keyword} <Retention time for cmd log files in seconds - nil = Forever>")
293
+ @cmd_log_retain_time = ConfigParser.handle_nil(parameters[0])
294
+ @cmd_log_retain_time = @cmd_log_retain_time.to_i if @cmd_log_retain_time
248
295
  when 'CMD_DECOM_LOG_CYCLE_TIME'
249
296
  parser.verify_num_parameters(1, 1, "#{keyword} <Maximum time between files in seconds>")
250
297
  @cmd_decom_log_cycle_time = parameters[0].to_i
251
298
  when 'CMD_DECOM_LOG_CYCLE_SIZE'
252
299
  parser.verify_num_parameters(1, 1, "#{keyword} <Maximum file size in bytes>")
253
300
  @cmd_decom_log_cycle_size = parameters[0].to_i
301
+ when 'CMD_DECOM_LOG_RETAIN_TIME'
302
+ parser.verify_num_parameters(1, 1, "#{keyword} <Retention time for cmd decom log files in seconds - nil = Forever>")
303
+ @cmd_decom_log_retain_time = ConfigParser.handle_nil(parameters[0])
304
+ @cmd_decom_log_retain_time = @cmd_decom_log_retain_time.to_i if @cmd_decom_log_retain_time
254
305
  when 'TLM_LOG_CYCLE_TIME'
255
306
  parser.verify_num_parameters(1, 1, "#{keyword} <Maximum time between files in seconds>")
256
307
  @tlm_log_cycle_time = parameters[0].to_i
257
308
  when 'TLM_LOG_CYCLE_SIZE'
258
309
  parser.verify_num_parameters(1, 1, "#{keyword} <Maximum file size in bytes>")
259
310
  @tlm_log_cycle_size = parameters[0].to_i
311
+ when 'TLM_LOG_RETAIN_TIME'
312
+ parser.verify_num_parameters(1, 1, "#{keyword} <Retention time for tlm log files in seconds - nil = Forever>")
313
+ @tlm_log_retain_time = ConfigParser.handle_nil(parameters[0])
314
+ @tlm_log_retain_time = @tlm_log_retain_time.to_i if @tlm_log_retain_time
260
315
  when 'TLM_DECOM_LOG_CYCLE_TIME'
261
316
  parser.verify_num_parameters(1, 1, "#{keyword} <Maximum time between files in seconds>")
262
317
  @tlm_decom_log_cycle_time = parameters[0].to_i
263
318
  when 'TLM_DECOM_LOG_CYCLE_SIZE'
264
319
  parser.verify_num_parameters(1, 1, "#{keyword} <Maximum file size in bytes>")
265
320
  @tlm_decom_log_cycle_size = parameters[0].to_i
321
+ when 'TLM_DECOM_LOG_RETAIN_TIME'
322
+ parser.verify_num_parameters(1, 1, "#{keyword} <Retention time for tlm decom log files in seconds - nil = Forever>")
323
+ @tlm_decom_log_retain_time = ConfigParser.handle_nil(parameters[0])
324
+ @tlm_decom_log_retain_time = @tlm_decom_log_retain_time.to_i if @tlm_decom_log_retain_time
325
+ when 'REDUCED_MINUTE_LOG_RETAIN_TIME'
326
+ parser.verify_num_parameters(1, 1, "#{keyword} <Retention time for reduced minute log files in seconds - nil = Forever>")
327
+ @reduced_minute_log_retain_time = ConfigParser.handle_nil(parameters[0])
328
+ @reduced_minute_log_retain_time = @reduced_minute_log_retain_time.to_i if @reduced_minute_log_retain_time
329
+ when 'REDUCED_HOUR_LOG_RETAIN_TIME'
330
+ parser.verify_num_parameters(1, 1, "#{keyword} <Retention time for reduced hour log files in seconds - nil = Forever>")
331
+ @reduced_hour_log_retain_time = ConfigParser.handle_nil(parameters[0])
332
+ @reduced_hour_log_retain_time = @reduced_hour_log_retain_time.to_i if @reduced_hour_log_retain_time
333
+ when 'REDUCED_DAY_LOG_RETAIN_TIME'
334
+ parser.verify_num_parameters(1, 1, "#{keyword} <Retention time for reduced day log files in seconds - nil = Forever>")
335
+ @reduced_day_log_retain_time = ConfigParser.handle_nil(parameters[0])
336
+ @reduced_day_log_retain_time = @reduced_day_log_retain_time.to_i if @reduced_day_log_retain_time
337
+ when 'LOG_RETAIN_TIME'
338
+ parser.verify_num_parameters(1, 1, "#{keyword} <Retention time for all log files in seconds - nil = Forever>")
339
+ log_retain_time = ConfigParser.handle_nil(parameters[0])
340
+ if log_retain_time
341
+ @cmd_log_retain_time = log_retain_time.to_i
342
+ @cmd_decom_log_retain_time = log_retain_time.to_i
343
+ @tlm_log_retain_time = log_retain_time.to_i
344
+ @tlm_decom_log_retain_time = log_retain_time.to_i
345
+ end
346
+ when 'REDUCED_LOG_RETAIN_TIME'
347
+ parser.verify_num_parameters(1, 1, "#{keyword} <Retention time for all reduced log files in seconds - nil = Forever>")
348
+ reduced_log_retain_time = ConfigParser.handle_nil(parameters[0])
349
+ if reduced_log_retain_time
350
+ @reduced_minute_log_retain_time = reduced_log_retain_time.to_i
351
+ @reduced_hour_log_retain_time = reduced_log_retain_time.to_i
352
+ @reduced_day_log_retain_time = reduced_log_retain_time.to_i
353
+ end
354
+ when 'CLEANUP_POLL_TIME'
355
+ parser.verify_num_parameters(1, 1, "#{keyword} <Cleanup polling period in seconds>")
356
+ @cleanup_poll_time = parameters[0].to_i
266
357
  else
267
358
  raise ConfigParser::Error.new(parser, "Unknown keyword and parameters for Target: #{keyword} #{parameters.join(" ")}")
268
359
  end
@@ -335,7 +426,7 @@ module Cosmos
335
426
  Store.del("#{@scope}__cosmoscmd__#{@name}")
336
427
 
337
428
  # Note: these match the names of the services in deploy_microservices
338
- %w(DECOM COMMANDLOG DECOMCMDLOG PACKETLOG DECOMLOG REDUCER).each do |type|
429
+ %w(DECOM COMMANDLOG DECOMCMDLOG PACKETLOG DECOMLOG REDUCER CLEANUP).each do |type|
339
430
  model = MicroserviceModel.get_model(name: "#{@scope}__#{type}__#{@name}", scope: @scope)
340
431
  model.destroy if model
341
432
  end
@@ -627,6 +718,22 @@ module Cosmos
627
718
  microservice.deploy(gem_path, variables)
628
719
  Logger.info "Configured microservice #{microservice_name}"
629
720
  end
721
+
722
+ if @cmd_log_retain_time or @cmd_decom_log_retain_time or @tlm_log_retain_time or @tlm_decom_log_retain_time or
723
+ @reduced_minute_log_retain_time or @reduced_hour_log_retain_time or @reduced_day_log_retain_time
724
+ # Cleanup Microservice
725
+ microservice_name = "#{@scope}__CLEANUP__#{@name}"
726
+ microservice = MicroserviceModel.new(
727
+ name: microservice_name,
728
+ cmd: ["ruby", "cleanup_microservice.rb", microservice_name],
729
+ work_dir: '/cosmos/lib/cosmos/microservices',
730
+ plugin: plugin,
731
+ scope: @scope
732
+ )
733
+ microservice.create
734
+ microservice.deploy(gem_path, variables)
735
+ Logger.info "Configured microservice #{microservice_name}"
736
+ end
630
737
  end
631
738
  end
632
739
  end
@@ -445,6 +445,11 @@ module Cosmos
445
445
  @meta ||= {}
446
446
  end
447
447
 
448
+ # Sets packet specific metadata
449
+ def meta=(meta)
450
+ @meta = meta
451
+ end
452
+
448
453
  # Indicates if the packet has been identified
449
454
  # @return [TrueClass or FalseClass]
450
455
  def identified?
@@ -1009,6 +1014,24 @@ module Cosmos
1009
1014
  config
1010
1015
  end
1011
1016
 
1017
+ def self.from_json(hash)
1018
+ endianness = hash['endianness'] ? hash['endianness'].intern : nil # Convert to symbol
1019
+ packet = Packet.new(hash['target_name'], hash['packet_name'], endianness, hash['description'])
1020
+ packet.short_buffer_allowed = hash['short_buffer_allowed']
1021
+ packet.hazardous = hash['hazardous']
1022
+ packet.hazardous_description = hash['hazardous_description']
1023
+ packet.messages_disabled = hash['messages_disabled']
1024
+ packet.disabled = hash['disabled']
1025
+ packet.hidden = hash['hidden']
1026
+ # packet.stale is read only
1027
+ packet.meta = hash['meta']
1028
+ # Can't convert processors
1029
+ hash['items'].each do |item|
1030
+ packet.define(PacketItem.from_json(item))
1031
+ end
1032
+ packet
1033
+ end
1034
+
1012
1035
  protected
1013
1036
 
1014
1037
  # Performs packet specific processing on the packet.
@@ -463,8 +463,8 @@ module Cosmos
463
463
  when 'POLY_READ_CONVERSION', 'POLY_WRITE_CONVERSION'
464
464
  usage = "#{keyword} <C0> <C1> <C2> ..."
465
465
  parser.verify_num_parameters(1, nil, usage)
466
- @current_item.read_conversion = PolynomialConversion.new(params) if keyword.include? "READ"
467
- @current_item.write_conversion = PolynomialConversion.new(params) if keyword.include? "WRITE"
466
+ @current_item.read_conversion = PolynomialConversion.new(*params) if keyword.include? "READ"
467
+ @current_item.write_conversion = PolynomialConversion.new(*params) if keyword.include? "WRITE"
468
468
 
469
469
  # Apply a segmented polynomial conversion to the current item
470
470
  # after it is read from the telemetry packet