cosmos 5.0.3 → 5.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/cosmos +1 -1
- data/lib/cosmos/api/api.rb +1 -25
- data/lib/cosmos/api/cmd_api.rb +6 -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 +8 -8
- data/lib/cosmos/config/config_parser.rb +2 -2
- data/lib/cosmos/config/meta_config_parser.rb +1 -1
- data/lib/cosmos/logs/log_writer.rb +2 -2
- data/lib/cosmos/microservices/decom_microservice.rb +1 -1
- data/lib/cosmos/microservices/interface_microservice.rb +0 -1
- data/lib/cosmos/microservices/microservice.rb +2 -2
- 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 +2 -2
- data/lib/cosmos/models/info_model.rb +1 -1
- data/lib/cosmos/models/interface_status_model.rb +1 -1
- data/lib/cosmos/models/metadata_model.rb +42 -216
- data/lib/cosmos/models/metric_model.rb +2 -2
- data/lib/cosmos/models/microservice_model.rb +1 -1
- data/lib/cosmos/models/microservice_status_model.rb +1 -1
- data/lib/cosmos/models/model.rb +16 -16
- data/lib/cosmos/models/note_model.rb +124 -0
- data/lib/cosmos/models/ping_model.rb +2 -1
- data/lib/cosmos/models/plugin_model.rb +1 -1
- data/lib/cosmos/models/process_status_model.rb +1 -1
- data/lib/cosmos/models/scope_model.rb +9 -6
- data/lib/cosmos/models/settings_model.rb +55 -0
- data/lib/cosmos/models/sorted_model.rb +165 -0
- data/lib/cosmos/models/target_model.rb +20 -20
- data/lib/cosmos/models/tool_config_model.rb +38 -0
- data/lib/cosmos/models/tool_model.rb +1 -1
- data/lib/cosmos/models/widget_model.rb +1 -1
- data/lib/cosmos/operators/microservice_operator.rb +2 -1
- data/lib/cosmos/script/calendar.rb +26 -15
- data/lib/cosmos/system/system.rb +2 -1
- 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 +31 -1
- data/lib/cosmos/topics/command_topic.rb +6 -4
- 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 +1 -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 +21 -16
- data/lib/cosmos/utilities/logger.rb +3 -3
- data/lib/cosmos/utilities/metric.rb +32 -26
- data/lib/cosmos/utilities/s3.rb +1 -1
- 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 +27 -126
- data/lib/cosmos/version.rb +5 -5
- metadata +7 -4
- data/lib/cosmos/models/narrative_model.rb +0 -280
@@ -0,0 +1,55 @@
|
|
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
|
+
require 'cosmos/models/model'
|
21
|
+
|
22
|
+
module Cosmos
|
23
|
+
class SettingsModel < Model
|
24
|
+
PRIMARY_KEY = 'cosmos__settings'
|
25
|
+
|
26
|
+
# NOTE: The following three class methods are used by the ModelController
|
27
|
+
# and are reimplemented to enable various Model class methods to work
|
28
|
+
def self.get(name:, scope: nil)
|
29
|
+
super(PRIMARY_KEY, name: name)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.names(scope: nil)
|
33
|
+
super(PRIMARY_KEY)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.all(scope: nil)
|
37
|
+
super(PRIMARY_KEY)
|
38
|
+
end
|
39
|
+
# END NOTE
|
40
|
+
|
41
|
+
def initialize(name:, scope: nil, data:)
|
42
|
+
super(PRIMARY_KEY, name: name, scope: scope)
|
43
|
+
@data = data
|
44
|
+
end
|
45
|
+
|
46
|
+
# @return [Hash] JSON encoding of this model
|
47
|
+
def as_json
|
48
|
+
{
|
49
|
+
'name' => @name,
|
50
|
+
'data' => @data,
|
51
|
+
'updated_at' => @updated_at
|
52
|
+
}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,165 @@
|
|
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
|
+
Store.zadd(@primary_key, @start, JSON.generate(as_json()))
|
123
|
+
if update
|
124
|
+
notify(kind: 'updated')
|
125
|
+
else
|
126
|
+
notify(kind: 'created')
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Update the Redis hash at primary_key
|
131
|
+
def update(start:)
|
132
|
+
@start = start
|
133
|
+
create(update: true)
|
134
|
+
end
|
135
|
+
|
136
|
+
# destroy the activity from the redis database
|
137
|
+
def destroy
|
138
|
+
self.class.destroy(scope: @scope, start: @start)
|
139
|
+
notify(kind: 'deleted')
|
140
|
+
end
|
141
|
+
|
142
|
+
# @return [] update the redis stream / timeline topic that something has changed
|
143
|
+
def notify(kind:, extra: nil)
|
144
|
+
notification = {
|
145
|
+
'data' => JSON.generate(as_json()),
|
146
|
+
'kind' => kind,
|
147
|
+
'type' => 'calendar',
|
148
|
+
}
|
149
|
+
notification['extra'] = extra unless extra.nil?
|
150
|
+
begin
|
151
|
+
CalendarTopic.write_entry(notification, scope: @scope)
|
152
|
+
rescue StandardError => e
|
153
|
+
raise SortedError.new "Failed to write to stream: #{notification}, #{e}"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# @return [Hash] JSON encoding of this model
|
158
|
+
def as_json
|
159
|
+
{ **super(),
|
160
|
+
'start' => @start,
|
161
|
+
'type' => SORTED_TYPE,
|
162
|
+
}
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -208,7 +208,7 @@ module Cosmos
|
|
208
208
|
tlm_log_cycle_time: tlm_log_cycle_time, tlm_log_cycle_size: tlm_log_cycle_size,
|
209
209
|
tlm_log_retain_time: tlm_log_retain_time,
|
210
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,
|
211
|
+
tlm_decom_log_retain_time: tlm_decom_log_retain_time,
|
212
212
|
reduced_minute_log_retain_time: reduced_minute_log_retain_time,
|
213
213
|
reduced_hour_log_retain_time: reduced_hour_log_retain_time, reduced_day_log_retain_time: reduced_day_log_retain_time,
|
214
214
|
cleanup_poll_time: cleanup_poll_time, needs_dependencies: needs_dependencies,
|
@@ -269,7 +269,7 @@ module Cosmos
|
|
269
269
|
'tlm_decom_log_retain_time' => @tlm_decom_log_retain_time,
|
270
270
|
'reduced_minute_log_retain_time' => @reduced_minute_log_retain_time,
|
271
271
|
'reduced_hour_log_retain_time' => @reduced_hour_log_retain_time,
|
272
|
-
'reduced_day_log_retain_time' => @reduced_day_log_retain_time,
|
272
|
+
'reduced_day_log_retain_time' => @reduced_day_log_retain_time,
|
273
273
|
'cleanup_poll_time' => @cleanup_poll_time,
|
274
274
|
'needs_dependencies' => @needs_dependencies,
|
275
275
|
}
|
@@ -301,7 +301,7 @@ module Cosmos
|
|
301
301
|
when 'CMD_DECOM_LOG_RETAIN_TIME'
|
302
302
|
parser.verify_num_parameters(1, 1, "#{keyword} <Retention time for cmd decom log files in seconds - nil = Forever>")
|
303
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
|
304
|
+
@cmd_decom_log_retain_time = @cmd_decom_log_retain_time.to_i if @cmd_decom_log_retain_time
|
305
305
|
when 'TLM_LOG_CYCLE_TIME'
|
306
306
|
parser.verify_num_parameters(1, 1, "#{keyword} <Maximum time between files in seconds>")
|
307
307
|
@tlm_log_cycle_time = parameters[0].to_i
|
@@ -311,7 +311,7 @@ module Cosmos
|
|
311
311
|
when 'TLM_LOG_RETAIN_TIME'
|
312
312
|
parser.verify_num_parameters(1, 1, "#{keyword} <Retention time for tlm log files in seconds - nil = Forever>")
|
313
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
|
314
|
+
@tlm_log_retain_time = @tlm_log_retain_time.to_i if @tlm_log_retain_time
|
315
315
|
when 'TLM_DECOM_LOG_CYCLE_TIME'
|
316
316
|
parser.verify_num_parameters(1, 1, "#{keyword} <Maximum time between files in seconds>")
|
317
317
|
@tlm_decom_log_cycle_time = parameters[0].to_i
|
@@ -333,22 +333,22 @@ module Cosmos
|
|
333
333
|
when 'REDUCED_DAY_LOG_RETAIN_TIME'
|
334
334
|
parser.verify_num_parameters(1, 1, "#{keyword} <Retention time for reduced day log files in seconds - nil = Forever>")
|
335
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
|
336
|
+
@reduced_day_log_retain_time = @reduced_day_log_retain_time.to_i if @reduced_day_log_retain_time
|
337
337
|
when 'LOG_RETAIN_TIME'
|
338
338
|
parser.verify_num_parameters(1, 1, "#{keyword} <Retention time for all log files in seconds - nil = Forever>")
|
339
339
|
log_retain_time = ConfigParser.handle_nil(parameters[0])
|
340
|
-
if log_retain_time
|
340
|
+
if log_retain_time
|
341
341
|
@cmd_log_retain_time = log_retain_time.to_i
|
342
|
-
@cmd_decom_log_retain_time = log_retain_time.to_i
|
342
|
+
@cmd_decom_log_retain_time = log_retain_time.to_i
|
343
343
|
@tlm_log_retain_time = log_retain_time.to_i
|
344
344
|
@tlm_decom_log_retain_time = log_retain_time.to_i
|
345
|
-
end
|
345
|
+
end
|
346
346
|
when 'REDUCED_LOG_RETAIN_TIME'
|
347
347
|
parser.verify_num_parameters(1, 1, "#{keyword} <Retention time for all reduced log files in seconds - nil = Forever>")
|
348
348
|
reduced_log_retain_time = ConfigParser.handle_nil(parameters[0])
|
349
|
-
if reduced_log_retain_time
|
349
|
+
if reduced_log_retain_time
|
350
350
|
@reduced_minute_log_retain_time = reduced_log_retain_time.to_i
|
351
|
-
@reduced_hour_log_retain_time = reduced_log_retain_time.to_i
|
351
|
+
@reduced_hour_log_retain_time = reduced_log_retain_time.to_i
|
352
352
|
@reduced_day_log_retain_time = reduced_log_retain_time.to_i
|
353
353
|
end
|
354
354
|
when 'CLEANUP_POLL_TIME'
|
@@ -380,7 +380,7 @@ module Cosmos
|
|
380
380
|
data = File.read(filename, mode: "rb")
|
381
381
|
begin
|
382
382
|
Cosmos.set_working_dir(File.dirname(filename)) do
|
383
|
-
data = ERB.new(data).result(binding.set_variables(variables)) if data.is_printable? and File.basename(filename)[0] != '_'
|
383
|
+
data = ERB.new(data, trim_mode: "-").result(binding.set_variables(variables)) if data.is_printable? and File.basename(filename)[0] != '_'
|
384
384
|
end
|
385
385
|
rescue => error
|
386
386
|
raise "ERB error parsing: #{filename}: #{error.formatted}"
|
@@ -413,12 +413,12 @@ module Cosmos
|
|
413
413
|
Store.hdel("#{@scope}__limits_groups", group)
|
414
414
|
end
|
415
415
|
self.class.packets(@name, type: :CMD, scope: @scope).each do |packet|
|
416
|
-
|
417
|
-
|
416
|
+
Topic.del("#{@scope}__COMMAND__{#{@name}}__#{packet['packet_name']}")
|
417
|
+
Topic.del("#{@scope}__DECOMCMD__{#{@name}}__#{packet['packet_name']}")
|
418
418
|
end
|
419
419
|
self.class.packets(@name, scope: @scope).each do |packet|
|
420
|
-
|
421
|
-
|
420
|
+
Topic.del("#{@scope}__TELEMETRY__{#{@name}}__#{packet['packet_name']}")
|
421
|
+
Topic.del("#{@scope}__DECOM__{#{@name}}__#{packet['packet_name']}")
|
422
422
|
CvtModel.del(target_name: @name, packet_name: packet['packet_name'], scope: @scope)
|
423
423
|
LimitsEventTopic.delete(@name, packet['packet_name'], scope: @scope)
|
424
424
|
end
|
@@ -455,7 +455,7 @@ module Cosmos
|
|
455
455
|
|
456
456
|
begin
|
457
457
|
Cosmos.set_working_dir(File.dirname(path)) do
|
458
|
-
return ERB.new(File.read(path)).result(b)
|
458
|
+
return ERB.new(File.read(path), trim_mode: "-").result(b)
|
459
459
|
end
|
460
460
|
rescue => error
|
461
461
|
raise "ERB error parsing: #{path}: #{error.formatted}"
|
@@ -585,10 +585,10 @@ module Cosmos
|
|
585
585
|
# No telemetry packets for this target
|
586
586
|
end
|
587
587
|
# It's ok to call initialize_streams with an empty array
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
588
|
+
Topic.initialize_streams(command_topic_list)
|
589
|
+
Topic.initialize_streams(decom_command_topic_list)
|
590
|
+
Topic.initialize_streams(packet_topic_list)
|
591
|
+
Topic.initialize_streams(decom_topic_list)
|
592
592
|
|
593
593
|
unless command_topic_list.empty?
|
594
594
|
# CommandLog Microservice
|
@@ -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
|
@@ -231,7 +231,7 @@ module Cosmos
|
|
231
231
|
|
232
232
|
# Load tool files
|
233
233
|
data = File.read(filename, mode: "rb")
|
234
|
-
data = ERB.new(data).result(binding.set_variables(variables)) if data.is_printable?
|
234
|
+
data = ERB.new(data, trim_mode: "-").result(binding.set_variables(variables)) if data.is_printable?
|
235
235
|
rubys3_client.put_object(bucket: 'tools', content_type: content_type, cache_control: cache_control, key: key, body: data)
|
236
236
|
end
|
237
237
|
end
|
@@ -121,7 +121,7 @@ module Cosmos
|
|
121
121
|
# Load widget file
|
122
122
|
data = File.read(filename, mode: "rb")
|
123
123
|
Cosmos.set_working_dir(File.dirname(filename)) do
|
124
|
-
data = ERB.new(data).result(binding.set_variables(variables)) if data.is_printable?
|
124
|
+
data = ERB.new(data, trim_mode: "-").result(binding.set_variables(variables)) if data.is_printable?
|
125
125
|
end
|
126
126
|
# TODO: support widgets that aren't just a single js file (and its associated map file)
|
127
127
|
rubys3_client.put_object(bucket: 'tools', content_type: 'application/javascript', cache_control: cache_control, key: @s3_key, body: data)
|
@@ -39,7 +39,7 @@ module Cosmos
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def convert_microservice_to_process_definition(microservice_name, microservice_config)
|
42
|
-
process_definition = ["ruby", "plugin_microservice.rb"
|
42
|
+
process_definition = ["ruby", "plugin_microservice.rb"]
|
43
43
|
work_dir = "/cosmos/lib/cosmos/microservices"
|
44
44
|
env = microservice_config["env"].dup
|
45
45
|
if microservice_config["needs_dependencies"]
|
@@ -47,6 +47,7 @@ module Cosmos
|
|
47
47
|
else
|
48
48
|
env['GEM_HOME'] = nil
|
49
49
|
end
|
50
|
+
env['COSMOS_MICROSERVICE_NAME'] = microservice_name
|
50
51
|
container = microservice_config["container"]
|
51
52
|
scope = microservice_name.split("__")[0]
|
52
53
|
return process_definition, work_dir, env, scope, container
|
@@ -18,6 +18,7 @@
|
|
18
18
|
# copyright holder
|
19
19
|
|
20
20
|
require 'cosmos/script/extract'
|
21
|
+
require 'time'
|
21
22
|
|
22
23
|
module Cosmos
|
23
24
|
module Script
|
@@ -25,38 +26,48 @@ module Cosmos
|
|
25
26
|
|
26
27
|
private
|
27
28
|
|
28
|
-
#
|
29
|
+
# Gets the current metadata
|
29
30
|
#
|
30
|
-
# @param target [String] Target to set metadata on
|
31
31
|
# @return The result of the method call.
|
32
|
-
def get_metadata(
|
33
|
-
|
34
|
-
response = $api_server.request('get', endpoint)
|
32
|
+
def get_metadata()
|
33
|
+
response = $api_server.request('get', "/cosmos-api/metadata/latest")
|
35
34
|
return nil if response.nil? || response.code != 200
|
36
35
|
return JSON.parse(response.body)
|
37
36
|
end
|
38
37
|
|
39
|
-
# Sets the metadata
|
38
|
+
# Sets the metadata
|
40
39
|
#
|
41
|
-
# @param target [String] Target to set metadata on
|
42
40
|
# @param metadata [Hash<Symbol, Variable>] A hash of metadata
|
43
|
-
# @param color [String] Events color to show on Calendar tool
|
44
|
-
# @param start
|
41
|
+
# @param color [String] Events color to show on Calendar tool, if nil will be blue
|
42
|
+
# @param start [Time] Metadata time value, if nil will be current time
|
45
43
|
# @return The result of the method call.
|
46
|
-
def set_metadata(
|
44
|
+
def set_metadata(metadata, color: nil, start: nil)
|
47
45
|
color = color.nil? ? '#003784' : color
|
48
|
-
data = {:
|
49
|
-
data[:start] = start unless start.nil?
|
46
|
+
data = { color: color, metadata: metadata }
|
47
|
+
data[:start] = start.iso8601 unless start.nil?
|
50
48
|
response = $api_server.request('post', '/cosmos-api/metadata', data: data, json: true)
|
51
49
|
return nil if response.nil? || response.code != 201
|
52
50
|
return JSON.parse(response.body)
|
53
51
|
end
|
54
52
|
|
55
|
-
#
|
53
|
+
# Updates the metadata
|
56
54
|
#
|
57
|
-
|
58
|
-
|
55
|
+
# @param start [Integer] Metadata time value as integer seconds from epoch
|
56
|
+
# @param metadata [Hash<Symbol, Variable>] A hash of metadata
|
57
|
+
# @param color [String] Events color to show on Calendar tool, if nil will be blue
|
58
|
+
# @return The result of the method call.
|
59
|
+
def update_metadata(start, metadata, color: nil)
|
60
|
+
color = color.nil? ? '#003784' : color
|
61
|
+
data = { :color => color, :metadata => metadata }
|
62
|
+
data[:start] = Time.at(start).iso8601
|
63
|
+
response = $api_server.request('put', "/cosmos-api/metadata/#{start}", data: data, json: true)
|
64
|
+
return nil if response.nil? || response.code != 201
|
65
|
+
return JSON.parse(response.body)
|
59
66
|
end
|
60
67
|
|
68
|
+
# Requests the metadata from the user for a target
|
69
|
+
def input_metadata(*args, **kwargs)
|
70
|
+
raise StandardError "can only be used in Script Runner"
|
71
|
+
end
|
61
72
|
end
|
62
73
|
end
|
data/lib/cosmos/system/system.rb
CHANGED
@@ -26,6 +26,7 @@ require 'cosmos/packets/limits'
|
|
26
26
|
require 'cosmos/system/target'
|
27
27
|
require 'cosmos/utilities/s3'
|
28
28
|
require 'cosmos/utilities/zip'
|
29
|
+
require 'cosmos/models/scope_model'
|
29
30
|
require 'thread'
|
30
31
|
require 'fileutils'
|
31
32
|
|
@@ -54,7 +55,7 @@ module Cosmos
|
|
54
55
|
|
55
56
|
# @return [Symbol] The current limits_set of the system returned from Redis
|
56
57
|
def self.limits_set
|
57
|
-
|
58
|
+
ScopeModel.limits_set(scope: $cosmos_scope)
|
58
59
|
end
|
59
60
|
|
60
61
|
def self.setup_targets(target_names, base_dir, scope:)
|
data/lib/cosmos/top_level.rb
CHANGED
@@ -37,9 +37,13 @@ class HazardousError < StandardError
|
|
37
37
|
attr_accessor :cmd_name
|
38
38
|
attr_accessor :cmd_params
|
39
39
|
attr_accessor :hazardous_description
|
40
|
+
attr_accessor :formatted # formatted command for use in resending original
|
40
41
|
|
41
42
|
def to_s
|
42
|
-
"#{target_name} #{cmd_name} with #{cmd_params} is Hazardous
|
43
|
+
string = "#{target_name} #{cmd_name} with #{cmd_params} is Hazardous"
|
44
|
+
string << "due to '#{hazardous_description}'" if hazardous_description
|
45
|
+
# Pass along the original formatted command so it can be resent
|
46
|
+
string << ".\n#{formatted}"
|
43
47
|
end
|
44
48
|
end
|
45
49
|
|
@@ -26,7 +26,7 @@ module Cosmos
|
|
26
26
|
# Notify to the topic
|
27
27
|
#
|
28
28
|
# ```json
|
29
|
-
# {
|
29
|
+
# {
|
30
30
|
# "kind" => "created",
|
31
31
|
# "type" => "trigger",
|
32
32
|
# "data" => {
|
@@ -46,7 +46,7 @@ module Cosmos
|
|
46
46
|
# }
|
47
47
|
# ```
|
48
48
|
def self.write_notification(notification, scope:)
|
49
|
-
|
49
|
+
Topic.write_topic("#{scope}#{PRIMARY_KEY}", notification, '*', 1000)
|
50
50
|
end
|
51
51
|
end
|
52
52
|
end
|
@@ -40,7 +40,37 @@ module Cosmos
|
|
40
40
|
json_hash[item.name + "__U"] = packet.read_item(item, :WITH_UNITS) if item.units
|
41
41
|
end
|
42
42
|
msg_hash['json_data'] = JSON.generate(json_hash.as_json)
|
43
|
-
|
43
|
+
Topic.write_topic(topic, msg_hash)
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.get_cmd_item(target_name, packet_name, param_name, type: :WITH_UNITS, scope: $cosmos_scope)
|
47
|
+
msg_id, msg_hash = Topic.get_newest_message("#{scope}__DECOMCMD__{#{target_name}}__#{packet_name}")
|
48
|
+
if msg_id
|
49
|
+
# TODO: We now have these reserved items directly on command packets
|
50
|
+
# Do we still calculate from msg_hash['time'] or use the times directly?
|
51
|
+
#
|
52
|
+
# if param_name == 'RECEIVED_TIMESECONDS' || param_name == 'PACKET_TIMESECONDS'
|
53
|
+
# Time.from_nsec_from_epoch(msg_hash['time'].to_i).to_f
|
54
|
+
# elsif param_name == 'RECEIVED_TIMEFORMATTED' || param_name == 'PACKET_TIMEFORMATTED'
|
55
|
+
# Time.from_nsec_from_epoch(msg_hash['time'].to_i).formatted
|
56
|
+
if param_name == 'RECEIVED_COUNT'
|
57
|
+
msg_hash['received_count'].to_i
|
58
|
+
else
|
59
|
+
json = msg_hash['json_data']
|
60
|
+
hash = JSON.parse(json)
|
61
|
+
# Start from the most complex down to the basic raw value
|
62
|
+
value = hash["#{param_name}__U"]
|
63
|
+
return value if value && type == :WITH_UNITS
|
64
|
+
|
65
|
+
value = hash["#{param_name}__F"]
|
66
|
+
return value if value && (type == :WITH_UNITS || type == :FORMATTED)
|
67
|
+
|
68
|
+
value = hash["#{param_name}__C"]
|
69
|
+
return value if value && (type == :WITH_UNITS || type == :FORMATTED || type == :CONVERTED)
|
70
|
+
|
71
|
+
return hash[param_name]
|
72
|
+
end
|
73
|
+
end
|
44
74
|
end
|
45
75
|
end
|
46
76
|
end
|
@@ -31,17 +31,17 @@ module Cosmos
|
|
31
31
|
received_count: packet.received_count,
|
32
32
|
stored: packet.stored,
|
33
33
|
buffer: packet.buffer(false) }
|
34
|
-
|
34
|
+
Topic.write_topic(topic, msg_hash)
|
35
35
|
end
|
36
36
|
|
37
37
|
# @param command [Hash] Command hash structure read to be written to a topic
|
38
38
|
def self.send_command(command, scope:)
|
39
39
|
ack_topic = "{#{scope}__ACKCMD}TARGET__#{command['target_name']}"
|
40
|
-
|
40
|
+
Topic.update_topic_offsets([ack_topic])
|
41
41
|
# Save the existing cmd_params Hash and JSON generate before writing to the topic
|
42
42
|
cmd_params = command['cmd_params']
|
43
43
|
command['cmd_params'] = JSON.generate(command['cmd_params'].as_json)
|
44
|
-
cmd_id =
|
44
|
+
cmd_id = Topic.write_topic("{#{scope}__CMD}TARGET__#{command['target_name']}", command, '*', 100)
|
45
45
|
# TODO: This timeout is fine for most but can we get the write_timeout from the interface here?
|
46
46
|
time = Time.now
|
47
47
|
while (Time.now - time) < COMMAND_ACK_TIMEOUT_S
|
@@ -66,7 +66,7 @@ module Cosmos
|
|
66
66
|
###########################################################################
|
67
67
|
|
68
68
|
def self.raise_hazardous_error(msg_hash, target_name, cmd_name, cmd_params)
|
69
|
-
_, description,
|
69
|
+
_, description, formatted = msg_hash["result"].split("\n")
|
70
70
|
# Create and populate a new HazardousError and raise it up
|
71
71
|
# The _cmd method in script/commands.rb rescues this and calls prompt_for_hazardous
|
72
72
|
error = HazardousError.new
|
@@ -74,6 +74,8 @@ module Cosmos
|
|
74
74
|
error.cmd_name = cmd_name
|
75
75
|
error.cmd_params = cmd_params
|
76
76
|
error.hazardous_description = description
|
77
|
+
error.formatted = formatted
|
78
|
+
|
77
79
|
# No Logger.info because the error is already logged by the Logger.info "Ack Received ...
|
78
80
|
raise error
|
79
81
|
end
|