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,937 @@
|
|
1
|
+
require 'aspera/cli/plugins/node'
|
2
|
+
require 'aspera/cli/plugins/ats'
|
3
|
+
require 'aspera/cli/basic_auth_plugin'
|
4
|
+
require 'aspera/cli/transfer_agent'
|
5
|
+
require 'aspera/on_cloud'
|
6
|
+
require 'aspera/persistency_action_once'
|
7
|
+
require 'securerandom'
|
8
|
+
require 'resolv'
|
9
|
+
require 'date'
|
10
|
+
|
11
|
+
module Aspera
|
12
|
+
module Cli
|
13
|
+
module Plugins
|
14
|
+
class Oncloud < BasicAuthPlugin
|
15
|
+
VAL_ALL='ALL'
|
16
|
+
private_constant :VAL_ALL
|
17
|
+
attr_reader :api_aoc
|
18
|
+
def initialize(env)
|
19
|
+
super(env)
|
20
|
+
@default_workspace_id=nil
|
21
|
+
@workspace_name=nil
|
22
|
+
@workspace_id=nil
|
23
|
+
@persist_ids=nil
|
24
|
+
@home_node_file=nil
|
25
|
+
@api_aoc=nil
|
26
|
+
@url_token_data=nil
|
27
|
+
@user_info=nil
|
28
|
+
@ats=Ats.new(@agents)
|
29
|
+
self.options.add_opt_list(:auth,Oauth.auth_types,"type of Oauth authentication")
|
30
|
+
self.options.add_opt_list(:operation,[:push,:pull],"client operation for transfers")
|
31
|
+
self.options.add_opt_simple(:client_id,"API client identifier in application")
|
32
|
+
self.options.add_opt_simple(:client_secret,"API client passcode")
|
33
|
+
self.options.add_opt_simple(:redirect_uri,"API client redirect URI")
|
34
|
+
self.options.add_opt_simple(:private_key,"RSA private key PEM value for JWT (prefix file path with @val:@file:)")
|
35
|
+
self.options.add_opt_simple(:workspace,"name of workspace")
|
36
|
+
self.options.add_opt_simple(:eid,"identifier") # used ?
|
37
|
+
self.options.add_opt_simple(:name,"resource name")
|
38
|
+
self.options.add_opt_simple(:link,"public link to shared resource")
|
39
|
+
self.options.add_opt_simple(:new_user_option,"new user creation option")
|
40
|
+
self.options.add_opt_simple(:from_folder,"share to share source folder")
|
41
|
+
self.options.add_opt_simple(:scope,"scope for AoC API calls")
|
42
|
+
self.options.add_opt_simple(:notify,"notify users that file was received")
|
43
|
+
self.options.add_opt_boolean(:bulk,"bulk operation")
|
44
|
+
self.options.add_opt_boolean(:default_ports,"use standard FASP ports or get from node api")
|
45
|
+
self.options.set_option(:bulk,:no)
|
46
|
+
self.options.set_option(:default_ports,:yes)
|
47
|
+
self.options.set_option(:new_user_option,{'package_contact'=>true})
|
48
|
+
self.options.set_option(:operation,:push)
|
49
|
+
self.options.set_option(:auth,:jwt)
|
50
|
+
self.options.set_option(:scope,OnCloud::SCOPE_FILES_USER)
|
51
|
+
self.options.set_option(:private_key,'@file:'+env[:private_key_path]) if env[:private_key_path].is_a?(String)
|
52
|
+
self.options.parse_options!
|
53
|
+
OnCloud.set_use_default_ports(self.options.get_option(:default_ports))
|
54
|
+
return if env[:man_only]
|
55
|
+
update_aoc_api
|
56
|
+
end
|
57
|
+
|
58
|
+
# call this to populate single AK secret in AoC API object, from options
|
59
|
+
# make sure secret is available
|
60
|
+
def find_ak_secret(ak,mandatory=true)
|
61
|
+
# secret hash is already provisioned
|
62
|
+
# optionally override with specific secret
|
63
|
+
@api_aoc.add_secrets({ak=>self.config.get_secret(ak,mandatory)})
|
64
|
+
# check that secret was provided as single value or dictionary
|
65
|
+
raise CliBadArgument,"Please provide option secret or entry in option secrets for: #{ak}" unless @api_aoc.has_secret(ak) or !mandatory
|
66
|
+
end
|
67
|
+
|
68
|
+
def user_info
|
69
|
+
if @user_info.nil?
|
70
|
+
# get our user's default information
|
71
|
+
# self?embed[]=default_workspace&embed[]=organization
|
72
|
+
@user_info=@api_aoc.read('self')[:data] rescue {
|
73
|
+
'name' => 'unknown',
|
74
|
+
'email' => 'unknown',
|
75
|
+
}
|
76
|
+
end
|
77
|
+
return @user_info
|
78
|
+
end
|
79
|
+
|
80
|
+
# starts transfer using transfer agent
|
81
|
+
def transfer_start(app,direction,node_file,ts_add)
|
82
|
+
ts_add.deep_merge!(OnCloud.analytics_ts(app,direction,@workspace_id,@workspace_name))
|
83
|
+
ts_add.deep_merge!(OnCloud.console_ts(app,user_info['name'],user_info['email']))
|
84
|
+
return self.transfer.start(*@api_aoc.tr_spec(app,direction,node_file,ts_add))
|
85
|
+
end
|
86
|
+
|
87
|
+
NODE4_COMMANDS=[ :browse, :find, :mkdir, :rename, :delete, :upload, :download, :transfer, :http_node_download, :v3, :file, :bearer_token_node, :permissions ]
|
88
|
+
|
89
|
+
def node_gen4_execute_action(top_node_file)
|
90
|
+
command_repo=self.options.get_next_command(NODE4_COMMANDS)
|
91
|
+
return execute_node_gen4_command(command_repo,top_node_file)
|
92
|
+
end
|
93
|
+
|
94
|
+
def execute_node_gen4_command(command_repo,top_node_file)
|
95
|
+
case command_repo
|
96
|
+
when :bearer_token_node
|
97
|
+
thepath=self.options.get_next_argument('path')
|
98
|
+
node_file = @api_aoc.resolve_node_file(top_node_file,thepath)
|
99
|
+
node_api=@api_aoc.get_node_api(node_file[:node_info],OnCloud::SCOPE_NODE_USER)
|
100
|
+
return Main.result_status(node_api.oauth_token)
|
101
|
+
when :browse
|
102
|
+
thepath=self.options.get_next_argument('path')
|
103
|
+
node_file = @api_aoc.resolve_node_file(top_node_file,thepath)
|
104
|
+
node_api=@api_aoc.get_node_api(node_file[:node_info],OnCloud::SCOPE_NODE_USER)
|
105
|
+
file_info = node_api.read("files/#{node_file[:file_id]}")[:data]
|
106
|
+
if file_info['type'].eql?('folder')
|
107
|
+
result=node_api.read("files/#{node_file[:file_id]}/files",self.options.get_option(:value,:optional))
|
108
|
+
items=result[:data]
|
109
|
+
self.format.display_status("Items: #{result[:data].length}/#{result[:http]['X-Total-Count']}")
|
110
|
+
else
|
111
|
+
items=[file_info]
|
112
|
+
end
|
113
|
+
return {:type=>:object_list,:data=>items,:fields=>['name','type','recursive_size','size','modified_time','access_level']}
|
114
|
+
when :find
|
115
|
+
thepath=self.options.get_next_argument('path')
|
116
|
+
exec_prefix='exec:'
|
117
|
+
expression=self.options.get_option(:value,:optional)||"#{exec_prefix}true"
|
118
|
+
node_file=@api_aoc.resolve_node_file(top_node_file,thepath)
|
119
|
+
if expression.start_with?(exec_prefix)
|
120
|
+
test_block=eval "lambda{|f|#{expression[exec_prefix.length..-1]}}"
|
121
|
+
else
|
122
|
+
test_block=lambda{|f|f['name'].match(/#{expression}/)}
|
123
|
+
end
|
124
|
+
return {:type=>:object_list,:data=>@api_aoc.find_files(node_file,test_block),:fields=>['path']}
|
125
|
+
when :mkdir
|
126
|
+
thepath=self.options.get_next_argument('path')
|
127
|
+
containing_folder_path = thepath.split(OnCloud::PATH_SEPARATOR)
|
128
|
+
new_folder=containing_folder_path.pop
|
129
|
+
node_file = @api_aoc.resolve_node_file(top_node_file,containing_folder_path.join(OnCloud::PATH_SEPARATOR))
|
130
|
+
node_api=@api_aoc.get_node_api(node_file[:node_info],OnCloud::SCOPE_NODE_USER)
|
131
|
+
result=node_api.create("files/#{node_file[:file_id]}/files",{:name=>new_folder,:type=>:folder})[:data]
|
132
|
+
return Main.result_status("created: #{result['name']} (id=#{result['id']})")
|
133
|
+
when :rename
|
134
|
+
thepath=self.options.get_next_argument('source path')
|
135
|
+
newname=self.options.get_next_argument('new name')
|
136
|
+
node_file = @api_aoc.resolve_node_file(top_node_file,thepath)
|
137
|
+
node_api=@api_aoc.get_node_api(node_file[:node_info],OnCloud::SCOPE_NODE_USER)
|
138
|
+
result=node_api.update("files/#{node_file[:file_id]}",{:name=>newname})[:data]
|
139
|
+
return Main.result_status("renamed #{thepath} to #{newname}")
|
140
|
+
when :delete
|
141
|
+
thepath=self.options.get_next_argument('path')
|
142
|
+
return do_bulk_operation(thepath,'deleted','path') do |thepath|
|
143
|
+
raise "expecting String (path), got #{thepath.class.name} (#{thepath})" unless thepath.is_a?(String)
|
144
|
+
node_file = @api_aoc.resolve_node_file(top_node_file,thepath)
|
145
|
+
node_api=@api_aoc.get_node_api(node_file[:node_info],OnCloud::SCOPE_NODE_USER)
|
146
|
+
result=node_api.delete("files/#{node_file[:file_id]}")[:data]
|
147
|
+
{'path'=>thepath}
|
148
|
+
end
|
149
|
+
when :transfer
|
150
|
+
# client side is agent
|
151
|
+
# server side is protocol server
|
152
|
+
# in same workspace
|
153
|
+
server_home_node_file=client_home_node_file=top_node_file
|
154
|
+
# default is push
|
155
|
+
case self.options.get_option(:operation,:mandatory)
|
156
|
+
when :push
|
157
|
+
client_tr_oper='send'
|
158
|
+
client_folder=self.options.get_option(:from_folder,:mandatory)
|
159
|
+
server_folder=self.transfer.destination_folder(client_tr_oper)
|
160
|
+
when :pull
|
161
|
+
client_tr_oper='receive'
|
162
|
+
client_folder=self.transfer.destination_folder(client_tr_oper)
|
163
|
+
server_folder=self.options.get_option(:from_folder,:mandatory)
|
164
|
+
end
|
165
|
+
client_node_file = @api_aoc.resolve_node_file(client_home_node_file,client_folder)
|
166
|
+
server_node_file = @api_aoc.resolve_node_file(server_home_node_file,server_folder)
|
167
|
+
# force node as transfer agent
|
168
|
+
@agents[:transfer].set_agent_instance(Fasp::Node.new(@api_aoc.get_node_api(client_node_file[:node_info],OnCloud::SCOPE_NODE_USER)))
|
169
|
+
# additional node to node TS info
|
170
|
+
add_ts={
|
171
|
+
'remote_access_key' => server_node_file[:node_info]['access_key'],
|
172
|
+
'destination_root_id' => server_node_file[:file_id],
|
173
|
+
'source_root_id' => client_node_file[:file_id]
|
174
|
+
}
|
175
|
+
return Main.result_transfer(transfer_start(OnCloud::FILES_APP,client_tr_oper,server_node_file,add_ts))
|
176
|
+
when :upload
|
177
|
+
node_file = @api_aoc.resolve_node_file(top_node_file,self.transfer.destination_folder('send'))
|
178
|
+
add_ts={'tags'=>{'aspera'=>{'files'=>{'parentCwd'=>"#{node_file[:node_info]['id']}:#{node_file[:file_id]}"}}}}
|
179
|
+
return Main.result_transfer(transfer_start(OnCloud::FILES_APP,'send',node_file,add_ts))
|
180
|
+
when :download
|
181
|
+
source_paths=self.transfer.ts_source_paths
|
182
|
+
# special case for AoC : all files must be in same folder
|
183
|
+
source_folder=source_paths.shift['source']
|
184
|
+
# if a single file: split into folder and path
|
185
|
+
if source_paths.empty?
|
186
|
+
source_folder=source_folder.split(OnCloud::PATH_SEPARATOR)
|
187
|
+
source_paths=[{'source'=>source_folder.pop}]
|
188
|
+
source_folder=source_folder.join(OnCloud::PATH_SEPARATOR)
|
189
|
+
end
|
190
|
+
node_file = @api_aoc.resolve_node_file(top_node_file,source_folder)
|
191
|
+
# override paths with just filename
|
192
|
+
add_ts={'tags'=>{'aspera'=>{'files'=>{'parentCwd'=>"#{node_file[:node_info]['id']}:#{node_file[:file_id]}"}}}}
|
193
|
+
add_ts.merge!({'paths'=>source_paths})
|
194
|
+
return Main.result_transfer(transfer_start(OnCloud::FILES_APP,'receive',node_file,add_ts))
|
195
|
+
when :http_node_download
|
196
|
+
source_paths=self.transfer.ts_source_paths
|
197
|
+
source_folder=source_paths.shift['source']
|
198
|
+
if source_paths.empty?
|
199
|
+
source_folder=source_folder.split(OnCloud::PATH_SEPARATOR)
|
200
|
+
source_paths=[{'source'=>source_folder.pop}]
|
201
|
+
source_folder=source_folder.join(OnCloud::PATH_SEPARATOR)
|
202
|
+
end
|
203
|
+
raise CliBadArgument,'one file at a time only in HTTP mode' if source_paths.length > 1
|
204
|
+
file_name = source_paths.first['source']
|
205
|
+
node_file = @api_aoc.resolve_node_file(top_node_file,File.join(source_folder,file_name))
|
206
|
+
node_api=@api_aoc.get_node_api(node_file[:node_info],OnCloud::SCOPE_NODE_USER)
|
207
|
+
node_api.call({:operation=>'GET',:subpath=>"files/#{node_file[:file_id]}/content",:save_to_file=>File.join(self.transfer.destination_folder('receive'),file_name)})
|
208
|
+
return Main.result_status("downloaded: #{file_name}")
|
209
|
+
when :v3
|
210
|
+
# Note: other "common" actions are unauthorized with user scope
|
211
|
+
command_legacy=self.options.get_next_command(Node::SIMPLE_ACTIONS)
|
212
|
+
# TODO: shall we support all methods here ? what if there is a link ?
|
213
|
+
node_api=@api_aoc.get_node_api(top_node_file[:node_info],OnCloud::SCOPE_NODE_USER)
|
214
|
+
return Node.new(@agents.merge(skip_basic_auth_options: true, node_api: node_api)).execute_action(command_legacy)
|
215
|
+
when :file
|
216
|
+
fileid=self.options.get_next_argument('file id')
|
217
|
+
node_file = @api_aoc.resolve_node_file(top_node_file)
|
218
|
+
node_api=@api_aoc.get_node_api(node_file[:node_info],OnCloud::SCOPE_NODE_USER)
|
219
|
+
items=node_api.read("files/#{fileid}")[:data]
|
220
|
+
return {:type=>:single_object,:data=>items}
|
221
|
+
when :permissions
|
222
|
+
fileid=self.options.get_next_argument('file id')
|
223
|
+
node_file = @api_aoc.resolve_node_file(top_node_file)
|
224
|
+
node_api=@api_aoc.get_node_api(node_file[:node_info],OnCloud::SCOPE_NODE_USER)
|
225
|
+
command_perms=self.options.get_next_command([:show,:create])
|
226
|
+
case command_perms
|
227
|
+
when :show
|
228
|
+
items=node_api.read('permissions',{'include'=>['[]','access_level','permission_count'],'file_id'=>fileid,'inherited'=>false})[:data]
|
229
|
+
return {:type=>:object_list,:data=>items}
|
230
|
+
when :create
|
231
|
+
#value=self.options.get_next_argument('creation value')
|
232
|
+
set_workspace_info
|
233
|
+
access_id="ASPERA_ACCESS_KEY_ADMIN_WS_#{@workspace_id}"
|
234
|
+
node_file[:node_info]
|
235
|
+
params={
|
236
|
+
"file_id"=>fileid,
|
237
|
+
"access_type"=>"user",
|
238
|
+
"access_id"=>access_id,
|
239
|
+
"access_levels"=>["list","read","write","delete","mkdir","rename","preview"],
|
240
|
+
"tags"=>{
|
241
|
+
"aspera"=>{
|
242
|
+
"files"=>{
|
243
|
+
"workspace"=>{
|
244
|
+
"id"=>@workspace_id,
|
245
|
+
"workspace_name"=>@workspace_name,
|
246
|
+
"user_name"=>user_info['name'],
|
247
|
+
"shared_by_user_id"=>user_info['id'],
|
248
|
+
"shared_by_name"=>user_info['name'],
|
249
|
+
"shared_by_email"=>user_info['email'],
|
250
|
+
"shared_with_name"=>access_id,
|
251
|
+
"access_key"=>node_file[:node_info]['access_key'],
|
252
|
+
"node"=>node_file[:node_info]['name']}}}}}
|
253
|
+
item=node_api.create('permissions',params)[:data]
|
254
|
+
return {:type=>:single_object,:data=>item}
|
255
|
+
else raise "error"
|
256
|
+
end
|
257
|
+
end # command_repo
|
258
|
+
throw "ERR"
|
259
|
+
end # execute_node_gen4_command
|
260
|
+
|
261
|
+
# build constructor option list for OnCloud based on options of CLI
|
262
|
+
def oncloud_params(subpath)
|
263
|
+
# copy command line options to args
|
264
|
+
opt=[:link,:url,:auth,:client_id,:client_secret,:scope,:redirect_uri,:private_key,:username].inject({}){|m,i|m[i]=self.options.get_option(i,:optional);m}
|
265
|
+
opt[:subpath]=subpath
|
266
|
+
return opt
|
267
|
+
end
|
268
|
+
|
269
|
+
# Create a new AoC API REST object and set @api_aoc.
|
270
|
+
# Parameters based on command line options
|
271
|
+
# @return nil
|
272
|
+
def update_aoc_api
|
273
|
+
@api_aoc=OnCloud.new(oncloud_params('api/v1'))
|
274
|
+
# add access key secrets
|
275
|
+
@api_aoc.add_secrets(self.config.get_secrets)
|
276
|
+
return nil
|
277
|
+
end
|
278
|
+
|
279
|
+
# initialize apis and authentication
|
280
|
+
# set:
|
281
|
+
# @default_workspace_id
|
282
|
+
# @workspace_name
|
283
|
+
# @workspace_id
|
284
|
+
# @persist_ids
|
285
|
+
# returns nil
|
286
|
+
def set_workspace_info
|
287
|
+
if @api_aoc.params[:auth].has_key?(:url_token)
|
288
|
+
# TODO: can there be several in list ?
|
289
|
+
@url_token_data=@api_aoc.read('url_tokens')[:data].first
|
290
|
+
@default_workspace_id=@url_token_data['data']['workspace_id']
|
291
|
+
@persist_ids=[] # TODO : @url_token_data['id'] ?
|
292
|
+
else
|
293
|
+
@default_workspace_id=user_info['default_workspace_id']
|
294
|
+
@persist_ids=[user_info['id']]
|
295
|
+
end
|
296
|
+
|
297
|
+
ws_name=self.options.get_option(:workspace,:optional)
|
298
|
+
if ws_name.nil?
|
299
|
+
Log.log.debug("using default workspace".green)
|
300
|
+
if @default_workspace_id.eql?(nil)
|
301
|
+
raise CliError,"no default workspace defined for user, please specify workspace"
|
302
|
+
end
|
303
|
+
# get default workspace
|
304
|
+
@workspace_id=@default_workspace_id
|
305
|
+
else
|
306
|
+
# lookup another workspace
|
307
|
+
wss=@api_aoc.read("workspaces",{'q'=>ws_name})[:data]
|
308
|
+
wss=wss.select { |i| i['name'].eql?(ws_name) }
|
309
|
+
case wss.length
|
310
|
+
when 0
|
311
|
+
raise CliBadArgument,"no such workspace: #{ws_name}"
|
312
|
+
when 1
|
313
|
+
@workspace_id=wss.first['id']
|
314
|
+
else
|
315
|
+
raise "unexpected case"
|
316
|
+
end
|
317
|
+
end
|
318
|
+
@workspace_data=@api_aoc.read("workspaces/#{@workspace_id}")[:data]
|
319
|
+
Log.log.debug("workspace_id=#{@workspace_id},@workspace_data=#{@workspace_data}".red)
|
320
|
+
|
321
|
+
@workspace_name||=@workspace_data['name']
|
322
|
+
Log.log.info("current workspace is "+@workspace_name.red)
|
323
|
+
|
324
|
+
# display workspace
|
325
|
+
self.format.display_status("Current Workspace: #{@workspace_name.red}#{@workspace_id == @default_workspace_id ? ' (default)' : ''}")
|
326
|
+
return nil
|
327
|
+
end
|
328
|
+
|
329
|
+
# @home_node_file (hash with :node_info and :file_id)
|
330
|
+
def set_home_node_file
|
331
|
+
if !@url_token_data.nil?
|
332
|
+
assert_public_link_types(['view_shared_file'])
|
333
|
+
home_node_id=@url_token_data['data']['node_id']
|
334
|
+
home_file_id=@url_token_data['data']['file_id']
|
335
|
+
end
|
336
|
+
home_node_id||=@workspace_data['home_node_id']||@workspace_data['node_id']
|
337
|
+
home_file_id||=@workspace_data['home_file_id']
|
338
|
+
raise "node_id must be defined" if home_node_id.to_s.empty?
|
339
|
+
@home_node_file={
|
340
|
+
node_info: @api_aoc.read("nodes/#{home_node_id}")[:data],
|
341
|
+
file_id: home_file_id
|
342
|
+
}
|
343
|
+
@api_aoc.check_get_node_file(@home_node_file)
|
344
|
+
|
345
|
+
return nil
|
346
|
+
end
|
347
|
+
|
348
|
+
def do_bulk_operation(ids_or_one,success_msg,id_result='id',&do_action)
|
349
|
+
ids_or_one=[ids_or_one] unless self.options.get_option(:bulk)
|
350
|
+
raise "expecting Array" unless ids_or_one.is_a?(Array)
|
351
|
+
result_list=[]
|
352
|
+
ids_or_one.each do |id|
|
353
|
+
one={id_result=>id}
|
354
|
+
begin
|
355
|
+
res=do_action.call(id)
|
356
|
+
one=res if id.is_a?(Hash) # if block returns a has, let's use this
|
357
|
+
one['status']=success_msg
|
358
|
+
rescue => e
|
359
|
+
one['status']=e.to_s
|
360
|
+
end
|
361
|
+
result_list.push(one)
|
362
|
+
end
|
363
|
+
return {:type=>:object_list,:data=>result_list,:fields=>[id_result,'status']}
|
364
|
+
end
|
365
|
+
|
366
|
+
# package creation params can give just email, and full hash is created
|
367
|
+
def resolve_package_recipients(package_creation,recipient_list_field)
|
368
|
+
return unless package_creation.has_key?(recipient_list_field)
|
369
|
+
raise CliBadArgument,"#{recipient_list_field} must be an Array" unless package_creation[recipient_list_field].is_a?(Array)
|
370
|
+
new_user_option=self.options.get_option(:new_user_option,:mandatory)
|
371
|
+
resolved_list=[]
|
372
|
+
package_creation[recipient_list_field].each do |recipient_email_or_info|
|
373
|
+
case recipient_email_or_info
|
374
|
+
when Hash
|
375
|
+
raise 'recipient element hash shall have field id and type' unless recipient_email_or_info.has_key?('id') and recipient_email_or_info.has_key?('type')
|
376
|
+
# already provided all information ?
|
377
|
+
resolved_list.push(recipient_email_or_info)
|
378
|
+
when String
|
379
|
+
if recipient_email_or_info.include?('@')
|
380
|
+
# or need to resolve email
|
381
|
+
item_lookup=@api_aoc.read('contacts',{'current_workspace_id'=>@workspace_id,'q'=>recipient_email_or_info})[:data]
|
382
|
+
case item_lookup.length
|
383
|
+
when 1; recipient_user_id=item_lookup.first
|
384
|
+
when 0; recipient_user_id=@api_aoc.create('contacts',{'current_workspace_id'=>@workspace_id,'email'=>recipient_email_or_info}.merge(new_user_option))[:data]
|
385
|
+
else raise CliBadArgument,"multiple match for: #{recipient_email_or_info}"
|
386
|
+
end
|
387
|
+
resolved_list.push({'id'=>recipient_user_id['source_id'],'type'=>recipient_user_id['source_type']})
|
388
|
+
else
|
389
|
+
item_lookup=@api_aoc.read('dropboxes',{'current_workspace_id'=>@workspace_id,'q'=>recipient_email_or_info})[:data]
|
390
|
+
case item_lookup.length
|
391
|
+
when 1; recipient_user_id=item_lookup.first
|
392
|
+
when 0; raise "no such shared inbox in workspace #{@workspace_name}"
|
393
|
+
else raise CliBadArgument,"multiple match for: #{recipient_email_or_info}"
|
394
|
+
end
|
395
|
+
resolved_list.push({'id'=>recipient_user_id['id'],'type'=>'dropbox'})
|
396
|
+
end
|
397
|
+
else
|
398
|
+
raise "recipient item must be a String (email, shared inboc) or hash (id,type)"
|
399
|
+
end
|
400
|
+
end
|
401
|
+
package_creation[recipient_list_field]=resolved_list
|
402
|
+
end
|
403
|
+
|
404
|
+
def url_query(default)
|
405
|
+
query=self.options.get_option(:query,:optional)||default
|
406
|
+
Log.log.debug("Query=#{query}".bg_red)
|
407
|
+
begin
|
408
|
+
# check it is suitable
|
409
|
+
URI.encode_www_form(query) unless query.nil?
|
410
|
+
rescue => e
|
411
|
+
raise CliBadArgument,"query must be an extended value which can be encoded with URI.encode_www_form. Refer to manual. (#{e.message})"
|
412
|
+
end
|
413
|
+
return query
|
414
|
+
end
|
415
|
+
|
416
|
+
def assert_public_link_types(expected)
|
417
|
+
if !expected.include?(@url_token_data['purpose'])
|
418
|
+
raise CliBadArgument,"public link type is #{@url_token_data['purpose']} but action requires one of #{expected.join(',')}"
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
def execute_admin_action
|
423
|
+
self.options.set_option(:scope,OnCloud::SCOPE_FILES_ADMIN)
|
424
|
+
update_aoc_api
|
425
|
+
command_admin=self.options.get_next_command([ :ats, :resource, :usage_reports, :analytics, :subscription, :auth_providers ])
|
426
|
+
case command_admin
|
427
|
+
when :auth_providers
|
428
|
+
command_auth_prov=self.options.get_next_command([ :list, :update ])
|
429
|
+
case command_auth_prov
|
430
|
+
when :list
|
431
|
+
providers=@api_aoc.read('admin/auth_providers')[:data]
|
432
|
+
return {:type=>:object_list,:data=>providers}
|
433
|
+
when :update
|
434
|
+
end
|
435
|
+
when :subscription
|
436
|
+
org=@api_aoc.read('organization')[:data]
|
437
|
+
bss_api=OnCloud.new(oncloud_params('bss/platform'))
|
438
|
+
graphql_query="
|
439
|
+
query ($organization_id: ID!) {
|
440
|
+
aoc (organization_id: $organization_id) {
|
441
|
+
bssSubscription {
|
442
|
+
endDate
|
443
|
+
startDate
|
444
|
+
termMonths
|
445
|
+
plan
|
446
|
+
trial
|
447
|
+
termType
|
448
|
+
instances {
|
449
|
+
id
|
450
|
+
entitlements {
|
451
|
+
maxUsageMb
|
452
|
+
}
|
453
|
+
}
|
454
|
+
additionalStorageVolumeGb
|
455
|
+
additionalEgressVolumeGb
|
456
|
+
additionalUsers
|
457
|
+
term {
|
458
|
+
startDate
|
459
|
+
endDate
|
460
|
+
transferVolumeGb
|
461
|
+
egressVolumeGb
|
462
|
+
storageVolumeGb
|
463
|
+
}
|
464
|
+
paygoRate {
|
465
|
+
rate
|
466
|
+
currency
|
467
|
+
}
|
468
|
+
aocPlanData {
|
469
|
+
tier
|
470
|
+
trial
|
471
|
+
workspaces { max }
|
472
|
+
users {
|
473
|
+
planAmount
|
474
|
+
max
|
475
|
+
}
|
476
|
+
samlIntegration
|
477
|
+
activity
|
478
|
+
sharedInboxes
|
479
|
+
uniqueUrls
|
480
|
+
support
|
481
|
+
}
|
482
|
+
}
|
483
|
+
}
|
484
|
+
}
|
485
|
+
"
|
486
|
+
result=bss_api.create('graphql',{'variables'=>{'organization_id'=>org['id']},'query'=>graphql_query})[:data]['data']
|
487
|
+
return {:type=>:single_object,:data=>result['aoc']['bssSubscription']}
|
488
|
+
when :ats
|
489
|
+
ats_api = Rest.new(@api_aoc.params.deep_merge({
|
490
|
+
:base_url => @api_aoc.params[:base_url]+'/admin/ats/pub/v1',
|
491
|
+
:auth => {:scope => OnCloud::SCOPE_FILES_ADMIN_USER}
|
492
|
+
}))
|
493
|
+
return @ats.execute_action_gen(ats_api)
|
494
|
+
# when :search_nodes
|
495
|
+
# query=self.options.get_option(:query,:optional) || '*'
|
496
|
+
# nodes=@api_aoc.read("search_nodes",{'q'=>query})[:data]
|
497
|
+
# # simplify output
|
498
|
+
# nodes=nodes.map do |i|
|
499
|
+
# item=i['_source']
|
500
|
+
# item['score']=i['_score']
|
501
|
+
# nodedata=item['access_key_recursive_counts'].first
|
502
|
+
# item.delete('access_key_recursive_counts')
|
503
|
+
# item['node']=nodedata
|
504
|
+
# item
|
505
|
+
# end
|
506
|
+
# return {:type=>:object_list,:data=>nodes,:fields=>['host_name','node_status.cluster_id','node_status.node_id']}
|
507
|
+
when :analytics
|
508
|
+
analytics_api = Rest.new(@api_aoc.params.deep_merge({
|
509
|
+
:base_url => @api_aoc.params[:base_url].gsub('/api/v1','')+'/analytics/v2',
|
510
|
+
:auth => {:scope => OnCloud::SCOPE_FILES_ADMIN_USER}
|
511
|
+
}))
|
512
|
+
command_analytics=self.options.get_next_command([ :application_events, :transfers ])
|
513
|
+
case command_analytics
|
514
|
+
when :application_events
|
515
|
+
event_type=command_analytics.to_s
|
516
|
+
events=analytics_api.read("organizations/#{user_info['organization_id']}/#{event_type}")[:data][event_type]
|
517
|
+
return {:type=>:object_list,:data=>events}
|
518
|
+
when :transfers
|
519
|
+
event_type=command_analytics.to_s
|
520
|
+
filter_resource=self.options.get_option(:name,:optional) || 'organizations'
|
521
|
+
filter_id=self.options.get_option(:id,:optional) || case filter_resource
|
522
|
+
when 'organizations'; user_info['organization_id']
|
523
|
+
when 'users'; user_info['id']
|
524
|
+
when 'nodes'; user_info['id']
|
525
|
+
else raise "organizations or users for option --name"
|
526
|
+
end
|
527
|
+
#
|
528
|
+
filter=self.options.get_option(:query,:optional) || {}
|
529
|
+
filter['limit']||=100
|
530
|
+
if self.options.get_option(:once_only,:mandatory)
|
531
|
+
saved_date=[]
|
532
|
+
startdate_persistency=PersistencyActionOnce.new(
|
533
|
+
manager: @agents[:persistency],
|
534
|
+
data: saved_date,
|
535
|
+
ids: ['aoc_ana_date',self.options.get_option(:url,:mandatory),@workspace_name].push(filter_resource,filter_id))
|
536
|
+
start_datetime=saved_date.first
|
537
|
+
stop_datetime=Time.now.utc.strftime('%FT%T.%LZ')
|
538
|
+
#Log.log().error("start: #{start_datetime}")
|
539
|
+
#Log.log().error("end: #{stop_datetime}")
|
540
|
+
saved_date[0]=stop_datetime
|
541
|
+
filter['start_time'] = start_datetime unless start_datetime.nil?
|
542
|
+
filter['stop_time'] = stop_datetime
|
543
|
+
end
|
544
|
+
notification=self.options.get_option(:notify,:optional)
|
545
|
+
events=analytics_api.read("#{filter_resource}/#{filter_id}/#{event_type}",url_query(filter))[:data][event_type]
|
546
|
+
startdate_persistency.save unless startdate_persistency.nil?
|
547
|
+
if !notification.nil?
|
548
|
+
require 'erb'
|
549
|
+
events.each do |transfer|
|
550
|
+
email_to_send={}
|
551
|
+
notification.each do |k,v|
|
552
|
+
email_to_send[k.to_sym]=ERB.new(v).result(binding)
|
553
|
+
end
|
554
|
+
Log.log().error("send email: #{email_to_send}")
|
555
|
+
self.config.send_email(email_to_send)
|
556
|
+
end
|
557
|
+
end
|
558
|
+
return {:type=>:object_list,:data=>events}
|
559
|
+
end
|
560
|
+
when :resource
|
561
|
+
resource_type=self.options.get_next_argument('resource',[:self,:organization,:user,:group,:client,:contact,:dropbox,:node,:operation,:package,:saml_configuration, :workspace, :dropbox_membership,:short_link,:workspace_membership,'admin/apps_new'.to_sym,'admin/client_registration_token'.to_sym,'integrations/kms_profile'.to_sym])
|
562
|
+
resource_class_path=resource_type.to_s+case resource_type;when :dropbox;'es';when :self,:organization,'admin/apps_new'.to_sym;'';else; 's';end
|
563
|
+
singleton_object=[:self,:organization].include?(resource_type)
|
564
|
+
global_operations=[:create,:list]
|
565
|
+
supported_operations=[:show,:modify]
|
566
|
+
supported_operations.push(:delete,*global_operations) unless singleton_object
|
567
|
+
supported_operations.push(:v4,:v3) if resource_type.eql?(:node)
|
568
|
+
supported_operations.push(:set_pub_key) if resource_type.eql?(:client)
|
569
|
+
supported_operations.push(:shared_folders) if [:node,:workspace].include?(resource_type)
|
570
|
+
command=self.options.get_next_command(supported_operations)
|
571
|
+
|
572
|
+
# require identifier for non global commands
|
573
|
+
if !singleton_object and !global_operations.include?(command)
|
574
|
+
res_id=self.options.get_option(:id)
|
575
|
+
res_name=self.options.get_option(:name)
|
576
|
+
if res_id.nil? and res_name.nil? and resource_type.eql?(:node)
|
577
|
+
set_workspace_info
|
578
|
+
set_home_node_file
|
579
|
+
res_id=@home_node_file[:node_info]['id']
|
580
|
+
end
|
581
|
+
if !res_name.nil?
|
582
|
+
Log.log.warn("name overrides id") unless res_id.nil?
|
583
|
+
matching=@api_aoc.read(resource_class_path,{:q=>res_name})[:data]
|
584
|
+
raise CliError,"no resource match name" if matching.empty?
|
585
|
+
raise CliError,"several resources match name (#{matching.join(',')})" unless matching.length.eql?(1)
|
586
|
+
res_id=matching.first['id']
|
587
|
+
end
|
588
|
+
raise CliBadArgument,"provide either id or name" if res_id.nil?
|
589
|
+
resource_instance_path="#{resource_class_path}/#{res_id}"
|
590
|
+
end
|
591
|
+
resource_instance_path=resource_class_path if singleton_object
|
592
|
+
case command
|
593
|
+
when :create
|
594
|
+
id_result='id'
|
595
|
+
id_result='token' if resource_class_path.eql?('admin/client_registration_tokens')
|
596
|
+
# TODO: report inconsistency: creation url is !=, and does not return id.
|
597
|
+
resource_class_path='admin/client_registration/token' if resource_class_path.eql?('admin/client_registration_tokens')
|
598
|
+
list_or_one=self.options.get_next_argument("creation data (Hash)")
|
599
|
+
return do_bulk_operation(list_or_one,'created',id_result)do|params|
|
600
|
+
raise "expecting Hash" unless params.is_a?(Hash)
|
601
|
+
@api_aoc.create(resource_class_path,params)[:data]
|
602
|
+
end
|
603
|
+
when :list
|
604
|
+
default_fields=['id','name']
|
605
|
+
list_query=nil
|
606
|
+
case resource_type
|
607
|
+
when :node; default_fields.push('host','access_key')
|
608
|
+
when :operation; default_fields=nil
|
609
|
+
when :contact; default_fields=["email","name","source_id","source_type"]
|
610
|
+
when 'admin/apps_new'.to_sym; list_query={:organization_apps=>true};default_fields=['app_type','available']
|
611
|
+
when 'admin/client_registration_token'.to_sym; default_fields=['id','value','data.client_subject_scopes','created_at']
|
612
|
+
end
|
613
|
+
result=@api_aoc.read(resource_class_path,url_query(list_query))
|
614
|
+
self.format.display_status("Items: #{result[:data].length}/#{result[:http]['X-Total-Count']}")
|
615
|
+
return {:type=>:object_list,:data=>result[:data],:fields=>default_fields}
|
616
|
+
when :show
|
617
|
+
object=@api_aoc.read(resource_instance_path)[:data]
|
618
|
+
fields=object.keys.select{|k|!k.eql?('certificate')}
|
619
|
+
return { :type=>:single_object, :data =>object, :fields=>fields }
|
620
|
+
when :modify
|
621
|
+
changes=self.options.get_next_argument('modified parameters (hash)')
|
622
|
+
@api_aoc.update(resource_instance_path,changes)
|
623
|
+
return Main.result_status('modified')
|
624
|
+
when :delete
|
625
|
+
return do_bulk_operation(res_id,'deleted')do|one_id|
|
626
|
+
@api_aoc.delete("#{resource_class_path}/#{one_id.to_s}")
|
627
|
+
{'id'=>one_id}
|
628
|
+
end
|
629
|
+
when :set_pub_key
|
630
|
+
# special : reads private and generate public
|
631
|
+
the_private_key=self.options.get_next_argument('private_key')
|
632
|
+
the_public_key=OpenSSL::PKey::RSA.new(the_private_key).public_key.to_s
|
633
|
+
@api_aoc.update(resource_instance_path,{:jwt_grant_enabled=>true, :public_key=>the_public_key})
|
634
|
+
return Main.result_success
|
635
|
+
when :v3,:v4
|
636
|
+
res_data=@api_aoc.read(resource_instance_path)[:data]
|
637
|
+
find_ak_secret(res_data['access_key'])
|
638
|
+
api_node=@api_aoc.get_node_api(res_data)
|
639
|
+
return Node.new(@agents.merge(skip_basic_auth_options: true, node_api: api_node)).execute_action if command.eql?(:v3)
|
640
|
+
ak_data=api_node.call({:operation=>'GET',:subpath=>"access_keys/#{res_data['access_key']}",:headers=>{'Accept'=>'application/json'}})[:data]
|
641
|
+
return node_gen4_execute_action({node_info: res_data, file_id: ak_data['root_file_id']})
|
642
|
+
# when :info
|
643
|
+
# object=@api_aoc.read(resource_instance_path)[:data]
|
644
|
+
# access_key=object['access_key']
|
645
|
+
# match_list=@api_aoc.read('admin/search_nodes',{:q=>"access_key:\"#{access_key}\""})[:data]
|
646
|
+
# result=match_list.select{|i|i["_source"]["access_key_recursive_counts"].first["access_key"].eql?(access_key)}
|
647
|
+
# return Main.result_status('Private node') if result.empty?
|
648
|
+
# raise CliError,"more than one match" unless result.length.eql?(1)
|
649
|
+
# result=result.first["_source"]
|
650
|
+
# result.merge!(result['access_key_recursive_counts'].first)
|
651
|
+
# result.delete('access_key_recursive_counts')
|
652
|
+
# result.delete('token')
|
653
|
+
# return { :type=>:single_object, :data =>result}
|
654
|
+
when :shared_folders
|
655
|
+
read_params = case resource_type
|
656
|
+
when :workspace;{'access_id'=>"ASPERA_ACCESS_KEY_ADMIN_WS_#{res_id}",'access_type'=>'user'}
|
657
|
+
when :node;{'include'=>['[]','access_level','permission_count'],'created_by_id'=>"ASPERA_ACCESS_KEY_ADMIN"}
|
658
|
+
else raise "error"
|
659
|
+
end
|
660
|
+
res_data=@api_aoc.read("#{resource_class_path}/#{res_id}/permissions",read_params)[:data]
|
661
|
+
fields=case resource_type
|
662
|
+
when :node;['id','file_id','file.path','access_type']
|
663
|
+
when :workspace;['id','node_id','file_id','node_name','file.path','tags.aspera.files.workspace.share_as']
|
664
|
+
else raise "error"
|
665
|
+
end
|
666
|
+
return { :type=>:object_list, :data =>res_data , :fields=>fields}
|
667
|
+
else raise :ERROR
|
668
|
+
end
|
669
|
+
when :usage_reports
|
670
|
+
return {:type=>:object_list,:data=>@api_aoc.read("usage_reports",{:workspace_id=>@workspace_id})[:data]}
|
671
|
+
end
|
672
|
+
end
|
673
|
+
|
674
|
+
ACTIONS=[ :apiinfo, :bearer_token, :organization, :tier_restrictions, :user, :workspace, :packages, :files, :gateway, :admin, :automation, :servers]
|
675
|
+
|
676
|
+
def execute_action
|
677
|
+
command=self.options.get_next_command(ACTIONS)
|
678
|
+
case command
|
679
|
+
when :apiinfo
|
680
|
+
api_info={}
|
681
|
+
num=1
|
682
|
+
Resolv::DNS.open{|dns|dns.each_address('api.ibmaspera.com'){|a| api_info["api.#{num}"]=a;num+=1}}
|
683
|
+
return {:type=>:single_object,:data=>api_info}
|
684
|
+
when :bearer_token
|
685
|
+
return {:type=>:text,:data=>@api_aoc.oauth_token}
|
686
|
+
when :organization
|
687
|
+
return { :type=>:single_object, :data =>@api_aoc.read('organization')[:data] }
|
688
|
+
when :tier_restrictions
|
689
|
+
return { :type=>:single_object, :data =>@api_aoc.read('tier_restrictions')[:data] }
|
690
|
+
when :user
|
691
|
+
command=self.options.get_next_command([ :workspaces,:info,:shared_inboxes ])
|
692
|
+
case command
|
693
|
+
when :workspaces
|
694
|
+
return {:type=>:object_list,:data=>@api_aoc.read("workspaces")[:data],:fields=>['id','name']}
|
695
|
+
# when :settings
|
696
|
+
# return {:type=>:object_list,:data=>@api_aoc.read("client_settings/")[:data]}
|
697
|
+
when :shared_inboxes
|
698
|
+
query=url_query(nil)
|
699
|
+
if query.nil?
|
700
|
+
set_workspace_info
|
701
|
+
query={'embed[]'=>'dropbox','workspace_id'=>@workspace_id,'aggregate_permissions_by_dropbox'=>true,'sort'=>'dropbox_name'}
|
702
|
+
end
|
703
|
+
return {:type=>:object_list,:data=>@api_aoc.read("dropbox_memberships",query)[:data],:fields=>['dropbox_id','dropbox.name']}
|
704
|
+
when :info
|
705
|
+
command=self.options.get_next_command([ :show,:modify ])
|
706
|
+
case command
|
707
|
+
when :show
|
708
|
+
return { :type=>:single_object, :data =>user_info }
|
709
|
+
when :modify
|
710
|
+
@api_aoc.update("users/#{user_info['id']}",self.options.get_next_argument('modified parameters (hash)'))
|
711
|
+
return Main.result_status('modified')
|
712
|
+
end
|
713
|
+
end
|
714
|
+
when :workspace # show current workspace parameters
|
715
|
+
set_workspace_info
|
716
|
+
return { :type=>:single_object, :data =>@workspace_data }
|
717
|
+
when :packages
|
718
|
+
set_workspace_info if @url_token_data.nil?
|
719
|
+
command_pkg=self.options.get_next_command([ :send, :recv, :list, :show, :delete ])
|
720
|
+
case command_pkg
|
721
|
+
when :send
|
722
|
+
package_creation=self.options.get_option(:value,:mandatory)
|
723
|
+
raise CliBadArgument,"value must be hash, refer to doc" unless package_creation.is_a?(Hash)
|
724
|
+
|
725
|
+
if !@url_token_data.nil?
|
726
|
+
assert_public_link_types(['send_package_to_user','send_package_to_dropbox'])
|
727
|
+
box_type=@url_token_data['purpose'].split('_').last
|
728
|
+
package_creation['recipients']=[{'id'=>@url_token_data['data']["#{box_type}_id"],'type'=>box_type}]
|
729
|
+
@workspace_id=@url_token_data['data']['workspace_id']
|
730
|
+
end
|
731
|
+
|
732
|
+
package_creation['workspace_id']=@workspace_id
|
733
|
+
|
734
|
+
# list of files to include in package, optional
|
735
|
+
#package_creation['file_names']=self.transfer.ts_source_paths.map{|i|File.basename(i['source'])}
|
736
|
+
|
737
|
+
# lookup users
|
738
|
+
resolve_package_recipients(package_creation,'recipients')
|
739
|
+
resolve_package_recipients(package_creation,'bcc_recipients')
|
740
|
+
|
741
|
+
# create a new package with one file
|
742
|
+
package_info=@api_aoc.create('packages',package_creation)[:data]
|
743
|
+
|
744
|
+
# get node information for the node on which package must be created
|
745
|
+
node_info=@api_aoc.read("nodes/#{package_info['node_id']}")[:data]
|
746
|
+
|
747
|
+
# tell Aspera what to expect in package: 1 transfer (can also be done after transfer)
|
748
|
+
@api_aoc.update("packages/#{package_info['id']}",{'sent'=>true,'transfers_expected'=>1})[:data]
|
749
|
+
|
750
|
+
# execute transfer
|
751
|
+
node_file = {node_info: node_info, file_id: package_info['contents_file_id']}
|
752
|
+
# raise esception if at least one error
|
753
|
+
Main.result_transfer(transfer_start(OnCloud::PACKAGES_APP,'send',node_file,OnCloud.package_tags(package_info,'upload')))
|
754
|
+
# return all info on package
|
755
|
+
return { :type=>:single_object, :data =>package_info}
|
756
|
+
when :recv
|
757
|
+
if !@url_token_data.nil?
|
758
|
+
assert_public_link_types(['view_received_package'])
|
759
|
+
self.options.set_option(:id,@url_token_data['data']['package_id'])
|
760
|
+
end
|
761
|
+
# scalar here
|
762
|
+
ids_to_download=self.options.get_option(:id,:mandatory)
|
763
|
+
skip_ids_data=[]
|
764
|
+
skip_ids_persistency=nil
|
765
|
+
if self.options.get_option(:once_only,:mandatory)
|
766
|
+
skip_ids_persistency=PersistencyActionOnce.new(
|
767
|
+
manager: @agents[:persistency],
|
768
|
+
data: skip_ids_data,
|
769
|
+
ids: ['aoc_recv',self.options.get_option(:url,:mandatory),@workspace_id].push(*@persist_ids))
|
770
|
+
end
|
771
|
+
if ids_to_download.eql?(VAL_ALL)
|
772
|
+
# get list of packages in inbox
|
773
|
+
package_info=@api_aoc.read('packages',{'archived'=>false,'exclude_dropbox_packages'=>true,'has_content'=>true,'received'=>true,'workspace_id'=>@workspace_id})[:data]
|
774
|
+
# remove from list the ones already downloaded
|
775
|
+
ids_to_download=package_info.map{|e|e['id']}
|
776
|
+
# array here
|
777
|
+
ids_to_download.select!{|id|!skip_ids_data.include?(id)}
|
778
|
+
end # ALL
|
779
|
+
# list here
|
780
|
+
ids_to_download = [ids_to_download] unless ids_to_download.is_a?(Array)
|
781
|
+
result_transfer=[]
|
782
|
+
self.format.display_status("found #{ids_to_download.length} package(s).")
|
783
|
+
ids_to_download.each do |package_id|
|
784
|
+
package_info=@api_aoc.read("packages/#{package_id}")[:data]
|
785
|
+
node_info=@api_aoc.read("nodes/#{package_info['node_id']}")[:data]
|
786
|
+
self.format.display_status("downloading package: #{package_info['name']}")
|
787
|
+
add_ts={'paths'=>[{'source'=>'.'}]}
|
788
|
+
node_file = {node_info: node_info, file_id: package_info['contents_file_id']}
|
789
|
+
statuses=transfer_start(OnCloud::PACKAGES_APP,'receive',node_file,OnCloud.package_tags(package_info,'download').merge(add_ts))
|
790
|
+
result_transfer.push({'package'=>package_id,'status'=>statuses.map{|i|i.to_s}.join(',')})
|
791
|
+
# update skip list only if all transfer sessions completed
|
792
|
+
if TransferAgent.session_status(statuses).eql?(:success)
|
793
|
+
skip_ids_data.push(package_id)
|
794
|
+
skip_ids_persistency.save unless skip_ids_persistency.nil?
|
795
|
+
end
|
796
|
+
end
|
797
|
+
return {:type=>:object_list,:data=>result_transfer}
|
798
|
+
when :show
|
799
|
+
package_id=self.options.get_next_argument('package ID')
|
800
|
+
package_info=@api_aoc.read("packages/#{package_id}")[:data]
|
801
|
+
return { :type=>:single_object, :data =>package_info }
|
802
|
+
when :list
|
803
|
+
# list all packages ('page'=>1,'per_page'=>10,)'sort'=>'-sent_at',
|
804
|
+
packages=@api_aoc.read("packages",{'archived'=>false,'exclude_dropbox_packages'=>true,'has_content'=>true,'received'=>true,'workspace_id'=>@workspace_id})[:data]
|
805
|
+
return {:type=>:object_list,:data=>packages,:fields=>['id','name','bytes_transferred']}
|
806
|
+
when :delete
|
807
|
+
list_or_one=self.options.get_option(:id,:mandatory)
|
808
|
+
return do_bulk_operation(list_or_one,'deleted')do|id|
|
809
|
+
raise "expecting String identifier" unless id.is_a?(String) or id.is_a?(Integer)
|
810
|
+
@api_aoc.delete("packages/#{id}")[:data]
|
811
|
+
end
|
812
|
+
end
|
813
|
+
when :files
|
814
|
+
# get workspace related information
|
815
|
+
set_workspace_info
|
816
|
+
set_home_node_file
|
817
|
+
find_ak_secret(@home_node_file[:node_info]['access_key'],false)
|
818
|
+
command_repo=self.options.get_next_command(NODE4_COMMANDS.clone.concat([:short_link]))
|
819
|
+
case command_repo
|
820
|
+
when *NODE4_COMMANDS; return execute_node_gen4_command(command_repo,@home_node_file)
|
821
|
+
when :short_link
|
822
|
+
folder_dest=self.options.get_option(:to_folder,:optional)
|
823
|
+
value_option=self.options.get_option(:value,:optional)
|
824
|
+
case value_option
|
825
|
+
when 'public'
|
826
|
+
value_option={'purpose'=>'token_auth_redirection'}
|
827
|
+
when 'private'
|
828
|
+
value_option={'purpose'=>'shared_folder_auth_link'}
|
829
|
+
when NilClass,Hash
|
830
|
+
else raise "value must be either: public, private, Hash or nil"
|
831
|
+
end
|
832
|
+
create_params=nil
|
833
|
+
node_file=nil
|
834
|
+
if !folder_dest.nil?
|
835
|
+
node_file = @api_aoc.resolve_node_file(@home_node_file,folder_dest)
|
836
|
+
create_params={
|
837
|
+
file_id: node_file[:file_id],
|
838
|
+
node_id: node_file[:node_info]['id'],
|
839
|
+
workspace_id: @workspace_id
|
840
|
+
}
|
841
|
+
end
|
842
|
+
if !value_option.nil? and !create_params.nil?
|
843
|
+
case value_option['purpose']
|
844
|
+
when 'shared_folder_auth_link'
|
845
|
+
value_option['data']=create_params
|
846
|
+
value_option['user_selected_name']=nil
|
847
|
+
when 'token_auth_redirection'
|
848
|
+
create_params['name']=''
|
849
|
+
value_option['data']={
|
850
|
+
aoc: true,
|
851
|
+
url_token_data: {
|
852
|
+
data: create_params,
|
853
|
+
purpose: 'view_shared_file'
|
854
|
+
}
|
855
|
+
}
|
856
|
+
value_option['user_selected_name']=nil
|
857
|
+
else
|
858
|
+
raise "purpose must be one of: token_auth_redirection or shared_folder_auth_link"
|
859
|
+
end
|
860
|
+
self.options.set_option(:value,value_option)
|
861
|
+
end
|
862
|
+
result=self.entity_action(@api_aoc,'short_links',nil,:id,'self')
|
863
|
+
if result[:data].is_a?(Hash) and result[:data].has_key?('created_at') and result[:data]['resource_type'].eql?('UrlToken')
|
864
|
+
node_api=@api_aoc.get_node_api(node_file[:node_info],OnCloud::SCOPE_NODE_USER)
|
865
|
+
perm_data={
|
866
|
+
"file_id" =>node_file[:file_id],
|
867
|
+
"access_type" =>"user",
|
868
|
+
"access_id" =>result[:data]['resource_id'],
|
869
|
+
"access_levels"=>["delete","list","mkdir","preview","read","rename","write"],
|
870
|
+
"tags" =>{
|
871
|
+
"url_token" =>true,
|
872
|
+
"workspace_id" =>@workspace_id,
|
873
|
+
"workspace_name" =>@workspace_name,
|
874
|
+
"folder_name" =>"my folder",
|
875
|
+
"created_by_name" =>user_info['name'],
|
876
|
+
"created_by_email"=>user_info['email'],
|
877
|
+
"access_key" =>node_file[:node_info]['access_key'],
|
878
|
+
"node" =>node_file[:node_info]['host']
|
879
|
+
}
|
880
|
+
}
|
881
|
+
node_api.create("permissions?file_id=#{node_file[:file_id]}",perm_data)
|
882
|
+
end
|
883
|
+
return result
|
884
|
+
end # files command
|
885
|
+
throw "Error: shall not reach this line"
|
886
|
+
when :automation
|
887
|
+
Log.log.warn("BETA: work under progress")
|
888
|
+
# automation api is not in the same place
|
889
|
+
automation_rest_params=@api_aoc.params.clone
|
890
|
+
automation_rest_params[:base_url].gsub!('/api/','/automation/')
|
891
|
+
automation_api=Rest.new(automation_rest_params)
|
892
|
+
command_automation=self.options.get_next_command([ :workflows, :instances ])
|
893
|
+
case command_automation
|
894
|
+
when :instances
|
895
|
+
return self.entity_action(@api_aoc,'workflow_instances',nil,:id,nil)
|
896
|
+
when :workflows
|
897
|
+
wF_COMMANDS=Plugin::ALL_OPS.clone.push(:action,:launch)
|
898
|
+
wf_command=self.options.get_next_command(wF_COMMANDS)
|
899
|
+
case wf_command
|
900
|
+
when *Plugin::ALL_OPS
|
901
|
+
return self.entity_command(wf_command,automation_api,'workflows',nil,:id)
|
902
|
+
when :launch
|
903
|
+
wf_id=self.options.get_option(:id,:mandatory)
|
904
|
+
data=automation_api.create("workflows/#{wf_id}/launch",{})[:data]
|
905
|
+
return {:type=>:single_object,:data=>data}
|
906
|
+
when :action
|
907
|
+
wf_command=self.options.get_next_command([:list,:create,:show])
|
908
|
+
wf_id=self.options.get_option(:id,:mandatory)
|
909
|
+
step=automation_api.create('steps',{'workflow_id'=>wf_id})[:data]
|
910
|
+
automation_api.update("workflows/#{wf_id}",{'step_order'=>[step["id"]]})
|
911
|
+
action=automation_api.create('actions',{'step_id'=>step["id"],'type'=>'manual'})[:data]
|
912
|
+
automation_api.update("steps/#{step["id"]}",{'action_order'=>[action["id"]]})
|
913
|
+
wf=automation_api.read("workflows/#{wf_id}")[:data]
|
914
|
+
return {:type=>:single_object,:data=>wf}
|
915
|
+
end
|
916
|
+
end
|
917
|
+
when :gateway
|
918
|
+
set_workspace_info
|
919
|
+
require 'aspera/faspex_gw'
|
920
|
+
FaspexGW.new(@api_aoc,@workspace_id).start_server
|
921
|
+
when :admin
|
922
|
+
return execute_admin_action
|
923
|
+
when :servers
|
924
|
+
self.format.display_status("Beta feature")
|
925
|
+
server_api=Rest.new(base_url: 'https://eudemo.asperademo.com')
|
926
|
+
require 'json'
|
927
|
+
servers=JSON.parse(server_api.read('servers')[:data])
|
928
|
+
return {:type=>:object_list,:data=>servers}
|
929
|
+
else
|
930
|
+
raise "internal error: #{command}"
|
931
|
+
end # action
|
932
|
+
raise RuntimeError, "internal error: command shall return"
|
933
|
+
end
|
934
|
+
end # Aspera
|
935
|
+
end # Plugins
|
936
|
+
end # Cli
|
937
|
+
end # Aspera
|