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