aspera-cli 4.4.0 → 4.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2095 -1503
- data/bin/ascli +2 -1
- data/bin/asession +4 -5
- data/docs/test_env.conf +3 -0
- data/examples/aoc.rb +4 -3
- data/examples/faspex4.rb +25 -25
- data/examples/proxy.pac +1 -1
- data/examples/transfer.rb +17 -17
- data/lib/aspera/aoc.rb +238 -185
- data/lib/aspera/ascmd.rb +93 -83
- data/lib/aspera/ats_api.rb +11 -10
- data/lib/aspera/cli/basic_auth_plugin.rb +13 -14
- data/lib/aspera/cli/extended_value.rb +42 -33
- data/lib/aspera/cli/formater.rb +142 -108
- data/lib/aspera/cli/info.rb +17 -0
- data/lib/aspera/cli/listener/line_dump.rb +3 -2
- data/lib/aspera/cli/listener/logger.rb +2 -1
- data/lib/aspera/cli/listener/progress.rb +16 -18
- data/lib/aspera/cli/listener/progress_multi.rb +18 -21
- data/lib/aspera/cli/main.rb +173 -149
- data/lib/aspera/cli/manager.rb +163 -168
- data/lib/aspera/cli/plugin.rb +43 -31
- data/lib/aspera/cli/plugins/alee.rb +6 -6
- data/lib/aspera/cli/plugins/aoc.rb +405 -370
- data/lib/aspera/cli/plugins/ats.rb +86 -79
- data/lib/aspera/cli/plugins/bss.rb +14 -16
- data/lib/aspera/cli/plugins/config.rb +580 -362
- data/lib/aspera/cli/plugins/console.rb +23 -19
- data/lib/aspera/cli/plugins/cos.rb +18 -18
- data/lib/aspera/cli/plugins/faspex.rb +201 -158
- data/lib/aspera/cli/plugins/faspex5.rb +80 -57
- data/lib/aspera/cli/plugins/node.rb +183 -166
- data/lib/aspera/cli/plugins/orchestrator.rb +71 -67
- data/lib/aspera/cli/plugins/preview.rb +92 -96
- data/lib/aspera/cli/plugins/server.rb +79 -75
- data/lib/aspera/cli/plugins/shares.rb +35 -19
- data/lib/aspera/cli/plugins/sync.rb +20 -22
- data/lib/aspera/cli/transfer_agent.rb +76 -113
- data/lib/aspera/cli/version.rb +2 -1
- data/lib/aspera/colors.rb +35 -27
- data/lib/aspera/command_line_builder.rb +48 -34
- data/lib/aspera/cos_node.rb +29 -21
- data/lib/aspera/data_repository.rb +3 -2
- data/lib/aspera/environment.rb +50 -45
- data/lib/aspera/fasp/{manager.rb → agent_base.rb} +28 -25
- data/lib/aspera/fasp/{connect.rb → agent_connect.rb} +52 -43
- data/lib/aspera/fasp/{local.rb → agent_direct.rb} +58 -72
- data/lib/aspera/fasp/{http_gw.rb → agent_httpgw.rb} +37 -43
- data/lib/aspera/fasp/{node.rb → agent_node.rb} +35 -16
- data/lib/aspera/fasp/agent_trsdk.rb +104 -0
- data/lib/aspera/fasp/error.rb +2 -1
- data/lib/aspera/fasp/error_info.rb +68 -52
- data/lib/aspera/fasp/installation.rb +152 -124
- data/lib/aspera/fasp/listener.rb +1 -0
- data/lib/aspera/fasp/parameters.rb +87 -92
- data/lib/aspera/fasp/parameters.yaml +305 -249
- data/lib/aspera/fasp/resume_policy.rb +11 -14
- data/lib/aspera/fasp/transfer_spec.rb +26 -0
- data/lib/aspera/fasp/uri.rb +22 -21
- data/lib/aspera/faspex_gw.rb +55 -89
- data/lib/aspera/hash_ext.rb +4 -3
- data/lib/aspera/id_generator.rb +8 -7
- data/lib/aspera/keychain/encrypted_hash.rb +121 -0
- data/lib/aspera/keychain/macos_security.rb +90 -0
- data/lib/aspera/log.rb +55 -37
- data/lib/aspera/nagios.rb +13 -12
- data/lib/aspera/node.rb +30 -25
- data/lib/aspera/oauth.rb +175 -226
- data/lib/aspera/open_application.rb +4 -3
- data/lib/aspera/persistency_action_once.rb +6 -6
- data/lib/aspera/persistency_folder.rb +5 -9
- data/lib/aspera/preview/file_types.rb +6 -5
- data/lib/aspera/preview/generator.rb +25 -24
- data/lib/aspera/preview/options.rb +16 -14
- data/lib/aspera/preview/utils.rb +98 -98
- data/lib/aspera/{proxy_auto_config.erb.js → proxy_auto_config.js} +23 -31
- data/lib/aspera/proxy_auto_config.rb +111 -20
- data/lib/aspera/rest.rb +154 -135
- data/lib/aspera/rest_call_error.rb +2 -2
- data/lib/aspera/rest_error_analyzer.rb +23 -25
- data/lib/aspera/rest_errors_aspera.rb +15 -14
- data/lib/aspera/ssh.rb +12 -10
- data/lib/aspera/sync.rb +42 -41
- data/lib/aspera/temp_file_manager.rb +18 -14
- data/lib/aspera/timer_limiter.rb +2 -1
- data/lib/aspera/uri_reader.rb +7 -5
- data/lib/aspera/web_auth.rb +79 -76
- metadata +116 -29
- data/docs/Makefile +0 -66
- data/docs/README.erb.md +0 -3973
- data/docs/README.md +0 -13
- data/docs/diagrams.txt +0 -49
- data/docs/doc_tools.rb +0 -58
- data/lib/aspera/api_detector.rb +0 -60
- data/lib/aspera/cli/plugins/shares2.rb +0 -114
- data/lib/aspera/secrets.rb +0 -20
data/lib/aspera/log.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'aspera/colors'
|
|
2
3
|
require 'logger'
|
|
3
4
|
require 'pp'
|
|
@@ -7,32 +8,43 @@ require 'singleton'
|
|
|
7
8
|
module Aspera
|
|
8
9
|
# Singleton object for logging
|
|
9
10
|
class Log
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
# display string for hidden secrets
|
|
12
|
+
HIDDEN_PASSWORD='🔑'
|
|
13
|
+
private_constant :HIDDEN_PASSWORD
|
|
12
14
|
include Singleton
|
|
15
|
+
# class methods
|
|
16
|
+
class << self
|
|
17
|
+
# levels are :debug,:info,:warn,:error,fatal,:unknown
|
|
18
|
+
def levels; Logger::Severity.constants.sort{|a,b|Logger::Severity.const_get(a)<=>Logger::Severity.const_get(b)}.map{|c|c.downcase.to_sym};end
|
|
13
19
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
# levels are :debug,:info,:warn,:error,fatal,:unknown
|
|
17
|
-
def self.levels; Logger::Severity.constants.sort{|a,b|Logger::Severity.const_get(a)<=>Logger::Severity.const_get(b)}.map{|c|c.downcase.to_sym};end
|
|
18
|
-
|
|
19
|
-
# where logs are sent to
|
|
20
|
-
def self.logtypes; [:stderr,:stdout,:syslog];end
|
|
20
|
+
# where logs are sent to
|
|
21
|
+
def logtypes; [:stderr,:stdout,:syslog];end
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
# get the logger object of singleton
|
|
24
|
+
def log; instance.logger;end
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
# dump object in debug mode
|
|
27
|
+
# @param name string or symbol
|
|
28
|
+
# @param format either pp or json format
|
|
29
|
+
def dump(name,object,format=:json)
|
|
30
|
+
log.debug() do
|
|
31
|
+
result=
|
|
32
|
+
case format
|
|
33
|
+
when :json
|
|
34
|
+
JSON.pretty_generate(object) rescue PP.pp(object,'')
|
|
35
|
+
when :ruby
|
|
36
|
+
PP.pp(object,'')
|
|
37
|
+
else
|
|
38
|
+
raise 'wrong parameter, expect pp or json'
|
|
39
|
+
end
|
|
40
|
+
"#{name.to_s.green} (#{format})=\n#{result}"
|
|
41
|
+
end
|
|
33
42
|
end
|
|
34
|
-
|
|
35
|
-
|
|
43
|
+
end # class
|
|
44
|
+
|
|
45
|
+
attr_reader :logger_type, :logger
|
|
46
|
+
attr_writer :program_name
|
|
47
|
+
attr_accessor :log_secrets
|
|
36
48
|
|
|
37
49
|
# set log level of underlying logger given symbol level
|
|
38
50
|
def level=(new_level)
|
|
@@ -44,25 +56,20 @@ module Aspera
|
|
|
44
56
|
Logger::Severity.constants.each do |name|
|
|
45
57
|
return name.downcase.to_sym if @logger.level.eql?(Logger::Severity.const_get(name))
|
|
46
58
|
end
|
|
47
|
-
|
|
59
|
+
# should not happen
|
|
60
|
+
raise "INTERNAL ERROR: unexpected level #{@logger.level}"
|
|
48
61
|
end
|
|
49
62
|
|
|
50
63
|
# change underlying logger, but keep log level
|
|
51
64
|
def logger_type=(new_logtype)
|
|
52
|
-
current_severity_integer
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
else
|
|
56
|
-
Logger::Severity::WARN
|
|
57
|
-
end
|
|
58
|
-
else
|
|
59
|
-
@logger.level
|
|
60
|
-
end
|
|
65
|
+
current_severity_integer=@logger.level unless @logger.nil?
|
|
66
|
+
current_severity_integer=ENV['AS_LOG_LEVEL'] if current_severity_integer.nil? && ENV.has_key?('AS_LOG_LEVEL')
|
|
67
|
+
current_severity_integer=Logger::Severity::WARN if current_severity_integer.nil?
|
|
61
68
|
case new_logtype
|
|
62
69
|
when :stderr
|
|
63
|
-
@logger = Logger.new(
|
|
70
|
+
@logger = Logger.new($stderr)
|
|
64
71
|
when :stdout
|
|
65
|
-
@logger = Logger.new(
|
|
72
|
+
@logger = Logger.new($stdout)
|
|
66
73
|
when :syslog
|
|
67
74
|
require 'syslog/logger'
|
|
68
75
|
@logger = Syslog::Logger.new(@program_name)
|
|
@@ -71,18 +78,29 @@ module Aspera
|
|
|
71
78
|
end
|
|
72
79
|
@logger.level=current_severity_integer
|
|
73
80
|
@logger_type=new_logtype
|
|
81
|
+
original_formatter = @logger.formatter || Logger::Formatter.new
|
|
82
|
+
# update formatter with password hiding, note that @log_secrets may be set AFTER this init is done, so it's done at runtime
|
|
83
|
+
@logger.formatter=lambda do |severity, datetime, progname, msg|
|
|
84
|
+
if msg.is_a?(String) && !@log_secrets
|
|
85
|
+
msg=msg
|
|
86
|
+
.gsub(/(["':][^"]*(password|secret|private_key)[^"]*["']?[=>: ]+")([^"]+)(")/){"#{Regexp.last_match(1)}#{HIDDEN_PASSWORD}#{Regexp.last_match(4)}"}
|
|
87
|
+
.gsub(/("[^"]*(secret)[^"]*"=>{)([^}]+)(})/){"#{Regexp.last_match(1)}#{HIDDEN_PASSWORD}#{Regexp.last_match(4)}"}
|
|
88
|
+
.gsub(/((secrets)={)([^}]+)(})/){"#{Regexp.last_match(1)}#{HIDDEN_PASSWORD}#{Regexp.last_match(4)}"}
|
|
89
|
+
.gsub(/--+BEGIN[A-Z ]+KEY--+.+--+END[A-Z ]+KEY--+/m){HIDDEN_PASSWORD}
|
|
90
|
+
end
|
|
91
|
+
original_formatter.call(severity, datetime, progname, msg)
|
|
92
|
+
end
|
|
74
93
|
end
|
|
75
94
|
|
|
76
|
-
attr_writer :program_name
|
|
77
|
-
|
|
78
95
|
private
|
|
79
96
|
|
|
80
97
|
def initialize
|
|
81
98
|
@logger=nil
|
|
82
99
|
@program_name='aspera'
|
|
83
|
-
|
|
100
|
+
@log_secrets=false
|
|
101
|
+
# this sets @logger and @logger_type (self needed to call method instead of local var)
|
|
84
102
|
self.logger_type=:stderr
|
|
103
|
+
raise 'error logger shall be defined' if @logger.nil?
|
|
85
104
|
end
|
|
86
|
-
|
|
87
105
|
end
|
|
88
106
|
end
|
data/lib/aspera/nagios.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'date'
|
|
2
3
|
|
|
3
4
|
module Aspera
|
|
@@ -5,24 +6,24 @@ module Aspera
|
|
|
5
6
|
# nagios levels
|
|
6
7
|
LEVELS=[:ok,:warning,:critical,:unknown,:dependent]
|
|
7
8
|
ADD_PREFIX='add_'
|
|
8
|
-
# add methods to add nagios error levels, each take component name and message
|
|
9
|
-
LEVELS.each_index do |code|
|
|
10
|
-
name="#{ADD_PREFIX}#{LEVELS[code]}".to_sym
|
|
11
|
-
define_method(name){|comp,msg|@data.push({:code=>code,:comp=>comp,:msg=>msg})}
|
|
12
|
-
public name
|
|
13
|
-
end
|
|
14
9
|
# date offset levels
|
|
15
10
|
DATE_WARN_OFFSET=2
|
|
16
11
|
DATE_CRIT_OFFSET=5
|
|
17
12
|
private_constant :LEVELS,:ADD_PREFIX,:DATE_WARN_OFFSET,:DATE_CRIT_OFFSET
|
|
18
13
|
|
|
14
|
+
# add methods to add nagios error levels, each take component name and message
|
|
15
|
+
LEVELS.each_index do |code|
|
|
16
|
+
name="#{ADD_PREFIX}#{LEVELS[code]}".to_sym
|
|
17
|
+
define_method(name){|comp,msg|@data.push({code: code,comp: comp,msg: msg})}
|
|
18
|
+
end
|
|
19
|
+
|
|
19
20
|
attr_reader :data
|
|
20
21
|
def initialize
|
|
21
22
|
@data=[]
|
|
22
23
|
end
|
|
23
24
|
|
|
24
25
|
# comparte remote time with local time
|
|
25
|
-
def check_time_offset(
|
|
26
|
+
def check_time_offset(remote_date, component)
|
|
26
27
|
# check date if specified : 2015-10-13T07:32:01Z
|
|
27
28
|
rtime = DateTime.strptime(remote_date)
|
|
28
29
|
diff_time = (rtime - DateTime.now).abs
|
|
@@ -38,22 +39,22 @@ module Aspera
|
|
|
38
39
|
end
|
|
39
40
|
end
|
|
40
41
|
|
|
41
|
-
def check_product_version(
|
|
42
|
+
def check_product_version(component, _product, version)
|
|
42
43
|
add_ok(component,"version #{version}")
|
|
43
44
|
# TODO check on database if latest version
|
|
44
45
|
end
|
|
45
46
|
|
|
46
47
|
# translate for display
|
|
47
48
|
def result
|
|
48
|
-
raise
|
|
49
|
-
{:
|
|
49
|
+
raise 'missing result' if @data.empty?
|
|
50
|
+
{type: :object_list,data: @data.map{|i|{'status'=>LEVELS[i[:code]].to_s,'component'=>i[:comp],'message'=>i[:msg]}}}
|
|
50
51
|
end
|
|
51
52
|
|
|
52
53
|
# process results of a analysis and display status and exit with code
|
|
53
54
|
def self.process(data)
|
|
54
|
-
raise
|
|
55
|
+
raise 'INTERNAL ERROR, result must be list and not empty' unless data.is_a?(Array) && !data.empty?
|
|
55
56
|
['status','component','message'].each{|c|raise "INTERNAL ERROR, result must have #{c}" unless data.first.has_key?(c)}
|
|
56
|
-
res_errors = data.
|
|
57
|
+
res_errors = data.reject{|s|s['status'].eql?('ok')}
|
|
57
58
|
# keep only errors in case of problem, other ok are assumed so
|
|
58
59
|
data = res_errors unless res_errors.empty?
|
|
59
60
|
# first is most critical
|
data/lib/aspera/node.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'aspera/fasp/transfer_spec'
|
|
1
3
|
require 'aspera/rest'
|
|
2
4
|
require 'aspera/oauth'
|
|
3
5
|
require 'aspera/log'
|
|
@@ -8,37 +10,40 @@ module Aspera
|
|
|
8
10
|
# Provides additional functions using node API.
|
|
9
11
|
class Node < Rest
|
|
10
12
|
# permissions
|
|
11
|
-
ACCESS_LEVELS
|
|
13
|
+
ACCESS_LEVELS=%w[delete list mkdir preview read rename write].freeze
|
|
14
|
+
# prefix for ruby code for filter
|
|
12
15
|
MATCH_EXEC_PREFIX='exec:'
|
|
13
|
-
# (public) default transfer username for access key based transfers
|
|
14
|
-
ACCESS_KEY_TRANSFER_USER='xfer'
|
|
15
|
-
SSH_PORT_DEFAULT=33001
|
|
16
|
-
UDP_PORT_DEFAULT=33001
|
|
17
16
|
|
|
18
17
|
# register node special token decoder
|
|
19
18
|
Oauth.register_decoder(lambda{|token|JSON.parse(Zlib::Inflate.inflate(Base64.decode64(token)).partition('==SIGNATURE==').first)})
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
class<<self
|
|
21
|
+
def set_ak_basic_token(ts,ak,secret)
|
|
22
|
+
Log.log.warn("Expected transfer user: #{Fasp::TransferSpec::ACCESS_KEY_TRANSFER_USER}, but have #{ts['remote_user']}") unless ts['remote_user'].eql?(Fasp::TransferSpec::ACCESS_KEY_TRANSFER_USER)
|
|
23
|
+
ts['token']="Basic #{Base64.strict_encode64("#{ak}:#{secret}")}"
|
|
24
|
+
end
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
# if prefix: ruby code
|
|
29
|
-
# if filder is nil, then always match
|
|
30
|
-
def self.file_matcher(match_expression)
|
|
31
|
-
match_expression||="#{MATCH_EXEC_PREFIX}true"
|
|
32
|
-
if match_expression.start_with?(MATCH_EXEC_PREFIX)
|
|
33
|
-
return eval "lambda{|f|#{match_expression[MATCH_EXEC_PREFIX.length..-1]}}"
|
|
26
|
+
def empty_binding
|
|
27
|
+
return Kernel.binding
|
|
34
28
|
end
|
|
35
|
-
return lambda{|f|f['name'].match(/#{match_expression}/)}
|
|
36
|
-
end
|
|
37
29
|
|
|
38
|
-
|
|
39
|
-
|
|
30
|
+
# for access keys: provide expression to match entry in folder
|
|
31
|
+
# if no prefix: regex
|
|
32
|
+
# if prefix: ruby code
|
|
33
|
+
# if filder is nil, then always match
|
|
34
|
+
def file_matcher(match_expression)
|
|
35
|
+
match_expression||="#{MATCH_EXEC_PREFIX}true"
|
|
36
|
+
if match_expression.start_with?(MATCH_EXEC_PREFIX)
|
|
37
|
+
return eval("lambda{|f|#{match_expression[MATCH_EXEC_PREFIX.length..-1]}}", empty_binding, __FILE__, __LINE__)
|
|
38
|
+
end
|
|
39
|
+
return lambda{|f|f['name'].match(/#{match_expression}/)}
|
|
40
|
+
end
|
|
40
41
|
end
|
|
41
42
|
|
|
43
|
+
# def initialize(rest_params)
|
|
44
|
+
# super(rest_params)
|
|
45
|
+
# end
|
|
46
|
+
|
|
42
47
|
# recursively crawl in a folder.
|
|
43
48
|
# subfolders a processed if the processing method returns true
|
|
44
49
|
# @param processor must provide a method to process each entry
|
|
@@ -57,13 +62,13 @@ module Aspera
|
|
|
57
62
|
#top_info=read("files/#{opt[:top_file_id]}")[:data]
|
|
58
63
|
folders_to_explore=[{id: opt[:top_file_id], relpath: opt[:top_file_path]}]
|
|
59
64
|
Log.dump(:folders_to_explore,folders_to_explore)
|
|
60
|
-
while !folders_to_explore.empty?
|
|
65
|
+
while !folders_to_explore.empty?
|
|
61
66
|
current_item = folders_to_explore.shift
|
|
62
67
|
Log.log.debug("searching #{current_item[:relpath]}".bg_green)
|
|
63
68
|
# get folder content
|
|
64
69
|
folder_contents = begin
|
|
65
70
|
read("files/#{current_item[:id]}/files")[:data]
|
|
66
|
-
rescue => e
|
|
71
|
+
rescue StandardError => e
|
|
67
72
|
Log.log.warn("#{current_item[:relpath]}: #{e.class} #{e.message}")
|
|
68
73
|
[]
|
|
69
74
|
end
|
|
@@ -72,8 +77,8 @@ module Aspera
|
|
|
72
77
|
relative_path=File.join(current_item[:relpath],entry['name'])
|
|
73
78
|
Log.log.debug("looking #{relative_path}".bg_green)
|
|
74
79
|
# entry type is file, folder or link
|
|
75
|
-
if processor.send(opt[:method],entry,relative_path)
|
|
76
|
-
folders_to_explore.push({:
|
|
80
|
+
if processor.send(opt[:method],entry,relative_path) && entry['type'].eql?('folder')
|
|
81
|
+
folders_to_explore.push({id: entry['id'],relpath: relative_path})
|
|
77
82
|
end
|
|
78
83
|
end
|
|
79
84
|
end
|