aspera-cli 4.21.2 → 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 +34 -16
- data/CONTRIBUTING.md +6 -10
- data/README.md +805 -574
- data/examples/get_proto_file.rb +1 -1
- data/lib/aspera/agent/base.rb +9 -5
- data/lib/aspera/agent/connect.rb +30 -28
- data/lib/aspera/agent/desktop.rb +29 -25
- data/lib/aspera/agent/direct.rb +137 -125
- data/lib/aspera/agent/httpgw.rb +22 -26
- data/lib/aspera/agent/node.rb +14 -11
- data/lib/aspera/agent/transferd.rb +6 -2
- data/lib/aspera/api/aoc.rb +6 -6
- data/lib/aspera/api/cos_node.rb +1 -1
- data/lib/aspera/api/httpgw.rb +7 -3
- data/lib/aspera/api/node.rb +6 -4
- data/lib/aspera/ascmd.rb +3 -3
- data/lib/aspera/ascp/installation.rb +15 -16
- 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 +38 -19
- data/lib/aspera/cli/formatter.rb +48 -48
- data/lib/aspera/cli/hints.rb +1 -1
- data/lib/aspera/cli/main.rb +190 -168
- data/lib/aspera/cli/manager.rb +15 -15
- 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 +144 -107
- data/lib/aspera/cli/plugins/ats.rb +19 -17
- data/lib/aspera/cli/plugins/config.rb +67 -83
- 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 +104 -80
- 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 +306 -179
- 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 +4 -3
- data/lib/aspera/environment.rb +6 -6
- data/lib/aspera/faspex_gw.rb +14 -14
- data/lib/aspera/faspex_postproc.rb +7 -6
- data/lib/aspera/hash_ext.rb +2 -2
- 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 +8 -6
- 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 +1 -1
- data/lib/aspera/preview/options.rb +16 -16
- data/lib/aspera/preview/terminal.rb +3 -3
- data/lib/aspera/preview/utils.rb +11 -13
- data/lib/aspera/products/connect.rb +1 -1
- data/lib/aspera/products/desktop.rb +1 -1
- data/lib/aspera/products/transferd.rb +1 -1
- data/lib/aspera/proxy_auto_config.rb +2 -2
- data/lib/aspera/rest.rb +52 -43
- data/lib/aspera/rest_errors_aspera.rb +1 -1
- data/lib/aspera/secret_hider.rb +5 -5
- data/lib/aspera/ssh.rb +4 -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 +1 -1
- data/lib/aspera/web_auth.rb +1 -1
- data/lib/aspera/web_server_simple.rb +53 -44
- data.tar.gz.sig +1 -2
- metadata +37 -4
- metadata.gz.sig +0 -0
- 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
|
@@ -480,7 +503,7 @@ module Aspera
|
|
480
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)
|
@@ -610,7 +660,7 @@ 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)
|
614
664
|
when :show
|
615
665
|
perm_id = instance_identifier
|
616
666
|
return Main.result_single_object(apifid[:api].read("permissions/#{perm_id}"))
|
@@ -624,7 +674,7 @@ module Aspera
|
|
624
674
|
end
|
625
675
|
when :create
|
626
676
|
create_param = options.get_next_argument('creation data', validation: Hash)
|
627
|
-
raise 'no file_id' if create_param.key?('file_id')
|
677
|
+
raise Cli::BadArgument, 'no file_id' if create_param.key?('file_id')
|
628
678
|
create_param['file_id'] = apifid[:file_id]
|
629
679
|
create_param['access_levels'] = Api::Node::ACCESS_LEVELS unless create_param.key?('access_levels')
|
630
680
|
# add application specific tags (AoC)
|
@@ -634,7 +684,7 @@ module Aspera
|
|
634
684
|
created_data = apifid[:api].create('permissions', create_param)
|
635
685
|
# notify application of creation
|
636
686
|
the_app&.[](:api)&.permissions_send_event(event_data: created_data, app_info: the_app)
|
637
|
-
return
|
687
|
+
return Main.result_single_object(created_data)
|
638
688
|
else Aspera.error_unreachable_line
|
639
689
|
end
|
640
690
|
else Aspera.error_unreachable_line
|
@@ -658,8 +708,8 @@ module Aspera
|
|
658
708
|
else
|
659
709
|
async_ids = @api_node.read('async/list')['sync_ids']
|
660
710
|
summaries = @api_node.create('async/summary', {'syncs' => async_ids})['sync_summaries']
|
661
|
-
selected = summaries.find{|s|s['name'].eql?(async_name)}
|
662
|
-
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?
|
663
713
|
async_id = selected['snid']
|
664
714
|
async_ids = [async_id]
|
665
715
|
end
|
@@ -668,22 +718,22 @@ module Aspera
|
|
668
718
|
case command
|
669
719
|
when :list
|
670
720
|
resp = @api_node.read('async/list')['sync_ids']
|
671
|
-
return
|
721
|
+
return Main.result_value_list(resp, name: 'id')
|
672
722
|
when :show
|
673
723
|
resp = @api_node.create('async/summary', post_data)['sync_summaries']
|
674
724
|
return Main.result_empty if resp.empty?
|
675
|
-
return
|
676
|
-
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)
|
677
727
|
when :delete
|
678
728
|
resp = @api_node.create('async/delete', post_data)
|
679
|
-
return
|
729
|
+
return Main.result_single_object(resp)
|
680
730
|
when :bandwidth
|
681
731
|
post_data['seconds'] = 100 # TODO: as parameter with --value
|
682
732
|
resp = @api_node.create('async/bandwidth', post_data)
|
683
733
|
data = resp['bandwidth_data']
|
684
734
|
return Main.result_empty if data.empty?
|
685
735
|
data = data.first[async_id]['data']
|
686
|
-
return
|
736
|
+
return Main.result_object_list(data)
|
687
737
|
when :files
|
688
738
|
# count int
|
689
739
|
# filename str
|
@@ -706,17 +756,17 @@ module Aspera
|
|
706
756
|
options.get_option(:username, mandatory: true),
|
707
757
|
async_id]))
|
708
758
|
unless iteration_data.first.nil?
|
709
|
-
data.select!{|l| l['fnid'].to_i > iteration_data.first}
|
759
|
+
data.select!{ |l| l['fnid'].to_i > iteration_data.first}
|
710
760
|
end
|
711
761
|
iteration_data[0] = data.last['fnid'].to_i unless data.empty?
|
712
762
|
end
|
713
763
|
return Main.result_empty if data.empty?
|
714
764
|
skip_ids_persistency&.save
|
715
|
-
return
|
765
|
+
return Main.result_object_list(data)
|
716
766
|
when :counters
|
717
767
|
resp = @api_node.create('async/counters', post_data)['sync_counters'].first[async_id].last
|
718
768
|
return Main.result_empty if resp.nil?
|
719
|
-
return
|
769
|
+
return Main.result_single_object(resp)
|
720
770
|
end
|
721
771
|
end
|
722
772
|
|
@@ -731,7 +781,7 @@ module Aspera
|
|
731
781
|
# name is unique, so we can return
|
732
782
|
return id if sync_info[field].eql?(value)
|
733
783
|
end
|
734
|
-
raise Cli::
|
784
|
+
raise Cli::BadIdentifier, "no such sync: #{field}=#{value}"
|
735
785
|
end
|
736
786
|
|
737
787
|
ACTIONS = %i[
|
@@ -745,60 +795,57 @@ module Aspera
|
|
745
795
|
asperabrowser
|
746
796
|
basic_token
|
747
797
|
bearer_token
|
748
|
-
simulator
|
798
|
+
simulator
|
799
|
+
telemetry
|
800
|
+
].concat(COMMON_ACTIONS).freeze
|
749
801
|
|
750
|
-
def execute_action(command=nil
|
802
|
+
def execute_action(command=nil)
|
751
803
|
command ||= options.get_next_command(ACTIONS)
|
752
804
|
case command
|
753
|
-
when *COMMON_ACTIONS then return execute_simple_common(command
|
805
|
+
when *COMMON_ACTIONS then return execute_simple_common(command)
|
754
806
|
when :async then return execute_async # former API
|
755
807
|
when :ssync
|
756
808
|
# newer API
|
757
809
|
sync_command = options.get_next_command(%i[start stop bandwidth counters files state summary].concat(Plugin::ALL_OPS) - %i[modify])
|
758
810
|
case sync_command
|
759
|
-
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)}
|
760
812
|
else
|
761
|
-
asyncs_id = instance_identifier
|
813
|
+
asyncs_id = instance_identifier{ |field, value| ssync_lookup(field, value)}
|
762
814
|
if %i[start stop].include?(sync_command)
|
763
815
|
@api_node.call(
|
764
|
-
operation:
|
765
|
-
subpath:
|
766
|
-
|
767
|
-
|
816
|
+
operation: 'POST',
|
817
|
+
subpath: "asyncs/#{asyncs_id}/#{sync_command}",
|
818
|
+
content_type: Rest::MIME_TEXT,
|
819
|
+
body: ''
|
820
|
+
)[:http].body
|
768
821
|
return Main.result_status('Done')
|
769
822
|
end
|
770
823
|
parameters = nil
|
771
824
|
parameters = options.get_option(:query, default: {}) if %i[bandwidth counters files].include?(sync_command)
|
772
|
-
return
|
825
|
+
return Main.result_single_object(@api_node.read("asyncs/#{asyncs_id}/#{sync_command}", parameters))
|
773
826
|
end
|
774
827
|
when :stream
|
775
828
|
command = options.get_next_command(%i[list create show modify cancel])
|
776
829
|
case command
|
777
830
|
when :list
|
778
831
|
resp = @api_node.read('ops/transfers', query_read_delete)
|
779
|
-
return
|
832
|
+
return Main.result_object_list(resp, fields: %w[id status]) # TODO: useful?
|
780
833
|
when :create
|
781
834
|
resp = @api_node.create('streams', value_create_modify(command: command))
|
782
|
-
return
|
835
|
+
return Main.result_single_object(resp)
|
783
836
|
when :show
|
784
837
|
resp = @api_node.read("ops/transfers/#{options.get_next_argument('transfer id')}")
|
785
|
-
return
|
838
|
+
return Main.result_single_object(resp)
|
786
839
|
when :modify
|
787
840
|
resp = @api_node.update("streams/#{options.get_next_argument('transfer id')}", value_create_modify(command: command))
|
788
|
-
return
|
841
|
+
return Main.result_single_object(resp)
|
789
842
|
when :cancel
|
790
843
|
resp = @api_node.cancel("streams/#{options.get_next_argument('transfer id')}")
|
791
|
-
return
|
792
|
-
else
|
793
|
-
raise 'error'
|
844
|
+
return Main.result_single_object(resp)
|
845
|
+
else Aspera.error_unexpected_value(command)
|
794
846
|
end
|
795
847
|
when :transfer
|
796
848
|
command = options.get_next_command(%i[list cancel show modify bandwidth_average sessions])
|
797
|
-
res_class_path = 'ops/transfers'
|
798
|
-
if %i[cancel show modify].include?(command)
|
799
|
-
one_res_id = instance_identifier
|
800
|
-
one_res_path = "#{res_class_path}/#{one_res_id}"
|
801
|
-
end
|
802
849
|
case command
|
803
850
|
when :list
|
804
851
|
transfer_filter = query_read_delete(default: {})
|
@@ -820,12 +867,12 @@ module Aspera
|
|
820
867
|
end
|
821
868
|
last_iteration_token = iteration_persistency.data.first
|
822
869
|
end
|
823
|
-
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?
|
824
871
|
max_items = transfer_filter.delete(MAX_ITEMS)
|
825
872
|
transfers_data = []
|
826
873
|
loop do
|
827
874
|
transfer_filter['iteration_token'] = last_iteration_token unless last_iteration_token.nil?
|
828
|
-
result = @api_node.call(operation: 'GET', subpath:
|
875
|
+
result = @api_node.call(operation: 'GET', subpath: 'ops/transfers', query: transfer_filter)
|
829
876
|
# no data
|
830
877
|
break if result[:data].empty?
|
831
878
|
# get next iteration token from link
|
@@ -841,7 +888,6 @@ module Aspera
|
|
841
888
|
last_iteration_token = next_iteration_token
|
842
889
|
transfers_data.concat(result[:data])
|
843
890
|
if max_items&.<=(transfers_data.length)
|
844
|
-
# if !max_items.nil? && (transfers_data.length >= max_items)
|
845
891
|
transfers_data = transfers_data.slice(0, max_items)
|
846
892
|
break
|
847
893
|
end
|
@@ -855,8 +901,8 @@ module Aspera
|
|
855
901
|
fields: %w[id status start_spec.direction start_spec.remote_user start_spec.remote_host start_spec.destination_path]
|
856
902
|
}
|
857
903
|
when :sessions
|
858
|
-
transfers_data = @api_node.read(
|
859
|
-
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
|
860
906
|
sessions.each do |session|
|
861
907
|
session['start_time'] = Time.at(session['start_time_usec'] / 1_000_000.0).utc.iso8601(0)
|
862
908
|
session['end_time'] = Time.at(session['end_time_usec'] / 1_000_000.0).utc.iso8601(0)
|
@@ -867,16 +913,16 @@ module Aspera
|
|
867
913
|
fields: %w[id status start_time end_time target_rate_kbps]
|
868
914
|
}
|
869
915
|
when :cancel
|
870
|
-
resp = @api_node.cancel(
|
871
|
-
return
|
916
|
+
resp = @api_node.cancel("ops/transfers/#{instance_identifier}")
|
917
|
+
return Main.result_single_object(resp)
|
872
918
|
when :show
|
873
|
-
resp = @api_node.read(
|
874
|
-
return
|
919
|
+
resp = @api_node.read("ops/transfers/#{instance_identifier}")
|
920
|
+
return Main.result_single_object(resp)
|
875
921
|
when :modify
|
876
|
-
resp = @api_node.update(
|
877
|
-
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)
|
878
924
|
when :bandwidth_average
|
879
|
-
transfers_data = @api_node.read(
|
925
|
+
transfers_data = @api_node.read('ops/transfers', query_read_delete)
|
880
926
|
# collect all key dates
|
881
927
|
bandwidth_period = {}
|
882
928
|
dir_info = %i[avg_kbps sessions].freeze
|
@@ -919,9 +965,8 @@ module Aspera
|
|
919
965
|
end
|
920
966
|
result.push({start: Time.at(start_date / 1_000_000), end: Time.at(end_date / 1_000_000)}.merge(period_bandwidth))
|
921
967
|
end
|
922
|
-
return
|
923
|
-
else
|
924
|
-
raise 'error'
|
968
|
+
return Main.result_object_list(result)
|
969
|
+
else Aspera.error_unexpected_value(command)
|
925
970
|
end
|
926
971
|
when :service
|
927
972
|
command = options.get_next_command(%i[list create delete])
|
@@ -931,7 +976,7 @@ module Aspera
|
|
931
976
|
case command
|
932
977
|
when :list
|
933
978
|
resp = @api_node.read('rund/services')
|
934
|
-
return
|
979
|
+
return Main.result_object_list(resp['services'])
|
935
980
|
when :create
|
936
981
|
# @json:'{"type":"WATCHFOLDERD","run_as":{"user":"user1"}}'
|
937
982
|
params = options.get_next_argument('creation data', validation: Hash)
|
@@ -957,9 +1002,9 @@ module Aspera
|
|
957
1002
|
return Main.result_status("#{resp['id']} created")
|
958
1003
|
when :list
|
959
1004
|
resp = @api_node.read(res_class_path, query_read_delete)
|
960
|
-
return
|
1005
|
+
return Main.result_value_list(resp['ids'], name: 'id')
|
961
1006
|
when :show
|
962
|
-
return
|
1007
|
+
return Main.result_single_object(@api_node.read(one_res_path))
|
963
1008
|
when :modify
|
964
1009
|
@api_node.update(one_res_path, options.get_option(:query, mandatory: true))
|
965
1010
|
return Main.result_status("#{one_res_id} updated")
|
@@ -967,7 +1012,7 @@ module Aspera
|
|
967
1012
|
@api_node.delete(one_res_path)
|
968
1013
|
return Main.result_status("#{one_res_id} deleted")
|
969
1014
|
when :state
|
970
|
-
return
|
1015
|
+
return Main.result_single_object(@api_node.read("#{one_res_path}/state"))
|
971
1016
|
end
|
972
1017
|
when :central
|
973
1018
|
command = options.get_next_command(%i[session file])
|
@@ -997,7 +1042,7 @@ module Aspera
|
|
997
1042
|
resp = @api_node.create('services/rest/transfers/v1/files', request_data)
|
998
1043
|
resp = JSON.parse(resp) if resp.is_a?(String)
|
999
1044
|
Log.log.debug{Log.dump(:resp, resp)}
|
1000
|
-
return
|
1045
|
+
return Main.result_object_list(resp['file_transfer_info_result']['file_transfer_info'], fields: %w[session_uuid file_id status path])
|
1001
1046
|
when :modify
|
1002
1047
|
request_data = options.get_next_argument('request data', mandatory: false, validation: Hash, default: {})
|
1003
1048
|
request_data.deep_merge!(validation) unless validation.nil?
|
@@ -1024,32 +1069,114 @@ module Aspera
|
|
1024
1069
|
return Main.result_status(Api::Node.bearer_token(payload: token_info, access_key: access_key, private_key: private_key))
|
1025
1070
|
when :simulator
|
1026
1071
|
require 'aspera/node_simulator'
|
1027
|
-
parameters = value_create_modify(command: command)
|
1028
|
-
|
1029
|
-
|
1030
|
-
uri
|
1031
|
-
server = WebServerSimple.new(uri, certificate: parameters[:certificate])
|
1032
|
-
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)
|
1033
1076
|
server.start
|
1034
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
|
1035
1162
|
end
|
1036
|
-
|
1163
|
+
Aspera.error_unreachable_line
|
1037
1164
|
end
|
1038
1165
|
|
1039
1166
|
private
|
1040
1167
|
|
1041
1168
|
# get remaining path arguments from command line, and add prefix
|
1042
|
-
def get_all_arguments_with_prefix(
|
1169
|
+
def get_all_arguments_with_prefix(name)
|
1043
1170
|
path_args = options.get_next_argument(name, multiple: true)
|
1044
|
-
return path_args if
|
1045
|
-
return path_args.map
|
1171
|
+
return path_args if @prefix_path.nil?
|
1172
|
+
return path_args.map{ |p| File.join(@prefix_path, p)}
|
1046
1173
|
end
|
1047
1174
|
|
1048
1175
|
# get next path argument from command line, and add prefix
|
1049
|
-
def get_one_argument_with_prefix(
|
1176
|
+
def get_one_argument_with_prefix(name)
|
1050
1177
|
path_arg = options.get_next_argument(name, validation: String)
|
1051
|
-
return path_arg if
|
1052
|
-
return File.join(
|
1178
|
+
return path_arg if @prefix_path.nil?
|
1179
|
+
return File.join(@prefix_path, path_arg)
|
1053
1180
|
end
|
1054
1181
|
end
|
1055
1182
|
end
|