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