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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/BUGS.md +0 -1
  4. data/CHANGELOG.md +71 -52
  5. data/CONTRIBUTING.md +31 -6
  6. data/README.md +404 -259
  7. data/bin/asession +2 -2
  8. data/docs/test_env.conf +1 -0
  9. data/examples/aoc.rb +2 -2
  10. data/examples/dascli +11 -11
  11. data/examples/faspex4.rb +7 -7
  12. data/examples/node.rb +1 -1
  13. data/examples/proxy.pac +2 -2
  14. data/examples/server.rb +3 -3
  15. data/lib/aspera/aoc.rb +105 -40
  16. data/lib/aspera/cli/extended_value.rb +4 -4
  17. data/lib/aspera/cli/{formater.rb → formatter.rb} +7 -7
  18. data/lib/aspera/cli/listener/progress.rb +1 -1
  19. data/lib/aspera/cli/listener/progress_multi.rb +2 -2
  20. data/lib/aspera/cli/main.rb +18 -18
  21. data/lib/aspera/cli/manager.rb +5 -5
  22. data/lib/aspera/cli/plugin.rb +23 -20
  23. data/lib/aspera/cli/plugins/aoc.rb +75 -112
  24. data/lib/aspera/cli/plugins/ats.rb +6 -6
  25. data/lib/aspera/cli/plugins/config.rb +84 -83
  26. data/lib/aspera/cli/plugins/cos.rb +1 -1
  27. data/lib/aspera/cli/plugins/faspex.rb +38 -38
  28. data/lib/aspera/cli/plugins/faspex5.rb +187 -43
  29. data/lib/aspera/cli/plugins/node.rb +30 -37
  30. data/lib/aspera/cli/plugins/orchestrator.rb +7 -4
  31. data/lib/aspera/cli/plugins/preview.rb +10 -9
  32. data/lib/aspera/cli/plugins/server.rb +1 -1
  33. data/lib/aspera/cli/plugins/shares.rb +67 -43
  34. data/lib/aspera/cli/transfer_agent.rb +16 -16
  35. data/lib/aspera/cli/version.rb +2 -1
  36. data/lib/aspera/command_line_builder.rb +70 -66
  37. data/lib/aspera/cos_node.rb +9 -9
  38. data/lib/aspera/fasp/agent_base.rb +3 -1
  39. data/lib/aspera/fasp/agent_connect.rb +23 -23
  40. data/lib/aspera/fasp/agent_direct.rb +13 -14
  41. data/lib/aspera/fasp/agent_httpgw.rb +20 -19
  42. data/lib/aspera/fasp/agent_node.rb +13 -15
  43. data/lib/aspera/fasp/agent_trsdk.rb +1 -1
  44. data/lib/aspera/fasp/installation.rb +5 -5
  45. data/lib/aspera/fasp/listener.rb +1 -1
  46. data/lib/aspera/fasp/parameters.rb +49 -41
  47. data/lib/aspera/fasp/parameters.yaml +311 -212
  48. data/lib/aspera/fasp/resume_policy.rb +2 -2
  49. data/lib/aspera/fasp/transfer_spec.rb +0 -13
  50. data/lib/aspera/faspex_gw.rb +80 -161
  51. data/lib/aspera/faspex_postproc.rb +77 -0
  52. data/lib/aspera/log.rb +7 -7
  53. data/lib/aspera/nagios.rb +6 -6
  54. data/lib/aspera/node.rb +24 -19
  55. data/lib/aspera/oauth.rb +50 -47
  56. data/lib/aspera/proxy_auto_config.js +22 -22
  57. data/lib/aspera/proxy_auto_config.rb +3 -3
  58. data/lib/aspera/rest.rb +12 -10
  59. data/lib/aspera/rest_error_analyzer.rb +5 -5
  60. data/lib/aspera/secret_hider.rb +4 -3
  61. data/lib/aspera/ssh.rb +4 -4
  62. data/lib/aspera/sync.rb +37 -36
  63. data/lib/aspera/web_auth.rb +7 -59
  64. data/lib/aspera/web_server_simple.rb +76 -0
  65. data.tar.gz.sig +0 -0
  66. metadata +6 -4
  67. 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
