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.
Files changed (88) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +3592 -0
  3. data/bin/ascli +7 -0
  4. data/bin/asession +89 -0
  5. data/docs/Makefile +59 -0
  6. data/docs/README.erb.md +3012 -0
  7. data/docs/README.md +13 -0
  8. data/docs/diagrams.txt +49 -0
  9. data/docs/secrets.make +38 -0
  10. data/docs/test_env.conf +117 -0
  11. data/docs/transfer_spec.html +99 -0
  12. data/examples/aoc.rb +17 -0
  13. data/examples/proxy.pac +60 -0
  14. data/examples/transfer.rb +115 -0
  15. data/lib/aspera/api_detector.rb +60 -0
  16. data/lib/aspera/ascmd.rb +151 -0
  17. data/lib/aspera/ats_api.rb +43 -0
  18. data/lib/aspera/cli/basic_auth_plugin.rb +38 -0
  19. data/lib/aspera/cli/extended_value.rb +88 -0
  20. data/lib/aspera/cli/formater.rb +238 -0
  21. data/lib/aspera/cli/listener/line_dump.rb +17 -0
  22. data/lib/aspera/cli/listener/logger.rb +20 -0
  23. data/lib/aspera/cli/listener/progress.rb +52 -0
  24. data/lib/aspera/cli/listener/progress_multi.rb +91 -0
  25. data/lib/aspera/cli/main.rb +304 -0
  26. data/lib/aspera/cli/manager.rb +440 -0
  27. data/lib/aspera/cli/plugin.rb +90 -0
  28. data/lib/aspera/cli/plugins/alee.rb +24 -0
  29. data/lib/aspera/cli/plugins/ats.rb +231 -0
  30. data/lib/aspera/cli/plugins/bss.rb +71 -0
  31. data/lib/aspera/cli/plugins/config.rb +806 -0
  32. data/lib/aspera/cli/plugins/console.rb +62 -0
  33. data/lib/aspera/cli/plugins/cos.rb +106 -0
  34. data/lib/aspera/cli/plugins/faspex.rb +377 -0
  35. data/lib/aspera/cli/plugins/faspex5.rb +93 -0
  36. data/lib/aspera/cli/plugins/node.rb +438 -0
  37. data/lib/aspera/cli/plugins/oncloud.rb +937 -0
  38. data/lib/aspera/cli/plugins/orchestrator.rb +169 -0
  39. data/lib/aspera/cli/plugins/preview.rb +464 -0
  40. data/lib/aspera/cli/plugins/server.rb +216 -0
  41. data/lib/aspera/cli/plugins/shares.rb +63 -0
  42. data/lib/aspera/cli/plugins/shares2.rb +114 -0
  43. data/lib/aspera/cli/plugins/sync.rb +65 -0
  44. data/lib/aspera/cli/plugins/xnode.rb +115 -0
  45. data/lib/aspera/cli/transfer_agent.rb +251 -0
  46. data/lib/aspera/cli/version.rb +5 -0
  47. data/lib/aspera/colors.rb +39 -0
  48. data/lib/aspera/command_line_builder.rb +137 -0
  49. data/lib/aspera/fasp/aoc.rb +24 -0
  50. data/lib/aspera/fasp/connect.rb +99 -0
  51. data/lib/aspera/fasp/error.rb +21 -0
  52. data/lib/aspera/fasp/error_info.rb +60 -0
  53. data/lib/aspera/fasp/http_gw.rb +81 -0
  54. data/lib/aspera/fasp/installation.rb +240 -0
  55. data/lib/aspera/fasp/listener.rb +11 -0
  56. data/lib/aspera/fasp/local.rb +377 -0
  57. data/lib/aspera/fasp/manager.rb +69 -0
  58. data/lib/aspera/fasp/node.rb +88 -0
  59. data/lib/aspera/fasp/parameters.rb +235 -0
  60. data/lib/aspera/fasp/resume_policy.rb +76 -0
  61. data/lib/aspera/fasp/uri.rb +51 -0
  62. data/lib/aspera/faspex_gw.rb +196 -0
  63. data/lib/aspera/hash_ext.rb +28 -0
  64. data/lib/aspera/log.rb +80 -0
  65. data/lib/aspera/nagios.rb +71 -0
  66. data/lib/aspera/node.rb +14 -0
  67. data/lib/aspera/oauth.rb +319 -0
  68. data/lib/aspera/on_cloud.rb +421 -0
  69. data/lib/aspera/open_application.rb +72 -0
  70. data/lib/aspera/persistency_action_once.rb +42 -0
  71. data/lib/aspera/persistency_folder.rb +91 -0
  72. data/lib/aspera/preview/file_types.rb +300 -0
  73. data/lib/aspera/preview/generator.rb +258 -0
  74. data/lib/aspera/preview/image_error.png +0 -0
  75. data/lib/aspera/preview/options.rb +35 -0
  76. data/lib/aspera/preview/utils.rb +131 -0
  77. data/lib/aspera/preview/video_error.png +0 -0
  78. data/lib/aspera/proxy_auto_config.erb.js +287 -0
  79. data/lib/aspera/proxy_auto_config.rb +34 -0
  80. data/lib/aspera/rest.rb +296 -0
  81. data/lib/aspera/rest_call_error.rb +13 -0
  82. data/lib/aspera/rest_error_analyzer.rb +98 -0
  83. data/lib/aspera/rest_errors_aspera.rb +58 -0
  84. data/lib/aspera/ssh.rb +53 -0
  85. data/lib/aspera/sync.rb +82 -0
  86. data/lib/aspera/temp_file_manager.rb +37 -0
  87. data/lib/aspera/uri_reader.rb +25 -0
  88. metadata +288 -0
