cosmos 5.0.2 → 5.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/cosmos +183 -42
- data/data/config/microservice.yaml +47 -35
- data/data/config/plugins.yaml +10 -147
- data/data/config/target.yaml +70 -0
- data/data/config/tool.yaml +37 -31
- data/ext/cosmos/ext/cosmos_io/cosmos_io.c +14 -14
- data/ext/cosmos/ext/packet/packet.c +3 -3
- data/ext/cosmos/ext/structure/structure.c +31 -31
- data/lib/cosmos/api/api.rb +1 -25
- data/lib/cosmos/api/cmd_api.rb +17 -6
- data/lib/cosmos/api/config_api.rb +10 -4
- data/lib/cosmos/api/limits_api.rb +1 -1
- data/lib/cosmos/api/settings_api.rb +19 -7
- data/lib/cosmos/api/target_api.rb +2 -2
- data/lib/cosmos/api/tlm_api.rb +65 -41
- data/lib/cosmos/config/config_parser.rb +19 -22
- data/lib/cosmos/config/meta_config_parser.rb +1 -1
- data/lib/cosmos/conversions/generic_conversion.rb +2 -2
- data/lib/cosmos/conversions/polynomial_conversion.rb +5 -8
- data/lib/cosmos/conversions/segmented_polynomial_conversion.rb +26 -9
- data/lib/cosmos/io/json_drb.rb +5 -1
- data/lib/cosmos/logs/log_writer.rb +78 -29
- data/lib/cosmos/microservices/cleanup_microservice.rb +28 -29
- data/lib/cosmos/microservices/decom_microservice.rb +1 -1
- data/lib/cosmos/microservices/interface_microservice.rb +0 -16
- data/lib/cosmos/microservices/microservice.rb +3 -3
- data/lib/cosmos/microservices/reducer_microservice.rb +12 -10
- data/lib/cosmos/models/cvt_model.rb +6 -6
- data/lib/cosmos/models/gem_model.rb +9 -3
- data/lib/cosmos/models/info_model.rb +1 -1
- data/lib/cosmos/models/interface_model.rb +16 -7
- data/lib/cosmos/models/interface_status_model.rb +1 -1
- data/lib/cosmos/models/metadata_model.rb +69 -219
- data/lib/cosmos/models/metric_model.rb +2 -2
- data/lib/cosmos/models/microservice_model.rb +7 -4
- data/lib/cosmos/models/microservice_status_model.rb +1 -1
- data/lib/cosmos/models/model.rb +23 -16
- data/lib/cosmos/models/note_model.rb +122 -0
- data/lib/cosmos/models/ping_model.rb +2 -1
- data/lib/cosmos/models/plugin_model.rb +108 -48
- data/lib/cosmos/models/process_status_model.rb +1 -1
- data/lib/cosmos/models/scope_model.rb +10 -25
- data/lib/cosmos/models/settings_model.rb +55 -0
- data/lib/cosmos/models/sorted_model.rb +167 -0
- data/lib/cosmos/models/target_model.rb +143 -27
- data/lib/cosmos/models/tool_config_model.rb +38 -0
- data/lib/cosmos/models/tool_model.rb +9 -9
- data/lib/cosmos/models/widget_model.rb +11 -11
- data/lib/cosmos/operators/microservice_operator.rb +2 -1
- data/lib/cosmos/packets/packet.rb +24 -1
- data/lib/cosmos/packets/packet_config.rb +2 -2
- data/lib/cosmos/packets/packet_item.rb +57 -0
- data/lib/cosmos/packets/packet_item_limits.rb +14 -2
- data/lib/cosmos/packets/parsers/packet_item_parser.rb +1 -1
- data/lib/cosmos/packets/parsers/packet_parser.rb +1 -1
- data/lib/cosmos/packets/parsers/xtce_parser.rb +1 -1
- data/lib/cosmos/packets/structure.rb +30 -33
- data/lib/cosmos/packets/structure_item.rb +10 -1
- data/lib/cosmos/script/api_shared.rb +30 -25
- data/lib/cosmos/script/calendar.rb +37 -15
- data/lib/cosmos/script/commands.rb +5 -7
- data/lib/cosmos/script/script.rb +19 -39
- data/lib/cosmos/script/storage.rb +92 -105
- data/lib/cosmos/system/system.rb +2 -1
- data/lib/cosmos/tools/table_manager/table_config.rb +16 -1
- data/lib/cosmos/tools/table_manager/table_item.rb +1 -1
- data/lib/cosmos/tools/table_manager/table_manager_core.rb +213 -309
- data/lib/cosmos/top_level.rb +5 -1
- data/lib/cosmos/topics/autonomic_topic.rb +2 -2
- data/lib/cosmos/topics/calendar_topic.rb +1 -1
- data/lib/cosmos/topics/command_decom_topic.rb +35 -1
- data/lib/cosmos/topics/command_topic.rb +6 -4
- data/lib/cosmos/topics/config_topic.rb +68 -0
- data/lib/cosmos/topics/interface_topic.rb +8 -8
- data/lib/cosmos/topics/limits_event_topic.rb +5 -3
- data/lib/cosmos/topics/notifications_topic.rb +1 -1
- data/lib/cosmos/topics/router_topic.rb +9 -9
- data/lib/cosmos/topics/telemetry_decom_topic.rb +5 -1
- data/lib/cosmos/topics/telemetry_topic.rb +1 -1
- data/lib/cosmos/topics/timeline_topic.rb +1 -1
- data/lib/cosmos/topics/topic.rb +23 -8
- data/lib/cosmos/utilities/logger.rb +4 -3
- data/lib/cosmos/utilities/metric.rb +32 -26
- data/lib/cosmos/utilities/s3.rb +61 -0
- data/lib/cosmos/utilities/s3_file_cache.rb +12 -6
- data/lib/cosmos/utilities/store.rb +1 -0
- data/lib/cosmos/utilities/store_autoload.rb +25 -134
- data/lib/cosmos/version.rb +5 -4
- data/templates/plugin-template/plugin.gemspec +0 -2
- metadata +12 -10
- data/bin/xtce_converter +0 -92
- data/lib/cosmos/models/narrative_model.rb +0 -280
@@ -0,0 +1,167 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
# Copyright 2022 Ball Aerospace & Technologies Corp.
|
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 program may also be used under the terms of a commercial or
|
17
|
+
# enterprise edition license of COSMOS if purchased from the
|
18
|
+
# copyright holder
|
19
|
+
|
20
|
+
# https://www.rubydoc.info/gems/redis/Redis/Commands/SortedSets
|
21
|
+
# https://redis.io/docs/manual/data-types/data-types-tutorial/#sorted-sets
|
22
|
+
|
23
|
+
require 'cosmos/models/model'
|
24
|
+
require 'cosmos/topics/calendar_topic'
|
25
|
+
|
26
|
+
module Cosmos
|
27
|
+
# Put these under the Cosmos module so they are easily accessed in the controller as
|
28
|
+
# Cosmos::SortedError vs Cosmos::SortedModel::Error
|
29
|
+
class SortedError < StandardError; end
|
30
|
+
class SortedInputError < SortedError; end
|
31
|
+
class SortedOverlapError < SortedError; end
|
32
|
+
|
33
|
+
class SortedModel < Model
|
34
|
+
SORTED_TYPE = 'sorted'.freeze # To be overriden by base class
|
35
|
+
PRIMARY_KEY = '__SORTED'.freeze # To be overriden by base class
|
36
|
+
|
37
|
+
# MUST be overriden by any subclasses
|
38
|
+
def self.pk(scope)
|
39
|
+
"#{scope}#{PRIMARY_KEY}"
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [String|nil] String of the saved json or nil if start not found
|
43
|
+
def self.get(start:, scope:)
|
44
|
+
result = Store.zrangebyscore(self.pk(scope), start, start)
|
45
|
+
return JSON.parse(result[0]) unless result.empty?
|
46
|
+
nil
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [Array<Hash>] Array up to the limit of the models (as Hash objects) stored under the primary key
|
50
|
+
def self.all(scope:, limit: 100)
|
51
|
+
result = Store.zrevrangebyscore(self.pk(scope), '+inf', '-inf', limit: [0, limit])
|
52
|
+
result.map { |item| JSON.parse(item) }
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [String|nil] json or nil if metadata empty
|
56
|
+
def self.get_current_value(scope:)
|
57
|
+
start = Time.now.to_i
|
58
|
+
array = Store.zrevrangebyscore(self.pk(scope), start, '-inf', limit: [0, 1])
|
59
|
+
return nil if array.empty?
|
60
|
+
return array[0]
|
61
|
+
end
|
62
|
+
|
63
|
+
# @param start [Integer] Start time to return values (inclusive)
|
64
|
+
# @param stop [Integer] Stop time to return values (inclusive)
|
65
|
+
# @return [Array|nil] Array up to 100 of this model or empty array
|
66
|
+
def self.range(start:, stop:, scope:, limit: 100)
|
67
|
+
if start > stop
|
68
|
+
raise SortedInputError.new "start: #{start} must be before stop: #{stop}"
|
69
|
+
end
|
70
|
+
result = Store.zrangebyscore(self.pk(scope), start, stop, limit: [0, limit])
|
71
|
+
result.map { |item| JSON.parse(item) }
|
72
|
+
end
|
73
|
+
|
74
|
+
# @return [Integer] count of the members stored under the primary key
|
75
|
+
def self.count(scope:)
|
76
|
+
Store.zcard(self.pk(scope))
|
77
|
+
end
|
78
|
+
|
79
|
+
# Remove member from a sorted set
|
80
|
+
# @return [Integer] count of the members removed, 0 if not found
|
81
|
+
def self.destroy(scope:, start:)
|
82
|
+
Store.zremrangebyscore(self.pk(scope), start, start)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Remove members from min to max of the sorted set.
|
86
|
+
# @return [Integer] count of the members removed
|
87
|
+
def self.range_destroy(scope:, start:, stop:)
|
88
|
+
Store.zremrangebyscore(self.pk(scope), start, stop)
|
89
|
+
end
|
90
|
+
|
91
|
+
attr_reader :start
|
92
|
+
|
93
|
+
# @param [Integer] start - start used to store data
|
94
|
+
# @param [String] scope - Cosmos scope to track event to
|
95
|
+
# @param [Anything] kwargs - Any kwargs to store in the JSON
|
96
|
+
def initialize(start:, scope:, type: SORTED_TYPE, **kwargs)
|
97
|
+
# Name becomes the start in the base class
|
98
|
+
super(self.class.pk(scope), name: start.to_s, scope: scope, **kwargs)
|
99
|
+
@type = type # For the as_json, from_json round trip
|
100
|
+
@start = start
|
101
|
+
end
|
102
|
+
|
103
|
+
# start MUST be a positive integer
|
104
|
+
def validate_start(update: false)
|
105
|
+
unless @start.is_a?(Integer)
|
106
|
+
raise SortedInputError.new "start must be integer: #{@start}"
|
107
|
+
end
|
108
|
+
if @start.to_i < 0
|
109
|
+
raise SortedInputError.new "start must be positive: #{@start}"
|
110
|
+
end
|
111
|
+
if !update and self.class.get(start: @start, scope: @scope)
|
112
|
+
raise SortedOverlapError.new "duplicate, existing data at #{@start}"
|
113
|
+
end
|
114
|
+
@start = @start.to_i
|
115
|
+
end
|
116
|
+
|
117
|
+
# Update the Redis hash at primary_key based on the initial passed start
|
118
|
+
# The member is set to the JSON generated via calling as_json
|
119
|
+
def create(update: false)
|
120
|
+
validate_start(update: update)
|
121
|
+
@updated_at = Time.now.to_nsec_from_epoch
|
122
|
+
SortedModel.destroy(scope: @scope, start: update) if update
|
123
|
+
Store.zadd(@primary_key, @start, JSON.generate(as_json()))
|
124
|
+
if update
|
125
|
+
notify(kind: 'updated')
|
126
|
+
else
|
127
|
+
notify(kind: 'created')
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Update the Redis hash at primary_key
|
132
|
+
def update(start:)
|
133
|
+
orig_start = @start
|
134
|
+
@start = start
|
135
|
+
create(update: orig_start)
|
136
|
+
end
|
137
|
+
|
138
|
+
# destroy the activity from the redis database
|
139
|
+
def destroy
|
140
|
+
self.class.destroy(scope: @scope, start: @start)
|
141
|
+
notify(kind: 'deleted')
|
142
|
+
end
|
143
|
+
|
144
|
+
# @return [] update the redis stream / timeline topic that something has changed
|
145
|
+
def notify(kind:, extra: nil)
|
146
|
+
notification = {
|
147
|
+
'data' => JSON.generate(as_json()),
|
148
|
+
'kind' => kind,
|
149
|
+
'type' => 'calendar',
|
150
|
+
}
|
151
|
+
notification['extra'] = extra unless extra.nil?
|
152
|
+
begin
|
153
|
+
CalendarTopic.write_entry(notification, scope: @scope)
|
154
|
+
rescue StandardError => e
|
155
|
+
raise SortedError.new "Failed to write to stream: #{notification}, #{e}"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# @return [Hash] JSON encoding of this model
|
160
|
+
def as_json
|
161
|
+
{ **super(),
|
162
|
+
'start' => @start,
|
163
|
+
'type' => SORTED_TYPE,
|
164
|
+
}
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -22,6 +22,7 @@ require 'cosmos/models/model'
|
|
22
22
|
require 'cosmos/models/cvt_model'
|
23
23
|
require 'cosmos/models/microservice_model'
|
24
24
|
require 'cosmos/topics/limits_event_topic'
|
25
|
+
require 'cosmos/topics/config_topic'
|
25
26
|
require 'cosmos/system'
|
26
27
|
require 'cosmos/utilities/s3'
|
27
28
|
require 'cosmos/utilities/zip'
|
@@ -51,12 +52,20 @@ module Cosmos
|
|
51
52
|
attr_accessor :id
|
52
53
|
attr_accessor :cmd_log_cycle_time
|
53
54
|
attr_accessor :cmd_log_cycle_size
|
55
|
+
attr_accessor :cmd_log_retain_time
|
54
56
|
attr_accessor :cmd_decom_log_cycle_time
|
55
57
|
attr_accessor :cmd_decom_log_cycle_size
|
58
|
+
attr_accessor :cmd_decom_log_retain_time
|
56
59
|
attr_accessor :tlm_log_cycle_time
|
57
60
|
attr_accessor :tlm_log_cycle_size
|
61
|
+
attr_accessor :tlm_log_retain_time
|
58
62
|
attr_accessor :tlm_decom_log_cycle_time
|
59
63
|
attr_accessor :tlm_decom_log_cycle_size
|
64
|
+
attr_accessor :tlm_decom_log_retain_time
|
65
|
+
attr_accessor :reduced_minute_log_retain_time
|
66
|
+
attr_accessor :reduced_hour_log_retain_time
|
67
|
+
attr_accessor :reduced_day_log_retain_time
|
68
|
+
attr_accessor :cleanup_poll_time
|
60
69
|
attr_accessor :needs_dependencies
|
61
70
|
|
62
71
|
# NOTE: The following three class methods are used by the ModelController
|
@@ -97,6 +106,11 @@ module Cosmos
|
|
97
106
|
result
|
98
107
|
end
|
99
108
|
|
109
|
+
# @return [Array>Hash>] All packet hashes under the target_name
|
110
|
+
def self.all_packet_name_descriptions(target_name, type: :TLM, scope:)
|
111
|
+
self.packets(target_name, type: type, scope: scope).map! { |hash| hash.slice("packet_name", "description") }
|
112
|
+
end
|
113
|
+
|
100
114
|
def self.set_packet(target_name, packet_name, packet, type: :TLM, scope:)
|
101
115
|
raise "Unknown type #{type} for #{target_name} #{packet_name}" unless VALID_TYPES.include?(type)
|
102
116
|
|
@@ -113,7 +127,6 @@ module Cosmos
|
|
113
127
|
packet = packet(target_name, packet_name, type: type, scope: scope)
|
114
128
|
item = packet['items'].find { |item| item['name'] == item_name.to_s }
|
115
129
|
raise "Item '#{packet['target_name']} #{packet['packet_name']} #{item_name}' does not exist" unless item
|
116
|
-
|
117
130
|
item
|
118
131
|
end
|
119
132
|
|
@@ -149,7 +162,7 @@ module Cosmos
|
|
149
162
|
when 'TARGET'
|
150
163
|
usage = "#{keyword} <TARGET FOLDER NAME> <TARGET NAME>"
|
151
164
|
parser.verify_num_parameters(2, 2, usage)
|
152
|
-
parser.
|
165
|
+
parser.verify_parameter_naming(2) # Target name is the 2nd parameter
|
153
166
|
return self.new(name: parameters[1].to_s.upcase, folder_name: parameters[0].to_s.upcase, plugin: plugin, scope: scope)
|
154
167
|
else
|
155
168
|
raise ConfigParser::Error.new(parser, "Unknown keyword and parameters for Target: #{keyword} #{parameters.join(" ")}")
|
@@ -171,20 +184,35 @@ module Cosmos
|
|
171
184
|
plugin: nil,
|
172
185
|
cmd_log_cycle_time: 600,
|
173
186
|
cmd_log_cycle_size: 50_000_000,
|
187
|
+
cmd_log_retain_time: nil,
|
174
188
|
cmd_decom_log_cycle_time: 600,
|
175
189
|
cmd_decom_log_cycle_size: 50_000_000,
|
190
|
+
cmd_decom_log_retain_time: nil,
|
176
191
|
tlm_log_cycle_time: 600,
|
177
192
|
tlm_log_cycle_size: 50_000_000,
|
193
|
+
tlm_log_retain_time: nil,
|
178
194
|
tlm_decom_log_cycle_time: 600,
|
179
195
|
tlm_decom_log_cycle_size: 50_000_000,
|
196
|
+
tlm_decom_log_retain_time: nil,
|
197
|
+
reduced_minute_log_retain_time: nil,
|
198
|
+
reduced_hour_log_retain_time: nil,
|
199
|
+
reduced_day_log_retain_time: nil,
|
200
|
+
cleanup_poll_time: 900,
|
180
201
|
needs_dependencies: false,
|
181
202
|
scope:
|
182
203
|
)
|
183
204
|
super("#{scope}__#{PRIMARY_KEY}", name: name, plugin: plugin, updated_at: updated_at,
|
184
205
|
cmd_log_cycle_time: cmd_log_cycle_time, cmd_log_cycle_size: cmd_log_cycle_size,
|
206
|
+
cmd_log_retain_time: cmd_log_retain_time,
|
185
207
|
cmd_decom_log_cycle_time: cmd_decom_log_cycle_time, cmd_decom_log_cycle_size: cmd_decom_log_cycle_size,
|
208
|
+
cmd_decom_log_retain_time: cmd_decom_log_retain_time,
|
186
209
|
tlm_log_cycle_time: tlm_log_cycle_time, tlm_log_cycle_size: tlm_log_cycle_size,
|
210
|
+
tlm_log_retain_time: tlm_log_retain_time,
|
187
211
|
tlm_decom_log_cycle_time: tlm_decom_log_cycle_time, tlm_decom_log_cycle_size: tlm_decom_log_cycle_size,
|
212
|
+
tlm_decom_log_retain_time: tlm_decom_log_retain_time,
|
213
|
+
reduced_minute_log_retain_time: reduced_minute_log_retain_time,
|
214
|
+
reduced_hour_log_retain_time: reduced_hour_log_retain_time, reduced_day_log_retain_time: reduced_day_log_retain_time,
|
215
|
+
cleanup_poll_time: cleanup_poll_time, needs_dependencies: needs_dependencies,
|
188
216
|
scope: scope)
|
189
217
|
@folder_name = folder_name
|
190
218
|
@requires = requires
|
@@ -197,12 +225,20 @@ module Cosmos
|
|
197
225
|
@id = id
|
198
226
|
@cmd_log_cycle_time = cmd_log_cycle_time
|
199
227
|
@cmd_log_cycle_size = cmd_log_cycle_size
|
228
|
+
@cmd_log_retain_time = cmd_log_retain_time
|
200
229
|
@cmd_decom_log_cycle_time = cmd_decom_log_cycle_time
|
201
230
|
@cmd_decom_log_cycle_size = cmd_decom_log_cycle_size
|
231
|
+
@cmd_decom_log_retain_time = cmd_decom_log_retain_time
|
202
232
|
@tlm_log_cycle_time = tlm_log_cycle_time
|
203
233
|
@tlm_log_cycle_size = tlm_log_cycle_size
|
234
|
+
@tlm_log_retain_time = tlm_log_retain_time
|
204
235
|
@tlm_decom_log_cycle_time = tlm_decom_log_cycle_time
|
205
236
|
@tlm_decom_log_cycle_size = tlm_decom_log_cycle_size
|
237
|
+
@tlm_decom_log_retain_time = tlm_decom_log_retain_time
|
238
|
+
@reduced_minute_log_retain_time = reduced_minute_log_retain_time
|
239
|
+
@reduced_hour_log_retain_time = reduced_hour_log_retain_time
|
240
|
+
@reduced_day_log_retain_time = reduced_day_log_retain_time
|
241
|
+
@cleanup_poll_time = cleanup_poll_time
|
206
242
|
@needs_dependencies = needs_dependencies
|
207
243
|
end
|
208
244
|
|
@@ -222,12 +258,20 @@ module Cosmos
|
|
222
258
|
'plugin' => @plugin,
|
223
259
|
'cmd_log_cycle_time' => @cmd_log_cycle_time,
|
224
260
|
'cmd_log_cycle_size' => @cmd_log_cycle_size,
|
261
|
+
'cmd_log_retain_time' => @cmd_log_retain_time,
|
225
262
|
'cmd_decom_log_cycle_time' => @cmd_decom_log_cycle_time,
|
226
263
|
'cmd_decom_log_cycle_size' => @cmd_decom_log_cycle_size,
|
264
|
+
'cmd_decom_log_retain_time' => @cmd_decom_log_retain_time,
|
227
265
|
'tlm_log_cycle_time' => @tlm_log_cycle_time,
|
228
266
|
'tlm_log_cycle_size' => @tlm_log_cycle_size,
|
267
|
+
'tlm_log_retain_time' => @tlm_log_retain_time,
|
229
268
|
'tlm_decom_log_cycle_time' => @tlm_decom_log_cycle_time,
|
230
269
|
'tlm_decom_log_cycle_size' => @tlm_decom_log_cycle_size,
|
270
|
+
'tlm_decom_log_retain_time' => @tlm_decom_log_retain_time,
|
271
|
+
'reduced_minute_log_retain_time' => @reduced_minute_log_retain_time,
|
272
|
+
'reduced_hour_log_retain_time' => @reduced_hour_log_retain_time,
|
273
|
+
'reduced_day_log_retain_time' => @reduced_day_log_retain_time,
|
274
|
+
'cleanup_poll_time' => @cleanup_poll_time,
|
231
275
|
'needs_dependencies' => @needs_dependencies,
|
232
276
|
}
|
233
277
|
end
|
@@ -245,31 +289,79 @@ module Cosmos
|
|
245
289
|
when 'CMD_LOG_CYCLE_SIZE'
|
246
290
|
parser.verify_num_parameters(1, 1, "#{keyword} <Maximum file size in bytes>")
|
247
291
|
@cmd_log_cycle_size = parameters[0].to_i
|
292
|
+
when 'CMD_LOG_RETAIN_TIME'
|
293
|
+
parser.verify_num_parameters(1, 1, "#{keyword} <Retention time for cmd log files in seconds - nil = Forever>")
|
294
|
+
@cmd_log_retain_time = ConfigParser.handle_nil(parameters[0])
|
295
|
+
@cmd_log_retain_time = @cmd_log_retain_time.to_i if @cmd_log_retain_time
|
248
296
|
when 'CMD_DECOM_LOG_CYCLE_TIME'
|
249
297
|
parser.verify_num_parameters(1, 1, "#{keyword} <Maximum time between files in seconds>")
|
250
298
|
@cmd_decom_log_cycle_time = parameters[0].to_i
|
251
299
|
when 'CMD_DECOM_LOG_CYCLE_SIZE'
|
252
300
|
parser.verify_num_parameters(1, 1, "#{keyword} <Maximum file size in bytes>")
|
253
301
|
@cmd_decom_log_cycle_size = parameters[0].to_i
|
302
|
+
when 'CMD_DECOM_LOG_RETAIN_TIME'
|
303
|
+
parser.verify_num_parameters(1, 1, "#{keyword} <Retention time for cmd decom log files in seconds - nil = Forever>")
|
304
|
+
@cmd_decom_log_retain_time = ConfigParser.handle_nil(parameters[0])
|
305
|
+
@cmd_decom_log_retain_time = @cmd_decom_log_retain_time.to_i if @cmd_decom_log_retain_time
|
254
306
|
when 'TLM_LOG_CYCLE_TIME'
|
255
307
|
parser.verify_num_parameters(1, 1, "#{keyword} <Maximum time between files in seconds>")
|
256
308
|
@tlm_log_cycle_time = parameters[0].to_i
|
257
309
|
when 'TLM_LOG_CYCLE_SIZE'
|
258
310
|
parser.verify_num_parameters(1, 1, "#{keyword} <Maximum file size in bytes>")
|
259
311
|
@tlm_log_cycle_size = parameters[0].to_i
|
312
|
+
when 'TLM_LOG_RETAIN_TIME'
|
313
|
+
parser.verify_num_parameters(1, 1, "#{keyword} <Retention time for tlm log files in seconds - nil = Forever>")
|
314
|
+
@tlm_log_retain_time = ConfigParser.handle_nil(parameters[0])
|
315
|
+
@tlm_log_retain_time = @tlm_log_retain_time.to_i if @tlm_log_retain_time
|
260
316
|
when 'TLM_DECOM_LOG_CYCLE_TIME'
|
261
317
|
parser.verify_num_parameters(1, 1, "#{keyword} <Maximum time between files in seconds>")
|
262
318
|
@tlm_decom_log_cycle_time = parameters[0].to_i
|
263
319
|
when 'TLM_DECOM_LOG_CYCLE_SIZE'
|
264
320
|
parser.verify_num_parameters(1, 1, "#{keyword} <Maximum file size in bytes>")
|
265
321
|
@tlm_decom_log_cycle_size = parameters[0].to_i
|
322
|
+
when 'TLM_DECOM_LOG_RETAIN_TIME'
|
323
|
+
parser.verify_num_parameters(1, 1, "#{keyword} <Retention time for tlm decom log files in seconds - nil = Forever>")
|
324
|
+
@tlm_decom_log_retain_time = ConfigParser.handle_nil(parameters[0])
|
325
|
+
@tlm_decom_log_retain_time = @tlm_decom_log_retain_time.to_i if @tlm_decom_log_retain_time
|
326
|
+
when 'REDUCED_MINUTE_LOG_RETAIN_TIME'
|
327
|
+
parser.verify_num_parameters(1, 1, "#{keyword} <Retention time for reduced minute log files in seconds - nil = Forever>")
|
328
|
+
@reduced_minute_log_retain_time = ConfigParser.handle_nil(parameters[0])
|
329
|
+
@reduced_minute_log_retain_time = @reduced_minute_log_retain_time.to_i if @reduced_minute_log_retain_time
|
330
|
+
when 'REDUCED_HOUR_LOG_RETAIN_TIME'
|
331
|
+
parser.verify_num_parameters(1, 1, "#{keyword} <Retention time for reduced hour log files in seconds - nil = Forever>")
|
332
|
+
@reduced_hour_log_retain_time = ConfigParser.handle_nil(parameters[0])
|
333
|
+
@reduced_hour_log_retain_time = @reduced_hour_log_retain_time.to_i if @reduced_hour_log_retain_time
|
334
|
+
when 'REDUCED_DAY_LOG_RETAIN_TIME'
|
335
|
+
parser.verify_num_parameters(1, 1, "#{keyword} <Retention time for reduced day log files in seconds - nil = Forever>")
|
336
|
+
@reduced_day_log_retain_time = ConfigParser.handle_nil(parameters[0])
|
337
|
+
@reduced_day_log_retain_time = @reduced_day_log_retain_time.to_i if @reduced_day_log_retain_time
|
338
|
+
when 'LOG_RETAIN_TIME'
|
339
|
+
parser.verify_num_parameters(1, 1, "#{keyword} <Retention time for all log files in seconds - nil = Forever>")
|
340
|
+
log_retain_time = ConfigParser.handle_nil(parameters[0])
|
341
|
+
if log_retain_time
|
342
|
+
@cmd_log_retain_time = log_retain_time.to_i
|
343
|
+
@cmd_decom_log_retain_time = log_retain_time.to_i
|
344
|
+
@tlm_log_retain_time = log_retain_time.to_i
|
345
|
+
@tlm_decom_log_retain_time = log_retain_time.to_i
|
346
|
+
end
|
347
|
+
when 'REDUCED_LOG_RETAIN_TIME'
|
348
|
+
parser.verify_num_parameters(1, 1, "#{keyword} <Retention time for all reduced log files in seconds - nil = Forever>")
|
349
|
+
reduced_log_retain_time = ConfigParser.handle_nil(parameters[0])
|
350
|
+
if reduced_log_retain_time
|
351
|
+
@reduced_minute_log_retain_time = reduced_log_retain_time.to_i
|
352
|
+
@reduced_hour_log_retain_time = reduced_log_retain_time.to_i
|
353
|
+
@reduced_day_log_retain_time = reduced_log_retain_time.to_i
|
354
|
+
end
|
355
|
+
when 'CLEANUP_POLL_TIME'
|
356
|
+
parser.verify_num_parameters(1, 1, "#{keyword} <Cleanup polling period in seconds>")
|
357
|
+
@cleanup_poll_time = parameters[0].to_i
|
266
358
|
else
|
267
359
|
raise ConfigParser::Error.new(parser, "Unknown keyword and parameters for Target: #{keyword} #{parameters.join(" ")}")
|
268
360
|
end
|
269
361
|
return nil
|
270
362
|
end
|
271
363
|
|
272
|
-
def deploy(gem_path, variables)
|
364
|
+
def deploy(gem_path, variables, validate_only: false)
|
273
365
|
rubys3_client = Aws::S3::Client.new
|
274
366
|
variables["target_name"] = @name
|
275
367
|
start_path = "/targets/#{@folder_name}/"
|
@@ -289,7 +381,7 @@ module Cosmos
|
|
289
381
|
data = File.read(filename, mode: "rb")
|
290
382
|
begin
|
291
383
|
Cosmos.set_working_dir(File.dirname(filename)) do
|
292
|
-
data = ERB.new(data).result(binding.set_variables(variables)) if data.is_printable? and File.basename(filename)[0] != '_'
|
384
|
+
data = ERB.new(data, trim_mode: "-").result(binding.set_variables(variables)) if data.is_printable? and File.basename(filename)[0] != '_'
|
293
385
|
end
|
294
386
|
rescue => error
|
295
387
|
raise "ERB error parsing: #{filename}: #{error.formatted}"
|
@@ -298,14 +390,23 @@ module Cosmos
|
|
298
390
|
FileUtils.mkdir_p(File.dirname(local_path))
|
299
391
|
File.open(local_path, 'wb') { |file| file.write(data) }
|
300
392
|
found = true
|
301
|
-
rubys3_client.put_object(bucket: 'config', key: key, body: data)
|
393
|
+
rubys3_client.put_object(bucket: 'config', key: key, body: data) unless validate_only
|
302
394
|
end
|
303
395
|
raise "No target files found at #{target_path}" unless found
|
304
396
|
|
305
397
|
target_folder = File.join(temp_dir, @name)
|
306
|
-
|
307
|
-
system =
|
308
|
-
|
398
|
+
# Build a System for just this target
|
399
|
+
system = System.new([@name], temp_dir)
|
400
|
+
if variables["xtce_output"]
|
401
|
+
puts "Converting target #{@name} to .xtce files in #{variables["xtce_output"]}/#{@name}"
|
402
|
+
system.packet_config.to_xtce(variables["xtce_output"])
|
403
|
+
end
|
404
|
+
unless validate_only
|
405
|
+
build_target_archive(rubys3_client, temp_dir, target_folder)
|
406
|
+
system = update_store(system)
|
407
|
+
deploy_microservices(gem_path, variables, system)
|
408
|
+
ConfigTopic.write({ kind: 'created', type: 'target', name: @name, plugin: @plugin }, scope: @scope)
|
409
|
+
end
|
309
410
|
ensure
|
310
411
|
FileUtils.remove_entry(temp_dir) if temp_dir and File.exist?(temp_dir)
|
311
412
|
end
|
@@ -322,12 +423,12 @@ module Cosmos
|
|
322
423
|
Store.hdel("#{@scope}__limits_groups", group)
|
323
424
|
end
|
324
425
|
self.class.packets(@name, type: :CMD, scope: @scope).each do |packet|
|
325
|
-
|
326
|
-
|
426
|
+
Topic.del("#{@scope}__COMMAND__{#{@name}}__#{packet['packet_name']}")
|
427
|
+
Topic.del("#{@scope}__DECOMCMD__{#{@name}}__#{packet['packet_name']}")
|
327
428
|
end
|
328
429
|
self.class.packets(@name, scope: @scope).each do |packet|
|
329
|
-
|
330
|
-
|
430
|
+
Topic.del("#{@scope}__TELEMETRY__{#{@name}}__#{packet['packet_name']}")
|
431
|
+
Topic.del("#{@scope}__DECOM__{#{@name}}__#{packet['packet_name']}")
|
331
432
|
CvtModel.del(target_name: @name, packet_name: packet['packet_name'], scope: @scope)
|
332
433
|
LimitsEventTopic.delete(@name, packet['packet_name'], scope: @scope)
|
333
434
|
end
|
@@ -335,10 +436,11 @@ module Cosmos
|
|
335
436
|
Store.del("#{@scope}__cosmoscmd__#{@name}")
|
336
437
|
|
337
438
|
# Note: these match the names of the services in deploy_microservices
|
338
|
-
%w(DECOM COMMANDLOG DECOMCMDLOG PACKETLOG DECOMLOG REDUCER).each do |type|
|
439
|
+
%w(DECOM COMMANDLOG DECOMCMDLOG PACKETLOG DECOMLOG REDUCER CLEANUP).each do |type|
|
339
440
|
model = MicroserviceModel.get_model(name: "#{@scope}__#{type}__#{@name}", scope: @scope)
|
340
441
|
model.destroy if model
|
341
442
|
end
|
443
|
+
ConfigTopic.write({ kind: 'deleted', type: 'target', name: @name, plugin: @plugin }, scope: @scope)
|
342
444
|
end
|
343
445
|
|
344
446
|
##################################################
|
@@ -364,7 +466,7 @@ module Cosmos
|
|
364
466
|
|
365
467
|
begin
|
366
468
|
Cosmos.set_working_dir(File.dirname(path)) do
|
367
|
-
return ERB.new(File.read(path)).result(b)
|
469
|
+
return ERB.new(File.read(path), trim_mode: "-").result(b)
|
368
470
|
end
|
369
471
|
rescue => error
|
370
472
|
raise "ERB error parsing: #{path}: #{error.formatted}"
|
@@ -406,9 +508,7 @@ module Cosmos
|
|
406
508
|
end
|
407
509
|
end
|
408
510
|
|
409
|
-
def update_store(
|
410
|
-
# Build a System for just this target
|
411
|
-
system = System.new([@name], temp_dir)
|
511
|
+
def update_store(system)
|
412
512
|
target = system.targets[@name]
|
413
513
|
|
414
514
|
# Add in the information from the target and update
|
@@ -494,10 +594,10 @@ module Cosmos
|
|
494
594
|
# No telemetry packets for this target
|
495
595
|
end
|
496
596
|
# It's ok to call initialize_streams with an empty array
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
597
|
+
Topic.initialize_streams(command_topic_list)
|
598
|
+
Topic.initialize_streams(decom_command_topic_list)
|
599
|
+
Topic.initialize_streams(packet_topic_list)
|
600
|
+
Topic.initialize_streams(decom_topic_list)
|
501
601
|
|
502
602
|
unless command_topic_list.empty?
|
503
603
|
# CommandLog Microservice
|
@@ -515,7 +615,7 @@ module Cosmos
|
|
515
615
|
],
|
516
616
|
topics: command_topic_list,
|
517
617
|
target_names: [@name],
|
518
|
-
plugin: plugin,
|
618
|
+
plugin: @plugin,
|
519
619
|
needs_dependencies: @needs_dependencies,
|
520
620
|
scope: @scope
|
521
621
|
)
|
@@ -538,7 +638,7 @@ module Cosmos
|
|
538
638
|
],
|
539
639
|
topics: decom_command_topic_list,
|
540
640
|
target_names: [@name],
|
541
|
-
plugin: plugin,
|
641
|
+
plugin: @plugin,
|
542
642
|
needs_dependencies: @needs_dependencies,
|
543
643
|
scope: @scope
|
544
644
|
)
|
@@ -563,7 +663,7 @@ module Cosmos
|
|
563
663
|
],
|
564
664
|
topics: packet_topic_list,
|
565
665
|
target_names: [@name],
|
566
|
-
plugin: plugin,
|
666
|
+
plugin: @plugin,
|
567
667
|
needs_dependencies: @needs_dependencies,
|
568
668
|
scope: @scope
|
569
669
|
)
|
@@ -586,7 +686,7 @@ module Cosmos
|
|
586
686
|
],
|
587
687
|
topics: decom_topic_list,
|
588
688
|
target_names: [@name],
|
589
|
-
plugin: plugin,
|
689
|
+
plugin: @plugin,
|
590
690
|
needs_dependencies: @needs_dependencies,
|
591
691
|
scope: @scope
|
592
692
|
)
|
@@ -603,7 +703,7 @@ module Cosmos
|
|
603
703
|
work_dir: '/cosmos/lib/cosmos/microservices',
|
604
704
|
topics: packet_topic_list,
|
605
705
|
target_names: [@name],
|
606
|
-
plugin: plugin,
|
706
|
+
plugin: @plugin,
|
607
707
|
needs_dependencies: @needs_dependencies,
|
608
708
|
scope: @scope
|
609
709
|
)
|
@@ -619,7 +719,7 @@ module Cosmos
|
|
619
719
|
cmd: ["ruby", "reducer_microservice.rb", microservice_name],
|
620
720
|
work_dir: '/cosmos/lib/cosmos/microservices',
|
621
721
|
topics: decom_topic_list,
|
622
|
-
plugin: plugin,
|
722
|
+
plugin: @plugin,
|
623
723
|
needs_dependencies: @needs_dependencies,
|
624
724
|
scope: @scope
|
625
725
|
)
|
@@ -627,6 +727,22 @@ module Cosmos
|
|
627
727
|
microservice.deploy(gem_path, variables)
|
628
728
|
Logger.info "Configured microservice #{microservice_name}"
|
629
729
|
end
|
730
|
+
|
731
|
+
if @cmd_log_retain_time or @cmd_decom_log_retain_time or @tlm_log_retain_time or @tlm_decom_log_retain_time or
|
732
|
+
@reduced_minute_log_retain_time or @reduced_hour_log_retain_time or @reduced_day_log_retain_time
|
733
|
+
# Cleanup Microservice
|
734
|
+
microservice_name = "#{@scope}__CLEANUP__#{@name}"
|
735
|
+
microservice = MicroserviceModel.new(
|
736
|
+
name: microservice_name,
|
737
|
+
cmd: ["ruby", "cleanup_microservice.rb", microservice_name],
|
738
|
+
work_dir: '/cosmos/lib/cosmos/microservices',
|
739
|
+
plugin: @plugin,
|
740
|
+
scope: @scope
|
741
|
+
)
|
742
|
+
microservice.create
|
743
|
+
microservice.deploy(gem_path, variables)
|
744
|
+
Logger.info "Configured microservice #{microservice_name}"
|
745
|
+
end
|
630
746
|
end
|
631
747
|
end
|
632
748
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
# Copyright 2022 Ball Aerospace & Technologies Corp.
|
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 program may also be used under the terms of a commercial or
|
17
|
+
# enterprise edition license of COSMOS if purchased from the
|
18
|
+
# copyright holder
|
19
|
+
|
20
|
+
module Cosmos
|
21
|
+
class ToolConfigModel
|
22
|
+
def self.list_configs(tool, scope: $cosmos_scope)
|
23
|
+
Store.hkeys("#{scope}__config__#{tool}")
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.load_config(tool, name, scope: $cosmos_scope)
|
27
|
+
Store.hget("#{scope}__config__#{tool}", name)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.save_config(tool, name, data, scope: $cosmos_scope)
|
31
|
+
Store.hset("#{scope}__config__#{tool}", name, data)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.delete_config(tool, name, scope: $cosmos_scope)
|
35
|
+
Store.hdel("#{scope}__config__#{tool}", name)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -209,13 +209,11 @@ module Cosmos
|
|
209
209
|
return nil
|
210
210
|
end
|
211
211
|
|
212
|
-
def deploy(gem_path, variables)
|
212
|
+
def deploy(gem_path, variables, validate_only: false)
|
213
213
|
return unless @folder_name
|
214
214
|
|
215
|
-
rubys3_client = Aws::S3::Client.new
|
216
|
-
|
217
215
|
# Ensure tools bucket exists
|
218
|
-
Cosmos::S3Utilities.ensure_public_bucket('tools')
|
216
|
+
Cosmos::S3Utilities.ensure_public_bucket('tools') unless validate_only
|
219
217
|
|
220
218
|
variables["tool_name"] = @name
|
221
219
|
start_path = "/tools/#{@folder_name}/"
|
@@ -223,16 +221,17 @@ module Cosmos
|
|
223
221
|
next if filename == '.' or filename == '..' or File.directory?(filename)
|
224
222
|
|
225
223
|
key = filename.split(gem_path + '/tools/')[-1]
|
226
|
-
|
227
224
|
extension = filename.split('.')[-1]
|
228
225
|
content_type = Rack::Mime.mime_type(".#{extension}")
|
229
226
|
|
230
|
-
cache_control = Cosmos::S3Utilities.get_cache_control(filename)
|
231
|
-
|
232
227
|
# Load tool files
|
233
228
|
data = File.read(filename, mode: "rb")
|
234
|
-
data = ERB.new(data).result(binding.set_variables(variables)) if data.is_printable?
|
235
|
-
|
229
|
+
data = ERB.new(data, trim_mode: "-").result(binding.set_variables(variables)) if data.is_printable?
|
230
|
+
unless validate_only
|
231
|
+
cache_control = Cosmos::S3Utilities.get_cache_control(filename)
|
232
|
+
Aws::S3::Client.new.put_object(bucket: 'tools', content_type: content_type, cache_control: cache_control, key: key, body: data)
|
233
|
+
ConfigTopic.write({ kind: 'created', type: 'tool', name: @folder_name, plugin: @plugin }, scope: @scope)
|
234
|
+
end
|
236
235
|
end
|
237
236
|
end
|
238
237
|
|
@@ -242,6 +241,7 @@ module Cosmos
|
|
242
241
|
prefix = "#{@folder_name}/"
|
243
242
|
rubys3_client.list_objects(bucket: 'tools', prefix: prefix).contents.each do |object|
|
244
243
|
rubys3_client.delete_object(bucket: 'tools', key: object.key)
|
244
|
+
ConfigTopic.write({ kind: 'deleted', type: 'tool', name: @folder_name, plugin: @plugin }, scope: @scope)
|
245
245
|
end
|
246
246
|
end
|
247
247
|
end
|
@@ -108,25 +108,25 @@ module Cosmos
|
|
108
108
|
raise ConfigParser::Error.new(parser, "Unknown keyword and parameters for Widget: #{keyword} #{parameters.join(" ")}")
|
109
109
|
end
|
110
110
|
|
111
|
-
def deploy(gem_path, variables)
|
112
|
-
rubys3_client = Aws::S3::Client.new
|
113
|
-
|
111
|
+
def deploy(gem_path, variables, validate_only: false)
|
114
112
|
# Ensure tools bucket exists
|
115
|
-
Cosmos::S3Utilities.ensure_public_bucket('tools')
|
113
|
+
Cosmos::S3Utilities.ensure_public_bucket('tools') unless validate_only
|
116
114
|
|
117
115
|
filename = gem_path + "/tools/widgets/" + @full_name + '/' + @filename
|
118
116
|
|
119
|
-
cache_control = Cosmos::S3Utilities.get_cache_control(@filename)
|
120
|
-
|
121
117
|
# Load widget file
|
122
118
|
data = File.read(filename, mode: "rb")
|
123
119
|
Cosmos.set_working_dir(File.dirname(filename)) do
|
124
|
-
data = ERB.new(data).result(binding.set_variables(variables)) if data.is_printable?
|
120
|
+
data = ERB.new(data, trim_mode: "-").result(binding.set_variables(variables)) if data.is_printable?
|
121
|
+
end
|
122
|
+
unless validate_only
|
123
|
+
cache_control = Cosmos::S3Utilities.get_cache_control(@filename)
|
124
|
+
# TODO: support widgets that aren't just a single js file (and its associated map file)
|
125
|
+
rubys3_client = Aws::S3::Client.new
|
126
|
+
rubys3_client.put_object(bucket: 'tools', content_type: 'application/javascript', cache_control: cache_control, key: @s3_key, body: data)
|
127
|
+
data = File.read(filename + '.map', mode: "rb")
|
128
|
+
rubys3_client.put_object(bucket: 'tools', content_type: 'application/json', cache_control: cache_control, key: @s3_key + '.map', body: data)
|
125
129
|
end
|
126
|
-
# TODO: support widgets that aren't just a single js file (and its associated map file)
|
127
|
-
rubys3_client.put_object(bucket: 'tools', content_type: 'application/javascript', cache_control: cache_control, key: @s3_key, body: data)
|
128
|
-
data = File.read(filename + '.map', mode: "rb")
|
129
|
-
rubys3_client.put_object(bucket: 'tools', content_type: 'application/json', cache_control: cache_control, key: @s3_key + '.map', body: data)
|
130
130
|
end
|
131
131
|
|
132
132
|
def undeploy
|