aspera-cli 4.24.2 → 4.25.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 +1070 -758
- data/CONTRIBUTING.md +130 -115
- data/README.md +961 -623
- data/lib/aspera/agent/direct.rb +14 -12
- data/lib/aspera/agent/factory.rb +9 -6
- data/lib/aspera/agent/transferd.rb +8 -8
- data/lib/aspera/api/aoc.rb +104 -67
- data/lib/aspera/api/ats.rb +1 -0
- data/lib/aspera/api/cos_node.rb +3 -2
- data/lib/aspera/api/faspex.rb +17 -10
- data/lib/aspera/api/node.rb +10 -12
- data/lib/aspera/ascmd.rb +2 -3
- data/lib/aspera/ascp/installation.rb +60 -46
- data/lib/aspera/ascp/management.rb +9 -5
- data/lib/aspera/assert.rb +28 -6
- data/lib/aspera/cli/error.rb +4 -2
- data/lib/aspera/cli/extended_value.rb +94 -62
- data/lib/aspera/cli/formatter.rb +44 -58
- data/lib/aspera/cli/main.rb +21 -14
- data/lib/aspera/cli/manager.rb +317 -250
- data/lib/aspera/cli/plugins/alee.rb +3 -3
- data/lib/aspera/cli/plugins/aoc.rb +139 -78
- data/lib/aspera/cli/plugins/ats.rb +30 -36
- data/lib/aspera/cli/plugins/base.rb +68 -55
- data/lib/aspera/cli/plugins/config.rb +90 -100
- data/lib/aspera/cli/plugins/console.rb +15 -9
- data/lib/aspera/cli/plugins/cos.rb +1 -1
- data/lib/aspera/cli/plugins/faspex.rb +39 -30
- data/lib/aspera/cli/plugins/faspex5.rb +57 -52
- data/lib/aspera/cli/plugins/faspio.rb +10 -7
- data/lib/aspera/cli/plugins/httpgw.rb +3 -2
- data/lib/aspera/cli/plugins/node.rb +140 -125
- data/lib/aspera/cli/plugins/oauth.rb +13 -12
- data/lib/aspera/cli/plugins/orchestrator.rb +116 -33
- data/lib/aspera/cli/plugins/preview.rb +28 -48
- data/lib/aspera/cli/plugins/server.rb +9 -10
- data/lib/aspera/cli/plugins/shares.rb +77 -43
- data/lib/aspera/cli/sync_actions.rb +49 -38
- data/lib/aspera/cli/transfer_agent.rb +16 -35
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/cli/wizard.rb +8 -5
- data/lib/aspera/command_line_builder.rb +24 -21
- data/lib/aspera/coverage.rb +6 -2
- data/lib/aspera/dot_container.rb +108 -0
- data/lib/aspera/environment.rb +71 -84
- data/lib/aspera/faspex_gw.rb +1 -1
- data/lib/aspera/faspex_postproc.rb +1 -1
- data/lib/aspera/id_generator.rb +7 -10
- data/lib/aspera/keychain/factory.rb +1 -2
- data/lib/aspera/keychain/macos_security.rb +2 -2
- data/lib/aspera/log.rb +2 -1
- data/lib/aspera/markdown.rb +31 -0
- data/lib/aspera/nagios.rb +6 -5
- data/lib/aspera/oauth/base.rb +41 -64
- data/lib/aspera/oauth/factory.rb +6 -7
- data/lib/aspera/oauth/generic.rb +1 -1
- data/lib/aspera/oauth/jwt.rb +1 -1
- data/lib/aspera/oauth/url_json.rb +6 -4
- data/lib/aspera/oauth/web.rb +2 -2
- data/lib/aspera/preview/file_types.rb +24 -38
- data/lib/aspera/preview/terminal.rb +95 -29
- data/lib/aspera/preview/utils.rb +6 -5
- data/lib/aspera/products/connect.rb +3 -3
- data/lib/aspera/rest.rb +54 -39
- data/lib/aspera/rest_error_analyzer.rb +4 -4
- data/lib/aspera/ssh.rb +10 -6
- data/lib/aspera/ssl.rb +41 -0
- data/lib/aspera/sync/conf.schema.yaml +184 -36
- data/lib/aspera/sync/database.rb +2 -1
- data/lib/aspera/sync/operations.rb +128 -72
- data/lib/aspera/transfer/parameters.rb +9 -10
- data/lib/aspera/transfer/spec.rb +2 -3
- data/lib/aspera/transfer/spec.schema.yaml +52 -22
- data/lib/aspera/transfer/spec_doc.rb +20 -30
- data/lib/aspera/uri_reader.rb +18 -4
- data/lib/transferd_pb.rb +2 -2
- data.tar.gz.sig +0 -0
- metadata +34 -6
- metadata.gz.sig +0 -0
|
@@ -17,13 +17,13 @@ module Aspera
|
|
|
17
17
|
nagios = Nagios.new
|
|
18
18
|
begin
|
|
19
19
|
api = Api::Alee.new(nil, nil, version: 'ping')
|
|
20
|
-
|
|
21
|
-
raise "unexpected response: #{
|
|
20
|
+
http = api.read(nil, ret: :resp)
|
|
21
|
+
raise "unexpected response: #{http.body}" unless http.body.eql?('pong')
|
|
22
22
|
nagios.add_ok('api', 'answered ok')
|
|
23
23
|
rescue StandardError => e
|
|
24
24
|
nagios.add_critical('api', e.to_s)
|
|
25
25
|
end
|
|
26
|
-
|
|
26
|
+
Main.result_object_list(nagios.status_list)
|
|
27
27
|
when :entitlement
|
|
28
28
|
entitlement_id = options.get_option(:username, mandatory: true)
|
|
29
29
|
customer_id = options.get_option(:password, mandatory: true)
|
|
@@ -62,6 +62,7 @@ module Aspera
|
|
|
62
62
|
'Aspera on Cloud'
|
|
63
63
|
end
|
|
64
64
|
|
|
65
|
+
# @return [Hash,NilClass]
|
|
65
66
|
def detect(base_url)
|
|
66
67
|
# no protocol ?
|
|
67
68
|
base_url = "https://#{base_url}" unless base_url.match?(%r{^[a-z]{1,6}://})
|
|
@@ -69,9 +70,9 @@ module Aspera
|
|
|
69
70
|
base_url = "#{base_url}.#{Api::AoC::SAAS_DOMAIN_PROD}" unless base_url.include?('.')
|
|
70
71
|
# AoC is only https
|
|
71
72
|
return unless base_url.start_with?('https://')
|
|
72
|
-
|
|
73
|
-
return if
|
|
74
|
-
redirect_uri = URI.parse(
|
|
73
|
+
location = Rest.new(base_url: base_url, redirect_max: 0).call(operation: 'GET', subpath: 'auth/ping', exception: false, ret: :resp)['Location']
|
|
74
|
+
return if location.nil?
|
|
75
|
+
redirect_uri = URI.parse(location)
|
|
75
76
|
od = Api::AoC.split_org_domain(URI.parse(base_url))
|
|
76
77
|
return unless redirect_uri.path.end_with?("oauth2/#{od[:organization]}/login")
|
|
77
78
|
# either in standard domain, or product name in page
|
|
@@ -81,8 +82,10 @@ module Aspera
|
|
|
81
82
|
}
|
|
82
83
|
end
|
|
83
84
|
|
|
84
|
-
#
|
|
85
|
-
# @
|
|
85
|
+
# Get folder path that does not exist
|
|
86
|
+
# @param base [String] Base folder path
|
|
87
|
+
# @param always [Boolean] `true` always add number, `false` only if base folder already exists
|
|
88
|
+
# @return [String] Folder path that does not exist, with possible .<number> extension
|
|
86
89
|
def next_available_folder(base, always: false)
|
|
87
90
|
counter = always ? 1 : 0
|
|
88
91
|
loop do
|
|
@@ -95,27 +98,26 @@ module Aspera
|
|
|
95
98
|
# Get folder path that does not exist
|
|
96
99
|
# If it exists, an extension is added
|
|
97
100
|
# or a sequential number if extension == :seq
|
|
98
|
-
# @param
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
else
|
|
111
|
-
folder
|
|
112
|
-
end
|
|
101
|
+
# @param package_info [Hash] Package information
|
|
102
|
+
# @param destination_folder [String] Base folder
|
|
103
|
+
# @param fld. [Array] List of fields of package
|
|
104
|
+
def unique_folder(package_info, destination_folder, fld: nil, seq: false, opt: false)
|
|
105
|
+
Aspera.assert_array_all(fld, String, type: Cli::BadArgument){'fld'}
|
|
106
|
+
Aspera.assert([1, 2].include?(fld.length)){'fld must have 1 or 2 elements'}
|
|
107
|
+
folder = Environment.instance.sanitized_filename(package_info[fld[0]])
|
|
108
|
+
if seq
|
|
109
|
+
folder = next_available_folder(folder, always: !opt)
|
|
110
|
+
elsif fld[1] && (Dir.exist?(folder) || !opt)
|
|
111
|
+
# NOTE: it might already exist
|
|
112
|
+
folder = "#{folder}.#{Environment.instance.sanitized_filename(fld[1])}"
|
|
113
113
|
end
|
|
114
|
+
puts("sub= #{folder}")
|
|
115
|
+
File.join(destination_folder, folder)
|
|
114
116
|
end
|
|
115
117
|
end
|
|
116
118
|
|
|
117
119
|
# @param wizard [Wizard] The wizard object
|
|
118
|
-
# @param app_url [
|
|
120
|
+
# @param app_url [String] Tested URL
|
|
119
121
|
# @return [Hash] :preset_value, :test_args
|
|
120
122
|
def wizard(wizard, app_url)
|
|
121
123
|
pub_link_info = Api::AoC.link_info(app_url)
|
|
@@ -132,7 +134,7 @@ module Aspera
|
|
|
132
134
|
test_args: 'organization'
|
|
133
135
|
}
|
|
134
136
|
end
|
|
135
|
-
options.declare(:use_generic_client, 'Wizard: AoC: use global or org specific jwt client id',
|
|
137
|
+
options.declare(:use_generic_client, 'Wizard: AoC: use global or org specific jwt client id', allowed: Allowed::TYPES_BOOLEAN, default: Api::AoC.saas_url?(app_url))
|
|
136
138
|
options.parse_options!
|
|
137
139
|
# make username mandatory for jwt, this triggers interactive input
|
|
138
140
|
wiz_username = options.get_option(:username, mandatory: true)
|
|
@@ -174,7 +176,7 @@ module Aspera
|
|
|
174
176
|
auto_set_jwt = true
|
|
175
177
|
Aspera.error_not_implemented
|
|
176
178
|
# aoc_api.oauth.grant_method = :web
|
|
177
|
-
# aoc_api.oauth.scope = Api::AoC::
|
|
179
|
+
# aoc_api.oauth.scope = Api::AoC::Scope::ADMIN
|
|
178
180
|
# aoc_api.oauth.specific_parameters[:redirect_uri] = REDIRECT_LOCALHOST
|
|
179
181
|
end
|
|
180
182
|
myself = aoc_api.read('self')
|
|
@@ -205,48 +207,58 @@ module Aspera
|
|
|
205
207
|
@cache_workspace_info = nil
|
|
206
208
|
@cache_home_node_file = nil
|
|
207
209
|
@cache_api_aoc = nil
|
|
208
|
-
|
|
209
|
-
options.declare(:
|
|
210
|
-
options.declare(:
|
|
211
|
-
options.declare(:
|
|
210
|
+
@scope = Api::AoC::Scope::USER
|
|
211
|
+
options.declare(:workspace, 'Name of workspace', allowed: [String, NilClass], default: Api::AoC::DEFAULT_WORKSPACE)
|
|
212
|
+
options.declare(:new_user_option, 'New user creation option for unknown package recipients', allowed: Hash)
|
|
213
|
+
options.declare(:validate_metadata, 'Validate shared inbox metadata', allowed: Allowed::TYPES_BOOLEAN, default: true)
|
|
214
|
+
options.declare(:package_folder, 'Handling of reception of packages in folders', allowed: Hash, default: {})
|
|
212
215
|
options.parse_options!
|
|
213
216
|
# add node plugin options (for manual)
|
|
214
217
|
Node.declare_options(options)
|
|
215
218
|
end
|
|
216
219
|
|
|
220
|
+
# Change API scope for subsequent calls, re-instantiate API object
|
|
221
|
+
# @param new_scope [String] New scope
|
|
222
|
+
def change_api_scope(new_scope)
|
|
223
|
+
@cache_api_aoc = nil
|
|
224
|
+
@scope = new_scope
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# create an API object with the same options, but with a different subpath
|
|
228
|
+
# @param aoc_base_path [String] New subpath
|
|
229
|
+
# @return [Api::AoC] API object for AoC (is Rest)
|
|
217
230
|
def api_from_options(aoc_base_path)
|
|
218
|
-
# create an API object with the same options, but with a different subpath
|
|
219
231
|
return new_with_options(
|
|
220
232
|
Api::AoC,
|
|
221
|
-
|
|
233
|
+
kwargs: {
|
|
234
|
+
scope: @scope,
|
|
222
235
|
subpath: aoc_base_path,
|
|
223
236
|
secret_finder: config
|
|
224
237
|
},
|
|
225
|
-
|
|
226
|
-
scope: Api::AoC::SCOPE_FILES_USER,
|
|
238
|
+
option: {
|
|
227
239
|
workspace: nil
|
|
228
240
|
}
|
|
229
241
|
)
|
|
230
242
|
end
|
|
231
243
|
|
|
232
244
|
# AoC Rest object
|
|
233
|
-
# @return [Rest
|
|
245
|
+
# @return [Api::AoC] API object for AoC (is Rest)
|
|
234
246
|
def aoc_api
|
|
235
247
|
if @cache_api_aoc.nil?
|
|
236
248
|
@cache_api_aoc = api_from_options(Api::AoC::API_V1)
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
transfer.httpgw_url_cb = lambda{organization['http_gateway_server_url']}
|
|
249
|
+
transfer.httpgw_url_cb = lambda do
|
|
250
|
+
organization = @cache_api_aoc.read('organization')
|
|
240
251
|
# @cache_api_aoc.current_user_info['connect_disabled']
|
|
252
|
+
organization['http_gateway_server_url'] if organization['http_gateway_enabled'] && organization['http_gateway_server_url']
|
|
241
253
|
end
|
|
242
254
|
end
|
|
243
255
|
return @cache_api_aoc
|
|
244
256
|
end
|
|
245
257
|
|
|
246
258
|
# Generate or update Hash with workspace id and name (option), if not already set
|
|
247
|
-
# @param hash [Hash,
|
|
248
|
-
# @param string [
|
|
249
|
-
# @param name [
|
|
259
|
+
# @param hash [Hash,nil] Optional base hash (modified)
|
|
260
|
+
# @param string [Boolean] true to set key as string, else as symbol
|
|
261
|
+
# @param name [Boolean] include name
|
|
250
262
|
# @return [Hash] with key `workspace_[id,name]` (symbol or string) only if defined
|
|
251
263
|
def workspace_id_hash(hash: nil, string: false, name: false)
|
|
252
264
|
info = aoc_api.workspace
|
|
@@ -288,7 +300,7 @@ module Aspera
|
|
|
288
300
|
query = query_read_delete(default: default_query)
|
|
289
301
|
# caller may add specific modifications or checks to query
|
|
290
302
|
yield(query) if block_given?
|
|
291
|
-
result = aoc_api.read_with_paging(resource_class_path,
|
|
303
|
+
result = aoc_api.read_with_paging(resource_class_path, base_query.merge(query).compact, formatter: formatter)
|
|
292
304
|
return Main.result_object_list(result[:items], fields: fields, total: result[:total])
|
|
293
305
|
end
|
|
294
306
|
|
|
@@ -313,14 +325,17 @@ module Aspera
|
|
|
313
325
|
Aspera.assert_type(query, Hash){'query'}
|
|
314
326
|
PACKAGE_RECEIVED_BASE_QUERY.each{ |k, v| query[k] = v unless query.key?(k)}
|
|
315
327
|
resolve_dropbox_name_default_ws_id(query)
|
|
316
|
-
return aoc_api.read_with_paging('packages', query
|
|
328
|
+
return aoc_api.read_with_paging('packages', query.compact, formatter: formatter)
|
|
317
329
|
end
|
|
318
330
|
|
|
319
331
|
NODE4_EXT_COMMANDS = %i[transfer].concat(Node::COMMANDS_GEN4).freeze
|
|
320
332
|
private_constant :NODE4_EXT_COMMANDS
|
|
321
333
|
|
|
322
|
-
#
|
|
323
|
-
# @param
|
|
334
|
+
# Execute a node gen4 command
|
|
335
|
+
# @param command_repo [Symbol] command to execute
|
|
336
|
+
# @param node_id [String] Node identifier
|
|
337
|
+
# @param file_id [String] Root file id for the operation (can be AK root, or other, e.g. package, or link). If `nil` use AK root file id.
|
|
338
|
+
# @param scope [String] node scope (Node::SCOPE_<USER|ADMIN>), or nil (requires secret)
|
|
324
339
|
def execute_nodegen4_command(command_repo, node_id, file_id: nil, scope: nil)
|
|
325
340
|
top_node_api = aoc_api.node_api_from(
|
|
326
341
|
node_id: node_id,
|
|
@@ -374,6 +389,7 @@ module Aspera
|
|
|
374
389
|
Aspera.error_unreachable_line
|
|
375
390
|
end
|
|
376
391
|
|
|
392
|
+
# @param resource_type [Symbol] One of ADMIN_OBJECTS
|
|
377
393
|
def execute_resource_action(resource_type)
|
|
378
394
|
# get path on API, resource type is singular, but api is plural
|
|
379
395
|
resource_class_path =
|
|
@@ -391,8 +407,9 @@ module Aspera
|
|
|
391
407
|
global_operations = %i[create list]
|
|
392
408
|
supported_operations = %i[show modify]
|
|
393
409
|
supported_operations.push(:delete, *global_operations) unless singleton_object
|
|
394
|
-
supported_operations.push(:do) if resource_type.eql?(:node)
|
|
410
|
+
supported_operations.push(:do, :bearer_token) if resource_type.eql?(:node)
|
|
395
411
|
supported_operations.push(:set_pub_key) if resource_type.eql?(:client)
|
|
412
|
+
supported_operations.push(:shared_folder, :dropbox) if resource_type.eql?(:workspace)
|
|
396
413
|
command = options.get_next_command(supported_operations)
|
|
397
414
|
# require identifier for non global commands
|
|
398
415
|
if !singleton_object && !global_operations.include?(command)
|
|
@@ -420,7 +437,7 @@ module Aspera
|
|
|
420
437
|
when :client_registration_token then default_fields.push('value', 'data.client_subject_scopes', 'created_at')
|
|
421
438
|
when :contact
|
|
422
439
|
default_fields = %w[source_type source_id name email]
|
|
423
|
-
default_query = {'include_only_user_personal_contacts' => true} if
|
|
440
|
+
default_query = {'include_only_user_personal_contacts' => true} if @scope == Api::AoC::Scope::USER
|
|
424
441
|
when :node then default_fields.push('name', 'host', 'access_key')
|
|
425
442
|
when :operation then default_fields = nil
|
|
426
443
|
when :short_link then default_fields.push('short_url', 'data.url_token_data.purpose')
|
|
@@ -453,18 +470,74 @@ module Aspera
|
|
|
453
470
|
return Main.result_success
|
|
454
471
|
when :do
|
|
455
472
|
command_repo = options.get_next_command(NODE4_EXT_COMMANDS)
|
|
456
|
-
return execute_nodegen4_command(command_repo, res_id)
|
|
473
|
+
return execute_nodegen4_command(command_repo, res_id, scope: Api::Node::SCOPE_ADMIN)
|
|
474
|
+
when :bearer_token
|
|
475
|
+
node_api = aoc_api.node_api_from(
|
|
476
|
+
node_id: res_id,
|
|
477
|
+
scope: options.get_next_argument('scope')
|
|
478
|
+
)
|
|
479
|
+
return Main.result_text(node_api.oauth.authorization)
|
|
480
|
+
when :dropbox
|
|
481
|
+
command_shared = options.get_next_command(%i[list])
|
|
482
|
+
case command_shared
|
|
483
|
+
when :list
|
|
484
|
+
query = options.get_option(:query) || {}
|
|
485
|
+
res_data = aoc_api.read('dropboxes', query.merge({'workspace_id'=>res_id}))
|
|
486
|
+
return Main.result_object_list(res_data, fields: %w[id name description])
|
|
487
|
+
end
|
|
488
|
+
when :shared_folder
|
|
489
|
+
query = options.get_option(:query) || Api::AoC.workspace_access(res_id).merge({'admin' => true})
|
|
490
|
+
shared_folders = aoc_api.read_with_paging("#{resource_instance_path}/permissions", query)[:items]
|
|
491
|
+
# inside a workspace
|
|
492
|
+
command_shared = options.get_next_command(%i[list member])
|
|
493
|
+
case command_shared
|
|
494
|
+
when :list
|
|
495
|
+
return Main.result_object_list(shared_folders, fields: %w[id node_name node_id file_id file.path tags.aspera.files.workspace.share_as])
|
|
496
|
+
when :member
|
|
497
|
+
shared_folder_id = instance_identifier
|
|
498
|
+
shared_folder = shared_folders.find{ |i| i['id'].eql?(shared_folder_id)}
|
|
499
|
+
Aspera.assert(shared_folder)
|
|
500
|
+
command_shared_member = options.get_next_command(%i[list])
|
|
501
|
+
case command_shared_member
|
|
502
|
+
when :list
|
|
503
|
+
node_api = aoc_api.node_api_from(
|
|
504
|
+
node_id: shared_folder['node_id'],
|
|
505
|
+
workspace_id: res_id,
|
|
506
|
+
workspace_name: nil,
|
|
507
|
+
scope: Api::Node::SCOPE_USER
|
|
508
|
+
)
|
|
509
|
+
result = node_api.read(
|
|
510
|
+
'permissions',
|
|
511
|
+
{'file_id' => shared_folder['file_id'], 'tag' => "aspera.files.workspace.id=#{res_id}"}
|
|
512
|
+
)
|
|
513
|
+
result.each do |item|
|
|
514
|
+
item['member'] = begin
|
|
515
|
+
if Api::AoC.workspace_access?(item)
|
|
516
|
+
{'name'=>'[Internal permission]'}
|
|
517
|
+
else
|
|
518
|
+
aoc_api.read("admin/#{item['access_type']}s/#{item['access_id']}") rescue {'name': 'not found'}
|
|
519
|
+
end
|
|
520
|
+
rescue => e
|
|
521
|
+
{'name'=>e.to_s}
|
|
522
|
+
end
|
|
523
|
+
end
|
|
524
|
+
# TODO : read users and group name and add, if query "include_members"
|
|
525
|
+
return Main.result_object_list(result, fields: %w[access_type access_id access_level last_updated_at member.name member.email member.system_group_type member.system_group])
|
|
526
|
+
end
|
|
527
|
+
end
|
|
457
528
|
else Aspera.error_unexpected_value(command)
|
|
458
529
|
end
|
|
459
530
|
end
|
|
460
531
|
|
|
461
|
-
ADMIN_ACTIONS = %i[ats resource usage_reports analytics subscription auth_providers].concat(ADMIN_OBJECTS).freeze
|
|
532
|
+
ADMIN_ACTIONS = %i[ats bearer_token resource usage_reports analytics subscription auth_providers].concat(ADMIN_OBJECTS).freeze
|
|
462
533
|
|
|
463
534
|
def execute_admin_action
|
|
464
|
-
#
|
|
465
|
-
|
|
535
|
+
# change scope to admin
|
|
536
|
+
change_api_scope(Api::AoC::Scope::ADMIN)
|
|
466
537
|
command_admin = options.get_next_command(ADMIN_ACTIONS)
|
|
467
538
|
case command_admin
|
|
539
|
+
when :bearer_token
|
|
540
|
+
return Main.result_text(aoc_api.oauth.authorization)
|
|
468
541
|
when :resource
|
|
469
542
|
Log.log.warn('resource command is deprecated (4.18), directly use the specific command instead')
|
|
470
543
|
return execute_resource_action(options.get_next_argument('resource', accept_list: ADMIN_OBJECTS))
|
|
@@ -593,13 +666,13 @@ module Aspera
|
|
|
593
666
|
when :ats
|
|
594
667
|
ats_api = Rest.new(**aoc_api.params.deep_merge({
|
|
595
668
|
base_url: "#{aoc_api.base_url}/admin/ats/pub/v1",
|
|
596
|
-
auth: {scope: Api::AoC::
|
|
669
|
+
auth: {params: {scope: Api::AoC::Scope::ADMIN_USER}}
|
|
597
670
|
}))
|
|
598
|
-
return Ats.new(context: context).
|
|
671
|
+
return Ats.new(context: context, api: ats_api).execute_action
|
|
599
672
|
when :analytics
|
|
600
673
|
analytics_api = Rest.new(**aoc_api.params.deep_merge({
|
|
601
674
|
base_url: "#{aoc_api.base_url.gsub('/api/v1', '')}/analytics/v2",
|
|
602
|
-
auth: {scope: Api::AoC::
|
|
675
|
+
auth: {params: {scope: Api::AoC::Scope::ADMIN_USER}}
|
|
603
676
|
}))
|
|
604
677
|
command_analytics = options.get_next_command(%i[application_events transfers files])
|
|
605
678
|
case command_analytics
|
|
@@ -624,13 +697,13 @@ module Aspera
|
|
|
624
697
|
start_date_persistency = PersistencyActionOnce.new(
|
|
625
698
|
manager: persistency,
|
|
626
699
|
data: saved_date,
|
|
627
|
-
id: IdGenerator.from_list(
|
|
700
|
+
id: IdGenerator.from_list(
|
|
628
701
|
'aoc_ana_date',
|
|
629
702
|
options.get_option(:url, mandatory: true),
|
|
630
703
|
aoc_api.workspace[:name],
|
|
631
704
|
event_resource_type.to_s,
|
|
632
705
|
event_resource_id
|
|
633
|
-
|
|
706
|
+
)
|
|
634
707
|
)
|
|
635
708
|
start_date_time = saved_date.first
|
|
636
709
|
stop_date_time = Time.now.utc.strftime('%FT%T.%LZ')
|
|
@@ -736,7 +809,7 @@ module Aspera
|
|
|
736
809
|
}
|
|
737
810
|
return result_list('short_links', fields: Formatter.all_but('data'), base_query: list_params) if command.eql?(:list)
|
|
738
811
|
one_id = instance_identifier
|
|
739
|
-
found = aoc_api.read_with_paging('short_links',
|
|
812
|
+
found = aoc_api.read_with_paging('short_links', list_params, formatter: formatter)[:items].find{ |item| item['id'].eql?(one_id)}
|
|
740
813
|
raise Cli::BadIdentifier.new('Short link', one_id) if found.nil?
|
|
741
814
|
return Main.result_single_object(found, fields: Formatter.all_but('data'))
|
|
742
815
|
when :modify
|
|
@@ -783,9 +856,10 @@ module Aspera
|
|
|
783
856
|
manager: persistency,
|
|
784
857
|
data: [],
|
|
785
858
|
id: IdGenerator.from_list(
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
859
|
+
'aoc_recv',
|
|
860
|
+
options.get_option(:url, mandatory: true),
|
|
861
|
+
aoc_api.workspace[:id],
|
|
862
|
+
aoc_api.additional_persistence_ids
|
|
789
863
|
)
|
|
790
864
|
)
|
|
791
865
|
end
|
|
@@ -886,7 +960,7 @@ module Aspera
|
|
|
886
960
|
# enforce workspace id from link (should be already ok, but in case user wanted to override)
|
|
887
961
|
package_data['workspace_id'] = aoc_api.public_link['data']['workspace_id']
|
|
888
962
|
end
|
|
889
|
-
package_data['encryption_at_rest'] = true if transfer.
|
|
963
|
+
package_data['encryption_at_rest'] = true if transfer.user_transfer_spec['content_protection'].eql?('encrypt')
|
|
890
964
|
# transfer may raise an error
|
|
891
965
|
created_package = aoc_api.create_package_simple(package_data, option_validate, new_user_option)
|
|
892
966
|
Main.result_transfer(transfer.start(created_package[:spec], rest_token: created_package[:node]))
|
|
@@ -921,13 +995,8 @@ module Aspera
|
|
|
921
995
|
end
|
|
922
996
|
# download all files, or specified list only
|
|
923
997
|
ts_paths = transfer.ts_source_paths(default: ['.'])
|
|
924
|
-
per_package_def = options.get_option(:package_folder)
|
|
925
|
-
|
|
926
|
-
raise Cli::BadArgument, "Invalid package folder option : #{per_package_def}" unless per_package_def =~ /\A([^+]+)(?:\+([^?]+)(\?)?)?\z/
|
|
927
|
-
per_package_field1 = Regexp.last_match(1)
|
|
928
|
-
per_package_field2 = Regexp.last_match(2)
|
|
929
|
-
per_package_sub_always = Regexp.last_match(3).nil?
|
|
930
|
-
end
|
|
998
|
+
per_package_def = options.get_option(:package_folder).symbolize_keys
|
|
999
|
+
save_metadata = per_package_def.delete(:inf)
|
|
931
1000
|
# get value outside of loop
|
|
932
1001
|
destination_folder = transfer.destination_folder(Transfer::Spec::DIRECTION_RECEIVE)
|
|
933
1002
|
result_transfer = []
|
|
@@ -943,23 +1012,14 @@ module Aspera
|
|
|
943
1012
|
Transfer::Spec::DIRECTION_RECEIVE,
|
|
944
1013
|
{'paths'=> ts_paths}
|
|
945
1014
|
)
|
|
946
|
-
unless per_package_def.
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
destination_folder,
|
|
950
|
-
Environment.instance.sanitized_filename(package_info[per_package_field1])
|
|
951
|
-
)
|
|
952
|
-
transfer.option_transfer_spec['destination_root'] = self.class.unique_folder(
|
|
953
|
-
folder,
|
|
954
|
-
extension: per_package_field2.eql?('seq') ? :seq : package_info[per_package_field2],
|
|
955
|
-
always: per_package_sub_always
|
|
956
|
-
)
|
|
957
|
-
end
|
|
958
|
-
formatter.display_status(%Q{Downloading package: [#{package_info['id']}] "#{package_info['name']}" to [#{destination_folder}]})
|
|
1015
|
+
transfer.user_transfer_spec['destination_root'] = self.class.unique_folder(package_info, destination_folder, **per_package_def) unless per_package_def.empty?
|
|
1016
|
+
dest_folder = transfer.user_transfer_spec['destination_root'] || destination_folder
|
|
1017
|
+
formatter.display_status(%Q{Downloading package: [#{package_info['id']}] "#{package_info['name']}" to [#{dest_folder}]})
|
|
959
1018
|
statuses = transfer.start(
|
|
960
1019
|
transfer_spec,
|
|
961
1020
|
rest_token: package_node_api
|
|
962
1021
|
)
|
|
1022
|
+
File.write(File.join(dest_folder, "#{package_id}.info.json"), package_info.to_json) if save_metadata
|
|
963
1023
|
result_transfer.push({'package' => package_id, Main::STATUS_FIELD => statuses})
|
|
964
1024
|
# update skip list only if all transfer sessions completed
|
|
965
1025
|
if skip_ids_persistency && TransferAgent.session_status(statuses).eql?(:success)
|
|
@@ -1036,6 +1096,7 @@ module Aspera
|
|
|
1036
1096
|
end
|
|
1037
1097
|
end
|
|
1038
1098
|
when :automation
|
|
1099
|
+
change_api_scope(Api::AoC::Scope::ADMIN_USER)
|
|
1039
1100
|
Log.log.warn('BETA: work under progress')
|
|
1040
1101
|
# automation api is not in the same place
|
|
1041
1102
|
automation_api = Rest.new(**aoc_api.params, base_url: aoc_api.base_url.gsub('/api/', '/automation/'))
|
|
@@ -18,10 +18,10 @@ module Aspera
|
|
|
18
18
|
# columns for list of cloud providers
|
|
19
19
|
CLOUD_TABLE = %w[id name].freeze
|
|
20
20
|
private_constant :CLOUD_TABLE
|
|
21
|
-
def initialize(**
|
|
22
|
-
super
|
|
23
|
-
@
|
|
24
|
-
@
|
|
21
|
+
def initialize(api: nil, **base_args)
|
|
22
|
+
super(**base_args)
|
|
23
|
+
@ats_api_open = Api::Ats.new
|
|
24
|
+
@ats_api_auth = api
|
|
25
25
|
options.declare(:ibm_api_key, 'IBM API key, see https://cloud.ibm.com/iam/apikeys')
|
|
26
26
|
options.declare(:instance, 'ATS instance in ibm cloud')
|
|
27
27
|
options.declare(:ats_key, 'ATS key identifier (ats_xxx)')
|
|
@@ -36,13 +36,13 @@ module Aspera
|
|
|
36
36
|
# TODO: provide list ?
|
|
37
37
|
cloud = options.get_option(:cloud, mandatory: true).upcase
|
|
38
38
|
region = options.get_option(:region, mandatory: true)
|
|
39
|
-
return @
|
|
39
|
+
return @ats_api_open.read("servers/#{cloud}/#{region}")
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
# require api key only if needed
|
|
43
|
-
def
|
|
44
|
-
return @
|
|
45
|
-
@
|
|
43
|
+
def ats_api
|
|
44
|
+
return @ats_api_auth unless @ats_api_auth.nil?
|
|
45
|
+
@ats_api_auth = Rest.new(
|
|
46
46
|
base_url: "#{Api::Ats::SERVICE_BASE_URL}/pub/v1",
|
|
47
47
|
auth: {
|
|
48
48
|
type: :basic,
|
|
@@ -73,10 +73,10 @@ module Aspera
|
|
|
73
73
|
when 'ibm-s3'
|
|
74
74
|
server_data2 = nil
|
|
75
75
|
if server_data.nil?
|
|
76
|
-
server_data2 = @
|
|
76
|
+
server_data2 = @ats_api_open.all_servers.find{ |s| s['id'].eql?(params['transfer_server_id'])}
|
|
77
77
|
raise "no such transfer server id: #{params['transfer_server_id']}" if server_data2.nil?
|
|
78
78
|
else
|
|
79
|
-
server_data2 = @
|
|
79
|
+
server_data2 = @ats_api_open.all_servers.find do |s|
|
|
80
80
|
s['cloud'].eql?(server_data['cloud']) &&
|
|
81
81
|
s['region'].eql?(server_data['region']) &&
|
|
82
82
|
s.key?('s3_authentication_endpoint')
|
|
@@ -88,31 +88,31 @@ module Aspera
|
|
|
88
88
|
params['storage']['endpoint'] = server_data2['s3_authentication_endpoint'] if !params['storage'].key?('authentication_endpoint')
|
|
89
89
|
end
|
|
90
90
|
end
|
|
91
|
-
res =
|
|
91
|
+
res = ats_api.create('access_keys', params)
|
|
92
92
|
return Main.result_single_object(res)
|
|
93
93
|
# TODO : action : modify, with "PUT"
|
|
94
94
|
when :list
|
|
95
95
|
params = query_read_delete(default: {'offset' => 0, 'max_results' => 1000})
|
|
96
|
-
res =
|
|
96
|
+
res = ats_api.read('access_keys', params)
|
|
97
97
|
return Main.result_object_list(res['data'], fields: ['name', 'id', 'created.at', 'modified.at'])
|
|
98
98
|
when :show
|
|
99
|
-
res =
|
|
99
|
+
res = ats_api.read("access_keys/#{access_key_id}")
|
|
100
100
|
return Main.result_single_object(res)
|
|
101
101
|
when :modify
|
|
102
102
|
params = value_create_modify(command: command)
|
|
103
103
|
params['id'] = access_key_id
|
|
104
|
-
|
|
104
|
+
ats_api.update("access_keys/#{access_key_id}", params)
|
|
105
105
|
return Main.result_status('modified')
|
|
106
106
|
when :entitlement
|
|
107
|
-
ak =
|
|
107
|
+
ak = ats_api.read("access_keys/#{access_key_id}")
|
|
108
108
|
api_bss = Api::Alee.new(ak['license']['entitlement_id'], ak['license']['customer_id'])
|
|
109
109
|
return Main.result_single_object(api_bss.read('entitlement'))
|
|
110
110
|
when :delete
|
|
111
|
-
|
|
111
|
+
ats_api.delete("access_keys/#{access_key_id}")
|
|
112
112
|
return Main.result_status("deleted #{access_key_id}")
|
|
113
113
|
when :node
|
|
114
|
-
ak_data =
|
|
115
|
-
server_data = @
|
|
114
|
+
ak_data = ats_api.read("access_keys/#{access_key_id}")
|
|
115
|
+
server_data = @ats_api_open.all_servers.find{ |i| i['id'].start_with?(ak_data['transfer_server_id'])}
|
|
116
116
|
raise Cli::Error, 'no such server found' if server_data.nil?
|
|
117
117
|
node_url = server_data['transfer_setup_url']
|
|
118
118
|
api_node = Api::Node.new(
|
|
@@ -126,7 +126,7 @@ module Aspera
|
|
|
126
126
|
command = options.get_next_command(Node::COMMANDS_GEN4)
|
|
127
127
|
return Node.new(context: context, api: api_node).execute_command_gen4(command, ak_data['root_file_id'])
|
|
128
128
|
when :cluster
|
|
129
|
-
ats_url =
|
|
129
|
+
ats_url = ats_api.base_url
|
|
130
130
|
api_ak_auth = Rest.new(
|
|
131
131
|
base_url: ats_url,
|
|
132
132
|
auth: {
|
|
@@ -140,19 +140,19 @@ module Aspera
|
|
|
140
140
|
end
|
|
141
141
|
end
|
|
142
142
|
|
|
143
|
-
def
|
|
143
|
+
def execute_action_cluster_open
|
|
144
144
|
command = options.get_next_command(%i[clouds list show])
|
|
145
145
|
case command
|
|
146
146
|
when :clouds
|
|
147
|
-
return Main.result_object_list(@
|
|
147
|
+
return Main.result_object_list(@ats_api_open.cloud_names.map{ |k, v| CLOUD_TABLE.zip([k, v]).to_h})
|
|
148
148
|
when :list
|
|
149
|
-
return Main.result_object_list(@
|
|
149
|
+
return Main.result_object_list(@ats_api_open.all_servers, fields: %w[id cloud region])
|
|
150
150
|
when :show
|
|
151
151
|
if options.get_option(:cloud) || options.get_option(:region)
|
|
152
152
|
server_data = server_by_cloud_region
|
|
153
153
|
else
|
|
154
154
|
server_id = instance_identifier
|
|
155
|
-
server_data = @
|
|
155
|
+
server_data = @ats_api_open.all_servers.find{ |i| i['id'].eql?(server_id)}
|
|
156
156
|
raise BadIdentifier.new('server', server_id) if server_data.nil?
|
|
157
157
|
end
|
|
158
158
|
return Main.result_single_object(server_data)
|
|
@@ -170,7 +170,9 @@ module Aspera
|
|
|
170
170
|
# does not work: base_url: 'https://iam.cloud.ibm.com/identity',
|
|
171
171
|
grant_type: 'urn:ibm:params:oauth:grant-type:apikey',
|
|
172
172
|
response_type: 'cloud_iam',
|
|
173
|
-
|
|
173
|
+
params: {
|
|
174
|
+
apikey: options.get_option(:ibm_api_key, mandatory: true)
|
|
175
|
+
}
|
|
174
176
|
}
|
|
175
177
|
)
|
|
176
178
|
end
|
|
@@ -213,31 +215,23 @@ module Aspera
|
|
|
213
215
|
ACTIONS = %i[cluster access_key api_key aws_trust_policy].freeze
|
|
214
216
|
|
|
215
217
|
# called for legacy and AoC
|
|
216
|
-
def
|
|
218
|
+
def execute_action
|
|
217
219
|
actions = ACTIONS.dup
|
|
218
|
-
actions.delete(:api_key) unless
|
|
220
|
+
actions.delete(:api_key) unless @ats_api_auth.nil?
|
|
219
221
|
command = options.get_next_command(actions)
|
|
220
|
-
@ats_api_pub_v1_cache = ats_api_arg
|
|
221
|
-
# keep as member variable as we may want to use the api in AoC name space
|
|
222
|
-
@ats_api_pub = Api::Ats.new
|
|
223
222
|
case command
|
|
224
223
|
when :cluster # display general ATS cluster information, this uses public API, no auth
|
|
225
|
-
return
|
|
224
|
+
return execute_action_cluster_open
|
|
226
225
|
when :access_key
|
|
227
226
|
return execute_action_access_key
|
|
228
227
|
when :api_key # manage credential to access ATS API
|
|
229
228
|
return execute_action_api_key
|
|
230
229
|
when :aws_trust_policy
|
|
231
|
-
res =
|
|
230
|
+
res = ats_api.read('aws/trustpolicy', {region: options.get_option(:region, mandatory: true)})
|
|
232
231
|
return Main.result_single_object(res)
|
|
233
232
|
else Aspera.error_unexpected_value(command)
|
|
234
233
|
end
|
|
235
234
|
end
|
|
236
|
-
|
|
237
|
-
# called for legacy ATS only
|
|
238
|
-
def execute_action
|
|
239
|
-
execute_action_gen(nil)
|
|
240
|
-
end
|
|
241
235
|
end
|
|
242
236
|
end
|
|
243
237
|
end
|