aspera-cli 4.16.0 → 4.17.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/CHANGELOG.md +50 -19
- data/CONTRIBUTING.md +3 -1
- data/README.md +965 -793
- data/bin/asession +29 -21
- data/lib/aspera/{fasp/agent_alpha.rb → agent/alpha.rb} +26 -25
- data/lib/aspera/{fasp/agent_base.rb → agent/base.rb} +15 -12
- data/lib/aspera/{fasp/agent_connect.rb → agent/connect.rb} +13 -11
- data/lib/aspera/{fasp/agent_direct.rb → agent/direct.rb} +49 -53
- data/lib/aspera/{fasp/agent_httpgw.rb → agent/httpgw.rb} +20 -19
- data/lib/aspera/{fasp/agent_node.rb → agent/node.rb} +20 -33
- data/lib/aspera/{fasp/agent_trsdk.rb → agent/trsdk.rb} +11 -11
- data/lib/aspera/api/aoc.rb +586 -0
- data/lib/aspera/api/ats.rb +46 -0
- data/lib/aspera/api/cos_node.rb +95 -0
- data/lib/aspera/api/node.rb +344 -0
- data/lib/aspera/ascmd.rb +46 -10
- data/lib/aspera/{fasp → ascp}/installation.rb +5 -5
- data/lib/aspera/{fasp → ascp}/management.rb +3 -8
- data/lib/aspera/{fasp → ascp}/products.rb +1 -1
- data/lib/aspera/assert.rb +30 -30
- data/lib/aspera/cli/basic_auth_plugin.rb +11 -10
- data/lib/aspera/cli/extended_value.rb +1 -1
- data/lib/aspera/cli/formatter.rb +13 -13
- data/lib/aspera/cli/hints.rb +5 -5
- data/lib/aspera/cli/main.rb +35 -28
- data/lib/aspera/cli/manager.rb +25 -24
- data/lib/aspera/cli/plugin.rb +22 -15
- data/lib/aspera/cli/plugin_factory.rb +61 -0
- data/lib/aspera/cli/plugins/alee.rb +7 -7
- data/lib/aspera/cli/plugins/aoc.rb +83 -77
- data/lib/aspera/cli/plugins/ats.rb +32 -33
- data/lib/aspera/cli/plugins/bss.rb +3 -4
- data/lib/aspera/cli/plugins/config.rb +169 -186
- data/lib/aspera/cli/plugins/console.rb +8 -6
- data/lib/aspera/cli/plugins/cos.rb +19 -18
- data/lib/aspera/cli/plugins/faspex.rb +61 -54
- data/lib/aspera/cli/plugins/faspex5.rb +150 -103
- data/lib/aspera/cli/plugins/node.rb +68 -73
- data/lib/aspera/cli/plugins/orchestrator.rb +34 -44
- data/lib/aspera/cli/plugins/preview.rb +31 -31
- data/lib/aspera/cli/plugins/server.rb +31 -33
- data/lib/aspera/cli/plugins/shares.rb +13 -11
- data/lib/aspera/cli/sync_actions.rb +8 -8
- data/lib/aspera/cli/transfer_agent.rb +32 -19
- data/lib/aspera/cli/transfer_progress.rb +1 -1
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/colors.rb +5 -0
- data/lib/aspera/command_line_builder.rb +14 -14
- data/lib/aspera/coverage.rb +1 -2
- data/lib/aspera/data_repository.rb +1 -1
- data/lib/aspera/environment.rb +2 -3
- data/lib/aspera/faspex_gw.rb +5 -6
- data/lib/aspera/faspex_postproc.rb +1 -1
- data/lib/aspera/id_generator.rb +2 -2
- data/lib/aspera/json_rpc.rb +5 -5
- data/lib/aspera/keychain/encrypted_hash.rb +6 -6
- data/lib/aspera/keychain/macos_security.rb +27 -22
- data/lib/aspera/log.rb +2 -2
- data/lib/aspera/nagios.rb +3 -3
- data/lib/aspera/node_simulator.rb +5 -6
- data/lib/aspera/oauth/base.rb +143 -0
- data/lib/aspera/oauth/factory.rb +124 -0
- data/lib/aspera/oauth/generic.rb +34 -0
- data/lib/aspera/oauth/jwt.rb +51 -0
- data/lib/aspera/oauth/url_json.rb +31 -0
- data/lib/aspera/oauth/web.rb +50 -0
- data/lib/aspera/oauth.rb +5 -331
- data/lib/aspera/open_application.rb +7 -7
- data/lib/aspera/persistency_action_once.rb +4 -4
- data/lib/aspera/persistency_folder.rb +2 -2
- data/lib/aspera/preview/generator.rb +5 -5
- data/lib/aspera/preview/terminal.rb +3 -2
- data/lib/aspera/preview/utils.rb +3 -3
- data/lib/aspera/proxy_auto_config.rb +4 -4
- data/lib/aspera/rest.rb +175 -144
- data/lib/aspera/rest_errors_aspera.rb +3 -3
- data/lib/aspera/resumer.rb +77 -0
- data/lib/aspera/ssh.rb +6 -1
- data/lib/aspera/{fasp → transfer}/error.rb +3 -3
- data/lib/aspera/{fasp → transfer}/error_info.rb +1 -1
- data/lib/aspera/{fasp → transfer}/faux_file.rb +1 -1
- data/lib/aspera/{fasp → transfer}/parameters.rb +58 -89
- data/lib/aspera/{fasp/transfer_spec.rb → transfer/spec.rb} +18 -16
- data/lib/aspera/{fasp/parameters.yaml → transfer/spec.yaml} +4 -99
- data/lib/aspera/{fasp → transfer}/sync.rb +32 -32
- data/lib/aspera/{fasp → transfer}/uri.rb +9 -8
- data/lib/aspera/web_server_simple.rb +11 -3
- data.tar.gz.sig +0 -0
- metadata +36 -63
- metadata.gz.sig +0 -0
- data/lib/aspera/aoc.rb +0 -601
- data/lib/aspera/ats_api.rb +0 -47
- data/lib/aspera/cos_node.rb +0 -94
- data/lib/aspera/fasp/resume_policy.rb +0 -79
- data/lib/aspera/node.rb +0 -339
data/lib/aspera/cli/plugin.rb
CHANGED
|
@@ -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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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 <
|
|
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
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
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/
|
|
8
|
-
require 'aspera/
|
|
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 <
|
|
20
|
+
class Aoc < Cli::BasicAuthPlugin
|
|
21
21
|
AOC_PATH_API_CLIENTS = 'admin/api-clients'
|
|
22
22
|
# default redirect for AoC web auth
|
|
23
|
-
|
|
24
|
-
|
|
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}.#{
|
|
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(
|
|
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?(
|
|
40
|
-
Log.log.debug{
|
|
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(
|
|
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: #{
|
|
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
|
-
|
|
117
|
-
aoc_api.oauth.
|
|
118
|
-
aoc_api.oauth.
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
325
|
-
url: client_apfid[:api].
|
|
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.
|
|
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.
|
|
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(
|
|
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.
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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 =
|
|
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
|
-
|
|
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
|
|
894
|
-
end
|
|
895
|
-
end
|
|
896
|
-
end
|
|
899
|
+
end
|
|
900
|
+
end
|
|
901
|
+
end
|
|
902
|
+
end
|