aspera-cli 4.9.0 → 4.11.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|