aspera-cli 4.11.0 → 4.12.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 +0 -1
- data/CHANGELOG.md +71 -52
- data/CONTRIBUTING.md +31 -6
- data/README.md +404 -259
- data/bin/asession +2 -2
- data/docs/test_env.conf +1 -0
- data/examples/aoc.rb +2 -2
- data/examples/dascli +11 -11
- data/examples/faspex4.rb +7 -7
- data/examples/node.rb +1 -1
- data/examples/proxy.pac +2 -2
- data/examples/server.rb +3 -3
- data/lib/aspera/aoc.rb +105 -40
- data/lib/aspera/cli/extended_value.rb +4 -4
- data/lib/aspera/cli/{formater.rb → formatter.rb} +7 -7
- data/lib/aspera/cli/listener/progress.rb +1 -1
- data/lib/aspera/cli/listener/progress_multi.rb +2 -2
- data/lib/aspera/cli/main.rb +18 -18
- data/lib/aspera/cli/manager.rb +5 -5
- data/lib/aspera/cli/plugin.rb +23 -20
- data/lib/aspera/cli/plugins/aoc.rb +75 -112
- data/lib/aspera/cli/plugins/ats.rb +6 -6
- data/lib/aspera/cli/plugins/config.rb +84 -83
- data/lib/aspera/cli/plugins/cos.rb +1 -1
- data/lib/aspera/cli/plugins/faspex.rb +38 -38
- data/lib/aspera/cli/plugins/faspex5.rb +187 -43
- data/lib/aspera/cli/plugins/node.rb +30 -37
- data/lib/aspera/cli/plugins/orchestrator.rb +7 -4
- data/lib/aspera/cli/plugins/preview.rb +10 -9
- data/lib/aspera/cli/plugins/server.rb +1 -1
- data/lib/aspera/cli/plugins/shares.rb +67 -43
- data/lib/aspera/cli/transfer_agent.rb +16 -16
- data/lib/aspera/cli/version.rb +2 -1
- data/lib/aspera/command_line_builder.rb +70 -66
- data/lib/aspera/cos_node.rb +9 -9
- data/lib/aspera/fasp/agent_base.rb +3 -1
- data/lib/aspera/fasp/agent_connect.rb +23 -23
- data/lib/aspera/fasp/agent_direct.rb +13 -14
- data/lib/aspera/fasp/agent_httpgw.rb +20 -19
- data/lib/aspera/fasp/agent_node.rb +13 -15
- data/lib/aspera/fasp/agent_trsdk.rb +1 -1
- data/lib/aspera/fasp/installation.rb +5 -5
- data/lib/aspera/fasp/listener.rb +1 -1
- data/lib/aspera/fasp/parameters.rb +49 -41
- data/lib/aspera/fasp/parameters.yaml +311 -212
- data/lib/aspera/fasp/resume_policy.rb +2 -2
- data/lib/aspera/fasp/transfer_spec.rb +0 -13
- data/lib/aspera/faspex_gw.rb +80 -161
- data/lib/aspera/faspex_postproc.rb +77 -0
- data/lib/aspera/log.rb +7 -7
- data/lib/aspera/nagios.rb +6 -6
- data/lib/aspera/node.rb +24 -19
- data/lib/aspera/oauth.rb +50 -47
- data/lib/aspera/proxy_auto_config.js +22 -22
- data/lib/aspera/proxy_auto_config.rb +3 -3
- data/lib/aspera/rest.rb +12 -10
- data/lib/aspera/rest_error_analyzer.rb +5 -5
- data/lib/aspera/secret_hider.rb +4 -3
- data/lib/aspera/ssh.rb +4 -4
- data/lib/aspera/sync.rb +37 -36
- data/lib/aspera/web_auth.rb +7 -59
- data/lib/aspera/web_server_simple.rb +76 -0
- data.tar.gz.sig +0 -0
- metadata +6 -4
- metadata.gz.sig +0 -0
@@ -28,14 +28,14 @@ module Aspera
|
|
28
28
|
TMP_DIR_PREFIX = 'prev_tmp'
|
29
29
|
DEFAULT_PREVIEWS_FOLDER = 'previews'
|
30
30
|
AK_MARKER_FILE = '.aspera_access_key'
|
31
|
-
|
31
|
+
PVCL_LOCAL_STORAGE = 'file:///'
|
32
32
|
LOG_LIMITER_SEC = 30.0
|
33
33
|
private_constant :PREV_GEN_TAG,
|
34
34
|
:PREVIEW_FOLDER_SUFFIX,
|
35
35
|
:PREVIEW_BASENAME,
|
36
36
|
:TMP_DIR_PREFIX,
|
37
37
|
:DEFAULT_PREVIEWS_FOLDER,
|
38
|
-
:
|
38
|
+
:PVCL_LOCAL_STORAGE,
|
39
39
|
:AK_MARKER_FILE,
|
40
40
|
:LOG_LIMITER_SEC
|
41
41
|
|
@@ -69,7 +69,7 @@ module Aspera
|
|
69
69
|
options.add_opt_simple(:skip_folders, 'list of folder to skip')
|
70
70
|
options.add_opt_simple(:case, 'basename of output for for test')
|
71
71
|
options.add_opt_simple(:scan_path, 'subpath in folder id to start scan in (default=/)')
|
72
|
-
options.add_opt_simple(:scan_id, '
|
72
|
+
options.add_opt_simple(:scan_id, 'folder id in storage to start scan in, default is access key main folder id')
|
73
73
|
options.add_opt_boolean(:mimemagic, 'use Mime type detection of gem mimemagic')
|
74
74
|
options.add_opt_list(:overwrite, %i[always never mtime], 'when to overwrite result file')
|
75
75
|
options.add_opt_list(:file_access, %i[local remote], 'how to read and write files in repository')
|
@@ -222,7 +222,7 @@ module Aspera
|
|
222
222
|
# TODO: configurable ? useful ?
|
223
223
|
@default_transfer_spec['remote_host'] = @transfer_server_address
|
224
224
|
end
|
225
|
-
|
225
|
+
t_spec = @default_transfer_spec.merge({
|
226
226
|
'direction' => direction,
|
227
227
|
'paths' => [{'source' => source_filename}],
|
228
228
|
'tags' => {
|
@@ -233,9 +233,9 @@ module Aspera
|
|
233
233
|
'file_id' => folder_id }}}
|
234
234
|
})
|
235
235
|
# force destination
|
236
|
-
#
|
236
|
+
# t_spec['destination_root']=destination
|
237
237
|
transfer.option_transfer_spec_deep_merge({'destination_root' => destination})
|
238
|
-
Main.result_transfer(transfer.start(
|
238
|
+
Main.result_transfer(transfer.start(t_spec))
|
239
239
|
end
|
240
240
|
|
241
241
|
def get_infos_local(gen_infos, entry)
|
@@ -437,7 +437,7 @@ module Aspera
|
|
437
437
|
raise 'only local storage allowed in this mode' unless @access_key_self['storage']['type'].eql?('local')
|
438
438
|
@local_storage_root = @access_key_self['storage']['path']
|
439
439
|
# TODO: option to override @local_storage_root='xxx'
|
440
|
-
@local_storage_root = @local_storage_root[
|
440
|
+
@local_storage_root = @local_storage_root[PVCL_LOCAL_STORAGE.length..-1] if @local_storage_root.start_with?(PVCL_LOCAL_STORAGE)
|
441
441
|
# TODO: windows could have "C:" ?
|
442
442
|
raise "not local storage: #{@local_storage_root}" unless @local_storage_root.start_with?('/')
|
443
443
|
raise CliError, "Local storage root folder #{@local_storage_root} does not exist." unless File.directory?(@local_storage_root)
|
@@ -456,6 +456,8 @@ module Aspera
|
|
456
456
|
end
|
457
457
|
end
|
458
458
|
Aspera::Preview::FileTypes.instance.use_mimemagic = options.get_option(:mimemagic, is_type: :mandatory)
|
459
|
+
# check tools that are anyway required for all cases
|
460
|
+
Aspera::Preview::Utils.check_tools(@skip_types)
|
459
461
|
case command
|
460
462
|
when :scan
|
461
463
|
scan_path = options.get_option(:scan_path)
|
@@ -490,8 +492,7 @@ module Aspera
|
|
490
492
|
send("process_#{command}", iteration_persistency)
|
491
493
|
return Main.result_status("#{command} finished")
|
492
494
|
when :check
|
493
|
-
|
494
|
-
return Main.result_status('tools validated')
|
495
|
+
return Main.result_status('Tools validated')
|
495
496
|
when :test
|
496
497
|
format = options.get_next_argument('format', expected: Aspera::Preview::Generator::PREVIEW_FORMATS)
|
497
498
|
source = options.get_next_argument('source file')
|
@@ -129,7 +129,7 @@ module Aspera
|
|
129
129
|
# actions without ascmd
|
130
130
|
BASE_ACTIONS = %i[health].concat(TRANSFER_COMMANDS).freeze
|
131
131
|
# all actions
|
132
|
-
ACTIONS = [
|
132
|
+
ACTIONS = [BASE_ACTIONS, Aspera::AsCmd::OPERATIONS, ASCMD_ALIASES.keys].flatten.freeze
|
133
133
|
|
134
134
|
def execute_action
|
135
135
|
server_transfer_spec = options_to_base_transfer_spec
|
@@ -5,6 +5,7 @@ require 'aspera/cli/plugins/node'
|
|
5
5
|
module Aspera
|
6
6
|
module Cli
|
7
7
|
module Plugins
|
8
|
+
# Plugin for Aspera Shares v1
|
8
9
|
class Shares < Aspera::Cli::BasicAuthPlugin
|
9
10
|
class << self
|
10
11
|
def detect(base_url)
|
@@ -23,9 +24,12 @@ module Aspera
|
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
def initialize(env)
|
28
|
+
super(env)
|
29
|
+
options.add_opt_list(:type, %i[any local ldap saml], 'Type of user/group for operations')
|
30
|
+
options.set_option(:type, :any)
|
31
|
+
options.parse_options!
|
32
|
+
end
|
29
33
|
|
30
34
|
SAML_IMPORT_MANDATORY = %w[id name_id].freeze
|
31
35
|
SAML_IMPORT_ALLOWED = %w[email given_name surname].concat(SAML_IMPORT_MANDATORY).freeze
|
@@ -52,58 +56,78 @@ module Aspera
|
|
52
56
|
return nagios.result
|
53
57
|
when :repository
|
54
58
|
api_shares_node = basic_auth_api('node_api')
|
55
|
-
|
56
|
-
|
57
|
-
when *Node::COMMANDS_SHARES then Node.new(@agents.merge(skip_basic_auth_options: true, node_api: api_shares_node)).execute_action(command)
|
58
|
-
else raise "INTERNAL ERROR, unknown command: [#{command}]"
|
59
|
-
end
|
59
|
+
repo_command = options.get_next_command(Node::COMMANDS_SHARES)
|
60
|
+
return Node.new(@agents.merge(skip_basic_auth_options: true, node_api: api_shares_node)).execute_action(repo_command)
|
60
61
|
when :admin
|
61
62
|
api_shares_admin = basic_auth_api('api/v1')
|
62
|
-
|
63
|
-
case
|
64
|
-
when :
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
63
|
+
admin_command = options.get_next_command(%i[user group share node])
|
64
|
+
case admin_command
|
65
|
+
when :node
|
66
|
+
return entity_action(api_shares_admin, 'data/nodes')
|
67
|
+
when :user, :group
|
68
|
+
entity_type = admin_command
|
69
|
+
entities_location = options.get_option(:type, is_type: :mandatory)
|
70
|
+
entities_path = "data/#{entities_location}_#{entity_type}s"
|
71
|
+
entity_action = nil
|
72
|
+
case entities_location
|
73
|
+
when :any
|
74
|
+
entities_path = "data/#{entity_type}s"
|
75
|
+
entity_action = %i[list show delete share_permissions app_authorizations].freeze
|
76
|
+
when :local
|
77
|
+
entity_action = %i[list show create modify delete].freeze
|
78
|
+
when :ldap
|
79
|
+
entity_action = %i[add].freeze
|
80
|
+
when :saml
|
81
|
+
entity_action = %i[import].freeze
|
82
|
+
end
|
83
|
+
entity_command = options.get_next_command(entity_action)
|
84
|
+
entity_path = "#{entities_path}/#{instance_identifier}" if %i[app_authorizations share_permissions].include?(entity_command)
|
85
|
+
case entity_command
|
86
|
+
when :list, :show, :create, :delete, :modify
|
87
|
+
display_fields = entity_type.eql?(:user) ? %w[id username first_name last_name email] : nil
|
88
|
+
display_fields.push(:directory_user) if entity_type.eql?(:user) && entities_location.eql?(:any)
|
89
|
+
return entity_command(entity_command, api_shares_admin, entities_path, display_fields: display_fields)
|
70
90
|
when :app_authorizations
|
71
|
-
|
91
|
+
case options.get_next_command(%i[modify show])
|
92
|
+
when :show
|
93
|
+
return {type: :single_object, data: api_shares_admin.read("#{entity_path}/app_authorizations")[:data]}
|
94
|
+
when :modify
|
95
|
+
parameters = options.get_option(:value, is_type: :mandatory)
|
96
|
+
return {type: :single_object, data: api_shares_admin.update("#{entity_path}/app_authorizations", parameters)[:data]}
|
97
|
+
end
|
72
98
|
when :share_permissions
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
99
|
+
case options.get_next_command(%i[list show])
|
100
|
+
when :list
|
101
|
+
return {type: :object_list, data: api_shares_admin.read("#{entity_path}/share_permissions")[:data]}
|
102
|
+
when :show
|
103
|
+
return {type: :single_object, data: api_shares_admin.read("#{entity_path}/share_permissions/#{instance_identifier}")[:data]}
|
104
|
+
end
|
105
|
+
when :import
|
78
106
|
parameters = options.get_option(:value, is_type: :mandatory)
|
79
|
-
return do_bulk_operation(parameters, 'created') do |
|
80
|
-
|
81
|
-
raise 'expecting Hash' unless
|
82
|
-
SAML_IMPORT_MANDATORY.each{|p|raise "missing mandatory field: #{p}" if
|
83
|
-
|
107
|
+
return do_bulk_operation(parameters, 'created') do |entity_parameters|
|
108
|
+
entity_parameters = entity_parameters.transform_keys{|k|k.gsub(/\s+/, '_').downcase}
|
109
|
+
raise 'expecting Hash' unless entity_parameters.is_a?(Hash)
|
110
|
+
SAML_IMPORT_MANDATORY.each{|p|raise "missing mandatory field: #{p}" if entity_parameters[p].nil?}
|
111
|
+
entity_parameters.each_key do |p|
|
84
112
|
raise "unsupported field: #{p}, use: #{SAML_IMPORT_ALLOWED.join(',')}" unless SAML_IMPORT_ALLOWED.include?(p)
|
85
113
|
end
|
86
|
-
api_shares_admin.create(
|
114
|
+
api_shares_admin.create("#{entities_path}/import", entity_parameters)[:data]
|
87
115
|
end
|
88
|
-
when :
|
116
|
+
when :add
|
89
117
|
parameters = options.get_option(:value)
|
90
|
-
return do_bulk_operation(parameters, 'created') do |
|
91
|
-
raise "expecting string (
|
92
|
-
api_shares_admin.create(
|
118
|
+
return do_bulk_operation(parameters, 'created') do |entity_name|
|
119
|
+
raise "expecting string (name), have #{entity_name.class}" unless entity_name.is_a?(String)
|
120
|
+
api_shares_admin.create(entities_path, {entity_type=>entity_name})[:data]
|
93
121
|
end
|
94
122
|
end
|
95
123
|
when :share
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
# share_name = options.get_next_argument('share name')
|
104
|
-
# share_id = all_shares.find{|s| s['name'].eql?(share_name)}['id']
|
105
|
-
# raise "NOT IMPLEMENTED: #{share_name} #{share_id}"
|
106
|
-
return {type: :object_list, data: api_shares_admin.read("data/shares/#{share_id}/user_permissions")[:data]}
|
124
|
+
share_command = options.get_next_command(%i[user_permissions group_permissions].concat(Plugin::ALL_OPS))
|
125
|
+
case share_command
|
126
|
+
when *Plugin::ALL_OPS
|
127
|
+
return entity_command(share_command, api_shares_admin, 'data/shares')
|
128
|
+
# return {type: :object_list, data: all_shares, fields: %w[id name status status_message]}
|
129
|
+
when :user_permissions, :group_permissions
|
130
|
+
return entity_action(api_shares_admin, "data/shares/#{instance_identifier}/#{share_command}")
|
107
131
|
end
|
108
132
|
end
|
109
133
|
end
|
@@ -25,7 +25,7 @@ module Aspera
|
|
25
25
|
|
26
26
|
<%=ts.to_yaml%>
|
27
27
|
END_OF_TEMPLATE
|
28
|
-
# % (
|
28
|
+
# % (formatting bug in eclipse)
|
29
29
|
private_constant :FILE_LIST_FROM_ARGS,
|
30
30
|
:FILE_LIST_FROM_TRANSFER_SPEC,
|
31
31
|
:FILE_LIST_OPTIONS,
|
@@ -42,8 +42,6 @@ module Aspera
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
-
attr_accessor :token_regenerator
|
46
|
-
|
47
45
|
# @param env external objects: option manager, config file manager
|
48
46
|
def initialize(opt_mgr, config)
|
49
47
|
@opt_mgr = opt_mgr
|
@@ -55,13 +53,10 @@ module Aspera
|
|
55
53
|
@progress_listener = Listener::ProgressMulti.new
|
56
54
|
# source/destination pair, like "paths" of transfer spec
|
57
55
|
@transfer_paths = nil
|
58
|
-
# only used with agent "direct" allows to regenerate the token if it is expired
|
59
|
-
@token_regenerator = nil
|
60
56
|
@opt_mgr.set_obj_attr(:ts, self, :option_transfer_spec)
|
61
57
|
@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
|
63
|
-
@opt_mgr.add_opt_simple(:sources, "How list of
|
64
|
-
@opt_mgr.add_opt_simple(:ascp_opts, 'Options for ascp in its native format')
|
58
|
+
@opt_mgr.add_opt_simple(:to_folder, 'Destination folder for transferred files')
|
59
|
+
@opt_mgr.add_opt_simple(:sources, "How list of transferred files is provided (#{FILE_LIST_OPTIONS.join(',')})")
|
65
60
|
@opt_mgr.add_opt_list(:src_type, %i[list pair], 'Type of file list')
|
66
61
|
@opt_mgr.add_opt_list(:transfer, TRANSFER_AGENTS, 'Type of transfer agent')
|
67
62
|
@opt_mgr.add_opt_simple(:transfer_info, 'Parameters for transfer agent')
|
@@ -70,7 +65,6 @@ module Aspera
|
|
70
65
|
@opt_mgr.set_option(:src_type, :list)
|
71
66
|
@opt_mgr.set_option(:progress, :native) # use native ascp progress bar as it is more reliable
|
72
67
|
@opt_mgr.parse_options!
|
73
|
-
Fasp::TransferSpec.ascp_opts_to_ts(@transfer_spec_cmdline, @opt_mgr.get_option(:ascp_opts))
|
74
68
|
end
|
75
69
|
|
76
70
|
def option_transfer_spec; @transfer_spec_cmdline; end
|
@@ -135,9 +129,15 @@ module Aspera
|
|
135
129
|
return dest_folder
|
136
130
|
end
|
137
131
|
|
138
|
-
|
132
|
+
def source_list
|
133
|
+
return ts_source_paths.map do |i|
|
134
|
+
i['source']
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# This is how the list of files to be transferred is specified
|
139
139
|
# get paths suitable for transfer spec from command line
|
140
|
-
# @return {source: (mandatory), destination: (optional)}
|
140
|
+
# @return [Hash] {source: (mandatory), destination: (optional)}
|
141
141
|
# computation is done only once, cache is kept in @transfer_paths
|
142
142
|
def ts_source_paths
|
143
143
|
# return cache if set
|
@@ -157,7 +157,7 @@ module Aspera
|
|
157
157
|
Log.log.debug('assume list provided in transfer spec')
|
158
158
|
special_case_direct_with_list =
|
159
159
|
@opt_mgr.get_option(:transfer, is_type: :mandatory).eql?(:direct) &&
|
160
|
-
Fasp::Parameters.ts_has_ascp_file_list(@transfer_spec_cmdline)
|
160
|
+
Fasp::Parameters.ts_has_ascp_file_list(@transfer_spec_cmdline, @opt_mgr.get_option(:transfer_info))
|
161
161
|
raise CliBadArgument, 'transfer spec on command line must have sources' if @transfer_paths.nil? && !special_case_direct_with_list
|
162
162
|
# here we assume check of sources is made in transfer agent
|
163
163
|
return @transfer_paths
|
@@ -185,8 +185,9 @@ module Aspera
|
|
185
185
|
end
|
186
186
|
|
187
187
|
# start a transfer and wait for completion, plugins shall use this method
|
188
|
-
# @param transfer_spec
|
189
|
-
|
188
|
+
# @param transfer_spec [Hash]
|
189
|
+
# @param rest_token [Rest] if oauth token regeneration supported
|
190
|
+
def start(transfer_spec, rest_token: nil)
|
190
191
|
# check parameters
|
191
192
|
raise 'transfer_spec must be hash' unless transfer_spec.is_a?(Hash)
|
192
193
|
# process :src option
|
@@ -216,8 +217,7 @@ module Aspera
|
|
216
217
|
# create transfer agent
|
217
218
|
set_agent_by_options
|
218
219
|
Log.log.debug{"transfer agent is a #{@agent.class}"}
|
219
|
-
@agent.
|
220
|
-
@agent.start_transfer(transfer_spec)
|
220
|
+
@agent.start_transfer(transfer_spec, token_regenerator: rest_token)
|
221
221
|
# list of : :success or error message
|
222
222
|
result = @agent.wait_for_transfers_completion
|
223
223
|
@progress_listener.reset
|
data/lib/aspera/cli/version.rb
CHANGED
@@ -6,8 +6,14 @@ module Aspera
|
|
6
6
|
# process_param is called repeatedly with all known parameters
|
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
|
-
# parameter with
|
10
|
-
|
9
|
+
# parameter with one of those tags is a command line option with --
|
10
|
+
CLI_OPTION_TYPE_SWITCH = %i[opt_without_arg opt_with_arg].freeze
|
11
|
+
CLI_OPTION_TYPES = %i[special ignore envvar].concat(CLI_OPTION_TYPE_SWITCH).freeze
|
12
|
+
OPTIONS_KEYS = %i[desc accepted_types default enum agents required cli ts].freeze
|
13
|
+
CLI_KEYS = %i[type switch convert variable].freeze
|
14
|
+
|
15
|
+
private_constant :CLI_OPTION_TYPE_SWITCH, :OPTIONS_KEYS, :CLI_KEYS
|
16
|
+
|
11
17
|
class << self
|
12
18
|
# transform yes/no to true/false
|
13
19
|
def yes_to_true(value)
|
@@ -19,36 +25,33 @@ module Aspera
|
|
19
25
|
end
|
20
26
|
|
21
27
|
# Called by provider of definition before constructor of this class so that params_definition has all mandatory fields
|
22
|
-
def normalize_description(
|
23
|
-
|
24
|
-
raise "Expecting Hash, but have #{options.class} in #{
|
25
|
-
|
26
|
-
|
28
|
+
def normalize_description(full_description)
|
29
|
+
full_description.each do |name, options|
|
30
|
+
raise "Expecting Hash, but have #{options.class} in #{name}" unless options.is_a?(Hash)
|
31
|
+
unsupported_keys = options.keys - OPTIONS_KEYS
|
32
|
+
raise "Unsupported definition keys: #{unsupported_keys}" unless unsupported_keys.empty?
|
33
|
+
raise "Missing key: cli for #{name}" unless options.key?(:cli)
|
34
|
+
raise 'Key: cli must be Hash' unless options[:cli].is_a?(Hash)
|
35
|
+
raise 'Missing key: cli.type' unless options[:cli].key?(:type)
|
36
|
+
raise "Unsupported processing type for #{name}: #{options[:cli][:type]}" unless CLI_OPTION_TYPES.include?(options[:cli][:type])
|
37
|
+
# by default : optional
|
27
38
|
options[:mandatory] ||= false
|
28
39
|
options[:desc] ||= ''
|
40
|
+
cli = options[:cli]
|
41
|
+
unsupported_cli_keys = cli.keys - CLI_KEYS
|
42
|
+
raise "Unsupported cli keys: #{unsupported_cli_keys}" unless unsupported_cli_keys.empty?
|
29
43
|
# by default : string, unless it's without arg
|
30
|
-
|
31
|
-
options[:accepted_types] = options[:cltype].eql?(:opt_without_arg) ? :bool : :string
|
32
|
-
end
|
44
|
+
options[:accepted_types] ||= options[:cli][:type].eql?(:opt_without_arg) ? :bool : :string
|
33
45
|
# single type is placed in array
|
34
46
|
options[:accepted_types] = [options[:accepted_types]] unless options[:accepted_types].is_a?(Array)
|
35
47
|
# add default switch name if not present
|
36
|
-
if !
|
37
|
-
|
48
|
+
if !cli.key?(:switch) && cli.key?(:type) && CLI_OPTION_TYPE_SWITCH.include?(cli[:type])
|
49
|
+
cli[:switch] = '--' + name.to_s.tr('_', '-')
|
38
50
|
end
|
39
51
|
end
|
40
52
|
end
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
|
45
|
-
# clvarname : command line variable name
|
46
|
-
def env_name(_param_name, options)
|
47
|
-
return options[:clvarname]
|
48
53
|
end
|
49
54
|
|
50
|
-
public
|
51
|
-
|
52
55
|
attr_reader :params_definition
|
53
56
|
|
54
57
|
# @param param_hash
|
@@ -60,22 +63,19 @@ module Aspera
|
|
60
63
|
@used_param_names = []
|
61
64
|
end
|
62
65
|
|
63
|
-
def warn_unrecognized_params
|
64
|
-
# warn about non translated arguments
|
65
|
-
@param_hash.each_pair{|key, val|Log.log.warn{"unrecognized parameter: #{key} = \"#{val}\""} if !@used_param_names.include?(key)}
|
66
|
-
end
|
67
|
-
|
68
66
|
# adds keys :env :args with resulting values after processing
|
69
67
|
# warns if some parameters were not used
|
70
68
|
def add_env_args(env, args)
|
71
69
|
Log.log.debug{"ENV=#{@result_env}, ARGS=#{@result_args}"}
|
72
|
-
|
70
|
+
# warn about non translated arguments
|
71
|
+
@param_hash.each_pair{|key, val|Log.log.warn{"unrecognized parameter: #{key} = \"#{val}\""} if !@used_param_names.include?(key)}
|
72
|
+
# set result
|
73
73
|
env.merge!(@result_env)
|
74
74
|
args.push(*@result_args)
|
75
75
|
return nil
|
76
76
|
end
|
77
77
|
|
78
|
-
# add options directly to
|
78
|
+
# add options directly to command line
|
79
79
|
def add_command_line_options(options)
|
80
80
|
return if options.nil?
|
81
81
|
options.each{|o|@result_args.push(o.to_s)}
|
@@ -87,88 +87,92 @@ module Aspera
|
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
|
+
def read_param(name)
|
91
|
+
return process_param(name, read: true)
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
90
96
|
# Process a parameter from transfer specification and generate command line param or env var
|
91
|
-
# @param
|
92
|
-
# @param
|
93
|
-
|
94
|
-
|
95
|
-
options = @params_definition[param_name]
|
97
|
+
# @param name [String] of parameter
|
98
|
+
# @param read [TrueClass,FalseClass] read and return value of parameter instead of normal processing (for special)
|
99
|
+
def process_param(name, read: false)
|
100
|
+
options = @params_definition[name]
|
96
101
|
# should not happen
|
97
102
|
if options.nil?
|
98
|
-
Log.log.warn{"Unknown parameter #{
|
103
|
+
Log.log.warn{"Unknown parameter #{name}"}
|
99
104
|
return
|
100
105
|
end
|
101
|
-
|
106
|
+
processing_type = read ? :get_value : options[:cli][:type]
|
102
107
|
# check mandatory parameter (nil is valid value)
|
103
|
-
raise Fasp::Error, "Missing mandatory parameter: #{
|
104
|
-
parameter_value = @param_hash[
|
105
|
-
|
108
|
+
raise Fasp::Error, "Missing mandatory parameter: #{name}" if options[:mandatory] && !@param_hash.key?(name)
|
109
|
+
parameter_value = @param_hash[name]
|
110
|
+
# no default setting
|
106
111
|
# parameter_value=options[:default] if parameter_value.nil? and options.has_key?(:default)
|
107
|
-
|
108
112
|
# Check parameter type
|
109
|
-
expected_classes = options[:accepted_types].map do |
|
110
|
-
case
|
113
|
+
expected_classes = options[:accepted_types].map do |type_symbol|
|
114
|
+
case type_symbol
|
111
115
|
when :string then String
|
112
116
|
when :array then Array
|
113
117
|
when :hash then Hash
|
114
118
|
when :int then Integer
|
115
119
|
when :bool then [TrueClass, FalseClass]
|
116
|
-
else raise "INTERNAL: unexpected value: #{
|
120
|
+
else raise "INTERNAL: unexpected value: #{type_symbol}"
|
117
121
|
end
|
118
122
|
end.flatten
|
119
|
-
|
123
|
+
# check that value is of expected type
|
124
|
+
raise Fasp::Error, "#{name} is : #{parameter_value.class} (#{parameter_value}), shall be #{options[:accepted_types]}, " \
|
120
125
|
unless parameter_value.nil? || expected_classes.include?(parameter_value.class)
|
121
|
-
|
126
|
+
# special processing will be requested with type get_value
|
127
|
+
@used_param_names.push(name) unless processing_type.eql?(:special)
|
122
128
|
|
123
129
|
# process only non-nil values
|
124
130
|
return nil if parameter_value.nil?
|
125
131
|
|
126
132
|
# check that value is of an accepted type (string, int bool)
|
127
|
-
raise "
|
133
|
+
raise "Enum value #{parameter_value} is not allowed for #{name}" if options.key?(:enum) && !options[:enum].include?(parameter_value)
|
128
134
|
|
129
135
|
# convert some values if value on command line needs processing from value in structure
|
130
|
-
case options[:
|
136
|
+
case options[:cli][:convert]
|
131
137
|
when Hash
|
132
138
|
# translate using conversion table
|
133
|
-
new_value = options[:
|
134
|
-
raise "unsupported value: #{parameter_value}, expect: #{options[:
|
139
|
+
new_value = options[:cli][:convert][parameter_value]
|
140
|
+
raise "unsupported value: #{parameter_value}, expect: #{options[:cli][:convert].keys.join(', ')}" if new_value.nil?
|
135
141
|
parameter_value = new_value
|
136
142
|
when String
|
137
|
-
# :
|
138
|
-
|
139
|
-
|
140
|
-
raise Fasp::Error, "unsupported #{
|
141
|
-
parameter_value =
|
143
|
+
# :convert has name of class and encoding method
|
144
|
+
conversion_class, conversion_method = options[:cli][:convert].split('.')
|
145
|
+
converted_value = Kernel.const_get(conversion_class).send(conversion_method, parameter_value)
|
146
|
+
raise Fasp::Error, "unsupported #{name}: #{parameter_value}" if converted_value.nil?
|
147
|
+
parameter_value = converted_value
|
142
148
|
when NilClass
|
143
|
-
else raise "not expected type for
|
149
|
+
else raise "not expected type for convert #{options[:cli][:convert].class} for #{name}"
|
144
150
|
end
|
145
151
|
|
146
|
-
case
|
147
|
-
when :
|
148
|
-
return
|
149
|
-
when :get_value # just get value
|
152
|
+
case processing_type
|
153
|
+
when :get_value # just get value (deferred)
|
150
154
|
return parameter_value
|
155
|
+
when :ignore, :special # ignore this parameter or process later
|
156
|
+
return
|
151
157
|
when :envvar # set in env var
|
152
|
-
|
153
|
-
@result_env[
|
158
|
+
raise 'error' unless options[:cli].key?(:variable)
|
159
|
+
@result_env[options[:cli][:variable]] = parameter_value
|
154
160
|
when :opt_without_arg # if present and true : just add option without value
|
155
161
|
add_param = false
|
156
162
|
case parameter_value
|
157
163
|
when false then nil # nothing to put on command line, no creation by default
|
158
164
|
when true then add_param = true
|
159
|
-
else raise Fasp::Error, "unsupported #{
|
165
|
+
else raise Fasp::Error, "unsupported #{name}: #{parameter_value}"
|
160
166
|
end
|
161
167
|
add_param = !add_param if options[:add_on_false]
|
162
|
-
add_command_line_options([options[:
|
168
|
+
add_command_line_options([options[:cli][:switch]]) if add_param
|
163
169
|
when :opt_with_arg # transform into command line option with value
|
164
170
|
# parameter_value=parameter_value.to_s if parameter_value.is_a?(Integer)
|
165
171
|
parameter_value = [parameter_value] unless parameter_value.is_a?(Array)
|
166
172
|
# if transfer_spec value is an array, applies option many times
|
167
|
-
parameter_value.each{|v|add_command_line_options([options[:
|
168
|
-
when NilClass
|
169
|
-
Log.log.debug{"Ignoring parameter: #{param_name}"}
|
173
|
+
parameter_value.each{|v|add_command_line_options([options[:cli][:switch], v])}
|
170
174
|
else
|
171
|
-
raise "ERROR: unknown
|
175
|
+
raise "ERROR: unknown option processing type: #{processing_type}/#{processing_type.class}"
|
172
176
|
end
|
173
177
|
end
|
174
178
|
end
|
data/lib/aspera/cos_node.rb
CHANGED
@@ -37,10 +37,10 @@ module Aspera
|
|
37
37
|
not_auth_codes: %w[401 403], # error codes when not authorized
|
38
38
|
headers: {'ibm-service-instance-id' => instance_id},
|
39
39
|
auth: {
|
40
|
-
type:
|
41
|
-
base_url:
|
42
|
-
|
43
|
-
generic:
|
40
|
+
type: :oauth2,
|
41
|
+
base_url: @auth_url,
|
42
|
+
grant_method: :generic,
|
43
|
+
generic: {
|
44
44
|
grant_type: 'urn:ibm:params:oauth:grant-type:apikey',
|
45
45
|
response_type: 'cloud_iam',
|
46
46
|
apikey: @api_key
|
@@ -74,11 +74,11 @@ module Aspera
|
|
74
74
|
def generate_token
|
75
75
|
# OAuth API to get delegated token
|
76
76
|
delegated_oauth = Oauth.new({
|
77
|
-
type:
|
78
|
-
base_url:
|
79
|
-
token_field:
|
80
|
-
|
81
|
-
generic:
|
77
|
+
type: :oauth2,
|
78
|
+
base_url: @auth_url,
|
79
|
+
token_field: TOKEN_FIELD,
|
80
|
+
grant_method: :generic,
|
81
|
+
generic: {
|
82
82
|
grant_type: 'urn:ibm:params:oauth:grant-type:apikey',
|
83
83
|
response_type: 'delegated_refresh_token',
|
84
84
|
apikey: @api_key,
|
@@ -6,6 +6,7 @@ module Aspera
|
|
6
6
|
# sub classes shall implement start_transfer and shutdown
|
7
7
|
class AgentBase
|
8
8
|
# fields description for JSON generation
|
9
|
+
# spellchecker: disable
|
9
10
|
INTEGER_FIELDS = %w[Bytescont FaspFileArgIndex StartByte Rate MinRate Port Priority RateCap MinRateCap TCPPort CreatePolicy TimePolicy
|
10
11
|
DatagramSize XoptFlags VLinkVersion PeerVLinkVersion DSPipelineDepth PeerDSPipelineDepth ReadBlockSize WriteBlockSize
|
11
12
|
ClusterNumNodes ClusterNodeId Size Written Loss FileBytes PreTransferBytes TransferBytes PMTU Elapsedusec ArgScansAttempted
|
@@ -14,6 +15,7 @@ module Aspera
|
|
14
15
|
MoveRange Keepalive TestLogin UseProxy Precalc RTTAutocorrect].freeze
|
15
16
|
EXPECTED_METHODS = %i[text struct enhanced].freeze
|
16
17
|
private_constant :INTEGER_FIELDS, :BOOLEAN_FIELDS, :EXPECTED_METHODS
|
18
|
+
# spellchecker: enable
|
17
19
|
|
18
20
|
class << self
|
19
21
|
# This checks the validity of the value returned by wait_for_transfers_completion
|
@@ -84,7 +86,7 @@ module Aspera
|
|
84
86
|
end
|
85
87
|
|
86
88
|
# the following methods must be implemented by subclass:
|
87
|
-
# start_transfer(transfer_spec) : start
|
89
|
+
# start_transfer(transfer_spec, token_regenerator: nil) : start transfer
|
88
90
|
# wait_for_transfers_completion : wait for termination of all transfers, @return list of : :success or error message
|
89
91
|
# optional: shutdown
|
90
92
|
end
|