aspera-cli 4.9.0 → 4.11.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
- checksums.yaml.gz.sig +0 -0
- data/BUGS.md +20 -0
- data/CHANGELOG.md +509 -0
- data/CONTRIBUTING.md +118 -0
- data/README.md +1241 -916
- data/bin/ascli +4 -4
- data/bin/asession +11 -11
- data/docs/test_env.conf +32 -21
- data/examples/aoc.rb +4 -4
- data/examples/dascli +16 -9
- data/examples/faspex4.rb +8 -8
- data/examples/node.rb +12 -12
- data/examples/server.rb +10 -10
- data/lib/aspera/aoc.rb +273 -266
- data/lib/aspera/ascmd.rb +56 -54
- data/lib/aspera/ats_api.rb +4 -4
- data/lib/aspera/cli/basic_auth_plugin.rb +15 -12
- data/lib/aspera/cli/extended_value.rb +5 -5
- data/lib/aspera/cli/formater.rb +64 -64
- data/lib/aspera/cli/info.rb +2 -2
- data/lib/aspera/cli/listener/line_dump.rb +1 -1
- data/lib/aspera/cli/listener/logger.rb +1 -1
- data/lib/aspera/cli/listener/progress.rb +5 -6
- data/lib/aspera/cli/listener/progress_multi.rb +14 -19
- data/lib/aspera/cli/main.rb +66 -67
- data/lib/aspera/cli/manager.rb +112 -110
- data/lib/aspera/cli/plugin.rb +57 -36
- data/lib/aspera/cli/plugins/alee.rb +4 -4
- data/lib/aspera/cli/plugins/aoc.rb +309 -670
- data/lib/aspera/cli/plugins/ats.rb +44 -46
- data/lib/aspera/cli/plugins/bss.rb +10 -10
- data/lib/aspera/cli/plugins/config.rb +497 -378
- data/lib/aspera/cli/plugins/console.rb +12 -12
- data/lib/aspera/cli/plugins/cos.rb +18 -20
- data/lib/aspera/cli/plugins/faspex.rb +112 -114
- data/lib/aspera/cli/plugins/faspex5.rb +71 -46
- data/lib/aspera/cli/plugins/node.rb +379 -283
- data/lib/aspera/cli/plugins/orchestrator.rb +46 -46
- data/lib/aspera/cli/plugins/preview.rb +122 -114
- data/lib/aspera/cli/plugins/server.rb +137 -83
- data/lib/aspera/cli/plugins/shares.rb +30 -29
- data/lib/aspera/cli/plugins/sync.rb +13 -33
- data/lib/aspera/cli/transfer_agent.rb +60 -59
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/colors.rb +3 -3
- data/lib/aspera/command_line_builder.rb +27 -27
- data/lib/aspera/cos_node.rb +22 -20
- data/lib/aspera/data_repository.rb +1 -1
- data/lib/aspera/environment.rb +35 -15
- data/lib/aspera/fasp/agent_base.rb +15 -15
- data/lib/aspera/fasp/agent_connect.rb +23 -21
- data/lib/aspera/fasp/agent_direct.rb +66 -64
- data/lib/aspera/fasp/agent_httpgw.rb +141 -78
- data/lib/aspera/fasp/agent_node.rb +23 -21
- data/lib/aspera/fasp/agent_trsdk.rb +20 -20
- data/lib/aspera/fasp/error.rb +3 -2
- data/lib/aspera/fasp/error_info.rb +11 -8
- data/lib/aspera/fasp/installation.rb +79 -79
- data/lib/aspera/fasp/listener.rb +1 -1
- data/lib/aspera/fasp/parameters.rb +86 -71
- data/lib/aspera/fasp/parameters.yaml +7 -4
- data/lib/aspera/fasp/resume_policy.rb +8 -8
- data/lib/aspera/fasp/transfer_spec.rb +35 -2
- data/lib/aspera/fasp/uri.rb +7 -7
- data/lib/aspera/faspex_gw.rb +7 -5
- data/lib/aspera/hash_ext.rb +3 -3
- data/lib/aspera/id_generator.rb +5 -5
- data/lib/aspera/keychain/encrypted_hash.rb +38 -105
- data/lib/aspera/keychain/macos_security.rb +128 -57
- data/lib/aspera/log.rb +7 -7
- data/lib/aspera/nagios.rb +19 -18
- data/lib/aspera/node.rb +209 -35
- data/lib/aspera/oauth.rb +37 -36
- data/lib/aspera/open_application.rb +19 -11
- data/lib/aspera/persistency_action_once.rb +4 -4
- data/lib/aspera/persistency_folder.rb +16 -15
- data/lib/aspera/preview/file_types.rb +8 -8
- data/lib/aspera/preview/generator.rb +67 -67
- data/lib/aspera/preview/utils.rb +27 -27
- data/lib/aspera/proxy_auto_config.js +41 -41
- data/lib/aspera/proxy_auto_config.rb +21 -14
- data/lib/aspera/rest.rb +72 -67
- data/lib/aspera/rest_call_error.rb +2 -1
- data/lib/aspera/rest_error_analyzer.rb +18 -17
- data/lib/aspera/rest_errors_aspera.rb +16 -16
- data/lib/aspera/secret_hider.rb +15 -13
- data/lib/aspera/ssh.rb +11 -10
- data/lib/aspera/sync.rb +158 -44
- data/lib/aspera/temp_file_manager.rb +2 -2
- data/lib/aspera/uri_reader.rb +4 -4
- data/lib/aspera/web_auth.rb +14 -13
- data.tar.gz.sig +0 -0
- metadata +11 -36
- metadata.gz.sig +0 -0
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'aspera/fasp/transfer_spec'
|
4
4
|
require 'aspera/cli/listener/logger'
|
5
5
|
require 'aspera/cli/listener/progress_multi'
|
6
|
+
require 'aspera/cli/info'
|
6
7
|
|
7
8
|
module Aspera
|
8
9
|
module Cli
|
@@ -14,7 +15,7 @@ module Aspera
|
|
14
15
|
FILE_LIST_FROM_ARGS = '@args'
|
15
16
|
# special value for --sources : read file list from transfer spec (--ts)
|
16
17
|
FILE_LIST_FROM_TRANSFER_SPEC = '@ts'
|
17
|
-
FILE_LIST_OPTIONS=[FILE_LIST_FROM_ARGS,FILE_LIST_FROM_TRANSFER_SPEC,'Array'].freeze
|
18
|
+
FILE_LIST_OPTIONS = [FILE_LIST_FROM_ARGS, FILE_LIST_FROM_TRANSFER_SPEC, 'Array'].freeze
|
18
19
|
DEFAULT_TRANSFER_NOTIF_TMPL = <<~END_OF_TEMPLATE
|
19
20
|
From: <%=from_name%> <<%=from_email%>>
|
20
21
|
To: <<%=to%>>
|
@@ -24,8 +25,10 @@ module Aspera
|
|
24
25
|
|
25
26
|
<%=ts.to_yaml%>
|
26
27
|
END_OF_TEMPLATE
|
27
|
-
|
28
|
-
private_constant :FILE_LIST_FROM_ARGS
|
28
|
+
# % (formating bug in eclipse)
|
29
|
+
private_constant :FILE_LIST_FROM_ARGS,
|
30
|
+
:FILE_LIST_FROM_TRANSFER_SPEC,
|
31
|
+
:FILE_LIST_OPTIONS,
|
29
32
|
:DEFAULT_TRANSFER_NOTIF_TMPL
|
30
33
|
TRANSFER_AGENTS = %i[direct node connect httpgw trsdk].freeze
|
31
34
|
|
@@ -39,8 +42,10 @@ module Aspera
|
|
39
42
|
end
|
40
43
|
end
|
41
44
|
|
45
|
+
attr_accessor :token_regenerator
|
46
|
+
|
42
47
|
# @param env external objects: option manager, config file manager
|
43
|
-
def initialize(opt_mgr,config)
|
48
|
+
def initialize(opt_mgr, config)
|
44
49
|
@opt_mgr = opt_mgr
|
45
50
|
@config = config
|
46
51
|
# command line can override transfer spec
|
@@ -50,19 +55,22 @@ module Aspera
|
|
50
55
|
@progress_listener = Listener::ProgressMulti.new
|
51
56
|
# source/destination pair, like "paths" of transfer spec
|
52
57
|
@transfer_paths = nil
|
53
|
-
|
54
|
-
@
|
55
|
-
@opt_mgr.
|
56
|
-
@opt_mgr.add_opt_simple(:
|
57
|
-
@opt_mgr.add_opt_simple(:
|
58
|
-
@opt_mgr.
|
59
|
-
@opt_mgr.
|
60
|
-
@opt_mgr.
|
61
|
-
@opt_mgr.add_opt_list(:
|
62
|
-
@opt_mgr.
|
63
|
-
@opt_mgr.
|
64
|
-
@opt_mgr.set_option(:
|
58
|
+
# only used with agent "direct" allows to regenerate the token if it is expired
|
59
|
+
@token_regenerator = nil
|
60
|
+
@opt_mgr.set_obj_attr(:ts, self, :option_transfer_spec)
|
61
|
+
@opt_mgr.add_opt_simple(:ts, "Override transfer spec values (Hash, e.g. use @json: prefix), current=#{@opt_mgr.get_option(:ts)}")
|
62
|
+
@opt_mgr.add_opt_simple(:to_folder, 'Destination folder for transfered files')
|
63
|
+
@opt_mgr.add_opt_simple(:sources, "How list of transfered files is provided (#{FILE_LIST_OPTIONS.join(',')})")
|
64
|
+
@opt_mgr.add_opt_simple(:ascp_opts, 'Options for ascp in its native format')
|
65
|
+
@opt_mgr.add_opt_list(:src_type, %i[list pair], 'Type of file list')
|
66
|
+
@opt_mgr.add_opt_list(:transfer, TRANSFER_AGENTS, 'Type of transfer agent')
|
67
|
+
@opt_mgr.add_opt_simple(:transfer_info, 'Parameters for transfer agent')
|
68
|
+
@opt_mgr.add_opt_list(:progress, %i[none native multi], 'Type of progress bar')
|
69
|
+
@opt_mgr.set_option(:transfer, :direct)
|
70
|
+
@opt_mgr.set_option(:src_type, :list)
|
71
|
+
@opt_mgr.set_option(:progress, :native) # use native ascp progress bar as it is more reliable
|
65
72
|
@opt_mgr.parse_options!
|
73
|
+
Fasp::TransferSpec.ascp_opts_to_ts(@transfer_spec_cmdline, @opt_mgr.get_option(:ascp_opts))
|
66
74
|
end
|
67
75
|
|
68
76
|
def option_transfer_spec; @transfer_spec_cmdline; end
|
@@ -76,8 +84,8 @@ module Aspera
|
|
76
84
|
@agent = instance
|
77
85
|
@agent.add_listener(Listener::Logger.new)
|
78
86
|
# use local progress bar if asked so, or if native and non local ascp (because only local ascp has native progress bar)
|
79
|
-
if @opt_mgr.get_option(:progress,is_type: :mandatory).eql?(:multi) ||
|
80
|
-
|
87
|
+
if @opt_mgr.get_option(:progress, is_type: :mandatory).eql?(:multi) ||
|
88
|
+
(@opt_mgr.get_option(:progress, is_type: :mandatory).eql?(:native) && !instance.class.to_s.eql?('Aspera::Fasp::AgentDirect'))
|
81
89
|
@agent.add_listener(@progress_listener)
|
82
90
|
end
|
83
91
|
end
|
@@ -85,20 +93,20 @@ module Aspera
|
|
85
93
|
# analyze options and create new agent if not already created or set
|
86
94
|
def set_agent_by_options
|
87
95
|
return nil unless @agent.nil?
|
88
|
-
agent_type = @opt_mgr.get_option(:transfer,is_type: :mandatory)
|
96
|
+
agent_type = @opt_mgr.get_option(:transfer, is_type: :mandatory)
|
89
97
|
# agent plugin is loaded on demand to avoid loading unnecessary dependencies
|
90
98
|
require "aspera/fasp/agent_#{agent_type}"
|
91
99
|
agent_options = @opt_mgr.get_option(:transfer_info)
|
92
|
-
raise CliBadArgument,"the transfer agent configuration shall be Hash, not #{agent_options.class} (#{agent_options}), "\
|
93
|
-
'use either @json:<json> or @preset:<parameter set name>' unless [Hash,NilClass].include?(agent_options.class)
|
100
|
+
raise CliBadArgument, "the transfer agent configuration shall be Hash, not #{agent_options.class} (#{agent_options}), "\
|
101
|
+
'use either @json:<json> or @preset:<parameter set name>' unless [Hash, NilClass].include?(agent_options.class)
|
94
102
|
# special case
|
95
103
|
if agent_type.eql?(:node) && agent_options.nil?
|
96
104
|
param_set_name = @config.get_plugin_default_config_name(:node)
|
97
|
-
raise CliBadArgument,"No default node configured, Please specify --#{:transfer_info.to_s.tr('_','-')}" if param_set_name.nil?
|
105
|
+
raise CliBadArgument, "No default node configured, Please specify --#{:transfer_info.to_s.tr('_', '-')}" if param_set_name.nil?
|
98
106
|
agent_options = @config.preset_by_name(param_set_name)
|
99
107
|
end
|
100
108
|
# special case
|
101
|
-
if agent_type.eql?(:direct) && @opt_mgr.get_option(:progress,is_type: :mandatory).eql?(:native)
|
109
|
+
if agent_type.eql?(:direct) && @opt_mgr.get_option(:progress, is_type: :mandatory).eql?(:native)
|
102
110
|
agent_options = {} if agent_options.nil?
|
103
111
|
agent_options[:quiet] = false
|
104
112
|
end
|
@@ -135,106 +143,99 @@ module Aspera
|
|
135
143
|
# return cache if set
|
136
144
|
return @transfer_paths unless @transfer_paths.nil?
|
137
145
|
# start with lower priority : get paths from transfer spec on command line
|
138
|
-
@transfer_paths = @transfer_spec_cmdline['paths'] if @transfer_spec_cmdline.
|
146
|
+
@transfer_paths = @transfer_spec_cmdline['paths'] if @transfer_spec_cmdline.key?('paths')
|
139
147
|
# is there a source list option ?
|
140
148
|
file_list = @opt_mgr.get_option(:sources)
|
141
149
|
case file_list
|
142
|
-
when nil,FILE_LIST_FROM_ARGS
|
150
|
+
when nil, FILE_LIST_FROM_ARGS
|
143
151
|
Log.log.debug('getting file list as parameters')
|
144
152
|
# get remaining arguments
|
145
|
-
file_list = @opt_mgr.get_next_argument('source file list',expected: :multiple)
|
146
|
-
raise CliBadArgument,'specify at least one file on command line or use '\
|
153
|
+
file_list = @opt_mgr.get_next_argument('source file list', expected: :multiple)
|
154
|
+
raise CliBadArgument, 'specify at least one file on command line or use '\
|
147
155
|
"--sources=#{FILE_LIST_FROM_TRANSFER_SPEC} to use transfer spec" if !file_list.is_a?(Array) || file_list.empty?
|
148
156
|
when FILE_LIST_FROM_TRANSFER_SPEC
|
149
157
|
Log.log.debug('assume list provided in transfer spec')
|
150
158
|
special_case_direct_with_list =
|
151
|
-
@opt_mgr.get_option(:transfer,is_type: :mandatory).eql?(:direct) &&
|
159
|
+
@opt_mgr.get_option(:transfer, is_type: :mandatory).eql?(:direct) &&
|
152
160
|
Fasp::Parameters.ts_has_ascp_file_list(@transfer_spec_cmdline)
|
153
|
-
raise CliBadArgument,'transfer spec on command line must have sources' if @transfer_paths.nil? && !special_case_direct_with_list
|
161
|
+
raise CliBadArgument, 'transfer spec on command line must have sources' if @transfer_paths.nil? && !special_case_direct_with_list
|
154
162
|
# here we assume check of sources is made in transfer agent
|
155
163
|
return @transfer_paths
|
156
164
|
when Array
|
157
165
|
Log.log.debug('getting file list as extended value')
|
158
|
-
raise CliBadArgument,'sources must be a Array of String' if !file_list.reject{|f|f.is_a?(String)}.empty?
|
166
|
+
raise CliBadArgument, 'sources must be a Array of String' if !file_list.reject{|f|f.is_a?(String)}.empty?
|
159
167
|
else
|
160
|
-
raise CliBadArgument,"sources must be a Array, not #{file_list.class}"
|
168
|
+
raise CliBadArgument, "sources must be a Array, not #{file_list.class}"
|
161
169
|
end
|
162
170
|
# here, file_list is an Array or String
|
163
171
|
if !@transfer_paths.nil?
|
164
172
|
Log.log.warn('--sources overrides paths from --ts')
|
165
173
|
end
|
166
|
-
case @opt_mgr.get_option(:src_type,is_type: :mandatory)
|
174
|
+
case @opt_mgr.get_option(:src_type, is_type: :mandatory)
|
167
175
|
when :list
|
168
176
|
# when providing a list, just specify source
|
169
177
|
@transfer_paths = file_list.map{|i|{'source' => i}}
|
170
178
|
when :pair
|
171
|
-
raise CliBadArgument,"When using pair, provide an even number of paths: #{file_list.length}" unless file_list.length.even?
|
172
|
-
@transfer_paths = file_list.each_slice(2).to_a.map{|s,d|{'source' => s,'destination' => d}}
|
179
|
+
raise CliBadArgument, "When using pair, provide an even number of paths: #{file_list.length}" unless file_list.length.even?
|
180
|
+
@transfer_paths = file_list.each_slice(2).to_a.map{|s, d|{'source' => s, 'destination' => d}}
|
173
181
|
else raise 'Unsupported src_type'
|
174
182
|
end
|
175
|
-
Log.log.debug
|
183
|
+
Log.log.debug{"paths=#{@transfer_paths}"}
|
176
184
|
return @transfer_paths
|
177
185
|
end
|
178
186
|
|
179
187
|
# start a transfer and wait for completion, plugins shall use this method
|
180
188
|
# @param transfer_spec
|
181
|
-
|
182
|
-
# tr_opts[:src] specifies how destination_root is set (how transfer spec was generated)
|
183
|
-
# other options are carried to specific agent
|
184
|
-
def start(transfer_spec,tr_opts)
|
189
|
+
def start(transfer_spec)
|
185
190
|
# check parameters
|
186
191
|
raise 'transfer_spec must be hash' unless transfer_spec.is_a?(Hash)
|
187
|
-
raise 'tr_opts must be hash' unless tr_opts.is_a?(Hash)
|
188
192
|
# process :src option
|
189
193
|
case transfer_spec['direction']
|
190
194
|
when Fasp::TransferSpec::DIRECTION_RECEIVE
|
191
195
|
# init default if required in any case
|
192
196
|
@transfer_spec_cmdline['destination_root'] ||= destination_folder(transfer_spec['direction'])
|
193
197
|
when Fasp::TransferSpec::DIRECTION_SEND
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
198
|
+
if transfer_spec.dig('tags', 'aspera', 'node', 'access_key')
|
199
|
+
# gen4
|
200
|
+
@transfer_spec_cmdline.delete('destination_root') if @transfer_spec_cmdline.key?('destination_root_id')
|
201
|
+
elsif transfer_spec.key?('token')
|
202
|
+
# gen3
|
199
203
|
# in that case, destination is set in return by application (API/upload_setup)
|
200
204
|
# but to_folder was used in initial API call
|
201
205
|
@transfer_spec_cmdline.delete('destination_root')
|
202
|
-
when :node_gen4
|
203
|
-
@transfer_spec_cmdline.delete('destination_root') if @transfer_spec_cmdline.has_key?('destination_root_id')
|
204
206
|
else
|
205
|
-
|
207
|
+
# init default if required
|
208
|
+
@transfer_spec_cmdline['destination_root'] ||= destination_folder(transfer_spec['direction'])
|
206
209
|
end
|
207
210
|
end
|
208
|
-
|
209
|
-
# only used here
|
210
|
-
tr_opts.delete(:src)
|
211
|
-
|
212
211
|
# update command line paths, unless destination already has one
|
213
212
|
@transfer_spec_cmdline['paths'] = transfer_spec['paths'] || ts_source_paths
|
214
|
-
|
215
213
|
transfer_spec.merge!(@transfer_spec_cmdline)
|
214
|
+
# remove values that are nil (user wants to delete)
|
215
|
+
transfer_spec.delete_if { |_key, value| value.nil? }
|
216
216
|
# create transfer agent
|
217
217
|
set_agent_by_options
|
218
|
-
Log.log.debug
|
219
|
-
@agent.
|
218
|
+
Log.log.debug{"transfer agent is a #{@agent.class}"}
|
219
|
+
@agent.token_regenerator = @token_regenerator if @agent.respond_to?(:token_regenerator=)
|
220
|
+
@agent.start_transfer(transfer_spec)
|
220
221
|
# list of : :success or error message
|
221
222
|
result = @agent.wait_for_transfers_completion
|
222
223
|
@progress_listener.reset
|
223
224
|
Fasp::AgentBase.validate_status_list(result)
|
224
|
-
send_email_transfer_notification(transfer_spec,result)
|
225
|
+
send_email_transfer_notification(transfer_spec, result)
|
225
226
|
return result
|
226
227
|
end
|
227
228
|
|
228
|
-
def send_email_transfer_notification(transfer_spec,statuses)
|
229
|
+
def send_email_transfer_notification(transfer_spec, statuses)
|
229
230
|
return if @opt_mgr.get_option(:notif_to).nil?
|
230
231
|
global_status = self.class.session_status(statuses)
|
231
232
|
email_vars = {
|
232
233
|
global_transfer_status: global_status,
|
233
|
-
subject: "
|
234
|
+
subject: "#{PROGRAM_NAME} transfer: #{global_status}",
|
234
235
|
body: "Transfer is: #{global_status}",
|
235
236
|
ts: transfer_spec
|
236
237
|
}
|
237
|
-
@config.send_email_template(email_vars
|
238
|
+
@config.send_email_template(email_template_default: DEFAULT_TRANSFER_NOTIF_TMPL, values: email_vars)
|
238
239
|
end
|
239
240
|
|
240
241
|
# shut down if agent requires it
|
data/lib/aspera/cli/version.rb
CHANGED
data/lib/aspera/colors.rb
CHANGED
@@ -5,7 +5,7 @@ class String
|
|
5
5
|
class << self
|
6
6
|
private
|
7
7
|
|
8
|
-
def vtcmd(code);"\e[#{code}m";end
|
8
|
+
def vtcmd(code); "\e[#{code}m"; end
|
9
9
|
end
|
10
10
|
# see https://en.wikipedia.org/wiki/ANSI_escape_code
|
11
11
|
# symbol is the method name added to String
|
@@ -35,11 +35,11 @@ class String
|
|
35
35
|
}.freeze
|
36
36
|
private_constant :VTSTYLES
|
37
37
|
# defines methods to String, one per entry in VTSTYLES
|
38
|
-
VTSTYLES.each do |name,code|
|
38
|
+
VTSTYLES.each do |name, code|
|
39
39
|
if $stderr.tty?
|
40
40
|
begin_seq = vtcmd(code)
|
41
41
|
end_code = 0 # by default reset all
|
42
|
-
if code <= 7 then
|
42
|
+
if code <= 7 then code + 20
|
43
43
|
elsif code <= 37 then 39
|
44
44
|
elsif code <= 47 then 49
|
45
45
|
end
|
@@ -7,8 +7,8 @@ module Aspera
|
|
7
7
|
# add_env_args is called to get resulting param list and env var (also checks that all params were used)
|
8
8
|
class CommandLineBuilder
|
9
9
|
# parameter with onne of those tags is an ascp command line option with --
|
10
|
-
CLTYPE_OPTIONS
|
11
|
-
class<<self
|
10
|
+
CLTYPE_OPTIONS = %i[opt_without_arg opt_with_arg].freeze
|
11
|
+
class << self
|
12
12
|
# transform yes/no to true/false
|
13
13
|
def yes_to_true(value)
|
14
14
|
case value
|
@@ -20,21 +20,21 @@ module Aspera
|
|
20
20
|
|
21
21
|
# Called by provider of definition before constructor of this class so that params_definition has all mandatory fields
|
22
22
|
def normalize_description(d)
|
23
|
-
d.each do |param_name,options|
|
23
|
+
d.each do |param_name, options|
|
24
24
|
raise "Expecting Hash, but have #{options.class} in #{param_name}" unless options.is_a?(Hash)
|
25
|
-
#options[:accepted_types]=:bool if options[:cltype].eql?(:envvar) and !options.has_key?(:accepted_types)
|
25
|
+
# options[:accepted_types]=:bool if options[:cltype].eql?(:envvar) and !options.has_key?(:accepted_types)
|
26
26
|
# by default : not mandatory
|
27
27
|
options[:mandatory] ||= false
|
28
28
|
options[:desc] ||= ''
|
29
29
|
# by default : string, unless it's without arg
|
30
|
-
if !options.
|
30
|
+
if !options.key?(:accepted_types)
|
31
31
|
options[:accepted_types] = options[:cltype].eql?(:opt_without_arg) ? :bool : :string
|
32
32
|
end
|
33
33
|
# single type is placed in array
|
34
34
|
options[:accepted_types] = [options[:accepted_types]] unless options[:accepted_types].is_a?(Array)
|
35
35
|
# add default switch name if not present
|
36
|
-
if !options.
|
37
|
-
options[:clswitch] = '--' + param_name.to_s.tr('_','-')
|
36
|
+
if !options.key?(:clswitch) && options.key?(:cltype) && CLTYPE_OPTIONS.include?(options[:cltype])
|
37
|
+
options[:clswitch] = '--' + param_name.to_s.tr('_', '-')
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
@@ -43,7 +43,7 @@ module Aspera
|
|
43
43
|
private
|
44
44
|
|
45
45
|
# clvarname : command line variable name
|
46
|
-
def env_name(_param_name,options)
|
46
|
+
def env_name(_param_name, options)
|
47
47
|
return options[:clvarname]
|
48
48
|
end
|
49
49
|
|
@@ -52,7 +52,7 @@ module Aspera
|
|
52
52
|
attr_reader :params_definition
|
53
53
|
|
54
54
|
# @param param_hash
|
55
|
-
def initialize(param_hash,params_definition)
|
55
|
+
def initialize(param_hash, params_definition)
|
56
56
|
@param_hash = param_hash # keep reference so that it can be modified by caller before calling `process_params`
|
57
57
|
@params_definition = params_definition
|
58
58
|
@result_env = {}
|
@@ -62,13 +62,13 @@ module Aspera
|
|
62
62
|
|
63
63
|
def warn_unrecognized_params
|
64
64
|
# warn about non translated arguments
|
65
|
-
@param_hash.each_pair{|key,val|Log.log.warn
|
65
|
+
@param_hash.each_pair{|key, val|Log.log.warn{"unrecognized parameter: #{key} = \"#{val}\""} if !@used_param_names.include?(key)}
|
66
66
|
end
|
67
67
|
|
68
68
|
# adds keys :env :args with resulting values after processing
|
69
69
|
# warns if some parameters were not used
|
70
|
-
def add_env_args(env,args)
|
71
|
-
Log.log.debug
|
70
|
+
def add_env_args(env, args)
|
71
|
+
Log.log.debug{"ENV=#{@result_env}, ARGS=#{@result_args}"}
|
72
72
|
warn_unrecognized_params
|
73
73
|
env.merge!(@result_env)
|
74
74
|
args.push(*@result_args)
|
@@ -82,7 +82,7 @@ module Aspera
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def process_params
|
85
|
-
@params_definition.
|
85
|
+
@params_definition.each_key do |k|
|
86
86
|
process_param(k)
|
87
87
|
end
|
88
88
|
end
|
@@ -91,19 +91,19 @@ module Aspera
|
|
91
91
|
# @param param_name : key in transfer spec
|
92
92
|
# @param action : type of processing: ignore getvalue envvar opt_without_arg opt_with_arg defer
|
93
93
|
# @param options : options for type
|
94
|
-
def process_param(param_name,action=nil)
|
94
|
+
def process_param(param_name, action=nil)
|
95
95
|
options = @params_definition[param_name]
|
96
96
|
# should not happen
|
97
97
|
if options.nil?
|
98
|
-
Log.log.warn
|
98
|
+
Log.log.warn{"Unknown parameter #{param_name}"}
|
99
99
|
return
|
100
100
|
end
|
101
101
|
action = options[:cltype] if action.nil?
|
102
102
|
# check mandatory parameter (nil is valid value)
|
103
|
-
raise Fasp::Error, "Missing mandatory parameter: #{param_name}" if options[:mandatory] && !@param_hash.
|
103
|
+
raise Fasp::Error, "Missing mandatory parameter: #{param_name}" if options[:mandatory] && !@param_hash.key?(param_name)
|
104
104
|
parameter_value = @param_hash[param_name]
|
105
105
|
|
106
|
-
#parameter_value=options[:default] if parameter_value.nil? and options.has_key?(:default)
|
106
|
+
# parameter_value=options[:default] if parameter_value.nil? and options.has_key?(:default)
|
107
107
|
|
108
108
|
# Check parameter type
|
109
109
|
expected_classes = options[:accepted_types].map do |s|
|
@@ -112,11 +112,11 @@ module Aspera
|
|
112
112
|
when :array then Array
|
113
113
|
when :hash then Hash
|
114
114
|
when :int then Integer
|
115
|
-
when :bool then [TrueClass,FalseClass]
|
115
|
+
when :bool then [TrueClass, FalseClass]
|
116
116
|
else raise "INTERNAL: unexpected value: #{s}"
|
117
117
|
end
|
118
118
|
end.flatten
|
119
|
-
raise Fasp::Error,"#{param_name} is : #{parameter_value.class} (#{parameter_value}), shall be #{options[:accepted_types]}, " \
|
119
|
+
raise Fasp::Error, "#{param_name} is : #{parameter_value.class} (#{parameter_value}), shall be #{options[:accepted_types]}, " \
|
120
120
|
unless parameter_value.nil? || expected_classes.include?(parameter_value.class)
|
121
121
|
@used_param_names.push(param_name) unless action.eql?(:defer)
|
122
122
|
|
@@ -124,7 +124,7 @@ module Aspera
|
|
124
124
|
return nil if parameter_value.nil?
|
125
125
|
|
126
126
|
# check that value is of an accepted type (string, int bool)
|
127
|
-
raise "Value #{parameter_value} is not allowed for #{param_name}" if options.
|
127
|
+
raise "Value #{parameter_value} is not allowed for #{param_name}" if options.key?(:enum) && !options[:enum].include?(parameter_value)
|
128
128
|
|
129
129
|
# convert some values if value on command line needs processing from value in structure
|
130
130
|
case options[:clconvert]
|
@@ -135,8 +135,8 @@ module Aspera
|
|
135
135
|
parameter_value = new_value
|
136
136
|
when String
|
137
137
|
# :clconvert has name of class and encoding method
|
138
|
-
convclass,convmethod = options[:clconvert].split('.')
|
139
|
-
newvalue = Kernel.const_get(convclass).send(convmethod,parameter_value)
|
138
|
+
convclass, convmethod = options[:clconvert].split('.')
|
139
|
+
newvalue = Kernel.const_get(convclass).send(convmethod, parameter_value)
|
140
140
|
raise Fasp::Error, "unsupported #{param_name}: #{parameter_value}" if newvalue.nil?
|
141
141
|
parameter_value = newvalue
|
142
142
|
when NilClass
|
@@ -144,13 +144,13 @@ module Aspera
|
|
144
144
|
end
|
145
145
|
|
146
146
|
case action
|
147
|
-
when :ignore
|
147
|
+
when :ignore, :defer # ignore this parameter or process later
|
148
148
|
return
|
149
149
|
when :get_value # just get value
|
150
150
|
return parameter_value
|
151
151
|
when :envvar # set in env var
|
152
152
|
# define ascp parameter in env var from transfer spec
|
153
|
-
@result_env[env_name(param_name,options)] = parameter_value
|
153
|
+
@result_env[env_name(param_name, options)] = parameter_value
|
154
154
|
when :opt_without_arg # if present and true : just add option without value
|
155
155
|
add_param = false
|
156
156
|
case parameter_value
|
@@ -161,12 +161,12 @@ module Aspera
|
|
161
161
|
add_param = !add_param if options[:add_on_false]
|
162
162
|
add_command_line_options([options[:clswitch]]) if add_param
|
163
163
|
when :opt_with_arg # transform into command line option with value
|
164
|
-
#parameter_value=parameter_value.to_s if parameter_value.is_a?(Integer)
|
164
|
+
# parameter_value=parameter_value.to_s if parameter_value.is_a?(Integer)
|
165
165
|
parameter_value = [parameter_value] unless parameter_value.is_a?(Array)
|
166
166
|
# if transfer_spec value is an array, applies option many times
|
167
|
-
parameter_value.each{|v|add_command_line_options([options[:clswitch],v])}
|
167
|
+
parameter_value.each{|v|add_command_line_options([options[:clswitch], v])}
|
168
168
|
when NilClass
|
169
|
-
Log.log.debug
|
169
|
+
Log.log.debug{"Ignoring parameter: #{param_name}"}
|
170
170
|
else
|
171
171
|
raise "ERROR: unknown action: #{action}/#{action.class}"
|
172
172
|
end
|
data/lib/aspera/cos_node.rb
CHANGED
@@ -5,19 +5,19 @@ require 'aspera/rest'
|
|
5
5
|
require 'xmlsimple'
|
6
6
|
|
7
7
|
module Aspera
|
8
|
-
class CosNode <
|
8
|
+
class CosNode < Aspera::Node
|
9
9
|
class << self
|
10
|
-
def parameters_from_svc_creds(service_credentials,bucket_region)
|
10
|
+
def parameters_from_svc_creds(service_credentials, bucket_region)
|
11
11
|
# check necessary contents
|
12
12
|
raise 'service_credentials must be a Hash' unless service_credentials.is_a?(Hash)
|
13
13
|
%w[apikey resource_instance_id endpoints].each do |field|
|
14
|
-
raise "service_credentials must have a field: #{field}" unless service_credentials.
|
14
|
+
raise "service_credentials must have a field: #{field}" unless service_credentials.key?(field)
|
15
15
|
end
|
16
|
-
Aspera::Log.dump('service_credentials',service_credentials)
|
16
|
+
Aspera::Log.dump('service_credentials', service_credentials)
|
17
17
|
# read endpoints from service provided in service credentials
|
18
18
|
endpoints = Aspera::Rest.new({base_url: service_credentials['endpoints']}).read('')[:data]
|
19
|
-
Aspera::Log.dump('endpoints',endpoints)
|
20
|
-
storage_endpoint = endpoints.dig('service-endpoints','regional',bucket_region,'public',bucket_region)
|
19
|
+
Aspera::Log.dump('endpoints', endpoints)
|
20
|
+
storage_endpoint = endpoints.dig('service-endpoints', 'regional', bucket_region, 'public', bucket_region)
|
21
21
|
raise "no such region: #{bucket_region}" if storage_endpoint.nil?
|
22
22
|
return {
|
23
23
|
instance_id: service_credentials['resource_instance_id'],
|
@@ -28,8 +28,8 @@ module Aspera
|
|
28
28
|
end
|
29
29
|
IBM_CLOUD_TOKEN_URL = 'https://iam.cloud.ibm.com/identity'
|
30
30
|
TOKEN_FIELD = 'delegated_refresh_token'
|
31
|
-
|
32
|
-
def initialize(bucket_name,storage_endpoint,instance_id,api_key,auth_url=IBM_CLOUD_TOKEN_URL)
|
31
|
+
|
32
|
+
def initialize(bucket_name, storage_endpoint, instance_id, api_key, auth_url= IBM_CLOUD_TOKEN_URL)
|
33
33
|
@auth_url = auth_url
|
34
34
|
@api_key = api_key
|
35
35
|
s3_api = Aspera::Rest.new({
|
@@ -53,18 +53,20 @@ module Aspera
|
|
53
53
|
url_params: {'faspConnectionInfo' => nil}
|
54
54
|
)[:http].body
|
55
55
|
ats_info = XmlSimple.xml_in(xml_result_text, {'ForceArray' => false})
|
56
|
-
Aspera::Log.dump('ats_info',ats_info)
|
57
|
-
|
58
|
-
base_url: ats_info['ATSEndpoint'],
|
59
|
-
auth: {
|
60
|
-
type: :basic,
|
61
|
-
username: ats_info['AccessKey']['Id'],
|
62
|
-
password: ats_info['AccessKey']['Secret']}})
|
63
|
-
# prepare transfer spec addition
|
64
|
-
@add_ts = {'tags' => {'aspera' => {'node' => {'storage_credentials' => {
|
56
|
+
Aspera::Log.dump('ats_info', ats_info)
|
57
|
+
@storage_credentials = {
|
65
58
|
'type' => 'token',
|
66
59
|
'token' => {TOKEN_FIELD => nil}
|
67
|
-
}
|
60
|
+
}
|
61
|
+
super(
|
62
|
+
params: {
|
63
|
+
base_url: ats_info['ATSEndpoint'],
|
64
|
+
auth: {
|
65
|
+
type: :basic,
|
66
|
+
username: ats_info['AccessKey']['Id'],
|
67
|
+
password: ats_info['AccessKey']['Secret']}},
|
68
|
+
add_tspec: {'tags'=>{'aspera'=>{'node'=>{'storage_credentials'=>@storage_credentials}}}})
|
69
|
+
# update storage_credentials AND Rest params
|
68
70
|
generate_token
|
69
71
|
end
|
70
72
|
|
@@ -83,8 +85,8 @@ module Aspera
|
|
83
85
|
receiver_client_ids: 'aspera_ats'
|
84
86
|
}})
|
85
87
|
# get delegated token to be placed in rest call header and in transfer tags
|
86
|
-
@
|
87
|
-
@params[:headers] = {'X-Aspera-Storage-Credentials' => JSON.generate(@
|
88
|
+
@storage_credentials['token'][TOKEN_FIELD] = delegated_oauth.get_authorization.gsub(/^Bearer /, '')
|
89
|
+
@params[:headers] = {'X-Aspera-Storage-Credentials' => JSON.generate(@storage_credentials)}
|
88
90
|
end
|
89
91
|
end
|
90
92
|
end
|
data/lib/aspera/environment.rb
CHANGED
@@ -10,12 +10,16 @@ module Aspera
|
|
10
10
|
OS_X = :osx
|
11
11
|
OS_LINUX = :linux
|
12
12
|
OS_AIX = :aix
|
13
|
-
OS_LIST = [OS_WINDOWS,OS_X,OS_LINUX,OS_AIX].freeze
|
13
|
+
OS_LIST = [OS_WINDOWS, OS_X, OS_LINUX, OS_AIX].freeze
|
14
14
|
CPU_X86_64 = :x86_64
|
15
15
|
CPU_PPC64 = :ppc64
|
16
16
|
CPU_PPC64LE = :ppc64le
|
17
17
|
CPU_S390 = :s390
|
18
|
-
CPU_LIST = [CPU_X86_64,CPU_PPC64,CPU_PPC64LE,CPU_S390].freeze
|
18
|
+
CPU_LIST = [CPU_X86_64, CPU_PPC64, CPU_PPC64LE, CPU_S390].freeze
|
19
|
+
|
20
|
+
BITS_PER_BYTE = 8
|
21
|
+
MEBI = 1024 * 1024
|
22
|
+
BYTES_PER_MEBIBIT = MEBI / BITS_PER_BYTE
|
19
23
|
|
20
24
|
class << self
|
21
25
|
def ruby_version
|
@@ -24,9 +28,9 @@ module Aspera
|
|
24
28
|
|
25
29
|
def os
|
26
30
|
case RbConfig::CONFIG['host_os']
|
27
|
-
when /mswin
|
31
|
+
when /mswin/, /msys/, /mingw/, /cygwin/, /bccwin/, /wince/, /emc/
|
28
32
|
return OS_WINDOWS
|
29
|
-
when /darwin
|
33
|
+
when /darwin/, /mac os/
|
30
34
|
return OS_X
|
31
35
|
when /linux/
|
32
36
|
return OS_LINUX
|
@@ -39,9 +43,9 @@ module Aspera
|
|
39
43
|
|
40
44
|
def cpu
|
41
45
|
case RbConfig::CONFIG['host_cpu']
|
42
|
-
when /x86_64
|
46
|
+
when /x86_64/, /x64/
|
43
47
|
return CPU_X86_64
|
44
|
-
when /powerpc
|
48
|
+
when /powerpc/, /ppc64/
|
45
49
|
return CPU_PPC64LE if os.eql?(OS_LINUX)
|
46
50
|
return CPU_PPC64
|
47
51
|
when /s390/
|
@@ -65,9 +69,9 @@ module Aspera
|
|
65
69
|
# on Windows, the env var %USERPROFILE% provides the path to user's home more reliably than %HOMEDRIVE%%HOMEPATH%
|
66
70
|
# so, tell Ruby the right way
|
67
71
|
def fix_home
|
68
|
-
return unless os.eql?(OS_WINDOWS) && ENV.
|
72
|
+
return unless os.eql?(OS_WINDOWS) && ENV.key?('USERPROFILE') && Dir.exist?(ENV['USERPROFILE'])
|
69
73
|
ENV['HOME'] = ENV['USERPROFILE']
|
70
|
-
Log.log.debug
|
74
|
+
Log.log.debug{"Windows: set home to USERPROFILE: #{ENV['HOME']}"}
|
71
75
|
end
|
72
76
|
|
73
77
|
def empty_binding
|
@@ -76,19 +80,35 @@ module Aspera
|
|
76
80
|
|
77
81
|
# secure execution of Ruby code
|
78
82
|
def secure_eval(code)
|
79
|
-
Kernel.send('lave'.reverse,code,empty_binding, __FILE__, __LINE__)
|
83
|
+
Kernel.send('lave'.reverse, code, empty_binding, __FILE__, __LINE__)
|
80
84
|
end
|
81
85
|
|
82
86
|
# value is provided in block
|
83
|
-
def write_file_restricted(path,force: false)
|
87
|
+
def write_file_restricted(path, force: false)
|
84
88
|
raise 'coding error, missing content block' unless block_given?
|
85
89
|
if force || !File.exist?(path)
|
86
90
|
File.unlink(path) rescue nil # Windows may give error
|
87
|
-
File.write(path,yield)
|
88
|
-
|
91
|
+
File.write(path, yield)
|
92
|
+
restrict_file_access(path)
|
89
93
|
end
|
90
94
|
return path
|
91
95
|
end
|
92
|
-
|
93
|
-
|
94
|
-
|
96
|
+
|
97
|
+
def restrict_file_access(path, mode: nil)
|
98
|
+
if mode.nil?
|
99
|
+
# or FileUtils ?
|
100
|
+
if File.file?(path)
|
101
|
+
mode = 0o600
|
102
|
+
elsif File.directory?(path)
|
103
|
+
mode = 0o700
|
104
|
+
else
|
105
|
+
Log.log.debug{"No restriction can be set for #{path}"}
|
106
|
+
end
|
107
|
+
end
|
108
|
+
File.chmod(mode, path) unless mode.nil?
|
109
|
+
rescue => e
|
110
|
+
Log.log.warn(e.message)
|
111
|
+
end
|
112
|
+
end # self
|
113
|
+
end # Environment
|
114
|
+
end # Aspera
|