aspera-cli 4.16.0 → 4.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +50 -19
  4. data/CONTRIBUTING.md +3 -1
  5. data/README.md +965 -793
  6. data/bin/asession +29 -21
  7. data/lib/aspera/{fasp/agent_alpha.rb → agent/alpha.rb} +26 -25
  8. data/lib/aspera/{fasp/agent_base.rb → agent/base.rb} +15 -12
  9. data/lib/aspera/{fasp/agent_connect.rb → agent/connect.rb} +13 -11
  10. data/lib/aspera/{fasp/agent_direct.rb → agent/direct.rb} +49 -53
  11. data/lib/aspera/{fasp/agent_httpgw.rb → agent/httpgw.rb} +20 -19
  12. data/lib/aspera/{fasp/agent_node.rb → agent/node.rb} +20 -33
  13. data/lib/aspera/{fasp/agent_trsdk.rb → agent/trsdk.rb} +11 -11
  14. data/lib/aspera/api/aoc.rb +586 -0
  15. data/lib/aspera/api/ats.rb +46 -0
  16. data/lib/aspera/api/cos_node.rb +95 -0
  17. data/lib/aspera/api/node.rb +344 -0
  18. data/lib/aspera/ascmd.rb +46 -10
  19. data/lib/aspera/{fasp → ascp}/installation.rb +5 -5
  20. data/lib/aspera/{fasp → ascp}/management.rb +3 -8
  21. data/lib/aspera/{fasp → ascp}/products.rb +1 -1
  22. data/lib/aspera/assert.rb +30 -30
  23. data/lib/aspera/cli/basic_auth_plugin.rb +11 -10
  24. data/lib/aspera/cli/extended_value.rb +1 -1
  25. data/lib/aspera/cli/formatter.rb +13 -13
  26. data/lib/aspera/cli/hints.rb +5 -5
  27. data/lib/aspera/cli/main.rb +35 -28
  28. data/lib/aspera/cli/manager.rb +25 -24
  29. data/lib/aspera/cli/plugin.rb +22 -15
  30. data/lib/aspera/cli/plugin_factory.rb +61 -0
  31. data/lib/aspera/cli/plugins/alee.rb +7 -7
  32. data/lib/aspera/cli/plugins/aoc.rb +83 -77
  33. data/lib/aspera/cli/plugins/ats.rb +32 -33
  34. data/lib/aspera/cli/plugins/bss.rb +3 -4
  35. data/lib/aspera/cli/plugins/config.rb +169 -186
  36. data/lib/aspera/cli/plugins/console.rb +8 -6
  37. data/lib/aspera/cli/plugins/cos.rb +19 -18
  38. data/lib/aspera/cli/plugins/faspex.rb +61 -54
  39. data/lib/aspera/cli/plugins/faspex5.rb +150 -103
  40. data/lib/aspera/cli/plugins/node.rb +68 -73
  41. data/lib/aspera/cli/plugins/orchestrator.rb +34 -44
  42. data/lib/aspera/cli/plugins/preview.rb +31 -31
  43. data/lib/aspera/cli/plugins/server.rb +31 -33
  44. data/lib/aspera/cli/plugins/shares.rb +13 -11
  45. data/lib/aspera/cli/sync_actions.rb +8 -8
  46. data/lib/aspera/cli/transfer_agent.rb +32 -19
  47. data/lib/aspera/cli/transfer_progress.rb +1 -1
  48. data/lib/aspera/cli/version.rb +1 -1
  49. data/lib/aspera/colors.rb +5 -0
  50. data/lib/aspera/command_line_builder.rb +14 -14
  51. data/lib/aspera/coverage.rb +1 -2
  52. data/lib/aspera/data_repository.rb +1 -1
  53. data/lib/aspera/environment.rb +2 -3
  54. data/lib/aspera/faspex_gw.rb +5 -6
  55. data/lib/aspera/faspex_postproc.rb +1 -1
  56. data/lib/aspera/id_generator.rb +2 -2
  57. data/lib/aspera/json_rpc.rb +5 -5
  58. data/lib/aspera/keychain/encrypted_hash.rb +6 -6
  59. data/lib/aspera/keychain/macos_security.rb +27 -22
  60. data/lib/aspera/log.rb +2 -2
  61. data/lib/aspera/nagios.rb +3 -3
  62. data/lib/aspera/node_simulator.rb +5 -6
  63. data/lib/aspera/oauth/base.rb +143 -0
  64. data/lib/aspera/oauth/factory.rb +124 -0
  65. data/lib/aspera/oauth/generic.rb +34 -0
  66. data/lib/aspera/oauth/jwt.rb +51 -0
  67. data/lib/aspera/oauth/url_json.rb +31 -0
  68. data/lib/aspera/oauth/web.rb +50 -0
  69. data/lib/aspera/oauth.rb +5 -331
  70. data/lib/aspera/open_application.rb +7 -7
  71. data/lib/aspera/persistency_action_once.rb +4 -4
  72. data/lib/aspera/persistency_folder.rb +2 -2
  73. data/lib/aspera/preview/generator.rb +5 -5
  74. data/lib/aspera/preview/terminal.rb +3 -2
  75. data/lib/aspera/preview/utils.rb +3 -3
  76. data/lib/aspera/proxy_auto_config.rb +4 -4
  77. data/lib/aspera/rest.rb +175 -144
  78. data/lib/aspera/rest_errors_aspera.rb +3 -3
  79. data/lib/aspera/resumer.rb +77 -0
  80. data/lib/aspera/ssh.rb +6 -1
  81. data/lib/aspera/{fasp → transfer}/error.rb +3 -3
  82. data/lib/aspera/{fasp → transfer}/error_info.rb +1 -1
  83. data/lib/aspera/{fasp → transfer}/faux_file.rb +1 -1
  84. data/lib/aspera/{fasp → transfer}/parameters.rb +58 -89
  85. data/lib/aspera/{fasp/transfer_spec.rb → transfer/spec.rb} +18 -16
  86. data/lib/aspera/{fasp/parameters.yaml → transfer/spec.yaml} +4 -99
  87. data/lib/aspera/{fasp → transfer}/sync.rb +32 -32
  88. data/lib/aspera/{fasp → transfer}/uri.rb +9 -8
  89. data/lib/aspera/web_server_simple.rb +11 -3
  90. data.tar.gz.sig +0 -0
  91. metadata +36 -63
  92. metadata.gz.sig +0 -0
  93. data/lib/aspera/aoc.rb +0 -601
  94. data/lib/aspera/ats_api.rb +0 -47
  95. data/lib/aspera/cos_node.rb +0 -94
  96. data/lib/aspera/fasp/resume_policy.rb +0 -79
  97. data/lib/aspera/node.rb +0 -339
