etna 0.1.37 → 0.1.41
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/etna.rb +1 -0
- data/lib/etna/application.rb +63 -9
- data/lib/etna/clients/metis/client.rb +54 -1
- data/lib/etna/clients/metis/workflows.rb +4 -3
- data/lib/etna/clients/metis/workflows/ingest_metis_data_workflow.rb +35 -0
- data/lib/etna/clients/metis/workflows/metis_upload_workflow.rb +1 -1
- data/lib/etna/controller.rb +18 -13
- data/lib/etna/filesystem.rb +123 -0
- data/lib/etna/logger.rb +4 -0
- data/lib/etna/remote.rb +38 -0
- data/lib/etna/route.rb +60 -0
- metadata +32 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 44b6c9fde1d01fab95038052180531fafd4a120e77ffbd12a8ac14e28122cd05
|
4
|
+
data.tar.gz: e1cb315eaeb4d35efc9e7f181e0cad767833b98f7ce3f26386e040c758c8483c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3129a01c4181a772ab6752ed319396485e06f774b8091bff1ed9cbf6543a34820e0cc0706fd313ce5b3fb848a25f347de17bc376dc66b36458975d6298f48608
|
7
|
+
data.tar.gz: 82c57cff18c826a0a2664a63e0a531df57c75af30ceb3408d1d8ec1b9cb942fd25bd11253e6d880db6973df4cd60ade0764fac798a543af1e7601bfcc21abc45
|
data/lib/etna.rb
CHANGED
data/lib/etna/application.rb
CHANGED
@@ -61,11 +61,49 @@ module Etna::Application
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def setup_yabeda
|
64
|
+
application = self.id
|
65
|
+
Yabeda.configure do
|
66
|
+
default_tag :application, application
|
67
|
+
|
68
|
+
group :etna do
|
69
|
+
histogram :response_time do
|
70
|
+
comment "Time spent by a controller returning a response"
|
71
|
+
unit :seconds
|
72
|
+
tags [:controller, :action, :user_hash, :project_name]
|
73
|
+
buckets [0.01, 0.1, 0.3, 0.5, 1, 5]
|
74
|
+
end
|
75
|
+
|
76
|
+
counter :visits do
|
77
|
+
comment "Counts visits to the controller"
|
78
|
+
tags [:controller, :action, :user_hash, :project_name]
|
79
|
+
end
|
80
|
+
|
81
|
+
counter :rollbar_errors do
|
82
|
+
comment "Counts errors detected by and sent to rollbar"
|
83
|
+
end
|
84
|
+
|
85
|
+
gauge :last_command_completion do
|
86
|
+
comment "Unix time of last time command was completed"
|
87
|
+
tags [:command, :status, :application]
|
88
|
+
end
|
89
|
+
|
90
|
+
histogram :command_runtime do
|
91
|
+
comment "Time spent processing a given command"
|
92
|
+
tags [:command, :status, :application]
|
93
|
+
unit :seconds
|
94
|
+
buckets [0.1, 1, 5, 60, 300, 1500]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
64
99
|
Yabeda.configure!
|
65
100
|
end
|
66
101
|
|
102
|
+
# Writes all metrics currently gathered to a text format prometheus file. If /tmp/metrics.prom is bind mounted
|
103
|
+
# to the host directed bound to the node_exporter's file exporter directory, these will be exported to
|
104
|
+
# prometheus. Combine this enable_job_metrics! for maximum effect.
|
67
105
|
def write_job_metrics(name)
|
68
|
-
node_metrics_dir =
|
106
|
+
node_metrics_dir = "/tmp/metrics.prom"
|
69
107
|
::FileUtils.mkdir_p(node_metrics_dir)
|
70
108
|
|
71
109
|
tmp_file = ::File.join(node_metrics_dir, "#{name}.prom.$$")
|
@@ -126,17 +164,33 @@ module Etna::Application
|
|
126
164
|
end
|
127
165
|
|
128
166
|
def run_command(config, *args, &block)
|
167
|
+
application = self.id
|
168
|
+
status = 'success'
|
169
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
129
170
|
cmd, cmd_args, cmd_kwds = find_command(*args)
|
130
|
-
cmd.setup(config)
|
131
171
|
|
132
|
-
|
133
|
-
|
134
|
-
|
172
|
+
begin
|
173
|
+
cmd.setup(config)
|
174
|
+
if block_given?
|
175
|
+
return unless yield [cmd, cmd_args]
|
176
|
+
end
|
135
177
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
178
|
+
cmd.execute(*cmd.fill_in_missing_params(cmd_args), **cmd_kwds)
|
179
|
+
rescue => e
|
180
|
+
Rollbar.error(e)
|
181
|
+
status = 'failed'
|
182
|
+
raise
|
183
|
+
ensure
|
184
|
+
if defined?(Yabeda) && Yabeda.configured?
|
185
|
+
tags = { command: cmd.class.name, status: status, application: application }
|
186
|
+
dur = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
|
187
|
+
|
188
|
+
Yabeda.etna.last_command_completion.set(tags, Time.now.to_i)
|
189
|
+
Yabeda.etna.command_runtime.measure(tags, dur)
|
190
|
+
|
191
|
+
write_job_metrics("run_command.#{cmd.class.name}")
|
192
|
+
end
|
193
|
+
end
|
140
194
|
end
|
141
195
|
end
|
142
196
|
|
@@ -210,6 +210,52 @@ module Etna
|
|
210
210
|
}
|
211
211
|
end
|
212
212
|
|
213
|
+
def resolve_conflicts_and_verify_rename(project_name:, source_bucket:, dest_bucket:, folder:, file:)
|
214
|
+
parent_folder = ::File.dirname(file.file_path)
|
215
|
+
|
216
|
+
should_rename_original = true
|
217
|
+
|
218
|
+
# If the destination folder already exists, check to see if
|
219
|
+
# the file also exists, otherwise we risk a
|
220
|
+
# rename conflict.
|
221
|
+
create_folder_request = CreateFolderRequest.new(
|
222
|
+
project_name: project_name,
|
223
|
+
bucket_name: dest_bucket,
|
224
|
+
folder_path: parent_folder
|
225
|
+
)
|
226
|
+
|
227
|
+
if folder_exists?(create_folder_request)
|
228
|
+
# If file exists in destination, delete the older file.
|
229
|
+
list_dest_folder_request = Etna::Clients::Metis::ListFolderRequest.new(
|
230
|
+
bucket_name: dest_bucket,
|
231
|
+
project_name: project_name,
|
232
|
+
folder_path: parent_folder
|
233
|
+
)
|
234
|
+
|
235
|
+
dest_file = list_folder(list_dest_folder_request).files.all.find { |f| f.file_name == file.file_name }
|
236
|
+
|
237
|
+
if (dest_file && file.updated_at <= dest_file.updated_at)
|
238
|
+
# Delete source file if it's out of date
|
239
|
+
delete_file(Etna::Clients::Metis::DeleteFileRequest.new(
|
240
|
+
bucket_name: source_bucket,
|
241
|
+
project_name: project_name,
|
242
|
+
file_path: file.file_path,
|
243
|
+
))
|
244
|
+
|
245
|
+
should_rename_original = false
|
246
|
+
elsif (dest_file && file.updated_at > dest_file.updated_at)
|
247
|
+
# Delete dest file if it's out of date
|
248
|
+
delete_file(Etna::Clients::Metis::DeleteFileRequest.new(
|
249
|
+
bucket_name: dest_bucket,
|
250
|
+
project_name: project_name,
|
251
|
+
file_path: dest_file.file_path,
|
252
|
+
))
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
should_rename_original
|
257
|
+
end
|
258
|
+
|
213
259
|
def recursively_rename_folder(project_name:, source_bucket:, dest_bucket:, folder:)
|
214
260
|
folder_contents = list_folder(
|
215
261
|
Etna::Clients::Metis::ListFolderRequest.new(
|
@@ -228,6 +274,13 @@ module Etna
|
|
228
274
|
end
|
229
275
|
|
230
276
|
folder_contents.files.all.each do |file|
|
277
|
+
should_rename = resolve_conflicts_and_verify_rename(
|
278
|
+
project_name: project_name,
|
279
|
+
source_bucket: source_bucket,
|
280
|
+
dest_bucket: dest_bucket,
|
281
|
+
folder: folder,
|
282
|
+
file: file)
|
283
|
+
|
231
284
|
rename_file(Etna::Clients::Metis::RenameFileRequest.new(
|
232
285
|
bucket_name: source_bucket,
|
233
286
|
project_name: project_name,
|
@@ -235,7 +288,7 @@ module Etna
|
|
235
288
|
new_bucket_name: dest_bucket,
|
236
289
|
new_file_path: file.file_path,
|
237
290
|
create_parent: true)
|
238
|
-
)
|
291
|
+
) if should_rename
|
239
292
|
end
|
240
293
|
|
241
294
|
# Now delete the source folder
|
@@ -1,3 +1,4 @@
|
|
1
|
-
require_relative
|
2
|
-
require_relative
|
3
|
-
require_relative
|
1
|
+
require_relative "./workflows/metis_download_workflow"
|
2
|
+
require_relative "./workflows/metis_upload_workflow"
|
3
|
+
require_relative "./workflows/sync_metis_data_workflow"
|
4
|
+
require_relative "./workflows/ingest_metis_data_workflow"
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "ostruct"
|
2
|
+
require "fileutils"
|
3
|
+
require "tempfile"
|
4
|
+
|
5
|
+
module Etna
|
6
|
+
module Clients
|
7
|
+
class Metis
|
8
|
+
class IngestMetisDataWorkflow < Struct.new(:metis_filesystem, :ingest_filesystem, :logger, keyword_init: true)
|
9
|
+
# Since we are doing manual triage of files,
|
10
|
+
# do not automatically copy directory trees.
|
11
|
+
# srcs must be a list of full paths to files.
|
12
|
+
def copy_files(srcs, &block)
|
13
|
+
srcs.each do |src|
|
14
|
+
if !ingest_filesystem.exist?(src)
|
15
|
+
logger&.warn("#{src} does not exist on source filesystem. Skipping.")
|
16
|
+
next
|
17
|
+
end
|
18
|
+
|
19
|
+
logger&.info("Copying file #{src} (#{Etna::Formatting.as_size(ingest_filesystem.stat(src).size)})")
|
20
|
+
|
21
|
+
# For ingestion triage, just copy over the exact path + filename.
|
22
|
+
copy_file(dest: src, src: src, &block)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def copy_file(dest:, src:, &block)
|
27
|
+
ingest_filesystem.with_readable(src, "r") do |io|
|
28
|
+
metis_filesystem.do_streaming_upload(io, dest, ingest_filesystem.stat(src).size)
|
29
|
+
yield src if block_given?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/etna/controller.rb
CHANGED
@@ -19,25 +19,30 @@ module Etna
|
|
19
19
|
@logger.warn(request_msg(line))
|
20
20
|
end
|
21
21
|
|
22
|
+
def handle_error(e)
|
23
|
+
case e
|
24
|
+
when Etna::Error
|
25
|
+
Rollbar.error(e)
|
26
|
+
@logger.error(request_msg("Exiting with #{e.status}, #{e.message}"))
|
27
|
+
return failure(e.status, error: e.message)
|
28
|
+
else
|
29
|
+
Rollbar.error(e)
|
30
|
+
@logger.error(request_msg('Caught unspecified error'))
|
31
|
+
@logger.error(request_msg(e.message))
|
32
|
+
e.backtrace.each do |trace|
|
33
|
+
@logger.error(request_msg(trace))
|
34
|
+
end
|
35
|
+
return failure(500, error: 'Server error.')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
22
39
|
def response(&block)
|
23
40
|
return instance_eval(&block) if block_given?
|
24
|
-
|
25
41
|
return send(@action) if @action
|
26
42
|
|
27
|
-
|
28
43
|
[501, {}, ['This controller is not implemented.']]
|
29
|
-
rescue Etna::Error => e
|
30
|
-
Rollbar.error(e)
|
31
|
-
@logger.error(request_msg("Exiting with #{e.status}, #{e.message}"))
|
32
|
-
return failure(e.status, error: e.message)
|
33
44
|
rescue Exception => e
|
34
|
-
|
35
|
-
@logger.error(request_msg('Caught unspecified error'))
|
36
|
-
@logger.error(request_msg(e.message))
|
37
|
-
e.backtrace.each do |trace|
|
38
|
-
@logger.error(request_msg(trace))
|
39
|
-
end
|
40
|
-
return failure(500, error: 'Server error.')
|
45
|
+
handle_error(e)
|
41
46
|
end
|
42
47
|
|
43
48
|
def require_params(*params)
|
data/lib/etna/filesystem.rb
CHANGED
@@ -3,6 +3,7 @@ require 'fileutils'
|
|
3
3
|
require 'open3'
|
4
4
|
require 'securerandom'
|
5
5
|
require 'concurrent-ruby'
|
6
|
+
require 'curb'
|
6
7
|
|
7
8
|
module Etna
|
8
9
|
# A class that encapsulates opening / reading file system entries that abstracts normal file access in order
|
@@ -50,6 +51,11 @@ module Etna
|
|
50
51
|
::FileUtils.mv(src, dest)
|
51
52
|
end
|
52
53
|
|
54
|
+
def stat(src)
|
55
|
+
raise "stat not supported by #{self.class.name}" unless self.class == Filesystem
|
56
|
+
::File.stat(src)
|
57
|
+
end
|
58
|
+
|
53
59
|
class EmptyIO < StringIO
|
54
60
|
def write(*args)
|
55
61
|
# Do nothing -- always leave empty
|
@@ -369,7 +375,120 @@ module Etna
|
|
369
375
|
end
|
370
376
|
end
|
371
377
|
|
378
|
+
class SftpFilesystem < Filesystem
|
379
|
+
include WithPipeConsumer
|
380
|
+
|
381
|
+
class SftpFile
|
382
|
+
attr_reader :size, :name
|
383
|
+
|
384
|
+
def initialize(metadata)
|
385
|
+
@metadata_parts = metadata.split(" ")
|
386
|
+
@size = @metadata_parts[4].to_i
|
387
|
+
@perms = @metadata_parts.first
|
388
|
+
@name = @metadata_parts[8]
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
def initialize(host:, username:, password: nil, port: 22, **args)
|
393
|
+
@username = username
|
394
|
+
@password = password
|
395
|
+
@host = host
|
396
|
+
@port = port
|
397
|
+
|
398
|
+
@dir_listings = {}
|
399
|
+
end
|
400
|
+
|
401
|
+
def url(src)
|
402
|
+
"sftp://#{@host}/#{src}"
|
403
|
+
end
|
404
|
+
|
405
|
+
def authn
|
406
|
+
"#{@username}:#{@password}"
|
407
|
+
end
|
408
|
+
|
409
|
+
def curl_cmd(path, opts=[])
|
410
|
+
connection = Curl::Easy.new(url(path))
|
411
|
+
connection.http_auth_types = :basic
|
412
|
+
connection.username = @username
|
413
|
+
connection.password = @password
|
414
|
+
|
415
|
+
connection
|
416
|
+
end
|
417
|
+
|
418
|
+
def sftp_file_from_path(src)
|
419
|
+
file = ls(::File.dirname(src)).split("\n").map do |listing|
|
420
|
+
SftpFile.new(listing)
|
421
|
+
end.select do |file|
|
422
|
+
file.name == ::File.basename(src)
|
423
|
+
end
|
424
|
+
|
425
|
+
raise "#{src} not found" if file.empty?
|
426
|
+
|
427
|
+
file.first
|
428
|
+
end
|
429
|
+
|
430
|
+
def mkcommand(rd, wd, file, opts, size_hint: nil)
|
431
|
+
env = {}
|
432
|
+
cmd = [env, "curl"]
|
433
|
+
|
434
|
+
cmd << "-u"
|
435
|
+
cmd << authn
|
436
|
+
cmd << "-o"
|
437
|
+
cmd << "-"
|
438
|
+
cmd << "-N"
|
439
|
+
cmd << url(file)
|
440
|
+
|
441
|
+
if opts.include?('r')
|
442
|
+
cmd << {out: wd}
|
443
|
+
end
|
444
|
+
|
445
|
+
cmd
|
446
|
+
end
|
447
|
+
|
448
|
+
def with_readable(src, opts = 'r', &block)
|
449
|
+
raise "#{src} does not exist" unless exist?(src)
|
450
|
+
|
451
|
+
sftp_file = sftp_file_from_path(src)
|
452
|
+
|
453
|
+
mkio(src, opts, size_hint: sftp_file.size, &block)
|
454
|
+
end
|
455
|
+
|
456
|
+
def exist?(src)
|
457
|
+
files = ls(::File.dirname(src))
|
458
|
+
files.include?(::File.basename(src))
|
459
|
+
end
|
460
|
+
|
461
|
+
def ls(dir)
|
462
|
+
dir = dir + "/" unless "/" == dir[-1] # Trailing / makes curl list directory
|
463
|
+
|
464
|
+
return @dir_listings[dir] if @dir_listings.has_key?(dir)
|
465
|
+
|
466
|
+
listing = ''
|
467
|
+
connection = curl_cmd(dir)
|
468
|
+
connection.on_body { |data| listing << data; data.size }
|
469
|
+
connection.perform
|
470
|
+
|
471
|
+
@dir_listings[dir] = listing
|
472
|
+
|
473
|
+
listing
|
474
|
+
end
|
475
|
+
|
476
|
+
def stat(src)
|
477
|
+
sftp_file_from_path(src)
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
372
481
|
class Mock < Filesystem
|
482
|
+
class MockStat
|
483
|
+
def initialize(io)
|
484
|
+
@io = io
|
485
|
+
end
|
486
|
+
|
487
|
+
def size
|
488
|
+
@io.respond_to?(:length) ? @io.length : 0
|
489
|
+
end
|
490
|
+
end
|
491
|
+
|
373
492
|
def initialize(&new_io)
|
374
493
|
@files = {}
|
375
494
|
@dirs = {}
|
@@ -438,6 +557,10 @@ module Etna
|
|
438
557
|
def exist?(src)
|
439
558
|
@files.include?(src) || @dirs.include?(src)
|
440
559
|
end
|
560
|
+
|
561
|
+
def stat(src)
|
562
|
+
@files[src].respond_to?(:stat) ? @files[src].stat : MockStat.new(@files[src])
|
563
|
+
end
|
441
564
|
end
|
442
565
|
end
|
443
566
|
end
|
data/lib/etna/logger.rb
CHANGED
data/lib/etna/remote.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require "net/ssh"
|
2
|
+
|
3
|
+
module Etna
|
4
|
+
class RemoteSSH
|
5
|
+
class RemoteSSHError < Exception
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(host:, username:, password: nil, port: 22, root:, **args)
|
9
|
+
@username = username
|
10
|
+
@password = password
|
11
|
+
@host = host
|
12
|
+
@port = port
|
13
|
+
@root = root
|
14
|
+
end
|
15
|
+
|
16
|
+
def ssh
|
17
|
+
@ssh ||= Net::SSH.start(@host, @username, password: @password)
|
18
|
+
end
|
19
|
+
|
20
|
+
def mkdir_p(dir)
|
21
|
+
output = ssh.exec!("mkdir -p #{dir}")
|
22
|
+
|
23
|
+
raise RemoteSSHError.new("Unable to mkdir -p, #{output}") unless 0 == output.exitstatus
|
24
|
+
end
|
25
|
+
|
26
|
+
def lftp_get(username:, password:, host:, remote_filename:, &block)
|
27
|
+
full_local_path = ::File.join(@root, host, remote_filename)
|
28
|
+
full_local_dir = ::File.dirname(full_local_path)
|
29
|
+
mkdir_p(full_local_dir)
|
30
|
+
|
31
|
+
cmd = "lftp sftp://#{username}:#{password}@#{host} -e \"get #{remote_filename} -o #{full_local_path}; bye\""
|
32
|
+
|
33
|
+
output = ssh.exec!(cmd)
|
34
|
+
raise RemoteSSHError.new("LFTP get failure: #{output}") unless 0 == output.exitstatus
|
35
|
+
yield remote_filename if block_given?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/etna/route.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'digest'
|
2
|
+
require 'date'
|
3
|
+
|
1
4
|
module Etna
|
2
5
|
class Route
|
3
6
|
attr_reader :name
|
@@ -58,6 +61,63 @@ module Etna
|
|
58
61
|
end
|
59
62
|
|
60
63
|
def call(app, request)
|
64
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
65
|
+
|
66
|
+
try_yabeda(request) do |tags|
|
67
|
+
Yabeda.etna.visits.increment(tags)
|
68
|
+
end
|
69
|
+
|
70
|
+
begin
|
71
|
+
process_call(app, request)
|
72
|
+
ensure
|
73
|
+
try_yabeda(request) do |tags|
|
74
|
+
dur = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
|
75
|
+
Yabeda.etna.response_time.measure(tags, dur)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def hash_user_email(email)
|
81
|
+
secret = Etna::Application.instance.config(:user_hash_secret) || 'notsosecret'
|
82
|
+
digest = email + secret + Date.today.to_s
|
83
|
+
|
84
|
+
if @name
|
85
|
+
digest += @name.to_s
|
86
|
+
else
|
87
|
+
digest += @route.to_s
|
88
|
+
end
|
89
|
+
|
90
|
+
Digest::MD5.hexdigest(digest)
|
91
|
+
end
|
92
|
+
|
93
|
+
def try_yabeda(request, &block)
|
94
|
+
if @action
|
95
|
+
controller, action = @action.split('#')
|
96
|
+
elsif @name
|
97
|
+
controller = "none"
|
98
|
+
action = @name
|
99
|
+
else
|
100
|
+
controller = "none"
|
101
|
+
action = @route
|
102
|
+
end
|
103
|
+
|
104
|
+
params = request.env['rack.request.params']
|
105
|
+
user = request.env['etna.user']
|
106
|
+
user_hash = user ? hash_user_email(user.email) : 'unknown'
|
107
|
+
project_name = "unknown"
|
108
|
+
|
109
|
+
if params && (params.include?(:project_name) || params.include?('project_name'))
|
110
|
+
project_name = params[:project_name] || params['project_name']
|
111
|
+
end
|
112
|
+
|
113
|
+
begin
|
114
|
+
block.call({ controller: controller, action: action, user_hash: user_hash, project_name: project_name })
|
115
|
+
rescue => e
|
116
|
+
raise e unless Etna::Application.instance.environment == :production
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def process_call(app, request)
|
61
121
|
update_params(request)
|
62
122
|
|
63
123
|
unless authorized?(request)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: etna
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.41
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Saurabh Asthana
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-08-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -94,6 +94,34 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: curb
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: net-ssh
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
97
125
|
description: See summary
|
98
126
|
email: Saurabh.Asthana@ucsf.edu
|
99
127
|
executables:
|
@@ -144,6 +172,7 @@ files:
|
|
144
172
|
- lib/etna/clients/metis/client.rb
|
145
173
|
- lib/etna/clients/metis/models.rb
|
146
174
|
- lib/etna/clients/metis/workflows.rb
|
175
|
+
- lib/etna/clients/metis/workflows/ingest_metis_data_workflow.rb
|
147
176
|
- lib/etna/clients/metis/workflows/metis_download_workflow.rb
|
148
177
|
- lib/etna/clients/metis/workflows/metis_upload_workflow.rb
|
149
178
|
- lib/etna/clients/metis/workflows/sync_metis_data_workflow.rb
|
@@ -171,6 +200,7 @@ files:
|
|
171
200
|
- lib/etna/metrics.rb
|
172
201
|
- lib/etna/multipart_serializable_nested_hash.rb
|
173
202
|
- lib/etna/parse_body.rb
|
203
|
+
- lib/etna/remote.rb
|
174
204
|
- lib/etna/route.rb
|
175
205
|
- lib/etna/server.rb
|
176
206
|
- lib/etna/sign_service.rb
|