aspera-cli 4.9.0 → 4.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/BUGS.md +20 -0
- data/CHANGELOG.md +509 -0
- data/CONTRIBUTING.md +118 -0
- data/README.md +1241 -916
- data/bin/ascli +4 -4
- data/bin/asession +11 -11
- data/docs/test_env.conf +32 -21
- data/examples/aoc.rb +4 -4
- data/examples/dascli +16 -9
- data/examples/faspex4.rb +8 -8
- data/examples/node.rb +12 -12
- data/examples/server.rb +10 -10
- data/lib/aspera/aoc.rb +273 -266
- data/lib/aspera/ascmd.rb +56 -54
- data/lib/aspera/ats_api.rb +4 -4
- data/lib/aspera/cli/basic_auth_plugin.rb +15 -12
- data/lib/aspera/cli/extended_value.rb +5 -5
- data/lib/aspera/cli/formater.rb +64 -64
- data/lib/aspera/cli/info.rb +2 -2
- data/lib/aspera/cli/listener/line_dump.rb +1 -1
- data/lib/aspera/cli/listener/logger.rb +1 -1
- data/lib/aspera/cli/listener/progress.rb +5 -6
- data/lib/aspera/cli/listener/progress_multi.rb +14 -19
- data/lib/aspera/cli/main.rb +66 -67
- data/lib/aspera/cli/manager.rb +112 -110
- data/lib/aspera/cli/plugin.rb +57 -36
- data/lib/aspera/cli/plugins/alee.rb +4 -4
- data/lib/aspera/cli/plugins/aoc.rb +309 -670
- data/lib/aspera/cli/plugins/ats.rb +44 -46
- data/lib/aspera/cli/plugins/bss.rb +10 -10
- data/lib/aspera/cli/plugins/config.rb +497 -378
- data/lib/aspera/cli/plugins/console.rb +12 -12
- data/lib/aspera/cli/plugins/cos.rb +18 -20
- data/lib/aspera/cli/plugins/faspex.rb +112 -114
- data/lib/aspera/cli/plugins/faspex5.rb +71 -46
- data/lib/aspera/cli/plugins/node.rb +379 -283
- data/lib/aspera/cli/plugins/orchestrator.rb +46 -46
- data/lib/aspera/cli/plugins/preview.rb +122 -114
- data/lib/aspera/cli/plugins/server.rb +137 -83
- data/lib/aspera/cli/plugins/shares.rb +30 -29
- data/lib/aspera/cli/plugins/sync.rb +13 -33
- data/lib/aspera/cli/transfer_agent.rb +60 -59
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/colors.rb +3 -3
- data/lib/aspera/command_line_builder.rb +27 -27
- data/lib/aspera/cos_node.rb +22 -20
- data/lib/aspera/data_repository.rb +1 -1
- data/lib/aspera/environment.rb +35 -15
- data/lib/aspera/fasp/agent_base.rb +15 -15
- data/lib/aspera/fasp/agent_connect.rb +23 -21
- data/lib/aspera/fasp/agent_direct.rb +66 -64
- data/lib/aspera/fasp/agent_httpgw.rb +141 -78
- data/lib/aspera/fasp/agent_node.rb +23 -21
- data/lib/aspera/fasp/agent_trsdk.rb +20 -20
- data/lib/aspera/fasp/error.rb +3 -2
- data/lib/aspera/fasp/error_info.rb +11 -8
- data/lib/aspera/fasp/installation.rb +79 -79
- data/lib/aspera/fasp/listener.rb +1 -1
- data/lib/aspera/fasp/parameters.rb +86 -71
- data/lib/aspera/fasp/parameters.yaml +7 -4
- data/lib/aspera/fasp/resume_policy.rb +8 -8
- data/lib/aspera/fasp/transfer_spec.rb +35 -2
- data/lib/aspera/fasp/uri.rb +7 -7
- data/lib/aspera/faspex_gw.rb +7 -5
- data/lib/aspera/hash_ext.rb +3 -3
- data/lib/aspera/id_generator.rb +5 -5
- data/lib/aspera/keychain/encrypted_hash.rb +38 -105
- data/lib/aspera/keychain/macos_security.rb +128 -57
- data/lib/aspera/log.rb +7 -7
- data/lib/aspera/nagios.rb +19 -18
- data/lib/aspera/node.rb +209 -35
- data/lib/aspera/oauth.rb +37 -36
- data/lib/aspera/open_application.rb +19 -11
- data/lib/aspera/persistency_action_once.rb +4 -4
- data/lib/aspera/persistency_folder.rb +16 -15
- data/lib/aspera/preview/file_types.rb +8 -8
- data/lib/aspera/preview/generator.rb +67 -67
- data/lib/aspera/preview/utils.rb +27 -27
- data/lib/aspera/proxy_auto_config.js +41 -41
- data/lib/aspera/proxy_auto_config.rb +21 -14
- data/lib/aspera/rest.rb +72 -67
- data/lib/aspera/rest_call_error.rb +2 -1
- data/lib/aspera/rest_error_analyzer.rb +18 -17
- data/lib/aspera/rest_errors_aspera.rb +16 -16
- data/lib/aspera/secret_hider.rb +15 -13
- data/lib/aspera/ssh.rb +11 -10
- data/lib/aspera/sync.rb +158 -44
- data/lib/aspera/temp_file_manager.rb +2 -2
- data/lib/aspera/uri_reader.rb +4 -4
- data/lib/aspera/web_auth.rb +14 -13
- data.tar.gz.sig +0 -0
- metadata +11 -36
- metadata.gz.sig +0 -0
@@ -1,10 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'aspera/cli/basic_auth_plugin'
|
4
|
+
require 'aspera/cli/plugins/sync'
|
4
5
|
require 'aspera/nagios'
|
5
6
|
require 'aspera/hash_ext'
|
6
7
|
require 'aspera/id_generator'
|
7
8
|
require 'aspera/node'
|
9
|
+
require 'aspera/aoc'
|
8
10
|
require 'aspera/fasp/transfer_spec'
|
9
11
|
require 'base64'
|
10
12
|
require 'zlib'
|
@@ -12,7 +14,7 @@ require 'zlib'
|
|
12
14
|
module Aspera
|
13
15
|
module Cli
|
14
16
|
module Plugins
|
15
|
-
class Node < BasicAuthPlugin
|
17
|
+
class Node < Aspera::Cli::BasicAuthPlugin
|
16
18
|
class << self
|
17
19
|
def detect(base_url)
|
18
20
|
api = Rest.new({ base_url: base_url})
|
@@ -22,55 +24,99 @@ module Aspera
|
|
22
24
|
end
|
23
25
|
return nil
|
24
26
|
end
|
27
|
+
|
28
|
+
def register_node_options(env)
|
29
|
+
env[:options].add_opt_simple(:validator, 'identifier of validator (optional for central)')
|
30
|
+
env[:options].add_opt_simple(:asperabrowserurl, 'URL for simple aspera web ui')
|
31
|
+
env[:options].add_opt_simple(:sync_name, 'sync name')
|
32
|
+
env[:options].add_opt_simple(:path, 'file or folder path for gen4 operation "file"')
|
33
|
+
env[:options].add_opt_list(:token_type, %i[aspera basic hybrid], 'Type of token used for transfers')
|
34
|
+
env[:options].add_opt_boolean(:default_ports, 'use standard FASP ports or get from node api (gen4)')
|
35
|
+
env[:options].set_option(:asperabrowserurl, 'https://asperabrowser.mybluemix.net')
|
36
|
+
env[:options].set_option(:token_type, :aspera)
|
37
|
+
env[:options].set_option(:default_ports, :yes)
|
38
|
+
env[:options].parse_options!
|
39
|
+
Aspera::Node.use_standard_ports = env[:options].get_option(:default_ports)
|
40
|
+
end
|
25
41
|
end
|
26
|
-
|
42
|
+
|
43
|
+
# SOAP API call to test central API
|
44
|
+
CENTRAL_SOAP_API_TEST = '<?xml version="1.0" encoding="UTF-8"?>'\
|
27
45
|
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:typ="urn:Aspera:XML:FASPSessionNET:2009/11:Types">'\
|
28
46
|
'<soapenv:Header></soapenv:Header>'\
|
29
47
|
'<soapenv:Body><typ:GetSessionInfoRequest><SessionFilter><SessionStatus>running</SessionStatus></SessionFilter></typ:GetSessionInfoRequest></soapenv:Body>'\
|
30
48
|
'</soapenv:Envelope>'
|
31
|
-
|
32
|
-
|
49
|
+
|
50
|
+
# fields removed in result of search
|
51
|
+
SEARCH_REMOVE_FIELDS = %w[basename permissions].freeze
|
52
|
+
|
53
|
+
# actions in execute_command_gen3
|
54
|
+
COMMANDS_GEN3 = %i[search space mkdir mklink mkfile rename delete browse upload download]
|
55
|
+
|
56
|
+
BASE_ACTIONS = %i[api_details].concat(COMMANDS_GEN3).freeze
|
57
|
+
|
58
|
+
SPECIAL_ACTIONS = %i[health events info license].freeze
|
59
|
+
|
60
|
+
# actions available in v3 in gen4
|
61
|
+
V3_IN_V4_ACTIONS = %i[access_key].concat(BASE_ACTIONS).concat(SPECIAL_ACTIONS).freeze
|
62
|
+
|
63
|
+
# actions used commonly when a node is involved
|
64
|
+
COMMON_ACTIONS = %i[access_key].concat(BASE_ACTIONS).concat(SPECIAL_ACTIONS).freeze
|
65
|
+
|
66
|
+
private_constant(*%i[CENTRAL_SOAP_API_TEST SEARCH_REMOVE_FIELDS BASE_ACTIONS SPECIAL_ACTIONS V3_IN_V4_ACTIONS COMMON_ACTIONS])
|
67
|
+
|
68
|
+
# used in aoc
|
69
|
+
NODE4_READ_ACTIONS = %i[bearer_token_node node_info browse find].freeze
|
70
|
+
|
71
|
+
# commands for execute_command_gen4
|
72
|
+
COMMANDS_GEN4 = %i[mkdir rename delete upload download sync http_node_download file v3].concat(NODE4_READ_ACTIONS).freeze
|
73
|
+
|
74
|
+
COMMANDS_COS = %i[upload download info access_key api_details transfer].freeze
|
75
|
+
COMMANDS_SHARES = (BASE_ACTIONS - %i[search]).freeze
|
76
|
+
COMMANDS_FASPEX = COMMON_ACTIONS
|
33
77
|
|
34
78
|
def initialize(env)
|
35
79
|
super(env)
|
36
|
-
|
37
|
-
@add_request_param = env[:add_request_param] || {}
|
38
|
-
options.add_opt_simple(:validator,'identifier of validator (optional for central)')
|
39
|
-
options.add_opt_simple(:asperabrowserurl,'URL for simple aspera web ui')
|
40
|
-
options.add_opt_simple(:sync_name,'sync name')
|
41
|
-
options.add_opt_list(:token_type,%i[aspera basic hybrid],'Type of token used for transfers')
|
42
|
-
options.set_option(:asperabrowserurl,'https://asperabrowser.mybluemix.net')
|
43
|
-
options.set_option(:token_type,:aspera)
|
44
|
-
options.parse_options!
|
80
|
+
self.class.register_node_options(env) unless env[:skip_node_options]
|
45
81
|
return if env[:man_only]
|
46
82
|
@api_node =
|
47
|
-
if env.
|
83
|
+
if env.key?(:node_api)
|
84
|
+
# this can be Aspera::Node or Aspera::Rest (shares)
|
48
85
|
env[:node_api]
|
49
|
-
elsif options.get_option(:password,is_type: :mandatory).start_with?('Bearer ')
|
86
|
+
elsif options.get_option(:password, is_type: :mandatory).start_with?('Bearer ')
|
50
87
|
# info is provided like node_info of aoc
|
51
|
-
|
52
|
-
base_url: options.get_option(:url,is_type: :mandatory),
|
88
|
+
Aspera::Node.new(params: {
|
89
|
+
base_url: options.get_option(:url, is_type: :mandatory),
|
53
90
|
headers: {
|
54
|
-
|
55
|
-
'Authorization'
|
91
|
+
Aspera::Node::X_ASPERA_ACCESSKEY => options.get_option(:username, is_type: :mandatory),
|
92
|
+
'Authorization' => options.get_option(:password, is_type: :mandatory)
|
56
93
|
}
|
57
94
|
})
|
58
95
|
else
|
59
96
|
# this is normal case
|
60
|
-
|
97
|
+
Aspera::Node.new(params: {
|
98
|
+
base_url: options.get_option(:url, is_type: :mandatory),
|
99
|
+
auth: {
|
100
|
+
type: :basic,
|
101
|
+
username: options.get_option(:username, is_type: :mandatory),
|
102
|
+
password: options.get_option(:password, is_type: :mandatory)
|
103
|
+
}})
|
61
104
|
end
|
62
105
|
end
|
63
106
|
|
64
107
|
def c_textify_browse(table_data)
|
65
|
-
return table_data.map
|
108
|
+
return table_data.map do |i|
|
109
|
+
i['permissions'] = i['permissions'].map { |x| x['name'] }.join(',')
|
110
|
+
i
|
111
|
+
end
|
66
112
|
end
|
67
113
|
|
68
114
|
# key/value is defined in main in hash_table
|
69
|
-
def c_textify_bool_list_result(list,name_list)
|
115
|
+
def c_textify_bool_list_result(list, name_list)
|
70
116
|
list.each_index do |i|
|
71
117
|
next unless name_list.include?(list[i]['key'])
|
72
118
|
list[i]['value'].each do |item|
|
73
|
-
list.push({'key' => item['name'],'value' => item['value']})
|
119
|
+
list.push({'key' => item['name'], 'value' => item['value']})
|
74
120
|
end
|
75
121
|
list.delete_at(i)
|
76
122
|
# continue at same index because we delete current one
|
@@ -79,7 +125,7 @@ module Aspera
|
|
79
125
|
end
|
80
126
|
|
81
127
|
# reduce the path from a result on given named column
|
82
|
-
def c_result_remove_prefix_path(result,column,path_prefix)
|
128
|
+
def c_result_remove_prefix_path(result, column, path_prefix)
|
83
129
|
if !path_prefix.nil?
|
84
130
|
case result[:type]
|
85
131
|
when :object_list
|
@@ -95,338 +141,376 @@ module Aspera
|
|
95
141
|
end
|
96
142
|
|
97
143
|
# translates paths results into CLI result, and removes prefix
|
98
|
-
def c_result_translate_rem_prefix(resp,type,success_msg,path_prefix)
|
99
|
-
|
144
|
+
def c_result_translate_rem_prefix(resp, type, success_msg, path_prefix)
|
145
|
+
errors = []
|
146
|
+
resres = { data: [], type: :object_list, fields: [type, 'result']}
|
100
147
|
JSON.parse(resp[:http].body)['paths'].each do |p|
|
101
148
|
result = success_msg
|
102
|
-
if p.
|
103
|
-
Log.log.error
|
149
|
+
if p.key?('error')
|
150
|
+
Log.log.error{"#{p['error']['user_message']} : #{p['path']}"}
|
104
151
|
result = 'ERROR: ' + p['error']['user_message']
|
152
|
+
errors.push([p['path'], p['error']['user_message']])
|
105
153
|
end
|
106
|
-
resres[:data].push({type => p['path'],'result' => result})
|
154
|
+
resres[:data].push({type => p['path'], 'result' => result})
|
155
|
+
end
|
156
|
+
# one error make all fail
|
157
|
+
unless errors.empty?
|
158
|
+
raise errors.map{|i|"#{i.first}: #{i.last}"}.join(', ')
|
107
159
|
end
|
108
|
-
return c_result_remove_prefix_path(resres,type,path_prefix)
|
160
|
+
return c_result_remove_prefix_path(resres, type, path_prefix)
|
109
161
|
end
|
110
162
|
|
111
163
|
# get path arguments from command line, and add prefix
|
112
|
-
def get_next_arg_add_prefix(path_prefix,name,number=:single)
|
113
|
-
thepath = options.get_next_argument(name,expected: number)
|
164
|
+
def get_next_arg_add_prefix(path_prefix, name, number=:single)
|
165
|
+
thepath = options.get_next_argument(name, expected: number)
|
114
166
|
return thepath if path_prefix.nil?
|
115
|
-
return File.join(path_prefix,thepath) if thepath.is_a?(String)
|
116
|
-
return thepath.map {|p| File.join(path_prefix,p)} if thepath.is_a?(Array)
|
117
|
-
raise StandardError,'expect: nil, String or Array'
|
167
|
+
return File.join(path_prefix, thepath) if thepath.is_a?(String)
|
168
|
+
return thepath.map {|p| File.join(path_prefix, p)} if thepath.is_a?(Array)
|
169
|
+
raise StandardError, 'expect: nil, String or Array'
|
118
170
|
end
|
119
171
|
|
120
|
-
|
121
|
-
|
122
|
-
COMMON_ACTIONS = %i[browse upload download api_details].concat(SIMPLE_ACTIONS).freeze
|
123
|
-
|
124
|
-
# common API to node and Shares
|
125
|
-
# prefix_path is used to list remote sources in Faspex
|
126
|
-
def execute_simple_common(command,prefix_path)
|
172
|
+
# file and folder related commands
|
173
|
+
def execute_command_gen3(command, prefix_path)
|
127
174
|
case command
|
128
|
-
when :health
|
129
|
-
nagios = Nagios.new
|
130
|
-
begin
|
131
|
-
info = @api_node.read('info')[:data]
|
132
|
-
nagios.add_ok('node api','accessible')
|
133
|
-
nagios.check_time_offset(info['current_time'],'node api')
|
134
|
-
nagios.check_product_version('node api','entsrv', info['version'])
|
135
|
-
rescue StandardError => e
|
136
|
-
nagios.add_critical('node api',e.to_s)
|
137
|
-
end
|
138
|
-
begin
|
139
|
-
@api_node.call(
|
140
|
-
operation: 'POST',
|
141
|
-
subpath: 'services/soap/Transfer-201210',
|
142
|
-
headers: {'Content-Type' => 'text/xml;charset=UTF-8','SOAPAction' => 'FASPSessionNET-200911#GetSessionInfo'},
|
143
|
-
text_body_params: SAMPLE_SOAP_CALL)[:http].body
|
144
|
-
nagios.add_ok('central','accessible by node')
|
145
|
-
rescue StandardError => e
|
146
|
-
nagios.add_critical('central',e.to_s)
|
147
|
-
end
|
148
|
-
return nagios.result
|
149
|
-
when :events
|
150
|
-
events = @api_node.read('events',options.get_option(:value))[:data]
|
151
|
-
return { type: :object_list, data: events}
|
152
|
-
when :info
|
153
|
-
node_info = @api_node.read('info')[:data]
|
154
|
-
return { type: :single_object, data: node_info, textify: lambda { |table_data| c_textify_bool_list_result(table_data,%w[capabilities settings])}}
|
155
|
-
when :license # requires: asnodeadmin -mu <node user> --acl-add=internal --internal
|
156
|
-
node_license = @api_node.read('license')[:data]
|
157
|
-
if node_license['failure'].is_a?(String) && node_license['failure'].include?('ACL')
|
158
|
-
Log.log.error('server must have: asnodeadmin -mu <node user> --acl-add=internal --internal')
|
159
|
-
end
|
160
|
-
return { type: :single_object, data: node_license}
|
161
175
|
when :delete
|
162
|
-
paths_to_delete = get_next_arg_add_prefix(prefix_path,'file list'
|
163
|
-
resp = @api_node.create('files/delete',{ paths: paths_to_delete.map{|i| {'path' => i.start_with?('/') ? i : '/' + i} }})
|
164
|
-
return c_result_translate_rem_prefix(resp,'file','deleted',prefix_path)
|
176
|
+
paths_to_delete = get_next_arg_add_prefix(prefix_path, 'file list', :multiple)
|
177
|
+
resp = @api_node.create('files/delete', { paths: paths_to_delete.map{|i| {'path' => i.start_with?('/') ? i : '/' + i} }})
|
178
|
+
return c_result_translate_rem_prefix(resp, 'file', 'deleted', prefix_path)
|
165
179
|
when :search
|
166
|
-
search_root = get_next_arg_add_prefix(prefix_path,'search root')
|
180
|
+
search_root = get_next_arg_add_prefix(prefix_path, 'search root')
|
167
181
|
parameters = {'path' => search_root}
|
168
182
|
other_options = options.get_option(:value)
|
169
183
|
parameters.merge!(other_options) unless other_options.nil?
|
170
|
-
resp = @api_node.create('files/search',parameters)
|
184
|
+
resp = @api_node.create('files/search', parameters)
|
171
185
|
result = { type: :object_list, data: resp[:data]['items']}
|
172
186
|
return Main.result_empty if result[:data].empty?
|
173
187
|
result[:fields] = result[:data].first.keys.reject{|i|SEARCH_REMOVE_FIELDS.include?(i)}
|
174
188
|
self.format.display_status("Items: #{resp[:data]['item_count']}/#{resp[:data]['total_count']}")
|
175
189
|
self.format.display_status("params: #{resp[:data]['parameters'].keys.map{|k|"#{k}:#{resp[:data]['parameters'][k]}"}.join(',')}")
|
176
|
-
return c_result_remove_prefix_path(result,'path',prefix_path)
|
190
|
+
return c_result_remove_prefix_path(result, 'path', prefix_path)
|
177
191
|
when :space
|
178
|
-
|
179
|
-
path_list = get_next_arg_add_prefix(prefix_path,'folder path or ext.val. list')
|
192
|
+
path_list = get_next_arg_add_prefix(prefix_path, 'folder path or ext.val. list')
|
180
193
|
path_list = [path_list] unless path_list.is_a?(Array)
|
181
|
-
resp = @api_node.create('space',{ 'paths' => path_list.map {|i| { path: i} } })
|
194
|
+
resp = @api_node.create('space', { 'paths' => path_list.map {|i| { path: i} } })
|
182
195
|
result = { data: resp[:data]['paths'], type: :object_list}
|
183
|
-
#return c_result_translate_rem_prefix(resp,'folder','created',prefix_path)
|
184
|
-
return c_result_remove_prefix_path(result,'path',prefix_path)
|
196
|
+
# return c_result_translate_rem_prefix(resp,'folder','created',prefix_path)
|
197
|
+
return c_result_remove_prefix_path(result, 'path', prefix_path)
|
185
198
|
when :mkdir
|
186
|
-
path_list = get_next_arg_add_prefix(prefix_path,'folder path or ext.val. list')
|
199
|
+
path_list = get_next_arg_add_prefix(prefix_path, 'folder path or ext.val. list')
|
187
200
|
path_list = [path_list] unless path_list.is_a?(Array)
|
188
|
-
|
189
|
-
|
190
|
-
resp = @api_node.create('files/create',{ 'paths' => [{ type: :directory, path: path_list }] })
|
191
|
-
return c_result_translate_rem_prefix(resp,'folder','created',prefix_path)
|
201
|
+
resp = @api_node.create('files/create', { 'paths' => [{ type: :directory, path: path_list }] })
|
202
|
+
return c_result_translate_rem_prefix(resp, 'folder', 'created', prefix_path)
|
192
203
|
when :mklink
|
193
|
-
target = get_next_arg_add_prefix(prefix_path,'target')
|
194
|
-
path_list = get_next_arg_add_prefix(prefix_path,'link path')
|
195
|
-
resp = @api_node.create('files/create',{ 'paths' => [{ type: :symbolic_link, path: path_list, target: { path: target} }] })
|
196
|
-
return c_result_translate_rem_prefix(resp,'folder','created',prefix_path)
|
204
|
+
target = get_next_arg_add_prefix(prefix_path, 'target')
|
205
|
+
path_list = get_next_arg_add_prefix(prefix_path, 'link path')
|
206
|
+
resp = @api_node.create('files/create', { 'paths' => [{ type: :symbolic_link, path: path_list, target: { path: target} }] })
|
207
|
+
return c_result_translate_rem_prefix(resp, 'folder', 'created', prefix_path)
|
197
208
|
when :mkfile
|
198
|
-
path_list = get_next_arg_add_prefix(prefix_path,'file path')
|
209
|
+
path_list = get_next_arg_add_prefix(prefix_path, 'file path')
|
199
210
|
contents64 = Base64.strict_encode64(options.get_next_argument('contents'))
|
200
|
-
resp = @api_node.create('files/create',{ 'paths' => [{ type: :file, path: path_list, contents: contents64 }] })
|
201
|
-
return c_result_translate_rem_prefix(resp,'folder','created',prefix_path)
|
211
|
+
resp = @api_node.create('files/create', { 'paths' => [{ type: :file, path: path_list, contents: contents64 }] })
|
212
|
+
return c_result_translate_rem_prefix(resp, 'folder', 'created', prefix_path)
|
202
213
|
when :rename
|
203
|
-
path_base = get_next_arg_add_prefix(prefix_path,'path_base')
|
204
|
-
path_src = get_next_arg_add_prefix(prefix_path,'path_src')
|
205
|
-
path_dst = get_next_arg_add_prefix(prefix_path,'path_dst')
|
206
|
-
resp = @api_node.create('files/rename',{ 'paths' => [{ 'path' => path_base, 'source' => path_src, 'destination' => path_dst }] })
|
207
|
-
return c_result_translate_rem_prefix(resp,'entry','moved',prefix_path)
|
214
|
+
path_base = get_next_arg_add_prefix(prefix_path, 'path_base')
|
215
|
+
path_src = get_next_arg_add_prefix(prefix_path, 'path_src')
|
216
|
+
path_dst = get_next_arg_add_prefix(prefix_path, 'path_dst')
|
217
|
+
resp = @api_node.create('files/rename', { 'paths' => [{ 'path' => path_base, 'source' => path_src, 'destination' => path_dst }] })
|
218
|
+
return c_result_translate_rem_prefix(resp, 'entry', 'moved', prefix_path)
|
208
219
|
when :browse
|
209
|
-
thepath = get_next_arg_add_prefix(prefix_path,'path')
|
220
|
+
thepath = get_next_arg_add_prefix(prefix_path, 'path')
|
210
221
|
query = { path: thepath}
|
211
222
|
additional_query = options.get_option(:query)
|
212
223
|
query.merge!(additional_query) unless additional_query.nil?
|
213
224
|
send_result = @api_node.create('files/browse', query)[:data]
|
214
|
-
#example: send_result={'items'=>[{'file'=>"filename1","permissions"=>[{'name'=>'read'},{'name'=>'write'}]}]}
|
225
|
+
# example: send_result={'items'=>[{'file'=>"filename1","permissions"=>[{'name'=>'read'},{'name'=>'write'}]}]}
|
215
226
|
# if there is no items
|
216
227
|
case send_result['self']['type']
|
217
|
-
when 'directory','container' # directory: node, container: shares
|
228
|
+
when 'directory', 'container' # directory: node, container: shares
|
218
229
|
result = { data: send_result['items'], type: :object_list, textify: lambda { |table_data| c_textify_browse(table_data) } }
|
219
230
|
self.format.display_status("Items: #{send_result['item_count']}/#{send_result['total_count']}")
|
220
231
|
else # 'file','symbolic_link'
|
221
232
|
result = { data: send_result['self'], type: :single_object}
|
222
|
-
#result={ data: [send_result['self']] , type: :object_list, textify: lambda { |table_data| c_textify_browse(table_data) } }
|
223
|
-
#raise "unknown type: #{send_result['self']['type']}"
|
233
|
+
# result={ data: [send_result['self']] , type: :object_list, textify: lambda { |table_data| c_textify_browse(table_data) } }
|
234
|
+
# raise "unknown type: #{send_result['self']['type']}"
|
224
235
|
end
|
225
|
-
return c_result_remove_prefix_path(result,'path',prefix_path)
|
226
|
-
when :upload
|
236
|
+
return c_result_remove_prefix_path(result, 'path', prefix_path)
|
237
|
+
when :upload, :download
|
227
238
|
token_type = options.get_option(:token_type)
|
228
239
|
# nil if Shares 1.x
|
229
240
|
token_type = :aspera if token_type.nil?
|
230
241
|
case token_type
|
231
|
-
when :aspera
|
242
|
+
when :aspera, :hybrid
|
232
243
|
# empty transfer spec for authorization request
|
233
|
-
request_transfer_spec={}
|
244
|
+
request_transfer_spec = {}
|
234
245
|
# set requested paths depending on direction
|
235
246
|
request_transfer_spec[:paths] = command.eql?(:download) ? transfer.ts_source_paths : [{ destination: transfer.destination_folder('send') }]
|
236
247
|
# add fixed parameters if any (for COS)
|
237
|
-
request_transfer_spec.
|
248
|
+
@api_node.add_tspec_info(request_transfer_spec) if @api_node.respond_to?(:add_tspec_info)
|
238
249
|
# prepare payload for single request
|
239
|
-
setup_payload={transfer_requests: [{transfer_request: request_transfer_spec}]}
|
250
|
+
setup_payload = {transfer_requests: [{transfer_request: request_transfer_spec}]}
|
240
251
|
# only one request, so only one answer
|
241
|
-
transfer_spec = @api_node.create("files/#{command}_setup",setup_payload)[:data]['transfer_specs'].first['transfer_spec']
|
252
|
+
transfer_spec = @api_node.create("files/#{command}_setup", setup_payload)[:data]['transfer_specs'].first['transfer_spec']
|
242
253
|
# delete this part, as the returned value contains only destination, and not sources
|
243
254
|
transfer_spec.delete('paths') if command.eql?(:upload)
|
244
255
|
when :basic
|
245
256
|
raise 'shall have auth' unless @api_node.params[:auth].is_a?(Hash)
|
246
257
|
raise 'shall be basic auth' unless @api_node.params[:auth][:type].eql?(:basic)
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
end
|
253
|
-
transfer_spec = {
|
254
|
-
'remote_host' => URI.parse(@api_node.params[:base_url]).host,
|
255
|
-
'remote_user' => Aspera::Fasp::TransferSpec::ACCESS_KEY_TRANSFER_USER,
|
256
|
-
'ssh_port' => Aspera::Fasp::TransferSpec::SSH_PORT,
|
257
|
-
'direction' => ts_direction,
|
258
|
-
'destination_root' => transfer.destination_folder(ts_direction)
|
259
|
-
}.deep_merge(@add_request_param)
|
258
|
+
transfer_spec = {}.merge(Aspera::Fasp::TransferSpec::AK_TSPEC_BASE)
|
259
|
+
transfer_spec['remote_host'] = URI.parse(@api_node.params[:base_url]).host
|
260
|
+
Fasp::TransferSpec.action_to_direction(transfer_spec, command)
|
261
|
+
transfer_spec['destination_root'] = transfer.destination_folder(transfer_spec['direction'])
|
262
|
+
@api_node.add_tspec_info(transfer_spec) if @api_node.respond_to?(:add_tspec_info)
|
260
263
|
else raise "ERROR: token_type #{tt}"
|
261
264
|
end
|
262
265
|
if %i[basic hybrid].include?(token_type)
|
263
|
-
|
266
|
+
@api_node.ts_basic_token(transfer_spec)
|
264
267
|
end
|
265
|
-
return Main.result_transfer(transfer.start(transfer_spec
|
268
|
+
return Main.result_transfer(transfer.start(transfer_spec))
|
269
|
+
end
|
270
|
+
raise 'INTERNAL ERROR'
|
271
|
+
end
|
272
|
+
|
273
|
+
# common API to node and Shares
|
274
|
+
# prefix_path is used to list remote sources in Faspex
|
275
|
+
def execute_simple_common(command, prefix_path)
|
276
|
+
case command
|
277
|
+
when *COMMANDS_GEN3
|
278
|
+
execute_command_gen3(command, prefix_path)
|
279
|
+
when :access_key
|
280
|
+
ak_command = options.get_next_command([:do].concat(Plugin::ALL_OPS))
|
281
|
+
case ak_command
|
282
|
+
when *Plugin::ALL_OPS then return entity_command(ak_command, @api_node, 'access_keys', id_default: 'self')
|
283
|
+
when :do
|
284
|
+
access_key = options.get_next_argument('access key id')
|
285
|
+
ak_info = @api_node.read("access_keys/#{access_key}")[:data]
|
286
|
+
# change API credentials if different access key
|
287
|
+
if !access_key.eql?('self')
|
288
|
+
@api_node.params[:auth][:username] = ak_info['id']
|
289
|
+
@api_node.params[:auth][:password] = config.lookup_secret(url: @api_node.params[:base_url], username: ak_info['id'], mandatory: true)
|
290
|
+
end
|
291
|
+
command_repo = options.get_next_command(COMMANDS_GEN4)
|
292
|
+
return execute_command_gen4(command_repo, ak_info['root_file_id'])
|
293
|
+
end
|
294
|
+
when :health
|
295
|
+
nagios = Nagios.new
|
296
|
+
begin
|
297
|
+
info = @api_node.read('info')[:data]
|
298
|
+
nagios.add_ok('node api', 'accessible')
|
299
|
+
nagios.check_time_offset(info['current_time'], 'node api')
|
300
|
+
nagios.check_product_version('node api', 'entsrv', info['version'])
|
301
|
+
rescue StandardError => e
|
302
|
+
nagios.add_critical('node api', e.to_s)
|
303
|
+
end
|
304
|
+
begin
|
305
|
+
@api_node.call(
|
306
|
+
operation: 'POST',
|
307
|
+
subpath: 'services/soap/Transfer-201210',
|
308
|
+
headers: {'Content-Type' => 'text/xml;charset=UTF-8', 'SOAPAction' => 'FASPSessionNET-200911#GetSessionInfo'},
|
309
|
+
text_body_params: CENTRAL_SOAP_API_TEST)[:http].body
|
310
|
+
nagios.add_ok('central', 'accessible by node')
|
311
|
+
rescue StandardError => e
|
312
|
+
nagios.add_critical('central', e.to_s)
|
313
|
+
end
|
314
|
+
return nagios.result
|
315
|
+
when :events
|
316
|
+
events = @api_node.read('events', options.get_option(:value))[:data]
|
317
|
+
return { type: :object_list, data: events}
|
318
|
+
when :info
|
319
|
+
nd_info = @api_node.read('info')[:data]
|
320
|
+
return { type: :single_object, data: nd_info, textify: lambda { |table_data| c_textify_bool_list_result(table_data, %w[capabilities settings])}}
|
321
|
+
when :license
|
322
|
+
# requires: asnodeadmin -mu <node user> --acl-add=internal --internal
|
323
|
+
node_license = @api_node.read('license')[:data]
|
324
|
+
if node_license['failure'].is_a?(String) && node_license['failure'].include?('ACL')
|
325
|
+
Log.log.error('server must have: asnodeadmin -mu <node user> --acl-add=internal --internal')
|
326
|
+
end
|
327
|
+
return { type: :single_object, data: node_license}
|
266
328
|
when :api_details
|
267
329
|
return { type: :single_object, data: @api_node.params }
|
268
330
|
end
|
269
331
|
end
|
270
332
|
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
333
|
+
def execute_node_gen4_file_command(command_node_file, top_file_id)
|
334
|
+
file_path = options.get_option(:path)
|
335
|
+
apifid =
|
336
|
+
if file_path.nil?
|
337
|
+
{api: @api_node, file_id: instance_identifier}
|
338
|
+
else
|
339
|
+
@api_node.resolve_api_fid(top_file_id, file_path) # TODO: allow follow link ?
|
340
|
+
end
|
341
|
+
case command_node_file
|
342
|
+
when :show
|
343
|
+
items = apifid[:api].read("files/#{apifid[:file_id]}")[:data]
|
344
|
+
return {type: :single_object, data: items}
|
345
|
+
when :modify
|
346
|
+
update_param = options.get_next_argument('update data', type: Hash)
|
347
|
+
apifid[:api].update("files/#{apifid[:file_id]}", update_param)[:data]
|
348
|
+
return Main.result_status('Done')
|
349
|
+
when :permission
|
350
|
+
command_perm = options.get_next_command(%i[list create delete])
|
351
|
+
case command_perm
|
352
|
+
when :list
|
353
|
+
# generic options : TODO: as arg ? option_url_query
|
354
|
+
list_options ||= {'include' => ['[]', 'access_level', 'permission_count']}
|
355
|
+
# add which one to get
|
356
|
+
list_options['file_id'] = apifid[:file_id]
|
357
|
+
list_options['inherited'] ||= false
|
358
|
+
items = apifid[:api].read('permissions', list_options)[:data]
|
359
|
+
return {type: :object_list, data: items}
|
360
|
+
when :delete
|
361
|
+
perm_id = instance_identifier
|
362
|
+
return do_bulk_operation(perm_id, 'deleted') do |one_id|
|
363
|
+
# TODO: notify event ?
|
364
|
+
apifid[:api].delete("permissions/#{perm_id}")
|
365
|
+
{'id' => one_id}
|
366
|
+
end
|
367
|
+
when :create
|
368
|
+
create_param = options.get_next_argument('creation data', type: Hash)
|
369
|
+
raise 'no file_id' if create_param.key?('file_id')
|
370
|
+
create_param['file_id'] = apifid[:file_id]
|
371
|
+
create_param['access_levels'] = Aspera::Node::ACCESS_LEVELS unless create_param.key?('access_levels')
|
372
|
+
# add application specific tags (AoC)
|
373
|
+
the_app = apifid[:api].app_info
|
374
|
+
the_app[:api].permissions_create_params(create_param: create_param, app_info: the_app) unless the_app.nil?
|
375
|
+
# create permission
|
376
|
+
created_data = apifid[:api].create('permissions', create_param)[:data]
|
377
|
+
# bnotify application of creation
|
378
|
+
the_app[:api].permissions_create_event(created_data: created_data, app_info: the_app) unless the_app.nil?
|
379
|
+
return { type: :single_object, data: created_data}
|
380
|
+
else raise "internal error:shall not reach here (#{command_perm})"
|
381
|
+
end
|
382
|
+
else raise "internal error:shall not reach here (#{command_node_file})"
|
383
|
+
end
|
279
384
|
end
|
280
385
|
|
281
|
-
|
282
|
-
|
283
|
-
def execute_node_gen4_command(command_repo, top_file_id)
|
284
|
-
#@api_node
|
386
|
+
def execute_command_gen4(command_repo, top_file_id)
|
285
387
|
case command_repo
|
286
|
-
when :
|
388
|
+
when :v3
|
389
|
+
# NOTE: other common actions are unauthorized with user scope
|
390
|
+
command_legacy = options.get_next_command(V3_IN_V4_ACTIONS)
|
391
|
+
# TODO: shall we support all methods here ? what if there is a link ?
|
392
|
+
apifid = @api_node.resolve_api_fid(top_file_id, '')
|
393
|
+
return Node.new(@agents.merge(skip_basic_auth_options: true, skip_node_options: true, node_api: apifid[:api])).execute_action(command_legacy)
|
394
|
+
when :node_info, :bearer_token_node
|
287
395
|
thepath = options.get_next_argument('path')
|
288
|
-
apifid = resolve_api_fid(top_file_id,thepath)
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
396
|
+
apifid = @api_node.resolve_api_fid(top_file_id, thepath)
|
397
|
+
result = {
|
398
|
+
url: apifid[:api].params[:base_url],
|
399
|
+
root_id: apifid[:file_id]
|
400
|
+
}
|
401
|
+
raise 'No auth for node' if apifid[:api].params[:auth].nil?
|
402
|
+
case apifid[:api].params[:auth][:type]
|
403
|
+
when :basic
|
404
|
+
result[:username] = apifid[:api].params[:auth][:username]
|
405
|
+
result[:password] = apifid[:api].params[:auth][:password]
|
406
|
+
when :oauth2
|
407
|
+
result[:username] = apifid[:api].params[:headers][Aspera::Node::X_ASPERA_ACCESSKEY]
|
408
|
+
result[:password] = apifid[:api].oauth_token
|
409
|
+
else raise 'unknown'
|
410
|
+
end
|
411
|
+
return {type: :single_object, data: result} if command_repo.eql?(:node_info)
|
412
|
+
raise 'not bearer token' unless result[:password].start_with?('Bearer ')
|
413
|
+
return Main.result_status(result[:password])
|
296
414
|
when :browse
|
297
415
|
thepath = options.get_next_argument('path')
|
298
|
-
apifid = resolve_api_fid(top_file_id,thepath)
|
416
|
+
apifid = @api_node.resolve_api_fid(top_file_id, thepath)
|
299
417
|
file_info = apifid[:api].read("files/#{apifid[:file_id]}")[:data]
|
300
418
|
if file_info['type'].eql?('folder')
|
301
|
-
result = apifid[:api].read("files/#{apifid[:file_id]}/files",options.get_option(:value))
|
419
|
+
result = apifid[:api].read("files/#{apifid[:file_id]}/files", options.get_option(:value))
|
302
420
|
items = result[:data]
|
303
421
|
self.format.display_status("Items: #{result[:data].length}/#{result[:http]['X-Total-Count']}")
|
304
422
|
else
|
305
423
|
items = [file_info]
|
306
424
|
end
|
307
|
-
return {type: :object_list,data: items,fields: %w[name type recursive_size size modified_time access_level]}
|
425
|
+
return {type: :object_list, data: items, fields: %w[name type recursive_size size modified_time access_level]}
|
308
426
|
when :find
|
309
427
|
thepath = options.get_next_argument('path')
|
310
|
-
apifid = resolve_api_fid(top_file_id,thepath)
|
428
|
+
apifid = @api_node.resolve_api_fid(top_file_id, thepath)
|
311
429
|
test_block = Aspera::Node.file_matcher(options.get_option(:value))
|
312
|
-
return {type: :object_list,data:
|
430
|
+
return {type: :object_list, data: @api_node.find_files(apifid[:file_id], test_block), fields: ['path']}
|
313
431
|
when :mkdir
|
314
432
|
thepath = options.get_next_argument('path')
|
315
|
-
containing_folder_path = thepath.split(
|
433
|
+
containing_folder_path = thepath.split(Aspera::Node::PATH_SEPARATOR)
|
316
434
|
new_folder = containing_folder_path.pop
|
317
|
-
apifid = resolve_api_fid(top_file_id,containing_folder_path.join(
|
318
|
-
result = apifid[:api].create("files/#{apifid[:file_id]}/files",{name: new_folder,type: :folder})[:data]
|
435
|
+
apifid = @api_node.resolve_api_fid(top_file_id, containing_folder_path.join(Aspera::Node::PATH_SEPARATOR))
|
436
|
+
result = apifid[:api].create("files/#{apifid[:file_id]}/files", {name: new_folder, type: :folder})[:data]
|
319
437
|
return Main.result_status("created: #{result['name']} (id=#{result['id']})")
|
320
438
|
when :rename
|
321
439
|
thepath = options.get_next_argument('source path')
|
322
440
|
newname = options.get_next_argument('new name')
|
323
|
-
apifid = resolve_api_fid(top_file_id,thepath)
|
324
|
-
result = apifid[:api].update("files/#{apifid[:file_id]}",{name: newname})[:data]
|
441
|
+
apifid = @api_node.resolve_api_fid(top_file_id, thepath)
|
442
|
+
result = apifid[:api].update("files/#{apifid[:file_id]}", {name: newname})[:data]
|
325
443
|
return Main.result_status("renamed #{thepath} to #{newname}")
|
326
444
|
when :delete
|
327
445
|
thepath = options.get_next_argument('path')
|
328
|
-
return do_bulk_operation(thepath,'deleted','path') do |l_path|
|
446
|
+
return do_bulk_operation(thepath, 'deleted', id_result: 'path') do |l_path|
|
329
447
|
raise "expecting String (path), got #{l_path.class.name} (#{l_path})" unless l_path.is_a?(String)
|
330
|
-
apifid = resolve_api_fid(top_file_id,l_path)
|
448
|
+
apifid = @api_node.resolve_api_fid(top_file_id, l_path)
|
331
449
|
result = apifid[:api].delete("files/#{apifid[:file_id]}")[:data]
|
332
450
|
{'path' => l_path}
|
333
451
|
end
|
452
|
+
when :sync
|
453
|
+
# remote is specified by option to_folder
|
454
|
+
apifid = @api_node.resolve_api_fid(top_file_id, transfer.destination_folder(Fasp::TransferSpec::DIRECTION_SEND))
|
455
|
+
transfer_spec = apifid[:api].transfer_spec_gen4(apifid[:file_id], Fasp::TransferSpec::DIRECTION_SEND)
|
456
|
+
Log.dump(:ts, transfer_spec)
|
457
|
+
sync_plugin = Plugins::Sync.new(@agents, transfer_spec: transfer_spec)
|
458
|
+
return sync_plugin.execute_action
|
334
459
|
when :upload
|
335
|
-
apifid = resolve_api_fid(top_file_id,transfer.destination_folder(Fasp::TransferSpec::DIRECTION_SEND))
|
336
|
-
|
337
|
-
return Main.result_transfer(transfer_start(AoC::FILES_APP,Fasp::TransferSpec::DIRECTION_SEND,apifid,add_ts))
|
460
|
+
apifid = @api_node.resolve_api_fid(top_file_id, transfer.destination_folder(Fasp::TransferSpec::DIRECTION_SEND))
|
461
|
+
return Main.result_transfer(transfer.start(apifid[:api].transfer_spec_gen4(apifid[:file_id], Fasp::TransferSpec::DIRECTION_SEND)))
|
338
462
|
when :download
|
339
463
|
source_paths = transfer.ts_source_paths
|
340
464
|
# special case for AoC : all files must be in same folder
|
341
465
|
source_folder = source_paths.shift['source']
|
342
466
|
# if a single file: split into folder and path
|
467
|
+
apifid = @api_node.resolve_api_fid(top_file_id, source_folder)
|
343
468
|
if source_paths.empty?
|
344
|
-
|
345
|
-
|
346
|
-
|
469
|
+
file_info = apifid[:api].read("files/#{apifid[:file_id]}")[:data]
|
470
|
+
case file_info['type']
|
471
|
+
when 'file'
|
472
|
+
# if the single source is a file, we need to split into folder path and filename
|
473
|
+
src_dir_elements = source_folder.split(Aspera::Node::PATH_SEPARATOR)
|
474
|
+
# filename is the last one
|
475
|
+
source_paths = [{'source' => src_dir_elements.pop}]
|
476
|
+
# source folder is what remains
|
477
|
+
source_folder = src_dir_elements.join(Aspera::Node::PATH_SEPARATOR)
|
478
|
+
# TODO: instead of creating a new object, use the same, and change file id with parent folder id ? possible ?
|
479
|
+
apifid = @api_node.resolve_api_fid(top_file_id, source_folder)
|
480
|
+
when 'link', 'folder'
|
481
|
+
# single source is 'folder' or 'link'
|
482
|
+
# TODO: add this ? , 'destination'=>file_info['name']
|
483
|
+
source_paths = [{'source' => '.'}]
|
484
|
+
else
|
485
|
+
raise "Unknown source type: #{file_info['type']}"
|
486
|
+
end
|
347
487
|
end
|
348
|
-
apifid
|
349
|
-
# override paths with just filename
|
350
|
-
add_ts = {'tags' => {'aspera' => {'files' => {'parentCwd' => "#{apifid[:node_info]['id']}:#{apifid[:file_id]}"}}}}
|
351
|
-
add_ts['paths'] = source_paths
|
352
|
-
return Main.result_transfer(transfer_start(AoC::FILES_APP,Fasp::TransferSpec::DIRECTION_RECEIVE,apifid,add_ts))
|
488
|
+
return Main.result_transfer(transfer.start(apifid[:api].transfer_spec_gen4(apifid[:file_id], Fasp::TransferSpec::DIRECTION_RECEIVE, {'paths'=>source_paths})))
|
353
489
|
when :http_node_download
|
354
490
|
source_paths = transfer.ts_source_paths
|
355
491
|
source_folder = source_paths.shift['source']
|
356
492
|
if source_paths.empty?
|
357
|
-
source_folder = source_folder.split(
|
493
|
+
source_folder = source_folder.split(Aspera::Node::PATH_SEPARATOR)
|
358
494
|
source_paths = [{'source' => source_folder.pop}]
|
359
|
-
source_folder = source_folder.join(
|
495
|
+
source_folder = source_folder.join(Aspera::Node::PATH_SEPARATOR)
|
360
496
|
end
|
361
|
-
raise CliBadArgument,'one file at a time only in HTTP mode' if source_paths.length > 1
|
497
|
+
raise CliBadArgument, 'one file at a time only in HTTP mode' if source_paths.length > 1
|
362
498
|
file_name = source_paths.first['source']
|
363
|
-
apifid = resolve_api_fid(top_file_id,File.join(source_folder,file_name))
|
499
|
+
apifid = @api_node.resolve_api_fid(top_file_id, File.join(source_folder, file_name))
|
364
500
|
apifid[:api].call(
|
365
501
|
operation: 'GET',
|
366
502
|
subpath: "files/#{apifid[:file_id]}/content",
|
367
|
-
save_to_file: File.join(transfer.destination_folder(Fasp::TransferSpec::DIRECTION_RECEIVE),file_name))
|
503
|
+
save_to_file: File.join(transfer.destination_folder(Fasp::TransferSpec::DIRECTION_RECEIVE), file_name))
|
368
504
|
return Main.result_status("downloaded: #{file_name}")
|
369
|
-
when :permission
|
370
|
-
command_perm = options.get_next_command(%i[list create])
|
371
|
-
case command_perm
|
372
|
-
when :list
|
373
|
-
# generic options : TODO: as arg ? option_url_query
|
374
|
-
list_options ||= {'include' => ['[]','access_level','permission_count']}
|
375
|
-
# special value: ALL will show all permissions
|
376
|
-
if !VAL_ALL.eql?(apifid[:file_id])
|
377
|
-
# add which one to get
|
378
|
-
list_options['file_id'] = apifid[:file_id]
|
379
|
-
list_options['inherited'] ||= false
|
380
|
-
end
|
381
|
-
items = apifid[:api].read('permissions',list_options)[:data]
|
382
|
-
return {type: :object_list,data: items}
|
383
|
-
when :create
|
384
|
-
#create_param=self.options.get_next_argument('creation data (Hash)')
|
385
|
-
set_workspace_info
|
386
|
-
access_id = "#{ID_AK_ADMIN}_WS_#{@workspace_id}"
|
387
|
-
apifid[:node_info]
|
388
|
-
params = {
|
389
|
-
'file_id' => apifid[:file_id], # mandatory
|
390
|
-
'access_type' => 'user', # mandatory: user or group
|
391
|
-
'access_id' => access_id, # id of user or group
|
392
|
-
'access_levels' => Aspera::Node::ACCESS_LEVELS,
|
393
|
-
'tags' => {'aspera' => {'files' => {'workspace' => {
|
394
|
-
'id' => @workspace_id,
|
395
|
-
'workspace_name' => @workspace_name,
|
396
|
-
'user_name' => aoc_api.user_info['name'],
|
397
|
-
'shared_by_user_id' => aoc_api.user_info['id'],
|
398
|
-
'shared_by_name' => aoc_api.user_info['name'],
|
399
|
-
'shared_by_email' => aoc_api.user_info['email'],
|
400
|
-
'shared_with_name' => access_id,
|
401
|
-
'access_key' => apifid[:node_info]['access_key'],
|
402
|
-
'node' => apifid[:node_info]['name']}}}}}
|
403
|
-
item = apifid[:api].create('permissions',params)[:data]
|
404
|
-
return {type: :single_object,data: item}
|
405
|
-
else raise "internal error:shall not reach here (#{command_perm})"
|
406
|
-
end
|
407
505
|
when :file
|
408
|
-
command_node_file = options.get_next_command(%i[show modify])
|
409
|
-
|
410
|
-
|
411
|
-
if !file_path.nil?
|
412
|
-
resolve_api_fid(top_file_id,file_path) # TODO: allow follow link ?
|
413
|
-
else
|
414
|
-
{node_info: top_file_id[:node_info],file_id: instance_identifier}
|
415
|
-
end
|
416
|
-
case command_node_file
|
417
|
-
when :show
|
418
|
-
items = apifid[:api].read("files/#{apifid[:file_id]}")[:data]
|
419
|
-
return {type: :single_object,data: items}
|
420
|
-
when :modify
|
421
|
-
update_param = options.get_next_argument('update data (Hash)')
|
422
|
-
res = apifid[:api].update("files/#{apifid[:file_id]}",update_param)[:data]
|
423
|
-
return {type: :single_object,data: res}
|
424
|
-
else raise "internal error:shall not reach here (#{command_node_file})"
|
425
|
-
end
|
506
|
+
command_node_file = options.get_next_command(%i[show modify permission])
|
507
|
+
return execute_node_gen4_file_command(command_node_file, top_file_id)
|
508
|
+
else raise "INTERNAL ERROR: no case for #{command_repo}"
|
426
509
|
end # command_repo
|
427
|
-
raise '
|
428
|
-
end #
|
510
|
+
# raise 'INTERNAL ERROR: missing return'
|
511
|
+
end # execute_command_gen4
|
429
512
|
|
513
|
+
# This is older API
|
430
514
|
def execute_async
|
431
515
|
command = options.get_next_command(%i[list delete files show counters bandwidth])
|
432
516
|
unless command.eql?(:list)
|
@@ -441,7 +525,7 @@ module Aspera
|
|
441
525
|
end
|
442
526
|
else
|
443
527
|
asyncids = @api_node.read('async/list')[:data]['sync_ids']
|
444
|
-
summaries = @api_node.create('async/summary',{'syncs' => asyncids})[:data]['sync_summaries']
|
528
|
+
summaries = @api_node.create('async/summary', {'syncs' => asyncids})[:data]['sync_summaries']
|
445
529
|
selected = summaries.find{|s|s['name'].eql?(asyncname)}
|
446
530
|
raise "no such sync: #{asyncname}" if selected.nil?
|
447
531
|
asyncid = selected['snid']
|
@@ -454,16 +538,16 @@ module Aspera
|
|
454
538
|
resp = @api_node.read('async/list')[:data]['sync_ids']
|
455
539
|
return { type: :value_list, data: resp, name: 'id' }
|
456
540
|
when :show
|
457
|
-
resp = @api_node.create('async/summary',pdata)[:data]['sync_summaries']
|
541
|
+
resp = @api_node.create('async/summary', pdata)[:data]['sync_summaries']
|
458
542
|
return Main.result_empty if resp.empty?
|
459
543
|
return { type: :object_list, data: resp, fields: %w[snid name local_dir remote_dir] } if asyncid.eql?('ALL')
|
460
544
|
return { type: :single_object, data: resp.first }
|
461
545
|
when :delete
|
462
|
-
resp = @api_node.create('async/delete',pdata)[:data]
|
546
|
+
resp = @api_node.create('async/delete', pdata)[:data]
|
463
547
|
return { type: :single_object, data: resp, name: 'id' }
|
464
548
|
when :bandwidth
|
465
549
|
pdata['seconds'] = 100 # TODO: as parameter with --value
|
466
|
-
resp = @api_node.create('async/bandwidth',pdata)[:data]
|
550
|
+
resp = @api_node.create('async/bandwidth', pdata)[:data]
|
467
551
|
data = resp['bandwidth_data']
|
468
552
|
return Main.result_empty if data.empty?
|
469
553
|
data = data.first[asyncid]['data']
|
@@ -475,19 +559,19 @@ module Aspera
|
|
475
559
|
# status int
|
476
560
|
filter = options.get_option(:value)
|
477
561
|
pdata.merge!(filter) unless filter.nil?
|
478
|
-
resp = @api_node.create('async/files',pdata)[:data]
|
562
|
+
resp = @api_node.create('async/files', pdata)[:data]
|
479
563
|
data = resp['sync_files']
|
480
564
|
data = data.first[asyncid] unless data.empty?
|
481
565
|
iteration_data = []
|
482
566
|
skip_ids_persistency = nil
|
483
|
-
if options.get_option(:once_only,is_type: :mandatory)
|
567
|
+
if options.get_option(:once_only, is_type: :mandatory)
|
484
568
|
skip_ids_persistency = PersistencyActionOnce.new(
|
485
569
|
manager: @agents[:persistency],
|
486
570
|
data: iteration_data,
|
487
571
|
id: IdGenerator.from_list([
|
488
572
|
'sync_files',
|
489
|
-
options.get_option(:url,is_type: :mandatory),
|
490
|
-
options.get_option(:username,is_type: :mandatory),
|
573
|
+
options.get_option(:url, is_type: :mandatory),
|
574
|
+
options.get_option(:username, is_type: :mandatory),
|
491
575
|
asyncid]))
|
492
576
|
unless iteration_data.first.nil?
|
493
577
|
data.select!{|l| l['fnid'].to_i > iteration_data.first}
|
@@ -498,27 +582,50 @@ module Aspera
|
|
498
582
|
skip_ids_persistency&.save
|
499
583
|
return { type: :object_list, data: data, name: 'id' }
|
500
584
|
when :counters
|
501
|
-
resp = @api_node.create('async/counters',pdata)[:data]['sync_counters'].first[asyncid].last
|
585
|
+
resp = @api_node.create('async/counters', pdata)[:data]['sync_counters'].first[asyncid].last
|
502
586
|
return Main.result_empty if resp.nil?
|
503
587
|
return { type: :single_object, data: resp }
|
504
588
|
end
|
505
589
|
end
|
506
590
|
|
507
|
-
ACTIONS = %i[
|
591
|
+
ACTIONS = %i[
|
592
|
+
async
|
593
|
+
sync
|
594
|
+
stream
|
595
|
+
transfer
|
596
|
+
service
|
597
|
+
watch_folder
|
598
|
+
central
|
599
|
+
asperabrowser
|
600
|
+
basic_token].concat(COMMON_ACTIONS).freeze
|
508
601
|
|
509
|
-
def execute_action(command=nil,prefix_path=nil)
|
602
|
+
def execute_action(command=nil, prefix_path=nil)
|
510
603
|
command ||= options.get_next_command(ACTIONS)
|
511
604
|
case command
|
512
|
-
when *COMMON_ACTIONS then return execute_simple_common(command,prefix_path)
|
605
|
+
when *COMMON_ACTIONS then return execute_simple_common(command, prefix_path)
|
513
606
|
when :async then return execute_async
|
607
|
+
when :sync
|
608
|
+
# newer api
|
609
|
+
sync_command = options.get_next_command(%i[bandwidth counters files start state stop summary].concat(Plugin::ALL_OPS) - %i[modify])
|
610
|
+
case sync_command
|
611
|
+
when *Plugin::ALL_OPS then return entity_command(sync_command, @api_node, 'asyncs', item_list_key: 'ids')
|
612
|
+
else
|
613
|
+
parameters = options.get_option(:value)
|
614
|
+
asyncs_id = instance_identifier
|
615
|
+
if %i[start stop].include?(sync_command)
|
616
|
+
@api_node.create("asyncs/#{asyncs_id}/#{sync_command}", parameters)
|
617
|
+
return Main.result_status('ok')
|
618
|
+
end
|
619
|
+
return { type: :single_object, data: @api_node.read("asyncs/#{asyncs_id}/#{sync_command}", parameters)[:data] }
|
620
|
+
end
|
514
621
|
when :stream
|
515
622
|
command = options.get_next_command(%i[list create show modify cancel])
|
516
623
|
case command
|
517
624
|
when :list
|
518
|
-
resp = @api_node.read('ops/transfers',options.get_option(:value))
|
625
|
+
resp = @api_node.read('ops/transfers', options.get_option(:value))
|
519
626
|
return { type: :object_list, data: resp[:data], fields: %w[id status] } # TODO: useful?
|
520
627
|
when :create
|
521
|
-
resp = @api_node.create('streams',options.get_option(:value,is_type: :mandatory))
|
628
|
+
resp = @api_node.create('streams', options.get_option(:value, is_type: :mandatory))
|
522
629
|
return { type: :single_object, data: resp[:data] }
|
523
630
|
when :show
|
524
631
|
trid = options.get_next_argument('transfer id')
|
@@ -526,7 +633,7 @@ module Aspera
|
|
526
633
|
return { type: :other_struct, data: resp[:data] }
|
527
634
|
when :modify
|
528
635
|
trid = options.get_next_argument('transfer id')
|
529
|
-
resp = @api_node.update('streams/' + trid,options.get_option(:value,is_type: :mandatory))
|
636
|
+
resp = @api_node.update('streams/' + trid, options.get_option(:value, is_type: :mandatory))
|
530
637
|
return { type: :other_struct, data: resp[:data] }
|
531
638
|
when :cancel
|
532
639
|
trid = options.get_next_argument('transfer id')
|
@@ -545,7 +652,9 @@ module Aspera
|
|
545
652
|
case command
|
546
653
|
when :list
|
547
654
|
# could use ? subpath: 'transfers'
|
548
|
-
|
655
|
+
query = options.get_option(:value) || options.get_option(:query)
|
656
|
+
raise 'Query must be a Hash' unless query.nil? || query.is_a?(Hash)
|
657
|
+
resp = @api_node.read(res_class_path, query)
|
549
658
|
return {
|
550
659
|
type: :object_list,
|
551
660
|
data: resp[:data],
|
@@ -560,22 +669,6 @@ module Aspera
|
|
560
669
|
else
|
561
670
|
raise 'error'
|
562
671
|
end
|
563
|
-
when :access_key
|
564
|
-
ak_command = options.get_next_command([Plugin::ALL_OPS,:do].flatten)
|
565
|
-
case ak_command
|
566
|
-
when *Plugin::ALL_OPS then return entity_command(ak_command,@api_node,'access_keys',id_default: 'self')
|
567
|
-
when :do
|
568
|
-
access_key = options.get_next_argument('access key id')
|
569
|
-
ak_info=@api_node.read("access_keys/#{access_key}")[:data]
|
570
|
-
# change API if needed
|
571
|
-
if !access_key.eql?('self')
|
572
|
-
secret=config.vault.get(username: access_key)[:secret] #, url: @api_node.params[:base_url] : TODO: better handle vault
|
573
|
-
@api_node.params[:auth][:username]=access_key
|
574
|
-
@api_node.params[:auth][:password]=secret
|
575
|
-
end
|
576
|
-
command_repo = options.get_next_command(NODE4_COMMANDS)
|
577
|
-
return execute_node_gen4_command(command_repo,ak_info['root_file_id'])
|
578
|
-
end
|
579
672
|
when :service
|
580
673
|
command = options.get_next_command(%i[list create delete])
|
581
674
|
if [:delete].include?(command)
|
@@ -588,7 +681,7 @@ module Aspera
|
|
588
681
|
when :create
|
589
682
|
# @json:'{"type":"WATCHFOLDERD","run_as":{"user":"user1"}}'
|
590
683
|
params = options.get_next_argument('Run creation data (structure)')
|
591
|
-
resp = @api_node.create('rund/services',params)
|
684
|
+
resp = @api_node.create('rund/services', params)
|
592
685
|
return Main.result_status("#{resp[:data]['id']} created")
|
593
686
|
when :delete
|
594
687
|
@api_node.delete("rund/services/#{svcid}")
|
@@ -606,15 +699,15 @@ module Aspera
|
|
606
699
|
@api_node.params[:headers]['X-aspera-WF-version'] = '2017_10_23'
|
607
700
|
case command
|
608
701
|
when :create
|
609
|
-
resp = @api_node.create(res_class_path,options.get_option(:value,is_type: :mandatory))
|
702
|
+
resp = @api_node.create(res_class_path, options.get_option(:value, is_type: :mandatory))
|
610
703
|
return Main.result_status("#{resp[:data]['id']} created")
|
611
704
|
when :list
|
612
|
-
resp = @api_node.read(res_class_path,options.get_option(:value))
|
705
|
+
resp = @api_node.read(res_class_path, options.get_option(:value))
|
613
706
|
return { type: :value_list, data: resp[:data]['ids'], name: 'id' }
|
614
707
|
when :show
|
615
708
|
return { type: :single_object, data: @api_node.read(one_res_path)[:data]}
|
616
709
|
when :modify
|
617
|
-
@api_node.update(one_res_path,options.get_option(:value,is_type: :mandatory))
|
710
|
+
@api_node.update(one_res_path, options.get_option(:value, is_type: :mandatory))
|
618
711
|
return Main.result_status("#{one_res_id} updated")
|
619
712
|
when :delete
|
620
713
|
@api_node.delete(one_res_path)
|
@@ -634,37 +727,40 @@ module Aspera
|
|
634
727
|
case command
|
635
728
|
when :list
|
636
729
|
request_data.deep_merge!({'validation' => validation}) unless validation.nil?
|
637
|
-
resp = @api_node.create('services/rest/transfers/v1/sessions',request_data)
|
638
|
-
return {
|
639
|
-
|
730
|
+
resp = @api_node.create('services/rest/transfers/v1/sessions', request_data)
|
731
|
+
return {
|
732
|
+
type: :object_list,
|
733
|
+
data: resp[:data]['session_info_result']['session_info'],
|
734
|
+
fields: %w[session_uuid status transport direction bytes_transferred]
|
735
|
+
}
|
640
736
|
end
|
641
737
|
when :file
|
642
738
|
command = options.get_next_command(%i[list modify])
|
643
739
|
case command
|
644
740
|
when :list
|
645
741
|
request_data.deep_merge!({'validation' => validation}) unless validation.nil?
|
646
|
-
resp = @api_node.create('services/rest/transfers/v1/files',request_data)[:data]
|
742
|
+
resp = @api_node.create('services/rest/transfers/v1/files', request_data)[:data]
|
647
743
|
resp = JSON.parse(resp) if resp.is_a?(String)
|
648
|
-
Log.dump(:resp,resp)
|
744
|
+
Log.dump(:resp, resp)
|
649
745
|
return { type: :object_list, data: resp['file_transfer_info_result']['file_transfer_info'], fields: %w[session_uuid file_id status path]}
|
650
746
|
when :modify
|
651
747
|
request_data.deep_merge!(validation) unless validation.nil?
|
652
|
-
@api_node.update('services/rest/transfers/v1/files',request_data)
|
748
|
+
@api_node.update('services/rest/transfers/v1/files', request_data)
|
653
749
|
return Main.result_status('updated')
|
654
750
|
end
|
655
751
|
end
|
656
752
|
when :asperabrowser
|
657
753
|
browse_params = {
|
658
|
-
'nodeUser' => options.get_option(:username,is_type: :mandatory),
|
659
|
-
'nodePW' => options.get_option(:password,is_type: :mandatory),
|
660
|
-
'nodeURL' => options.get_option(:url,is_type: :mandatory)
|
754
|
+
'nodeUser' => options.get_option(:username, is_type: :mandatory),
|
755
|
+
'nodePW' => options.get_option(:password, is_type: :mandatory),
|
756
|
+
'nodeURL' => options.get_option(:url, is_type: :mandatory)
|
661
757
|
}
|
662
758
|
# encode parameters so that it looks good in url
|
663
759
|
encoded_params = Base64.strict_encode64(Zlib::Deflate.deflate(JSON.generate(browse_params))).gsub(/=+$/, '').tr('+/', '-_').reverse
|
664
760
|
OpenApplication.instance.uri(options.get_option(:asperabrowserurl) + '?goto=' + encoded_params)
|
665
761
|
return Main.result_status('done')
|
666
762
|
when :basic_token
|
667
|
-
return Main.result_status(Rest.basic_creds(options.get_option(:username,is_type: :mandatory),options.get_option(:password,is_type: :mandatory)))
|
763
|
+
return Main.result_status(Rest.basic_creds(options.get_option(:username, is_type: :mandatory), options.get_option(:password, is_type: :mandatory)))
|
668
764
|
end # case command
|
669
765
|
raise 'ERROR: shall not reach this line'
|
670
766
|
end # execute_action
|