@@ -19,6 +19,7 @@ module Aspera
19
19
  MAX_PAGES = 'pmax'
20
20
  # special identifier format: look for this name to find where supported
21
21
  REGEX_LOOKUP_ID_BY_FIELD = /^%([^:]+):(.*)$/.freeze
22
+ INIT_PARAMS = %i[options transfer config formatter persistency only_manual].freeze
22
23
 
23
24
  class << self
24
25
  def declare_generic_options(options)
@@ -33,12 +34,18 @@ module Aspera
33
34
  end
34
35
  end
35
36
 
36
- def initialize(env)
37
- assert_type(env, Hash)
38
- @agents = env
37
+ attr_accessor(*INIT_PARAMS)
38
+
39
+ def initialize(options:, transfer:, config:, formatter:, persistency:, only_manual:)
40
+ @options = options
41
+ @transfer = transfer
42
+ @config = config
43
+ @formatter = formatter
44
+ @persistency = persistency
45
+ @only_manual = only_manual
39
46
  # check presence in descendant of mandatory method and constant
40
- assert(respond_to?(:execute_action)){"Missing method 'execute_action' in #{self.class}"}
41
- assert(self.class.constants.include?(:ACTIONS)){'ACTIONS shall be redefined by subclass'}
47
+ Aspera.assert(respond_to?(:execute_action)){"Missing method 'execute_action' in #{self.class}"}
48
+ Aspera.assert(self.class.constants.include?(:ACTIONS)){'ACTIONS shall be redefined by subclass'}
42
49
  # manual header for all plugins
43
50
  options.parser.separator('')
44
51
  options.parser.separator("COMMAND: #{self.class.name.split('::').last.downcase}")
@@ -46,6 +53,11 @@ module Aspera
46
53
  options.parser.separator('OPTIONS:')
47
54
  end
48
55
 
56
+ def init_params
57
+ # return a hash of instance variables
58
+ INIT_PARAMS.map{|p| [p, instance_variable_get("@#{p}".to_sym)]}.to_h
59
+ end
60
+
49
61
  # must be called AFTER the instance action, ... folder browse <call instance_identifier>
50
62
  # @param description [String] description of the identifier
51
63
  # @param as_option [Symbol] option name to use if identifier is an option
@@ -76,7 +88,7 @@ module Aspera
76
88
  # @param id_result [String] key in result hash to use as identifier
77
89
  # @param fields [Array] fields to display
78
90
  def do_bulk_operation(command:, descr:, values: Hash, id_result: 'id', fields: :default)
79
- assert(block_given?){'missing block'}
91
+ Aspera.assert(block_given?){'missing block'}
80
92
  is_bulk = options.get_option(:bulk)
81
93
  case values
82
94
  when :identifier
@@ -238,23 +250,18 @@ module Aspera
238
250
  value = default if value.nil?
239
251
  unless type.nil?
240
252
  type = [type] unless type.is_a?(Array)
241
- assert(type.all?(Class)){"check types must be a Class, not #{type.map(&:class).join(',')}"}
253
+ Aspera.assert(type.all?(Class)){"check types must be a Class, not #{type.map(&:class).join(',')}"}
242
254
  if bulk
243
- assert_type(value, Array, exception_class: Cli::BadArgument)
255
+ Aspera.assert_type(value, Array, exception_class: Cli::BadArgument)
244
256
  value.each do |v|
245
- assert_values(v.class, type, exception_class: Cli::BadArgument)
257
+ Aspera.assert_values(v.class, type, exception_class: Cli::BadArgument)
246
258
  end
