aspera-cli 4.27.0 → 4.27.1
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/CHANGELOG.md +29 -0
- data/CONTRIBUTING.md +1 -7
- data/TODO.md +50 -0
- data/docs/README.md +708 -488
- data/lib/aspera/agent/base.rb +10 -2
- data/lib/aspera/agent/connect.rb +7 -7
- data/lib/aspera/agent/desktop.rb +3 -3
- data/lib/aspera/agent/direct.rb +48 -19
- data/lib/aspera/agent/factory.rb +3 -3
- data/lib/aspera/agent/httpgw.rb +55 -14
- data/lib/aspera/agent/node.rb +2 -2
- data/lib/aspera/agent/transferd.rb +12 -12
- data/lib/aspera/api/aoc.rb +28 -28
- data/lib/aspera/api/cos_node.rb +10 -9
- data/lib/aspera/api/faspex.rb +2 -2
- data/lib/aspera/api/httpgw.rb +20 -20
- data/lib/aspera/api/node.rb +31 -53
- data/lib/aspera/ascmd.rb +13 -13
- data/lib/aspera/ascp/installation.rb +43 -36
- data/lib/aspera/ascp/management.rb +6 -6
- data/lib/aspera/assert.rb +12 -13
- data/lib/aspera/cli/ascp_actions.rb +7 -7
- data/lib/aspera/cli/async_transfer_store.rb +49 -5
- data/lib/aspera/cli/bootstrapper.rb +9 -9
- data/lib/aspera/cli/command_registry.rb +1 -1
- data/lib/aspera/cli/command_spec.rb +6 -3
- data/lib/aspera/cli/context.rb +3 -3
- data/lib/aspera/cli/extended_value.rb +26 -26
- data/lib/aspera/cli/formatter.rb +76 -54
- data/lib/aspera/cli/gem_checker.rb +1 -1
- data/lib/aspera/cli/hints.rb +2 -2
- data/lib/aspera/cli/http.rb +22 -29
- data/lib/aspera/cli/mailer.rb +7 -7
- data/lib/aspera/cli/mcp_tool.rb +31 -4
- data/lib/aspera/cli/option_declarator.rb +77 -0
- data/lib/aspera/cli/options.schema.yaml +273 -3
- data/lib/aspera/cli/parser.rb +539 -280
- data/lib/aspera/cli/plugins/alee.rb +1 -1
- data/lib/aspera/cli/plugins/aoc.rb +297 -313
- data/lib/aspera/cli/plugins/ats.rb +25 -21
- data/lib/aspera/cli/plugins/base.rb +357 -186
- data/lib/aspera/cli/plugins/basic_auth.rb +0 -12
- data/lib/aspera/cli/plugins/config.rb +76 -73
- data/lib/aspera/cli/plugins/console.rb +8 -8
- data/lib/aspera/cli/plugins/cos.rb +4 -3
- data/lib/aspera/cli/plugins/factory.rb +2 -2
- data/lib/aspera/cli/plugins/faspex5.rb +259 -248
- data/lib/aspera/cli/plugins/faspio.rb +7 -2
- data/lib/aspera/cli/plugins/httpgw.rb +1 -1
- data/lib/aspera/cli/plugins/mcp.rb +11 -11
- data/lib/aspera/cli/plugins/node.rb +227 -283
- data/lib/aspera/cli/plugins/orchestrator.rb +23 -23
- data/lib/aspera/cli/plugins/preview.rb +61 -64
- data/lib/aspera/cli/plugins/server.rb +36 -31
- data/lib/aspera/cli/plugins/shares.rb +174 -135
- data/lib/aspera/cli/preset_actions.rb +39 -19
- data/lib/aspera/cli/preset_manager.rb +74 -32
- data/lib/aspera/cli/result.rb +18 -16
- data/lib/aspera/cli/runner.rb +75 -39
- data/lib/aspera/cli/secret_finder.rb +1 -1
- data/lib/aspera/cli/sync_actions.rb +36 -35
- data/lib/aspera/cli/terminal_formatter.rb +2 -2
- data/lib/aspera/cli/transfer_actions.rb +17 -10
- data/lib/aspera/cli/transfer_agent.rb +44 -44
- data/lib/aspera/cli/transfer_progress.rb +7 -7
- data/lib/aspera/cli/vault_manager.rb +34 -12
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/cli/wizard.rb +17 -20
- data/lib/aspera/colors.rb +3 -3
- data/lib/aspera/command_line_builder.rb +16 -16
- data/lib/aspera/command_line_converter.rb +1 -1
- data/lib/aspera/coverage.rb +1 -2
- data/lib/aspera/data_repository.rb +1 -1
- data/lib/aspera/dot_container.rb +8 -8
- data/lib/aspera/environment.rb +12 -12
- data/lib/aspera/faspex_gw.rb +4 -4
- data/lib/aspera/faspex_postproc.rb +14 -9
- data/lib/aspera/graphql.rb +4 -2
- data/lib/aspera/hash_ext.rb +2 -2
- data/lib/aspera/json_rpc/client.rb +1 -1
- data/lib/aspera/keychain/base.rb +10 -3
- data/lib/aspera/keychain/encrypted_hash.rb +92 -17
- data/lib/aspera/keychain/factory.rb +17 -5
- data/lib/aspera/keychain/hashicorp_vault.rb +1 -1
- data/lib/aspera/keychain/macos_security.rb +23 -25
- data/lib/aspera/keychain/one_password_api.rb +86 -0
- data/lib/aspera/keychain/one_password_base.rb +34 -0
- data/lib/aspera/keychain/one_password_cli.rb +98 -0
- data/lib/aspera/link_header.rb +2 -2
- data/lib/aspera/log.rb +13 -13
- data/lib/aspera/markdown.rb +5 -5
- data/lib/aspera/nagios.rb +8 -8
- data/lib/aspera/node_simulator.rb +33 -27
- data/lib/aspera/oauth/base.rb +4 -5
- data/lib/aspera/oauth/boot.rb +3 -3
- data/lib/aspera/oauth/factory.rb +5 -5
- data/lib/aspera/oauth/jwt.rb +5 -7
- data/lib/aspera/oauth/web.rb +4 -4
- data/lib/aspera/persistency_action_once.rb +4 -4
- data/lib/aspera/persistency_folder.rb +8 -8
- data/lib/aspera/preview/file_types.rb +4 -4
- data/lib/aspera/preview/generator.rb +49 -46
- data/lib/aspera/preview/options.rb +3 -2
- data/lib/aspera/preview/terminal.rb +5 -5
- data/lib/aspera/preview/utils.rb +65 -18
- data/lib/aspera/products/connect.rb +2 -2
- data/lib/aspera/products/desktop.rb +1 -1
- data/lib/aspera/products/other.rb +2 -2
- data/lib/aspera/products/transferd.rb +3 -3
- data/lib/aspera/proxy_auto_config.rb +10 -10
- data/lib/aspera/rest.rb +149 -115
- data/lib/aspera/rest_error_analyzer.rb +3 -3
- data/lib/aspera/rest_list.rb +10 -9
- data/lib/aspera/schema/IBM Aspera Node API-4.4.6.yaml +6232 -0
- data/lib/aspera/schema/IBM Aspera faspio Gateway API-1.0.0.yaml +249 -0
- data/lib/aspera/schema/IBM_Aspera_Shares.yaml +4653 -0
- data/lib/aspera/schema/documentation.rb +17 -11
- data/lib/aspera/schema/reader.rb +78 -4
- data/lib/aspera/schema/registry.rb +26 -7
- data/lib/aspera/secret_hider.rb +5 -5
- data/lib/aspera/ssh.rb +64 -31
- data/lib/aspera/ssl.rb +3 -3
- data/lib/aspera/sync/database.rb +2 -2
- data/lib/aspera/sync/operations.rb +13 -13
- data/lib/aspera/temp_file_manager.rb +24 -4
- data/lib/aspera/transfer/faux_file.rb +2 -2
- data/lib/aspera/transfer/parameters.rb +15 -15
- data/lib/aspera/transfer/resumer.rb +9 -9
- data/lib/aspera/transfer/spec.rb +1 -1
- data/lib/aspera/uri_reader.rb +52 -15
- data/lib/aspera/web_auth.rb +6 -5
- data/lib/aspera/web_server_simple.rb +9 -9
- data/lib/aspera/yaml.rb +4 -4
- data.tar.gz.sig +0 -0
- metadata +10 -4
- metadata.gz.sig +0 -0
- data/lib/aspera/cli/plugins/faspex.rb +0 -576
- data/lib/aspera/transfer/uri.rb +0 -56
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# cspell:ignore snid fnid bidi ssync asyncs rund asnodeadmin mkfile mklink asperabrowser asperabrowserurl watchfolders watchfolderd entsrv
|
|
4
|
+
require 'aspera/schema/registry'
|
|
4
5
|
require 'aspera/cli/plugins/basic_auth'
|
|
5
6
|
require 'aspera/cli/sync_actions'
|
|
6
7
|
require 'aspera/cli/special_values'
|
|
@@ -22,30 +23,6 @@ module Aspera
|
|
|
22
23
|
class Node < BasicAuth
|
|
23
24
|
include SyncActions
|
|
24
25
|
|
|
25
|
-
# Processing of paths in arguments and results
|
|
26
|
-
# Used only by Faspex4 to browse packages
|
|
27
|
-
class NodePathPrefix
|
|
28
|
-
def initialize(path)
|
|
29
|
-
@root = path
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# get next path argument from command line, and add prefix
|
|
33
|
-
def add_to_path(path_arg)
|
|
34
|
-
File.join(@root, path_arg)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# get remaining path arguments from command line, and add prefix
|
|
38
|
-
def add_to_paths!(path_args)
|
|
39
|
-
path_args.map!{ |p| add_to_path(p)}
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def remove_in_object_list!(obj_list)
|
|
43
|
-
obj_list.each do |item|
|
|
44
|
-
item['path'] = item['path'].delete_prefix(@root) if item['path'].start_with?(@root)
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
26
|
application_name 'HSTS Node API'
|
|
50
27
|
|
|
51
28
|
SESSION_TIME_FIELDS = %i[start end].freeze
|
|
@@ -82,31 +59,12 @@ module Aspera
|
|
|
82
59
|
}
|
|
83
60
|
rescue StandardError => e
|
|
84
61
|
error = e
|
|
85
|
-
Log.log.debug{"detect error: #{e}"}
|
|
62
|
+
Log.log.debug { "detect error: #{e}" }
|
|
86
63
|
end
|
|
87
64
|
raise error if error
|
|
88
65
|
return
|
|
89
66
|
end
|
|
90
67
|
|
|
91
|
-
# Called by non-Node plugins (Ats, Cos, Aoc) to declare Node options on their
|
|
92
|
-
# own options object. The DSL registry is walked so descriptions stay in one place.
|
|
93
|
-
def declare_options(options)
|
|
94
|
-
return if options.option_declared?(:root_id)
|
|
95
|
-
command_registry.option_specs.each_value do |spec|
|
|
96
|
-
next if options.option_declared?(spec.name)
|
|
97
|
-
options.declare(
|
|
98
|
-
spec.name,
|
|
99
|
-
description: spec.description,
|
|
100
|
-
short: spec.short,
|
|
101
|
-
allowed: spec.allowed,
|
|
102
|
-
default: spec.default,
|
|
103
|
-
handler: spec.handler,
|
|
104
|
-
schema: spec.schema
|
|
105
|
-
)
|
|
106
|
-
end
|
|
107
|
-
options.parse_options!
|
|
108
|
-
end
|
|
109
|
-
|
|
110
68
|
# Using /files/browse: is it a folder (node and shares)
|
|
111
69
|
def gen3_entry_folder?(entry)
|
|
112
70
|
FOLDER_TYPES.include?(entry['type'])
|
|
@@ -114,7 +72,7 @@ module Aspera
|
|
|
114
72
|
end
|
|
115
73
|
|
|
116
74
|
# DSL option declarations - at class level, picked up by Base#initialize via ancestor chain.
|
|
117
|
-
#
|
|
75
|
+
# Included by other plugins (Ats, Cos, Aoc) via `use_options Node`.
|
|
118
76
|
option :validator, description: 'Identifier of validator (optional for central)'
|
|
119
77
|
option :asperabrowserurl, description: 'URL for simple aspera web ui', default: 'https://asperabrowser.mybluemix.net'
|
|
120
78
|
option :node_api, description: 'Gen4: standard_ports: Use standard FASP ports (true) or get from node API (false). cache: Set to false to force actual file system read',
|
|
@@ -149,37 +107,83 @@ module Aspera
|
|
|
149
107
|
SEARCH_REMOVE_FIELDS = %w[basename permissions].freeze
|
|
150
108
|
|
|
151
109
|
# Actions in execute_command_gen3
|
|
152
|
-
COMMANDS_GEN3 = %i[search space mkdir mklink mkfile rename delete
|
|
153
|
-
|
|
154
|
-
|
|
110
|
+
COMMANDS_GEN3 = %i[search space mkdir mklink mkfile rename delete ls upload download cat sync transport spec]
|
|
111
|
+
|
|
112
|
+
# Shared DSL metadata for Gen3 commands (description:, arguments:, transfer_paths:, aliases:).
|
|
113
|
+
# Consumed by commands_under(:files) in shares.rb and commands_under %i[source node]) in faspex.rb.
|
|
114
|
+
# :sync is excluded (intermediate node with sub-commands, handled separately).
|
|
115
|
+
# action: entries are node-specific and intentionally omitted.
|
|
116
|
+
COMMANDS_GEN3_SPEC = {
|
|
117
|
+
search: {description: 'Search for files', arguments: [{name: :search_root, type: String}]},
|
|
118
|
+
space: {description: 'Show space information', arguments: [{name: :path_list, multiple: true}]},
|
|
119
|
+
mkdir: {description: 'Create a folder (Gen3)', arguments: [{name: :path_list, multiple: true}]},
|
|
120
|
+
mklink: {description: 'Create a symbolic link (Gen3)', arguments: [{name: :target, type: String}, {name: :link_path, type: String}]},
|
|
121
|
+
mkfile: {description: 'Create a file (Gen3)', arguments: [{name: :file_path, type: String}, {name: :contents, mandatory: false, default: nil}]},
|
|
122
|
+
rename: {description: 'Rename a file or folder (Gen3)', arguments: [{name: :path_base, type: String}, {name: :path_src, type: String}, {name: :path_dst, type: String}]},
|
|
123
|
+
delete: {description: 'Delete files or folders (Gen3)', arguments: [{name: :paths, multiple: true}]},
|
|
124
|
+
ls: {description: 'List files (Gen3)', arguments: [{name: :path, type: String}], aliases: [:browse]},
|
|
125
|
+
upload: {description: 'Upload files (Gen3)', transfer_paths: :send},
|
|
126
|
+
download: {description: 'Download files (Gen3)', transfer_paths: :receive},
|
|
127
|
+
cat: {description: 'Show file contents (Gen3)', arguments: [{name: :remote_path, type: String}]},
|
|
128
|
+
transport: {description: 'Show transport parameters'},
|
|
129
|
+
spec: {description: 'Show transfer spec base'},
|
|
130
|
+
api_details: {description: 'Show API details'},
|
|
131
|
+
health: {description: 'Check node health'},
|
|
132
|
+
events: {description: 'List events'},
|
|
133
|
+
info: {description: 'Show node info'},
|
|
134
|
+
slash: {description: 'Show root info'},
|
|
135
|
+
license: {description: 'Show license'},
|
|
136
|
+
access_keys: {description: 'Manage access keys'}
|
|
137
|
+
}.freeze
|
|
138
|
+
|
|
139
|
+
BASE_ACTIONS = (%i[api_details] + COMMANDS_GEN3).freeze
|
|
155
140
|
|
|
156
141
|
SPECIAL_ACTIONS = %i[health events info slash license].freeze
|
|
157
142
|
|
|
158
143
|
# commands for : `execute_simple_common`: actions used commonly when a node is involved
|
|
159
|
-
COMMON_ACTIONS = %i[access_keys]
|
|
144
|
+
COMMON_ACTIONS = (%i[access_keys] + BASE_ACTIONS + SPECIAL_ACTIONS).freeze
|
|
160
145
|
|
|
161
146
|
private_constant :CENTRAL_SOAP_API_TEST, :SEARCH_REMOVE_FIELDS, :BASE_ACTIONS, :SPECIAL_ACTIONS, :COMMON_ACTIONS
|
|
162
147
|
|
|
163
148
|
# used in aoc
|
|
164
|
-
NODE4_READ_ACTIONS = %i[bearer_token_node node_info
|
|
149
|
+
NODE4_READ_ACTIONS = %i[bearer_token_node node_info ls find].freeze
|
|
165
150
|
|
|
166
151
|
# commands for execute_command_gen4
|
|
167
|
-
COMMANDS_GEN4 = %i[mkdir mklink mkfile rename delete upload download sync cat show modify permission thumbnail v3]
|
|
152
|
+
COMMANDS_GEN4 = (%i[mkdir mklink mkfile rename delete upload download sync cat show modify permission thumbnail v3] + NODE4_READ_ACTIONS).freeze
|
|
153
|
+
|
|
154
|
+
# Shared DSL metadata for all Gen4 commands (description:, arguments:, transfer_paths:, aliases:).
|
|
155
|
+
# Consumed by commands_under %i[access_keys do]) in node.rb and by aoc.rb.
|
|
156
|
+
# :sync and :permission are excluded: they are intermediate nodes handled separately.
|
|
157
|
+
SINGLE_PATH_ARG = [{name: :path, type: String}].freeze
|
|
158
|
+
COMMANDS_GEN4_SPEC = {
|
|
159
|
+
mkdir: {description: 'Create folder', arguments: SINGLE_PATH_ARG},
|
|
160
|
+
mklink: {description: 'Create symbolic link', arguments: SINGLE_PATH_ARG},
|
|
161
|
+
mkfile: {description: 'Create file', arguments: [{name: :path, type: String}, {name: :contents, mandatory: false, default: nil}]},
|
|
162
|
+
rename: {description: 'Rename entry', arguments: [{name: :source_path, type: String}, {name: :new_name, type: String}]},
|
|
163
|
+
delete: {description: 'Delete entry', arguments: [{name: :paths, type: String, bulk: true}]},
|
|
164
|
+
upload: {description: 'Upload files', transfer_paths: :send},
|
|
165
|
+
download: {description: 'Download files', transfer_paths: :receive},
|
|
166
|
+
modify: {description: 'Modify file', arguments: [{name: :path, type: String}, {name: :update_value, type: Hash, schema: 'node:components.schemas.files-id-put-request'}]},
|
|
167
|
+
cat: {description: 'Show file contents', arguments: SINGLE_PATH_ARG},
|
|
168
|
+
show: {description: 'Show file info', arguments: SINGLE_PATH_ARG},
|
|
169
|
+
thumbnail: {description: 'Show file thumbnail', arguments: SINGLE_PATH_ARG},
|
|
170
|
+
bearer_token_node: {description: 'Show bearer token for file node', arguments: SINGLE_PATH_ARG},
|
|
171
|
+
node_info: {description: 'Show node info for file', arguments: SINGLE_PATH_ARG},
|
|
172
|
+
ls: {description: 'List files', arguments: SINGLE_PATH_ARG, aliases: [:browse]},
|
|
173
|
+
find: {description: 'Find files', arguments: SINGLE_PATH_ARG + FILTER_ARGS},
|
|
174
|
+
v3: {description: 'Legacy v3 commands on files'}
|
|
175
|
+
}.freeze
|
|
176
|
+
private_constant :SINGLE_PATH_ARG
|
|
168
177
|
|
|
169
178
|
# commands supported in ATS for COS
|
|
170
179
|
COMMANDS_COS = %i[upload download info access_keys api_details transfer].freeze
|
|
171
180
|
COMMANDS_SHARES = (BASE_ACTIONS - %i[search]).freeze
|
|
172
|
-
COMMANDS_FASPEX = COMMON_ACTIONS
|
|
173
|
-
|
|
174
181
|
# `browse` display fields for gen4
|
|
175
182
|
GEN4_LS_FIELDS = %w[name type recursive_size size modified_time access_level].freeze
|
|
176
183
|
|
|
177
184
|
# @param api [Rest] an existing API object for the Node API
|
|
178
|
-
|
|
179
|
-
def initialize(context:, api: nil, prefix_path: nil)
|
|
180
|
-
@node_path_prefix = prefix_path ? NodePathPrefix.new(prefix_path) : nil
|
|
185
|
+
def initialize(context:, api: nil)
|
|
181
186
|
super(context: context, basic_options: api.nil?)
|
|
182
|
-
Node.declare_options(options)
|
|
183
187
|
return if context.only_manual?
|
|
184
188
|
@api_node =
|
|
185
189
|
if !api.nil?
|
|
@@ -207,7 +211,7 @@ module Aspera
|
|
|
207
211
|
# Gen3 API
|
|
208
212
|
# @param path [String] starting path
|
|
209
213
|
def browse_gen3(path)
|
|
210
|
-
folders_to_process =
|
|
214
|
+
folders_to_process = path
|
|
211
215
|
folders_to_process = [folders_to_process]
|
|
212
216
|
query = options.get_option(:query) || {}
|
|
213
217
|
# special parameter: max number of entries in result
|
|
@@ -220,7 +224,7 @@ module Aspera
|
|
|
220
224
|
single_call = query.key?('skip')
|
|
221
225
|
# API default is 100, so use 1000 for default
|
|
222
226
|
query['count'] ||= 1000
|
|
223
|
-
Aspera.assert(!(recursive && single_call), type: Cli::BadArgument){'options `recursive` and `skip` cannot be used together'}
|
|
227
|
+
Aspera.assert(!(recursive && single_call), type: Cli::BadArgument) { 'options `recursive` and `skip` cannot be used together' }
|
|
224
228
|
all_items = []
|
|
225
229
|
until folders_to_process.empty?
|
|
226
230
|
path = folders_to_process.shift
|
|
@@ -231,10 +235,7 @@ module Aspera
|
|
|
231
235
|
# example: send_result={'items'=>[{'file'=>"filename1","permissions"=>[{'name'=>'read'},{'name'=>'write'}]}]}
|
|
232
236
|
response = @api_node.create('files/browse', query)
|
|
233
237
|
# 'file','symbolic_link'
|
|
234
|
-
if !Node.gen3_entry_folder?(response['self']) || only_path
|
|
235
|
-
@node_path_prefix&.remove_in_object_list!([response['self']])
|
|
236
|
-
return Result::SingleObject.new(response['self'])
|
|
237
|
-
end
|
|
238
|
+
return Result::SingleObject.new(response['self']) if !Node.gen3_entry_folder?(response['self']) || only_path
|
|
238
239
|
items = response['items']
|
|
239
240
|
total_count ||= response['total_count']
|
|
240
241
|
all_items.concat(items)
|
|
@@ -242,7 +243,7 @@ module Aspera
|
|
|
242
243
|
formatter.display_item_count(response['item_count'], total_count)
|
|
243
244
|
break
|
|
244
245
|
end
|
|
245
|
-
folders_to_process.concat(items.select{ |i| Node.gen3_entry_folder?(i)}.map{ |i| i['path']}) if recursive
|
|
246
|
+
folders_to_process.concat(items.select { |i| Node.gen3_entry_folder?(i) }.map { |i| i['path'] }) if recursive
|
|
246
247
|
if !max_items.nil? && (all_items.count >= max_items)
|
|
247
248
|
all_items = all_items.slice(0, max_items) if all_items.count > max_items
|
|
248
249
|
break
|
|
@@ -254,7 +255,6 @@ module Aspera
|
|
|
254
255
|
end
|
|
255
256
|
query.delete('skip')
|
|
256
257
|
end
|
|
257
|
-
@node_path_prefix&.remove_in_object_list!(all_items)
|
|
258
258
|
return Result::ObjectList.new(all_items)
|
|
259
259
|
ensure
|
|
260
260
|
RestParameters.instance.spinner_cb.call(action: :success)
|
|
@@ -297,7 +297,7 @@ module Aspera
|
|
|
297
297
|
# @param path [String] plain path or %id:<file_id> selector
|
|
298
298
|
def apifid_from_path(top_file_id, path)
|
|
299
299
|
if (m = Parser.percent_selector(path))
|
|
300
|
-
Aspera.assert_values(m[:field], ['id'], type: BadArgument){'file id'}
|
|
300
|
+
Aspera.assert_values(m[:field], ['id'], type: BadArgument) { 'file id' }
|
|
301
301
|
val = m[:value]
|
|
302
302
|
return Api::NodeFileId.new(@api_node, val.nil? || val.empty? ? top_file_id : val)
|
|
303
303
|
end
|
|
@@ -309,7 +309,7 @@ module Aspera
|
|
|
309
309
|
# (intermediate nodes whose path cannot yet be injected via execute_leaf).
|
|
310
310
|
def apifid_from_next_arg(top_file_id)
|
|
311
311
|
file_path = options.instance_identifier(description: 'path or %id:<id> or %id:') do |attribute, value|
|
|
312
|
-
Aspera.assert_values(attribute, ['id'], type: BadArgument){'file id'}
|
|
312
|
+
Aspera.assert_values(attribute, ['id'], type: BadArgument) { 'file id' }
|
|
313
313
|
return Api::NodeFileId.new(@api_node, value.nil? || value.empty? ? top_file_id : value)
|
|
314
314
|
end
|
|
315
315
|
@api_node.resolve_api_fid(top_file_id, file_path)
|
|
@@ -321,21 +321,30 @@ module Aspera
|
|
|
321
321
|
# @return [Integer] id of the sync
|
|
322
322
|
# @raise [Cli::BadArgument] if no such sync, or not by name
|
|
323
323
|
def async_lookup(field, value)
|
|
324
|
-
Aspera.assert_values(field, ['name'], type: Cli::BadArgument){'search field'}
|
|
324
|
+
Aspera.assert_values(field, ['name'], type: Cli::BadArgument) { 'search field' }
|
|
325
325
|
async_ids = @api_node.read('async/list')['sync_ids']
|
|
326
326
|
summaries = @api_node.create('async/summary', {'syncs' => async_ids})['sync_summaries']
|
|
327
|
-
selected = summaries.find{ |s| s['name'].eql?(value)}
|
|
327
|
+
selected = summaries.find { |s| s['name'].eql?(value) }
|
|
328
328
|
raise Cli::BadIdentifier.new('sync', value, field: field) if selected.nil?
|
|
329
329
|
return selected['snid']
|
|
330
330
|
end
|
|
331
331
|
|
|
332
|
+
# Lookup for access_keys: only supports %id:self selector.
|
|
333
|
+
# @param field [String] must be 'id'
|
|
334
|
+
# @param value [String] must be 'self'
|
|
335
|
+
# @return [String] the resolved access key id
|
|
336
|
+
def lookup_access_key_self_id(field, value, **)
|
|
337
|
+
Aspera.assert(field.eql?('id') && value.eql?('self'), type: BadArgument) { 'only selector: %id:self' }
|
|
338
|
+
@api_node.read('access_keys/self')['id']
|
|
339
|
+
end
|
|
340
|
+
|
|
332
341
|
# Search /asyncs by name
|
|
333
342
|
# @param field [String] name of the field to search
|
|
334
343
|
# @param value [String] value of the field to search
|
|
335
344
|
# @return [Integer] id of the sync
|
|
336
345
|
# @raise [Cli::BadArgument] if no such sync, or not by name
|
|
337
346
|
def ssync_lookup(field, value)
|
|
338
|
-
Aspera.assert_values(field, ['name'], type: Cli::BadArgument){'search field'}
|
|
347
|
+
Aspera.assert_values(field, ['name'], type: Cli::BadArgument) { 'search field' }
|
|
339
348
|
@api_node.read('asyncs')['ids'].each do |id|
|
|
340
349
|
sync_info = @api_node.read("asyncs/#{id}")['configuration']
|
|
341
350
|
# name is unique, so we can return
|
|
@@ -346,106 +355,77 @@ module Aspera
|
|
|
346
355
|
|
|
347
356
|
# --- DSL command declarations ---
|
|
348
357
|
|
|
349
|
-
# Gen3 leaf commands
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
action:
|
|
367
|
-
|
|
368
|
-
command :
|
|
369
|
-
|
|
370
|
-
arguments: [{name: :remote_path, type: String}]
|
|
371
|
-
command :sync, description: 'Synchronize folders (Gen3)'
|
|
372
|
-
commands_under(:sync) do
|
|
358
|
+
# Gen3 leaf commands — metadata from COMMANDS_GEN3_SPEC; action: added where node-specific.
|
|
359
|
+
# :sync is declared separately (intermediate node with sub-commands).
|
|
360
|
+
GEN3_NODE_ACTIONS = {
|
|
361
|
+
ls: ->(path:, **) { browse_gen3(path) },
|
|
362
|
+
transport: ->(**) { Result::SingleObject.new(@api_node.transport_params) },
|
|
363
|
+
spec: ->(**) { Result::SingleObject.new(@api_node.base_spec, fields: Formatter.all_but(Transfer::Spec::SPECIFIC)) },
|
|
364
|
+
api_details: ->(**) { Result::SingleObject.new({base_url: @api_node.base_url}.merge(@api_node.params)) },
|
|
365
|
+
events: ->(**) { Result::ObjectList.new(@api_node.read('events', query_read_delete(schema: Schema::Registry.query_params(Schema::Registry::NODE, 'events'))), fields: ->(f) { !f.start_with?('data') }) },
|
|
366
|
+
info: ->(**) { Result::SingleObject.new(@api_node.read('info')) },
|
|
367
|
+
slash: ->(**) { Result::SingleObject.new(@api_node.read('')) },
|
|
368
|
+
license: ->(**) { Result::SingleObject.new(@api_node.read('license')) }
|
|
369
|
+
}.freeze
|
|
370
|
+
private_constant :GEN3_NODE_ACTIONS
|
|
371
|
+
COMMANDS_GEN3_SPEC.each do |cmd, spec|
|
|
372
|
+
next if cmd.eql?(:sync) # intermediate node with sub-commands
|
|
373
|
+
next if cmd.eql?(:access_keys) # intermediate node declared separately below
|
|
374
|
+
action = GEN3_NODE_ACTIONS[cmd]
|
|
375
|
+
command cmd, **spec, **(action ? {action: action} : {})
|
|
376
|
+
end
|
|
377
|
+
command :sync, description: 'Synchronize folders (Gen3)'
|
|
378
|
+
commands_under :sync do
|
|
373
379
|
Sync::Operations::DIRECTIONS.each do |dir|
|
|
374
|
-
command
|
|
380
|
+
command dir, description: "#{dir.capitalize}-sync (Gen3)", transfer_paths: :send, arguments: SyncActions::PATH_AND_INFO_ARGS
|
|
375
381
|
end
|
|
376
382
|
command :admin, description: 'Manage sync database (admin operations)'
|
|
377
|
-
SyncActions.register_sync_admin_commands(self,
|
|
378
|
-
end
|
|
379
|
-
command :transport, description: 'Show transport parameters',
|
|
380
|
-
action: ->{Result::SingleObject.new(@api_node.transport_params)}
|
|
381
|
-
command :spec, description: 'Show transfer spec base',
|
|
382
|
-
action: ->{Result::SingleObject.new(@api_node.base_spec, fields: Formatter.all_but(Transfer::Spec::SPECIFIC))}
|
|
383
|
-
# Other common leaf commands
|
|
384
|
-
command :api_details, description: 'Show API details',
|
|
385
|
-
action: ->{Result::SingleObject.new({base_url: @api_node.base_url}.merge(@api_node.params))}
|
|
386
|
-
command :health, description: 'Check node health'
|
|
387
|
-
command :events, description: 'List events',
|
|
388
|
-
action: ->{Result::ObjectList.new(@api_node.read('events', query_read_delete), fields: ->(f){!f.start_with?('data')})}
|
|
389
|
-
command :info, description: 'Show node info',
|
|
390
|
-
action: ->{Result::SingleObject.new(@api_node.read('info'))}
|
|
391
|
-
command :slash, description: 'Show root info',
|
|
392
|
-
action: ->{Result::SingleObject.new(@api_node.read(''))}
|
|
393
|
-
command :license, description: 'Show license',
|
|
394
|
-
action: ->{Result::SingleObject.new(@api_node.read('license'))}
|
|
383
|
+
SyncActions.register_sync_admin_commands(self, :admin)
|
|
384
|
+
end
|
|
395
385
|
# access_keys sub-tree
|
|
396
386
|
command :access_keys, description: 'Manage access keys'
|
|
397
|
-
commands_under
|
|
387
|
+
commands_under :access_keys do
|
|
398
388
|
command :do, description: 'Execute Gen4 command via access key',
|
|
399
389
|
arguments: [{name: :access_key_id, type: :identifier}],
|
|
400
390
|
setup: :setup_access_key_do
|
|
401
391
|
command :set_bearer_key, description: 'Set bearer key on access key',
|
|
402
392
|
arguments: [{name: :access_key_id}, {name: :bearer_key_pem, type: String}]
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
commands_under
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
kwargs = {description: "Gen4 #{cmd} command"}
|
|
414
|
-
kwargs[:setup] = :setup_access_key_do_permission if cmd.eql?(:permission)
|
|
415
|
-
kwargs[:arguments] = [{name: :source_path, type: String}, {name: :new_name, type: String}] if cmd.eql?(:rename)
|
|
416
|
-
kwargs[:arguments] = [{name: :paths, type: String, bulk: true}] if cmd.eql?(:delete)
|
|
417
|
-
kwargs[:arguments] = [{name: :path, type: String}, {name: :contents, mandatory: false, default: nil}] if cmd.eql?(:mkfile)
|
|
418
|
-
kwargs[:arguments] = [{name: :path, type: String}, {name: :update_value, type: Hash}] if cmd.eql?(:modify)
|
|
419
|
-
kwargs[:arguments] = [{name: :path, type: String}] if COMMANDS_GEN4_SINGLE_PATH.include?(cmd)
|
|
420
|
-
kwargs[:transfer_paths] = :send if cmd.eql?(:upload)
|
|
421
|
-
kwargs[:transfer_paths] = :receive if cmd.eql?(:download)
|
|
422
|
-
command(cmd, **kwargs)
|
|
393
|
+
crud_commands entity: 'access_keys',
|
|
394
|
+
api: :@api_node,
|
|
395
|
+
|
|
396
|
+
body_component: Schema::Registry::NODE,
|
|
397
|
+
lookup: :lookup_access_key_self_id
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
commands_under %i[access_keys do] do
|
|
401
|
+
COMMANDS_GEN4_SPEC.each do |cmd, spec|
|
|
402
|
+
command cmd, **spec
|
|
423
403
|
end
|
|
424
|
-
command :
|
|
425
|
-
|
|
404
|
+
command :permission, description: 'Manage permissions', setup: :setup_access_key_do_permission
|
|
405
|
+
command :sync, description: 'Synchronize folders'
|
|
406
|
+
commands_under :sync do
|
|
426
407
|
Sync::Operations::DIRECTIONS.each do |dir|
|
|
427
|
-
command
|
|
408
|
+
command dir, description: "#{dir.capitalize}-sync", transfer_paths: :send, arguments: SyncActions::PATH_AND_INFO_ARGS
|
|
428
409
|
end
|
|
429
410
|
command :admin, description: 'Manage sync database (admin operations)'
|
|
430
|
-
SyncActions.register_sync_admin_commands(self,
|
|
411
|
+
SyncActions.register_sync_admin_commands(self, :admin)
|
|
431
412
|
end
|
|
432
413
|
end
|
|
433
|
-
commands_under
|
|
414
|
+
commands_under %i[access_keys do permission] do
|
|
434
415
|
command :list, description: 'List permissions on a file'
|
|
435
416
|
command :show, description: 'Show a permission',
|
|
436
417
|
arguments: [{name: :perm_id, type: :identifier}],
|
|
437
|
-
action: ->(apifid:, perm_id:, **){Result::SingleObject.new(apifid.node_api.read("permissions/#{perm_id}"))}
|
|
418
|
+
action: ->(apifid:, perm_id:, **) { Result::SingleObject.new(apifid.node_api.read("permissions/#{perm_id}")) }
|
|
438
419
|
command :create, description: 'Create a permission',
|
|
439
|
-
arguments: [{name: :data, type: Hash}]
|
|
420
|
+
arguments: [{name: :data, type: Hash, schema: 'node:components.schemas.permissions-post-request'}]
|
|
440
421
|
command :modify, description: 'Modify a permission',
|
|
441
|
-
arguments: [{name: :perm_id, type: :identifier}, {name: :data, type: Hash}]
|
|
442
|
-
command :delete, description: 'Delete
|
|
422
|
+
arguments: [{name: :perm_id, type: :identifier}, {name: :data, type: Hash, schema: 'node:components.schemas.permissions-id-put-request'}]
|
|
423
|
+
command :delete, description: 'Delete permissions',
|
|
443
424
|
arguments: [{name: :perm_id, bulk: true}]
|
|
444
425
|
end
|
|
445
426
|
# async (legacy /async)
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
command :list, description: 'List async sync IDs', action: ->{Result::ValueList.new(@api_node.read('async/list')['sync_ids'])}
|
|
427
|
+
commands_under :async, description: 'synchronization (legacy /async)' do
|
|
428
|
+
command :list, description: 'List async sync IDs', action: -> { Result::ValueList.new(@api_node.read('async/list')['sync_ids']) }
|
|
449
429
|
command :show, description: 'Show async summary',
|
|
450
430
|
arguments: [{name: :async_id, type: :identifier, lookup: :async_lookup}]
|
|
451
431
|
command :delete, description: 'Delete async',
|
|
@@ -458,73 +438,70 @@ module Aspera
|
|
|
458
438
|
arguments: [{name: :async_id, type: :identifier, lookup: :async_lookup}]
|
|
459
439
|
end
|
|
460
440
|
# ssync (/asyncs)
|
|
461
|
-
command :ssync, description: 'Manage sync operations (/asyncs)'
|
|
462
|
-
commands_under
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
command :
|
|
469
|
-
arguments: [{name: :ssync_id, type: :identifier, lookup: :ssync_lookup}],
|
|
470
|
-
action: :action_ssync_delete
|
|
471
|
-
command :start, description: 'Start a sync',
|
|
441
|
+
# command :ssync, description: 'Manage sync operations (/asyncs)'
|
|
442
|
+
commands_under :ssync, description: 'synchronization (/asyncs)' do
|
|
443
|
+
crud_commands entity: 'asyncs',
|
|
444
|
+
api: :@api_node,
|
|
445
|
+
operations: %i[create list show delete],
|
|
446
|
+
items_key: 'ids',
|
|
447
|
+
lookup: :ssync_lookup
|
|
448
|
+
command :start, description: 'Start a sync',
|
|
472
449
|
arguments: [{name: :ssync_id, type: :identifier, lookup: :ssync_lookup}],
|
|
473
450
|
action: :action_ssync_start
|
|
474
|
-
command :stop,
|
|
451
|
+
command :stop, description: 'Stop a sync',
|
|
475
452
|
arguments: [{name: :ssync_id, type: :identifier, lookup: :ssync_lookup}],
|
|
476
453
|
action: :action_ssync_stop
|
|
477
454
|
command :bandwidth, description: 'Show sync bandwidth',
|
|
478
455
|
arguments: [{name: :ssync_id, type: :identifier, lookup: :ssync_lookup}],
|
|
479
|
-
action: ->(ssync_id:, **){Result::SingleObject.new(@api_node.read("asyncs/#{ssync_id}/bandwidth", options.get_option(:query) || {}))}
|
|
480
|
-
command :counters,
|
|
456
|
+
action: ->(ssync_id:, **) { Result::SingleObject.new(@api_node.read("asyncs/#{ssync_id}/bandwidth", options.get_option(:query) || {})) }
|
|
457
|
+
command :counters, description: 'Show sync counters',
|
|
481
458
|
arguments: [{name: :ssync_id, type: :identifier, lookup: :ssync_lookup}],
|
|
482
|
-
action: ->(ssync_id:, **){Result::SingleObject.new(@api_node.read("asyncs/#{ssync_id}/counters", options.get_option(:query) || {}))}
|
|
483
|
-
command :files,
|
|
459
|
+
action: ->(ssync_id:, **) { Result::SingleObject.new(@api_node.read("asyncs/#{ssync_id}/counters", options.get_option(:query) || {})) }
|
|
460
|
+
command :files, description: 'List sync files',
|
|
484
461
|
arguments: [{name: :ssync_id, type: :identifier, lookup: :ssync_lookup}],
|
|
485
|
-
action: ->(ssync_id:, **){Result::SingleObject.new(@api_node.read("asyncs/#{ssync_id}/files", options.get_option(:query) || {}))}
|
|
486
|
-
command :state,
|
|
462
|
+
action: ->(ssync_id:, **) { Result::SingleObject.new(@api_node.read("asyncs/#{ssync_id}/files", options.get_option(:query) || {})) }
|
|
463
|
+
command :state, description: 'Show sync state',
|
|
487
464
|
arguments: [{name: :ssync_id, type: :identifier, lookup: :ssync_lookup}],
|
|
488
|
-
action: ->(ssync_id:, **){Result::SingleObject.new(@api_node.read("asyncs/#{ssync_id}/state"))}
|
|
489
|
-
command :summary,
|
|
465
|
+
action: ->(ssync_id:, **) { Result::SingleObject.new(@api_node.read("asyncs/#{ssync_id}/state")) }
|
|
466
|
+
command :summary, description: 'Show sync summary',
|
|
490
467
|
arguments: [{name: :ssync_id, type: :identifier, lookup: :ssync_lookup}],
|
|
491
|
-
action: ->(ssync_id:, **){Result::SingleObject.new(@api_node.read("asyncs/#{ssync_id}/summary"))}
|
|
468
|
+
action: ->(ssync_id:, **) { Result::SingleObject.new(@api_node.read("asyncs/#{ssync_id}/summary")) }
|
|
492
469
|
end
|
|
493
470
|
# stream
|
|
494
471
|
command :stream, description: 'Manage stream operations'
|
|
495
|
-
commands_under
|
|
496
|
-
command :list, description: 'List streams', action: ->{Result::ObjectList.new(@api_node.read('ops/transfers', query_read_delete), fields: %w[id status])}
|
|
472
|
+
commands_under :stream do
|
|
473
|
+
command :list, description: 'List streams', action: -> { Result::ObjectList.new(@api_node.read('ops/transfers', query_read_delete), fields: %w[id status]) }
|
|
497
474
|
command :create, description: 'Create a stream',
|
|
498
|
-
arguments: [{name: :data, type: Hash}],
|
|
499
|
-
action: ->(data:, **){Result::SingleObject.new(@api_node.create('streams', data))}
|
|
475
|
+
arguments: [{name: :data, type: Hash, schema: 'node:components.schemas.transferPostRequest'}],
|
|
476
|
+
action: ->(data:, **) { Result::SingleObject.new(@api_node.create('streams', data)) }
|
|
500
477
|
command :show, description: 'Show a stream',
|
|
501
478
|
arguments: [{name: :transfer_id, type: :identifier}],
|
|
502
|
-
action: ->(transfer_id:, **){Result::SingleObject.new(@api_node.read("ops/transfers/#{transfer_id}"))}
|
|
479
|
+
action: ->(transfer_id:, **) { Result::SingleObject.new(@api_node.read("ops/transfers/#{transfer_id}")) }
|
|
503
480
|
command :modify, description: 'Modify a stream',
|
|
504
|
-
arguments: [{name: :transfer_id, type: :identifier}, {name: :data, type: Hash}],
|
|
505
|
-
action: ->(data:, transfer_id:, **){Result::SingleObject.new(@api_node.update("streams/#{transfer_id}", data))}
|
|
481
|
+
arguments: [{name: :transfer_id, type: :identifier}, {name: :data, type: Hash, schema: 'node:components.schemas.transferPutRequest'}],
|
|
482
|
+
action: ->(data:, transfer_id:, **) { Result::SingleObject.new(@api_node.update("streams/#{transfer_id}", data)) }
|
|
506
483
|
command :cancel, description: 'Cancel a stream',
|
|
507
484
|
arguments: [{name: :transfer_id, type: :identifier}],
|
|
508
|
-
action: ->(transfer_id:, **){Result::SingleObject.new(@api_node.cancel("streams/#{transfer_id}"))}
|
|
485
|
+
action: ->(transfer_id:, **) { Result::SingleObject.new(@api_node.cancel("streams/#{transfer_id}")) }
|
|
509
486
|
end
|
|
510
487
|
# transfer
|
|
511
488
|
command :transfer, description: 'Manage transfer operations'
|
|
512
|
-
commands_under
|
|
513
|
-
command :list,
|
|
514
|
-
command :cancel,
|
|
489
|
+
commands_under :transfer do
|
|
490
|
+
command :list, description: 'List transfers'
|
|
491
|
+
command :cancel, description: 'Cancel a transfer',
|
|
515
492
|
arguments: [{name: :transfer_id, type: :identifier}]
|
|
516
|
-
command :show,
|
|
493
|
+
command :show, description: 'Show a transfer',
|
|
517
494
|
arguments: [{name: :transfer_id, type: :identifier}],
|
|
518
|
-
action: ->(transfer_id:, **){Result::SingleObject.new(@api_node.read("ops/transfers/#{transfer_id}"))}
|
|
495
|
+
action: ->(transfer_id:, **) { Result::SingleObject.new(@api_node.read("ops/transfers/#{transfer_id}")) }
|
|
519
496
|
command :modify, description: 'Modify a transfer',
|
|
520
|
-
arguments: [{name: :transfer_id, type: :identifier}, {name: :update_value, type: Hash}]
|
|
497
|
+
arguments: [{name: :transfer_id, type: :identifier}, {name: :update_value, type: Hash, schema: 'node:components.schemas.transferPutRequest'}]
|
|
521
498
|
command :bandwidth_average, description: 'Show average bandwidth per period'
|
|
522
499
|
command :sessions, description: 'List transfer sessions'
|
|
523
500
|
end
|
|
524
501
|
# service
|
|
525
502
|
command :service, description: 'Manage services'
|
|
526
|
-
commands_under
|
|
527
|
-
command :list, description: 'List services', action: ->{Result::ObjectList.new(@api_node.read('rund/services')['services'])}
|
|
503
|
+
commands_under :service do
|
|
504
|
+
command :list, description: 'List services', action: -> { Result::ObjectList.new(@api_node.read('rund/services')['services']) }
|
|
528
505
|
command :create, description: 'Create a service',
|
|
529
506
|
arguments: [{name: :creation_data, type: Hash}]
|
|
530
507
|
command :delete, description: 'Delete a service',
|
|
@@ -532,34 +509,34 @@ module Aspera
|
|
|
532
509
|
end
|
|
533
510
|
# watch_folder
|
|
534
511
|
command :watch_folder, description: 'Manage watch folders', setup: :setup_watch_folder
|
|
535
|
-
commands_under
|
|
512
|
+
commands_under :watch_folder do
|
|
536
513
|
command :create, description: 'Create a watch folder',
|
|
537
514
|
arguments: [{name: :data, type: Hash}],
|
|
538
|
-
action: ->(data:, **){Result::Status.new("#{@api_node.create('v3/watchfolders', data)['id']} created")}
|
|
515
|
+
action: ->(data:, **) { Result::Status.new("#{@api_node.create('v3/watchfolders', data)['id']} created") }
|
|
539
516
|
command :list, description: 'List watch folders',
|
|
540
|
-
action: ->{Result::ValueList.new(@api_node.read('v3/watchfolders', query_read_delete)['ids'])}
|
|
517
|
+
action: -> { Result::ValueList.new(@api_node.read('v3/watchfolders', query_read_delete)['ids']) }
|
|
541
518
|
command :show, description: 'Show a watch folder',
|
|
542
|
-
arguments: [{name: :
|
|
543
|
-
action: ->(
|
|
519
|
+
arguments: [{name: :watch_folder_id, type: :identifier}],
|
|
520
|
+
action: ->(watch_folder_id:, **) { Result::SingleObject.new(@api_node.read("v3/watchfolders/#{watch_folder_id}")) }
|
|
544
521
|
command :modify, description: 'Modify a watch folder',
|
|
545
|
-
arguments: [{name: :
|
|
522
|
+
arguments: [{name: :watch_folder_id, type: :identifier}, {name: :data, type: Hash}]
|
|
546
523
|
command :delete, description: 'Delete a watch folder',
|
|
547
|
-
arguments: [{name: :
|
|
524
|
+
arguments: [{name: :watch_folder_id, type: :identifier}]
|
|
548
525
|
command :state, description: 'Show watch folder state',
|
|
549
|
-
arguments: [{name: :
|
|
550
|
-
action: ->(
|
|
526
|
+
arguments: [{name: :watch_folder_id, type: :identifier}],
|
|
527
|
+
action: ->(watch_folder_id:, **) { Result::SingleObject.new(@api_node.read("v3/watchfolders/#{watch_folder_id}/state")) }
|
|
551
528
|
end
|
|
552
529
|
# central
|
|
553
530
|
command :central, description: 'Query Central service'
|
|
554
|
-
commands_under
|
|
531
|
+
commands_under :central do
|
|
555
532
|
command :session, description: 'Query sessions'
|
|
556
533
|
command :file, description: 'Query files'
|
|
557
534
|
end
|
|
558
|
-
commands_under
|
|
535
|
+
commands_under %i[central session] do
|
|
559
536
|
command :list, description: 'List sessions',
|
|
560
537
|
arguments: [{name: :request_data, type: Hash, mandatory: false, default: nil}]
|
|
561
538
|
end
|
|
562
|
-
commands_under
|
|
539
|
+
commands_under %i[central file] do
|
|
563
540
|
command :list, description: 'List file transfers',
|
|
564
541
|
arguments: [{name: :request_data, type: Hash, mandatory: false, default: nil}]
|
|
565
542
|
command :modify, description: 'Modify file transfer validation',
|
|
@@ -567,72 +544,60 @@ module Aspera
|
|
|
567
544
|
end
|
|
568
545
|
# Standalone leaf commands
|
|
569
546
|
command :asperabrowser, description: 'Open Aspera browser'
|
|
570
|
-
command :basic_token, description: 'Generate basic auth token', action: ->{Result::Text.new(Rest.basic_authorization(options.get_option(:username, mandatory: true), options.get_option(:password, mandatory: true)))}
|
|
547
|
+
command :basic_token, description: 'Generate basic auth token', action: -> { Result::Text.new(Rest.basic_authorization(options.get_option(:username, mandatory: true), options.get_option(:password, mandatory: true))) }
|
|
571
548
|
command :bearer_token, description: 'Generate bearer token',
|
|
572
|
-
arguments: [{name: :private_key_pem, type: String}, {name: :user_group_id, type: Hash}]
|
|
549
|
+
arguments: [{name: :private_key_pem, type: String}, {name: :user_group_id, type: Hash, schema: 'opts:components.schemas.NodeBearerTokenOptions'}]
|
|
573
550
|
command :simulator, description: 'Start node simulator',
|
|
574
|
-
arguments: [{name: :parameters, type: Hash, mandatory: false, default: {}}]
|
|
551
|
+
arguments: [{name: :parameters, type: Hash, mandatory: false, default: {}, schema: 'opts:components.schemas.NodeSimulatorOptions'}]
|
|
575
552
|
command :telemetry, description: 'Report telemetry to external system',
|
|
576
|
-
arguments: [{name: :parameters, type: Hash, mandatory: false, default: {}}]
|
|
553
|
+
arguments: [{name: :parameters, type: Hash, mandatory: false, default: {}, schema: 'opts:components.schemas.NodeTelemetryOptions'}]
|
|
577
554
|
|
|
578
555
|
# --- Handler methods (Gen3) ---
|
|
579
556
|
|
|
580
557
|
def action_delete(paths:, **)
|
|
581
558
|
# TODO: add query for recursive
|
|
582
559
|
paths_to_delete = Array(paths)
|
|
583
|
-
@
|
|
584
|
-
resp = @api_node.create('files/delete', {paths: paths_to_delete.map{ |i| {'path' => i.start_with?('/') ? i : "/#{i}"}}})
|
|
560
|
+
resp = @api_node.create('files/delete', {paths: paths_to_delete.map { |i| {'path' => i.start_with?('/') ? i : "/#{i}"} }})
|
|
585
561
|
cli_result_from_paths_response(resp, 'file deleted')
|
|
586
562
|
end
|
|
587
563
|
|
|
588
564
|
def action_search(search_root:, **)
|
|
589
|
-
search_root = @node_path_prefix.nil? ? search_root : @node_path_prefix.add_to_path(search_root)
|
|
590
565
|
parameters = {'path' => search_root}
|
|
591
566
|
other_options = options.get_option(:query)
|
|
592
567
|
parameters.merge!(other_options) unless other_options.nil?
|
|
593
568
|
resp = @api_node.create('files/search', parameters)
|
|
594
569
|
return Result::Empty.new if resp['items'].empty?
|
|
595
|
-
fields = resp['items'].first.keys.reject{ |i| SEARCH_REMOVE_FIELDS.include?(i)}
|
|
570
|
+
fields = resp['items'].first.keys.reject { |i| SEARCH_REMOVE_FIELDS.include?(i) }
|
|
596
571
|
formatter.display_item_count(resp['item_count'], resp['total_count'])
|
|
597
|
-
formatter.display_status("params: #{resp['parameters'].keys.map{ |k| "#{k}:#{resp['parameters'][k]}"}.join(',')}")
|
|
598
|
-
@node_path_prefix&.remove_in_object_list!(resp['items'])
|
|
572
|
+
formatter.display_status("params: #{resp['parameters'].keys.map { |k| "#{k}:#{resp['parameters'][k]}" }.join(',')}")
|
|
599
573
|
Result::ObjectList.new(resp['items'], fields: fields)
|
|
600
574
|
end
|
|
601
575
|
|
|
602
576
|
def action_space(path_list:, **)
|
|
603
577
|
path_list = Array(path_list)
|
|
604
|
-
@
|
|
605
|
-
resp = @api_node.create('space', {'paths' => path_list.map{ |i| {path: i}}})
|
|
606
|
-
@node_path_prefix&.remove_in_object_list!(resp['paths'])
|
|
578
|
+
resp = @api_node.create('space', {'paths' => path_list.map { |i| {path: i} }})
|
|
607
579
|
Result::ObjectList.new(resp['paths'])
|
|
608
580
|
end
|
|
609
581
|
|
|
610
582
|
def action_mkdir(path_list:, **)
|
|
611
583
|
path_list = Array(path_list)
|
|
612
|
-
@
|
|
613
|
-
resp = @api_node.create('files/create', {'paths' => path_list.map{ |i| {type: :directory, path: i}}})
|
|
584
|
+
resp = @api_node.create('files/create', {'paths' => path_list.map { |i| {type: :directory, path: i} }})
|
|
614
585
|
cli_result_from_paths_response(resp, 'folder created')
|
|
615
586
|
end
|
|
616
587
|
|
|
617
588
|
def action_mklink(target:, link_path:, **)
|
|
618
|
-
|
|
619
|
-
one_path = @node_path_prefix.nil? ? link_path : @node_path_prefix.add_to_path(link_path)
|
|
620
|
-
resp = @api_node.create('files/create', {'paths' => [{type: :symbolic_link, path: one_path, target: {path: target}}]})
|
|
589
|
+
resp = @api_node.create('files/create', {'paths' => [{type: :symbolic_link, path: link_path, target: {path: target}}]})
|
|
621
590
|
cli_result_from_paths_response(resp, 'link created')
|
|
622
591
|
end
|
|
623
592
|
|
|
624
593
|
def action_mkfile(file_path:, contents:, **)
|
|
625
|
-
one_path = @node_path_prefix.nil? ? file_path : @node_path_prefix.add_to_path(file_path)
|
|
626
594
|
contents64 = contents.nil? ? '' : Base64.strict_encode64(contents)
|
|
627
|
-
resp = @api_node.create('files/create', {'paths' => [{type: :file, path:
|
|
595
|
+
resp = @api_node.create('files/create', {'paths' => [{type: :file, path: file_path, contents: contents64}]})
|
|
628
596
|
cli_result_from_paths_response(resp, 'file created')
|
|
629
597
|
end
|
|
630
598
|
|
|
631
599
|
def action_rename(path_base:, path_src:, path_dst:, **)
|
|
632
600
|
# TODO: multiple ?
|
|
633
|
-
path_base = @node_path_prefix.nil? ? path_base : @node_path_prefix.add_to_path(path_base)
|
|
634
|
-
path_src = @node_path_prefix.nil? ? path_src : @node_path_prefix.add_to_path(path_src)
|
|
635
|
-
path_dst = @node_path_prefix.nil? ? path_dst : @node_path_prefix.add_to_path(path_dst)
|
|
636
601
|
resp = @api_node.create('files/rename', {'paths' => [{'path' => path_base, 'source' => path_src, 'destination' => path_dst}]})
|
|
637
602
|
cli_result_from_paths_response(resp, 'entry moved')
|
|
638
603
|
end
|
|
@@ -646,14 +611,14 @@ module Aspera
|
|
|
646
611
|
'files/sync_setup',
|
|
647
612
|
{transfer_requests: [{transfer_request: request_transfer_spec}]}
|
|
648
613
|
)['transfer_specs'].first['transfer_spec']
|
|
649
|
-
transfer_spec.delete_if{ |_k, v| v.nil?}
|
|
614
|
+
transfer_spec.delete_if { |_k, v| v.nil? }
|
|
650
615
|
Log.dump(:ts, transfer_spec)
|
|
651
616
|
transfer_spec
|
|
652
617
|
end
|
|
653
618
|
end
|
|
654
619
|
|
|
655
620
|
Sync::Operations::DIRECTIONS.each do |dir|
|
|
656
|
-
define_method(:"action_sync_#{dir}"){
|
|
621
|
+
define_method(:"action_sync_#{dir}") { |path:, sync_info: {}, **| run_sync_transfer(dir, path: path, sync_info: sync_info, &sync_gen3_block) }
|
|
657
622
|
end
|
|
658
623
|
|
|
659
624
|
def action_upload
|
|
@@ -684,7 +649,6 @@ module Aspera
|
|
|
684
649
|
end
|
|
685
650
|
|
|
686
651
|
def action_cat(remote_path:, **)
|
|
687
|
-
remote_path = @node_path_prefix.nil? ? remote_path : @node_path_prefix.add_to_path(remote_path)
|
|
688
652
|
http = @api_node.read("files/#{URI.encode_www_form_component(remote_path)}/contents", ret: :resp)
|
|
689
653
|
Result::Text.new(http.body)
|
|
690
654
|
end
|
|
@@ -727,24 +691,14 @@ module Aspera
|
|
|
727
691
|
Result::Status.new('Updated')
|
|
728
692
|
end
|
|
729
693
|
|
|
730
|
-
def action_watch_folder_modify(data:,
|
|
731
|
-
@api_node.update("v3/watchfolders/#{
|
|
732
|
-
Result::Status.new("#{
|
|
694
|
+
def action_watch_folder_modify(data:, watch_folder_id:, **)
|
|
695
|
+
@api_node.update("v3/watchfolders/#{watch_folder_id}", data)
|
|
696
|
+
Result::Status.new("#{watch_folder_id} updated")
|
|
733
697
|
end
|
|
734
698
|
|
|
735
|
-
def action_watch_folder_delete(
|
|
736
|
-
@api_node.delete("v3/watchfolders/#{
|
|
737
|
-
Result::Status.new("#{
|
|
738
|
-
end
|
|
739
|
-
|
|
740
|
-
# access_keys > CRUD
|
|
741
|
-
Operations::ALL.each do |op|
|
|
742
|
-
define_action_method([:access_keys, op]) do
|
|
743
|
-
entity_execute(api: @api_node, entity: 'access_keys', command: op) do |field, value|
|
|
744
|
-
Aspera.assert(field.eql?('id') && value.eql?('self'), type: BadArgument){'only selector: %id:self'}
|
|
745
|
-
@api_node.read('access_keys/self')['id']
|
|
746
|
-
end
|
|
747
|
-
end
|
|
699
|
+
def action_watch_folder_delete(watch_folder_id:, **)
|
|
700
|
+
@api_node.delete("v3/watchfolders/#{watch_folder_id}")
|
|
701
|
+
Result::Status.new("#{watch_folder_id} deleted")
|
|
748
702
|
end
|
|
749
703
|
|
|
750
704
|
# access_keys > do - setup: resolve access key and root file id
|
|
@@ -756,7 +710,7 @@ module Aspera
|
|
|
756
710
|
ak_info = @api_node.read("access_keys/#{access_key_id}")
|
|
757
711
|
ak_secret = context.secret_finder.lookup(url: @api_node.base_url, username: ak_info['id'])
|
|
758
712
|
if !access_key_id.eql?('self')
|
|
759
|
-
Aspera.assert(ak_secret, type: Cli::MissingArgument){"Please provide secret for #{ak_info['id']} using option: secret or by setting a preset for #{ak_info['id']}@#{@api_node.base_url}."}
|
|
713
|
+
Aspera.assert(ak_secret, type: Cli::MissingArgument) { "Please provide secret for #{ak_info['id']} using option: secret or by setting a preset for #{ak_info['id']}@#{@api_node.base_url}." }
|
|
760
714
|
@api_node.auth_params[:username] = ak_info['id']
|
|
761
715
|
@api_node.auth_params[:password] = ak_secret
|
|
762
716
|
end
|
|
@@ -772,8 +726,8 @@ module Aspera
|
|
|
772
726
|
{apifid: apifid_from_next_arg(@do_root_file_id)}
|
|
773
727
|
end
|
|
774
728
|
|
|
775
|
-
# access_keys > do >
|
|
776
|
-
def
|
|
729
|
+
# access_keys > do > ls
|
|
730
|
+
def action_access_keys_do_ls(path:, do_root_file_id:, **)
|
|
777
731
|
apifid = apifid_from_path(do_root_file_id, path)
|
|
778
732
|
file_info = apifid.node_api.read("files/#{apifid.file_id}", headers: Api::Node.add_cache_control)
|
|
779
733
|
return Result::ObjectList.new([file_info], fields: GEN4_LS_FIELDS) unless file_info['type'].eql?('folder')
|
|
@@ -781,9 +735,9 @@ module Aspera
|
|
|
781
735
|
end
|
|
782
736
|
|
|
783
737
|
# access_keys > do > find
|
|
784
|
-
def action_access_keys_do_find(path:, do_root_file_id:, **)
|
|
738
|
+
def action_access_keys_do_find(path:, filter: nil, do_root_file_id:, **)
|
|
785
739
|
apifid = apifid_from_path(do_root_file_id, path)
|
|
786
|
-
Result::ObjectList.new(@api_node.find_files(apifid.file_id,
|
|
740
|
+
Result::ObjectList.new(@api_node.find_files(apifid.file_id, Base.file_matcher(filter)), fields: ['path'])
|
|
787
741
|
end
|
|
788
742
|
|
|
789
743
|
# access_keys > do > cat
|
|
@@ -820,8 +774,7 @@ module Aspera
|
|
|
820
774
|
|
|
821
775
|
# access_keys > do > delete
|
|
822
776
|
def action_access_keys_do_delete(paths:, do_root_file_id:, **)
|
|
823
|
-
|
|
824
|
-
Result.bulk(paths, is_bulk: is_bulk, command: :delete, id_result: 'path', bfail: options.get_option(:bfail)) do |l_path|
|
|
777
|
+
bulk_result(paths, command: :delete, id_result: 'path') do |l_path|
|
|
825
778
|
apifid = if (m = Parser.percent_selector(l_path))
|
|
826
779
|
Aspera.assert_values(m[:field], ['id'], type: BadIdentifier)
|
|
827
780
|
Api::NodeFileId.new(@api_node, m[:value])
|
|
@@ -843,8 +796,8 @@ module Aspera
|
|
|
843
796
|
end
|
|
844
797
|
|
|
845
798
|
Sync::Operations::DIRECTIONS.each do |dir|
|
|
846
|
-
define_method(:"action_access_keys_do_sync_#{dir}") do |do_root_file_id:, **|
|
|
847
|
-
run_sync_transfer(dir, &sync_gen4_block(do_root_file_id))
|
|
799
|
+
define_method(:"action_access_keys_do_sync_#{dir}") do |path:, sync_info: {}, do_root_file_id:, **|
|
|
800
|
+
run_sync_transfer(dir, path: path, sync_info: sync_info, &sync_gen4_block(do_root_file_id))
|
|
848
801
|
end
|
|
849
802
|
end
|
|
850
803
|
|
|
@@ -884,7 +837,7 @@ module Aspera
|
|
|
884
837
|
when :oauth2
|
|
885
838
|
result[:username] = apifid.node_api.params[:headers][Api::Node::HEADER_X_ASPERA_ACCESS_KEY]
|
|
886
839
|
result[:password] = apifid.node_api.oauth.authorization
|
|
887
|
-
else Aspera.error_unexpected_value(apifid.node_api.auth_params[:type]){'Node API Auth type'}
|
|
840
|
+
else Aspera.error_unexpected_value(apifid.node_api.auth_params[:type]) { 'Node API Auth type' }
|
|
888
841
|
end
|
|
889
842
|
[apifid, result]
|
|
890
843
|
end
|
|
@@ -897,7 +850,7 @@ module Aspera
|
|
|
897
850
|
def action_access_keys_do_bearer_token_node(path:, do_root_file_id:, **)
|
|
898
851
|
apifid, result = gen4_apifid_info(do_root_file_id, path)
|
|
899
852
|
Log.dump(:result, result)
|
|
900
|
-
Aspera.assert(apifid.node_api.auth_params[:type].eql?(:oauth2), type: BadArgument){"Cannot get bearer token if authenticating with secret (#{apifid.node_api.auth_params[:type]})"}
|
|
853
|
+
Aspera.assert(apifid.node_api.auth_params[:type].eql?(:oauth2), type: BadArgument) { "Cannot get bearer token if authenticating with secret (#{apifid.node_api.auth_params[:type]})" }
|
|
901
854
|
Aspera.assert(OAuth::Factory.bearer_auth?(result[:password]), 'Not using bearer token auth')
|
|
902
855
|
Result::Text.new(result[:password])
|
|
903
856
|
end
|
|
@@ -924,8 +877,8 @@ module Aspera
|
|
|
924
877
|
if check_exists
|
|
925
878
|
folder_content = apifid.node_api.read("files/#{apifid.file_id}/files")
|
|
926
879
|
link_name = ".#{new_item}.asp-lnk"
|
|
927
|
-
found = folder_content.find{ |i| i['name'].eql?(new_item) || i['name'].eql?(link_name)}
|
|
928
|
-
Aspera.assert(!found, type: Cli::Error){"A #{found['type']} already exists with name #{new_item}"}
|
|
880
|
+
found = folder_content.find { |i| i['name'].eql?(new_item) || i['name'].eql?(link_name) }
|
|
881
|
+
Aspera.assert(!found, type: Cli::Error) { "A #{found['type']} already exists with name #{new_item}" }
|
|
929
882
|
end
|
|
930
883
|
[apifid, payload]
|
|
931
884
|
end
|
|
@@ -961,9 +914,7 @@ module Aspera
|
|
|
961
914
|
end
|
|
962
915
|
|
|
963
916
|
def action_access_keys_do_permission_delete(perm_id:, apifid:, **)
|
|
964
|
-
|
|
965
|
-
items = perm_id.is_a?(Array) ? perm_id : [perm_id]
|
|
966
|
-
Result.bulk(items, is_bulk: is_bulk, command: :delete, bfail: options.get_option(:bfail)) do |one_id|
|
|
917
|
+
bulk_result(perm_id, command: :delete) do |one_id|
|
|
967
918
|
apifid.node_api.delete("permissions/#{one_id}")
|
|
968
919
|
the_app = apifid.node_api.app_info
|
|
969
920
|
the_app&.api&.permissions_send_event(event_data: {}, app_info: the_app, types: ['permission.deleted'])
|
|
@@ -973,7 +924,7 @@ module Aspera
|
|
|
973
924
|
|
|
974
925
|
def action_access_keys_do_permission_create(data:, apifid:, **)
|
|
975
926
|
create_param = data
|
|
976
|
-
Aspera.assert(!create_param.key?('file_id'), type: Cli::BadArgument){'no file_id'}
|
|
927
|
+
Aspera.assert(!create_param.key?('file_id'), type: Cli::BadArgument) { 'no file_id' }
|
|
977
928
|
create_param['file_id'] = apifid.file_id
|
|
978
929
|
create_param['access_levels'] = Api::Node::ACCESS_LEVELS unless create_param.key?('access_levels')
|
|
979
930
|
the_app = apifid.node_api.app_info
|
|
@@ -1036,7 +987,7 @@ module Aspera
|
|
|
1036
987
|
data: iteration_data,
|
|
1037
988
|
id: IdGenerator.from_list('sync_files', options.get_option(:url, mandatory: true), options.get_option(:username, mandatory: true), async_id)
|
|
1038
989
|
)
|
|
1039
|
-
data.select!{ |l| l['fnid'].to_i > iteration_data.first} unless iteration_data.first.nil?
|
|
990
|
+
data.select! { |l| l['fnid'].to_i > iteration_data.first } unless iteration_data.first.nil?
|
|
1040
991
|
iteration_data[0] = data.last['fnid'].to_i unless data.empty?
|
|
1041
992
|
end
|
|
1042
993
|
return Result::Empty.new if data.empty?
|
|
@@ -1051,15 +1002,6 @@ module Aspera
|
|
|
1051
1002
|
Result::SingleObject.new(resp)
|
|
1052
1003
|
end
|
|
1053
1004
|
|
|
1054
|
-
def action_ssync_delete(ssync_id:, **)
|
|
1055
|
-
is_bulk = options.get_option(:bulk)
|
|
1056
|
-
items = ssync_id.is_a?(Array) ? ssync_id : [ssync_id]
|
|
1057
|
-
Result.bulk(items, is_bulk: is_bulk, command: :delete, bfail: options.get_option(:bfail)) do |one_id|
|
|
1058
|
-
@api_node.delete("asyncs/#{one_id}", query_read_delete)
|
|
1059
|
-
{'id' => one_id}
|
|
1060
|
-
end
|
|
1061
|
-
end
|
|
1062
|
-
|
|
1063
1005
|
def action_ssync_start(ssync_id:, **)
|
|
1064
1006
|
@api_node.call(operation: 'POST', subpath: "asyncs/#{ssync_id}/start", content_type: Mime::TEXT, body: '', ret: :resp).body
|
|
1065
1007
|
Result::Status.new('Done')
|
|
@@ -1072,7 +1014,7 @@ module Aspera
|
|
|
1072
1014
|
|
|
1073
1015
|
# transfer sub-commands
|
|
1074
1016
|
def action_transfer_list
|
|
1075
|
-
transfer_filter = query_read_delete(default: {})
|
|
1017
|
+
transfer_filter = query_read_delete(default: {}, schema: Schema::Registry.query_params(Schema::Registry::NODE, 'ops/transfers'))
|
|
1076
1018
|
iteration_persistency = nil
|
|
1077
1019
|
if options.get_option(:once_only, mandatory: true)
|
|
1078
1020
|
iteration_persistency = PersistencyActionOnce.new(
|
|
@@ -1094,8 +1036,8 @@ module Aspera
|
|
|
1094
1036
|
end
|
|
1095
1037
|
|
|
1096
1038
|
def action_transfer_sessions
|
|
1097
|
-
transfers_data = @api_node.read('ops/transfers', query_read_delete)
|
|
1098
|
-
sessions = transfers_data.flat_map{ |t| t['sessions']}
|
|
1039
|
+
transfers_data = @api_node.read('ops/transfers', query_read_delete(schema: Schema::Registry.query_params(Schema::Registry::NODE, 'ops/transfers')))
|
|
1040
|
+
sessions = transfers_data.flat_map { |t| t['sessions'] }
|
|
1099
1041
|
sessions.each do |session|
|
|
1100
1042
|
SESSION_TIME_FIELDS.each do |what|
|
|
1101
1043
|
session["#{what}_time"] = session["#{what}_time_usec"] ? Time.at(session["#{what}_time_usec"] / 1_000_000.0).utc.iso8601(0) : nil
|
|
@@ -1115,7 +1057,7 @@ module Aspera
|
|
|
1115
1057
|
end
|
|
1116
1058
|
|
|
1117
1059
|
def action_transfer_bandwidth_average
|
|
1118
|
-
transfers_data = @api_node.read('ops/transfers', query_read_delete)
|
|
1060
|
+
transfers_data = @api_node.read('ops/transfers', query_read_delete(schema: Schema::Registry.query_params(Schema::Registry::NODE, 'ops/transfers')))
|
|
1119
1061
|
bandwidth_period = {}
|
|
1120
1062
|
dir_info = %i[avg_kbps sessions].freeze
|
|
1121
1063
|
transfers_data.each do |t|
|
|
@@ -1129,7 +1071,7 @@ module Aspera
|
|
|
1129
1071
|
end_date = all_dates[index + 1]
|
|
1130
1072
|
break if end_date.nil?
|
|
1131
1073
|
period_bandwidth = Transfer::Spec::DIRECTION_ENUM_VALUES.map(&:to_sym).to_h do |dir|
|
|
1132
|
-
[dir, dir_info.to_h{ |k2| [k2, 0]}]
|
|
1074
|
+
[dir, dir_info.to_h { |k2| [k2, 0] }]
|
|
1133
1075
|
end
|
|
1134
1076
|
transfers_data.each do |t|
|
|
1135
1077
|
next if t['avg_rate_kbps'].zero?
|
|
@@ -1138,7 +1080,7 @@ module Aspera
|
|
|
1138
1080
|
info[:avg_kbps] += t['avg_rate_kbps']
|
|
1139
1081
|
info[:sessions] += 1
|
|
1140
1082
|
end
|
|
1141
|
-
next if Transfer::Spec::DIRECTION_ENUM_VALUES.map(&:to_sym).all?{ |dir| period_bandwidth[dir][:sessions].zero?}
|
|
1083
|
+
next if Transfer::Spec::DIRECTION_ENUM_VALUES.map(&:to_sym).all? { |dir| period_bandwidth[dir][:sessions].zero? }
|
|
1142
1084
|
result.push({start: Time.at(start_date / 1_000_000), end: Time.at(end_date / 1_000_000)}.merge(period_bandwidth))
|
|
1143
1085
|
end
|
|
1144
1086
|
Result::ObjectList.new(result)
|
|
@@ -1211,7 +1153,7 @@ module Aspera
|
|
|
1211
1153
|
def action_simulator(parameters: {}, **)
|
|
1212
1154
|
require 'aspera/node_simulator'
|
|
1213
1155
|
parameters = parameters.symbolize_keys
|
|
1214
|
-
uri = URI.parse(parameters.delete(:url){WebServerSimple::DEFAULT_URL})
|
|
1156
|
+
uri = URI.parse(parameters.delete(:url) { WebServerSimple::DEFAULT_URL })
|
|
1215
1157
|
server = WebServerSimple.new(uri, **parameters.slice(*WebServerSimple::PARAMS))
|
|
1216
1158
|
server.mount(uri.path, NodeSimulatorServlet, parameters.except(*WebServerSimple::PARAMS), NodeSimulator.new)
|
|
1217
1159
|
server.start
|
|
@@ -1221,13 +1163,13 @@ module Aspera
|
|
|
1221
1163
|
def action_telemetry(parameters: {}, **)
|
|
1222
1164
|
parameters = parameters.symbolize_keys
|
|
1223
1165
|
%i[url key].each do |psym|
|
|
1224
|
-
Aspera.assert(parameters.key?(psym), type: Cli::BadArgument){"Missing parameter: #{psym}"}
|
|
1166
|
+
Aspera.assert(parameters.key?(psym), type: Cli::BadArgument) { "Missing parameter: #{psym}" }
|
|
1225
1167
|
end
|
|
1226
1168
|
require 'socket'
|
|
1227
1169
|
parameters[:interval] = 10 unless parameters.key?(:interval)
|
|
1228
1170
|
parameters[:hostname] = Socket.gethostname unless parameters.key?(:hostname)
|
|
1229
1171
|
interval = parameters[:interval].to_f
|
|
1230
|
-
Aspera.assert(interval > 0, type: Cli::BadArgument){'Interval must be a positive number in seconds'}
|
|
1172
|
+
Aspera.assert(interval > 0, type: Cli::BadArgument) { 'Interval must be a positive number in seconds' }
|
|
1231
1173
|
otel_api = Rest.new(
|
|
1232
1174
|
base_url: "#{parameters[:url]}/v1",
|
|
1233
1175
|
headers: {
|
|
@@ -1294,16 +1236,19 @@ module Aspera
|
|
|
1294
1236
|
end
|
|
1295
1237
|
end
|
|
1296
1238
|
|
|
1297
|
-
# Dispatch a command that has already been read from the argument stream.
|
|
1298
|
-
# Used when a new Node instance is created
|
|
1299
|
-
#
|
|
1300
|
-
# Re-enters the DSL registry
|
|
1239
|
+
# Dispatch a Gen3 command that has already been read from the argument stream.
|
|
1240
|
+
# Used when a new Node instance is created by an external plugin (shares, faspex, cos, :v3)
|
|
1241
|
+
# and the command symbol was already consumed before the Node was instantiated.
|
|
1242
|
+
# Re-enters the DSL registry so Proc actions and intermediate nodes (sync, access_keys)
|
|
1301
1243
|
# are resolved normally.
|
|
1244
|
+
# Pre-resolved CLI arguments (e.g. path:) can be forwarded via +ctx+ to avoid
|
|
1245
|
+
# re-consuming tokens that were already resolved by the calling plugin's DSL.
|
|
1302
1246
|
# @param command [Symbol] command already consumed from the argument stream
|
|
1247
|
+
# @param ctx [Hash] pre-resolved context (keyword args forwarded to dispatch)
|
|
1303
1248
|
# @return [Object] CLI result
|
|
1304
|
-
def dispatch_v3_command(command)
|
|
1305
|
-
Aspera.assert_values(command, COMMANDS_GEN3 + %i[health events info slash license api_details access_keys transfer]){'v3 command'}
|
|
1306
|
-
dispatch_from_registry([command],
|
|
1249
|
+
def dispatch_v3_command(command, **ctx)
|
|
1250
|
+
Aspera.assert_values(command, COMMANDS_GEN3 + %i[health events info slash license api_details access_keys transfer]) { 'v3 command' }
|
|
1251
|
+
dispatch_from_registry([command], ctx)
|
|
1307
1252
|
end
|
|
1308
1253
|
|
|
1309
1254
|
private
|
|
@@ -1317,21 +1262,20 @@ module Aspera
|
|
|
1317
1262
|
response['paths'].each do |p|
|
|
1318
1263
|
result = success_msg
|
|
1319
1264
|
if p.key?('error')
|
|
1320
|
-
Log.log.error{"#{p['error']['user_message']} : #{p['path']}"}
|
|
1265
|
+
Log.log.error { "#{p['error']['user_message']} : #{p['path']}" }
|
|
1321
1266
|
result = p['error']['user_message']
|
|
1322
1267
|
errors.push([p['path'], p['error']['user_message']])
|
|
1323
1268
|
end
|
|
1324
1269
|
obj_list.push({'path' => p['path'], 'result' => result})
|
|
1325
1270
|
end
|
|
1326
1271
|
# one error make all fail
|
|
1327
|
-
raise errors.map{ |i| "#{i.first}: #{i.last}"}.join(', ') unless errors.empty?
|
|
1272
|
+
raise errors.map { |i| "#{i.first}: #{i.last}" }.join(', ') unless errors.empty?
|
|
1328
1273
|
obj_list
|
|
1329
1274
|
end
|
|
1330
1275
|
|
|
1331
1276
|
# Translates paths results into CLI result, and removes prefix
|
|
1332
1277
|
def cli_result_from_paths_response(response, success_msg)
|
|
1333
1278
|
obj_list = response_to_result(response, success_msg)
|
|
1334
|
-
@node_path_prefix&.remove_in_object_list!(obj_list)
|
|
1335
1279
|
return Result::ObjectList.new(obj_list, fields: %w[path result])
|
|
1336
1280
|
end
|
|
1337
1281
|
end
|