aspera-cli 4.21.1 → 4.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/BUGS.md +1 -1
- data/CHANGELOG.md +52 -22
- data/CONTRIBUTING.md +69 -148
- data/README.md +929 -668
- data/bin/ascli +5 -14
- data/bin/asession +1 -3
- data/examples/get_proto_file.rb +4 -3
- data/examples/proxy.pac +20 -20
- data/lib/aspera/agent/base.rb +11 -5
- data/lib/aspera/agent/connect.rb +30 -28
- data/lib/aspera/agent/{alpha.rb → desktop.rb} +35 -31
- data/lib/aspera/agent/direct.rb +141 -121
- data/lib/aspera/agent/httpgw.rb +22 -26
- data/lib/aspera/agent/node.rb +14 -11
- data/lib/aspera/agent/transferd.rb +30 -19
- data/lib/aspera/api/alee.rb +1 -1
- data/lib/aspera/api/aoc.rb +6 -6
- data/lib/aspera/api/cos_node.rb +2 -2
- data/lib/aspera/api/httpgw.rb +7 -3
- data/lib/aspera/api/node.rb +10 -8
- data/lib/aspera/ascmd.rb +3 -3
- data/lib/aspera/ascp/installation.rb +53 -72
- data/lib/aspera/ascp/management.rb +1 -1
- data/lib/aspera/assert.rb +11 -2
- data/lib/aspera/cli/error.rb +2 -2
- data/lib/aspera/cli/extended_value.rb +46 -21
- data/lib/aspera/cli/formatter.rb +55 -48
- data/lib/aspera/cli/hints.rb +1 -1
- data/lib/aspera/cli/info.rb +1 -0
- data/lib/aspera/cli/main.rb +192 -170
- data/lib/aspera/cli/manager.rb +18 -18
- data/lib/aspera/cli/plugin.rb +23 -20
- data/lib/aspera/cli/plugin_factory.rb +1 -1
- data/lib/aspera/cli/plugins/alee.rb +1 -1
- data/lib/aspera/cli/plugins/aoc.rb +247 -159
- data/lib/aspera/cli/plugins/ats.rb +19 -17
- data/lib/aspera/cli/plugins/config.rb +76 -113
- data/lib/aspera/cli/plugins/console.rb +5 -3
- data/lib/aspera/cli/plugins/faspex.rb +39 -35
- data/lib/aspera/cli/plugins/faspex5.rb +111 -84
- data/lib/aspera/cli/plugins/faspio.rb +13 -1
- data/lib/aspera/cli/plugins/httpgw.rb +13 -1
- data/lib/aspera/cli/plugins/node.rb +312 -182
- data/lib/aspera/cli/plugins/orchestrator.rb +34 -40
- data/lib/aspera/cli/plugins/preview.rb +3 -3
- data/lib/aspera/cli/plugins/server.rb +6 -6
- data/lib/aspera/cli/plugins/shares.rb +5 -5
- data/lib/aspera/cli/sync_actions.rb +19 -18
- data/lib/aspera/cli/transfer_agent.rb +5 -5
- data/lib/aspera/cli/transfer_progress.rb +2 -2
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/command_line_builder.rb +116 -95
- data/lib/aspera/coverage.rb +8 -5
- data/lib/aspera/environment.rb +26 -17
- data/lib/aspera/faspex_gw.rb +14 -14
- data/lib/aspera/faspex_postproc.rb +10 -11
- data/lib/aspera/hash_ext.rb +4 -14
- data/lib/aspera/json_rpc.rb +1 -1
- data/lib/aspera/keychain/encrypted_hash.rb +47 -34
- data/lib/aspera/keychain/factory.rb +41 -0
- data/lib/aspera/keychain/hashicorp_vault.rb +71 -0
- data/lib/aspera/keychain/macos_security.rb +19 -11
- data/lib/aspera/log.rb +28 -34
- data/lib/aspera/nagios.rb +6 -6
- data/lib/aspera/node_simulator.rb +8 -8
- data/lib/aspera/oauth/base.rb +14 -7
- data/lib/aspera/oauth/factory.rb +5 -6
- data/lib/aspera/oauth/url_json.rb +6 -6
- data/lib/aspera/persistency_action_once.rb +6 -4
- data/lib/aspera/persistency_folder.rb +2 -2
- data/lib/aspera/preview/generator.rb +13 -10
- data/lib/aspera/preview/options.rb +16 -16
- data/lib/aspera/preview/terminal.rb +4 -4
- data/lib/aspera/preview/utils.rb +15 -17
- data/lib/aspera/products/connect.rb +35 -1
- data/lib/aspera/products/{alpha.rb → desktop.rb} +3 -3
- data/lib/aspera/products/transferd.rb +9 -2
- data/lib/aspera/proxy_auto_config.rb +2 -2
- data/lib/aspera/rest.rb +56 -47
- data/lib/aspera/rest_errors_aspera.rb +1 -1
- data/lib/aspera/secret_hider.rb +12 -5
- data/lib/aspera/ssh.rb +4 -4
- data/lib/aspera/temp_file_manager.rb +5 -4
- data/lib/aspera/transfer/convert.rb +29 -0
- data/lib/aspera/transfer/error_info.rb +66 -66
- data/lib/aspera/transfer/parameters.rb +13 -68
- data/lib/aspera/transfer/spec.rb +5 -6
- data/lib/aspera/transfer/spec.schema.yaml +753 -0
- data/lib/aspera/transfer/spec_doc.rb +62 -0
- data/lib/aspera/transfer/sync.rb +23 -72
- data/lib/aspera/transfer/sync_instance.schema.yaml +13 -0
- data/lib/aspera/transfer/sync_session.schema.yaml +79 -0
- data/lib/aspera/transfer/uri.rb +6 -6
- data/lib/aspera/uri_reader.rb +18 -1
- data/lib/aspera/web_auth.rb +1 -1
- data/lib/aspera/web_server_simple.rb +53 -44
- data.tar.gz.sig +0 -0
- metadata +28 -165
- metadata.gz.sig +0 -0
- data/examples/build_exec +0 -74
- data/examples/build_exec_rubyc +0 -40
- data/examples/build_package.sh +0 -28
- data/lib/aspera/transfer/spec.yaml +0 -718
@@ -47,6 +47,7 @@ module Aspera
|
|
47
47
|
test_endpoint = 'ping'
|
48
48
|
result = api.call(operation: 'GET', subpath: test_endpoint)
|
49
49
|
next unless result[:http].body.eql?('')
|
50
|
+
# also remove "/"
|
50
51
|
url_end = -2 - test_endpoint.length
|
51
52
|
return {
|
52
53
|
url: result[:http].uri.to_s[0..url_end],
|
@@ -107,7 +108,7 @@ module Aspera
|
|
107
108
|
SEARCH_REMOVE_FIELDS = %w[basename permissions].freeze
|
108
109
|
|
109
110
|
# actions in execute_command_gen3
|
110
|
-
COMMANDS_GEN3 = %i[search space mkdir mklink mkfile rename delete browse upload download
|
111
|
+
COMMANDS_GEN3 = %i[search space mkdir mklink mkfile rename delete browse upload download cat sync transport]
|
111
112
|
|
112
113
|
BASE_ACTIONS = %i[api_details].concat(COMMANDS_GEN3).freeze
|
113
114
|
|
@@ -125,7 +126,7 @@ module Aspera
|
|
125
126
|
NODE4_READ_ACTIONS = %i[bearer_token_node node_info browse find].freeze
|
126
127
|
|
127
128
|
# commands for execute_command_gen4
|
128
|
-
COMMANDS_GEN4 = %i[mkdir rename delete upload download sync
|
129
|
+
COMMANDS_GEN4 = %i[mkdir mklink mkfile rename delete upload download sync cat show modify permission thumbnail v3].concat(NODE4_READ_ACTIONS).freeze
|
129
130
|
|
130
131
|
# commands supported in ATS for COS
|
131
132
|
COMMANDS_COS = %i[upload download info access_keys api_details transfer].freeze
|
@@ -134,13 +135,16 @@ module Aspera
|
|
134
135
|
|
135
136
|
GEN4_LS_FIELDS = %w[name type recursive_size size modified_time access_level].freeze
|
136
137
|
|
137
|
-
|
138
|
+
# @param api [Rest] an existing API object for the Node API
|
139
|
+
# @param prefix_path [String,nil] for Faspex 4, allows browsing a package
|
140
|
+
def initialize(api: nil, prefix_path: nil, **env)
|
141
|
+
@prefix_path = prefix_path
|
138
142
|
super(**env, basic_options: api.nil?)
|
139
|
-
Node.declare_options(options)
|
140
|
-
return if only_manual
|
143
|
+
Node.declare_options(options)
|
144
|
+
return if env[:broker].only_manual?
|
141
145
|
@api_node =
|
142
146
|
if !api.nil?
|
143
|
-
# this can be Api::Node or Rest (
|
147
|
+
# this can be Api::Node or Rest (Shares)
|
144
148
|
api
|
145
149
|
elsif OAuth::Factory.bearer?(options.get_option(:password, mandatory: true))
|
146
150
|
# info is provided like node_info of aoc
|
@@ -161,23 +165,22 @@ module Aspera
|
|
161
165
|
end
|
162
166
|
|
163
167
|
# reduce the path from a result on given named column
|
164
|
-
def c_result_remove_prefix_path(result, column
|
165
|
-
if
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
end
|
171
|
-
when :single_object
|
172
|
-
item = result[:data]
|
173
|
-
item[column] = item[column][path_prefix.length..-1] if item[column].start_with?(path_prefix)
|
168
|
+
def c_result_remove_prefix_path(result, column)
|
169
|
+
return result if @prefix_path.nil?
|
170
|
+
case result[:type]
|
171
|
+
when :object_list
|
172
|
+
result[:data].each do |item|
|
173
|
+
item[column] = item[column][@prefix_path.length..-1] if item[column].start_with?(@prefix_path)
|
174
174
|
end
|
175
|
+
when :single_object
|
176
|
+
item = result[:data]
|
177
|
+
item[column] = item[column][@prefix_path.length..-1] if item[column].start_with?(@prefix_path)
|
175
178
|
end
|
176
179
|
return result
|
177
180
|
end
|
178
181
|
|
179
182
|
# translates paths results into CLI result, and removes prefix
|
180
|
-
def c_result_translate_rem_prefix(response, type, success_msg
|
183
|
+
def c_result_translate_rem_prefix(response, type, success_msg)
|
181
184
|
errors = []
|
182
185
|
final_result = {type: :object_list, data: [], fields: [type, 'result']}
|
183
186
|
response['paths'].each do |p|
|
@@ -191,16 +194,16 @@ module Aspera
|
|
191
194
|
end
|
192
195
|
# one error make all fail
|
193
196
|
unless errors.empty?
|
194
|
-
raise errors.map{|i|"#{i.first}: #{i.last}"}.join(', ')
|
197
|
+
raise errors.map{ |i| "#{i.first}: #{i.last}"}.join(', ')
|
195
198
|
end
|
196
|
-
return c_result_remove_prefix_path(final_result, type
|
199
|
+
return c_result_remove_prefix_path(final_result, type)
|
197
200
|
end
|
198
201
|
|
199
|
-
def browse_gen3
|
200
|
-
folders_to_process = [get_one_argument_with_prefix(
|
202
|
+
def browse_gen3
|
203
|
+
folders_to_process = [get_one_argument_with_prefix('path')]
|
201
204
|
query = options.get_option(:query, default: {})
|
202
205
|
# special parameter: max number of entries in result
|
203
|
-
max_items = query.delete(
|
206
|
+
max_items = query.delete(MAX_ITEMS)
|
204
207
|
# special parameter: recursive browsing
|
205
208
|
recursive = query.delete('recursive')
|
206
209
|
# special parameter: only return one entry for the path, even if folder
|
@@ -209,7 +212,7 @@ module Aspera
|
|
209
212
|
single_call = query.key?('skip')
|
210
213
|
# API default is 100, so use 1000 for default
|
211
214
|
query['count'] ||= 1000
|
212
|
-
raise Cli::BadArgument, 'options recursive and skip cannot be used together' if recursive && single_call
|
215
|
+
raise Cli::BadArgument, 'options `recursive` and `skip` cannot be used together' if recursive && single_call
|
213
216
|
all_items = []
|
214
217
|
until folders_to_process.empty?
|
215
218
|
path = folders_to_process.shift
|
@@ -222,7 +225,7 @@ module Aspera
|
|
222
225
|
response = @api_node.create('files/browse', query)
|
223
226
|
# 'file','symbolic_link'
|
224
227
|
if !Node.gen3_entry_folder?(response['self']) || only_path
|
225
|
-
result = {
|
228
|
+
result = {type: :single_object, data: response['self']}
|
226
229
|
break
|
227
230
|
end
|
228
231
|
items = response['items']
|
@@ -233,7 +236,7 @@ module Aspera
|
|
233
236
|
break
|
234
237
|
end
|
235
238
|
if recursive
|
236
|
-
folders_to_process.concat(items.select{|i|Node.gen3_entry_folder?(i)}.map{|i|i['path']})
|
239
|
+
folders_to_process.concat(items.select{ |i| Node.gen3_entry_folder?(i)}.map{ |i| i['path']})
|
237
240
|
end
|
238
241
|
if !max_items.nil? && (all_items.count >= max_items)
|
239
242
|
all_items = all_items.slice(0, max_items) if all_items.count > max_items
|
@@ -248,73 +251,94 @@ module Aspera
|
|
248
251
|
end
|
249
252
|
result ||= {type: :object_list, data: all_items}
|
250
253
|
formatter.long_operation_terminated
|
251
|
-
return c_result_remove_prefix_path(result, 'path'
|
254
|
+
return c_result_remove_prefix_path(result, 'path')
|
252
255
|
end
|
253
256
|
|
254
|
-
#
|
255
|
-
|
257
|
+
# Create async transfer spec request from direction and folders
|
258
|
+
# @param sync_direction one of push pull bidi
|
259
|
+
# @param local_path local folder to sync
|
260
|
+
# @param remote_path remote folder to sync
|
261
|
+
def sync_spec_request(sync_direction, local_path, remote_path)
|
262
|
+
case sync_direction
|
263
|
+
when :push then {
|
264
|
+
type: :sync_upload,
|
265
|
+
paths: [{
|
266
|
+
source: local_path,
|
267
|
+
destination: remote_path
|
268
|
+
}]
|
269
|
+
}
|
270
|
+
when :pull then {
|
271
|
+
type: :sync_download,
|
272
|
+
paths: [{
|
273
|
+
source: remote_path,
|
274
|
+
destination: local_path
|
275
|
+
}]
|
276
|
+
}
|
277
|
+
when :bidi then {
|
278
|
+
type: :sync,
|
279
|
+
paths: [{
|
280
|
+
source: local_path,
|
281
|
+
destination: remote_path
|
282
|
+
}]
|
283
|
+
}
|
284
|
+
else Aspera.error_unexpected_value(sync_direction)
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
# Commands based on Gen3 API for file and folder
|
289
|
+
def execute_command_gen3(command)
|
256
290
|
case command
|
257
291
|
when :delete
|
258
292
|
# TODO: add query for recursive
|
259
|
-
paths_to_delete = get_all_arguments_with_prefix(
|
260
|
-
resp = @api_node.create('files/delete', {
|
261
|
-
return c_result_translate_rem_prefix(resp, 'file', 'deleted'
|
293
|
+
paths_to_delete = get_all_arguments_with_prefix('file list')
|
294
|
+
resp = @api_node.create('files/delete', {paths: paths_to_delete.map{ |i| {'path' => i.start_with?('/') ? i : "/#{i}"}}})
|
295
|
+
return c_result_translate_rem_prefix(resp, 'file', 'deleted')
|
262
296
|
when :search
|
263
|
-
search_root = get_one_argument_with_prefix(
|
297
|
+
search_root = get_one_argument_with_prefix('search root')
|
264
298
|
parameters = {'path' => search_root}
|
265
299
|
other_options = options.get_option(:query)
|
266
300
|
parameters.merge!(other_options) unless other_options.nil?
|
267
301
|
resp = @api_node.create('files/search', parameters)
|
268
|
-
result = {
|
302
|
+
result = {type: :object_list, data: resp['items']}
|
269
303
|
return Main.result_empty if result[:data].empty?
|
270
|
-
result[:fields] = result[:data].first.keys.reject{|i|SEARCH_REMOVE_FIELDS.include?(i)}
|
304
|
+
result[:fields] = result[:data].first.keys.reject{ |i| SEARCH_REMOVE_FIELDS.include?(i)}
|
271
305
|
formatter.display_item_count(resp['item_count'], resp['total_count'])
|
272
|
-
formatter.display_status("params: #{resp['parameters'].keys.map{|k|"#{k}:#{resp['parameters'][k]}"}.join(',')}")
|
273
|
-
return c_result_remove_prefix_path(result, 'path'
|
306
|
+
formatter.display_status("params: #{resp['parameters'].keys.map{ |k| "#{k}:#{resp['parameters'][k]}"}.join(',')}")
|
307
|
+
return c_result_remove_prefix_path(result, 'path')
|
274
308
|
when :space
|
275
|
-
path_list = get_all_arguments_with_prefix(
|
276
|
-
resp = @api_node.create('space', {
|
277
|
-
result = {
|
278
|
-
# return c_result_translate_rem_prefix(resp,'folder','created'
|
279
|
-
return c_result_remove_prefix_path(result, 'path'
|
309
|
+
path_list = get_all_arguments_with_prefix('folder path or ext.val. list')
|
310
|
+
resp = @api_node.create('space', {'paths' => path_list.map{ |i| {path: i}}})
|
311
|
+
result = {type: :object_list, data: resp['paths']}
|
312
|
+
# return c_result_translate_rem_prefix(resp,'folder','created',@prefix_path)
|
313
|
+
return c_result_remove_prefix_path(result, 'path')
|
280
314
|
when :mkdir
|
281
|
-
path_list = get_all_arguments_with_prefix(
|
282
|
-
resp = @api_node.create('files/create', {
|
283
|
-
return c_result_translate_rem_prefix(resp, 'folder', 'created'
|
315
|
+
path_list = get_all_arguments_with_prefix('folder path or ext.val. list')
|
316
|
+
resp = @api_node.create('files/create', {'paths' => path_list.map{ |i| {type: :directory, path: i}}})
|
317
|
+
return c_result_translate_rem_prefix(resp, 'folder', 'created')
|
284
318
|
when :mklink
|
285
|
-
target = get_one_argument_with_prefix(
|
286
|
-
one_path = get_one_argument_with_prefix(
|
287
|
-
resp = @api_node.create('files/create', {
|
288
|
-
return c_result_translate_rem_prefix(resp, 'folder', 'created'
|
319
|
+
target = get_one_argument_with_prefix('target')
|
320
|
+
one_path = get_one_argument_with_prefix('link path')
|
321
|
+
resp = @api_node.create('files/create', {'paths' => [{type: :symbolic_link, path: one_path, target: {path: target}}]})
|
322
|
+
return c_result_translate_rem_prefix(resp, 'folder', 'created')
|
289
323
|
when :mkfile
|
290
|
-
one_path = get_one_argument_with_prefix(
|
324
|
+
one_path = get_one_argument_with_prefix('file path')
|
291
325
|
contents64 = Base64.strict_encode64(options.get_next_argument('contents'))
|
292
|
-
resp = @api_node.create('files/create', {
|
293
|
-
return c_result_translate_rem_prefix(resp, 'folder', 'created'
|
326
|
+
resp = @api_node.create('files/create', {'paths' => [{type: :file, path: one_path, contents: contents64}]})
|
327
|
+
return c_result_translate_rem_prefix(resp, 'folder', 'created')
|
294
328
|
when :rename
|
295
329
|
# TODO: multiple ?
|
296
|
-
path_base = get_one_argument_with_prefix(
|
297
|
-
path_src = get_one_argument_with_prefix(
|
298
|
-
path_dst = get_one_argument_with_prefix(
|
299
|
-
resp = @api_node.create('files/rename', {
|
300
|
-
return c_result_translate_rem_prefix(resp, 'entry', 'moved'
|
330
|
+
path_base = get_one_argument_with_prefix('path_base')
|
331
|
+
path_src = get_one_argument_with_prefix('path_src')
|
332
|
+
path_dst = get_one_argument_with_prefix('path_dst')
|
333
|
+
resp = @api_node.create('files/rename', {'paths' => [{'path' => path_base, 'source' => path_src, 'destination' => path_dst}]})
|
334
|
+
return c_result_translate_rem_prefix(resp, 'entry', 'moved')
|
301
335
|
when :browse
|
302
|
-
return browse_gen3
|
336
|
+
return browse_gen3
|
303
337
|
when :sync
|
304
338
|
return execute_sync_action do |sync_direction, local_path, remote_path|
|
305
339
|
# Gen3 API
|
306
340
|
# empty transfer spec for authorization request
|
307
|
-
request_transfer_spec =
|
308
|
-
type: case sync_direction
|
309
|
-
when :push then :sync_upload
|
310
|
-
when :pull then :sync_download
|
311
|
-
when :bidi then :sync
|
312
|
-
end,
|
313
|
-
paths: [{
|
314
|
-
source: remote_path,
|
315
|
-
destination: local_path
|
316
|
-
}]
|
317
|
-
}
|
341
|
+
request_transfer_spec = sync_spec_request(sync_direction, local_path, remote_path)
|
318
342
|
# add fixed parameters if any (for COS)
|
319
343
|
@api_node.add_tspec_info(request_transfer_spec) if @api_node.respond_to?(:add_tspec_info)
|
320
344
|
# prepare payload for single request
|
@@ -322,7 +346,7 @@ module Aspera
|
|
322
346
|
# only one request, so only one answer
|
323
347
|
transfer_spec = @api_node.create('files/sync_setup', setup_payload)['transfer_specs'].first['transfer_spec']
|
324
348
|
# API returns null tag... but async does not like it
|
325
|
-
transfer_spec.delete_if{ |_k, v| v.nil?
|
349
|
+
transfer_spec.delete_if{ |_k, v| v.nil?}
|
326
350
|
# delete this part, as the returned value contains only destination, and not sources
|
327
351
|
# transfer_spec.delete('paths') if command.eql?(:upload)
|
328
352
|
Log.log.debug{Log.dump(:ts, transfer_spec)}
|
@@ -335,7 +359,7 @@ module Aspera
|
|
335
359
|
request_transfer_spec[:paths] = if command.eql?(:download)
|
336
360
|
transfer.ts_source_paths
|
337
361
|
else
|
338
|
-
[{
|
362
|
+
[{destination: transfer.destination_folder(Transfer::Spec::DIRECTION_SEND)}]
|
339
363
|
end
|
340
364
|
# add fixed parameters if any (for COS)
|
341
365
|
@api_node.add_tspec_info(request_transfer_spec) if @api_node.respond_to?(:add_tspec_info)
|
@@ -346,32 +370,30 @@ module Aspera
|
|
346
370
|
# delete this part, as the returned value contains only destination, and not sources
|
347
371
|
transfer_spec.delete('paths') if command.eql?(:upload)
|
348
372
|
return Main.result_transfer(transfer.start(transfer_spec))
|
349
|
-
when :
|
350
|
-
remote_path = get_one_argument_with_prefix(
|
351
|
-
|
352
|
-
@api_node.call(
|
373
|
+
when :cat
|
374
|
+
remote_path = get_one_argument_with_prefix('remote path')
|
375
|
+
File.basename(remote_path)
|
376
|
+
result = @api_node.call(
|
353
377
|
operation: 'GET',
|
354
|
-
subpath: "files/#{URI.encode_www_form_component(remote_path)}/contents"
|
355
|
-
|
356
|
-
return Main.result_status("downloaded: #{file_name}")
|
378
|
+
subpath: "files/#{URI.encode_www_form_component(remote_path)}/contents")
|
379
|
+
return Main.result_text(result[:http].body)
|
357
380
|
when :transport
|
358
|
-
return
|
381
|
+
return Main.result_single_object(@api_node.transport_params)
|
359
382
|
end
|
360
383
|
Aspera.error_unreachable_line
|
361
384
|
end
|
362
385
|
|
363
386
|
# common API to node and Shares
|
364
|
-
|
365
|
-
def execute_simple_common(command, prefix_path)
|
387
|
+
def execute_simple_common(command)
|
366
388
|
case command
|
367
389
|
when *COMMANDS_GEN3
|
368
|
-
execute_command_gen3(command
|
390
|
+
execute_command_gen3(command)
|
369
391
|
when :access_keys
|
370
392
|
ak_command = options.get_next_command(%i[do set_bearer_key].concat(Plugin::ALL_OPS))
|
371
393
|
case ak_command
|
372
394
|
when *Plugin::ALL_OPS
|
373
395
|
return entity_command(ak_command, @api_node, 'access_keys') do |field, value|
|
374
|
-
raise 'only selector: %id:self' unless field.eql?('id') && value.eql?('self')
|
396
|
+
raise Cli::BadIdentifier, 'only selector: %id:self' unless field.eql?('id') && value.eql?('self')
|
375
397
|
@api_node.read('access_keys/self')['id']
|
376
398
|
end
|
377
399
|
when :do
|
@@ -410,11 +432,12 @@ module Aspera
|
|
410
432
|
end
|
411
433
|
begin
|
412
434
|
@api_node.call(
|
413
|
-
operation:
|
414
|
-
subpath:
|
415
|
-
|
416
|
-
body:
|
417
|
-
|
435
|
+
operation: 'POST',
|
436
|
+
subpath: 'services/soap/Transfer-201210',
|
437
|
+
content_type: Rest::MIME_TEXT,
|
438
|
+
body: CENTRAL_SOAP_API_TEST,
|
439
|
+
headers: {'Content-Type' => 'text/xml;charset=UTF-8', 'SOAPAction' => 'FASPSessionNET-200911#GetSessionInfo'}
|
440
|
+
)[:http].body
|
418
441
|
nagios.add_ok('central', 'accessible by node')
|
419
442
|
rescue StandardError => e
|
420
443
|
nagios.add_critical('central', e.to_s)
|
@@ -422,22 +445,22 @@ module Aspera
|
|
422
445
|
return nagios.result
|
423
446
|
when :events
|
424
447
|
events = @api_node.read('events', query_read_delete)
|
425
|
-
return
|
448
|
+
return Main.result_object_list(events, fields: ->(f){!f.start_with?('data')})
|
426
449
|
when :info
|
427
450
|
nd_info = @api_node.read('info')
|
428
|
-
return
|
451
|
+
return Main.result_single_object(nd_info)
|
429
452
|
when :slash
|
430
453
|
nd_info = @api_node.read('')
|
431
|
-
return
|
454
|
+
return Main.result_single_object(nd_info)
|
432
455
|
when :license
|
433
456
|
# requires: asnodeadmin -mu <node user> --acl-add=internal --internal
|
434
457
|
node_license = @api_node.read('license')
|
435
458
|
if node_license['failure'].is_a?(String) && node_license['failure'].include?('ACL')
|
436
459
|
Log.log.error('server must have: asnodeadmin -mu <node user> --acl-add=internal --internal')
|
437
460
|
end
|
438
|
-
return
|
461
|
+
return Main.result_single_object(node_license)
|
439
462
|
when :api_details
|
440
|
-
return {
|
463
|
+
return Main.result_single_object({base_url: @api_node.base_url}.merge(@api_node.params))
|
441
464
|
end
|
442
465
|
end
|
443
466
|
|
@@ -445,7 +468,7 @@ module Aspera
|
|
445
468
|
# @return [Hash] api and main file id for given path or id in next argument
|
446
469
|
def apifid_from_next_arg(top_file_id)
|
447
470
|
file_path = instance_identifier(description: 'path or %id:<id>') do |attribute, value|
|
448
|
-
raise 'Only selection "id" is supported (file id)' unless attribute.eql?('id')
|
471
|
+
raise Cli::BadIdentifier, 'Only selection "id" is supported (file id)' unless attribute.eql?('id')
|
449
472
|
# directly return result for method
|
450
473
|
return {api: @api_node, file_id: value}
|
451
474
|
end
|
@@ -456,7 +479,7 @@ module Aspera
|
|
456
479
|
def execute_command_gen4(command_repo, top_file_id)
|
457
480
|
override_file_id = options.get_option(:root_id)
|
458
481
|
top_file_id = override_file_id unless override_file_id.nil?
|
459
|
-
raise 'Specify root file id with option root_id' if top_file_id.nil?
|
482
|
+
raise Cli::Error, 'Specify root file id with option root_id' if top_file_id.nil?
|
460
483
|
case command_repo
|
461
484
|
when :v3
|
462
485
|
# NOTE: other common actions are unauthorized with user scope
|
@@ -477,10 +500,10 @@ module Aspera
|
|
477
500
|
result[:password] = apifid[:api].auth_params[:password]
|
478
501
|
when :oauth2
|
479
502
|
result[:username] = apifid[:api].params[:headers][Api::Node::HEADER_X_ASPERA_ACCESS_KEY]
|
480
|
-
result[:password] = apifid[:api].oauth.
|
503
|
+
result[:password] = apifid[:api].oauth.authorization
|
481
504
|
else Aspera.error_unreachable_line
|
482
505
|
end
|
483
|
-
return
|
506
|
+
return Main.result_single_object(result) if command_repo.eql?(:node_info)
|
484
507
|
# check format of bearer token
|
485
508
|
OAuth::Factory.bearer_extract(result[:password])
|
486
509
|
return Main.result_status(result[:password])
|
@@ -489,20 +512,48 @@ module Aspera
|
|
489
512
|
file_info = apifid[:api].read_with_cache("files/#{apifid[:file_id]}")
|
490
513
|
unless file_info['type'].eql?('folder')
|
491
514
|
# a single file
|
492
|
-
return
|
515
|
+
return Main.result_object_list([file_info], fields: GEN4_LS_FIELDS)
|
493
516
|
end
|
494
|
-
return
|
517
|
+
return Main.result_object_list(apifid[:api].list_files(apifid[:file_id]), fields: GEN4_LS_FIELDS)
|
495
518
|
when :find
|
496
519
|
apifid = apifid_from_next_arg(top_file_id)
|
497
520
|
find_lambda = Api::Node.file_matcher_from_argument(options)
|
498
|
-
return
|
499
|
-
when :mkdir
|
521
|
+
return Main.result_object_list(@api_node.find_files(apifid[:file_id], find_lambda), fields: ['path'])
|
522
|
+
when :mkdir, :mklink, :mkfile
|
500
523
|
containing_folder_path = options.get_next_argument('path').split(Api::Node::PATH_SEPARATOR)
|
501
|
-
|
502
|
-
# add trailing slash to force last link to be resolved
|
524
|
+
new_item = containing_folder_path.pop
|
503
525
|
apifid = @api_node.resolve_api_fid(top_file_id, containing_folder_path.join(Api::Node::PATH_SEPARATOR), true)
|
504
|
-
|
505
|
-
|
526
|
+
query = options.get_option(:query, mandatory: false)
|
527
|
+
check_exists = true
|
528
|
+
payload = {name: new_item}
|
529
|
+
if query
|
530
|
+
check_exists = !query.delete('check').eql?(false)
|
531
|
+
target = query.delete('target')
|
532
|
+
if target
|
533
|
+
target_apifid = @api_node.resolve_api_fid(top_file_id, target, true)
|
534
|
+
payload[:target_id] = target_apifid[:file_id]
|
535
|
+
end
|
536
|
+
payload.merge!(query.symbolize_keys)
|
537
|
+
end
|
538
|
+
if check_exists
|
539
|
+
folder_content = apifid[:api].read("files/#{apifid[:file_id]}/files")
|
540
|
+
link_name = ".#{new_item}.asp-lnk"
|
541
|
+
found = folder_content.find{ |i| i['name'].eql?(new_item) || i['name'].eql?(link_name)}
|
542
|
+
raise "A #{found['type']} already exists with name #{new_item}" if found
|
543
|
+
end
|
544
|
+
case command_repo
|
545
|
+
when :mkdir
|
546
|
+
payload[:type] = :folder
|
547
|
+
when :mklink
|
548
|
+
payload[:type] = :link
|
549
|
+
Aspera.assert(payload[:target_id]){'Missing target_id'}
|
550
|
+
Aspera.assert(payload[:target_node_id]){'Missing target_node_id'}
|
551
|
+
when :mkfile
|
552
|
+
payload[:type] = :file
|
553
|
+
payload[:contents] = Base64.strict_encode64(options.get_next_argument('contents'))
|
554
|
+
end
|
555
|
+
result = apifid[:api].create("files/#{apifid[:file_id]}/files", payload)
|
556
|
+
return Main.result_single_object(result)
|
506
557
|
when :rename
|
507
558
|
file_path = options.get_next_argument('source path')
|
508
559
|
apifid = @api_node.resolve_api_fid(top_file_id, file_path)
|
@@ -562,11 +613,11 @@ module Aspera
|
|
562
613
|
# TODO: add this ? , 'destination'=>file_info['name']
|
563
614
|
source_paths = [{'source' => '.'}]
|
564
615
|
else
|
565
|
-
raise "Unknown source type: #{file_info['type']}"
|
616
|
+
raise BadArgument, "Unknown source type: #{file_info['type']}"
|
566
617
|
end
|
567
618
|
end
|
568
619
|
return Main.result_transfer(transfer.start(apifid[:api].transfer_spec_gen4(apifid[:file_id], Transfer::Spec::DIRECTION_RECEIVE, {'paths'=>source_paths})))
|
569
|
-
when :
|
620
|
+
when :cat
|
570
621
|
source_paths = transfer.ts_source_paths
|
571
622
|
source_folder = source_paths.shift['source']
|
572
623
|
if source_paths.empty?
|
@@ -577,15 +628,14 @@ module Aspera
|
|
577
628
|
raise Cli::BadArgument, 'one file at a time only in HTTP mode' if source_paths.length > 1
|
578
629
|
file_name = source_paths.first['source']
|
579
630
|
apifid = @api_node.resolve_api_fid(top_file_id, File.join(source_folder, file_name))
|
580
|
-
apifid[:api].call(
|
631
|
+
result = apifid[:api].call(
|
581
632
|
operation: 'GET',
|
582
|
-
subpath: "files/#{apifid[:file_id]}/content"
|
583
|
-
|
584
|
-
return Main.result_status("downloaded: #{file_name}")
|
633
|
+
subpath: "files/#{apifid[:file_id]}/content")
|
634
|
+
return Main.result_text(result[:http].body)
|
585
635
|
when :show
|
586
636
|
apifid = apifid_from_next_arg(top_file_id)
|
587
637
|
items = apifid[:api].read("files/#{apifid[:file_id]}")
|
588
|
-
return
|
638
|
+
return Main.result_single_object(items)
|
589
639
|
when :modify
|
590
640
|
apifid = apifid_from_next_arg(top_file_id)
|
591
641
|
update_param = options.get_next_argument('update data', validation: Hash)
|
@@ -601,7 +651,7 @@ module Aspera
|
|
601
651
|
return Main.result_image(result[:http].body, formatter: formatter)
|
602
652
|
when :permission
|
603
653
|
apifid = apifid_from_next_arg(top_file_id)
|
604
|
-
command_perm = options.get_next_command(%i[list create delete])
|
654
|
+
command_perm = options.get_next_command(%i[list show create delete])
|
605
655
|
case command_perm
|
606
656
|
when :list
|
607
657
|
list_query = query_read_delete(default: {'include' => Rest.array_params(%w[access_level permission_count])})
|
@@ -610,7 +660,10 @@ module Aspera
|
|
610
660
|
list_query['inherited'] = false if list_query.key?('file_id') && !list_query.key?('inherited')
|
611
661
|
# NOTE: supports per_page and page and header X-Total-Count
|
612
662
|
items = apifid[:api].read('permissions', list_query)
|
613
|
-
return
|
663
|
+
return Main.result_object_list(items)
|
664
|
+
when :show
|
665
|
+
perm_id = instance_identifier
|
666
|
+
return Main.result_single_object(apifid[:api].read("permissions/#{perm_id}"))
|
614
667
|
when :delete
|
615
668
|
return do_bulk_operation(command: command_perm, descr: 'identifier', values: :identifier) do |one_id|
|
616
669
|
apifid[:api].delete("permissions/#{one_id}")
|
@@ -621,7 +674,7 @@ module Aspera
|
|
621
674
|
end
|
622
675
|
when :create
|
623
676
|
create_param = options.get_next_argument('creation data', validation: Hash)
|
624
|
-
raise 'no file_id' if create_param.key?('file_id')
|
677
|
+
raise Cli::BadArgument, 'no file_id' if create_param.key?('file_id')
|
625
678
|
create_param['file_id'] = apifid[:file_id]
|
626
679
|
create_param['access_levels'] = Api::Node::ACCESS_LEVELS unless create_param.key?('access_levels')
|
627
680
|
# add application specific tags (AoC)
|
@@ -631,7 +684,7 @@ module Aspera
|
|
631
684
|
created_data = apifid[:api].create('permissions', create_param)
|
632
685
|
# notify application of creation
|
633
686
|
the_app&.[](:api)&.permissions_send_event(event_data: created_data, app_info: the_app)
|
634
|
-
return
|
687
|
+
return Main.result_single_object(created_data)
|
635
688
|
else Aspera.error_unreachable_line
|
636
689
|
end
|
637
690
|
else Aspera.error_unreachable_line
|
@@ -655,8 +708,8 @@ module Aspera
|
|
655
708
|
else
|
656
709
|
async_ids = @api_node.read('async/list')['sync_ids']
|
657
710
|
summaries = @api_node.create('async/summary', {'syncs' => async_ids})['sync_summaries']
|
658
|
-
selected = summaries.find{|s|s['name'].eql?(async_name)}
|
659
|
-
raise "no such sync: #{async_name}" if selected.nil?
|
711
|
+
selected = summaries.find{ |s| s['name'].eql?(async_name)}
|
712
|
+
raise Cli::BadIdentifier, "no such sync: #{async_name}" if selected.nil?
|
660
713
|
async_id = selected['snid']
|
661
714
|
async_ids = [async_id]
|
662
715
|
end
|
@@ -665,22 +718,22 @@ module Aspera
|
|
665
718
|
case command
|
666
719
|
when :list
|
667
720
|
resp = @api_node.read('async/list')['sync_ids']
|
668
|
-
return
|
721
|
+
return Main.result_value_list(resp, name: 'id')
|
669
722
|
when :show
|
670
723
|
resp = @api_node.create('async/summary', post_data)['sync_summaries']
|
671
724
|
return Main.result_empty if resp.empty?
|
672
|
-
return
|
673
|
-
return
|
725
|
+
return Main.result_object_list(resp, fields: %w[snid name local_dir remote_dir]) if async_id.eql?(SpecialValues::ALL)
|
726
|
+
return Main.result_single_object(resp.first)
|
674
727
|
when :delete
|
675
728
|
resp = @api_node.create('async/delete', post_data)
|
676
|
-
return
|
729
|
+
return Main.result_single_object(resp)
|
677
730
|
when :bandwidth
|
678
731
|
post_data['seconds'] = 100 # TODO: as parameter with --value
|
679
732
|
resp = @api_node.create('async/bandwidth', post_data)
|
680
733
|
data = resp['bandwidth_data']
|
681
734
|
return Main.result_empty if data.empty?
|
682
735
|
data = data.first[async_id]['data']
|
683
|
-
return
|
736
|
+
return Main.result_object_list(data)
|
684
737
|
when :files
|
685
738
|
# count int
|
686
739
|
# filename str
|
@@ -703,17 +756,17 @@ module Aspera
|
|
703
756
|
options.get_option(:username, mandatory: true),
|
704
757
|
async_id]))
|
705
758
|
unless iteration_data.first.nil?
|
706
|
-
data.select!{|l| l['fnid'].to_i > iteration_data.first}
|
759
|
+
data.select!{ |l| l['fnid'].to_i > iteration_data.first}
|
707
760
|
end
|
708
761
|
iteration_data[0] = data.last['fnid'].to_i unless data.empty?
|
709
762
|
end
|
710
763
|
return Main.result_empty if data.empty?
|
711
764
|
skip_ids_persistency&.save
|
712
|
-
return
|
765
|
+
return Main.result_object_list(data)
|
713
766
|
when :counters
|
714
767
|
resp = @api_node.create('async/counters', post_data)['sync_counters'].first[async_id].last
|
715
768
|
return Main.result_empty if resp.nil?
|
716
|
-
return
|
769
|
+
return Main.result_single_object(resp)
|
717
770
|
end
|
718
771
|
end
|
719
772
|
|
@@ -728,7 +781,7 @@ module Aspera
|
|
728
781
|
# name is unique, so we can return
|
729
782
|
return id if sync_info[field].eql?(value)
|
730
783
|
end
|
731
|
-
raise Cli::
|
784
|
+
raise Cli::BadIdentifier, "no such sync: #{field}=#{value}"
|
732
785
|
end
|
733
786
|
|
734
787
|
ACTIONS = %i[
|
@@ -742,60 +795,57 @@ module Aspera
|
|
742
795
|
asperabrowser
|
743
796
|
basic_token
|
744
797
|
bearer_token
|
745
|
-
simulator
|
798
|
+
simulator
|
799
|
+
telemetry
|
800
|
+
].concat(COMMON_ACTIONS).freeze
|
746
801
|
|
747
|
-
def execute_action(command=nil
|
802
|
+
def execute_action(command=nil)
|
748
803
|
command ||= options.get_next_command(ACTIONS)
|
749
804
|
case command
|
750
|
-
when *COMMON_ACTIONS then return execute_simple_common(command
|
805
|
+
when *COMMON_ACTIONS then return execute_simple_common(command)
|
751
806
|
when :async then return execute_async # former API
|
752
807
|
when :ssync
|
753
808
|
# newer API
|
754
809
|
sync_command = options.get_next_command(%i[start stop bandwidth counters files state summary].concat(Plugin::ALL_OPS) - %i[modify])
|
755
810
|
case sync_command
|
756
|
-
when *Plugin::ALL_OPS then return entity_command(sync_command, @api_node, 'asyncs', item_list_key: 'ids'){|field, value|ssync_lookup(field, value)}
|
811
|
+
when *Plugin::ALL_OPS then return entity_command(sync_command, @api_node, 'asyncs', item_list_key: 'ids'){ |field, value| ssync_lookup(field, value)}
|
757
812
|
else
|
758
|
-
asyncs_id = instance_identifier
|
813
|
+
asyncs_id = instance_identifier{ |field, value| ssync_lookup(field, value)}
|
759
814
|
if %i[start stop].include?(sync_command)
|
760
815
|
@api_node.call(
|
761
|
-
operation:
|
762
|
-
subpath:
|
763
|
-
|
764
|
-
|
816
|
+
operation: 'POST',
|
817
|
+
subpath: "asyncs/#{asyncs_id}/#{sync_command}",
|
818
|
+
content_type: Rest::MIME_TEXT,
|
819
|
+
body: ''
|
820
|
+
)[:http].body
|
765
821
|
return Main.result_status('Done')
|
766
822
|
end
|
767
823
|
parameters = nil
|
768
824
|
parameters = options.get_option(:query, default: {}) if %i[bandwidth counters files].include?(sync_command)
|
769
|
-
return
|
825
|
+
return Main.result_single_object(@api_node.read("asyncs/#{asyncs_id}/#{sync_command}", parameters))
|
770
826
|
end
|
771
827
|
when :stream
|
772
828
|
command = options.get_next_command(%i[list create show modify cancel])
|
773
829
|
case command
|
774
830
|
when :list
|
775
831
|
resp = @api_node.read('ops/transfers', query_read_delete)
|
776
|
-
return
|
832
|
+
return Main.result_object_list(resp, fields: %w[id status]) # TODO: useful?
|
777
833
|
when :create
|
778
834
|
resp = @api_node.create('streams', value_create_modify(command: command))
|
779
|
-
return
|
835
|
+
return Main.result_single_object(resp)
|
780
836
|
when :show
|
781
837
|
resp = @api_node.read("ops/transfers/#{options.get_next_argument('transfer id')}")
|
782
|
-
return
|
838
|
+
return Main.result_single_object(resp)
|
783
839
|
when :modify
|
784
840
|
resp = @api_node.update("streams/#{options.get_next_argument('transfer id')}", value_create_modify(command: command))
|
785
|
-
return
|
841
|
+
return Main.result_single_object(resp)
|
786
842
|
when :cancel
|
787
843
|
resp = @api_node.cancel("streams/#{options.get_next_argument('transfer id')}")
|
788
|
-
return
|
789
|
-
else
|
790
|
-
raise 'error'
|
844
|
+
return Main.result_single_object(resp)
|
845
|
+
else Aspera.error_unexpected_value(command)
|
791
846
|
end
|
792
847
|
when :transfer
|
793
848
|
command = options.get_next_command(%i[list cancel show modify bandwidth_average sessions])
|
794
|
-
res_class_path = 'ops/transfers'
|
795
|
-
if %i[cancel show modify].include?(command)
|
796
|
-
one_res_id = instance_identifier
|
797
|
-
one_res_path = "#{res_class_path}/#{one_res_id}"
|
798
|
-
end
|
799
849
|
case command
|
800
850
|
when :list
|
801
851
|
transfer_filter = query_read_delete(default: {})
|
@@ -817,12 +867,12 @@ module Aspera
|
|
817
867
|
end
|
818
868
|
last_iteration_token = iteration_persistency.data.first
|
819
869
|
end
|
820
|
-
raise 'reset only with once_only' if transfer_filter.key?('reset') && iteration_persistency.nil?
|
870
|
+
raise Cli::BadArgument, 'reset only with once_only' if transfer_filter.key?('reset') && iteration_persistency.nil?
|
821
871
|
max_items = transfer_filter.delete(MAX_ITEMS)
|
822
872
|
transfers_data = []
|
823
873
|
loop do
|
824
874
|
transfer_filter['iteration_token'] = last_iteration_token unless last_iteration_token.nil?
|
825
|
-
result = @api_node.call(operation: 'GET', subpath:
|
875
|
+
result = @api_node.call(operation: 'GET', subpath: 'ops/transfers', query: transfer_filter)
|
826
876
|
# no data
|
827
877
|
break if result[:data].empty?
|
828
878
|
# get next iteration token from link
|
@@ -838,7 +888,6 @@ module Aspera
|
|
838
888
|
last_iteration_token = next_iteration_token
|
839
889
|
transfers_data.concat(result[:data])
|
840
890
|
if max_items&.<=(transfers_data.length)
|
841
|
-
# if !max_items.nil? && (transfers_data.length >= max_items)
|
842
891
|
transfers_data = transfers_data.slice(0, max_items)
|
843
892
|
break
|
844
893
|
end
|
@@ -852,8 +901,8 @@ module Aspera
|
|
852
901
|
fields: %w[id status start_spec.direction start_spec.remote_user start_spec.remote_host start_spec.destination_path]
|
853
902
|
}
|
854
903
|
when :sessions
|
855
|
-
transfers_data = @api_node.read(
|
856
|
-
sessions = transfers_data.map{|t|t['sessions']}.flatten
|
904
|
+
transfers_data = @api_node.read('ops/transfers', query_read_delete)
|
905
|
+
sessions = transfers_data.map{ |t| t['sessions']}.flatten
|
857
906
|
sessions.each do |session|
|
858
907
|
session['start_time'] = Time.at(session['start_time_usec'] / 1_000_000.0).utc.iso8601(0)
|
859
908
|
session['end_time'] = Time.at(session['end_time_usec'] / 1_000_000.0).utc.iso8601(0)
|
@@ -864,16 +913,16 @@ module Aspera
|
|
864
913
|
fields: %w[id status start_time end_time target_rate_kbps]
|
865
914
|
}
|
866
915
|
when :cancel
|
867
|
-
resp = @api_node.cancel(
|
868
|
-
return
|
916
|
+
resp = @api_node.cancel("ops/transfers/#{instance_identifier}")
|
917
|
+
return Main.result_single_object(resp)
|
869
918
|
when :show
|
870
|
-
resp = @api_node.read(
|
871
|
-
return
|
919
|
+
resp = @api_node.read("ops/transfers/#{instance_identifier}")
|
920
|
+
return Main.result_single_object(resp)
|
872
921
|
when :modify
|
873
|
-
resp = @api_node.update(
|
874
|
-
return
|
922
|
+
resp = @api_node.update("ops/transfers/#{instance_identifier}", options.get_next_argument('update value', validation: Hash))
|
923
|
+
return Main.result_single_object(resp)
|
875
924
|
when :bandwidth_average
|
876
|
-
transfers_data = @api_node.read(
|
925
|
+
transfers_data = @api_node.read('ops/transfers', query_read_delete)
|
877
926
|
# collect all key dates
|
878
927
|
bandwidth_period = {}
|
879
928
|
dir_info = %i[avg_kbps sessions].freeze
|
@@ -916,9 +965,8 @@ module Aspera
|
|
916
965
|
end
|
917
966
|
result.push({start: Time.at(start_date / 1_000_000), end: Time.at(end_date / 1_000_000)}.merge(period_bandwidth))
|
918
967
|
end
|
919
|
-
return
|
920
|
-
else
|
921
|
-
raise 'error'
|
968
|
+
return Main.result_object_list(result)
|
969
|
+
else Aspera.error_unexpected_value(command)
|
922
970
|
end
|
923
971
|
when :service
|
924
972
|
command = options.get_next_command(%i[list create delete])
|
@@ -928,7 +976,7 @@ module Aspera
|
|
928
976
|
case command
|
929
977
|
when :list
|
930
978
|
resp = @api_node.read('rund/services')
|
931
|
-
return
|
979
|
+
return Main.result_object_list(resp['services'])
|
932
980
|
when :create
|
933
981
|
# @json:'{"type":"WATCHFOLDERD","run_as":{"user":"user1"}}'
|
934
982
|
params = options.get_next_argument('creation data', validation: Hash)
|
@@ -954,9 +1002,9 @@ module Aspera
|
|
954
1002
|
return Main.result_status("#{resp['id']} created")
|
955
1003
|
when :list
|
956
1004
|
resp = @api_node.read(res_class_path, query_read_delete)
|
957
|
-
return
|
1005
|
+
return Main.result_value_list(resp['ids'], name: 'id')
|
958
1006
|
when :show
|
959
|
-
return
|
1007
|
+
return Main.result_single_object(@api_node.read(one_res_path))
|
960
1008
|
when :modify
|
961
1009
|
@api_node.update(one_res_path, options.get_option(:query, mandatory: true))
|
962
1010
|
return Main.result_status("#{one_res_id} updated")
|
@@ -964,7 +1012,7 @@ module Aspera
|
|
964
1012
|
@api_node.delete(one_res_path)
|
965
1013
|
return Main.result_status("#{one_res_id} deleted")
|
966
1014
|
when :state
|
967
|
-
return
|
1015
|
+
return Main.result_single_object(@api_node.read("#{one_res_path}/state"))
|
968
1016
|
end
|
969
1017
|
when :central
|
970
1018
|
command = options.get_next_command(%i[session file])
|
@@ -994,7 +1042,7 @@ module Aspera
|
|
994
1042
|
resp = @api_node.create('services/rest/transfers/v1/files', request_data)
|
995
1043
|
resp = JSON.parse(resp) if resp.is_a?(String)
|
996
1044
|
Log.log.debug{Log.dump(:resp, resp)}
|
997
|
-
return
|
1045
|
+
return Main.result_object_list(resp['file_transfer_info_result']['file_transfer_info'], fields: %w[session_uuid file_id status path])
|
998
1046
|
when :modify
|
999
1047
|
request_data = options.get_next_argument('request data', mandatory: false, validation: Hash, default: {})
|
1000
1048
|
request_data.deep_merge!(validation) unless validation.nil?
|
@@ -1013,7 +1061,7 @@ module Aspera
|
|
1013
1061
|
Environment.instance.open_uri("#{options.get_option(:asperabrowserurl)}?goto=#{encoded_params}")
|
1014
1062
|
return Main.result_status('done')
|
1015
1063
|
when :basic_token
|
1016
|
-
return Main.result_status(Rest.
|
1064
|
+
return Main.result_status(Rest.basic_authorization(options.get_option(:username, mandatory: true), options.get_option(:password, mandatory: true)))
|
1017
1065
|
when :bearer_token
|
1018
1066
|
private_key = OpenSSL::PKey::RSA.new(options.get_next_argument('private RSA key PEM value', validation: String))
|
1019
1067
|
token_info = options.get_next_argument('user and group identification', validation: Hash)
|
@@ -1021,32 +1069,114 @@ module Aspera
|
|
1021
1069
|
return Main.result_status(Api::Node.bearer_token(payload: token_info, access_key: access_key, private_key: private_key))
|
1022
1070
|
when :simulator
|
1023
1071
|
require 'aspera/node_simulator'
|
1024
|
-
parameters = value_create_modify(command: command)
|
1025
|
-
|
1026
|
-
|
1027
|
-
uri
|
1028
|
-
server = WebServerSimple.new(uri, certificate: parameters[:certificate])
|
1029
|
-
server.mount(uri.path, NodeSimulatorServlet, parameters[:credentials], NodeSimulator.new)
|
1072
|
+
parameters = value_create_modify(command: command, default: {}).symbolize_keys
|
1073
|
+
uri = URI.parse(parameters.delete(:url){WebServerSimple::DEFAULT_URL})
|
1074
|
+
server = WebServerSimple.new(uri, **parameters.slice(*WebServerSimple::PARAMS))
|
1075
|
+
server.mount(uri.path, NodeSimulatorServlet, parameters.except(*WebServerSimple::PARAMS), NodeSimulator.new)
|
1030
1076
|
server.start
|
1031
1077
|
return Main.result_status('Simulator terminated')
|
1078
|
+
when :telemetry
|
1079
|
+
parameters = value_create_modify(command: command, default: {}).symbolize_keys
|
1080
|
+
%i[url apikey].each do |psym|
|
1081
|
+
raise Cli::BadArgument, "Missing parameter: #{psym}" unless parameters.key?(psym)
|
1082
|
+
end
|
1083
|
+
require 'socket'
|
1084
|
+
parameters[:interval] = 10 unless parameters.key?(:interval)
|
1085
|
+
parameters[:hostname] = Socket.gethostname unless parameters.key?(:hostname)
|
1086
|
+
interval = parameters[:interval].to_f
|
1087
|
+
raise Cli::BadArgument, 'Interval must be a positive number in seconds' if interval <= 0
|
1088
|
+
backend_api = Rest.new(
|
1089
|
+
base_url: "#{parameters[:url]}/v1",
|
1090
|
+
headers: {
|
1091
|
+
# 'Authorization' => "apiToken #{parameters[:apikey]}",
|
1092
|
+
'x-instana-key' => parameters[:apikey],
|
1093
|
+
'x-instana-host' => parameters[:hostname]
|
1094
|
+
}
|
1095
|
+
)
|
1096
|
+
|
1097
|
+
loop do
|
1098
|
+
start_time = Time.now
|
1099
|
+
transfer_filter = {active_only: true}
|
1100
|
+
transfers_data = []
|
1101
|
+
loop do
|
1102
|
+
result = @api_node.call(operation: 'GET', subpath: 'ops/transfers', query: transfer_filter)
|
1103
|
+
# no data
|
1104
|
+
break if result[:data].empty?
|
1105
|
+
# get next iteration token from link
|
1106
|
+
next_iteration_token = nil
|
1107
|
+
link_info = result[:http]['Link']
|
1108
|
+
unless link_info.nil?
|
1109
|
+
m = link_info.match(/<([^>]+)>/)
|
1110
|
+
Aspera.assert(m){"Cannot parse iteration in Link: #{link_info}"}
|
1111
|
+
next_iteration_token = CGI.parse(URI.parse(m[1]).query)['iteration_token']&.first
|
1112
|
+
end
|
1113
|
+
# same as last iteration: stop
|
1114
|
+
break if next_iteration_token&.eql?(transfer_filter[:iteration_token])
|
1115
|
+
transfer_filter[:iteration_token] = next_iteration_token
|
1116
|
+
transfers_data.concat(result[:data])
|
1117
|
+
break if next_iteration_token.nil?
|
1118
|
+
end
|
1119
|
+
puts("#{transfers_data.length} active transfers")
|
1120
|
+
epoch_nsec = start_time.to_i * 1_000_000_000 + start_time.nsec
|
1121
|
+
# https://www.ibm.com/docs/en/instana-observability/current?topic=instana-backend
|
1122
|
+
backend_api.create('metrics', {
|
1123
|
+
resourceMetrics: [
|
1124
|
+
{
|
1125
|
+
resource: {
|
1126
|
+
attributes: [
|
1127
|
+
{
|
1128
|
+
key: 'service.name',
|
1129
|
+
value: {
|
1130
|
+
stringValue: 'mycurl5'
|
1131
|
+
}
|
1132
|
+
}
|
1133
|
+
]
|
1134
|
+
},
|
1135
|
+
scopeMetrics: [
|
1136
|
+
{
|
1137
|
+
metrics: [
|
1138
|
+
{
|
1139
|
+
name: 'tutur2',
|
1140
|
+
unit: '1',
|
1141
|
+
description: '',
|
1142
|
+
sum: {
|
1143
|
+
aggregationTemporality: 1,
|
1144
|
+
isMonotonic: true,
|
1145
|
+
dataPoints: [
|
1146
|
+
{
|
1147
|
+
asDouble: 4,
|
1148
|
+
startTimeUnixNano: epoch_nsec,
|
1149
|
+
timeUnixNano: epoch_nsec
|
1150
|
+
}
|
1151
|
+
]
|
1152
|
+
}
|
1153
|
+
}
|
1154
|
+
]
|
1155
|
+
}
|
1156
|
+
]
|
1157
|
+
}
|
1158
|
+
]
|
1159
|
+
})
|
1160
|
+
sleep([0, interval - (Time.now - start_time)].max)
|
1161
|
+
end
|
1032
1162
|
end
|
1033
|
-
|
1163
|
+
Aspera.error_unreachable_line
|
1034
1164
|
end
|
1035
1165
|
|
1036
1166
|
private
|
1037
1167
|
|
1038
1168
|
# get remaining path arguments from command line, and add prefix
|
1039
|
-
def get_all_arguments_with_prefix(
|
1169
|
+
def get_all_arguments_with_prefix(name)
|
1040
1170
|
path_args = options.get_next_argument(name, multiple: true)
|
1041
|
-
return path_args if
|
1042
|
-
return path_args.map
|
1171
|
+
return path_args if @prefix_path.nil?
|
1172
|
+
return path_args.map{ |p| File.join(@prefix_path, p)}
|
1043
1173
|
end
|
1044
1174
|
|
1045
1175
|
# get next path argument from command line, and add prefix
|
1046
|
-
def get_one_argument_with_prefix(
|
1176
|
+
def get_one_argument_with_prefix(name)
|
1047
1177
|
path_arg = options.get_next_argument(name, validation: String)
|
1048
|
-
return path_arg if
|
1049
|
-
return File.join(
|
1178
|
+
return path_arg if @prefix_path.nil?
|
1179
|
+
return File.join(@prefix_path, path_arg)
|
1050
1180
|
end
|
1051
1181
|
end
|
1052
1182
|
end
|