247
259
  else
248
- assert_values(value.class, type, exception_class: Cli::BadArgument)
260
+ Aspera.assert_values(value.class, type, exception_class: Cli::BadArgument)
249
261
  end
250
262
  end
251
263
  return value
252
264
  end
253
-
254
- # shortcuts helpers for plugin environment
255
- %i[options transfer config formatter persistency].each do |name|
256
- define_method(name){@agents[name]}
257
- end
258
265
  end # Plugin
259
266
  end # Cli
260
267
  end # Aspera
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+ module Aspera
5
+ module Cli
6
+ # option is retrieved from another object using accessor
7
+ class PluginFactory
8
+ include Singleton
9
+ attr_reader :lookup_folders, :plugins
10
+
11
+ RUBY_FILE_EXT = '.rb'
12
+ PLUGINS_MODULE = 'Plugins'
13
+ private_constant :RUBY_FILE_EXT
14
+ class << self
15
+ # instantiate a plugin
16
+ # plugins must be Capitalized
17
+ def plugin_class(plugin_name_sym)
18
+ # Module.nesting[2] is Cli::Plugins
19
+ return Object.const_get("#{Module.nesting[2]}::#{PLUGINS_MODULE}::#{plugin_name_sym.to_s.capitalize}")
20
+ end
21
+ end
22
+
23
+ def initialize
24
+ @lookup_folders = []
25
+ @plugins = {}
26
+ end
27
+
28
+ def add_plugin_info(path)
29
+ raise "ERROR: plugin path must end with #{RUBY_FILE_EXT}" if !path.end_with?(RUBY_FILE_EXT)
30
+ plugin_symbol = File.basename(path, RUBY_FILE_EXT).to_sym
31
+ req = path.sub(/#{RUBY_FILE_EXT}$/o, '')
32
+ if @plugins.key?(plugin_symbol)
33
+ Log.log.warn{"skipping plugin already registered: #{plugin_symbol}"}
34
+ return
35
+ end
36
+ @plugins[plugin_symbol] = {source: path, require_stanza: req}
37
+ end
38
+
39
+ def add_lookup_folder(folder)
40
+ @lookup_folders.unshift(folder)
41
+ end
42
+
43
+ # find plugins in defined paths
44
+ def add_plugins_from_lookup_folders
45
+ @lookup_folders.each do |folder|
46
+ next unless File.directory?(folder)
47
+ # TODO: add gem root to load path ? and require short folder ?
48
+ # $LOAD_PATH.push(folder) if i[:add_path]
49
+ Dir.entries(folder).select{|file|file.end_with?(RUBY_FILE_EXT)}.each do |source|
50
+ add_plugin_info(File.join(folder, source))
51
+ end
52
+ end
53
+ end
54
+
55
+ def create(plugin_name_sym, **args)
56
+ # TODO: check that ancestor is Plugin?
57
+ self.class.plugin_class(plugin_name_sym).new(**args)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'aspera/aoc'
3
+ require 'aspera/api/aoc'
4
4
 
5
5
  module Aspera
6
6
  module Cli
7
7
  module Plugins
8
- class Alee < Aspera::Cli::BasicAuthPlugin
8
+ class Alee < Cli::BasicAuthPlugin
9
9
  ACTIONS = %i[entitlement].freeze
10
10
 
11
11
  def execute_action
@@ -14,11 +14,11 @@ module Aspera
14
14
  when :entitlement
15
15
  entitlement_id = options.get_option(:username, mandatory: true)
16
16
  customer_id = options.get_option(:password, mandatory: true)
17
- api_metering = AoC.metering_api(entitlement_id, customer_id)
17
+ api_metering = Api::AoC.metering_api(entitlement_id, customer_id)
18
18
  return {type: :single_object, data: api_metering.read('entitlement')[:data]}
19
19
  end
20
20
  end
21
- end # Aspera
22
- end # Plugins
23
- end # Cli
24
- end # Aspera
21
+ end
22
+ end
23
+ end
24
+ end
@@ -4,10 +4,10 @@ require 'aspera/cli/plugins/node'
4
4
  require 'aspera/cli/plugins/ats'
5
5
  require 'aspera/cli/basic_auth_plugin'
6
6
  require 'aspera/cli/transfer_agent'
7
- require 'aspera/fasp/agent_node'
8
- require 'aspera/fasp/transfer_spec'
9
- require 'aspera/aoc'
10
- require 'aspera/node'
7
+ require 'aspera/agent/node'
8
+ require 'aspera/transfer/spec'
9
+ require 'aspera/api/aoc'
10
+ require 'aspera/api/node'
11
11
  require 'aspera/persistency_action_once'
12
12
  require 'aspera/id_generator'
13
13
  require 'aspera/assert'
@@ -17,11 +17,13 @@ require 'date'
17
17
  module Aspera
18
18
  module Cli
19
19
  module Plugins
20
- class Aoc < Aspera::Cli::BasicAuthPlugin
20
+ class Aoc < Cli::BasicAuthPlugin
21
21
  AOC_PATH_API_CLIENTS = 'admin/api-clients'
22
22
  # default redirect for AoC web auth
23
- DEFAULT_REDIRECT = 'http://localhost:12345'
24
- private_constant :AOC_PATH_API_CLIENTS, :DEFAULT_REDIRECT
23
+ REDIRECT_LOCALHOST = 'http://localhost:12345'
24
+ # OAuth methods supported
25
+ STD_AUTH_TYPES = %i[web jwt].freeze
26
+ private_constant :AOC_PATH_API_CLIENTS, :REDIRECT_LOCALHOST, :STD_AUTH_TYPES
25
27
  class << self
26
28
  def application_name
27
29
  'Aspera on Cloud'
@@ -31,13 +33,13 @@ module Aspera
31
33
  # no protocol ?
32
34
  base_url = "https://#{base_url}" unless base_url.match?(%r{^[a-z]{1,6}://})
33
35
  # only org provided ?
34
- base_url = "#{base_url}.#{Aspera::AoC::PROD_DOMAIN}" unless base_url.include?('.')
36
+ base_url = "#{base_url}.#{Api::AoC::PROD_DOMAIN}" unless base_url.include?('.')
35
37
  # AoC is only https
36
38
  return nil unless base_url.start_with?('https://')
37
- result = Rest.new({base_url: base_url, redirect_max: 10}).read('')
39
+ result = Rest.new(base_url: base_url, redirect_max: 10).read('')
38
40
  # Any AoC is on this domain
39
- return nil unless result[:http].uri.host.end_with?(Aspera::AoC::PROD_DOMAIN)
40
- Log.log.debug{'AoC Main page: #{result[:http].body.include?(Aspera::AoC::PRODUCT_NAME)}'}
41
+ return nil unless result[:http].uri.host.end_with?(Api::AoC::PROD_DOMAIN)
42
+ Log.log.debug{"AoC Main page: #{result[:http].body.include?(Api::AoC::PRODUCT_NAME)}"}
41
43
  base_url = result[:http].uri.to_s if result[:http].uri.path.include?('/public')
42
44
  # either in standard domain, or product name in page
43
45
  return {
@@ -48,7 +50,7 @@ module Aspera
48
50
 
49
51
  def private_key_required?(url)
50
52
  # pub link do not need private key
51
- return AoC.link_info(url)[:token].nil?
53
+ return Api::AoC.link_info(url)[:token].nil?
52
54
  end
53
55
 
54
56
  # @param [Hash] env : options, formatter
@@ -61,9 +63,9 @@ module Aspera
61
63
  options.declare(:use_generic_client, 'Wizard: AoC: use global or org specific jwt client id', values: :bool, default: true)
62
64
  options.parse_options!
63
65
  instance_url = options.get_option(:url, mandatory: true)
64
- pub_link_info = AoC.link_info(instance_url)
66
+ pub_link_info = Api::AoC.link_info(instance_url)
65
67
  if !pub_link_info[:token].nil?
66
- pub_api = Rest.new({base_url: "https://#{URI.parse(pub_link_info[:url]).host}/api/v1"})
68
+ pub_api = Rest.new(base_url: "https://#{URI.parse(pub_link_info[:url]).host}/api/v1")
67
69
  pub_info = pub_api.read('env/url_token_check', {token: pub_link_info[:token]})[:data]
68
70
  preset_value = {
69
71
  link: instance_url
@@ -100,7 +102,7 @@ module Aspera
100
102
  formatter.display_status('Navigate to: 𓃑 → Admin → Integrations → API Clients')
101
103
  formatter.display_status('Check or create in integration:')
102
104
  formatter.display_status("- name: #{@info[:name]}")
103
- formatter.display_status("- redirect uri: #{DEFAULT_REDIRECT}")
105
+ formatter.display_status("- redirect uri: #{REDIRECT_LOCALHOST}")
104
106
  formatter.display_status('- origin: localhost')
105
107
  formatter.display_status('Use the generated client id and secret in the following prompts.'.red)
106
108
  end
@@ -113,13 +115,14 @@ module Aspera
113
115
  formatter.display_status('We will use web authentication to bootstrap.')
114
116
  auto_set_pub_key = true
115
117
  auto_set_jwt = true
116
- aoc_api.oauth.generic_parameters[:grant_method] = :web
117
- aoc_api.oauth.generic_parameters[:scope] = AoC::SCOPE_FILES_ADMIN
118
- aoc_api.oauth.specific_parameters[:redirect_uri] = DEFAULT_REDIRECT
118
+ raise 'TODO'
119
+ # aoc_api.oauth.grant_method = :web
120
+ # aoc_api.oauth.scope = Api::AoC::SCOPE_FILES_ADMIN
121
+ # aoc_api.oauth.specific_parameters[:redirect_uri] = REDIRECT_LOCALHOST
119
122
  end
120
123
  myself = object.aoc_api.read('self')[:data]
121
124
  if auto_set_pub_key
122
- assert(myself['public_key'].empty?, exception_class: Cli::Error){'Public key is already set in profile (use --override=yes)'} unless option_override
125
+ Aspera.assert(myself['public_key'].empty?, exception_class: Cli::Error){'Public key is already set in profile (use --override=yes)'} unless option_override
123
126
  formatter.display_status('Updating profile with the public key.')
124
127
  aoc_api.update("users/#{myself['id']}", {'public_key' => pub_key_pem})
125
128
  end
@@ -172,19 +175,19 @@ module Aspera
172
175
  'received' => true,
173
176
  'completed' => true}.freeze
174
177
 
175
- def initialize(env)
176
- super(env)
178
+ def initialize(**env)
179
+ super
177
180
  @cache_workspace_info = nil
178
181
  @cache_home_node_file = nil
179
182
  @cache_api_aoc = nil
180
- options.declare(:auth, 'OAuth type of authentication', values: Oauth::STD_AUTH_TYPES, default: :jwt)
183
+ options.declare(:auth, 'OAuth type of authentication', values: STD_AUTH_TYPES, default: :jwt)
181
184
  options.declare(:client_id, 'OAuth API client identifier')
182
185
  options.declare(:client_secret, 'OAuth API client secret')
183
- options.declare(:scope, 'OAuth scope for AoC API calls', default: AoC::SCOPE_FILES_USER)
186
+ options.declare(:scope, 'OAuth scope for AoC API calls', default: Api::AoC::SCOPE_FILES_USER)
184
187
  options.declare(:redirect_uri, 'OAuth API client redirect URI')
185
188
  options.declare(:private_key, 'OAuth JWT RSA private key PEM value (prefix file path with @file:)')
186
189
  options.declare(:passphrase, 'RSA private key passphrase')
187
- options.declare(:workspace, 'Name of workspace', types: [String, NilClass], default: Aspera::AoC::DEFAULT_WORKSPACE)
190
+ options.declare(:workspace, 'Name of workspace', types: [String, NilClass], default: Api::AoC::DEFAULT_WORKSPACE)
188
191
  options.declare(:new_user_option, 'New user creation option for unknown package recipients')
189
192
  options.declare(:validate_metadata, 'Validate shared inbox metadata', values: :bool, default: true)
190
193
  options.parse_options!
@@ -195,9 +198,9 @@ module Aspera
195
198
  OPTIONS_NEW = %i[url auth client_id client_secret scope redirect_uri private_key passphrase username password workspace].freeze
196
199
 
197
200
  def api_from_options(new_base_path)
198
- create_values = {subpath: new_base_path, secret_finder: @agents[:config]}
201
+ create_values = {subpath: new_base_path, secret_finder: config}
199
202
  # create an API object with the same options, but with a different subpath
200
- return Aspera::AoC.new(**OPTIONS_NEW.each_with_object(create_values) { |i, m|m[i] = options.get_option(i) unless options.get_option(i).nil?})
203
+ return Api::AoC.new(**OPTIONS_NEW.each_with_object(create_values) { |i, m|m[i] = options.get_option(i) unless options.get_option(i).nil?})
201
204
  rescue ArgumentError => e
202
205
  if (m = e.message.match(/missing keyword: :(.*)$/))
203
206
  raise Cli::Error, "Missing option: #{m[1]}"
@@ -206,7 +209,14 @@ module Aspera
206
209
  end
207
210
 
208
211
  def aoc_api
209
- @cache_api_aoc = api_from_options(AoC::API_V1) if @cache_api_aoc.nil?
212
+ if @cache_api_aoc.nil?
213
+ @cache_api_aoc = api_from_options(Api::AoC::API_V1)
214
+ organization = @cache_api_aoc.read('organization')[:data]
215
+ if organization['http_gateway_enabled'] && organization['http_gateway_server_url']
216
+ transfer.httpgw_url_cb = lambda { organization['http_gateway_server_url'] }
217
+ # @cache_api_aoc.current_user_info['connect_disabled']
218
+ end
219
+ end
210
220
  return @cache_api_aoc
211
221
  end
212
222
 
@@ -214,7 +224,7 @@ module Aspera
214
224
  # @return identifier
215
225
  def get_resource_id_from_args(resource_class_path)
216
226
  return instance_identifier do |field, value|
217
- assert(field.eql?('name'), exception_class: Cli::BadArgument){'only selection by name is supported'}
227
+ Aspera.assert(field.eql?('name'), exception_class: Cli::BadArgument){'only selection by name is supported'}
218
228
  aoc_api.lookup_by_name(resource_class_path, value)['id']
219
229
  end
220
230
  end
@@ -226,8 +236,8 @@ module Aspera
226
236
  # Call block with same query using paging and response information
227
237
  # @return [Hash] {data: , total: }
228
238
  def api_call_paging(base_query={})
229
- assert_type(base_query, Hash){'query'}
230
- assert(block_given?)
239
+ Aspera.assert_type(base_query, Hash){'query'}
240
+ Aspera.assert(block_given?)
231
241
  # set default large page if user does not specify own parameters. AoC Caps to 1000 anyway
232
242
  base_query['per_page'] = 1000 unless base_query.key?('per_page')
233
243
  max_items = base_query.delete(MAX_ITEMS)
@@ -265,8 +275,8 @@ module Aspera
265
275
 
266
276
  # list all entities, given additional, default and user's queries
267
277
  def result_list(resource_class_path, fields: nil, base_query: {}, default_query: {})
268
- assert_type(base_query, Hash)
269
- assert_type(default_query, Hash)
278
+ Aspera.assert_type(base_query, Hash)
279
+ Aspera.assert_type(default_query, Hash)
270
280
  user_query = query_read_delete(default: default_query)
271
281
  # caller may add specific modifications or checks
272
282
  yield(user_query) if block_given?
@@ -277,11 +287,13 @@ module Aspera
277
287
  if query.key?('dropbox_name')
278
288
  # convenience: specify name instead of id
279
289
  raise 'not both dropbox_name and dropbox_id' if query.key?('dropbox_id')
290
+ # TODO : craft a query that looks for dropbox only in current workspace
280
291
  query['dropbox_id'] = aoc_api.lookup_by_name('dropboxes', query['dropbox_name'])['id']
281
292
  query.delete('dropbox_name')
282
293
  end
283
294
  query['workspace_id'] ||= aoc_api.context[:workspace_id] unless aoc_api.context[:workspace_id].eql?(:undefined)
284
- query['exclude_dropbox_packages'] = true unless query.key?('dropbox_id')
295
+ # by default show dropbox packages only for dropboxes
296
+ query['exclude_dropbox_packages'] = !query.key?('dropbox_id') unless query.key?('exclude_dropbox_packages')
285
297
  end
286
298
 
287
299
  NODE4_EXT_COMMANDS = %i[transfer].concat(Node::COMMANDS_GEN4).freeze
@@ -297,7 +309,7 @@ module Aspera
297
309
  scope: scope
298
310
  )
299
311
  file_id = top_node_api.read("access_keys/#{top_node_api.app_info[:node_info]['access_key']}")[:data]['root_file_id'] if file_id.nil?
300
- node_plugin = Node.new(@agents, api: top_node_api)
312
+ node_plugin = Node.new(**init_params, api: top_node_api)
301
313
  case command_repo
302
314
  when *Node::COMMANDS_GEN4
303
315
  return node_plugin.execute_command_gen4(command_repo, file_id)
@@ -309,20 +321,20 @@ module Aspera
309
321
  source_folder = options.get_next_argument('folder of source files', type: String)
310
322
  case push_pull
311
323
  when :push
312
- client_direction = Fasp::TransferSpec::DIRECTION_SEND
324
+ client_direction = Transfer::Spec::DIRECTION_SEND
313
325
  client_folder = source_folder
314
326
  server_folder = transfer.destination_folder(client_direction)
315
327
  when :pull
316
- client_direction = Fasp::TransferSpec::DIRECTION_RECEIVE
328
+ client_direction = Transfer::Spec::DIRECTION_RECEIVE
317
329
  client_folder = transfer.destination_folder(client_direction)
318
330
  server_folder = source_folder
319
- else error_unreachable_line
331
+ else Aspera.error_unreachable_line
320
332
  end
321
333
  client_apfid = top_node_api.resolve_api_fid(file_id, client_folder)
322
334
  server_apfid = top_node_api.resolve_api_fid(file_id, server_folder)
323
335
  # force node as transfer agent
324
- @agents[:transfer].agent_instance = Fasp::AgentNode.new({
325
- url: client_apfid[:api].params[:base_url],
336
+ transfer.agent_instance = Agent::Node.new({
337
+ url: client_apfid[:api].base_url,
326
338
  username: client_apfid[:api].app_info[:node_info]['access_key'],
327
339
  password: client_apfid[:api].oauth_token,
328
340
  root_id: client_apfid[:file_id]
@@ -337,14 +349,14 @@ module Aspera
337
349
  server_apfid[:file_id],
338
350
  client_direction,
339
351
  add_ts)))
340
- else error_unreachable_line
352
+ else Aspera.error_unreachable_line
341
353
  end # command_repo
342
- error_unreachable_line
354
+ Aspera.error_unreachable_line
343
355
  end # execute_nodegen4_command
344
356
 
345
357
  def execute_admin_action
346
358
  # upgrade scope to admin
347
- aoc_api.oauth.generic_parameters[:scope] = AoC::SCOPE_FILES_ADMIN
359
+ aoc_api.oauth.scope = Api::AoC::SCOPE_FILES_ADMIN
348
360
  command_admin = options.get_next_command(%i[ats resource usage_reports analytics subscription auth_providers])
349
361
  case command_admin
350
362
  when :auth_providers
@@ -411,15 +423,15 @@ module Aspera
411
423
  result = bss_api.create('graphql', {'variables' => {'organization_id' => org['id']}, 'query' => graphql_query})[:data]['data']
412
424
  return {type: :single_object, data: result['aoc']['bssSubscription']}
413
425
  when :ats
414
- ats_api = Rest.new(aoc_api.params.deep_merge({
415
- base_url: "#{aoc_api.params[:base_url]}/admin/ats/pub/v1",
416
- auth: {scope: AoC::SCOPE_FILES_ADMIN_USER}
426
+ ats_api = Rest.new(**aoc_api.params.deep_merge({
427
+ base_url: "#{aoc_api.base_url}/admin/ats/pub/v1",
428
+ auth: {scope: Api::AoC::SCOPE_FILES_ADMIN_USER}
417
429
  }))
418
- return Ats.new(@agents).execute_action_gen(ats_api)
430
+ return Ats.new(**init_params).execute_action_gen(ats_api)
419
431
  when :analytics
420
- analytics_api = Rest.new(aoc_api.params.deep_merge({
421
- base_url: "#{aoc_api.params[:base_url].gsub('/api/v1', '')}/analytics/v2",
422
- auth: {scope: AoC::SCOPE_FILES_ADMIN_USER}
432
+ analytics_api = Rest.new(**aoc_api.params.deep_merge({
433
+ base_url: "#{aoc_api.base_url.gsub('/api/v1', '')}/analytics/v2",
434
+ auth: {scope: Api::AoC::SCOPE_FILES_ADMIN_USER}
423
435
  }))
424
436
  command_analytics = options.get_next_command(%i[application_events transfers])
425
437
  case command_analytics
@@ -435,14 +447,14 @@ module Aspera
435
447
  when :organizations then aoc_api.current_user_info['organization_id']
436
448
  when :users then aoc_api.current_user_info['id']
437
449
  when :nodes then aoc_api.current_user_info['id'] # TODO: consistent ? # rubocop:disable Lint/DuplicateBranch
438
- else error_unreachable_line
450
+ else Aspera.error_unreachable_line
439
451
  end
440
452
  filter = options.get_option(:query) || {}
441
453
  filter['limit'] ||= 100
442
454
  if options.get_option(:once_only, mandatory: true)
443
455
  saved_date = []
444
456
  start_date_persistency = PersistencyActionOnce.new(
445
- manager: @agents[:persistency],
457
+ manager: persistency,
446
458
  data: saved_date,
447
459
  id: IdGenerator.from_list([
448
460
  'aoc_ana_date',
@@ -549,7 +561,7 @@ module Aspera
549
561
  # init context
550
562
  aoc_api.context(:files)
551
563
  return execute_nodegen4_command(command_repo, res_id)
552
- else error_unexpected_value(command)
564
+ else Aspera.error_unexpected_value(command)
553
565
  end
554
566
  when :usage_reports
555
567
  return result_list('usage_reports', base_query: {workspace_id: aoc_api.context(:files)[:workspace_id]})
@@ -574,10 +586,10 @@ module Aspera
574
586
  when :reminder
575
587
  # send an email reminder with list of orgs
576
588
  user_email = options.get_option(:username, mandatory: true)
577
- Rest.new(base_url: "#{AoC.api_base_url}/#{AoC::API_V1}").create('organization_reminders', {email: user_email})[:data]
589
+ Rest.new(base_url: "#{Api::AoC.api_base_url}/#{Api::AoC::API_V1}").create('organization_reminders', {email: user_email})[:data]
578
590
  return Main.result_status("List of organizations user is member of, has been sent by e-mail to #{user_email}")
579
591
  when :servers
580
- return {type: :object_list, data: Rest.new(base_url: "#{AoC.api_base_url}/#{AoC::API_V1}").read('servers')[:data]}
592
+ return {type: :object_list, data: Rest.new(base_url: "#{Api::AoC.api_base_url}/#{Api::AoC::API_V1}").read('servers')[:data]}
581
593
  when :bearer_token
582
594
  return {type: :text, data: aoc_api.oauth_token}
583
595
  when :organization
@@ -659,7 +671,7 @@ module Aspera
659
671
  if options.get_option(:once_only, mandatory: true)
660
672
  # TODO: add query info to id
661
673
  skip_ids_persistency = PersistencyActionOnce.new(
662
- manager: @agents[:persistency],
674
+ manager: persistency,
663
675
  data: skip_ids_data,
664
676
  id: IdGenerator.from_list(
665
677
  ['aoc_recv',
@@ -670,12 +682,12 @@ module Aspera
670
682
  case ids_to_download
671
683
  when ExtendedValue::ALL, ExtendedValue::INIT
672
684
  query = query_read_delete(default: PACKAGE_RECEIVED_BASE_QUERY)
673
- assert_type(query, Hash){'query'}
685
+ Aspera.assert_type(query, Hash){'query'}
674
686
  resolve_dropbox_name_default_ws_id(query)
675
687
  # remove from list the ones already downloaded
676
688
  all_ids = api_read_all('packages', query)[:data].map{|e|e['id']}
677
689
  if ids_to_download.eql?(ExtendedValue::INIT)
678
- assert(skip_ids_persistency){'Only with option once_only'}
690
+ Aspera.assert(skip_ids_persistency){'Only with option once_only'}
679
691
  skip_ids_persistency.data.clear.concat(all_ids)
680
692
  skip_ids_persistency.save
681
693
  return Main.result_status("Initialized skip for #{skip_ids_persistency.data.count} package(s)")
@@ -690,7 +702,7 @@ module Aspera
690
702
  formatter.display_status("found #{ids_to_download.length} package(s).")
691
703
  ids_to_download.each do |package_id|
692
704
  package_info = aoc_api.read("packages/#{package_id}")[:data]
693
- formatter.display_status("downloading package: #{package_info['name']}")
705
+ formatter.display_status("downloading package: [#{package_info['id']}] #{package_info['name']}")
694
706
  package_node_api = aoc_api.node_api_from(
695
707
  node_id: package_info['node_id'],
696
708
  workspace_id: aoc_api.context[:workspace_id],
@@ -699,7 +711,7 @@ module Aspera
699
711
  statuses = transfer.start(
700
712
  package_node_api.transfer_spec_gen4(
701
713
  package_info['contents_file_id'],
702
- Fasp::TransferSpec::DIRECTION_RECEIVE,
714
+ Transfer::Spec::DIRECTION_RECEIVE,
703
715
  {'paths'=> [{'source' => '.'}]}),
704
716
  rest_token: package_node_api)
705
717
  result_transfer.push({'package' => package_id, Main::STATUS_FIELD => statuses})
@@ -722,19 +734,19 @@ module Aspera
722
734
  end
723
735
  when :delete
724
736
  return do_bulk_operation(command: package_command, descr: 'identifier', values: identifier) do |id|
725
- assert_values(id.class, [String, Integer]){'identifier'}
737
+ Aspera.assert_values(id.class, [String, Integer]){'identifier'}
726
738
  aoc_api.delete("packages/#{id}")[:data]
727
739
  end
728
740
  when *Node::NODE4_READ_ACTIONS
729
741
  package_id = instance_identifier
730
742
  package_info = aoc_api.read("packages/#{package_id}")[:data]
731
- return execute_nodegen4_command(package_command, package_info['node_id'], file_id: package_info['file_id'], scope: Aspera::Node::SCOPE_USER)
743
+ return execute_nodegen4_command(package_command, package_info['node_id'], file_id: package_info['file_id'], scope: Api::Node::SCOPE_USER)
732
744
  end
733
745
  when :files
734
746
  command_repo = options.get_next_command([:short_link].concat(NODE4_EXT_COMMANDS))
735
747
  case command_repo
736
748
  when *NODE4_EXT_COMMANDS
737
- return execute_nodegen4_command(command_repo, aoc_api.context[:home_node_id], file_id: aoc_api.context[:home_file_id], scope: Aspera::Node::SCOPE_USER)
749
+ return execute_nodegen4_command(command_repo, aoc_api.context[:home_node_id], file_id: aoc_api.context[:home_file_id], scope: Api::Node::SCOPE_USER)
738
750
  when :short_link
739
751
  link_type = options.get_next_argument('link type', expected: %i[public private])
740
752
  short_link_command = options.get_next_command(%i[create delete list])
@@ -752,7 +764,7 @@ module Aspera
752
764
  purpose = case link_type
753
765
  when :public then 'token_auth_redirection'
754
766
  when :private then 'shared_folder_auth_link'
755
- else error_unreachable_line
767
+ else Aspera.error_unreachable_line
756
768
  end
757
769
  case short_link_command
758
770
  when :delete
@@ -812,7 +824,7 @@ module Aspera
812
824
  if link_type.eql?(:public)
813
825
  # TODO: merge with node permissions ?
814
826
  # TODO: access level as arg
815
- access_levels = Aspera::Node::ACCESS_LEVELS # ['delete','list','mkdir','preview','read','rename','write']
827
+ access_levels = Api::Node::ACCESS_LEVELS # ['delete','list','mkdir','preview','read','rename','write']
816
828
  folder_name = File.basename(folder_dest)
817
829
  perm_data = {
818
830
  'file_id' => shared_apfid[:file_id],
@@ -841,9 +853,7 @@ module Aspera
841
853
  when :automation
842
854
  Log.log.warn('BETA: work under progress')
843
855
  # automation api is not in the same place
844
- automation_rest_params = aoc_api.params.clone
845
- automation_rest_params[:base_url].gsub!('/api/', '/automation/')
846
- automation_api = Rest.new(automation_rest_params)
856
+ automation_api = Rest.new(**aoc_api.params.merge(base_url: aoc_api.base_url.gsub('/api/', '/automation/')))
847
857
  command_automation = options.get_next_command(%i[workflows instances])
848
858
  case command_automation
849
859
  when :instances
@@ -878,19 +888,15 @@ module Aspera
878
888
  uri = URI.parse(url)
879
889
  server = WebServerSimple.new(uri)
880
890
  server.mount(uri.path, Faspex4GWServlet, aoc_api, aoc_api.context(:files)[:workspace_id])
881
- trap('INT') { server.shutdown }
882
- formatter.display_status("Faspex 4 gateway listening on #{url}")
883
- Log.log.info("Listening on #{url}")
884
- # this is blocking until server exits
885
891
  server.start
886
892
  return Main.result_status('Gateway terminated')
887
- else error_unreachable_line
893
+ else Aspera.error_unreachable_line
888
894
  end # action
889
- error_unreachable_line
895
+ Aspera.error_unreachable_line
890
896
  end
891
897
 
892
898
  private :execute_admin_action
893
- end # AoC
894
- end # Plugins
895
- end # Cli
896
- end # Aspera
899
+ end
900
+ end
901
+ end
902
+ end