aspera-cli 4.8.0 → 4.9.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/README.md +445 -160
- data/docs/test_env.conf +1 -5
- data/examples/dascli +1 -4
- data/examples/{transfer.rb → node.rb} +17 -46
- data/examples/server.rb +93 -0
- data/lib/aspera/aoc.rb +4 -2
- data/lib/aspera/ats_api.rb +3 -1
- data/lib/aspera/cli/extended_value.rb +1 -0
- data/lib/aspera/cli/formater.rb +3 -1
- data/lib/aspera/cli/info.rb +1 -1
- data/lib/aspera/cli/main.rb +14 -11
- data/lib/aspera/cli/manager.rb +4 -4
- data/lib/aspera/cli/plugin.rb +50 -9
- data/lib/aspera/cli/plugins/aoc.rb +88 -52
- data/lib/aspera/cli/plugins/config.rb +5 -0
- data/lib/aspera/cli/plugins/faspex.rb +5 -4
- data/lib/aspera/cli/plugins/node.rb +3 -2
- data/lib/aspera/cli/plugins/server.rb +7 -108
- data/lib/aspera/cli/plugins/shares.rb +21 -1
- data/lib/aspera/cli/transfer_agent.rb +21 -14
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/environment.rb +15 -2
- data/lib/aspera/fasp/agent_base.rb +9 -7
- data/lib/aspera/fasp/installation.rb +15 -19
- data/lib/aspera/fasp/parameters.rb +38 -30
- data/lib/aspera/fasp/parameters.yaml +69 -17
- data/lib/aspera/hash_ext.rb +14 -2
- data/lib/aspera/id_generator.rb +12 -10
- data/lib/aspera/keychain/encrypted_hash.rb +3 -3
- data/lib/aspera/log.rb +1 -1
- data/lib/aspera/nagios.rb +26 -19
- data/lib/aspera/oauth.rb +4 -4
- data/lib/aspera/open_application.rb +21 -19
- data/lib/aspera/persistency_folder.rb +3 -0
- data/lib/aspera/preview/image_error.png +0 -0
- data/lib/aspera/preview/video_error.png +0 -0
- data/lib/aspera/proxy_auto_config.rb +6 -4
- data/lib/aspera/rest_error_analyzer.rb +15 -13
- data/lib/aspera/rest_errors_aspera.rb +42 -40
- data/lib/aspera/secret_hider.rb +11 -5
- data/lib/aspera/ssh.rb +1 -0
- data/lib/aspera/uri_reader.rb +15 -13
- data.tar.gz.sig +0 -0
- metadata +4 -3
- metadata.gz.sig +0 -0
data/docs/test_env.conf
CHANGED
@@ -61,7 +61,6 @@ tst_faspex5_web:
|
|
61
61
|
client_secret: your value here
|
62
62
|
tst_faspex5:
|
63
63
|
url: your value here
|
64
|
-
insecure: your value here
|
65
64
|
auth: your value here
|
66
65
|
client_id: your value here
|
67
66
|
client_secret: your value here
|
@@ -98,7 +97,6 @@ tst_orch:
|
|
98
97
|
url: your value here
|
99
98
|
username: your value here
|
100
99
|
password: your value here
|
101
|
-
insecure: your value here
|
102
100
|
tst_ats:
|
103
101
|
ibm_api_key: your value here
|
104
102
|
ats_key: your value here
|
@@ -108,7 +106,6 @@ tst_bss:
|
|
108
106
|
password: your value here
|
109
107
|
tst_ak_preview:
|
110
108
|
url: your value here
|
111
|
-
insecure: your value here
|
112
109
|
username: your value here
|
113
110
|
password: your value here
|
114
111
|
mimemagic: your value here
|
@@ -116,7 +113,6 @@ tst_node_preview:
|
|
116
113
|
url: your value here
|
117
114
|
username: your value here
|
118
115
|
password: your value here
|
119
|
-
insecure: your value here
|
120
116
|
tst_cos:
|
121
117
|
apikey: your value here
|
122
118
|
crn: your value here
|
@@ -168,4 +164,4 @@ misc:
|
|
168
164
|
aoc_workspace2: your value here
|
169
165
|
http_gw_fqdn_port: your value here
|
170
166
|
tst_secrets:
|
171
|
-
|
167
|
+
eudemo-sedemo: your value here
|
data/examples/dascli
CHANGED
@@ -3,10 +3,8 @@
|
|
3
3
|
# by default take latest version
|
4
4
|
: ${version:=latest}
|
5
5
|
imgtag=$image:$version
|
6
|
-
# same location as in Dockerfile: generic top folder for apps
|
7
|
-
appdir=/usr/src/app
|
8
6
|
# same location as in Dockerfile: main config folder for ascli in container
|
9
|
-
ascli_home_container
|
7
|
+
ascli_home_container=/home/cliuser/.aspera/ascli
|
10
8
|
# convenience: special argument to install the image
|
11
9
|
case "$1" in install) docker pull $imgtag; exit 0; esac
|
12
10
|
# set default location for config folder on host if necessary
|
@@ -20,7 +18,6 @@ exec docker run \
|
|
20
18
|
--rm \
|
21
19
|
--tty \
|
22
20
|
--interactive \
|
23
|
-
--env ASCLI_HOME="$ascli_home_container" \
|
24
21
|
--volume "$ASCLI_HOME:$ascli_home_container" \
|
25
22
|
$imgtag \
|
26
23
|
ascli "$@"
|
@@ -15,11 +15,12 @@ require 'tmpdir'
|
|
15
15
|
|
16
16
|
tmpdir = ENV['tmp'] || Dir.tmpdir || '.'
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
raise 'Usage: PASSWORD=<password> $0 https://<address>:<port> <node user>' unless ARGV.length.eql?(2) && ENV.has_key?('PASSWORD')
|
19
|
+
|
20
|
+
# example : https://node_asperaweb@eudemo.asperademo.com:9092
|
21
|
+
node_uri = URI.parse(ARGV.shift)
|
22
|
+
node_user = ARGV.shift
|
23
|
+
node_pass = ENV['PASSWORD']
|
23
24
|
|
24
25
|
##############################################################
|
25
26
|
# generic initialisation : configuration of FaspManager
|
@@ -40,14 +41,14 @@ Aspera::Fasp::Installation.instance.ascp_path = ENV['ascp'] if ENV.has_key?('asc
|
|
40
41
|
# or install:
|
41
42
|
#
|
42
43
|
|
43
|
-
# get
|
44
|
-
|
44
|
+
# get Transfer Agent
|
45
|
+
transfer_agent = Aspera::Fasp::AgentDirect.new
|
45
46
|
|
46
47
|
# Note that it would also be possible to start transfers using other agents
|
47
48
|
#require 'aspera/fasp/connect'
|
48
|
-
#
|
49
|
+
#transfer_agent=Aspera::Fasp::Connect.new
|
49
50
|
#require 'aspera/fasp/node'
|
50
|
-
#
|
51
|
+
#transfer_agent=Aspera::Fasp::Node.new(Aspera::Rest.new(...))
|
51
52
|
|
52
53
|
##############################################################
|
53
54
|
# Optional : register an event listener
|
@@ -60,48 +61,18 @@ class MyListener < Aspera::Fasp::Listener
|
|
60
61
|
end
|
61
62
|
|
62
63
|
# register the sample listener to display events
|
63
|
-
|
64
|
-
|
65
|
-
##############################################################
|
66
|
-
# first example: download by SSH credentials
|
67
|
-
|
68
|
-
# manually build teansfer spec
|
69
|
-
transfer_spec = {
|
70
|
-
#'remote_host' =>'demo.asperasoft.com',
|
71
|
-
'remote_host' => URI.parse(DEMO_CONFIG[0]).host,
|
72
|
-
'ssh_port' => URI.parse(DEMO_CONFIG[0]).port,
|
73
|
-
'remote_user' => URI.parse(DEMO_CONFIG[0]).user,
|
74
|
-
'remote_password' => DEMO_CONFIG[2],
|
75
|
-
'direction' => 'receive',
|
76
|
-
'destination_root' => tmpdir,
|
77
|
-
'paths' => [{'source' => 'aspera-test-dir-tiny/200KB.1'}]
|
78
|
-
}
|
79
|
-
# start transfer in separate thread
|
80
|
-
# method returns as soon as transfer thread is created
|
81
|
-
# it des not wait for completion, or even for session startup
|
82
|
-
fasp_manager.start_transfer(transfer_spec)
|
83
|
-
|
84
|
-
# optional: helper method: wait for completion of transfers
|
85
|
-
# here we started a single transfer session (no multisession parameter)
|
86
|
-
# get array of status, one for each session (so, a single value array)
|
87
|
-
# each status is either :success or "error message"
|
88
|
-
transfer_result = fasp_manager.wait_for_transfers_completion
|
89
|
-
$stdout.puts(JSON.generate(transfer_result))
|
90
|
-
# get list of errors only
|
91
|
-
errors = transfer_result.reject{|i|i.eql?(:success)}
|
92
|
-
# the transfer was not success, as there is at least one error
|
93
|
-
raise "Error(s) occured: #{errors.join(',')}" if !errors.empty?
|
64
|
+
transfer_agent.add_listener(MyListener.new)
|
94
65
|
|
95
66
|
##############################################################
|
96
|
-
#
|
67
|
+
# Upload with node authorization
|
97
68
|
|
98
69
|
# create rest client for Node API on a public demo system, using public demo credentials
|
99
70
|
node_api = Aspera::Rest.new({
|
100
|
-
base_url:
|
71
|
+
base_url: node_uri.to_s,
|
101
72
|
auth: {
|
102
73
|
type: :basic,
|
103
|
-
username:
|
104
|
-
password:
|
74
|
+
username: node_user,
|
75
|
+
password: node_pass
|
105
76
|
}})
|
106
77
|
# define sample file(s) and destination folder
|
107
78
|
sources = ["#{tmpdir}/sample_file.txt"]
|
@@ -117,9 +88,9 @@ transfer_spec['paths'] = sources.map{|p|{'source' => p}}
|
|
117
88
|
# set authentication type to "token" (will trigger use of bypass SSH key)
|
118
89
|
transfer_spec['authentication'] = 'token'
|
119
90
|
# from here : same as example 1
|
120
|
-
|
91
|
+
transfer_agent.start_transfer(transfer_spec)
|
121
92
|
# optional: wait for transfer completion helper function to get events
|
122
|
-
transfer_result =
|
93
|
+
transfer_result = transfer_agent.wait_for_transfers_completion
|
123
94
|
errors = transfer_result.reject{|i|i.eql?(:success)}
|
124
95
|
# the transfer was not success, as there is at least one error
|
125
96
|
raise "Error(s) occured: #{errors.join(',')}" if !errors.empty?
|
data/examples/server.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Example: transfer a file using one of the provided transfer agents
|
5
|
+
# location of ascp can be specified with env var "ascp"
|
6
|
+
# temp folder can be specified with env var "tmp"
|
7
|
+
require 'aspera/fasp/agent_direct'
|
8
|
+
require 'aspera/fasp/listener'
|
9
|
+
require 'aspera/fasp/installation'
|
10
|
+
require 'aspera/log'
|
11
|
+
require 'aspera/rest'
|
12
|
+
require 'aspera/rest_errors_aspera'
|
13
|
+
require 'json'
|
14
|
+
require 'tmpdir'
|
15
|
+
|
16
|
+
tmpdir = ENV['tmp'] || Dir.tmpdir || '.'
|
17
|
+
|
18
|
+
raise 'Usage: PASSWORD=<password> $0 ssh://<address>:<port> <transfer user>' unless ARGV.length.eql?(2) && ENV.has_key?('PASSWORD')
|
19
|
+
|
20
|
+
# example : ssh://asperaweb@eudemo.asperademo.com:33001
|
21
|
+
server_uri = URI.parse(ARGV.shift)
|
22
|
+
server_user = ARGV.shift
|
23
|
+
server_pass = ENV['PASSWORD']
|
24
|
+
|
25
|
+
##############################################################
|
26
|
+
# generic initialisation : configuration of FaspManager
|
27
|
+
|
28
|
+
# set trace level for sample, set to :debug to see complete list of debug information
|
29
|
+
Aspera::Log.instance.level = :debug
|
30
|
+
|
31
|
+
# register aspera REST call error handlers
|
32
|
+
Aspera::RestErrorsAspera.register_handlers
|
33
|
+
|
34
|
+
# some required files are generated here (keys, certs)
|
35
|
+
Aspera::Fasp::Installation.instance.folder = tmpdir
|
36
|
+
# set path to your copy of ascp binary (else, let the system find)
|
37
|
+
Aspera::Fasp::Installation.instance.ascp_path = ENV['ascp'] if ENV.has_key?('ascp')
|
38
|
+
# another way is to detect installed products and use one of them
|
39
|
+
#Aspera::Fasp::Installation.instance.installed_products.each{|p|puts("found: #{p[:name]}")}
|
40
|
+
#Aspera::Fasp::Installation.instance.use_ascp_from_product('Aspera Connect')
|
41
|
+
# or install:
|
42
|
+
#
|
43
|
+
|
44
|
+
# get Transfer Agent
|
45
|
+
transfer_agent = Aspera::Fasp::AgentDirect.new
|
46
|
+
|
47
|
+
# Note that it would also be possible to start transfers using other agents
|
48
|
+
#require 'aspera/fasp/connect'
|
49
|
+
#transfer_agent=Aspera::Fasp::Connect.new
|
50
|
+
#require 'aspera/fasp/node'
|
51
|
+
#transfer_agent=Aspera::Fasp::Node.new(Aspera::Rest.new(...))
|
52
|
+
|
53
|
+
##############################################################
|
54
|
+
# Optional : register an event listener
|
55
|
+
|
56
|
+
# example of event listener that displays events on stdout
|
57
|
+
class MyListener < Aspera::Fasp::Listener
|
58
|
+
# this is the callback called during transfers, here we only display the received information
|
59
|
+
# but it could be used to get detailed error information, check "type" field is "ERROR"
|
60
|
+
def event_enhanced(data);$stdout.puts(JSON.generate(data));$stdout.flush;end
|
61
|
+
end
|
62
|
+
|
63
|
+
# register the sample listener to display events
|
64
|
+
transfer_agent.add_listener(MyListener.new)
|
65
|
+
|
66
|
+
##############################################################
|
67
|
+
# first example: download by SSH credentials
|
68
|
+
|
69
|
+
# manually build teansfer spec
|
70
|
+
transfer_spec = {
|
71
|
+
'remote_host' => server_uri.host,
|
72
|
+
'ssh_port' => server_uri.port,
|
73
|
+
'remote_user' => server_user,
|
74
|
+
'remote_password' => server_pass,
|
75
|
+
'direction' => 'receive',
|
76
|
+
'destination_root' => tmpdir,
|
77
|
+
'paths' => [{'source' => 'aspera-test-dir-tiny/200KB.1'}]
|
78
|
+
}
|
79
|
+
# start transfer in separate thread
|
80
|
+
# method returns as soon as transfer thread is created
|
81
|
+
# it des not wait for completion, or even for session startup
|
82
|
+
transfer_agent.start_transfer(transfer_spec)
|
83
|
+
|
84
|
+
# optional: helper method: wait for completion of transfers
|
85
|
+
# here we started a single transfer session (no multisession parameter)
|
86
|
+
# get array of status, one for each session (so, a single value array)
|
87
|
+
# each status is either :success or "error message"
|
88
|
+
transfer_result = transfer_agent.wait_for_transfers_completion
|
89
|
+
$stdout.puts(JSON.generate(transfer_result))
|
90
|
+
# get list of errors only
|
91
|
+
errors = transfer_result.reject{|i|i.eql?(:success)}
|
92
|
+
# the transfer was not success, as there is at least one error
|
93
|
+
raise "Error(s) occured: #{errors.join(',')}" if !errors.empty?
|
data/lib/aspera/aoc.rb
CHANGED
@@ -6,6 +6,7 @@ require 'aspera/hash_ext'
|
|
6
6
|
require 'aspera/data_repository'
|
7
7
|
require 'aspera/fasp/transfer_spec'
|
8
8
|
require 'base64'
|
9
|
+
require 'cgi'
|
9
10
|
|
10
11
|
Aspera::Oauth.register_token_creator(:aoc_pub_link,lambda{|o|
|
11
12
|
o.api.call({
|
@@ -315,7 +316,8 @@ module Aspera
|
|
315
316
|
end
|
316
317
|
else
|
317
318
|
# retrieve values from API
|
318
|
-
std_t_spec = node_api.create(
|
319
|
+
std_t_spec = node_api.create(
|
320
|
+
'files/download_setup',
|
319
321
|
{transfer_requests: [{ transfer_request: {paths: [{'source' => '/'}] } }] }
|
320
322
|
)[:data]['transfer_specs'].first['transfer_spec']
|
321
323
|
%w[remote_host remote_user ssh_port fasp_port].each {|i| transfer_spec[i] = std_t_spec[i]}
|
@@ -453,7 +455,7 @@ module Aspera
|
|
453
455
|
# @param options additional search options
|
454
456
|
def lookup_entity_by_name(entity_type,entity_name,options={})
|
455
457
|
# returns entities whose name contains value (case insensitive)
|
456
|
-
matching_items = read(entity_type,options.merge({'q' => entity_name}))[:data]
|
458
|
+
matching_items = read(entity_type,options.merge({'q' => CGI.escape(entity_name)}))[:data]
|
457
459
|
case matching_items.length
|
458
460
|
when 1 then return matching_items.first
|
459
461
|
when 0 then raise %Q{#{ENTITY_NOT_FOUND} #{entity_type}: "#{entity_name}"}
|
data/lib/aspera/ats_api.rb
CHANGED
data/lib/aspera/cli/formater.rb
CHANGED
@@ -14,7 +14,7 @@ module Aspera
|
|
14
14
|
CSV_RECORD_SEPARATOR = "\n"
|
15
15
|
CSV_FIELD_SEPARATOR = ','
|
16
16
|
# supported output formats
|
17
|
-
DISPLAY_FORMATS = %i[
|
17
|
+
DISPLAY_FORMATS = %i[text nagios ruby json jsonpp yaml table csv].freeze
|
18
18
|
# user output levels
|
19
19
|
DISPLAY_LEVELS = %i[info data error].freeze
|
20
20
|
CONF_OVERVIEW_KEYS=%w[config parameter value].freeze
|
@@ -147,6 +147,8 @@ module Aspera
|
|
147
147
|
# comma separated list in string format
|
148
148
|
user_asked_fields_list_str = @option_fields
|
149
149
|
case @option_format
|
150
|
+
when :text
|
151
|
+
display_message(:data,res_data.to_s)
|
150
152
|
when :nagios
|
151
153
|
Nagios.process(res_data)
|
152
154
|
when :ruby
|
data/lib/aspera/cli/info.rb
CHANGED
@@ -11,7 +11,7 @@ module Aspera
|
|
11
11
|
SRC_URL = 'https://github.com/IBM/aspera-cli'
|
12
12
|
# set this to warn in advance when minimum required ruby version will increase
|
13
13
|
# for example currently minimum version is 2.4 in gemspec, but future minimum will be 2.5
|
14
|
-
# set to
|
14
|
+
# set to current minimum if there is no deprecation
|
15
15
|
# the actual current minimum required version is in gemspec at required_ruby_version
|
16
16
|
RUBY_FUTURE_MINIMUM_VERSION = '2.5'
|
17
17
|
end
|
data/lib/aspera/cli/main.rb
CHANGED
@@ -16,6 +16,7 @@ require 'aspera/rest'
|
|
16
16
|
require 'aspera/nagios'
|
17
17
|
require 'aspera/colors'
|
18
18
|
require 'aspera/secret_hider'
|
19
|
+
require 'net/ssh'
|
19
20
|
|
20
21
|
module Aspera
|
21
22
|
module Cli
|
@@ -266,12 +267,12 @@ module Aspera
|
|
266
267
|
# early debug for parser
|
267
268
|
# Note: does not accept shortcuts
|
268
269
|
def early_debug_setup(argv)
|
269
|
-
Log.instance.program_name = PROGRAM_NAME
|
270
|
+
Aspera::Log.instance.program_name = PROGRAM_NAME
|
270
271
|
argv.each do |arg|
|
271
272
|
case arg
|
272
273
|
when '--' then break
|
273
|
-
when /^--log-level=(.*)/ then Log.instance.level = Regexp.last_match(1).to_sym
|
274
|
-
when /^--logger=(.*)/ then Log.instance.logger_type = Regexp.last_match(1).to_sym
|
274
|
+
when /^--log-level=(.*)/ then Aspera::Log.instance.level = Regexp.last_match(1).to_sym
|
275
|
+
when /^--logger=(.*)/ then Aspera::Log.instance.logger_type = Regexp.last_match(1).to_sym
|
275
276
|
end
|
276
277
|
end
|
277
278
|
end
|
@@ -334,19 +335,21 @@ module Aspera
|
|
334
335
|
@plugin_env[:formater].display_results(command_plugin.execute_action) if execute_command
|
335
336
|
# finish
|
336
337
|
@plugin_env[:transfer].shutdown
|
337
|
-
rescue
|
338
|
-
rescue
|
339
|
-
rescue
|
340
|
-
rescue
|
341
|
-
rescue
|
342
|
-
rescue
|
343
|
-
rescue
|
344
|
-
rescue
|
338
|
+
rescue Net::SSH::AuthenticationFailed => e; exception_info = {e: e,t: 'SSH',security: true}
|
339
|
+
rescue CliBadArgument => e; exception_info = {e: e,t: 'Argument',usage: true}
|
340
|
+
rescue CliNoSuchId => e; exception_info = {e: e,t: 'Identifier'}
|
341
|
+
rescue CliError => e; exception_info = {e: e,t: 'Tool',usage: true}
|
342
|
+
rescue Fasp::Error => e; exception_info = {e: e,t: 'FASP(ascp)'}
|
343
|
+
rescue Aspera::RestCallError => e; exception_info = {e: e,t: 'Rest'}
|
344
|
+
rescue SocketError => e; exception_info = {e: e,t: 'Network'}
|
345
|
+
rescue StandardError => e; exception_info = {e: e,t: 'Other',debug: true}
|
346
|
+
rescue Interrupt => e; exception_info = {e: e,t: 'Interruption',debug: true}
|
345
347
|
end
|
346
348
|
# cleanup file list files
|
347
349
|
TempFileManager.instance.cleanup
|
348
350
|
# 1- processing of error condition
|
349
351
|
unless exception_info.nil?
|
352
|
+
Log.log.warn(exception_info[:e].message) if Aspera::Log.instance.logger_type.eql?(:syslog) && exception_info[:security]
|
350
353
|
@plugin_env[:formater].display_message(:error,"#{ERROR_FLASH} #{exception_info[:t]}: #{exception_info[:e].message}")
|
351
354
|
@plugin_env[:formater].display_message(:error,'Use option -h to get help.') if exception_info[:usage]
|
352
355
|
if exception_info[:e].is_a?(Fasp::Error) && exception_info[:e].message.eql?('Remote host is not who we expected')
|
data/lib/aspera/cli/manager.rb
CHANGED
@@ -56,7 +56,7 @@ module Aspera
|
|
56
56
|
|
57
57
|
class << self
|
58
58
|
def enum_to_bool(enum)
|
59
|
-
raise "Value not valid for boolean: #{enum}/#{enum.class}" unless BOOLEAN_VALUES.include?(enum)
|
59
|
+
raise "Value not valid for boolean: [#{enum}]/#{enum.class}" unless BOOLEAN_VALUES.include?(enum)
|
60
60
|
return TRUE_VALUES.include?(enum)
|
61
61
|
end
|
62
62
|
|
@@ -210,7 +210,7 @@ module Aspera
|
|
210
210
|
end
|
211
211
|
value = ExtendedValue.instance.evaluate(value)
|
212
212
|
value = Manager.enum_to_bool(value) if @declared_options[option_symbol][:values].eql?(BOOLEAN_VALUES)
|
213
|
-
Log.log.debug("
|
213
|
+
Log.log.debug("(#{@declared_options[option_symbol][:type]}/#{where}) set #{option_symbol}=#{value}")
|
214
214
|
case @declared_options[option_symbol][:type]
|
215
215
|
when :accessor
|
216
216
|
@declared_options[option_symbol][:accessor].value = value
|
@@ -235,10 +235,10 @@ module Aspera
|
|
235
235
|
else
|
236
236
|
raise 'unknown type'
|
237
237
|
end
|
238
|
-
Log.log.debug("
|
238
|
+
Log.log.debug("(#{@declared_options[option_symbol][:type]}) get #{option_symbol}=#{result}")
|
239
239
|
end
|
240
240
|
# do not fail for manual generation if option mandatory but not set
|
241
|
-
result = '' if result.nil? && !@fail_on_missing_mandatory
|
241
|
+
result = '' if result.nil? && is_type.eql?(:mandatory) && !@fail_on_missing_mandatory
|
242
242
|
#Log.log.debug("interactive=#{@ask_missing_mandatory}")
|
243
243
|
if result.nil?
|
244
244
|
if !@ask_missing_mandatory
|
data/lib/aspera/cli/plugin.rb
CHANGED
@@ -4,9 +4,9 @@ module Aspera
|
|
4
4
|
module Cli
|
5
5
|
# base class for plugins modules
|
6
6
|
class Plugin
|
7
|
-
#
|
7
|
+
# operations without id
|
8
8
|
GLOBAL_OPS = %i[create list].freeze
|
9
|
-
#
|
9
|
+
# operations with id
|
10
10
|
INSTANCE_OPS = %i[modify delete show].freeze
|
11
11
|
ALL_OPS = [GLOBAL_OPS,INSTANCE_OPS].flatten.freeze
|
12
12
|
# max number of items for list command
|
@@ -34,6 +34,8 @@ module Aspera
|
|
34
34
|
options.add_opt_simple(:value,'extended value for create, update, list filter')
|
35
35
|
options.add_opt_simple(:property,'name of property to set')
|
36
36
|
options.add_opt_simple(:id,"resource identifier (#{INSTANCE_OPS.join(',')})")
|
37
|
+
options.add_opt_boolean(:bulk,'Bulk operation (only some)')
|
38
|
+
options.set_option(:bulk,:no)
|
37
39
|
options.parse_options!
|
38
40
|
@@options_created = true # rubocop:disable Style/ClassVars
|
39
41
|
end
|
@@ -46,8 +48,41 @@ module Aspera
|
|
46
48
|
end
|
47
49
|
|
48
50
|
# TODO
|
49
|
-
def get_next_id_command(instance_ops: INSTANCE_OPS,global_ops: GLOBAL_OPS)
|
50
|
-
|
51
|
+
#def get_next_id_command(instance_ops: INSTANCE_OPS,global_ops: GLOBAL_OPS)
|
52
|
+
# return get_next_argument('command',expected: command_list)
|
53
|
+
#end
|
54
|
+
|
55
|
+
# For create and delete operations: execute one actin or multiple if bulk is yes
|
56
|
+
# @param params either single id or hash, or array for bulk
|
57
|
+
# @param success_msg deleted or created
|
58
|
+
def do_bulk_operation(single_or_array,success_msg,id_result: 'id',fields: :default)
|
59
|
+
raise 'programming error: missing block' unless block_given?
|
60
|
+
params = options.get_option(:bulk) ? single_or_array : [single_or_array]
|
61
|
+
raise 'expecting Array for bulk operation' unless params.is_a?(Array)
|
62
|
+
Log.log.warn('Empty list given for bulk operation') if params.empty?
|
63
|
+
Log.dump(:bulk_create,params)
|
64
|
+
result_list = []
|
65
|
+
params.each do |param|
|
66
|
+
# init for delete
|
67
|
+
result = {id_result => param}
|
68
|
+
begin
|
69
|
+
# execute custom code
|
70
|
+
res = yield(param)
|
71
|
+
# if block returns a hash, let's use this (create)
|
72
|
+
result = res if param.is_a?(Hash)
|
73
|
+
result['status'] = success_msg
|
74
|
+
rescue StandardError => e
|
75
|
+
result['status'] = e.to_s
|
76
|
+
end
|
77
|
+
result_list.push(result)
|
78
|
+
end
|
79
|
+
display_fields = [id_result,'status']
|
80
|
+
if options.get_option(:bulk)
|
81
|
+
return {type: :object_list,data: result_list,fields: display_fields}
|
82
|
+
else
|
83
|
+
display_fields = fields unless fields.eql?(:default)
|
84
|
+
return {type: :single_object,data: result_list.first,fields: display_fields}
|
85
|
+
end
|
51
86
|
end
|
52
87
|
|
53
88
|
# @param command [Symbol] command to execute: create show list modify delete
|
@@ -56,6 +91,7 @@ module Aspera
|
|
56
91
|
# @param display_fields [Array] fields to display by default
|
57
92
|
# @param id_default [String] default identifier to use for existing entity commands (show, modify)
|
58
93
|
# @param item_list_key [String] result is in a subkey of the json
|
94
|
+
# @return result suitable for CLI result
|
59
95
|
def entity_command(command,rest_api,res_class_path,display_fields: nil,id_default: nil,item_list_key: false)
|
60
96
|
if INSTANCE_OPS.include?(command)
|
61
97
|
begin
|
@@ -76,7 +112,15 @@ module Aspera
|
|
76
112
|
end
|
77
113
|
case command
|
78
114
|
when :create
|
79
|
-
return
|
115
|
+
return do_bulk_operation(parameters,'created',fields: display_fields) do |params|
|
116
|
+
raise 'expecting Hash' unless params.is_a?(Hash)
|
117
|
+
rest_api.create(res_class_path,params)[:data]
|
118
|
+
end
|
119
|
+
when :delete
|
120
|
+
return do_bulk_operation(one_res_id,'deleted') do |one_id|
|
121
|
+
rest_api.delete("#{res_class_path}/#{one_id}")
|
122
|
+
{'id' => one_id}
|
123
|
+
end
|
80
124
|
when :show
|
81
125
|
return {type: :single_object, data: rest_api.read(one_res_path)[:data], fields: display_fields}
|
82
126
|
when :list
|
@@ -102,9 +146,6 @@ module Aspera
|
|
102
146
|
parameters = {property => parameters} unless property.nil?
|
103
147
|
rest_api.update(one_res_path,parameters)
|
104
148
|
return Main.result_status('modified')
|
105
|
-
when :delete
|
106
|
-
rest_api.delete(one_res_path)
|
107
|
-
return Main.result_status('deleted')
|
108
149
|
else
|
109
150
|
raise "unknown action: #{command}"
|
110
151
|
end
|
@@ -117,7 +158,7 @@ module Aspera
|
|
117
158
|
return entity_command(command,rest_api,res_class_path,**opts)
|
118
159
|
end
|
119
160
|
|
120
|
-
# shortcuts for plugin environment
|
161
|
+
# shortcuts helpers for plugin environment
|
121
162
|
def options; return @agents[:options];end
|
122
163
|
|
123
164
|
def transfer; return @agents[:transfer];end
|