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