aspera-cli 4.14.0 → 4.16.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 +0 -0
- data/BUGS.md +29 -3
- data/CHANGELOG.md +300 -185
- data/CONTRIBUTING.md +74 -23
- data/README.md +2346 -1619
- data/bin/ascli +16 -25
- data/bin/asession +15 -15
- data/examples/dascli +2 -2
- data/examples/proxy.pac +1 -1
- data/lib/aspera/aoc.rb +216 -150
- data/lib/aspera/ascmd.rb +25 -18
- data/lib/aspera/assert.rb +45 -0
- data/lib/aspera/cli/basic_auth_plugin.rb +9 -6
- data/lib/aspera/cli/error.rb +17 -0
- data/lib/aspera/cli/extended_value.rb +51 -16
- data/lib/aspera/cli/formatter.rb +276 -174
- data/lib/aspera/cli/hints.rb +81 -0
- data/lib/aspera/cli/main.rb +114 -147
- data/lib/aspera/cli/manager.rb +181 -136
- data/lib/aspera/cli/plugin.rb +82 -64
- data/lib/aspera/cli/plugins/alee.rb +0 -1
- data/lib/aspera/cli/plugins/aoc.rb +327 -331
- data/lib/aspera/cli/plugins/ats.rb +12 -8
- data/lib/aspera/cli/plugins/bss.rb +2 -2
- data/lib/aspera/cli/plugins/config.rb +575 -439
- data/lib/aspera/cli/plugins/console.rb +40 -0
- data/lib/aspera/cli/plugins/cos.rb +4 -5
- data/lib/aspera/cli/plugins/faspex.rb +111 -92
- data/lib/aspera/cli/plugins/faspex5.rb +245 -182
- data/lib/aspera/cli/plugins/node.rb +239 -160
- data/lib/aspera/cli/plugins/orchestrator.rb +56 -19
- data/lib/aspera/cli/plugins/preview.rb +54 -38
- data/lib/aspera/cli/plugins/server.rb +63 -20
- data/lib/aspera/cli/plugins/shares.rb +64 -38
- data/lib/aspera/cli/sync_actions.rb +68 -0
- data/lib/aspera/cli/transfer_agent.rb +64 -67
- data/lib/aspera/cli/transfer_progress.rb +73 -0
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/colors.rb +3 -1
- data/lib/aspera/command_line_builder.rb +27 -22
- data/lib/aspera/cos_node.rb +6 -4
- data/lib/aspera/coverage.rb +22 -0
- data/lib/aspera/data_repository.rb +33 -2
- data/lib/aspera/environment.rb +21 -8
- data/lib/aspera/fasp/agent_alpha.rb +116 -0
- data/lib/aspera/fasp/agent_base.rb +40 -76
- data/lib/aspera/fasp/agent_connect.rb +21 -22
- data/lib/aspera/fasp/agent_direct.rb +169 -179
- data/lib/aspera/fasp/agent_httpgw.rb +200 -195
- data/lib/aspera/fasp/agent_node.rb +43 -35
- data/lib/aspera/fasp/agent_trsdk.rb +124 -41
- data/lib/aspera/fasp/error_info.rb +2 -2
- data/lib/aspera/fasp/faux_file.rb +52 -0
- data/lib/aspera/fasp/installation.rb +89 -191
- data/lib/aspera/fasp/management.rb +249 -0
- data/lib/aspera/fasp/parameters.rb +86 -47
- data/lib/aspera/fasp/parameters.yaml +75 -8
- data/lib/aspera/fasp/products.rb +162 -0
- data/lib/aspera/fasp/resume_policy.rb +7 -5
- data/lib/aspera/fasp/sync.rb +273 -0
- data/lib/aspera/fasp/transfer_spec.rb +10 -8
- data/lib/aspera/fasp/uri.rb +6 -6
- data/lib/aspera/faspex_gw.rb +11 -8
- data/lib/aspera/faspex_postproc.rb +8 -7
- data/lib/aspera/hash_ext.rb +2 -2
- data/lib/aspera/id_generator.rb +3 -1
- data/lib/aspera/json_rpc.rb +51 -0
- data/lib/aspera/keychain/encrypted_hash.rb +46 -11
- data/lib/aspera/keychain/macos_security.rb +15 -13
- data/lib/aspera/line_logger.rb +23 -0
- data/lib/aspera/log.rb +61 -19
- data/lib/aspera/nagios.rb +7 -2
- data/lib/aspera/node.rb +105 -21
- data/lib/aspera/node_simulator.rb +214 -0
- data/lib/aspera/oauth.rb +57 -36
- data/lib/aspera/open_application.rb +4 -4
- data/lib/aspera/persistency_action_once.rb +13 -14
- data/lib/aspera/persistency_folder.rb +5 -4
- data/lib/aspera/preview/file_types.rb +56 -268
- data/lib/aspera/preview/generator.rb +28 -39
- data/lib/aspera/preview/options.rb +2 -0
- data/lib/aspera/preview/terminal.rb +36 -16
- data/lib/aspera/preview/utils.rb +23 -29
- data/lib/aspera/proxy_auto_config.rb +6 -3
- data/lib/aspera/rest.rb +127 -80
- data/lib/aspera/rest_call_error.rb +1 -1
- data/lib/aspera/rest_error_analyzer.rb +16 -14
- data/lib/aspera/rest_errors_aspera.rb +39 -34
- data/lib/aspera/secret_hider.rb +18 -17
- data/lib/aspera/ssh.rb +10 -5
- data/lib/aspera/temp_file_manager.rb +11 -4
- data/lib/aspera/web_auth.rb +10 -7
- data/lib/aspera/web_server_simple.rb +11 -5
- data.tar.gz.sig +0 -0
- metadata +108 -39
- metadata.gz.sig +0 -0
- data/lib/aspera/cli/listener/line_dump.rb +0 -19
- data/lib/aspera/cli/listener/logger.rb +0 -22
- data/lib/aspera/cli/listener/progress.rb +0 -50
- data/lib/aspera/cli/listener/progress_multi.rb +0 -84
- data/lib/aspera/cli/plugins/sync.rb +0 -44
- data/lib/aspera/fasp/listener.rb +0 -13
- data/lib/aspera/sync.rb +0 -213
|
@@ -7,6 +7,46 @@ module Aspera
|
|
|
7
7
|
module Cli
|
|
8
8
|
module Plugins
|
|
9
9
|
class Console < Aspera::Cli::BasicAuthPlugin
|
|
10
|
+
STANDARD_PATH = '/aspera/console'
|
|
11
|
+
class << self
|
|
12
|
+
def detect(address_or_url)
|
|
13
|
+
address_or_url = "https://#{address_or_url}" unless address_or_url.match?(%r{^[a-z]{1,6}://})
|
|
14
|
+
urls = [address_or_url]
|
|
15
|
+
urls.push("#{address_or_url}#{STANDARD_PATH}") unless address_or_url.end_with?(STANDARD_PATH)
|
|
16
|
+
|
|
17
|
+
urls.each do |base_url|
|
|
18
|
+
next unless base_url.start_with?('https://')
|
|
19
|
+
api = Rest.new(base_url: base_url, redirect_max: 2)
|
|
20
|
+
test_endpoint = 'login'
|
|
21
|
+
test_page = api.call({operation: 'GET', subpath: test_endpoint, url_params: {local: true}})
|
|
22
|
+
next unless test_page[:http].body.include?('Aspera Console')
|
|
23
|
+
version = 'unknown'
|
|
24
|
+
if (m = test_page[:http].body.match(/\(v([1-9]\..*)\)/))
|
|
25
|
+
version = m[1]
|
|
26
|
+
end
|
|
27
|
+
url = test_page[:http].uri.to_s
|
|
28
|
+
return {
|
|
29
|
+
version: version,
|
|
30
|
+
url: url[0..url.index(test_endpoint) - 2]
|
|
31
|
+
}
|
|
32
|
+
rescue StandardError => e
|
|
33
|
+
Log.log.debug{"detect error: #{e}"}
|
|
34
|
+
end
|
|
35
|
+
return nil
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def wizard(object:, private_key_path: nil, pub_key_pem: nil)
|
|
39
|
+
options = object.options
|
|
40
|
+
return {
|
|
41
|
+
preset_value: {
|
|
42
|
+
url: options.get_option(:url, mandatory: true),
|
|
43
|
+
username: options.get_option(:username, mandatory: true),
|
|
44
|
+
password: options.get_option(:password, mandatory: true)
|
|
45
|
+
},
|
|
46
|
+
test_args: 'transfer list'
|
|
47
|
+
}
|
|
48
|
+
end
|
|
49
|
+
end
|
|
10
50
|
DEFAULT_FILTER_AGE_SECONDS = 3 * 3600
|
|
11
51
|
private_constant :DEFAULT_FILTER_AGE_SECONDS
|
|
12
52
|
def initialize(env)
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require 'aspera/cli/plugin'
|
|
4
4
|
require 'aspera/cli/plugins/node'
|
|
5
5
|
require 'aspera/cos_node'
|
|
6
|
+
require 'aspera/assert'
|
|
6
7
|
|
|
7
8
|
module Aspera
|
|
8
9
|
module Cli
|
|
@@ -10,7 +11,6 @@ module Aspera
|
|
|
10
11
|
class Cos < Aspera::Cli::Plugin
|
|
11
12
|
def initialize(env)
|
|
12
13
|
super(env)
|
|
13
|
-
@service_creds = nil
|
|
14
14
|
options.declare(:bucket, 'Bucket name')
|
|
15
15
|
options.declare(:endpoint, 'Storage endpoint url')
|
|
16
16
|
options.declare(:apikey, 'Storage API key')
|
|
@@ -31,19 +31,18 @@ module Aspera
|
|
|
31
31
|
# get service credentials, Hash, e.g. @json:@file:...
|
|
32
32
|
service_credentials = options.get_option(:service_credentials)
|
|
33
33
|
storage_endpoint = options.get_option(:endpoint)
|
|
34
|
-
|
|
35
|
-
raise CliBadArgument, 'endpoint and service_credentials are mutually exclusive' unless service_credentials.nil? || storage_endpoint.nil?
|
|
34
|
+
assert(service_credentials.nil? ^ storage_endpoint.nil?, exception_class: Cli::BadArgument){'endpoint and service_credentials are mutually exclusive'}
|
|
36
35
|
if service_credentials.nil?
|
|
37
36
|
service_api_key = options.get_option(:apikey, mandatory: true)
|
|
38
37
|
instance_id = options.get_option(:crn, mandatory: true)
|
|
39
38
|
else
|
|
40
|
-
params = CosNode.
|
|
39
|
+
params = CosNode.parameters_from_svc_credentials(service_credentials, options.get_option(:region, mandatory: true))
|
|
41
40
|
storage_endpoint = params[:storage_endpoint]
|
|
42
41
|
service_api_key = params[:service_api_key]
|
|
43
42
|
instance_id = params[:instance_id]
|
|
44
43
|
end
|
|
45
44
|
api_node = CosNode.new(bucket_name, storage_endpoint, instance_id, service_api_key, options.get_option(:identity, mandatory: true))
|
|
46
|
-
node_plugin = Node.new(@agents
|
|
45
|
+
node_plugin = Node.new(@agents, api: api_node)
|
|
47
46
|
command = options.get_next_command(Node::COMMANDS_COS)
|
|
48
47
|
return node_plugin.execute_action(command)
|
|
49
48
|
end
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# cspell:ignore passcode xrds workgroups dmembership wmembership
|
|
3
4
|
require 'aspera/cli/basic_auth_plugin'
|
|
4
5
|
require 'aspera/cli/plugins/node'
|
|
5
6
|
require 'aspera/cli/plugins/config'
|
|
6
7
|
require 'aspera/cli/extended_value'
|
|
7
8
|
require 'aspera/cli/transfer_agent'
|
|
8
|
-
require 'aspera/persistency_action_once'
|
|
9
|
-
require 'aspera/open_application'
|
|
10
9
|
require 'aspera/fasp/uri'
|
|
11
10
|
require 'aspera/fasp/transfer_spec'
|
|
11
|
+
require 'aspera/persistency_action_once'
|
|
12
|
+
require 'aspera/open_application'
|
|
12
13
|
require 'aspera/nagios'
|
|
13
14
|
require 'aspera/id_generator'
|
|
15
|
+
require 'aspera/log'
|
|
16
|
+
require 'aspera/assert'
|
|
14
17
|
require 'xmlsimple'
|
|
15
18
|
require 'json'
|
|
16
19
|
require 'cgi'
|
|
@@ -32,69 +35,79 @@ module Aspera
|
|
|
32
35
|
ATOM_EXT_PARAMS = [MAX_ITEMS, MAX_PAGES].concat(ATOM_PARAMS).freeze
|
|
33
36
|
# sub path in url for public link delivery
|
|
34
37
|
PUB_LINK_EXTERNAL_MATCH = 'external_deliveries/'
|
|
38
|
+
STANDARD_PATH = '/aspera/faspex'
|
|
35
39
|
private_constant(*%i[KEY_NODE KEY_PATH PACKAGE_MATCH_FIELD ATOM_MAILBOXES ATOM_PARAMS ATOM_EXT_PARAMS PUB_LINK_EXTERNAL_MATCH])
|
|
36
40
|
|
|
37
41
|
class << self
|
|
38
|
-
def detect(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
def detect(address_or_url)
|
|
43
|
+
address_or_url = "https://#{address_or_url}" unless address_or_url.match?(%r{^[a-z]{1,6}://})
|
|
44
|
+
urls = [address_or_url]
|
|
45
|
+
urls.push("#{address_or_url}#{STANDARD_PATH}") unless address_or_url.end_with?(STANDARD_PATH)
|
|
46
|
+
|
|
47
|
+
urls.each do |base_url|
|
|
48
|
+
next unless base_url.start_with?('https://')
|
|
49
|
+
api = Rest.new(base_url: base_url, redirect_max: 1)
|
|
50
|
+
result = api.call(
|
|
51
|
+
operation: 'POST',
|
|
52
|
+
subpath: '',
|
|
53
|
+
headers: {'Accept' => 'application/xrds+xml', 'Content-type' => 'text/plain'},
|
|
54
|
+
text_body_params: '')
|
|
55
|
+
# 4.x
|
|
56
|
+
next unless result[:http].body.start_with?('<?xml')
|
|
47
57
|
res_s = XmlSimple.xml_in(result[:http].body, {'ForceArray' => false})
|
|
58
|
+
Log.log.debug{"version: #{result[:http]['X-IBM-Aspera']}"}
|
|
48
59
|
version = res_s['XRD']['application']['version']
|
|
49
|
-
|
|
60
|
+
# take redirect if any
|
|
61
|
+
return {version: version, url: result[:http].uri.to_s}
|
|
62
|
+
rescue StandardError => e
|
|
63
|
+
Log.log.debug{"detect error: #{e}"}
|
|
50
64
|
end
|
|
51
65
|
return nil
|
|
52
66
|
end
|
|
53
67
|
|
|
54
|
-
|
|
68
|
+
def wizard(object:, private_key_path: nil, pub_key_pem: nil)
|
|
69
|
+
options = object.options
|
|
70
|
+
return {
|
|
71
|
+
preset_value: {
|
|
72
|
+
url: options.get_option(:url, mandatory: true),
|
|
73
|
+
username: options.get_option(:username, mandatory: true),
|
|
74
|
+
password: options.get_option(:password, mandatory: true)
|
|
75
|
+
},
|
|
76
|
+
test_args: 'me'
|
|
77
|
+
}
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# extract elements from faspex public link
|
|
55
81
|
def get_link_data(public_url)
|
|
56
82
|
public_uri = URI.parse(public_url)
|
|
57
|
-
|
|
83
|
+
assert((m = public_uri.path.match(%r{^(.*)/(external.*)$})), exception_class: Cli::BadArgument){'Public link does not match Faspex format'}
|
|
58
84
|
base = m[1]
|
|
59
85
|
subpath = m[2]
|
|
60
86
|
port_add = public_uri.port.eql?(public_uri.default_port) ? '' : ":#{public_uri.port}"
|
|
61
87
|
result = {
|
|
62
88
|
base_url: "#{public_uri.scheme}://#{public_uri.host}#{port_add}#{base}",
|
|
63
89
|
subpath: subpath,
|
|
64
|
-
query:
|
|
90
|
+
query: Rest.decode_query(public_uri.query)
|
|
65
91
|
}
|
|
66
|
-
Log.dump('link data', result)
|
|
92
|
+
Log.log.debug{Log.dump('link data', result)}
|
|
67
93
|
return result
|
|
68
94
|
end
|
|
69
95
|
|
|
70
|
-
# get
|
|
96
|
+
# get Fasp::Uri::SCHEME URI from entry in xml, and fix problems.
|
|
71
97
|
def get_fasp_uri_from_entry(entry, raise_no_link: true)
|
|
72
98
|
unless entry.key?('link')
|
|
73
|
-
raise
|
|
99
|
+
raise Cli::BadArgument, 'package has no link (deleted?)' if raise_no_link
|
|
74
100
|
return nil
|
|
75
101
|
end
|
|
76
102
|
result = entry['link'].find{|e| e['rel'].eql?('package')}['href']
|
|
77
|
-
# tags in the end of URL is not well % encoded... there are "=" that should be %3D
|
|
78
|
-
# TODO: enter ticket to Faspex ?
|
|
79
|
-
# ##XXif m=result.match(/(=+)$/);result.gsub!(/=+$/,"#{"%3D"*m[1].length}");end
|
|
80
103
|
return result
|
|
81
104
|
end
|
|
82
105
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
# field_sym : :id or :name
|
|
92
|
-
def get_source_id(source_list, source_name)
|
|
93
|
-
source_ids = source_list.select { |i| i['name'].eql?(source_name) }
|
|
94
|
-
if source_ids.empty?
|
|
95
|
-
raise CliError, %Q(No such Faspex source "#{source_name}" in [#{source_list.map{|i| %Q("#{i['name']}")}.join(', ')}])
|
|
96
|
-
end
|
|
97
|
-
return source_ids.first['id']
|
|
106
|
+
# @return [Integer] identifier of source
|
|
107
|
+
def get_source_id_by_name(source_name, source_list)
|
|
108
|
+
match_source = source_list.find { |i| i['name'].eql?(source_name) }
|
|
109
|
+
return match_source['id'] unless match_source.nil?
|
|
110
|
+
raise Cli::Error, %Q(No such Faspex source: "#{source_name}" in [#{source_list.map{|i| %Q("#{i['name']}")}.join(', ')}])
|
|
98
111
|
end
|
|
99
112
|
end
|
|
100
113
|
|
|
@@ -104,8 +117,8 @@ module Aspera
|
|
|
104
117
|
super(env)
|
|
105
118
|
options.declare(:link, 'Public link for specific operation')
|
|
106
119
|
options.declare(:delivery_info, 'Package delivery information', types: Hash)
|
|
107
|
-
options.declare(:
|
|
108
|
-
options.declare(:storage, 'Faspex local storage definition')
|
|
120
|
+
options.declare(:remote_source, 'Remote source for package send (id or %name:)')
|
|
121
|
+
options.declare(:storage, 'Faspex local storage definition (for browsing source)')
|
|
109
122
|
options.declare(:recipient, 'Use if recipient is a dropbox (with *)')
|
|
110
123
|
options.declare(:box, 'Package box', values: ATOM_MAILBOXES, default: :inbox)
|
|
111
124
|
options.parse_options!
|
|
@@ -148,9 +161,9 @@ module Aspera
|
|
|
148
161
|
max_pages = nil
|
|
149
162
|
result = []
|
|
150
163
|
if !mailbox_query.nil?
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
164
|
+
assert_type(mailbox_query, Hash){'query'}
|
|
165
|
+
assert((mailbox_query.keys - ATOM_EXT_PARAMS).empty?){"query: supported params: #{ATOM_EXT_PARAMS}"}
|
|
166
|
+
assert(!(mailbox_query.key?('startIndex') && mailbox_query.key?('page'))){'query: startIndex and page are exclusive'}
|
|
154
167
|
max_items = mailbox_query[MAX_ITEMS]
|
|
155
168
|
mailbox_query.delete(MAX_ITEMS)
|
|
156
169
|
max_pages = mailbox_query[MAX_PAGES]
|
|
@@ -160,8 +173,8 @@ module Aspera
|
|
|
160
173
|
# get a batch of package information
|
|
161
174
|
# order: first batch is latest packages, and then in a batch ids are increasing
|
|
162
175
|
atom_xml = api_v3.call({operation: 'GET', subpath: "#{mailbox}.atom", headers: {'Accept' => 'application/xml'}, url_params: mailbox_query})[:http].body
|
|
163
|
-
box_data = XmlSimple.xml_in(atom_xml, {'ForceArray' =>
|
|
164
|
-
Log.dump(:box_data, box_data)
|
|
176
|
+
box_data = XmlSimple.xml_in(atom_xml, {'ForceArray' => %w[entry field link to]})
|
|
177
|
+
Log.log.debug{Log.dump(:box_data, box_data)}
|
|
165
178
|
items = box_data.key?('entry') ? box_data['entry'] : []
|
|
166
179
|
Log.log.debug{"new items: #{items.count}"}
|
|
167
180
|
# it is the end if page is empty
|
|
@@ -173,11 +186,14 @@ module Aspera
|
|
|
173
186
|
package[PACKAGE_MATCH_FIELD] =
|
|
174
187
|
case mailbox
|
|
175
188
|
when :inbox, :archive
|
|
176
|
-
recipient = package['to'].find{|i|recipient_names.include?(i['name']
|
|
177
|
-
recipient.nil? ? nil : recipient['recipient_delivery_id']
|
|
189
|
+
recipient = package['to'].find{|i|recipient_names.include?(i['name'])}
|
|
190
|
+
recipient.nil? ? nil : recipient['recipient_delivery_id']
|
|
178
191
|
else # :sent
|
|
179
|
-
package['delivery_id']
|
|
192
|
+
package['delivery_id']
|
|
180
193
|
end
|
|
194
|
+
# add special key
|
|
195
|
+
package['items'] = package['link'].is_a?(Array) ? package['link'].length : 0
|
|
196
|
+
package['metadata'] = package['metadata']['field'].each_with_object({}){|i, m| m[i['name']] = i['content'] }
|
|
181
197
|
# if we look for a specific package
|
|
182
198
|
stop_condition = true if !stop_at_id.nil? && stop_at_id.eql?(package[PACKAGE_MATCH_FIELD])
|
|
183
199
|
# keep only those for the specified recipient
|
|
@@ -197,7 +213,7 @@ module Aspera
|
|
|
197
213
|
break if link.nil?
|
|
198
214
|
# replace parameters with the ones from next link
|
|
199
215
|
params = CGI.parse(URI.parse(link['href']).query)
|
|
200
|
-
mailbox_query = params.keys.each_with_object({}){|i, m
|
|
216
|
+
mailbox_query = params.keys.each_with_object({}){|i, m| m[i] = params[i].first }
|
|
201
217
|
Log.log.debug{"query: #{mailbox_query}"}
|
|
202
218
|
break if !max_pages.nil? && (mailbox_query['page'].to_i > max_pages)
|
|
203
219
|
end
|
|
@@ -210,7 +226,7 @@ module Aspera
|
|
|
210
226
|
# pub link user
|
|
211
227
|
link_data = self.class.get_link_data(public_link_url)
|
|
212
228
|
if !['external/submissions/new', 'external/dropbox_submissions/new'].include?(link_data[:subpath])
|
|
213
|
-
raise
|
|
229
|
+
raise Cli::BadArgument, "pub link is #{link_data[:subpath]}, expecting external/submissions/new"
|
|
214
230
|
end
|
|
215
231
|
create_path = link_data[:subpath].split('/')[0..-2].join('/')
|
|
216
232
|
package_create_params[:passcode] = link_data[:query]['passcode']
|
|
@@ -225,11 +241,11 @@ module Aspera
|
|
|
225
241
|
subpath: create_path,
|
|
226
242
|
json_params: package_create_params,
|
|
227
243
|
headers: {'Accept' => 'text/javascript'}})[:http].body
|
|
228
|
-
# get
|
|
244
|
+
# get arguments of function call
|
|
229
245
|
package_creation_data.delete!("\n") # one line
|
|
230
246
|
package_creation_data.gsub!(/^[^"]+\("\{/, '{') # delete header
|
|
231
247
|
package_creation_data.gsub!(/"\);[^"]+$/, '"') # delete trailer
|
|
232
|
-
package_creation_data.gsub!(/\}", *"/, '},"') # between two
|
|
248
|
+
package_creation_data.gsub!(/\}", *"/, '},"') # between two arguments
|
|
233
249
|
package_creation_data.gsub!('\\"', '"') # remove protecting quote
|
|
234
250
|
begin
|
|
235
251
|
package_creation_data = JSON.parse("[#{package_creation_data}]")
|
|
@@ -254,18 +270,20 @@ module Aspera
|
|
|
254
270
|
end
|
|
255
271
|
return nagios.result
|
|
256
272
|
when :package
|
|
257
|
-
command_pkg = options.get_next_command(%i[send
|
|
273
|
+
command_pkg = options.get_next_command(%i[send receive list show], aliases: {recv: :receive})
|
|
258
274
|
case command_pkg
|
|
275
|
+
when :show
|
|
276
|
+
delivery_id = instance_identifier
|
|
277
|
+
return {type: :single_object, data: mailbox_filtered_entries(stop_at_id: delivery_id).find{|p|p[PACKAGE_MATCH_FIELD].eql?(delivery_id)} }
|
|
259
278
|
when :list
|
|
260
279
|
return {
|
|
261
|
-
type:
|
|
262
|
-
data:
|
|
263
|
-
fields:
|
|
264
|
-
textify: lambda {|table_data|Faspex.textify_package_list(table_data)}
|
|
280
|
+
type: :object_list,
|
|
281
|
+
data: mailbox_filtered_entries,
|
|
282
|
+
fields: [PACKAGE_MATCH_FIELD, 'title', 'items']
|
|
265
283
|
}
|
|
266
284
|
when :send
|
|
267
285
|
delivery_info = options.get_option(:delivery_info, mandatory: true)
|
|
268
|
-
|
|
286
|
+
assert_type(delivery_info, Hash, exception_class: Cli::BadArgument){'delivery_info'}
|
|
269
287
|
# actual parameter to faspex API
|
|
270
288
|
package_create_params = {'delivery' => delivery_info}
|
|
271
289
|
public_link_url = options.get_option(:link)
|
|
@@ -274,32 +292,32 @@ module Aspera
|
|
|
274
292
|
delivery_info['sources'] ||= [{'paths' => []}]
|
|
275
293
|
first_source = delivery_info['sources'].first
|
|
276
294
|
first_source['paths'].push(*transfer.source_list)
|
|
277
|
-
|
|
278
|
-
|
|
295
|
+
source_id = instance_identifier(as_option: :remote_source) do |field, value|
|
|
296
|
+
assert(field.eql?('name'), exception_class: Cli::BadArgument){'only name as selector, or give id'}
|
|
279
297
|
source_list = api_v3.call({operation: 'GET', subpath: 'source_shares', headers: {'Accept' => 'application/json'}})[:data]['items']
|
|
280
|
-
|
|
281
|
-
first_source['id'] = source_id
|
|
298
|
+
self.class.get_source_id_by_name(value, source_list)
|
|
282
299
|
end
|
|
300
|
+
first_source['id'] = source_id.to_i unless source_id.nil?
|
|
283
301
|
pkg_created = api_v3.call({
|
|
284
302
|
operation: 'POST',
|
|
285
303
|
subpath: 'send',
|
|
286
304
|
json_params: package_create_params,
|
|
287
305
|
headers: {'Accept' => 'application/json'}
|
|
288
306
|
})[:data]
|
|
289
|
-
if
|
|
290
|
-
# no transfer spec if remote source
|
|
307
|
+
if first_source.key?('id')
|
|
308
|
+
# no transfer spec if remote source: handled by faspex
|
|
291
309
|
return {data: [pkg_created['links']['status']], type: :value_list, name: 'link'}
|
|
292
310
|
end
|
|
293
|
-
raise
|
|
311
|
+
raise Cli::BadArgument, 'expecting one session exactly' if pkg_created['xfer_sessions'].length != 1
|
|
294
312
|
transfer_spec = pkg_created['xfer_sessions'].first
|
|
295
313
|
# use source from cmd line, this one only contains destination (already in dest root)
|
|
296
314
|
transfer_spec.delete('paths')
|
|
297
315
|
else # public link
|
|
298
316
|
transfer_spec = send_public_link_to_ts(public_link_url, package_create_params)
|
|
299
317
|
end
|
|
300
|
-
# Log.dump('transfer_spec',transfer_spec)
|
|
318
|
+
# Log.log.debug{Log.dump('transfer_spec',transfer_spec)}
|
|
301
319
|
return Main.result_transfer(transfer.start(transfer_spec))
|
|
302
|
-
when :
|
|
320
|
+
when :receive
|
|
303
321
|
link_url = options.get_option(:link)
|
|
304
322
|
# list of faspex ID/URI to download
|
|
305
323
|
pkg_id_uri = nil
|
|
@@ -322,11 +340,16 @@ module Aspera
|
|
|
322
340
|
delivery_id = instance_identifier
|
|
323
341
|
raise 'empty id' if delivery_id.empty?
|
|
324
342
|
recipient = options.get_option(:recipient)
|
|
325
|
-
if
|
|
343
|
+
if delivery_id.eql?(ExtendedValue::ALL)
|
|
326
344
|
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)}}
|
|
345
|
+
elsif delivery_id.eql?(ExtendedValue::INIT)
|
|
346
|
+
assert(skip_ids_persistency){'Only with option once_only'}
|
|
347
|
+
skip_ids_persistency.data.clear.concat(mailbox_filtered_entries.map{|i|{id: i[PACKAGE_MATCH_FIELD]}})
|
|
348
|
+
skip_ids_persistency.save
|
|
349
|
+
return Main.result_status("Initialized skip for #{skip_ids_persistency.data.count} package(s)")
|
|
327
350
|
elsif !recipient.nil? && recipient.start_with?('*')
|
|
328
351
|
found_package_link = mailbox_filtered_entries(stop_at_id: delivery_id).find{|p|p[PACKAGE_MATCH_FIELD].eql?(delivery_id)}['link'].first['href']
|
|
329
|
-
raise
|
|
352
|
+
raise "Not Found. Dropbox and Workgroup packages can use the link option with #{Fasp::Uri::SCHEME}" if found_package_link.nil?
|
|
330
353
|
pkg_id_uri = [{id: delivery_id, uri: found_package_link}]
|
|
331
354
|
else
|
|
332
355
|
# TODO: delivery id is the right one if package was receive by workgroup
|
|
@@ -339,12 +362,12 @@ module Aspera
|
|
|
339
362
|
package_entry = XmlSimple.xml_in(entry_xml, {'ForceArray' => true})
|
|
340
363
|
pkg_id_uri = [{id: delivery_id, uri: self.class.get_fasp_uri_from_entry(package_entry)}]
|
|
341
364
|
end
|
|
342
|
-
when
|
|
365
|
+
when /^#{Fasp::Uri::SCHEME}:/o
|
|
343
366
|
pkg_id_uri = [{id: 'package', uri: link_url}]
|
|
344
367
|
else
|
|
345
368
|
link_data = self.class.get_link_data(link_url)
|
|
346
369
|
if !link_data[:subpath].start_with?(PUB_LINK_EXTERNAL_MATCH)
|
|
347
|
-
raise
|
|
370
|
+
raise Cli::BadArgument, "Pub link is #{link_data[:subpath]}. Expecting #{PUB_LINK_EXTERNAL_MATCH}"
|
|
348
371
|
end
|
|
349
372
|
# NOTE: unauthenticated API (authorization is in url params)
|
|
350
373
|
api_public_link = Rest.new({base_url: link_data[:base_url]})
|
|
@@ -355,10 +378,10 @@ module Aspera
|
|
|
355
378
|
headers: {'Accept' => 'application/xml'})
|
|
356
379
|
if !package_creation_data[:http].body.start_with?('<?xml ')
|
|
357
380
|
OpenApplication.instance.uri(link_url)
|
|
358
|
-
raise
|
|
381
|
+
raise Cli::Error, 'Unexpected response: package not found ?'
|
|
359
382
|
end
|
|
360
383
|
package_entry = XmlSimple.xml_in(package_creation_data[:http].body, {'ForceArray' => false})
|
|
361
|
-
Log.dump(:package_entry, package_entry)
|
|
384
|
+
Log.log.debug{Log.dump(:package_entry, package_entry)}
|
|
362
385
|
transfer_uri = self.class.get_fasp_uri_from_entry(package_entry)
|
|
363
386
|
pkg_id_uri = [{id: package_entry['id'], uri: transfer_uri}]
|
|
364
387
|
end # public link
|
|
@@ -366,7 +389,7 @@ module Aspera
|
|
|
366
389
|
# TODO : remove ids from skip not present in inbox to avoid growing too big
|
|
367
390
|
# skip_ids_data.select!{|id|pkg_id_uri.select{|p|p[:id].eql?(id)}}
|
|
368
391
|
pkg_id_uri.reject!{|i|skip_ids_data.include?(i[:id])}
|
|
369
|
-
Log.dump(:pkg_id_uri, pkg_id_uri)
|
|
392
|
+
Log.log.debug{Log.dump(:pkg_id_uri, pkg_id_uri)}
|
|
370
393
|
return Main.result_status('no new package') if pkg_id_uri.empty?
|
|
371
394
|
result_transfer = []
|
|
372
395
|
pkg_id_uri.each do |id_uri|
|
|
@@ -375,7 +398,7 @@ module Aspera
|
|
|
375
398
|
statuses = [:success]
|
|
376
399
|
else
|
|
377
400
|
transfer_spec = Fasp::Uri.new(id_uri[:uri]).transfer_spec
|
|
378
|
-
# NOTE: only external users have token in
|
|
401
|
+
# NOTE: only external users have token in Fasp::Uri::SCHEME link !
|
|
379
402
|
if !transfer_spec.key?('token')
|
|
380
403
|
sanitized = id_uri[:uri].gsub('&', '&')
|
|
381
404
|
xml_payload =
|
|
@@ -397,42 +420,38 @@ module Aspera
|
|
|
397
420
|
return Main.result_transfer_multiple(result_transfer)
|
|
398
421
|
end
|
|
399
422
|
when :source
|
|
400
|
-
command_source = options.get_next_command(%i[list
|
|
423
|
+
command_source = options.get_next_command(%i[list info node])
|
|
401
424
|
source_list = api_v3.call({operation: 'GET', subpath: 'source_shares', headers: {'Accept' => 'application/json'}})[:data]['items']
|
|
402
425
|
case command_source
|
|
403
426
|
when :list
|
|
404
427
|
return {type: :object_list, data: source_list}
|
|
405
|
-
else # :
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
# get id and name
|
|
412
|
-
source_name = source_ids.first['name']
|
|
413
|
-
# source_id=source_ids.first['id']
|
|
428
|
+
else # :info :node
|
|
429
|
+
source_id = instance_identifier do |field, value|
|
|
430
|
+
assert(field.eql?('name'), exception_class: Cli::BadArgument){'only name as selector, or give id'}
|
|
431
|
+
self.class.get_source_id_by_name(value, source_list)
|
|
432
|
+
end.to_i
|
|
433
|
+
source_name = source_list.find{|i|i['id'].eql?(source_id)}['name']
|
|
414
434
|
source_hash = options.get_option(:storage, mandatory: true)
|
|
415
435
|
# check value of option
|
|
416
|
-
|
|
436
|
+
assert_type(source_hash, Hash, exception_class: Cli::Error){'storage option'}
|
|
417
437
|
source_hash.each do |name, storage|
|
|
418
|
-
|
|
438
|
+
assert_type(storage, Hash, exception_class: Cli::Error){"storage '#{name}'"}
|
|
419
439
|
[KEY_NODE, KEY_PATH].each do |key|
|
|
420
|
-
|
|
440
|
+
assert(storage.key?(key), exception_class: Cli::Error){"storage '#{name}' must have a '#{key}'"}
|
|
421
441
|
end
|
|
422
442
|
end
|
|
423
443
|
if !source_hash.key?(source_name)
|
|
424
|
-
raise
|
|
444
|
+
raise Cli::Error, "No such storage in config file: \"#{source_name}\" in [#{source_hash.keys.join(', ')}]"
|
|
425
445
|
end
|
|
426
446
|
source_info = source_hash[source_name]
|
|
427
|
-
Log.log.debug{
|
|
428
|
-
|
|
429
|
-
case command_node
|
|
447
|
+
Log.log.debug{Log.dump(:source_info, source_info)}
|
|
448
|
+
case command_source
|
|
430
449
|
when :info
|
|
431
450
|
return {data: source_info, type: :single_object}
|
|
432
451
|
when :node
|
|
433
452
|
node_config = ExtendedValue.instance.evaluate(source_info[KEY_NODE])
|
|
434
|
-
raise CliError, "bad type for: \"#{source_info[KEY_NODE]}\"" unless node_config.is_a?(Hash)
|
|
435
453
|
Log.log.debug{"node=#{node_config}"}
|
|
454
|
+
assert_type(node_config, Hash, exception_class: Cli::Error){source_info[KEY_NODE]}
|
|
436
455
|
api_node = Rest.new({
|
|
437
456
|
base_url: node_config['url'],
|
|
438
457
|
auth: {
|
|
@@ -440,7 +459,7 @@ module Aspera
|
|
|
440
459
|
username: node_config['username'],
|
|
441
460
|
password: node_config['password']}})
|
|
442
461
|
command = options.get_next_command(Node::COMMANDS_FASPEX)
|
|
443
|
-
return Node.new(@agents
|
|
462
|
+
return Node.new(@agents, api: api_node).execute_action(command, source_info[KEY_PATH])
|
|
444
463
|
end
|
|
445
464
|
end
|
|
446
465
|
when :me
|