cosmos 5.0.2 → 5.0.3

Sign up to get free protection for your applications and to get access to all the features.
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