aspera-cli 4.0.0.pre1
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 +7 -0
- data/README.md +3592 -0
- data/bin/ascli +7 -0
- data/bin/asession +89 -0
- data/docs/Makefile +59 -0
- data/docs/README.erb.md +3012 -0
- data/docs/README.md +13 -0
- data/docs/diagrams.txt +49 -0
- data/docs/secrets.make +38 -0
- data/docs/test_env.conf +117 -0
- data/docs/transfer_spec.html +99 -0
- data/examples/aoc.rb +17 -0
- data/examples/proxy.pac +60 -0
- data/examples/transfer.rb +115 -0
- data/lib/aspera/api_detector.rb +60 -0
- data/lib/aspera/ascmd.rb +151 -0
- data/lib/aspera/ats_api.rb +43 -0
- data/lib/aspera/cli/basic_auth_plugin.rb +38 -0
- data/lib/aspera/cli/extended_value.rb +88 -0
- data/lib/aspera/cli/formater.rb +238 -0
- data/lib/aspera/cli/listener/line_dump.rb +17 -0
- data/lib/aspera/cli/listener/logger.rb +20 -0
- data/lib/aspera/cli/listener/progress.rb +52 -0
- data/lib/aspera/cli/listener/progress_multi.rb +91 -0
- data/lib/aspera/cli/main.rb +304 -0
- data/lib/aspera/cli/manager.rb +440 -0
- data/lib/aspera/cli/plugin.rb +90 -0
- data/lib/aspera/cli/plugins/alee.rb +24 -0
- data/lib/aspera/cli/plugins/ats.rb +231 -0
- data/lib/aspera/cli/plugins/bss.rb +71 -0
- data/lib/aspera/cli/plugins/config.rb +806 -0
- data/lib/aspera/cli/plugins/console.rb +62 -0
- data/lib/aspera/cli/plugins/cos.rb +106 -0
- data/lib/aspera/cli/plugins/faspex.rb +377 -0
- data/lib/aspera/cli/plugins/faspex5.rb +93 -0
- data/lib/aspera/cli/plugins/node.rb +438 -0
- data/lib/aspera/cli/plugins/oncloud.rb +937 -0
- data/lib/aspera/cli/plugins/orchestrator.rb +169 -0
- data/lib/aspera/cli/plugins/preview.rb +464 -0
- data/lib/aspera/cli/plugins/server.rb +216 -0
- data/lib/aspera/cli/plugins/shares.rb +63 -0
- data/lib/aspera/cli/plugins/shares2.rb +114 -0
- data/lib/aspera/cli/plugins/sync.rb +65 -0
- data/lib/aspera/cli/plugins/xnode.rb +115 -0
- data/lib/aspera/cli/transfer_agent.rb +251 -0
- data/lib/aspera/cli/version.rb +5 -0
- data/lib/aspera/colors.rb +39 -0
- data/lib/aspera/command_line_builder.rb +137 -0
- data/lib/aspera/fasp/aoc.rb +24 -0
- data/lib/aspera/fasp/connect.rb +99 -0
- data/lib/aspera/fasp/error.rb +21 -0
- data/lib/aspera/fasp/error_info.rb +60 -0
- data/lib/aspera/fasp/http_gw.rb +81 -0
- data/lib/aspera/fasp/installation.rb +240 -0
- data/lib/aspera/fasp/listener.rb +11 -0
- data/lib/aspera/fasp/local.rb +377 -0
- data/lib/aspera/fasp/manager.rb +69 -0
- data/lib/aspera/fasp/node.rb +88 -0
- data/lib/aspera/fasp/parameters.rb +235 -0
- data/lib/aspera/fasp/resume_policy.rb +76 -0
- data/lib/aspera/fasp/uri.rb +51 -0
- data/lib/aspera/faspex_gw.rb +196 -0
- data/lib/aspera/hash_ext.rb +28 -0
- data/lib/aspera/log.rb +80 -0
- data/lib/aspera/nagios.rb +71 -0
- data/lib/aspera/node.rb +14 -0
- data/lib/aspera/oauth.rb +319 -0
- data/lib/aspera/on_cloud.rb +421 -0
- data/lib/aspera/open_application.rb +72 -0
- data/lib/aspera/persistency_action_once.rb +42 -0
- data/lib/aspera/persistency_folder.rb +91 -0
- data/lib/aspera/preview/file_types.rb +300 -0
- data/lib/aspera/preview/generator.rb +258 -0
- data/lib/aspera/preview/image_error.png +0 -0
- data/lib/aspera/preview/options.rb +35 -0
- data/lib/aspera/preview/utils.rb +131 -0
- data/lib/aspera/preview/video_error.png +0 -0
- data/lib/aspera/proxy_auto_config.erb.js +287 -0
- data/lib/aspera/proxy_auto_config.rb +34 -0
- data/lib/aspera/rest.rb +296 -0
- data/lib/aspera/rest_call_error.rb +13 -0
- data/lib/aspera/rest_error_analyzer.rb +98 -0
- data/lib/aspera/rest_errors_aspera.rb +58 -0
- data/lib/aspera/ssh.rb +53 -0
- data/lib/aspera/sync.rb +82 -0
- data/lib/aspera/temp_file_manager.rb +37 -0
- data/lib/aspera/uri_reader.rb +25 -0
- metadata +288 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'aspera/cli/basic_auth_plugin'
|
2
|
+
require 'aspera/nagios'
|
3
|
+
|
4
|
+
module Aspera
|
5
|
+
module Cli
|
6
|
+
module Plugins
|
7
|
+
class Console < BasicAuthPlugin
|
8
|
+
def initialize(env)
|
9
|
+
super(env)
|
10
|
+
self.options.add_opt_date(:filter_from,"only after date")
|
11
|
+
self.options.add_opt_date(:filter_to,"only before date")
|
12
|
+
self.options.set_option(:filter_from,Manager.time_to_string(Time.now - 3*3600))
|
13
|
+
self.options.set_option(:filter_to,Manager.time_to_string(Time.now))
|
14
|
+
self.options.parse_options!
|
15
|
+
end
|
16
|
+
|
17
|
+
ACTIONS=[:transfer,:nagios_check]
|
18
|
+
|
19
|
+
def execute_action
|
20
|
+
api_console=basic_auth_api('api')
|
21
|
+
command=self.options.get_next_command(ACTIONS)
|
22
|
+
case command
|
23
|
+
when :nagios_check
|
24
|
+
nagios=Nagios.new
|
25
|
+
begin
|
26
|
+
api_console.read('ssh_keys')
|
27
|
+
nagios.add_ok('console api','accessible')
|
28
|
+
rescue => e
|
29
|
+
nagios.add_critical('console api',e.to_s)
|
30
|
+
end
|
31
|
+
return nagios.result
|
32
|
+
when :transfer
|
33
|
+
command=self.options.get_next_command([ :current, :smart ])
|
34
|
+
case command
|
35
|
+
when :smart
|
36
|
+
command=self.options.get_next_command([:list,:submit])
|
37
|
+
case command
|
38
|
+
when :list
|
39
|
+
return {:type=>:object_list,:data=>api_console.read('smart_transfers')[:data]}
|
40
|
+
when :submit
|
41
|
+
smart_id = self.options.get_next_argument("smart_id")
|
42
|
+
params = self.options.get_next_argument("transfer parameters")
|
43
|
+
return {:type=>:object_list,:data=>api_console.create('smart_transfers/'+smart_id,params)[:data]}
|
44
|
+
end
|
45
|
+
when :current
|
46
|
+
command=self.options.get_next_command([ :list ])
|
47
|
+
case command
|
48
|
+
when :list
|
49
|
+
return {:type=>:object_list,
|
50
|
+
:data=>api_console.read('transfers',{
|
51
|
+
'from'=>self.options.get_option(:filter_from,:mandatory),
|
52
|
+
'to'=>self.options.get_option(:filter_to,:mandatory)
|
53
|
+
})[:data],
|
54
|
+
:fields=>['id','contact','name','status']}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end # Console
|
60
|
+
end # Plugins
|
61
|
+
end # Cli
|
62
|
+
end # Aspera
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'aspera/cli/plugins/node'
|
2
|
+
require 'aspera/cli/plugin'
|
3
|
+
require 'xmlsimple'
|
4
|
+
|
5
|
+
module Aspera
|
6
|
+
module Cli
|
7
|
+
module Plugins
|
8
|
+
class Cos < Plugin
|
9
|
+
# IBM Cloud authentication : + token
|
10
|
+
IBM_CLOUD_OAUTH_URL='https://iam.cloud.ibm.com/identity'
|
11
|
+
private_constant :IBM_CLOUD_OAUTH_URL
|
12
|
+
def initialize(env)
|
13
|
+
super(env)
|
14
|
+
@service_creds=nil
|
15
|
+
self.options.add_opt_simple(:bucket,'IBM Cloud Object storage bucket')
|
16
|
+
self.options.add_opt_simple(:endpoint,'storage endpoint url')
|
17
|
+
self.options.add_opt_simple(:apikey,'storage API key')
|
18
|
+
self.options.add_opt_simple(:crn,'ressource instance id')
|
19
|
+
#self.options.add_opt_simple(:oauth,'Oauth url')
|
20
|
+
self.options.add_opt_simple(:service_credentials,'IBM Cloud service credentials (Hash)')
|
21
|
+
self.options.add_opt_simple(:region,'IBM Cloud Object storage region')
|
22
|
+
end
|
23
|
+
|
24
|
+
ACTIONS=[:node]
|
25
|
+
|
26
|
+
def execute_action
|
27
|
+
command=self.options.get_next_command(ACTIONS)
|
28
|
+
case command
|
29
|
+
when :node
|
30
|
+
bucket_name=self.options.get_option(:bucket,:mandatory)
|
31
|
+
# get service credentials, Hash, e.g. @json:@file:...
|
32
|
+
service_credentials=self.options.get_option(:service_credentials,:optional)
|
33
|
+
storage_endpoint=self.options.get_option(:endpoint,:optional)
|
34
|
+
raise "one of: endpoint or service_credentials is required" if service_credentials.nil? and storage_endpoint.nil?
|
35
|
+
raise "endpoint and service_credentials are mutually exclusive" unless service_credentials.nil? or storage_endpoint.nil?
|
36
|
+
if service_credentials.nil?
|
37
|
+
serv_cred_storage_api_key = self.options.get_option(:apikey,:mandatory)
|
38
|
+
instance_id = self.options.get_option(:crn,:mandatory)
|
39
|
+
else
|
40
|
+
# check necessary contents
|
41
|
+
raise CliBadArgument,'service_credentials must be a Hash' unless service_credentials.is_a?(Hash)
|
42
|
+
['apikey','resource_instance_id','endpoints'].each do |field|
|
43
|
+
raise CliBadArgument,"service_credentials must have a field: #{field}" unless service_credentials.has_key?(field)
|
44
|
+
end
|
45
|
+
Aspera::Log.dump('service_credentials',service_credentials)
|
46
|
+
# get options
|
47
|
+
bucket_region=self.options.get_option(:region,:mandatory)
|
48
|
+
# get API key from service credentials
|
49
|
+
serv_cred_storage_api_key=service_credentials['apikey']
|
50
|
+
instance_id=service_credentials['resource_instance_id']
|
51
|
+
# read endpoints from service provided in service credentials
|
52
|
+
endpoints=Aspera::Rest.new({:base_url=>service_credentials['endpoints']}).read('')[:data]
|
53
|
+
Aspera::Log.dump('endpoints',endpoints)
|
54
|
+
storage_endpoint='https://'+endpoints['service-endpoints']['regional'][bucket_region]['public'][bucket_region]
|
55
|
+
end
|
56
|
+
|
57
|
+
s3_api=Aspera::Rest.new({
|
58
|
+
:base_url => storage_endpoint,
|
59
|
+
:not_auth_codes => ['401','403'],
|
60
|
+
:headers => {'ibm-service-instance-id' => instance_id},
|
61
|
+
:auth => {
|
62
|
+
:type => :oauth2,
|
63
|
+
:base_url => IBM_CLOUD_OAUTH_URL,
|
64
|
+
:grant => :ibm_apikey,
|
65
|
+
:api_key => serv_cred_storage_api_key
|
66
|
+
}})
|
67
|
+
# read FASP connection information for bucket
|
68
|
+
xml_result_text=s3_api.call({:operation=>'GET',:subpath=>bucket_name,:headers=>{'Accept'=>'application/xml'},:url_params=>{'faspConnectionInfo'=>nil}})[:http].body
|
69
|
+
ats_info=XmlSimple.xml_in(xml_result_text, {'ForceArray' => false})
|
70
|
+
Aspera::Log.dump('ats_info',ats_info)
|
71
|
+
# get delegated token
|
72
|
+
delegated_oauth=Oauth.new({
|
73
|
+
:type => :oauth2,
|
74
|
+
:base_url => IBM_CLOUD_OAUTH_URL,
|
75
|
+
:grant => :delegated_refresh,
|
76
|
+
:api_key => serv_cred_storage_api_key,
|
77
|
+
:token_field=> 'delegated_refresh_token'
|
78
|
+
})
|
79
|
+
# to be placed in rest call header and in transfer tags
|
80
|
+
aspera_storage_credentials={
|
81
|
+
'type' => 'token',
|
82
|
+
'token' => {'delegated_refresh_token'=>delegated_oauth.get_authorization().gsub(/^Bearer /,'')}
|
83
|
+
}
|
84
|
+
# transfer spec addition
|
85
|
+
add_ts={'tags'=>{'aspera'=>{'node'=>{'storage_credentials'=>aspera_storage_credentials}}}}
|
86
|
+
# set a general addon to transfer spec
|
87
|
+
# here we choose to use the add_request_param
|
88
|
+
#self.transfer.option_transfer_spec_deep_merge(add_ts)
|
89
|
+
api_node=Rest.new({
|
90
|
+
:base_url => ats_info['ATSEndpoint'],
|
91
|
+
:headers => {'X-Aspera-Storage-Credentials'=>JSON.generate(aspera_storage_credentials)},
|
92
|
+
:auth => {
|
93
|
+
:type => :basic,
|
94
|
+
:username => ats_info['AccessKey']['Id'],
|
95
|
+
:password => ats_info['AccessKey']['Secret']}})
|
96
|
+
#command=self.options.get_next_command(Node::ACTIONS)
|
97
|
+
#command=self.options.get_next_command(Node::COMMON_ACTIONS)
|
98
|
+
command=self.options.get_next_command([:upload,:download,:info,:access_key,:api_details])
|
99
|
+
node_plugin=Node.new(@agents.merge(skip_basic_auth_options: true, node_api: api_node, add_request_param: add_ts))
|
100
|
+
return node_plugin.execute_action(command)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,377 @@
|
|
1
|
+
require 'aspera/cli/basic_auth_plugin'
|
2
|
+
require 'aspera/cli/plugins/node'
|
3
|
+
require 'aspera/cli/plugins/config'
|
4
|
+
require 'aspera/cli/extended_value'
|
5
|
+
require 'aspera/cli/transfer_agent'
|
6
|
+
require 'aspera/persistency_action_once'
|
7
|
+
require 'aspera/open_application'
|
8
|
+
require 'aspera/fasp/uri'
|
9
|
+
require 'aspera/nagios'
|
10
|
+
require 'xmlsimple'
|
11
|
+
require 'json'
|
12
|
+
|
13
|
+
module Aspera
|
14
|
+
module Cli
|
15
|
+
module Plugins
|
16
|
+
class Faspex < BasicAuthPlugin
|
17
|
+
KEY_NODE='node'
|
18
|
+
KEY_PATH='path'
|
19
|
+
VAL_ALL='ALL'
|
20
|
+
private_constant :KEY_NODE,:KEY_PATH,:VAL_ALL
|
21
|
+
def initialize(env)
|
22
|
+
@api_v3=nil
|
23
|
+
@api_v4=nil
|
24
|
+
super(env)
|
25
|
+
self.options.add_opt_simple(:link,'public link for specific operation')
|
26
|
+
self.options.add_opt_simple(:delivery_info,'package delivery information (extended value)')
|
27
|
+
self.options.add_opt_simple(:source_name,'create package from remote source (by name)')
|
28
|
+
self.options.add_opt_simple(:storage,'Faspex local storage definition')
|
29
|
+
self.options.add_opt_list(:box,[:inbox,:sent,:archive],'package box')
|
30
|
+
self.options.set_option(:box,:inbox)
|
31
|
+
self.options.parse_options!
|
32
|
+
end
|
33
|
+
|
34
|
+
# extract elements from anonymous faspex link
|
35
|
+
def self.get_link_data(publink)
|
36
|
+
publink_uri=URI.parse(publink)
|
37
|
+
if m=publink_uri.path.match(/^(.*)\/(external.*)$/)
|
38
|
+
base=m[1]
|
39
|
+
subpath=m[2]
|
40
|
+
else
|
41
|
+
raise CliBadArgument, 'public link does not match Faspex format'
|
42
|
+
end
|
43
|
+
port_add=publink_uri.port.eql?(publink_uri.default_port)?'':":#{publink_uri.port}"
|
44
|
+
result={
|
45
|
+
:base_url => "#{publink_uri.scheme}://#{publink_uri.host}#{port_add}#{base}",
|
46
|
+
:subpath => subpath,
|
47
|
+
:query => URI::decode_www_form(publink_uri.query).inject({}){|m,v|m[v.first]=v.last;m}
|
48
|
+
}
|
49
|
+
Log.dump('publink',result)
|
50
|
+
return result
|
51
|
+
end
|
52
|
+
|
53
|
+
# get faspe: URI from entry in xml, and fix problems..
|
54
|
+
def self.get_fasp_uri_from_entry(entry)
|
55
|
+
raise CliBadArgument, 'package is empty' unless entry.has_key?('link')
|
56
|
+
result=entry['link'].select{|e| e['rel'].eql?('package')}.first['href']
|
57
|
+
# tags in the end of URL is not well % encoded... there are "=" that should be %3D
|
58
|
+
# TODO: enter ticket to Faspex ?
|
59
|
+
###XXif m=result.match(/(=+)$/);result.gsub!(/=+$/,"#{"%3D"*m[1].length}");end
|
60
|
+
return result
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.textify_package_list(table_data)
|
64
|
+
return table_data.map { |e|
|
65
|
+
e.keys.each {|k| e[k]=e[k].first if e[k].is_a?(Array) and e[k].length == 1}
|
66
|
+
e['items'] = e.has_key?('link') ? e['link'].length : 0
|
67
|
+
e
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
# field_sym : :id or :name
|
72
|
+
def self.get_source_id(source_list,source_name)
|
73
|
+
source_ids=source_list.select { |i| i['name'].eql?(source_name) }
|
74
|
+
if source_ids.empty?
|
75
|
+
raise CliError,"No such Faspex source #{field_sym.to_s}: #{field_value} in [#{source_list.map{|i| i[field_sym.to_s]}.join(', ')}]"
|
76
|
+
end
|
77
|
+
return source_ids.first['id']
|
78
|
+
end
|
79
|
+
|
80
|
+
def api_v3
|
81
|
+
if @api_v3.nil?
|
82
|
+
@api_v3=basic_auth_api
|
83
|
+
end
|
84
|
+
return @api_v3
|
85
|
+
end
|
86
|
+
|
87
|
+
def api_v4
|
88
|
+
if @api_v4.nil?
|
89
|
+
faspex_api_base=self.options.get_option(:url,:mandatory)
|
90
|
+
@api_v4=Rest.new({
|
91
|
+
:base_url => faspex_api_base+'/api',
|
92
|
+
:auth => {
|
93
|
+
:type => :oauth2,
|
94
|
+
:base_url => faspex_api_base+'/auth/oauth2',
|
95
|
+
:grant => :header_userpass,
|
96
|
+
:user_name => self.options.get_option(:username,:mandatory),
|
97
|
+
:user_pass => self.options.get_option(:password,:mandatory),
|
98
|
+
:scope => 'admin'
|
99
|
+
}})
|
100
|
+
end
|
101
|
+
return @api_v4
|
102
|
+
end
|
103
|
+
|
104
|
+
ACTIONS=[ :nagios_check,:package, :source, :me, :dropbox, :v4, :address_book, :login_methods ]
|
105
|
+
|
106
|
+
# we match recv command on atom feed on this field
|
107
|
+
PACKAGE_MATCH_FIELD='package_id'
|
108
|
+
|
109
|
+
def mailbox_all_entries
|
110
|
+
mailbox=self.options.get_option(:box,:mandatory).to_s
|
111
|
+
all_inbox_xml=api_v3.call({:operation=>'GET',:subpath=>"#{mailbox}.atom",:headers=>{'Accept'=>'application/xml'}})[:http].body
|
112
|
+
all_inbox_data=XmlSimple.xml_in(all_inbox_xml, {'ForceArray' => true})
|
113
|
+
Log.dump(:all_inbox_data,all_inbox_data)
|
114
|
+
result=all_inbox_data.has_key?('entry') ? all_inbox_data['entry'] : []
|
115
|
+
result.each do |e|
|
116
|
+
e[PACKAGE_MATCH_FIELD]=e['to'].first['recipient_delivery_id'].first
|
117
|
+
end
|
118
|
+
# remove dropbox packages
|
119
|
+
result.select!{|p|p['metadata'].first['field'].select{|j|j['name'].eql?('_dropbox_name')}.empty? rescue false}
|
120
|
+
return result
|
121
|
+
end
|
122
|
+
|
123
|
+
# retrieve transfer spec from pub link for send package
|
124
|
+
def send_publink_to_ts(public_link_url,package_create_params)
|
125
|
+
delivery_info=package_create_params['delivery']
|
126
|
+
# pub link user
|
127
|
+
link_data=self.class.get_link_data(public_link_url)
|
128
|
+
if !['external/submissions/new','external/dropbox_submissions/new'].include?(link_data[:subpath])
|
129
|
+
raise CliBadArgument,"pub link is #{link_data[:subpath]}, expecting external/submissions/new"
|
130
|
+
end
|
131
|
+
create_path=link_data[:subpath].split('/')[0..-2].join('/')
|
132
|
+
package_create_params.merge!({:passcode=>link_data[:query]['passcode']})
|
133
|
+
delivery_info.merge!({
|
134
|
+
:transfer_type => 'connect',
|
135
|
+
:source_paths_list => self.transfer.ts_source_paths.map{|i|i['source']}.join("\r\n")})
|
136
|
+
api_public_link=Rest.new({:base_url=>link_data[:base_url]})
|
137
|
+
# Hum, as this does not always work (only user, but not dropbox), we get the javascript and need hack
|
138
|
+
#pkg_created=api_public_link.create(create_path,package_create_params)[:data]
|
139
|
+
# so extract data from javascript
|
140
|
+
pkgdatares=api_public_link.call({:operation=>'POST',:subpath=>create_path,:json_params=>package_create_params,:headers=>{'Accept'=>'text/javascript'}})[:http].body
|
141
|
+
# get args of function call
|
142
|
+
pkgdatares.gsub!("\n",'') # one line
|
143
|
+
pkgdatares.gsub!(/^[^"]+\("\{/,'{') # delete header
|
144
|
+
pkgdatares.gsub!(/"\);[^"]+$/,'"') # delete trailer
|
145
|
+
pkgdatares.gsub!(/\}", *"/,'},"') # between two args
|
146
|
+
pkgdatares.gsub!('\\"','"') # remove protecting quote
|
147
|
+
begin
|
148
|
+
pkgdatares=JSON.parse("[#{pkgdatares}]")
|
149
|
+
rescue JSON::ParserError # => e
|
150
|
+
raise "Link not valid"
|
151
|
+
end
|
152
|
+
return pkgdatares.first
|
153
|
+
end
|
154
|
+
|
155
|
+
def execute_action
|
156
|
+
command=self.options.get_next_command(ACTIONS)
|
157
|
+
case command
|
158
|
+
when :nagios_check
|
159
|
+
nagios=Nagios.new
|
160
|
+
begin
|
161
|
+
api_v3.read('me')
|
162
|
+
nagios.add_ok('faspex api','accessible')
|
163
|
+
rescue => e
|
164
|
+
nagios.add_critical('faspex api',e.to_s)
|
165
|
+
end
|
166
|
+
return nagios.result
|
167
|
+
when :package
|
168
|
+
command_pkg=self.options.get_next_command([ :send, :recv, :list ])
|
169
|
+
case command_pkg
|
170
|
+
when :list
|
171
|
+
return {:type=>:object_list,:data=>self.mailbox_all_entries,:fields=>[PACKAGE_MATCH_FIELD,'title','items'], :textify => lambda { |table_data| Faspex.textify_package_list(table_data)} }
|
172
|
+
when :send
|
173
|
+
delivery_info=self.options.get_option(:delivery_info,:mandatory)
|
174
|
+
raise CliBadArgument,'delivery_info must be hash, refer to doc' unless delivery_info.is_a?(Hash)
|
175
|
+
# actual parameter to faspex API
|
176
|
+
package_create_params={'delivery'=>delivery_info}
|
177
|
+
public_link_url=self.options.get_option(:link,:optional)
|
178
|
+
if public_link_url.nil?
|
179
|
+
# authenticated user
|
180
|
+
delivery_info['sources']||=[{'paths'=>[]}]
|
181
|
+
first_source=delivery_info['sources'].first
|
182
|
+
first_source['paths'].push(*self.transfer.ts_source_paths.map{|i|i['source']})
|
183
|
+
source_name=self.options.get_option(:source_name,:optional)
|
184
|
+
if !source_name.nil?
|
185
|
+
source_list=api_v3.call({:operation=>'GET',:subpath=>'source_shares',:headers=>{'Accept'=>'application/json'}})[:data]['items']
|
186
|
+
source_id=self.class.get_source_id(source_list,source_name)
|
187
|
+
first_source['id']=source_id
|
188
|
+
end
|
189
|
+
pkg_created=api_v3.call({:operation=>'POST',:subpath=>'send',:json_params=>package_create_params,:headers=>{'Accept'=>'application/json'}})[:data]
|
190
|
+
if !source_name.nil?
|
191
|
+
# no transfer spec if remote source
|
192
|
+
return {:data=>[pkg_created['links']['status']],:type=>:value_list,:name=>'link'}
|
193
|
+
end
|
194
|
+
raise CliBadArgument,'expecting one session exactly' if pkg_created['xfer_sessions'].length != 1
|
195
|
+
transfer_spec=pkg_created['xfer_sessions'].first
|
196
|
+
# use source from cmd line, this one only contains destination (already in dest root)
|
197
|
+
transfer_spec.delete('paths')
|
198
|
+
else # publink
|
199
|
+
transfer_spec=send_publink_to_ts(public_link_url,package_create_params)
|
200
|
+
end
|
201
|
+
#Log.dump('transfer_spec',transfer_spec)
|
202
|
+
return Main.result_transfer(self.transfer.start(transfer_spec,{:src=>:node_gen3}))
|
203
|
+
when :recv
|
204
|
+
public_link_url=self.options.get_option(:link,:optional)
|
205
|
+
if !public_link_url.nil?
|
206
|
+
link_data=self.class.get_link_data(public_link_url)
|
207
|
+
if !link_data[:subpath].match(%r{external_deliveries/})
|
208
|
+
raise CliBadArgument,"pub link is #{link_data[:subpath]}, expecting external_deliveries/"
|
209
|
+
end
|
210
|
+
# Note: unauthenticated API
|
211
|
+
api_public_link=Rest.new({:base_url=>link_data[:base_url]})
|
212
|
+
pkgdatares=api_public_link.call({:operation=>'GET',:subpath=>link_data[:subpath],:url_params=>{:passcode=>link_data[:query]['passcode']},:headers=>{'Accept'=>'application/xml'}})
|
213
|
+
if !pkgdatares[:http].body.start_with?('<?xml ')
|
214
|
+
OpenApplication.instance.uri(public_link_url)
|
215
|
+
raise CliError, 'no such package'
|
216
|
+
end
|
217
|
+
package_entry=XmlSimple.xml_in(pkgdatares[:http].body, {'ForceArray' => false})
|
218
|
+
transfer_uri=self.class.get_fasp_uri_from_entry(package_entry)
|
219
|
+
transfer_spec=Fasp::Uri.new(transfer_uri).transfer_spec
|
220
|
+
transfer_spec['direction']='receive'
|
221
|
+
return Main.result_transfer(self.transfer.start(transfer_spec,{:src=>:node_gen3}))
|
222
|
+
end # public link
|
223
|
+
# get command line parameters
|
224
|
+
delivid=self.options.get_option(:id,:mandatory)
|
225
|
+
# list of faspex ID/URI to download
|
226
|
+
pkg_id_uri=nil
|
227
|
+
skip_ids_data=[]
|
228
|
+
skip_ids_persistency=nil
|
229
|
+
if self.options.get_option(:once_only,:mandatory)
|
230
|
+
skip_ids_persistency=PersistencyActionOnce.new(
|
231
|
+
manager: @agents[:persistency],
|
232
|
+
data: skip_ids_data,
|
233
|
+
ids: ['faspex_recv',self.options.get_option(:url,:mandatory),self.options.get_option(:username,:mandatory),self.options.get_option(:box,:mandatory).to_s])
|
234
|
+
end
|
235
|
+
if delivid.eql?(VAL_ALL)
|
236
|
+
pkg_id_uri=mailbox_all_entries.map{|i|{:id=>i[PACKAGE_MATCH_FIELD],:uri=>self.class.get_fasp_uri_from_entry(i)}}
|
237
|
+
# TODO : remove ids from skip not present in inbox
|
238
|
+
# skip_ids_data.select!{|id|pkg_id_uri.select{|p|p[:id].eql?(id)}}
|
239
|
+
pkg_id_uri.select!{|i|!skip_ids_data.include?(i[:id])}
|
240
|
+
else
|
241
|
+
# TODO: delivery id is the right one if package was receive by group
|
242
|
+
endpoint=case self.options.get_option(:box,:mandatory)
|
243
|
+
when :inbox,:archive;'received'
|
244
|
+
when :sent;'sent'
|
245
|
+
end
|
246
|
+
entry_xml=api_v3.call({:operation=>'GET',:subpath=>"#{endpoint}/#{delivid}",:headers=>{'Accept'=>'application/xml'}})[:http].body
|
247
|
+
package_entry=XmlSimple.xml_in(entry_xml, {'ForceArray' => true})
|
248
|
+
pkg_id_uri=[{:id=>delivid,:uri=>self.class.get_fasp_uri_from_entry(package_entry)}]
|
249
|
+
end
|
250
|
+
Log.dump(:pkg_id_uri,pkg_id_uri)
|
251
|
+
return Main.result_status('no package') if pkg_id_uri.empty?
|
252
|
+
result_transfer=[]
|
253
|
+
pkg_id_uri.each do |id_uri|
|
254
|
+
transfer_spec=Fasp::Uri.new(id_uri[:uri]).transfer_spec
|
255
|
+
# NOTE: only external users have token in faspe: link !
|
256
|
+
if !transfer_spec.has_key?('token')
|
257
|
+
sanitized=id_uri[:uri].gsub('&','&')
|
258
|
+
# TODO: file jira
|
259
|
+
#XXsanitized.gsub!(/%3D%3D$/,'==')
|
260
|
+
#XXsanitized.gsub!(/%3D$/,'=')
|
261
|
+
xmlpayload='<?xml version="1.0" encoding="UTF-8"?><url-list xmlns="http://schemas.asperasoft.com/xml/url-list"><url href="'+sanitized+'"/></url-list>'
|
262
|
+
transfer_spec['token']=api_v3.call({:operation=>'POST',:subpath=>'issue-token?direction=down',:headers=>{'Accept'=>'text/plain','Content-Type'=>'application/vnd.aspera.url-list+xml'},:text_body_params=>xmlpayload})[:http].body
|
263
|
+
end
|
264
|
+
transfer_spec['direction']='receive'
|
265
|
+
statuses=self.transfer.start(transfer_spec,{:src=>:node_gen3})
|
266
|
+
result_transfer.push({'package'=>id_uri[:id],'status'=>statuses.map{|i|i.to_s}.join(',')})
|
267
|
+
# skip only if all sessions completed
|
268
|
+
skip_ids_data.push(id_uri[:id]) if TransferAgent.session_status(statuses).eql?(:success)
|
269
|
+
end
|
270
|
+
skip_ids_persistency.save unless skip_ids_persistency.nil?
|
271
|
+
return {:type=>:object_list,:data=>result_transfer}
|
272
|
+
end
|
273
|
+
when :source
|
274
|
+
command_source=self.options.get_next_command([ :list, :id, :name ])
|
275
|
+
source_list=api_v3.call({:operation=>'GET',:subpath=>'source_shares',:headers=>{'Accept'=>'application/json'}})[:data]['items']
|
276
|
+
case command_source
|
277
|
+
when :list
|
278
|
+
return {:type=>:object_list,:data=>source_list}
|
279
|
+
else # :id or :name
|
280
|
+
source_match_val=self.options.get_next_argument('source id or name')
|
281
|
+
source_ids=source_list.select { |i| i[command_source.to_s].to_s.eql?(source_match_val) }
|
282
|
+
if source_ids.empty?
|
283
|
+
raise CliError,"No such Faspex source #{command_source.to_s}: #{source_match_val} in [#{source_list.map{|i| i[command_source.to_s]}.join(', ')}]"
|
284
|
+
end
|
285
|
+
# get id and name
|
286
|
+
source_name=source_ids.first['name']
|
287
|
+
source_id=source_ids.first['id']
|
288
|
+
source_hash=self.options.get_option(:storage,:mandatory)
|
289
|
+
# check value of option
|
290
|
+
raise CliError,'storage option must be a Hash' unless source_hash.is_a?(Hash)
|
291
|
+
source_hash.each do |name,storage|
|
292
|
+
raise CliError,"storage '#{name}' must be a Hash" unless storage.is_a?(Hash)
|
293
|
+
[KEY_NODE,KEY_PATH].each do |key|
|
294
|
+
raise CliError,"storage '#{name}' must have a '#{key}'" unless storage.has_key?(key)
|
295
|
+
end
|
296
|
+
end
|
297
|
+
if !source_hash.has_key?(source_name)
|
298
|
+
raise CliError,"No such storage in config file: \"#{source_name}\" in [#{source_hash.keys.join(', ')}]"
|
299
|
+
end
|
300
|
+
source_info=source_hash[source_name]
|
301
|
+
Log.log.debug("source_info: #{source_info}")
|
302
|
+
command_node=self.options.get_next_command([ :info, :node ])
|
303
|
+
case command_node
|
304
|
+
when :info
|
305
|
+
return {:data=>source_info,:type=>:single_object}
|
306
|
+
when :node
|
307
|
+
node_config=ExtendedValue.instance.evaluate(source_info[KEY_NODE])
|
308
|
+
raise CliError,"bad type for: \"#{source_info[KEY_NODE]}\"" unless node_config.is_a?(Hash)
|
309
|
+
Log.log.debug("node=#{node_config}")
|
310
|
+
api_node=Rest.new({
|
311
|
+
:base_url => node_config['url'],
|
312
|
+
:auth => {
|
313
|
+
:type =>:basic,
|
314
|
+
:username => node_config['username'],
|
315
|
+
:password => node_config['password']}})
|
316
|
+
command=self.options.get_next_command(Node::COMMON_ACTIONS)
|
317
|
+
return Node.new(@agents.merge(skip_basic_auth_options: true, node_api: api_node)).execute_action(command,source_info[KEY_PATH])
|
318
|
+
end
|
319
|
+
end
|
320
|
+
when :me
|
321
|
+
my_info=api_v3.call({:operation=>'GET',:subpath=>'me',:headers=>{'Accept'=>'application/json'}})[:data]
|
322
|
+
return {:data=>my_info, :type=>:single_object}
|
323
|
+
when :dropbox
|
324
|
+
command_pkg=self.options.get_next_command([ :list ])
|
325
|
+
case command_pkg
|
326
|
+
when :list
|
327
|
+
dropbox_list=api_v3.call({:operation=>'GET',:subpath=>'dropboxes',:headers=>{'Accept'=>'application/json'}})[:data]
|
328
|
+
return {:type=>:object_list, :data=>dropbox_list['items'], :fields=>['name','id','description','can_read','can_write']}
|
329
|
+
end
|
330
|
+
when :v4
|
331
|
+
command=self.options.get_next_command([:package,:dropbox, :dmembership, :workgroup,:wmembership,:user,:metadata_profile])
|
332
|
+
case command
|
333
|
+
when :dropbox
|
334
|
+
return self.entity_action(api_v4,'admin/dropboxes',['id','e_wg_name','e_wg_desc','created_at'],:id)
|
335
|
+
when :dmembership
|
336
|
+
return self.entity_action(api_v4,'dropbox_memberships',nil,:id)
|
337
|
+
when :workgroup
|
338
|
+
return self.entity_action(api_v4,'admin/workgroups',['id','e_wg_name','e_wg_desc','created_at'],:id)
|
339
|
+
when :wmembership
|
340
|
+
return self.entity_action(api_v4,'workgroup_memberships',nil,:id)
|
341
|
+
when :user
|
342
|
+
return self.entity_action(api_v4,'users',['id','name','first_name','last_name'],:id)
|
343
|
+
when :metadata_profile
|
344
|
+
return self.entity_action(api_v4,'metadata_profiles',nil,:id)
|
345
|
+
when :package
|
346
|
+
pkg_box_type=self.options.get_next_command([:users])
|
347
|
+
pkg_box_id=self.options.get_option(:id,:mandatory)
|
348
|
+
return self.entity_action(api_v4,"#{pkg_box_type}/#{pkg_box_id}/packages",nil,:id)
|
349
|
+
end
|
350
|
+
when :address_book
|
351
|
+
result=api_v3.call({:operation=>'GET',:subpath=>'address-book',:headers=>{'Accept'=>'application/json'},:url_params=>{'format'=>'json','count'=>100000}})[:data]
|
352
|
+
self.format.display_status("users: #{result['itemsPerPage']}/#{result['totalResults']}, start:#{result['startIndex']}")
|
353
|
+
users=result['entry']
|
354
|
+
# add missing entries
|
355
|
+
users.each do |u|
|
356
|
+
unless u['emails'].nil?
|
357
|
+
email=u['emails'].find{|i|i['primary'].eql?('true')}
|
358
|
+
u['email'] = email['value'] unless email.nil?
|
359
|
+
end
|
360
|
+
if u['email'].nil?
|
361
|
+
Log.log.warn("Skip user without email: #{u}")
|
362
|
+
next
|
363
|
+
end
|
364
|
+
u['first_name'],u['last_name'] = u['displayName'].split(' ',2)
|
365
|
+
u['x']=true
|
366
|
+
end
|
367
|
+
return {:type=>:object_list,:data=>users}
|
368
|
+
when :login_methods
|
369
|
+
login_meths=api_v3.call({:operation=>'GET',:subpath=>'login/new',:headers=>{'Accept'=>'application/xrds+xml'}})[:http].body
|
370
|
+
login_methods=XmlSimple.xml_in(login_meths, {'ForceArray' => false})
|
371
|
+
return {:type=>:object_list, :data=>login_methods['XRD']['Service']}
|
372
|
+
end # command
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end # Cli
|
377
|
+
end # Aspera
|