@@ -0,0 +1,93 @@
1
+ require 'aspera/cli/basic_auth_plugin'
2
+ require 'aspera/persistency_action_once'
3
+
4
+ module Aspera
5
+ module Cli
6
+ module Plugins
7
+ class Faspex5 < BasicAuthPlugin
8
+ VAL_ALL='ALL'
9
+ def initialize(env)
10
+ super(env)
11
+ #self.options.add_opt_simple(:delivery_info,'package delivery information (extended value)')
12
+ #self.options.parse_options!
13
+ end
14
+ ACTIONS=[ :node, :package ]
15
+
16
+ # http://apie-next-ui-shell-dev.mybluemix.net/explorer/catalog/aspera/product/ibm-aspera/api/faspex5-api/spec/openapi
17
+ def execute_action
18
+ # get parameters
19
+ faxpex5_api_base_url=self.options.get_option(:url,:mandatory)
20
+ faxpex5_username=self.options.get_option(:username,:mandatory)
21
+ faxpex5_password=self.options.get_option(:password,:mandatory)
22
+ faxpex5_api_base_url+='/api/v5'
23
+ # create object for REST calls to Shares2
24
+ api_v5=Rest.new({
25
+ :base_url => faxpex5_api_base_url,
26
+ :auth => {
27
+ :type => :oauth2,
28
+ :base_url => faxpex5_api_base_url,
29
+ :grant => :body_data,
30
+ :token_field =>'auth_token',
31
+ :path_token => 'authenticate',
32
+ :path_authorize => :unused,
33
+ :userpass_body => {name: faxpex5_username,password: faxpex5_password}
34
+ }})
35
+ command=self.options.get_next_command(ACTIONS)
36
+ case command
37
+ when :node
38
+ return self.entity_action(api_v5,'nodes',nil,:id,nil,true)
39
+ when :package
40
+ command=self.options.get_next_command([:list,:show,:send,:receive])
41
+ case command
42
+ when :list
43
+ parameters=self.options.get_option(:value,:optional)
44
+ return {:type => :object_list, :data=>api_v5.read('packages',parameters)[:data]['packages']}
45
+ when :show
46
+ id=self.options.get_option(:id,:mandatory)
47
+ return {:type => :single_object, :data=>api_v5.read("packages/#{id}")[:data]}
48
+ when :send
49
+ parameters=self.options.get_option(:value,:mandatory)
50
+ raise CliBadArgument,'package value must be hash, refer to API' unless parameters.is_a?(Hash)
51
+ package=api_v5.create('packages',parameters)[:data]
52
+ transfer_spec=api_v5.create("packages/#{package['id']}/transfer_spec/upload",{transfer_type: 'Connect'})[:data]
53
+ transfer_spec.delete('authentication')
54
+ return Main.result_transfer(self.transfer.start(transfer_spec,{:src=>:node_gen3}))
55
+ when :receive
56
+ pkg_type='received'
57
+ pack_id=self.options.get_option(:id,:mandatory)
58
+ package_ids=[pack_id]
59
+ skip_ids_data=[]
60
+ skip_ids_persistency=nil
61
+ if self.options.get_option(:once_only,:mandatory)
62
+ skip_ids_persistency=PersistencyActionOnce.new(
63
+ manager: @agents[:persistency],
64
+ data: skip_ids_data,
65
+ ids: ['faspex_recv',self.options.get_option(:url,:mandatory),self.options.get_option(:username,:mandatory),pkg_type])
66
+ end
67
+ if pack_id.eql?(VAL_ALL)
68
+ # todo: if packages have same name, they will overwrite
69
+ parameters=self.options.get_option(:value,:optional)
70
+ parameters||={"type"=>"received","subtype"=>"mypackages","limit"=>1000}
71
+ raise CliBadArgument,'value filter must be hash (API GET)' unless parameters.is_a?(Hash)
72
+ package_ids=api_v5.read('packages',parameters)[:data]['packages'].map{|p|p['id']}
73
+ package_ids.select!{|i|!skip_ids_data.include?(i)}
74
+ end
75
+ result_transfer=[]
76
+ package_ids.each do |id|
77
+ # TODO: allow from sent as well ?
78
+ transfer_spec=api_v5.create("packages/#{id}/transfer_spec/download",{transfer_type: 'Connect', type: pkg_type})[:data]
79
+ transfer_spec.delete('authentication')
80
+ statuses=self.transfer.start(transfer_spec,{:src=>:node_gen3})
81
+ result_transfer.push({'package'=>id,'status'=>statuses.map{|i|i.to_s}.join(',')})
82
+ # skip only if all sessions completed
83
+ skip_ids_data.push(id) if TransferAgent.session_status(statuses).eql?(:success)
84
+ end
85
+ skip_ids_persistency.save unless skip_ids_persistency.nil?
86
+ return {:type=>:object_list,:data=>result_transfer}
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end # Plugins
92
+ end # Cli
93
+ end # Aspera
@@ -0,0 +1,438 @@
1
+ require 'aspera/cli/basic_auth_plugin'
2
+ require 'aspera/nagios'
3
+ require 'aspera/hash_ext'
4
+ require 'base64'
5
+ require 'zlib'
6
+
7
+ module Aspera
8
+ module Cli
9
+ module Plugins
10
+ class Node < BasicAuthPlugin
11
+ SAMPLE_SOAP_CALL='<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:typ="urn:Aspera:XML:FASPSessionNET:2009/11:Types"><soapenv:Header></soapenv:Header><soapenv:Body><typ:GetSessionInfoRequest><SessionFilter><SessionStatus>running</SessionStatus></SessionFilter></typ:GetSessionInfoRequest></soapenv:Body></soapenv:Envelope>'
12
+ private_constant :SAMPLE_SOAP_CALL
13
+ def initialize(env)
14
+ super(env)
15
+ # this is added to some requests , for instance to add tags
16
+ @add_request_param = env[:add_request_param] || {}
17
+ unless env[:skip_basic_auth_options]
18
+ self.options.add_opt_simple(:validator,"identifier of validator (optional for central)")
19
+ self.options.add_opt_simple(:asperabrowserurl,"URL for simple aspera web ui")
20
+ self.options.add_opt_simple(:name,"sync name")
21
+ self.options.add_opt_list(:token,[:aspera,:basic,:auto],'todo: type of token used for transfers')
22
+ self.options.set_option(:asperabrowserurl,'https://asperabrowser.mybluemix.net')
23
+ self.options.set_option(:token,:aspera)
24
+ self.options.parse_options!
25
+ end
26
+ return if env[:man_only]
27
+ if env.has_key?(:node_api)
28
+ @api_node=env[:node_api]
29
+ else
30
+ @api_node=basic_auth_api unless env[:man_only]
31
+ end
32
+ end
33
+
34
+ def c_textify_browse(table_data)
35
+ return table_data.map {|i| i['permissions']=i['permissions'].map { |x| x['name'] }.join(','); i }
36
+ end
37
+
38
+ # key/value is defined in main in hash_table
39
+ def c_textify_bool_list_result(list,name_list)
40
+ list.each_index do |i|
41
+ if name_list.include?(list[i]['key'])
42
+ list[i]['value'].each do |item|
43
+ list.push({'key'=>item['name'],'value'=>item['value']})
44
+ end
45
+ list.delete_at(i)
46
+ # continue at same index because we delete current one
47
+ redo
48
+ end
49
+ end
50
+ end
51
+
52
+ # reduce the path from a result on given named column
53
+ def c_result_remove_prefix_path(result,column,path_prefix)
54
+ if !path_prefix.nil?
55
+ case result[:type]
56
+ when :object_list
57
+ result[:data].each do |item|
58
+ item[column].replace(item[column][path_prefix.length..-1]) if item[column].start_with?(path_prefix)
59
+ end
60
+ when :single_object
61
+ item=result[:data]
62
+ item[column].replace(item[column][path_prefix.length..-1]) if item[column].start_with?(path_prefix)
63
+ end
64
+ end
65
+ return result
66
+ end
67
+
68
+ # translates paths results into CLI result, and removes prefix
69
+ def c_result_translate_rem_prefix(resp,type,success_msg,path_prefix)
70
+ resres={:data=>[],:type=>:object_list,:fields=>[type,'result']}
71
+ JSON.parse(resp[:http].body)['paths'].each do |p|
72
+ result=success_msg
73
+ if p.has_key?('error')
74
+ Log.log.error("#{p['error']['user_message']} : #{p['path']}")
75
+ result="ERROR: "+p['error']['user_message']
76
+ end
77
+ resres[:data].push({type=>p['path'],'result'=>result})
78
+ end
79
+ return c_result_remove_prefix_path(resres,type,path_prefix)
80
+ end
81
+
82
+ # get path arguments from command line, and add prefix
83
+ def get_next_arg_add_prefix(path_prefix,name,number=:single)
84
+ thepath=self.options.get_next_argument(name,number)
85
+ return thepath if path_prefix.nil?
86
+ return File.join(path_prefix,thepath) if thepath.is_a?(String)
87
+ return thepath.map {|p| File.join(path_prefix,p)} if thepath.is_a?(Array)
88
+ raise StandardError,"expect: nil, String or Array"
89
+ end
90
+
91
+ SIMPLE_ACTIONS=[:nagios_check,:events, :space, :info, :license, :mkdir, :mklink, :mkfile, :rename, :delete, :search ]
92
+
93
+ COMMON_ACTIONS=[:browse, :upload, :download, :api_details ].concat(SIMPLE_ACTIONS)
94
+
95
+ # common API to node and Shares
96
+ # prefix_path is used to list remote sources in Faspex
97
+ def execute_simple_common(command,prefix_path)
98
+ case command
99
+ when :nagios_check
100
+ nagios=Nagios.new
101
+ begin
102
+ info=@api_node.read('info')[:data]
103
+ nagios.add_ok('node api','accessible')
104
+ nagios.check_time_offset(info['current_time'],'node api')
105
+ nagios.check_product_version( 'node api','entsrv', info['version'])
106
+ rescue => e
107
+ nagios.add_critical('node api',e.to_s)
108
+ end
109
+ begin
110
+ @api_node.call({:operation=>'POST',:subpath=>'services/soap/Transfer-201210',:headers=>{'Content-Type'=>'text/xml;charset=UTF-8','SOAPAction'=>'FASPSessionNET-200911#GetSessionInfo'},:text_body_params=>SAMPLE_SOAP_CALL})[:http].body
111
+ nagios.add_ok('central','accessible by node')
112
+ rescue => e
113
+ nagios.add_critical('central',e.to_s)
114
+ end
115
+ return nagios.result
116
+ when :events
117
+ events=@api_node.read('events',self.options.get_option(:value,:optional))[:data]
118
+ return { :type=>:object_list, :data => events}
119
+ when :info
120
+ node_info=@api_node.read('info')[:data]
121
+ return { :type=>:single_object, :data => node_info, :textify => lambda { |table_data| c_textify_bool_list_result(table_data,['capabilities','settings'])}}
122
+ when :license # requires: asnodeadmin -mu <node user> --acl-add=internal --internal
123
+ node_license=@api_node.read('license')[:data]
124
+ if node_license['failure'].is_a?(String) and node_license['failure'].include?('ACL')
125
+ Log.log.error("server must have: asnodeadmin -mu <node user> --acl-add=internal --internal")
126
+ end
127
+ return { :type=>:single_object, :data => node_license}
128
+ when :delete
129
+ paths_to_delete = get_next_arg_add_prefix(prefix_path,"file list",:multiple)
130
+ resp=@api_node.create('files/delete',{:paths=>paths_to_delete.map{|i| {'path'=>i.start_with?('/') ? i : '/'+i} }})
131
+ return c_result_translate_rem_prefix(resp,'file','deleted',prefix_path)
132
+ when :search
133
+ search_root = get_next_arg_add_prefix(prefix_path,"search root")
134
+ parameters={'path'=>search_root}
135
+ other_options=self.options.get_option(:value,:optional)
136
+ parameters.merge!(other_options) unless other_options.nil?
137
+ resp=@api_node.create('files/search',parameters)
138
+ result={ :type=>:object_list, :data => resp[:data]['items']}
139
+ return Main.result_empty if result[:data].empty?
140
+ result[:fields]=result[:data].first.keys.select{|i|!['basename','permissions'].include?(i)}
141
+ self.format.display_status("Items: #{resp[:data]['item_count']}/#{resp[:data]['total_count']}")
142
+ self.format.display_status("params: #{resp[:data]['parameters'].keys.map{|k|"#{k}:#{resp[:data]['parameters'][k]}"}.join(',')}")
143
+ return c_result_remove_prefix_path(result,'path',prefix_path)
144
+ when :space
145
+ # TODO: could be a list of path
146
+ path_list=get_next_arg_add_prefix(prefix_path,"folder path or ext.val. list")
147
+ path_list=[path_list] unless path_list.is_a?(Array)
148
+ resp=@api_node.create('space',{ "paths" => path_list.map {|i| {:path=>i} } } )
149
+ result={:data=>resp[:data]['paths'],:type=>:object_list}
150
+ #return c_result_translate_rem_prefix(resp,'folder','created',prefix_path)
151
+ return c_result_remove_prefix_path(result,'path',prefix_path)
152
+ when :mkdir
153
+ path_list=get_next_arg_add_prefix(prefix_path,"folder path or ext.val. list")
154
+ path_list=[path_list] unless path_list.is_a?(Array)
155
+ #TODO
156
+ #resp=@api_node.create('space',{ "paths" => path_list.map {|i| {:type=>:directory,:path=>i} } } )
157
+ resp=@api_node.create('files/create',{ "paths" => [{ :type => :directory, :path => path_list } ] } )
158
+ return c_result_translate_rem_prefix(resp,'folder','created',prefix_path)
159
+ when :mklink
160
+ target=get_next_arg_add_prefix(prefix_path,"target")
161
+ path_list=get_next_arg_add_prefix(prefix_path,"link path")
162
+ resp=@api_node.create('files/create',{ "paths" => [{ :type => :symbolic_link, :path => path_list, :target => {:path => target} } ] } )
163
+ return c_result_translate_rem_prefix(resp,'folder','created',prefix_path)
164
+ when :mkfile
165
+ path_list=get_next_arg_add_prefix(prefix_path,"file path")
166
+ contents64=Base64.strict_encode64(self.options.get_next_argument("contents"))
167
+ resp=@api_node.create('files/create',{ "paths" => [{ :type => :file, :path => path_list, :contents => contents64 } ] } )
168
+ return c_result_translate_rem_prefix(resp,'folder','created',prefix_path)
169
+ when :rename
170
+ path_base=get_next_arg_add_prefix(prefix_path,"path_base")
171
+ path_src=get_next_arg_add_prefix(prefix_path,"path_src")
172
+ path_dst=get_next_arg_add_prefix(prefix_path,"path_dst")
173
+ resp=@api_node.create('files/rename',{ "paths" => [{ "path" => path_base, "source" => path_src, "destination" => path_dst } ] } )
174
+ return c_result_translate_rem_prefix(resp,'entry','moved',prefix_path)
175
+ when :browse
176
+ thepath=get_next_arg_add_prefix(prefix_path,"path")
177
+ query={ :path => thepath}
178
+ additional_query=self.options.get_option(:query,:optional)
179
+ query.merge!(additional_query) unless additional_query.nil?
180
+ send_result=@api_node.create('files/browse', query)[:data]
181
+ #example: send_result={'items'=>[{'file'=>"filename1","permissions"=>[{'name'=>'read'},{'name'=>'write'}]}]}
182
+ # if there is no items
183
+ case send_result['self']['type']
184
+ when 'directory','container' # directory: node, container: shares
185
+ result={ :data => send_result['items'] , :type => :object_list, :textify => lambda { |table_data| c_textify_browse(table_data) } }
186
+ self.format.display_status("Items: #{send_result['item_count']}/#{send_result['total_count']}")
187
+ else # 'file','symbolic_link'
188
+ result={ :data => send_result['self'] , :type => :single_object}
189
+ #result={ :data => [send_result['self']] , :type => :object_list, :textify => lambda { |table_data| c_textify_browse(table_data) } }
190
+ #raise "unknown type: #{send_result['self']['type']}"
191
+ end
192
+ return c_result_remove_prefix_path(result,'path',prefix_path)
193
+ when :upload
194
+ # we send only a list of one transfer request
195
+ transfer_request = { :paths => [ { :destination => self.transfer.destination_folder('send') } ] }
196
+ transfer_request.deep_merge!(@add_request_param)
197
+ send_result=@api_node.create('files/upload_setup',{:transfer_requests => [ { :transfer_request => transfer_request } ] } )[:data]
198
+ # only one request, so only one answer
199
+ transfer_spec=send_result['transfer_specs'].first['transfer_spec']
200
+ # delete this part, as the returned value contains only destination, and not sources
201
+ transfer_spec.delete('paths')
202
+ return Main.result_transfer(self.transfer.start(transfer_spec,{:src=>:node_gen3}))
203
+ when :download
204
+ transfer_request = {:paths => self.transfer.ts_source_paths }
205
+ transfer_request.deep_merge!(@add_request_param)
206
+ send_result=@api_node.create('files/download_setup',{:transfer_requests => [ { :transfer_request => transfer_request } ] } )[:data]
207
+ # only one request, so only one answer
208
+ transfer_spec=send_result['transfer_specs'].first['transfer_spec']
209
+ return Main.result_transfer(self.transfer.start(transfer_spec,{:src=>:node_gen3}))
210
+ when :api_details
211
+ return { :type=>:single_object, :data => @api_node.params }
212
+ end
213
+ end
214
+
215
+ def execute_async
216
+ command=self.options.get_next_command([:list,:delete,:files,:show,:counters,:bandwidth])
217
+ unless command.eql?(:list)
218
+ asyncname=self.options.get_option(:name,:optional)
219
+ if asyncname.nil?
220
+ asyncid=self.options.get_option(:id,:mandatory)
221
+ if asyncid.eql?('ALL') and [:show,:delete].include?(command)
222
+ asyncids=@api_node.read('async/list')[:data]['sync_ids']
223
+ else
224
+ Integer(asyncid) # must be integer
225
+ asyncids=[asyncid]
226
+ end
227
+ else
228
+ asyncids=@api_node.read('async/list')[:data]['sync_ids']
229
+ summaries=@api_node.create('async/summary',{'syncs' => asyncids})[:data]['sync_summaries']
230
+ selected=summaries.select{|s|s['name'].eql?(asyncname)}.first
231
+ raise "no such sync: #{asyncname}" if selected.nil?
232
+ asyncid=selected['snid']
233
+ asyncids=[asyncid]
234
+ end
235
+ pdata={'syncs' => asyncids}
236
+ end
237
+ case command
238
+ when :list
239
+ resp=@api_node.read('async/list')[:data]['sync_ids']
240
+ return { :type => :value_list, :data => resp, :name=>'id' }
241
+ when :show
242
+ resp=@api_node.create('async/summary',pdata)[:data]['sync_summaries']
243
+ return Main.result_empty if resp.empty?
244
+ if asyncid.eql?('ALL')
245
+ return { :type => :object_list, :data => resp, :fields => ['snid','name','local_dir','remote_dir'] }
246
+ else
247
+ return { :type => :single_object, :data => resp.first }
248
+ end
249
+ when :delete
250
+ resp=@api_node.create('async/delete',pdata)[:data]
251
+ return { :type => :single_object, :data => resp, :name=>'id' }
252
+ when :bandwidth
253
+ pdata['seconds']=100 # TODO: as parameter with --value
254
+ resp=@api_node.create('async/bandwidth',pdata)[:data]
255
+ data=resp['bandwidth_data']
256
+ return Main.result_empty if data.empty?
257
+ data=data.first[asyncid]['data']
258
+ return { :type => :object_list, :data => data, :name=>'id' }
259
+ when :files
260
+ # count int
261
+ # filename str
262
+ # skip int
263
+ # status int
264
+ filter=self.options.get_option(:value,:optional)
265
+ pdata.merge!(filter) unless filter.nil?
266
+ resp=@api_node.create('async/files',pdata)[:data]
267
+ data=resp['sync_files']
268
+ data=data.first[asyncid] unless data.empty?
269
+ iteration_data=[]
270
+ skip_ids_persistency=nil
271
+ if self.options.get_option(:once_only,:mandatory)
272
+ skip_ids_persistency=PersistencyActionOnce.new(
273
+ manager: @agents[:persistency],
274
+ data: iteration_data,
275
+ ids: ['sync_files',self.options.get_option(:url,:mandatory),self.options.get_option(:username,:mandatory),asyncid])
276
+ unless iteration_data.first.nil?
277
+ data.select!{|l| l['fnid'].to_i>iteration_data.first}
278
+ end
279
+ iteration_data[0]=data.last['fnid'].to_i unless data.empty?
280
+ end
281
+ return Main.result_empty if data.empty?
282
+ skip_ids_persistency.save unless skip_ids_persistency.nil?
283
+ return { :type => :object_list, :data => data, :name=>'id' }
284
+ when :counters
285
+ resp=@api_node.create('async/counters',pdata)[:data]["sync_counters"].first[asyncid].last
286
+ return Main.result_empty if resp.nil?
287
+ return { :type => :single_object, :data => resp }
288
+ end
289
+ end
290
+
291
+ ACTIONS=[ :postprocess,:stream, :transfer, :cleanup, :forward, :access_key, :watch_folder, :service, :async, :central, :asperabrowser, :basic_token ].concat(COMMON_ACTIONS)
292
+
293
+ def execute_action(command=nil,prefix_path=nil)
294
+ command||=self.options.get_next_command(ACTIONS)
295
+ case command
296
+ when *COMMON_ACTIONS; return execute_simple_common(command,prefix_path)
297
+ when :async; return execute_async()
298
+ when :stream
299
+ command=self.options.get_next_command([ :list, :create, :show, :modify, :cancel ])
300
+ case command
301
+ when :list
302
+ resp=@api_node.read('ops/transfers',self.options.get_option(:value,:optional))
303
+ return { :type => :object_list, :data => resp[:data], :fields=>['id','status'] } # TODO
304
+ when :create
305
+ resp=@api_node.create('streams',self.options.get_option(:value,:mandatory))
306
+ return { :type => :single_object, :data => resp[:data] }
307
+ when :show
308
+ trid=self.options.get_next_argument("transfer id")
309
+ resp=@api_node.read('ops/transfers/'+trid)
310
+ return { :type=>:other_struct, :data => resp[:data] }
311
+ when :modify
312
+ trid=self.options.get_next_argument("transfer id")
313
+ resp=@api_node.update('streams/'+trid,self.options.get_option(:value,:mandatory))
314
+ return { :type=>:other_struct, :data => resp[:data] }
315
+ when :cancel
316
+ trid=self.options.get_next_argument("transfer id")
317
+ resp=@api_node.cancel('streams/'+trid)
318
+ return { :type=>:other_struct, :data => resp[:data] }
319
+ else
320
+ raise "error"
321
+ end
322
+ when :transfer
323
+ command=self.options.get_next_command([ :list, :cancel, :show ])
324
+ res_class_path='ops/transfers'
325
+ if [:cancel, :show].include?(command)
326
+ one_res_id=self.options.get_option(:id,:mandatory)
327
+ one_res_path="#{res_class_path}/#{one_res_id}"
328
+ end
329
+ case command
330
+ when :list
331
+ # could use ? :subpath=>'transfers'
332
+ resp=@api_node.read(res_class_path,self.options.get_option(:value,:optional))
333
+ return { :type => :object_list, :data => resp[:data], :fields=>['id','status','start_spec.direction','start_spec.remote_user','start_spec.remote_host','start_spec.destination_path']}
334
+ when :cancel
335
+ resp=@api_node.cancel(one_res_path)
336
+ return { :type=>:other_struct, :data => resp[:data] }
337
+ when :show
338
+ resp=@api_node.read(one_res_path)
339
+ return { :type=>:other_struct, :data => resp[:data] }
340
+ else
341
+ raise "error"
342
+ end
343
+ when :access_key
344
+ return self.entity_action(@api_node,'access_keys',['id','root_file_id','storage'],:id,'self')
345
+ when :service
346
+ command=self.options.get_next_command([ :list, :create, :delete])
347
+ if [:delete].include?(command)
348
+ svcid=self.options.get_option(:id,:mandatory)
349
+ end
350
+ case command
351
+ when :list
352
+ resp=@api_node.read('rund/services')
353
+ return { :type=>:object_list, :data => resp[:data]["services"] }
354
+ when :create
355
+ # @json:'{"type":"WATCHFOLDERD","run_as":{"user":"user1"}}'
356
+ params=self.options.get_next_argument("Run creation data (structure)")
357
+ resp=@api_node.create('rund/services',params)
358
+ return Main.result_status("#{resp[:data]['id']} created")
359
+ when :delete
360
+ resp=@api_node.delete("rund/services/#{svcid}")
361
+ return Main.result_status("#{svcid} deleted")
362
+ end
363
+ when :watch_folder
364
+ res_class_path='v3/watchfolders'
365
+ #return entity_action(@api_node,'v3/watchfolders',nil,:id)
366
+ command=self.options.get_next_command([ :create, :list, :show, :modify, :delete, :state])
367
+ if [:show,:modify,:delete,:state].include?(command)
368
+ one_res_id=self.options.get_option(:id,:mandatory)
369
+ one_res_path="#{res_class_path}/#{one_res_id}"
370
+ end
371
+ # hum, to avoid: Unable to convert 2016_09_14 configuration
372
+ @api_node.params[:headers]||={}
373
+ @api_node.params[:headers]['X-aspera-WF-version']='2017_10_23'
374
+ case command
375
+ when :create
376
+ resp=@api_node.create(res_class_path,self.options.get_option(:value,:mandatory))
377
+ return Main.result_status("#{resp[:data]['id']} created")
378
+ when :list
379
+ resp=@api_node.read(res_class_path,self.options.get_option(:value,:optional))
380
+ return { :type=>:value_list, :data => resp[:data]['ids'], :name=>'id' }
381
+ when :show
382
+ return {:type=>:single_object, :data=>@api_node.read(one_res_path)[:data]}
383
+ when :modify
384
+ @api_node.update(one_res_path,self.options.get_option(:value,:mandatory))
385
+ return Main.result_status("#{one_res_id} updated")
386
+ when :delete
387
+ @api_node.delete(one_res_path)
388
+ return Main.result_status("#{one_res_id} deleted")
389
+ when :state
390
+ return { :type=>:single_object, :data => @api_node.read("#{one_res_path}/state")[:data] }
391
+ end
392
+ when :central
393
+ command=self.options.get_next_command([ :session,:file])
394
+ validator_id=self.options.get_option(:validator)
395
+ validation={"validator_id"=>validator_id} unless validator_id.nil?
396
+ request_data=self.options.get_option(:value,:optional)
397
+ request_data||={}
398
+ case command
399
+ when :session
400
+ command=self.options.get_next_command([ :list])
401
+ case command
402
+ when :list
403
+ request_data.deep_merge!({"validation"=>validation}) unless validation.nil?
404
+ resp=@api_node.create('services/rest/transfers/v1/sessions',request_data)
405
+ return {:type=>:object_list,:data=>resp[:data]["session_info_result"]["session_info"],:fields=>["session_uuid","status","transport","direction","bytes_transferred"]}
406
+ end
407
+ when :file
408
+ command=self.options.get_next_command([ :list, :modify])
409
+ case command
410
+ when :list
411
+ request_data.deep_merge!({"validation"=>validation}) unless validation.nil?
412
+ resp=@api_node.create('services/rest/transfers/v1/files',request_data)
413
+ return {:type=>:object_list,:data=>resp[:data]["file_transfer_info_result"]["file_transfer_info"],:fields=>["session_uuid","file_id","status","path"]}
414
+ when :modify
415
+ request_data.deep_merge!(validation) unless validation.nil?
416
+ @api_node.update('services/rest/transfers/v1/files',request_data)
417
+ return Main.result_status('updated')
418
+ end
419
+ end
420
+ when :asperabrowser
421
+ browse_params={
422
+ 'nodeUser' => self.options.get_option(:username,:mandatory),
423
+ 'nodePW' => self.options.get_option(:password,:mandatory),
424
+ 'nodeURL' => self.options.get_option(:url,:mandatory)
425
+ }
426
+ # encode parameters so that it looks good in url
427
+ encoded_params=Base64.strict_encode64(Zlib::Deflate.deflate(JSON.generate(browse_params))).gsub(/=+$/, '').tr('+/', '-_').reverse
428
+ OpenApplication.instance.uri(self.options.get_option(:asperabrowserurl)+'?goto='+encoded_params)
429
+ return Main.result_status('done')
430
+ when :basic_token
431
+ return Main.result_status("Basic "+Base64.strict_encode64("#{self.options.get_option(:username,:mandatory)}:#{self.options.get_option(:password,:mandatory)}"))
432
+ end # case command
433
+ raise "ERROR: shall not reach this line"
434
+ end # execute_action
435
+ end # Main
436
+ end # Plugin
437
+ end # Cli
438
+ end # Aspera