- LOCAL_STORAGE_PCVL = 'file:///'
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
- :LOCAL_STORAGE_PCVL,
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, 'forder id in storage to start scan in, default is access key main folder 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
- tspec = @default_transfer_spec.merge({
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
- # tspec['destination_root']=destination
236
+ # t_spec['destination_root']=destination
237
237
  transfer.option_transfer_spec_deep_merge({'destination_root' => destination})
238
- Main.result_transfer(transfer.start(tspec))
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[LOCAL_STORAGE_PCVL.length..-1] if @local_storage_root.start_with?(LOCAL_STORAGE_PCVL)
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
- Aspera::Preview::Utils.check_tools(@skip_types)
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 = [].concat(BASE_ACTIONS, Aspera::AsCmd::OPERATIONS, ASCMD_ALIASES.keys).freeze
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
- # def initialize(env)
27
- # super(env)
28
- # end
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
- command = options.get_next_command(Node::COMMANDS_SHARES)
56
- case command
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
- command = options.get_next_command(%i[user share])
63
- case command
64
- when :user
65
- command = options.get_next_command(%i[list app_authorizations share_permissions saml_import ldap_import])
66
- user_id = instance_identifier if %i[app_authorizations share_permissions].include?(command)
67
- case command
68
- when :list
69
- return {type: :object_list, data: api_shares_admin.read('data/users')[:data], fields: %w[id username email directory_user urn]}
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
- return {type: :single_object, data: api_shares_admin.read("data/users/#{user_id}/app_authorizations")[:data]}
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
- # share_name = options.get_next_argument('share name')
74
- # all_shares = api_shares_admin.read('data/shares')[:data]
75
- # share_id = all_shares.find{|s| s['name'].eql?(share_name)}['id']
76
- return {type: :object_list, data: api_shares_admin.read("data/users/#{user_id}/share_permissions")[:data]}
77
- when :saml_import
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 |user_params|
80
- user_params = user_params.transform_keys{|k|k.gsub(/\s+/, '_').downcase}
81
- raise 'expecting Hash' unless user_params.is_a?(Hash)
82
- SAML_IMPORT_MANDATORY.each{|p|raise "missing mandatory field: #{p}" if user_params[p].nil?}
83
- user_params.each_key do |p|
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('data/saml_users/import', user_params)[:data]
114
+ api_shares_admin.create("#{entities_path}/import", entity_parameters)[:data]
87
115
  end
88
- when :ldap_import
116
+ when :add
89
117
  parameters = options.get_option(:value)
90
- return do_bulk_operation(parameters, 'created') do |user_name|
91
- raise "expecting string (user name), have #{user_name.class}" unless user_name.is_a?(String)
92
- api_shares_admin.create('data/ldap_users', {'user'=>user_name})[:data]
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
- command = options.get_next_command(%i[list user_permissions])
97
- share_id = instance_identifier if %i[user_permissions].include?(command)
98
- all_shares = api_shares_admin.read('data/shares')[:data]
99
- case command
100
- when :list
101
- return {type: :object_list, data: all_shares, fields: %w[id name status status_message]}
102
- when :user_permissions
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
- # % (formating bug in eclipse)
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 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')
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
- # This is how the list of files to be transfered is specified
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
- def start(transfer_spec)
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.token_regenerator = @token_regenerator if @agent.respond_to?(:token_regenerator=)
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
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Aspera
4
4
  module Cli
5
- VERSION = '4.11.0'
5
+ # for beta add extension : .beta1
6
+ VERSION = '4.12.0'
6
7
  end
7
8
  end
@@ -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 onne of those tags is an ascp command line option with --
10
- CLTYPE_OPTIONS = %i[opt_without_arg opt_with_arg].freeze
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(d)
23
- d.each do |param_name, options|
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)
26
- # by default : not mandatory
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
- if !options.key?(:accepted_types)
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 !options.key?(:clswitch) && options.key?(:cltype) && CLTYPE_OPTIONS.include?(options[:cltype])
37
- options[:clswitch] = '--' + param_name.to_s.tr('_', '-')
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
- warn_unrecognized_params
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 ascp command line
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 param_name : key in transfer spec
92
- # @param action : type of processing: ignore getvalue envvar opt_without_arg opt_with_arg defer
93
- # @param options : options for type
94
- def process_param(param_name, action=nil)
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 #{param_name}"}
103
+ Log.log.warn{"Unknown parameter #{name}"}
99
104
  return
100
105
  end
101
- action = options[:cltype] if action.nil?
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: #{param_name}" if options[:mandatory] && !@param_hash.key?(param_name)
104
- parameter_value = @param_hash[param_name]
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 |s|
110
- case s
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: #{s}"
120
+ else raise "INTERNAL: unexpected value: #{type_symbol}"
117
121
  end
118
122
  end.flatten
119
- raise Fasp::Error, "#{param_name} is : #{parameter_value.class} (#{parameter_value}), shall be #{options[:accepted_types]}, " \
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
- @used_param_names.push(param_name) unless action.eql?(:defer)
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 "Value #{parameter_value} is not allowed for #{param_name}" if options.key?(:enum) && !options[:enum].include?(parameter_value)
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[:clconvert]
136
+ case options[:cli][:convert]
131
137
  when Hash
132
138
  # translate using conversion table
133
- new_value = options[:clconvert][parameter_value]
134
- raise "unsupported value: #{parameter_value}, expect: #{options[:clconvert].keys.join(', ')}" if new_value.nil?
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
- # :clconvert has name of class and encoding method
138
- convclass, convmethod = options[:clconvert].split('.')
139
- newvalue = Kernel.const_get(convclass).send(convmethod, parameter_value)
140
- raise Fasp::Error, "unsupported #{param_name}: #{parameter_value}" if newvalue.nil?
141
- parameter_value = newvalue
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 clconvert #{options[:clconvert].class} for #{param_name}"
149
+ else raise "not expected type for convert #{options[:cli][:convert].class} for #{name}"
144
150
  end
145
151
 
146
- case action
147
- when :ignore, :defer # ignore this parameter or process later
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
- # define ascp parameter in env var from transfer spec
153
- @result_env[env_name(param_name, options)] = parameter_value
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 #{param_name}: #{parameter_value}"
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[:clswitch]]) if add_param
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[:clswitch], v])}
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 action: #{action}/#{action.class}"
175
+ raise "ERROR: unknown option processing type: #{processing_type}/#{processing_type.class}"
172
176
  end
173
177
  end
174
178
  end
@@ -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: :oauth2,
41
- base_url: @auth_url,
42
- crtype: :generic,
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: :oauth2,
78
- base_url: @auth_url,
79
- token_field: TOKEN_FIELD,
80
- crtype: :generic,
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 and wait for completion
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