aspera-cli 4.10.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 +621 -378
- data/bin/ascli +4 -4
- data/bin/asession +11 -11
- data/docs/test_env.conf +28 -19
- data/examples/aoc.rb +4 -4
- data/examples/dascli +11 -9
- data/examples/faspex4.rb +8 -8
- data/examples/node.rb +11 -11
- data/examples/server.rb +9 -9
- 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/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 +110 -110
- data/lib/aspera/cli/plugin.rb +54 -37
- data/lib/aspera/cli/plugins/alee.rb +4 -4
- data/lib/aspera/cli/plugins/aoc.rb +308 -669
- 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 +447 -344
- 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 +110 -112
- data/lib/aspera/cli/plugins/faspex5.rb +67 -46
- data/lib/aspera/cli/plugins/node.rb +364 -288
- 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 +57 -57
- 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 +30 -28
- 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 +65 -67
- data/lib/aspera/fasp/agent_httpgw.rb +72 -68
- 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 +78 -78
- data/lib/aspera/fasp/listener.rb +1 -1
- data/lib/aspera/fasp/parameters.rb +75 -72
- data/lib/aspera/fasp/parameters.yaml +2 -2
- 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 +23 -28
- data/lib/aspera/keychain/macos_security.rb +21 -20
- 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 +13 -13
- 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 +16 -16
- data/lib/aspera/rest.rb +56 -60
- 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 +8 -5
- metadata.gz.sig +0 -0
@@ -18,23 +18,21 @@ require 'cgi'
|
|
18
18
|
module Aspera
|
19
19
|
module Cli
|
20
20
|
module Plugins
|
21
|
-
class Faspex < BasicAuthPlugin
|
21
|
+
class Faspex < Aspera::Cli::BasicAuthPlugin
|
22
22
|
# required hash key for source in config
|
23
23
|
KEY_NODE = 'node' # value must be hash with url, username, password
|
24
24
|
KEY_PATH = 'path' # value must be same sub-path as in Faspex's node
|
25
|
-
VAL_ALL = 'ALL'
|
26
25
|
# added field in result that identifies the package
|
27
26
|
PACKAGE_MATCH_FIELD = 'package_id'
|
28
27
|
# list of supported atoms
|
29
28
|
ATOM_MAILBOXES = %i[inbox archive sent].freeze
|
30
29
|
# allowed parameters for inbox.atom
|
31
30
|
ATOM_PARAMS = %w[page count startIndex].freeze
|
32
|
-
# with special parameters (from Plugin class) : max and pmax
|
33
|
-
ATOM_EXT_PARAMS =
|
31
|
+
# with special parameters (from Plugin class) : max and pmax (from Plugin)
|
32
|
+
ATOM_EXT_PARAMS = [MAX_ITEMS, MAX_PAGES].concat(ATOM_PARAMS).freeze
|
34
33
|
# sub path in url for public link delivery
|
35
34
|
PUB_LINK_EXTERNAL_MATCH = 'external_deliveries/'
|
36
|
-
private_constant
|
37
|
-
:ATOM_EXT_PARAMS,:PUB_LINK_EXTERNAL_MATCH
|
35
|
+
private_constant(*%i[KEY_NODE KEY_PATH PACKAGE_MATCH_FIELD ATOM_MAILBOXES ATOM_PARAMS ATOM_EXT_PARAMS PUB_LINK_EXTERNAL_MATCH])
|
38
36
|
|
39
37
|
class << self
|
40
38
|
def detect(base_url)
|
@@ -56,45 +54,45 @@ module Aspera
|
|
56
54
|
# extract elements from anonymous faspex link
|
57
55
|
def get_link_data(publink)
|
58
56
|
publink_uri = URI.parse(publink)
|
59
|
-
raise CliBadArgument, 'Public link does not match Faspex format' unless (m = publink_uri.path.match(
|
57
|
+
raise CliBadArgument, 'Public link does not match Faspex format' unless (m = publink_uri.path.match(%r{^(.*)/(external.*)$}))
|
60
58
|
base = m[1]
|
61
59
|
subpath = m[2]
|
62
60
|
port_add = publink_uri.port.eql?(publink_uri.default_port) ? '' : ":#{publink_uri.port}"
|
63
61
|
result = {
|
64
62
|
base_url: "#{publink_uri.scheme}://#{publink_uri.host}#{port_add}#{base}",
|
65
63
|
subpath: subpath,
|
66
|
-
query: URI.decode_www_form(publink_uri.query).each_with_object({}){|v,h|h[v.first] = v.last;}
|
64
|
+
query: URI.decode_www_form(publink_uri.query).each_with_object({}){|v, h|h[v.first] = v.last; }
|
67
65
|
}
|
68
|
-
Log.dump('publink',result)
|
66
|
+
Log.dump('publink', result)
|
69
67
|
return result
|
70
68
|
end
|
71
69
|
|
72
70
|
# get faspe: URI from entry in xml, and fix problems..
|
73
71
|
def get_fasp_uri_from_entry(entry, raise_no_link: true)
|
74
|
-
unless entry.
|
72
|
+
unless entry.key?('link')
|
75
73
|
raise CliBadArgument, 'package has no link (deleted?)' if raise_no_link
|
76
74
|
return nil
|
77
75
|
end
|
78
76
|
result = entry['link'].find{|e| e['rel'].eql?('package')}['href']
|
79
77
|
# tags in the end of URL is not well % encoded... there are "=" that should be %3D
|
80
78
|
# TODO: enter ticket to Faspex ?
|
81
|
-
|
79
|
+
# ##XXif m=result.match(/(=+)$/);result.gsub!(/=+$/,"#{"%3D"*m[1].length}");end
|
82
80
|
return result
|
83
81
|
end
|
84
82
|
|
85
83
|
def textify_package_list(table_data)
|
86
84
|
return table_data.map do |e|
|
87
|
-
e.
|
88
|
-
e['items'] = e.
|
85
|
+
e.each_key {|k| e[k] = e[k].first if e[k].is_a?(Array) && (e[k].length == 1)}
|
86
|
+
e['items'] = e.key?('link') ? e['link'].length : 0
|
89
87
|
e
|
90
88
|
end
|
91
89
|
end
|
92
90
|
|
93
91
|
# field_sym : :id or :name
|
94
|
-
def get_source_id(source_list,source_name)
|
92
|
+
def get_source_id(source_list, source_name)
|
95
93
|
source_ids = source_list.select { |i| i['name'].eql?(source_name) }
|
96
94
|
if source_ids.empty?
|
97
|
-
raise CliError
|
95
|
+
raise CliError, %Q(No such Faspex source "#{source_name}" in [#{source_list.map{|i| %Q("#{i['name']}")}.join(', ')}])
|
98
96
|
end
|
99
97
|
return source_ids.first['id']
|
100
98
|
end
|
@@ -104,13 +102,13 @@ module Aspera
|
|
104
102
|
@api_v3 = nil
|
105
103
|
@api_v4 = nil
|
106
104
|
super(env)
|
107
|
-
options.add_opt_simple(:link,'public link for specific operation')
|
108
|
-
options.add_opt_simple(:delivery_info,'package delivery information (extended value)')
|
109
|
-
options.add_opt_simple(:source_name,'create package from remote source (by name)')
|
110
|
-
options.add_opt_simple(:storage,'Faspex local storage definition')
|
111
|
-
options.add_opt_simple(:recipient,'use if recipient is a dropbox (with *)')
|
112
|
-
options.add_opt_list(:box,ATOM_MAILBOXES,'package box')
|
113
|
-
options.set_option(:box
|
105
|
+
options.add_opt_simple(:link, 'public link for specific operation')
|
106
|
+
options.add_opt_simple(:delivery_info, 'package delivery information (extended value)')
|
107
|
+
options.add_opt_simple(:source_name, 'create package from remote source (by name)')
|
108
|
+
options.add_opt_simple(:storage, 'Faspex local storage definition')
|
109
|
+
options.add_opt_simple(:recipient, 'use if recipient is a dropbox (with *)')
|
110
|
+
options.add_opt_list(:box, ATOM_MAILBOXES, 'package box')
|
111
|
+
options.set_option(:box, :inbox)
|
114
112
|
options.parse_options!
|
115
113
|
end
|
116
114
|
|
@@ -123,13 +121,13 @@ module Aspera
|
|
123
121
|
|
124
122
|
def api_v4
|
125
123
|
if @api_v4.nil?
|
126
|
-
faspex_api_base = options.get_option(:url,is_type: :mandatory)
|
124
|
+
faspex_api_base = options.get_option(:url, is_type: :mandatory)
|
127
125
|
@api_v4 = Rest.new({
|
128
126
|
base_url: faspex_api_base + '/api',
|
129
127
|
auth: {
|
130
128
|
type: :oauth2,
|
131
129
|
base_url: faspex_api_base + '/auth/oauth2',
|
132
|
-
auth: {type: :basic, username: options.get_option(:username,is_type: :mandatory), password: options.get_option(:password,is_type: :mandatory)},
|
130
|
+
auth: {type: :basic, username: options.get_option(:username, is_type: :mandatory), password: options.get_option(:password, is_type: :mandatory)},
|
133
131
|
crtype: :generic,
|
134
132
|
generic: {grant_type: 'password'},
|
135
133
|
scope: 'admin'
|
@@ -140,11 +138,11 @@ module Aspera
|
|
140
138
|
|
141
139
|
# query supports : {"startIndex":10,"count":1,"page":109,"max":2,"pmax":1}
|
142
140
|
def mailbox_filtered_entries(stop_at_id: nil)
|
143
|
-
recipient_names = [options.get_option(:recipient) || options.get_option(:username,is_type: :mandatory)]
|
141
|
+
recipient_names = [options.get_option(:recipient) || options.get_option(:username, is_type: :mandatory)]
|
144
142
|
# some workgroup messages have no star in recipient name
|
145
143
|
recipient_names.push(recipient_names.first[1..-1]) if recipient_names.first.start_with?('*')
|
146
144
|
# mailbox is in ATOM_MAILBOXES
|
147
|
-
mailbox = options.get_option(:box,is_type: :mandatory)
|
145
|
+
mailbox = options.get_option(:box, is_type: :mandatory)
|
148
146
|
# parameters
|
149
147
|
mailbox_query = options.get_option(:query)
|
150
148
|
max_items = nil
|
@@ -153,7 +151,7 @@ module Aspera
|
|
153
151
|
if !mailbox_query.nil?
|
154
152
|
raise 'query: must be Hash or nil' unless mailbox_query.is_a?(Hash)
|
155
153
|
raise "query: supported params: #{ATOM_EXT_PARAMS}" unless (mailbox_query.keys - ATOM_EXT_PARAMS).empty?
|
156
|
-
raise 'query: startIndex and page are exclusive' if mailbox_query.
|
154
|
+
raise 'query: startIndex and page are exclusive' if mailbox_query.key?('startIndex') && mailbox_query.key?('page')
|
157
155
|
max_items = mailbox_query[MAX_ITEMS]
|
158
156
|
mailbox_query.delete(MAX_ITEMS)
|
159
157
|
max_pages = mailbox_query[MAX_PAGES]
|
@@ -162,11 +160,11 @@ module Aspera
|
|
162
160
|
loop do
|
163
161
|
# get a batch of package information
|
164
162
|
# order: first batch is latest packages, and then in a batch ids are increasing
|
165
|
-
atom_xml = api_v3.call({operation: 'GET',subpath: "#{mailbox}.atom",headers: {'Accept' => 'application/xml'},url_params: mailbox_query})[:http].body
|
163
|
+
atom_xml = api_v3.call({operation: 'GET', subpath: "#{mailbox}.atom", headers: {'Accept' => 'application/xml'}, url_params: mailbox_query})[:http].body
|
166
164
|
box_data = XmlSimple.xml_in(atom_xml, {'ForceArray' => true})
|
167
|
-
Log.dump(:box_data,box_data)
|
168
|
-
items = box_data.
|
169
|
-
Log.log.debug
|
165
|
+
Log.dump(:box_data, box_data)
|
166
|
+
items = box_data.key?('entry') ? box_data['entry'] : []
|
167
|
+
Log.log.debug{"new items: #{items.count}"}
|
170
168
|
# it is the end if page is empty
|
171
169
|
break if items.empty?
|
172
170
|
stop_condition = false
|
@@ -174,7 +172,7 @@ module Aspera
|
|
174
172
|
items.reverse_each do |package|
|
175
173
|
package[PACKAGE_MATCH_FIELD] =
|
176
174
|
case mailbox
|
177
|
-
when :inbox
|
175
|
+
when :inbox, :archive
|
178
176
|
recipient = package['to'].find{|i|recipient_names.include?(i['name'].first)}
|
179
177
|
recipient.nil? ? nil : recipient['recipient_delivery_id'].first
|
180
178
|
else # :sent
|
@@ -186,33 +184,33 @@ module Aspera
|
|
186
184
|
result.push(package) unless package[PACKAGE_MATCH_FIELD].nil?
|
187
185
|
end
|
188
186
|
break if stop_condition
|
189
|
-
#result.push({PACKAGE_MATCH_FIELD=>'======'})
|
190
|
-
Log.log.debug
|
187
|
+
# result.push({PACKAGE_MATCH_FIELD=>'======'})
|
188
|
+
Log.log.debug{"total items: #{result.count}"}
|
191
189
|
# reach the limit ?
|
192
190
|
if !max_items.nil? && (result.count >= max_items)
|
193
|
-
result = result.slice(0,max_items) if result.count > max_items
|
191
|
+
result = result.slice(0, max_items) if result.count > max_items
|
194
192
|
break
|
195
193
|
end
|
196
194
|
link = box_data['link'].find{|i|i['rel'].eql?('next')}
|
197
|
-
Log.log.debug
|
195
|
+
Log.log.debug{"link: #{link}"}
|
198
196
|
# no next link
|
199
197
|
break if link.nil?
|
200
198
|
# replace parameters with the ones from next link
|
201
199
|
params = CGI.parse(URI.parse(link['href']).query)
|
202
|
-
mailbox_query = params.keys.each_with_object({}){|i,m|;m[i] = params[i].first;}
|
203
|
-
Log.log.debug
|
200
|
+
mailbox_query = params.keys.each_with_object({}){|i, m|; m[i] = params[i].first; }
|
201
|
+
Log.log.debug{"query: #{mailbox_query}"}
|
204
202
|
break if !max_pages.nil? && (mailbox_query['page'].to_i > max_pages)
|
205
203
|
end
|
206
204
|
return result
|
207
205
|
end
|
208
206
|
|
209
207
|
# retrieve transfer spec from pub link for send package
|
210
|
-
def send_publink_to_ts(public_link_url,package_create_params)
|
208
|
+
def send_publink_to_ts(public_link_url, package_create_params)
|
211
209
|
delivery_info = package_create_params['delivery']
|
212
210
|
# pub link user
|
213
211
|
link_data = self.class.get_link_data(public_link_url)
|
214
|
-
if !['external/submissions/new','external/dropbox_submissions/new'].include?(link_data[:subpath])
|
215
|
-
raise CliBadArgument,"pub link is #{link_data[:subpath]}, expecting external/submissions/new"
|
212
|
+
if !['external/submissions/new', 'external/dropbox_submissions/new'].include?(link_data[:subpath])
|
213
|
+
raise CliBadArgument, "pub link is #{link_data[:subpath]}, expecting external/submissions/new"
|
216
214
|
end
|
217
215
|
create_path = link_data[:subpath].split('/')[0..-2].join('/')
|
218
216
|
package_create_params[:passcode] = link_data[:query]['passcode']
|
@@ -220,7 +218,7 @@ module Aspera
|
|
220
218
|
delivery_info[:source_paths_list] = transfer.ts_source_paths.map{|i|i['source']}.join("\r\n")
|
221
219
|
api_public_link = Rest.new({base_url: link_data[:base_url]})
|
222
220
|
# Hum, as this does not always work (only user, but not dropbox), we get the javascript and need hack
|
223
|
-
#pkg_created=api_public_link.create(create_path,package_create_params)[:data]
|
221
|
+
# pkg_created=api_public_link.create(create_path,package_create_params)[:data]
|
224
222
|
# so extract data from javascript
|
225
223
|
pkgdatares = api_public_link.call({
|
226
224
|
operation: 'POST',
|
@@ -229,10 +227,10 @@ module Aspera
|
|
229
227
|
headers: {'Accept' => 'text/javascript'}})[:http].body
|
230
228
|
# get args of function call
|
231
229
|
pkgdatares.delete!("\n") # one line
|
232
|
-
pkgdatares.gsub!(/^[^"]+\("\{/,'{') # delete header
|
233
|
-
pkgdatares.gsub!(/"\);[^"]+$/,'"') # delete trailer
|
234
|
-
pkgdatares.gsub!(/\}", *"/,'},"') # between two args
|
235
|
-
pkgdatares.gsub!('\\"','"') # remove protecting quote
|
230
|
+
pkgdatares.gsub!(/^[^"]+\("\{/, '{') # delete header
|
231
|
+
pkgdatares.gsub!(/"\);[^"]+$/, '"') # delete trailer
|
232
|
+
pkgdatares.gsub!(/\}", *"/, '},"') # between two args
|
233
|
+
pkgdatares.gsub!('\\"', '"') # remove protecting quote
|
236
234
|
begin
|
237
235
|
pkgdatares = JSON.parse("[#{pkgdatares}]")
|
238
236
|
rescue JSON::ParserError # => e
|
@@ -250,9 +248,9 @@ module Aspera
|
|
250
248
|
nagios = Nagios.new
|
251
249
|
begin
|
252
250
|
api_v3.read('me')
|
253
|
-
nagios.add_ok('faspex api','accessible')
|
251
|
+
nagios.add_ok('faspex api', 'accessible')
|
254
252
|
rescue StandardError => e
|
255
|
-
nagios.add_critical('faspex api',e.to_s)
|
253
|
+
nagios.add_critical('faspex api', e.to_s)
|
256
254
|
end
|
257
255
|
return nagios.result
|
258
256
|
when :package
|
@@ -262,12 +260,12 @@ module Aspera
|
|
262
260
|
return {
|
263
261
|
type: :object_list,
|
264
262
|
data: mailbox_filtered_entries,
|
265
|
-
fields: [PACKAGE_MATCH_FIELD,'title','items'],
|
263
|
+
fields: [PACKAGE_MATCH_FIELD, 'title', 'items'],
|
266
264
|
textify: lambda {|table_data|Faspex.textify_package_list(table_data)}
|
267
265
|
}
|
268
266
|
when :send
|
269
|
-
delivery_info = options.get_option(:delivery_info,is_type: :mandatory)
|
270
|
-
raise CliBadArgument,'delivery_info must be hash, refer to doc' unless delivery_info.is_a?(Hash)
|
267
|
+
delivery_info = options.get_option(:delivery_info, is_type: :mandatory)
|
268
|
+
raise CliBadArgument, 'delivery_info must be hash, refer to doc' unless delivery_info.is_a?(Hash)
|
271
269
|
# actual parameter to faspex API
|
272
270
|
package_create_params = {'delivery' => delivery_info}
|
273
271
|
public_link_url = options.get_option(:link)
|
@@ -278,8 +276,8 @@ module Aspera
|
|
278
276
|
first_source['paths'].push(*transfer.ts_source_paths.map{|i|i['source']})
|
279
277
|
source_name = options.get_option(:source_name)
|
280
278
|
if !source_name.nil?
|
281
|
-
source_list = api_v3.call({operation: 'GET',subpath: 'source_shares',headers: {'Accept' => 'application/json'}})[:data]['items']
|
282
|
-
source_id = self.class.get_source_id(source_list,source_name)
|
279
|
+
source_list = api_v3.call({operation: 'GET', subpath: 'source_shares', headers: {'Accept' => 'application/json'}})[:data]['items']
|
280
|
+
source_id = self.class.get_source_id(source_list, source_name)
|
283
281
|
first_source['id'] = source_id
|
284
282
|
end
|
285
283
|
pkg_created = api_v3.call({
|
@@ -290,17 +288,17 @@ module Aspera
|
|
290
288
|
})[:data]
|
291
289
|
if !source_name.nil?
|
292
290
|
# no transfer spec if remote source
|
293
|
-
return {data: [pkg_created['links']['status']],type: :value_list,name: 'link'}
|
291
|
+
return {data: [pkg_created['links']['status']], type: :value_list, name: 'link'}
|
294
292
|
end
|
295
|
-
raise CliBadArgument,'expecting one session exactly' if pkg_created['xfer_sessions'].length != 1
|
293
|
+
raise CliBadArgument, 'expecting one session exactly' if pkg_created['xfer_sessions'].length != 1
|
296
294
|
transfer_spec = pkg_created['xfer_sessions'].first
|
297
295
|
# use source from cmd line, this one only contains destination (already in dest root)
|
298
296
|
transfer_spec.delete('paths')
|
299
297
|
else # publink
|
300
|
-
transfer_spec = send_publink_to_ts(public_link_url,package_create_params)
|
298
|
+
transfer_spec = send_publink_to_ts(public_link_url, package_create_params)
|
301
299
|
end
|
302
|
-
#Log.dump('transfer_spec',transfer_spec)
|
303
|
-
return Main.result_transfer(transfer.start(transfer_spec
|
300
|
+
# Log.dump('transfer_spec',transfer_spec)
|
301
|
+
return Main.result_transfer(transfer.start(transfer_spec))
|
304
302
|
when :recv
|
305
303
|
link_url = options.get_option(:link)
|
306
304
|
# list of faspex ID/URI to download
|
@@ -309,46 +307,46 @@ module Aspera
|
|
309
307
|
skip_ids_persistency = nil
|
310
308
|
case link_url
|
311
309
|
when nil # usual case: no link
|
312
|
-
if options.get_option(:once_only,is_type: :mandatory)
|
310
|
+
if options.get_option(:once_only, is_type: :mandatory)
|
313
311
|
skip_ids_persistency = PersistencyActionOnce.new(
|
314
312
|
manager: @agents[:persistency],
|
315
313
|
data: skip_ids_data,
|
316
314
|
id: IdGenerator.from_list([
|
317
315
|
'faspex_recv',
|
318
|
-
options.get_option(:url,is_type: :mandatory),
|
319
|
-
options.get_option(:username,is_type: :mandatory),
|
320
|
-
options.get_option(:box,is_type: :mandatory).to_s
|
316
|
+
options.get_option(:url, is_type: :mandatory),
|
317
|
+
options.get_option(:username, is_type: :mandatory),
|
318
|
+
options.get_option(:box, is_type: :mandatory).to_s
|
321
319
|
]))
|
322
320
|
end
|
323
321
|
# get command line parameters
|
324
322
|
delivid = instance_identifier
|
325
323
|
raise 'empty id' if delivid.empty?
|
326
324
|
recipient = options.get_option(:recipient)
|
327
|
-
if
|
328
|
-
pkg_id_uri = mailbox_filtered_entries.map{|i|{id: i[PACKAGE_MATCH_FIELD],uri: self.class.get_fasp_uri_from_entry(i, raise_no_link: false)}}
|
325
|
+
if VAL_ALL.eql?(delivid)
|
326
|
+
pkg_id_uri = mailbox_filtered_entries.map{|i|{id: i[PACKAGE_MATCH_FIELD], uri: self.class.get_fasp_uri_from_entry(i, raise_no_link: false)}}
|
329
327
|
elsif !recipient.nil? && recipient.start_with?('*')
|
330
328
|
found_package_link = mailbox_filtered_entries(stop_at_id: delivid).find{|p|p[PACKAGE_MATCH_FIELD].eql?(delivid)}['link'].first['href']
|
331
329
|
raise 'Not Found. Dropbox and Workgroup packages can use the link option with faspe:' if found_package_link.nil?
|
332
|
-
pkg_id_uri = [{id: delivid,uri: found_package_link}]
|
330
|
+
pkg_id_uri = [{id: delivid, uri: found_package_link}]
|
333
331
|
else
|
334
332
|
# TODO: delivery id is the right one if package was receive by workgroup
|
335
333
|
endpoint =
|
336
|
-
case options.get_option(:box,is_type: :mandatory)
|
337
|
-
when :inbox
|
334
|
+
case options.get_option(:box, is_type: :mandatory)
|
335
|
+
when :inbox, :archive then'received'
|
338
336
|
when :sent then 'sent'
|
339
337
|
end
|
340
|
-
entry_xml = api_v3.call({operation: 'GET',subpath: "#{endpoint}/#{delivid}",headers: {'Accept' => 'application/xml'}})[:http].body
|
338
|
+
entry_xml = api_v3.call({operation: 'GET', subpath: "#{endpoint}/#{delivid}", headers: {'Accept' => 'application/xml'}})[:http].body
|
341
339
|
package_entry = XmlSimple.xml_in(entry_xml, {'ForceArray' => true})
|
342
|
-
pkg_id_uri = [{id: delivid,uri: self.class.get_fasp_uri_from_entry(package_entry)}]
|
340
|
+
pkg_id_uri = [{id: delivid, uri: self.class.get_fasp_uri_from_entry(package_entry)}]
|
343
341
|
end
|
344
342
|
when /^faspe:/
|
345
|
-
pkg_id_uri = [{id: 'package',uri: link_url}]
|
343
|
+
pkg_id_uri = [{id: 'package', uri: link_url}]
|
346
344
|
else
|
347
345
|
link_data = self.class.get_link_data(link_url)
|
348
346
|
if !link_data[:subpath].start_with?(PUB_LINK_EXTERNAL_MATCH)
|
349
|
-
raise CliBadArgument,"Pub link is #{link_data[:subpath]}. Expecting #{PUB_LINK_EXTERNAL_MATCH}"
|
347
|
+
raise CliBadArgument, "Pub link is #{link_data[:subpath]}. Expecting #{PUB_LINK_EXTERNAL_MATCH}"
|
350
348
|
end
|
351
|
-
#
|
349
|
+
# NOTE: unauthenticated API (authorization is in url params)
|
352
350
|
api_public_link = Rest.new({base_url: link_data[:base_url]})
|
353
351
|
pkgdatares = api_public_link.call(
|
354
352
|
operation: 'GET',
|
@@ -360,15 +358,15 @@ module Aspera
|
|
360
358
|
raise CliError, 'Unexpected response: package not found ?'
|
361
359
|
end
|
362
360
|
package_entry = XmlSimple.xml_in(pkgdatares[:http].body, {'ForceArray' => false})
|
363
|
-
Log.dump(:package_entry,package_entry)
|
361
|
+
Log.dump(:package_entry, package_entry)
|
364
362
|
transfer_uri = self.class.get_fasp_uri_from_entry(package_entry)
|
365
|
-
pkg_id_uri = [{id: package_entry['id'],uri: transfer_uri}]
|
363
|
+
pkg_id_uri = [{id: package_entry['id'], uri: transfer_uri}]
|
366
364
|
end # public link
|
367
365
|
# prune packages already downloaded
|
368
366
|
# TODO : remove ids from skip not present in inbox to avoid growing too big
|
369
367
|
# skip_ids_data.select!{|id|pkg_id_uri.select{|p|p[:id].eql?(id)}}
|
370
368
|
pkg_id_uri.reject!{|i|skip_ids_data.include?(i[:id])}
|
371
|
-
Log.dump(:pkg_id_uri,pkg_id_uri)
|
369
|
+
Log.dump(:pkg_id_uri, pkg_id_uri)
|
372
370
|
return Main.result_status('no new package') if pkg_id_uri.empty?
|
373
371
|
result_transfer = []
|
374
372
|
pkg_id_uri.each do |id_uri|
|
@@ -378,20 +376,20 @@ module Aspera
|
|
378
376
|
else
|
379
377
|
transfer_spec = Fasp::Uri.new(id_uri[:uri]).transfer_spec
|
380
378
|
# NOTE: only external users have token in faspe: link !
|
381
|
-
if !transfer_spec.
|
382
|
-
sanitized = id_uri[:uri].gsub('&','&')
|
379
|
+
if !transfer_spec.key?('token')
|
380
|
+
sanitized = id_uri[:uri].gsub('&', '&')
|
383
381
|
xmlpayload =
|
384
382
|
%Q(<?xml version="1.0" encoding="UTF-8"?><url-list xmlns="http://schemas.asperasoft.com/xml/url-list"><url href="#{sanitized}"/></url-list>)
|
385
383
|
transfer_spec['token'] = api_v3.call({
|
386
384
|
operation: 'POST',
|
387
385
|
subpath: 'issue-token?direction=down',
|
388
|
-
headers: {'Accept' => 'text/plain','Content-Type' => 'application/vnd.aspera.url-list+xml'},
|
386
|
+
headers: {'Accept' => 'text/plain', 'Content-Type' => 'application/vnd.aspera.url-list+xml'},
|
389
387
|
text_body_params: xmlpayload})[:http].body
|
390
388
|
end
|
391
389
|
transfer_spec['direction'] = Fasp::TransferSpec::DIRECTION_RECEIVE
|
392
|
-
statuses = transfer.start(transfer_spec
|
390
|
+
statuses = transfer.start(transfer_spec)
|
393
391
|
end
|
394
|
-
result_transfer.push({'package' => id_uri[:id],Main::STATUS_FIELD => statuses})
|
392
|
+
result_transfer.push({'package' => id_uri[:id], Main::STATUS_FIELD => statuses})
|
395
393
|
# skip only if all sessions completed
|
396
394
|
skip_ids_data.push(id_uri[:id]) if TransferAgent.session_status(statuses).eql?(:success)
|
397
395
|
end
|
@@ -400,87 +398,87 @@ module Aspera
|
|
400
398
|
end
|
401
399
|
when :source
|
402
400
|
command_source = options.get_next_command(%i[list id name])
|
403
|
-
source_list = api_v3.call({operation: 'GET',subpath: 'source_shares',headers: {'Accept' => 'application/json'}})[:data]['items']
|
401
|
+
source_list = api_v3.call({operation: 'GET', subpath: 'source_shares', headers: {'Accept' => 'application/json'}})[:data]['items']
|
404
402
|
case command_source
|
405
403
|
when :list
|
406
|
-
return {type: :object_list,data: source_list}
|
404
|
+
return {type: :object_list, data: source_list}
|
407
405
|
else # :id or :name
|
408
406
|
source_match_val = options.get_next_argument('source id or name')
|
409
407
|
source_ids = source_list.select { |i| i[command_source.to_s].to_s.eql?(source_match_val) }
|
410
408
|
if source_ids.empty?
|
411
|
-
raise CliError,"No such Faspex source #{command_source}: #{source_match_val} in [#{source_list.map{|i| i[command_source.to_s]}.join(', ')}]"
|
409
|
+
raise CliError, "No such Faspex source #{command_source}: #{source_match_val} in [#{source_list.map{|i| i[command_source.to_s]}.join(', ')}]"
|
412
410
|
end
|
413
411
|
# get id and name
|
414
412
|
source_name = source_ids.first['name']
|
415
|
-
#source_id=source_ids.first['id']
|
416
|
-
source_hash = options.get_option(:storage,is_type: :mandatory)
|
413
|
+
# source_id=source_ids.first['id']
|
414
|
+
source_hash = options.get_option(:storage, is_type: :mandatory)
|
417
415
|
# check value of option
|
418
|
-
raise CliError,'storage option must be a Hash' unless source_hash.is_a?(Hash)
|
419
|
-
source_hash.each do |name,storage|
|
420
|
-
raise CliError,"storage '#{name}' must be a Hash" unless storage.is_a?(Hash)
|
421
|
-
[KEY_NODE,KEY_PATH].each do |key|
|
422
|
-
raise CliError,"storage '#{name}' must have a '#{key}'" unless storage.
|
416
|
+
raise CliError, 'storage option must be a Hash' unless source_hash.is_a?(Hash)
|
417
|
+
source_hash.each do |name, storage|
|
418
|
+
raise CliError, "storage '#{name}' must be a Hash" unless storage.is_a?(Hash)
|
419
|
+
[KEY_NODE, KEY_PATH].each do |key|
|
420
|
+
raise CliError, "storage '#{name}' must have a '#{key}'" unless storage.key?(key)
|
423
421
|
end
|
424
422
|
end
|
425
|
-
if !source_hash.
|
426
|
-
raise CliError,"No such storage in config file: \"#{source_name}\" in [#{source_hash.keys.join(', ')}]"
|
423
|
+
if !source_hash.key?(source_name)
|
424
|
+
raise CliError, "No such storage in config file: \"#{source_name}\" in [#{source_hash.keys.join(', ')}]"
|
427
425
|
end
|
428
426
|
source_info = source_hash[source_name]
|
429
|
-
Log.log.debug
|
427
|
+
Log.log.debug{"source_info: #{source_info}"}
|
430
428
|
command_node = options.get_next_command(%i[info node])
|
431
429
|
case command_node
|
432
430
|
when :info
|
433
|
-
return {data: source_info,type: :single_object}
|
431
|
+
return {data: source_info, type: :single_object}
|
434
432
|
when :node
|
435
433
|
node_config = ExtendedValue.instance.evaluate(source_info[KEY_NODE])
|
436
|
-
raise CliError,"bad type for: \"#{source_info[KEY_NODE]}\"" unless node_config.is_a?(Hash)
|
437
|
-
Log.log.debug
|
434
|
+
raise CliError, "bad type for: \"#{source_info[KEY_NODE]}\"" unless node_config.is_a?(Hash)
|
435
|
+
Log.log.debug{"node=#{node_config}"}
|
438
436
|
api_node = Rest.new({
|
439
437
|
base_url: node_config['url'],
|
440
438
|
auth: {
|
441
439
|
type: :basic,
|
442
440
|
username: node_config['username'],
|
443
441
|
password: node_config['password']}})
|
444
|
-
command = options.get_next_command(Node::
|
445
|
-
return Node.new(@agents.merge(skip_basic_auth_options: true, node_api: api_node)).execute_action(command,source_info[KEY_PATH])
|
442
|
+
command = options.get_next_command(Node::COMMANDS_FASPEX)
|
443
|
+
return Node.new(@agents.merge(skip_basic_auth_options: true, node_api: api_node)).execute_action(command, source_info[KEY_PATH])
|
446
444
|
end
|
447
445
|
end
|
448
446
|
when :me
|
449
|
-
my_info = api_v3.call({operation: 'GET',subpath: 'me',headers: {'Accept' => 'application/json'}})[:data]
|
447
|
+
my_info = api_v3.call({operation: 'GET', subpath: 'me', headers: {'Accept' => 'application/json'}})[:data]
|
450
448
|
return {data: my_info, type: :single_object}
|
451
449
|
when :dropbox
|
452
450
|
command_pkg = options.get_next_command([:list])
|
453
451
|
case command_pkg
|
454
452
|
when :list
|
455
|
-
dropbox_list = api_v3.call({operation: 'GET',subpath: 'dropboxes',headers: {'Accept' => 'application/json'}})[:data]
|
453
|
+
dropbox_list = api_v3.call({operation: 'GET', subpath: 'dropboxes', headers: {'Accept' => 'application/json'}})[:data]
|
456
454
|
return {type: :object_list, data: dropbox_list['items'], fields: %w[name id description can_read can_write]}
|
457
455
|
end
|
458
456
|
when :v4
|
459
457
|
command = options.get_next_command(%i[package dropbox dmembership workgroup wmembership user metadata_profile])
|
460
458
|
case command
|
461
459
|
when :dropbox
|
462
|
-
return entity_action(api_v4,'admin/dropboxes',display_fields: %w[id e_wg_name e_wg_desc created_at])
|
460
|
+
return entity_action(api_v4, 'admin/dropboxes', display_fields: %w[id e_wg_name e_wg_desc created_at])
|
463
461
|
when :dmembership
|
464
|
-
return entity_action(api_v4,'dropbox_memberships')
|
462
|
+
return entity_action(api_v4, 'dropbox_memberships')
|
465
463
|
when :workgroup
|
466
|
-
return entity_action(api_v4,'admin/workgroups',display_fields: %w[id e_wg_name e_wg_desc created_at])
|
464
|
+
return entity_action(api_v4, 'admin/workgroups', display_fields: %w[id e_wg_name e_wg_desc created_at])
|
467
465
|
when :wmembership
|
468
|
-
return entity_action(api_v4,'workgroup_memberships')
|
466
|
+
return entity_action(api_v4, 'workgroup_memberships')
|
469
467
|
when :user
|
470
|
-
return entity_action(api_v4,'users',display_fields: %w[id name first_name last_name])
|
468
|
+
return entity_action(api_v4, 'users', display_fields: %w[id name first_name last_name])
|
471
469
|
when :metadata_profile
|
472
|
-
return entity_action(api_v4,'metadata_profiles')
|
470
|
+
return entity_action(api_v4, 'metadata_profiles')
|
473
471
|
when :package
|
474
472
|
pkg_box_type = options.get_next_command([:users])
|
475
473
|
pkg_box_id = instance_identifier
|
476
|
-
return entity_action(api_v4,"#{pkg_box_type}/#{pkg_box_id}/packages")
|
474
|
+
return entity_action(api_v4, "#{pkg_box_type}/#{pkg_box_id}/packages")
|
477
475
|
end
|
478
476
|
when :address_book
|
479
477
|
result = api_v3.call(
|
480
478
|
operation: 'GET',
|
481
479
|
subpath: 'address-book',
|
482
480
|
headers: {'Accept' => 'application/json'},
|
483
|
-
url_params: {'format' => 'json','count' => 100_000}
|
481
|
+
url_params: {'format' => 'json', 'count' => 100_000}
|
484
482
|
)[:data]
|
485
483
|
self.format.display_status("users: #{result['itemsPerPage']}/#{result['totalResults']}, start:#{result['startIndex']}")
|
486
484
|
users = result['entry']
|
@@ -491,15 +489,15 @@ module Aspera
|
|
491
489
|
u['email'] = email['value'] unless email.nil?
|
492
490
|
end
|
493
491
|
if u['email'].nil?
|
494
|
-
Log.log.warn
|
492
|
+
Log.log.warn{"Skip user without email: #{u}"}
|
495
493
|
next
|
496
494
|
end
|
497
|
-
u['first_name'],u['last_name'] = u['displayName'].split(' ',2)
|
495
|
+
u['first_name'], u['last_name'] = u['displayName'].split(' ', 2)
|
498
496
|
u['x'] = true
|
499
497
|
end
|
500
|
-
return {type: :object_list,data: users}
|
498
|
+
return {type: :object_list, data: users}
|
501
499
|
when :login_methods
|
502
|
-
login_meths = api_v3.call({operation: 'GET',subpath: 'login/new',headers: {'Accept' => 'application/xrds+xml'}})[:http].body
|
500
|
+
login_meths = api_v3.call({operation: 'GET', subpath: 'login/new', headers: {'Accept' => 'application/xrds+xml'}})[:http].body
|
503
501
|
login_methods = XmlSimple.xml_in(login_meths, {'ForceArray' => false})
|
504
502
|
return {type: :object_list, data: login_methods['XRD']['Service']}
|
505
503
|
end # command
|