aspera-cli 4.27.1 → 4.27.3
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 +67 -1
- data/bin/ascli +2 -1
- data/docs/README.md +805 -747
- data/lib/aspera/agent/connect.rb +6 -4
- data/lib/aspera/agent/desktop.rb +2 -2
- data/lib/aspera/agent/direct.rb +3 -1
- data/lib/aspera/agent/node.rb +3 -3
- data/lib/aspera/api/alee.rb +1 -1
- data/lib/aspera/api/aoc.rb +14 -12
- data/lib/aspera/api/ats.rb +1 -1
- data/lib/aspera/api/cos_node.rb +2 -2
- data/lib/aspera/api/faspex.rb +9 -7
- data/lib/aspera/api/httpgw.rb +37 -33
- data/lib/aspera/api/node.rb +38 -33
- data/lib/aspera/ascmd.rb +3 -1
- data/lib/aspera/ascp/installation.rb +62 -27
- data/lib/aspera/ascp/management.rb +1 -0
- data/lib/aspera/assert.rb +4 -0
- data/lib/aspera/cli/ascp_actions.rb +20 -41
- data/lib/aspera/cli/async_transfer_store.rb +2 -2
- data/lib/aspera/cli/bootstrapper.rb +11 -15
- data/lib/aspera/cli/command_line.rb +252 -0
- data/lib/aspera/cli/command_registry.rb +149 -33
- data/lib/aspera/cli/command_spec.rb +103 -14
- data/lib/aspera/cli/completion/ascli.bash +12 -0
- data/lib/aspera/cli/completion/ascli.fish +16 -0
- data/lib/aspera/cli/completion/ascli.zsh +19 -0
- data/lib/aspera/cli/context.rb +3 -0
- data/lib/aspera/cli/deprecation.rb +37 -0
- data/lib/aspera/cli/extended_value.rb +2 -0
- data/lib/aspera/cli/formatter.rb +87 -75
- data/lib/aspera/cli/gem_checker.rb +1 -1
- data/lib/aspera/cli/hints.rb +7 -6
- data/lib/aspera/cli/http.rb +21 -21
- data/lib/aspera/cli/info.rb +3 -0
- data/lib/aspera/cli/mcp_tool.rb +47 -83
- data/lib/aspera/cli/option_declarator.rb +33 -42
- data/lib/aspera/cli/option_registry.rb +69 -0
- data/lib/aspera/cli/option_types.rb +103 -0
- data/lib/aspera/cli/option_value.rb +281 -0
- data/lib/aspera/cli/options.schema.yaml +38 -5
- data/lib/aspera/cli/parser.rb +307 -848
- data/lib/aspera/cli/plugins/alee.rb +7 -4
- data/lib/aspera/cli/plugins/aoc.rb +435 -380
- data/lib/aspera/cli/plugins/ats.rb +58 -73
- data/lib/aspera/cli/plugins/base.rb +190 -240
- data/lib/aspera/cli/plugins/basic_auth.rb +2 -10
- data/lib/aspera/cli/plugins/config.rb +244 -178
- data/lib/aspera/cli/plugins/console.rb +102 -38
- data/lib/aspera/cli/plugins/cos.rb +6 -23
- data/lib/aspera/cli/plugins/factory.rb +3 -0
- data/lib/aspera/cli/plugins/faspex5.rb +176 -173
- data/lib/aspera/cli/plugins/faspio.rb +5 -10
- data/lib/aspera/cli/plugins/httpgw.rb +8 -11
- data/lib/aspera/cli/plugins/mcp.rb +20 -55
- data/lib/aspera/cli/plugins/node.rb +277 -311
- data/lib/aspera/cli/plugins/orchestrator.rb +90 -77
- data/lib/aspera/cli/plugins/preview.rb +79 -90
- data/lib/aspera/cli/plugins/server.rb +76 -50
- data/lib/aspera/cli/plugins/shares.rb +68 -116
- data/lib/aspera/cli/preset_actions.rb +17 -10
- data/lib/aspera/cli/preset_manager.rb +12 -2
- data/lib/aspera/cli/prompt.rb +35 -0
- data/lib/aspera/cli/result.rb +13 -18
- data/lib/aspera/cli/runner.rb +31 -54
- data/lib/aspera/cli/special_values.rb +5 -0
- data/lib/aspera/cli/sync_actions.rb +41 -37
- data/lib/aspera/cli/terminal_formatter.rb +9 -3
- data/lib/aspera/cli/transfer_actions.rb +0 -6
- data/lib/aspera/cli/transfer_agent.rb +29 -35
- data/lib/aspera/cli/vault_manager.rb +0 -17
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/cli/wizard.rb +4 -2
- data/lib/aspera/command_line_builder.rb +1 -0
- data/lib/aspera/coverage.rb +1 -0
- data/lib/aspera/environment.rb +7 -1
- data/lib/aspera/faspex_gw.rb +2 -1
- data/lib/aspera/faspex_postproc.rb +1 -0
- data/lib/aspera/graphql.rb +5 -5
- data/lib/aspera/json_rpc/client.rb +5 -5
- data/lib/aspera/keychain/encrypted_hash.rb +1 -1
- data/lib/aspera/keychain/one_password_api.rb +1 -1
- data/lib/aspera/link_header.rb +2 -2
- data/lib/aspera/log.rb +22 -25
- data/lib/aspera/markdown.rb +2 -0
- data/lib/aspera/mime.rb +25 -0
- data/lib/aspera/node_simulator.rb +1 -0
- data/lib/aspera/oauth/base.rb +35 -25
- data/lib/aspera/oauth/factory.rb +1 -0
- data/lib/aspera/oauth/generic.rb +1 -1
- data/lib/aspera/oauth/jwt.rb +1 -1
- data/lib/aspera/oauth/web.rb +9 -8
- data/lib/aspera/preview/file_types.rb +4 -4
- data/lib/aspera/preview/generator.rb +7 -0
- data/lib/aspera/preview/options.rb +4 -4
- data/lib/aspera/preview/terminal.rb +4 -3
- data/lib/aspera/preview/utils.rb +9 -6
- data/lib/aspera/products/connect.rb +1 -1
- data/lib/aspera/rainbow.rb +7 -0
- data/lib/aspera/rest/aspera_errors.rb +60 -0
- data/lib/aspera/rest/call_error.rb +27 -0
- data/lib/aspera/rest/client.rb +514 -0
- data/lib/aspera/rest/error_analyzer.rb +113 -0
- data/lib/aspera/rest/list.rb +143 -0
- data/lib/aspera/rest/parameters.rb +55 -0
- data/lib/aspera/rest/util.rb +176 -0
- data/lib/aspera/rest.rb +7 -621
- data/lib/aspera/schema/IBM Aspera Console-enhanced.yaml +1125 -0
- data/lib/aspera/schema/IBM Aspera on Cloud API-0.2.6-enhanced.yaml +39 -0
- data/lib/aspera/schema/IBM Aspera on Cloud Automation API-1.0.5-enhanced.yaml +2395 -0
- data/lib/aspera/schema/documentation.rb +13 -3
- data/lib/aspera/schema/registry.rb +18 -1
- data/lib/aspera/schema/validator.rb +92 -0
- data/lib/aspera/secret_hider.rb +36 -25
- data/lib/aspera/string_ext.rb +15 -0
- data/lib/aspera/temp_file_manager.rb +6 -5
- data/lib/aspera/transfer/parameters.rb +2 -0
- data/lib/aspera/transfer/spec.rb +1 -0
- data/lib/aspera/transfer/spec.schema.yaml +1 -0
- data/lib/aspera/uri_reader.rb +11 -11
- data/lib/aspera/web_auth/index.html +147 -0
- data/lib/aspera/web_auth/server.rb +81 -0
- data.tar.gz.sig +0 -0
- metadata +39 -7
- metadata.gz.sig +0 -0
- data/lib/aspera/colors.rb +0 -79
- data/lib/aspera/rest_call_error.rb +0 -25
- data/lib/aspera/rest_error_analyzer.rb +0 -111
- data/lib/aspera/rest_errors_aspera.rb +0 -58
- data/lib/aspera/rest_list.rb +0 -136
- data/lib/aspera/web_auth.rb +0 -211
|
@@ -12,7 +12,7 @@ require 'aspera/id_generator'
|
|
|
12
12
|
require 'aspera/api/node'
|
|
13
13
|
require 'aspera/oauth'
|
|
14
14
|
require 'aspera/node_simulator'
|
|
15
|
-
require 'aspera/
|
|
15
|
+
require 'aspera/rest/list'
|
|
16
16
|
require 'aspera/assert'
|
|
17
17
|
require 'base64'
|
|
18
18
|
require 'zlib'
|
|
@@ -47,7 +47,7 @@ module Aspera
|
|
|
47
47
|
error = nil
|
|
48
48
|
urls.each do |base_url|
|
|
49
49
|
next unless base_url.match?(%r{^https?://})
|
|
50
|
-
api = Rest.new(base_url: base_url)
|
|
50
|
+
api = Rest::Client.new(base_url: base_url)
|
|
51
51
|
test_endpoint = 'ping'
|
|
52
52
|
http = api.read(test_endpoint, ret: :resp)
|
|
53
53
|
next unless http.body.eql?('')
|
|
@@ -76,9 +76,9 @@ module Aspera
|
|
|
76
76
|
option :validator, description: 'Identifier of validator (optional for central)'
|
|
77
77
|
option :asperabrowserurl, description: 'URL for simple aspera web ui', default: 'https://asperabrowser.mybluemix.net'
|
|
78
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',
|
|
79
|
-
allowed: Hash,
|
|
79
|
+
allowed: Hash, on_set: Api::Node.method(:api_options=)
|
|
80
80
|
option :root_id, description: 'Gen4: File id of top folder when using access key (override AK root id)'
|
|
81
|
-
option :dynamic_key, description: 'Private key PEM to use for dynamic key auth',
|
|
81
|
+
option :dynamic_key, description: 'Private key PEM to use for dynamic key auth', on_set: Api::Node.method(:use_dynamic_key=)
|
|
82
82
|
|
|
83
83
|
# @param wizard [Wizard] The wizard object
|
|
84
84
|
# @param app_url [String] Tested URL
|
|
@@ -106,25 +106,21 @@ module Aspera
|
|
|
106
106
|
# Fields removed in result of search
|
|
107
107
|
SEARCH_REMOVE_FIELDS = %w[basename permissions].freeze
|
|
108
108
|
|
|
109
|
-
#
|
|
110
|
-
|
|
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.
|
|
109
|
+
# DSL metadata for Gen3 root commands (description:, arguments:, transfer_paths:, aliases:).
|
|
110
|
+
# :access_keys is skipped (intermediate node declared separately), :sync is declared separately.
|
|
111
|
+
# action: entries are in GEN3_NODE_ACTIONS, or implicit.
|
|
116
112
|
COMMANDS_GEN3_SPEC = {
|
|
117
|
-
search: {description: 'Search for files', arguments: [{name: :
|
|
118
|
-
space: {description: 'Show space information', arguments: [{name: :
|
|
119
|
-
mkdir: {description: 'Create a folder (Gen3)', arguments: [{name: :
|
|
120
|
-
mklink: {description: 'Create a symbolic link (Gen3)', arguments: [{name: :target
|
|
121
|
-
mkfile: {description: 'Create a file (Gen3)', arguments: [{name: :
|
|
122
|
-
rename: {description: 'Rename a file or folder (Gen3)', arguments: [{name: :
|
|
113
|
+
search: {description: 'Search for files', arguments: [{name: :path}]},
|
|
114
|
+
space: {description: 'Show space information', arguments: [{name: :paths, multiple: true}]},
|
|
115
|
+
mkdir: {description: 'Create a folder (Gen3)', arguments: [{name: :paths, multiple: true}]},
|
|
116
|
+
mklink: {description: 'Create a symbolic link (Gen3)', arguments: [{name: :target}, {name: :link_path}]},
|
|
117
|
+
mkfile: {description: 'Create a file (Gen3)', arguments: [{name: :path}, {name: :contents, mandatory: false, default: nil}]},
|
|
118
|
+
rename: {description: 'Rename a file or folder (Gen3)', arguments: [{name: :folder}, {name: :source}, {name: :destination}]},
|
|
123
119
|
delete: {description: 'Delete files or folders (Gen3)', arguments: [{name: :paths, multiple: true}]},
|
|
124
|
-
ls: {description: 'List files (Gen3)', arguments: [{name: :path
|
|
120
|
+
ls: {description: 'List files (Gen3)', arguments: [{name: :path}], aliases: [:browse]},
|
|
125
121
|
upload: {description: 'Upload files (Gen3)', transfer_paths: :send},
|
|
126
122
|
download: {description: 'Download files (Gen3)', transfer_paths: :receive},
|
|
127
|
-
cat: {description: 'Show file contents (Gen3)', arguments: [{name: :
|
|
123
|
+
cat: {description: 'Show file contents (Gen3)', arguments: [{name: :path}]},
|
|
128
124
|
transport: {description: 'Show transport parameters'},
|
|
129
125
|
spec: {description: 'Show transfer spec base'},
|
|
130
126
|
api_details: {description: 'Show API details'},
|
|
@@ -136,60 +132,52 @@ module Aspera
|
|
|
136
132
|
access_keys: {description: 'Manage access keys'}
|
|
137
133
|
}.freeze
|
|
138
134
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
SPECIAL_ACTIONS = %i[health events info slash license].freeze
|
|
142
|
-
|
|
143
|
-
# commands for : `execute_simple_common`: actions used commonly when a node is involved
|
|
144
|
-
COMMON_ACTIONS = (%i[access_keys] + BASE_ACTIONS + SPECIAL_ACTIONS).freeze
|
|
145
|
-
|
|
146
|
-
private_constant :CENTRAL_SOAP_API_TEST, :SEARCH_REMOVE_FIELDS, :BASE_ACTIONS, :SPECIAL_ACTIONS, :COMMON_ACTIONS
|
|
135
|
+
private_constant :CENTRAL_SOAP_API_TEST, :SEARCH_REMOVE_FIELDS
|
|
147
136
|
|
|
148
|
-
#
|
|
137
|
+
# Gen4 read commands also exposed on AoC packages (`aoc packages ls <id>`)
|
|
149
138
|
NODE4_READ_ACTIONS = %i[bearer_token_node node_info ls find].freeze
|
|
150
139
|
|
|
151
|
-
#
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
|
140
|
+
# DSL metadata for Gen4 commands under `access_keys do` (description:, arguments:, transfer_paths:, aliases:).
|
|
141
|
+
# Other plugins expose this sub-tree with `mount:` (aoc, ats).
|
|
142
|
+
# :sync, :permission and :v3 are excluded: they are intermediate nodes declared separately.
|
|
143
|
+
SINGLE_PATH_ARG = [{name: :path}].freeze
|
|
158
144
|
COMMANDS_GEN4_SPEC = {
|
|
159
145
|
mkdir: {description: 'Create folder', arguments: SINGLE_PATH_ARG},
|
|
160
146
|
mklink: {description: 'Create symbolic link', arguments: SINGLE_PATH_ARG},
|
|
161
|
-
mkfile: {description: 'Create file', arguments: [{name: :path
|
|
162
|
-
rename: {description: 'Rename entry', arguments: [{name: :source_path
|
|
163
|
-
delete: {description: 'Delete entry', arguments: [{name: :
|
|
147
|
+
mkfile: {description: 'Create file', arguments: [{name: :path}, {name: :contents, mandatory: false, default: nil}]},
|
|
148
|
+
rename: {description: 'Rename entry', arguments: [{name: :source_path}, {name: :new_name}]},
|
|
149
|
+
delete: {description: 'Delete entry', arguments: [{name: :path, bulk: true}]},
|
|
164
150
|
upload: {description: 'Upload files', transfer_paths: :send},
|
|
165
151
|
download: {description: 'Download files', transfer_paths: :receive},
|
|
166
|
-
modify: {description: 'Modify file', arguments: [{name: :path
|
|
152
|
+
modify: {description: 'Modify file', arguments: [{name: :path}, {name: :file, type: Hash, schema: 'node:components.schemas.files-id-put-request'}]},
|
|
167
153
|
cat: {description: 'Show file contents', arguments: SINGLE_PATH_ARG},
|
|
168
154
|
show: {description: 'Show file info', arguments: SINGLE_PATH_ARG},
|
|
169
155
|
thumbnail: {description: 'Show file thumbnail', arguments: SINGLE_PATH_ARG},
|
|
170
156
|
bearer_token_node: {description: 'Show bearer token for file node', arguments: SINGLE_PATH_ARG},
|
|
171
157
|
node_info: {description: 'Show node info for file', arguments: SINGLE_PATH_ARG},
|
|
172
158
|
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'}
|
|
159
|
+
find: {description: 'Find files', arguments: SINGLE_PATH_ARG + FILTER_ARGS}
|
|
175
160
|
}.freeze
|
|
176
161
|
private_constant :SINGLE_PATH_ARG
|
|
177
162
|
|
|
178
|
-
# commands
|
|
163
|
+
# Root commands exposed by `cos node` and `shares files` (mount: only:)
|
|
179
164
|
COMMANDS_COS = %i[upload download info access_keys api_details transfer].freeze
|
|
180
|
-
COMMANDS_SHARES =
|
|
165
|
+
COMMANDS_SHARES = %i[api_details space mkdir mklink mkfile rename delete ls upload download cat sync transport spec].freeze
|
|
181
166
|
# `browse` display fields for gen4
|
|
182
167
|
GEN4_LS_FIELDS = %w[name type recursive_size size modified_time access_level].freeze
|
|
183
168
|
|
|
184
|
-
# @param api [Rest] an existing API object for the Node API
|
|
169
|
+
# @param api [Rest::Client] an existing API object for the Node API
|
|
185
170
|
def initialize(context:, api: nil)
|
|
186
|
-
super(context: context
|
|
187
|
-
|
|
188
|
-
@api_node =
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
171
|
+
super(context: context)
|
|
172
|
+
# Api::Node or Rest::Client (Shares), when provided by the host plugin
|
|
173
|
+
@api_node = api
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Node API: provided by the host plugin, or built from CLI options on first use.
|
|
177
|
+
# @return [Api::Node, Rest::Client]
|
|
178
|
+
def api_node
|
|
179
|
+
@api_node ||=
|
|
180
|
+
if OAuth::Factory.bearer_auth?(options.get_option(:password, mandatory: true))
|
|
193
181
|
# info is provided like node_info of aoc
|
|
194
182
|
Api::Node.new(
|
|
195
183
|
base_url: options.get_option(:url, mandatory: true),
|
|
@@ -213,9 +201,10 @@ module Aspera
|
|
|
213
201
|
def browse_gen3(path)
|
|
214
202
|
folders_to_process = path
|
|
215
203
|
folders_to_process = [folders_to_process]
|
|
204
|
+
# not a URL query: merged into the POST body of files/browse
|
|
216
205
|
query = options.get_option(:query) || {}
|
|
217
206
|
# special parameter: max number of entries in result
|
|
218
|
-
max_items = query.delete(
|
|
207
|
+
max_items = query.delete(Rest::List::MAX_ITEMS)
|
|
219
208
|
# special parameter: recursive browsing
|
|
220
209
|
recursive = query.delete('recursive')
|
|
221
210
|
# special parameter: only return one entry for the path, even if folder
|
|
@@ -233,7 +222,7 @@ module Aspera
|
|
|
233
222
|
total_count = nil
|
|
234
223
|
loop do
|
|
235
224
|
# example: send_result={'items'=>[{'file'=>"filename1","permissions"=>[{'name'=>'read'},{'name'=>'write'}]}]}
|
|
236
|
-
response =
|
|
225
|
+
response = api_node.create('files/browse', query)
|
|
237
226
|
# 'file','symbolic_link'
|
|
238
227
|
return Result::SingleObject.new(response['self']) if !Node.gen3_entry_folder?(response['self']) || only_path
|
|
239
228
|
items = response['items']
|
|
@@ -251,13 +240,13 @@ module Aspera
|
|
|
251
240
|
break if all_items.count >= total_count
|
|
252
241
|
offset += items.count
|
|
253
242
|
query['skip'] = offset
|
|
254
|
-
|
|
243
|
+
Rest::Parameters.instance.spinner_cb.call(all_items.count)
|
|
255
244
|
end
|
|
256
245
|
query.delete('skip')
|
|
257
246
|
end
|
|
258
247
|
return Result::ObjectList.new(all_items)
|
|
259
248
|
ensure
|
|
260
|
-
|
|
249
|
+
Rest::Parameters.instance.spinner_cb.call(action: :success)
|
|
261
250
|
end
|
|
262
251
|
|
|
263
252
|
# Create async transfer spec request from direction and folders
|
|
@@ -299,20 +288,9 @@ module Aspera
|
|
|
299
288
|
if (m = Parser.percent_selector(path))
|
|
300
289
|
Aspera.assert_values(m[:field], ['id'], type: BadArgument) { 'file id' }
|
|
301
290
|
val = m[:value]
|
|
302
|
-
return Api::NodeFileId.new(
|
|
303
|
-
end
|
|
304
|
-
@api_node.resolve_api_fid(top_file_id, path)
|
|
305
|
-
end
|
|
306
|
-
|
|
307
|
-
# Legacy helper: resolve a NodeFileId by reading path from the CLI argument stream.
|
|
308
|
-
# Used only by setup_access_key_do_permission and action_access_keys_do_permission
|
|
309
|
-
# (intermediate nodes whose path cannot yet be injected via execute_leaf).
|
|
310
|
-
def apifid_from_next_arg(top_file_id)
|
|
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' }
|
|
313
|
-
return Api::NodeFileId.new(@api_node, value.nil? || value.empty? ? top_file_id : value)
|
|
291
|
+
return Api::NodeFileId.new(api_node, val.nil? || val.empty? ? top_file_id : val)
|
|
314
292
|
end
|
|
315
|
-
|
|
293
|
+
api_node.resolve_api_fid(top_file_id, path)
|
|
316
294
|
end
|
|
317
295
|
|
|
318
296
|
# Search /async by name
|
|
@@ -322,8 +300,8 @@ module Aspera
|
|
|
322
300
|
# @raise [Cli::BadArgument] if no such sync, or not by name
|
|
323
301
|
def async_lookup(field, value)
|
|
324
302
|
Aspera.assert_values(field, ['name'], type: Cli::BadArgument) { 'search field' }
|
|
325
|
-
async_ids =
|
|
326
|
-
summaries =
|
|
303
|
+
async_ids = api_node.read('async/list')['sync_ids']
|
|
304
|
+
summaries = api_node.create('async/summary', {'syncs' => async_ids})['sync_summaries']
|
|
327
305
|
selected = summaries.find { |s| s['name'].eql?(value) }
|
|
328
306
|
raise Cli::BadIdentifier.new('sync', value, field: field) if selected.nil?
|
|
329
307
|
return selected['snid']
|
|
@@ -335,7 +313,7 @@ module Aspera
|
|
|
335
313
|
# @return [String] the resolved access key id
|
|
336
314
|
def lookup_access_key_self_id(field, value, **)
|
|
337
315
|
Aspera.assert(field.eql?('id') && value.eql?('self'), type: BadArgument) { 'only selector: %id:self' }
|
|
338
|
-
|
|
316
|
+
api_node.read('access_keys/self')['id']
|
|
339
317
|
end
|
|
340
318
|
|
|
341
319
|
# Search /asyncs by name
|
|
@@ -345,8 +323,8 @@ module Aspera
|
|
|
345
323
|
# @raise [Cli::BadArgument] if no such sync, or not by name
|
|
346
324
|
def ssync_lookup(field, value)
|
|
347
325
|
Aspera.assert_values(field, ['name'], type: Cli::BadArgument) { 'search field' }
|
|
348
|
-
|
|
349
|
-
sync_info =
|
|
326
|
+
api_node.read('asyncs')['ids'].each do |id|
|
|
327
|
+
sync_info = api_node.read("asyncs/#{id}")['configuration']
|
|
350
328
|
# name is unique, so we can return
|
|
351
329
|
return id if sync_info[field].eql?(value)
|
|
352
330
|
end
|
|
@@ -359,17 +337,16 @@ module Aspera
|
|
|
359
337
|
# :sync is declared separately (intermediate node with sub-commands).
|
|
360
338
|
GEN3_NODE_ACTIONS = {
|
|
361
339
|
ls: ->(path:, **) { browse_gen3(path) },
|
|
362
|
-
transport: ->(**) { Result::SingleObject.new(
|
|
363
|
-
spec: ->(**) { Result::SingleObject.new(
|
|
364
|
-
api_details: ->(**) { Result::SingleObject.new({base_url:
|
|
365
|
-
events: ->(**) { Result::ObjectList.new(
|
|
366
|
-
info: ->(**) { Result::SingleObject.new(
|
|
367
|
-
slash: ->(**) { Result::SingleObject.new(
|
|
368
|
-
license: ->(**) { Result::SingleObject.new(
|
|
340
|
+
transport: ->(**) { Result::SingleObject.new(api_node.transport_params) },
|
|
341
|
+
spec: ->(**) { Result::SingleObject.new(api_node.base_spec, fields: Formatter.all_but(*Transfer::Spec::SPECIFIC)) },
|
|
342
|
+
api_details: ->(**) { Result::SingleObject.new({base_url: api_node.base_url}.merge(api_node.params)) },
|
|
343
|
+
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') }) },
|
|
344
|
+
info: ->(**) { Result::SingleObject.new(api_node.read('info')) },
|
|
345
|
+
slash: ->(**) { Result::SingleObject.new(api_node.read('')) },
|
|
346
|
+
license: ->(**) { Result::SingleObject.new(api_node.read('license')) }
|
|
369
347
|
}.freeze
|
|
370
348
|
private_constant :GEN3_NODE_ACTIONS
|
|
371
349
|
COMMANDS_GEN3_SPEC.each do |cmd, spec|
|
|
372
|
-
next if cmd.eql?(:sync) # intermediate node with sub-commands
|
|
373
350
|
next if cmd.eql?(:access_keys) # intermediate node declared separately below
|
|
374
351
|
action = GEN3_NODE_ACTIONS[cmd]
|
|
375
352
|
command cmd, **spec, **(action ? {action: action} : {})
|
|
@@ -389,9 +366,9 @@ module Aspera
|
|
|
389
366
|
arguments: [{name: :access_key_id, type: :identifier}],
|
|
390
367
|
setup: :setup_access_key_do
|
|
391
368
|
command :set_bearer_key, description: 'Set bearer key on access key',
|
|
392
|
-
arguments: [{name: :access_key_id}, {name: :bearer_key_pem
|
|
369
|
+
arguments: [{name: :access_key_id, type: :identifier}, {name: :bearer_key_pem}]
|
|
393
370
|
crud_commands entity: 'access_keys',
|
|
394
|
-
api:
|
|
371
|
+
api: :api_node,
|
|
395
372
|
|
|
396
373
|
body_component: Schema::Registry::NODE,
|
|
397
374
|
lookup: :lookup_access_key_self_id
|
|
@@ -401,7 +378,10 @@ module Aspera
|
|
|
401
378
|
COMMANDS_GEN4_SPEC.each do |cmd, spec|
|
|
402
379
|
command cmd, **spec
|
|
403
380
|
end
|
|
404
|
-
command :
|
|
381
|
+
command :v3, description: 'Legacy v3 commands on files', mount: {plugin: self, instance: :v3_node_plugin}
|
|
382
|
+
command :permission, description: 'Manage permissions',
|
|
383
|
+
arguments: [{name: :path, description: 'Path, or %id:<file id>, or %id: for root'}],
|
|
384
|
+
setup: :setup_access_key_do_permission
|
|
405
385
|
command :sync, description: 'Synchronize folders'
|
|
406
386
|
commands_under :sync do
|
|
407
387
|
Sync::Operations::DIRECTIONS.each do |dir|
|
|
@@ -414,22 +394,34 @@ module Aspera
|
|
|
414
394
|
commands_under %i[access_keys do permission] do
|
|
415
395
|
command :list, description: 'List permissions on a file'
|
|
416
396
|
command :show, description: 'Show a permission',
|
|
417
|
-
arguments: [{name: :
|
|
418
|
-
action: ->(apifid:,
|
|
397
|
+
arguments: [{name: :permission_id, type: :identifier}],
|
|
398
|
+
action: ->(apifid:, permission_id:, **) { Result::SingleObject.new(apifid.node_api.read("permissions/#{permission_id}")) }
|
|
419
399
|
command :create, description: 'Create a permission',
|
|
420
|
-
arguments: [{name: :
|
|
421
|
-
command
|
|
422
|
-
|
|
400
|
+
arguments: [{name: :permission, type: Hash, schema: 'node:components.schemas.permissions-post-request'}]
|
|
401
|
+
command(
|
|
402
|
+
:modify, description: 'Modify a permission',
|
|
403
|
+
arguments: [{name: :permission_id, type: :identifier}, {name: :permission, type: Hash, schema: 'node:components.schemas.permissions-id-put-request'}],
|
|
404
|
+
action: lambda do |permission:, apifid:, permission_id:, **|
|
|
405
|
+
apifid.node_api.update("permissions/#{permission_id}", permission)
|
|
406
|
+
Result::Status.new('Updated')
|
|
407
|
+
end
|
|
408
|
+
)
|
|
423
409
|
command :delete, description: 'Delete permissions',
|
|
424
|
-
arguments: [{name: :
|
|
410
|
+
arguments: [{name: :permission_id, type: :identifier, bulk: true}]
|
|
425
411
|
end
|
|
426
412
|
# async (legacy /async)
|
|
427
|
-
commands_under :async, description: '
|
|
428
|
-
command :list, description: 'List async sync IDs', action: -> { Result::ValueList.new(
|
|
413
|
+
commands_under :async, description: 'Manage legacy synchronizations (/async)' do
|
|
414
|
+
command :list, description: 'List async sync IDs', action: ->(**) { Result::ValueList.new(api_node.read('async/list')['sync_ids']) }
|
|
429
415
|
command :show, description: 'Show async summary',
|
|
430
416
|
arguments: [{name: :async_id, type: :identifier, lookup: :async_lookup}]
|
|
431
|
-
command
|
|
432
|
-
|
|
417
|
+
command(
|
|
418
|
+
:delete, description: 'Delete async',
|
|
419
|
+
arguments: [{name: :async_id, type: :identifier, lookup: :async_lookup}],
|
|
420
|
+
action: lambda do |async_id:, **|
|
|
421
|
+
async_ids = async_id.eql?(SpecialValues::ALL) ? api_node.read('async/list')['sync_ids'] : [async_id]
|
|
422
|
+
Result::SingleObject.new(api_node.create('async/delete', {'syncs' => async_ids}))
|
|
423
|
+
end
|
|
424
|
+
)
|
|
433
425
|
command :bandwidth, description: 'Show async bandwidth',
|
|
434
426
|
arguments: [{name: :async_id, type: :identifier, lookup: :async_lookup}]
|
|
435
427
|
command :files, description: 'List async files',
|
|
@@ -438,93 +430,138 @@ module Aspera
|
|
|
438
430
|
arguments: [{name: :async_id, type: :identifier, lookup: :async_lookup}]
|
|
439
431
|
end
|
|
440
432
|
# ssync (/asyncs)
|
|
441
|
-
|
|
442
|
-
commands_under :ssync, description: 'synchronization (/asyncs)' do
|
|
433
|
+
commands_under :ssync, description: 'Manage synchronizations (/asyncs)' do
|
|
443
434
|
crud_commands entity: 'asyncs',
|
|
444
|
-
|
|
435
|
+
name: 'sync session',
|
|
436
|
+
id_name: :ssync_id,
|
|
437
|
+
api: :api_node,
|
|
445
438
|
operations: %i[create list show delete],
|
|
446
439
|
items_key: 'ids',
|
|
447
440
|
lookup: :ssync_lookup
|
|
448
|
-
command
|
|
449
|
-
arguments: [{name: :ssync_id, type: :identifier, lookup: :ssync_lookup}],
|
|
450
|
-
action:
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
441
|
+
command(
|
|
442
|
+
:start, description: 'Start a sync', arguments: [{name: :ssync_id, type: :identifier, lookup: :ssync_lookup}],
|
|
443
|
+
action: lambda do |ssync_id:, **|
|
|
444
|
+
api_node.call(operation: 'POST', subpath: "asyncs/#{ssync_id}/start", content_type: Mime::TEXT, body: '', ret: :resp).body
|
|
445
|
+
Result::Status.new('Done')
|
|
446
|
+
end
|
|
447
|
+
)
|
|
448
|
+
command(
|
|
449
|
+
:stop, description: 'Stop a sync', arguments: [{name: :ssync_id, type: :identifier, lookup: :ssync_lookup}],
|
|
450
|
+
action: lambda do |ssync_id:, **|
|
|
451
|
+
api_node.call(operation: 'POST', subpath: "asyncs/#{ssync_id}/stop", content_type: Mime::TEXT, body: '', ret: :resp).body
|
|
452
|
+
Result::Status.new('Done')
|
|
453
|
+
end
|
|
454
|
+
)
|
|
454
455
|
command :bandwidth, description: 'Show sync bandwidth',
|
|
455
456
|
arguments: [{name: :ssync_id, type: :identifier, lookup: :ssync_lookup}],
|
|
456
|
-
action: ->(ssync_id:, **) { Result::SingleObject.new(
|
|
457
|
+
action: ->(ssync_id:, **) { Result::SingleObject.new(api_node.read("asyncs/#{ssync_id}/bandwidth", query_read_delete(default: {}))) }
|
|
457
458
|
command :counters, description: 'Show sync counters',
|
|
458
459
|
arguments: [{name: :ssync_id, type: :identifier, lookup: :ssync_lookup}],
|
|
459
|
-
action: ->(ssync_id:, **) { Result::SingleObject.new(
|
|
460
|
+
action: ->(ssync_id:, **) { Result::SingleObject.new(api_node.read("asyncs/#{ssync_id}/counters", query_read_delete(default: {}))) }
|
|
460
461
|
command :files, description: 'List sync files',
|
|
461
462
|
arguments: [{name: :ssync_id, type: :identifier, lookup: :ssync_lookup}],
|
|
462
|
-
action: ->(ssync_id:, **) { Result::SingleObject.new(
|
|
463
|
+
action: ->(ssync_id:, **) { Result::SingleObject.new(api_node.read("asyncs/#{ssync_id}/files", query_read_delete(default: {}))) }
|
|
463
464
|
command :state, description: 'Show sync state',
|
|
464
465
|
arguments: [{name: :ssync_id, type: :identifier, lookup: :ssync_lookup}],
|
|
465
|
-
action: ->(ssync_id:, **) { Result::SingleObject.new(
|
|
466
|
+
action: ->(ssync_id:, **) { Result::SingleObject.new(api_node.read("asyncs/#{ssync_id}/state")) }
|
|
466
467
|
command :summary, description: 'Show sync summary',
|
|
467
468
|
arguments: [{name: :ssync_id, type: :identifier, lookup: :ssync_lookup}],
|
|
468
|
-
action: ->(ssync_id:, **) { Result::SingleObject.new(
|
|
469
|
+
action: ->(ssync_id:, **) { Result::SingleObject.new(api_node.read("asyncs/#{ssync_id}/summary")) }
|
|
469
470
|
end
|
|
470
471
|
# stream
|
|
471
472
|
command :stream, description: 'Manage stream operations'
|
|
472
473
|
commands_under :stream do
|
|
473
|
-
command :list, description: 'List streams', action: -> { Result::ObjectList.new(
|
|
474
|
+
command :list, description: 'List streams', action: ->(**) { Result::ObjectList.new(api_node.read('ops/transfers', query_read_delete), fields: %w[id status]) }
|
|
474
475
|
command :create, description: 'Create a stream',
|
|
475
|
-
arguments: [{name: :
|
|
476
|
-
action: ->(
|
|
476
|
+
arguments: [{name: :stream, type: Hash, schema: 'node:components.schemas.transferPostRequest'}],
|
|
477
|
+
action: ->(stream:, **) { Result::SingleObject.new(api_node.create('streams', stream)) }
|
|
477
478
|
command :show, description: 'Show a stream',
|
|
478
479
|
arguments: [{name: :transfer_id, type: :identifier}],
|
|
479
|
-
action: ->(transfer_id:, **) { Result::SingleObject.new(
|
|
480
|
+
action: ->(transfer_id:, **) { Result::SingleObject.new(api_node.read("ops/transfers/#{transfer_id}")) }
|
|
480
481
|
command :modify, description: 'Modify a stream',
|
|
481
|
-
arguments: [{name: :transfer_id, type: :identifier}, {name: :
|
|
482
|
-
action: ->(
|
|
482
|
+
arguments: [{name: :transfer_id, type: :identifier}, {name: :stream, type: Hash, schema: 'node:components.schemas.transferPutRequest'}],
|
|
483
|
+
action: ->(stream:, transfer_id:, **) { Result::SingleObject.new(api_node.update("streams/#{transfer_id}", stream)) }
|
|
483
484
|
command :cancel, description: 'Cancel a stream',
|
|
484
485
|
arguments: [{name: :transfer_id, type: :identifier}],
|
|
485
|
-
action: ->(transfer_id:, **) { Result::SingleObject.new(
|
|
486
|
+
action: ->(transfer_id:, **) { Result::SingleObject.new(api_node.cancel("streams/#{transfer_id}")) }
|
|
486
487
|
end
|
|
487
488
|
# transfer
|
|
488
489
|
command :transfer, description: 'Manage transfer operations'
|
|
489
490
|
commands_under :transfer do
|
|
490
491
|
command :list, description: 'List transfers'
|
|
491
|
-
command
|
|
492
|
-
|
|
492
|
+
command(
|
|
493
|
+
:cancel, description: 'Cancel a transfer',
|
|
494
|
+
arguments: [{name: :transfer_id, type: :identifier}],
|
|
495
|
+
action: lambda do |transfer_id:, **|
|
|
496
|
+
api_node.cancel("ops/transfers/#{transfer_id}")
|
|
497
|
+
Result::Status.new('Cancelled')
|
|
498
|
+
end
|
|
499
|
+
)
|
|
493
500
|
command :show, description: 'Show a transfer',
|
|
494
501
|
arguments: [{name: :transfer_id, type: :identifier}],
|
|
495
|
-
action: ->(transfer_id:, **) { Result::SingleObject.new(
|
|
496
|
-
command
|
|
497
|
-
|
|
502
|
+
action: ->(transfer_id:, **) { Result::SingleObject.new(api_node.read("ops/transfers/#{transfer_id}")) }
|
|
503
|
+
command(
|
|
504
|
+
:modify, description: 'Modify a transfer',
|
|
505
|
+
arguments: [{name: :transfer_id, type: :identifier}, {name: :transfer, type: Hash, schema: 'node:components.schemas.transferPutRequest'}],
|
|
506
|
+
action: lambda do |transfer:, transfer_id:, **|
|
|
507
|
+
api_node.update("ops/transfers/#{transfer_id}", transfer)
|
|
508
|
+
Result::Status.new('Modified')
|
|
509
|
+
end
|
|
510
|
+
)
|
|
498
511
|
command :bandwidth_average, description: 'Show average bandwidth per period'
|
|
499
512
|
command :sessions, description: 'List transfer sessions'
|
|
500
513
|
end
|
|
501
514
|
# service
|
|
502
515
|
command :service, description: 'Manage services'
|
|
503
516
|
commands_under :service do
|
|
504
|
-
command :list,
|
|
505
|
-
command
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
517
|
+
command :list, description: 'List services', action: ->(**) { Result::ObjectList.new(api_node.read('rund/services')['services']) }
|
|
518
|
+
command(
|
|
519
|
+
:create, description: 'Create a service',
|
|
520
|
+
arguments: [{name: :service, type: Hash}],
|
|
521
|
+
action: lambda do |service:, **|
|
|
522
|
+
resp = api_node.create('rund/services', service)
|
|
523
|
+
Result::Status.new("#{resp['id']} created")
|
|
524
|
+
end
|
|
525
|
+
)
|
|
526
|
+
command(
|
|
527
|
+
:delete, description: 'Delete a service',
|
|
528
|
+
arguments: [{name: :service_id, type: :identifier}],
|
|
529
|
+
action: lambda do |service_id:, **|
|
|
530
|
+
api_node.delete("rund/services/#{service_id}")
|
|
531
|
+
Result::Status.new("#{service_id} deleted")
|
|
532
|
+
end
|
|
533
|
+
)
|
|
509
534
|
end
|
|
510
535
|
# watch_folder
|
|
511
536
|
command :watch_folder, description: 'Manage watch folders', setup: :setup_watch_folder
|
|
512
537
|
commands_under :watch_folder do
|
|
513
538
|
command :create, description: 'Create a watch folder',
|
|
514
|
-
arguments: [{name: :
|
|
515
|
-
action: ->(
|
|
539
|
+
arguments: [{name: :watch_folder, type: Hash}],
|
|
540
|
+
action: ->(watch_folder:, **) { Result::Status.new("#{api_node.create('v3/watchfolders', watch_folder)['id']} created") }
|
|
516
541
|
command :list, description: 'List watch folders',
|
|
517
|
-
action: -> { Result::ValueList.new(
|
|
542
|
+
action: ->(**) { Result::ValueList.new(api_node.read('v3/watchfolders', query_read_delete)['ids']) }
|
|
518
543
|
command :show, description: 'Show a watch folder',
|
|
519
544
|
arguments: [{name: :watch_folder_id, type: :identifier}],
|
|
520
|
-
action: ->(watch_folder_id:, **) { Result::SingleObject.new(
|
|
521
|
-
command
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
545
|
+
action: ->(watch_folder_id:, **) { Result::SingleObject.new(api_node.read("v3/watchfolders/#{watch_folder_id}")) }
|
|
546
|
+
command(
|
|
547
|
+
:modify, description: 'Modify a watch folder',
|
|
548
|
+
arguments: [{name: :watch_folder_id, type: :identifier}, {name: :watch_folder, type: Hash}],
|
|
549
|
+
action: lambda do |watch_folder:, watch_folder_id:, **|
|
|
550
|
+
api_node.update("v3/watchfolders/#{watch_folder_id}", watch_folder)
|
|
551
|
+
Result::Status.new("#{watch_folder_id} updated")
|
|
552
|
+
end
|
|
553
|
+
)
|
|
554
|
+
command(
|
|
555
|
+
:delete, description: 'Delete a watch folder',
|
|
556
|
+
arguments: [{name: :watch_folder_id, type: :identifier}],
|
|
557
|
+
action: lambda do |watch_folder_id:, **|
|
|
558
|
+
api_node.delete("v3/watchfolders/#{watch_folder_id}")
|
|
559
|
+
Result::Status.new("#{watch_folder_id} deleted")
|
|
560
|
+
end
|
|
561
|
+
)
|
|
562
|
+
command :state, description: 'Show watch folder state',
|
|
526
563
|
arguments: [{name: :watch_folder_id, type: :identifier}],
|
|
527
|
-
action: ->(watch_folder_id:, **) { Result::SingleObject.new(
|
|
564
|
+
action: ->(watch_folder_id:, **) { Result::SingleObject.new(api_node.read("v3/watchfolders/#{watch_folder_id}/state")) }
|
|
528
565
|
end
|
|
529
566
|
# central
|
|
530
567
|
command :central, description: 'Query Central service'
|
|
@@ -534,19 +571,26 @@ module Aspera
|
|
|
534
571
|
end
|
|
535
572
|
commands_under %i[central session] do
|
|
536
573
|
command :list, description: 'List sessions',
|
|
537
|
-
arguments: [{name: :
|
|
574
|
+
arguments: [{name: :criteria, type: Hash, mandatory: false, default: nil}]
|
|
538
575
|
end
|
|
539
576
|
commands_under %i[central file] do
|
|
540
577
|
command :list, description: 'List file transfers',
|
|
541
|
-
arguments: [{name: :
|
|
578
|
+
arguments: [{name: :criteria, type: Hash, mandatory: false, default: nil}]
|
|
542
579
|
command :modify, description: 'Modify file transfer validation',
|
|
543
|
-
arguments: [{name: :
|
|
580
|
+
arguments: [{name: :file, type: Hash, mandatory: false, default: nil}]
|
|
544
581
|
end
|
|
545
582
|
# Standalone leaf commands
|
|
546
583
|
command :asperabrowser, description: 'Open Aspera browser'
|
|
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))) }
|
|
548
|
-
command
|
|
549
|
-
|
|
584
|
+
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))) }
|
|
585
|
+
command(
|
|
586
|
+
:bearer_token, description: 'Generate bearer token',
|
|
587
|
+
arguments: [{name: :private_key_pem}, {name: :token, type: Hash, schema: 'opts:components.schemas.NodeBearerTokenOptions'}],
|
|
588
|
+
action: lambda do |private_key_pem:, token:, **|
|
|
589
|
+
private_key = OpenSSL::PKey::RSA.new(private_key_pem)
|
|
590
|
+
access_key = options.get_option(:username, mandatory: true)
|
|
591
|
+
Result::Text.new(Api::Node.bearer_token(payload: token, access_key: access_key, private_key: private_key))
|
|
592
|
+
end
|
|
593
|
+
)
|
|
550
594
|
command :simulator, description: 'Start node simulator',
|
|
551
595
|
arguments: [{name: :parameters, type: Hash, mandatory: false, default: {}, schema: 'opts:components.schemas.NodeSimulatorOptions'}]
|
|
552
596
|
command :telemetry, description: 'Report telemetry to external system',
|
|
@@ -557,15 +601,16 @@ module Aspera
|
|
|
557
601
|
def action_delete(paths:, **)
|
|
558
602
|
# TODO: add query for recursive
|
|
559
603
|
paths_to_delete = Array(paths)
|
|
560
|
-
resp =
|
|
604
|
+
resp = api_node.create('files/delete', {paths: paths_to_delete.map { |i| {'path' => i.start_with?('/') ? i : "/#{i}"} }})
|
|
561
605
|
cli_result_from_paths_response(resp, 'file deleted')
|
|
562
606
|
end
|
|
563
607
|
|
|
564
|
-
def action_search(
|
|
565
|
-
parameters = {'path' =>
|
|
608
|
+
def action_search(path:, **)
|
|
609
|
+
parameters = {'path' => path}
|
|
610
|
+
# not a URL query: merged into the POST body of files/search
|
|
566
611
|
other_options = options.get_option(:query)
|
|
567
612
|
parameters.merge!(other_options) unless other_options.nil?
|
|
568
|
-
resp =
|
|
613
|
+
resp = api_node.create('files/search', parameters)
|
|
569
614
|
return Result::Empty.new if resp['items'].empty?
|
|
570
615
|
fields = resp['items'].first.keys.reject { |i| SEARCH_REMOVE_FIELDS.include?(i) }
|
|
571
616
|
formatter.display_item_count(resp['item_count'], resp['total_count'])
|
|
@@ -573,32 +618,32 @@ module Aspera
|
|
|
573
618
|
Result::ObjectList.new(resp['items'], fields: fields)
|
|
574
619
|
end
|
|
575
620
|
|
|
576
|
-
def action_space(
|
|
577
|
-
|
|
578
|
-
resp =
|
|
621
|
+
def action_space(paths:, **)
|
|
622
|
+
paths = Array(paths)
|
|
623
|
+
resp = api_node.create('space', {'paths' => paths.map { |i| {path: i} }})
|
|
579
624
|
Result::ObjectList.new(resp['paths'])
|
|
580
625
|
end
|
|
581
626
|
|
|
582
|
-
def action_mkdir(
|
|
583
|
-
|
|
584
|
-
resp =
|
|
627
|
+
def action_mkdir(paths:, **)
|
|
628
|
+
paths = Array(paths)
|
|
629
|
+
resp = api_node.create('files/create', {'paths' => paths.map { |i| {type: :directory, path: i} }})
|
|
585
630
|
cli_result_from_paths_response(resp, 'folder created')
|
|
586
631
|
end
|
|
587
632
|
|
|
588
633
|
def action_mklink(target:, link_path:, **)
|
|
589
|
-
resp =
|
|
634
|
+
resp = api_node.create('files/create', {'paths' => [{type: :symbolic_link, path: link_path, target: {path: target}}]})
|
|
590
635
|
cli_result_from_paths_response(resp, 'link created')
|
|
591
636
|
end
|
|
592
637
|
|
|
593
|
-
def action_mkfile(
|
|
638
|
+
def action_mkfile(path:, contents:, **)
|
|
594
639
|
contents64 = contents.nil? ? '' : Base64.strict_encode64(contents)
|
|
595
|
-
resp =
|
|
640
|
+
resp = api_node.create('files/create', {'paths' => [{type: :file, path: path, contents: contents64}]})
|
|
596
641
|
cli_result_from_paths_response(resp, 'file created')
|
|
597
642
|
end
|
|
598
643
|
|
|
599
|
-
def action_rename(
|
|
644
|
+
def action_rename(folder:, source:, destination:, **)
|
|
600
645
|
# TODO: multiple ?
|
|
601
|
-
resp =
|
|
646
|
+
resp = api_node.create('files/rename', {'paths' => [{'path' => folder, 'source' => source, 'destination' => destination}]})
|
|
602
647
|
cli_result_from_paths_response(resp, 'entry moved')
|
|
603
648
|
end
|
|
604
649
|
|
|
@@ -606,8 +651,8 @@ module Aspera
|
|
|
606
651
|
def sync_gen3_block
|
|
607
652
|
lambda do |direction, local_path, remote_path|
|
|
608
653
|
request_transfer_spec = sync_spec_request(direction, local_path, remote_path)
|
|
609
|
-
|
|
610
|
-
transfer_spec =
|
|
654
|
+
api_node.add_tspec_info(request_transfer_spec) if api_node.respond_to?(:add_tspec_info)
|
|
655
|
+
transfer_spec = api_node.create(
|
|
611
656
|
'files/sync_setup',
|
|
612
657
|
{transfer_requests: [{transfer_request: request_transfer_spec}]}
|
|
613
658
|
)['transfer_specs'].first['transfer_spec']
|
|
@@ -621,42 +666,42 @@ module Aspera
|
|
|
621
666
|
define_method(:"action_sync_#{dir}") { |path:, sync_info: {}, **| run_sync_transfer(dir, path: path, sync_info: sync_info, &sync_gen3_block) }
|
|
622
667
|
end
|
|
623
668
|
|
|
624
|
-
def action_upload
|
|
669
|
+
def action_upload(**)
|
|
625
670
|
# empty transfer spec for authorization request
|
|
626
671
|
request_transfer_spec = {}
|
|
627
672
|
request_transfer_spec[:paths] = [{destination: transfer.destination_folder(Transfer::Spec::DIRECTION_SEND)}]
|
|
628
673
|
# add fixed parameters if any (for COS)
|
|
629
|
-
|
|
674
|
+
api_node.add_tspec_info(request_transfer_spec) if api_node.respond_to?(:add_tspec_info)
|
|
630
675
|
Api::Node.add_public_key(request_transfer_spec)
|
|
631
676
|
setup_payload = {transfer_requests: [{transfer_request: request_transfer_spec}]}
|
|
632
|
-
transfer_spec =
|
|
677
|
+
transfer_spec = api_node.create('files/upload_setup', setup_payload)['transfer_specs'].first['transfer_spec']
|
|
633
678
|
Api::Node.add_private_key(transfer_spec)
|
|
634
679
|
transfer_spec.delete('paths')
|
|
635
680
|
Runner.result_transfer(transfer.start(transfer_spec))
|
|
636
681
|
end
|
|
637
682
|
|
|
638
|
-
def action_download
|
|
683
|
+
def action_download(**)
|
|
639
684
|
# empty transfer spec for authorization request
|
|
640
685
|
request_transfer_spec = {}
|
|
641
686
|
request_transfer_spec[:paths] = transfer.ts_source_paths
|
|
642
687
|
# add fixed parameters if any (for COS)
|
|
643
|
-
|
|
688
|
+
api_node.add_tspec_info(request_transfer_spec) if api_node.respond_to?(:add_tspec_info)
|
|
644
689
|
Api::Node.add_public_key(request_transfer_spec)
|
|
645
690
|
setup_payload = {transfer_requests: [{transfer_request: request_transfer_spec}]}
|
|
646
|
-
transfer_spec =
|
|
691
|
+
transfer_spec = api_node.create('files/download_setup', setup_payload)['transfer_specs'].first['transfer_spec']
|
|
647
692
|
Api::Node.add_private_key(transfer_spec)
|
|
648
693
|
Runner.result_transfer(transfer.start(transfer_spec))
|
|
649
694
|
end
|
|
650
695
|
|
|
651
|
-
def action_cat(
|
|
652
|
-
http =
|
|
696
|
+
def action_cat(path:, **)
|
|
697
|
+
http = api_node.read("files/#{URI.encode_www_form_component(path)}/contents", ret: :resp)
|
|
653
698
|
Result::Text.new(http.body)
|
|
654
699
|
end
|
|
655
700
|
|
|
656
|
-
def action_health
|
|
701
|
+
def action_health(**)
|
|
657
702
|
nagios = Nagios.new
|
|
658
703
|
begin
|
|
659
|
-
info =
|
|
704
|
+
info = api_node.read('info')
|
|
660
705
|
nagios.add_ok('node api', 'accessible')
|
|
661
706
|
nagios.check_time_offset(info['current_time'], 'node api')
|
|
662
707
|
nagios.check_product_version('node api', 'entsrv', info['version'])
|
|
@@ -664,7 +709,7 @@ module Aspera
|
|
|
664
709
|
nagios.add_critical('node api', e.to_s)
|
|
665
710
|
end
|
|
666
711
|
begin
|
|
667
|
-
|
|
712
|
+
api_node.call(
|
|
668
713
|
operation: 'POST',
|
|
669
714
|
subpath: 'services/soap/Transfer-201210',
|
|
670
715
|
content_type: Mime::TEXT,
|
|
@@ -681,49 +726,32 @@ module Aspera
|
|
|
681
726
|
|
|
682
727
|
# watch_folder setup: inject required API header (avoids "Unable to convert 2016_09_14 configuration")
|
|
683
728
|
def setup_watch_folder(**)
|
|
684
|
-
|
|
685
|
-
@api_node.params[:headers]['X-aspera-WF-version'] = '2017_10_23'
|
|
729
|
+
api_node.headers['X-aspera-WF-version'] = '2017_10_23'
|
|
686
730
|
{}
|
|
687
731
|
end
|
|
688
732
|
|
|
689
|
-
def action_access_keys_do_permission_modify(data:, apifid:, perm_id:, **)
|
|
690
|
-
apifid.node_api.update("permissions/#{perm_id}", data)
|
|
691
|
-
Result::Status.new('Updated')
|
|
692
|
-
end
|
|
693
|
-
|
|
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")
|
|
697
|
-
end
|
|
698
|
-
|
|
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")
|
|
702
|
-
end
|
|
703
|
-
|
|
704
733
|
# access_keys > do - setup: resolve access key and root file id
|
|
705
|
-
# access_key_id is resolved by execute_leaf (via instance_arg in CommandSpec)
|
|
706
734
|
# @return [Hash] context hash containing :do_root_file_id
|
|
707
735
|
def setup_access_key_do(access_key_id:, **)
|
|
708
736
|
@do_root_file_id = options.get_option(:root_id)
|
|
709
737
|
if @do_root_file_id.nil?
|
|
710
|
-
ak_info =
|
|
711
|
-
ak_secret = context.secret_finder.lookup(url:
|
|
738
|
+
ak_info = api_node.read("access_keys/#{access_key_id}")
|
|
739
|
+
ak_secret = context.secret_finder.lookup(url: api_node.base_url, username: ak_info['id'])
|
|
712
740
|
if !access_key_id.eql?('self')
|
|
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']}@#{
|
|
714
|
-
|
|
715
|
-
|
|
741
|
+
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}." }
|
|
742
|
+
api_node.auth_params[:username] = ak_info['id']
|
|
743
|
+
api_node.auth_params[:password] = ak_secret
|
|
716
744
|
end
|
|
717
745
|
@do_root_file_id = ak_info['root_file_id']
|
|
718
746
|
end
|
|
719
747
|
{do_root_file_id: @do_root_file_id}
|
|
720
748
|
end
|
|
721
749
|
|
|
722
|
-
# access_keys > do > permission - setup: resolve apifid from
|
|
723
|
-
#
|
|
750
|
+
# access_keys > do > permission - setup: resolve apifid from the path argument of the node
|
|
751
|
+
# do_root_file_id: comes from ctx (setup_access_key_do, or seed of a mount)
|
|
724
752
|
# @return [Hash] context hash containing :apifid
|
|
725
|
-
def setup_access_key_do_permission(**)
|
|
726
|
-
{apifid:
|
|
753
|
+
def setup_access_key_do_permission(do_root_file_id:, path:, **)
|
|
754
|
+
{apifid: apifid_from_path(do_root_file_id, path)}
|
|
727
755
|
end
|
|
728
756
|
|
|
729
757
|
# access_keys > do > ls
|
|
@@ -737,7 +765,7 @@ module Aspera
|
|
|
737
765
|
# access_keys > do > find
|
|
738
766
|
def action_access_keys_do_find(path:, filter: nil, do_root_file_id:, **)
|
|
739
767
|
apifid = apifid_from_path(do_root_file_id, path)
|
|
740
|
-
Result::ObjectList.new(
|
|
768
|
+
Result::ObjectList.new(api_node.find_files(apifid.file_id, Base.file_matcher(filter)), fields: ['path'])
|
|
741
769
|
end
|
|
742
770
|
|
|
743
771
|
# access_keys > do > cat
|
|
@@ -753,9 +781,9 @@ module Aspera
|
|
|
753
781
|
end
|
|
754
782
|
|
|
755
783
|
# access_keys > do > modify
|
|
756
|
-
def action_access_keys_do_modify(path:,
|
|
784
|
+
def action_access_keys_do_modify(path:, file:, do_root_file_id:, **)
|
|
757
785
|
apifid = apifid_from_path(do_root_file_id, path)
|
|
758
|
-
apifid.node_api.update("files/#{apifid.file_id}",
|
|
786
|
+
apifid.node_api.update("files/#{apifid.file_id}", file)
|
|
759
787
|
Result::Status.new('Done')
|
|
760
788
|
end
|
|
761
789
|
|
|
@@ -767,19 +795,19 @@ module Aspera
|
|
|
767
795
|
|
|
768
796
|
# access_keys > do > rename
|
|
769
797
|
def action_access_keys_do_rename(source_path:, new_name:, do_root_file_id:, **)
|
|
770
|
-
apifid =
|
|
798
|
+
apifid = api_node.resolve_api_fid(do_root_file_id, source_path)
|
|
771
799
|
apifid.node_api.update("files/#{apifid.file_id}", {name: new_name})
|
|
772
800
|
Result::Status.new("renamed to #{new_name}")
|
|
773
801
|
end
|
|
774
802
|
|
|
775
803
|
# access_keys > do > delete
|
|
776
|
-
def action_access_keys_do_delete(
|
|
777
|
-
bulk_result(
|
|
804
|
+
def action_access_keys_do_delete(path:, do_root_file_id:, **)
|
|
805
|
+
bulk_result(path, command: :delete, id_result: 'path') do |l_path|
|
|
778
806
|
apifid = if (m = Parser.percent_selector(l_path))
|
|
779
807
|
Aspera.assert_values(m[:field], ['id'], type: BadIdentifier)
|
|
780
|
-
Api::NodeFileId.new(
|
|
808
|
+
Api::NodeFileId.new(api_node, m[:value])
|
|
781
809
|
else
|
|
782
|
-
|
|
810
|
+
api_node.resolve_api_fid(do_root_file_id, l_path)
|
|
783
811
|
end
|
|
784
812
|
apifid.node_api.delete("files/#{apifid.file_id}")
|
|
785
813
|
{'path' => l_path}
|
|
@@ -790,7 +818,7 @@ module Aspera
|
|
|
790
818
|
def sync_gen4_block(do_root_file_id)
|
|
791
819
|
lambda do |direction, _local_path, remote_path|
|
|
792
820
|
ts_direction = direction.eql?(:pull) ? Transfer::Spec::DIRECTION_RECEIVE : Transfer::Spec::DIRECTION_SEND
|
|
793
|
-
apifid =
|
|
821
|
+
apifid = api_node.resolve_api_fid(do_root_file_id, remote_path)
|
|
794
822
|
apifid.node_api.transfer_spec_gen4(apifid.file_id, ts_direction)
|
|
795
823
|
end
|
|
796
824
|
end
|
|
@@ -803,27 +831,20 @@ module Aspera
|
|
|
803
831
|
|
|
804
832
|
# access_keys > do > upload
|
|
805
833
|
def action_access_keys_do_upload(do_root_file_id:, **)
|
|
806
|
-
apifid =
|
|
834
|
+
apifid = api_node.resolve_api_fid(do_root_file_id, transfer.destination_folder(Transfer::Spec::DIRECTION_SEND), true)
|
|
807
835
|
Runner.result_transfer(transfer.start(apifid.node_api.transfer_spec_gen4(apifid.file_id, Transfer::Spec::DIRECTION_SEND)))
|
|
808
836
|
end
|
|
809
837
|
|
|
810
838
|
# access_keys > do > download
|
|
811
839
|
def action_access_keys_do_download(do_root_file_id:, **)
|
|
812
|
-
apifid, source_paths =
|
|
840
|
+
apifid, source_paths = api_node.resolve_api_fid_paths(do_root_file_id, transfer.ts_source_paths)
|
|
813
841
|
Runner.result_transfer(transfer.start(apifid.node_api.transfer_spec_gen4(apifid.file_id, Transfer::Spec::DIRECTION_RECEIVE, {'paths'=>source_paths})))
|
|
814
842
|
end
|
|
815
843
|
|
|
816
|
-
# access_keys > do >
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
end
|
|
821
|
-
|
|
822
|
-
# access_keys > do > v3
|
|
823
|
-
def action_access_keys_do_v3(do_root_file_id:, **)
|
|
824
|
-
# Build a fresh Node for the v3 root, then let the DSL dispatcher consume the next command.
|
|
825
|
-
v3_node = Node.new(context: context, api: @api_node.resolve_api_fid(do_root_file_id, '').node_api)
|
|
826
|
-
v3_node.execute_action
|
|
844
|
+
# access_keys > do > v3 - mount target: Node plugin on the node hosting the root file
|
|
845
|
+
# @return [Node]
|
|
846
|
+
def v3_node_plugin(do_root_file_id:, **)
|
|
847
|
+
Node.new(context: context, api: api_node.resolve_api_fid(do_root_file_id, '').node_api)
|
|
827
848
|
end
|
|
828
849
|
|
|
829
850
|
# access_keys > do > node_info / bearer_token_node — shared helper builds the result hash
|
|
@@ -861,7 +882,8 @@ module Aspera
|
|
|
861
882
|
# @param path [String] full path (folder/name)
|
|
862
883
|
def gen4_mk_resolve(top_file_id, path)
|
|
863
884
|
containing_folder_path, new_item = Api::Node.split_folder(path)
|
|
864
|
-
apifid =
|
|
885
|
+
apifid = api_node.resolve_api_fid(top_file_id, containing_folder_path, true)
|
|
886
|
+
# not a URL query: special keys `check` and `target`, rest merged into the POST body
|
|
865
887
|
query = options.get_option(:query)
|
|
866
888
|
check_exists = true
|
|
867
889
|
payload = {name: new_item}
|
|
@@ -869,7 +891,7 @@ module Aspera
|
|
|
869
891
|
check_exists = !query.delete('check').eql?(false)
|
|
870
892
|
target = query.delete('target')
|
|
871
893
|
if target
|
|
872
|
-
target_apifid =
|
|
894
|
+
target_apifid = api_node.resolve_api_fid(top_file_id, target, true)
|
|
873
895
|
payload[:target_id] = target_apifid.file_id
|
|
874
896
|
end
|
|
875
897
|
payload.merge!(query.symbolize_keys)
|
|
@@ -913,8 +935,8 @@ module Aspera
|
|
|
913
935
|
Result::ObjectList.new(apifid.node_api.read_with_pages('permissions', list_query))
|
|
914
936
|
end
|
|
915
937
|
|
|
916
|
-
def action_access_keys_do_permission_delete(
|
|
917
|
-
bulk_result(
|
|
938
|
+
def action_access_keys_do_permission_delete(permission_id:, apifid:, **)
|
|
939
|
+
bulk_result(permission_id, command: :delete) do |one_id|
|
|
918
940
|
apifid.node_api.delete("permissions/#{one_id}")
|
|
919
941
|
the_app = apifid.node_api.app_info
|
|
920
942
|
the_app&.api&.permissions_send_event(event_data: {}, app_info: the_app, types: ['permission.deleted'])
|
|
@@ -922,8 +944,8 @@ module Aspera
|
|
|
922
944
|
end
|
|
923
945
|
end
|
|
924
946
|
|
|
925
|
-
def action_access_keys_do_permission_create(
|
|
926
|
-
create_param =
|
|
947
|
+
def action_access_keys_do_permission_create(permission:, apifid:, **)
|
|
948
|
+
create_param = permission
|
|
927
949
|
Aspera.assert(!create_param.key?('file_id'), type: Cli::BadArgument) { 'no file_id' }
|
|
928
950
|
create_param['file_id'] = apifid.file_id
|
|
929
951
|
create_param['access_levels'] = Api::Node::ACCESS_LEVELS unless create_param.key?('access_levels')
|
|
@@ -936,36 +958,31 @@ module Aspera
|
|
|
936
958
|
|
|
937
959
|
# access_keys > set_bearer_key
|
|
938
960
|
def action_access_keys_set_bearer_key(access_key_id:, bearer_key_pem:, **)
|
|
939
|
-
access_key_id =
|
|
961
|
+
access_key_id = api_node.read('access_keys/self')['id'] if access_key_id.eql?('self')
|
|
940
962
|
key = OpenSSL::PKey.read(bearer_key_pem)
|
|
941
963
|
key = key.public_key if key.private?
|
|
942
|
-
|
|
964
|
+
api_node.update("access_keys/#{access_key_id}", {token_verification_key: key.to_pem})
|
|
943
965
|
Result::Status.new('public key updated')
|
|
944
966
|
end
|
|
945
967
|
|
|
946
968
|
# async sub-commands: individual handlers
|
|
947
969
|
def action_async_show(async_id:, **)
|
|
948
|
-
async_ids =
|
|
970
|
+
async_ids = api_node.read('async/list')['sync_ids']
|
|
949
971
|
if async_id.eql?(SpecialValues::ALL)
|
|
950
|
-
resp =
|
|
972
|
+
resp = api_node.create('async/summary', {'syncs' => async_ids})['sync_summaries']
|
|
951
973
|
return Result::Empty.new if resp.empty?
|
|
952
974
|
return Result::ObjectList.new(resp, fields: %w[snid name local_dir remote_dir])
|
|
953
975
|
end
|
|
954
976
|
Integer(async_id)
|
|
955
|
-
resp =
|
|
977
|
+
resp = api_node.create('async/summary', {'syncs' => [async_id]})['sync_summaries']
|
|
956
978
|
return Result::Empty.new if resp.empty?
|
|
957
979
|
Result::SingleObject.new(resp.first)
|
|
958
980
|
end
|
|
959
981
|
|
|
960
|
-
def action_async_delete(async_id:, **)
|
|
961
|
-
async_ids = async_id.eql?(SpecialValues::ALL) ? @api_node.read('async/list')['sync_ids'] : [async_id]
|
|
962
|
-
Result::SingleObject.new(@api_node.create('async/delete', {'syncs' => async_ids}))
|
|
963
|
-
end
|
|
964
|
-
|
|
965
982
|
def action_async_bandwidth(async_id:, **)
|
|
966
983
|
Integer(async_id)
|
|
967
984
|
post_data = {'syncs' => [async_id], 'seconds' => 100}
|
|
968
|
-
resp =
|
|
985
|
+
resp = api_node.create('async/bandwidth', post_data)
|
|
969
986
|
data = resp['bandwidth_data']
|
|
970
987
|
return Result::Empty.new if data.empty?
|
|
971
988
|
Result::ObjectList.new(data.first[async_id]['data'])
|
|
@@ -974,9 +991,10 @@ module Aspera
|
|
|
974
991
|
def action_async_files(async_id:, **)
|
|
975
992
|
Integer(async_id)
|
|
976
993
|
post_data = {'syncs' => [async_id]}
|
|
994
|
+
# not a URL query: merged into the POST body of async/files
|
|
977
995
|
filter = options.get_option(:query)
|
|
978
996
|
post_data.merge!(filter) unless filter.nil?
|
|
979
|
-
resp =
|
|
997
|
+
resp = api_node.create('async/files', post_data)
|
|
980
998
|
data = resp['sync_files']
|
|
981
999
|
data = data.first[async_id] unless data.empty?
|
|
982
1000
|
iteration_data = []
|
|
@@ -997,23 +1015,13 @@ module Aspera
|
|
|
997
1015
|
|
|
998
1016
|
def action_async_counters(async_id:, **)
|
|
999
1017
|
Integer(async_id)
|
|
1000
|
-
resp =
|
|
1018
|
+
resp = api_node.create('async/counters', {'syncs' => [async_id]})['sync_counters'].first[async_id].last
|
|
1001
1019
|
return Result::Empty.new if resp.nil?
|
|
1002
1020
|
Result::SingleObject.new(resp)
|
|
1003
1021
|
end
|
|
1004
1022
|
|
|
1005
|
-
def action_ssync_start(ssync_id:, **)
|
|
1006
|
-
@api_node.call(operation: 'POST', subpath: "asyncs/#{ssync_id}/start", content_type: Mime::TEXT, body: '', ret: :resp).body
|
|
1007
|
-
Result::Status.new('Done')
|
|
1008
|
-
end
|
|
1009
|
-
|
|
1010
|
-
def action_ssync_stop(ssync_id:, **)
|
|
1011
|
-
@api_node.call(operation: 'POST', subpath: "asyncs/#{ssync_id}/stop", content_type: Mime::TEXT, body: '', ret: :resp).body
|
|
1012
|
-
Result::Status.new('Done')
|
|
1013
|
-
end
|
|
1014
|
-
|
|
1015
1023
|
# transfer sub-commands
|
|
1016
|
-
def action_transfer_list
|
|
1024
|
+
def action_transfer_list(**)
|
|
1017
1025
|
transfer_filter = query_read_delete(default: {}, schema: Schema::Registry.query_params(Schema::Registry::NODE, 'ops/transfers'))
|
|
1018
1026
|
iteration_persistency = nil
|
|
1019
1027
|
if options.get_option(:once_only, mandatory: true)
|
|
@@ -1030,13 +1038,13 @@ module Aspera
|
|
|
1030
1038
|
else
|
|
1031
1039
|
Aspera.assert(!transfer_filter.key?('reset'), 'reset only with once_only', type: Cli::BadArgument)
|
|
1032
1040
|
end
|
|
1033
|
-
transfers_data =
|
|
1041
|
+
transfers_data = api_node.read_with_paging('ops/transfers', transfer_filter, iteration: iteration_persistency&.data)
|
|
1034
1042
|
iteration_persistency&.save
|
|
1035
1043
|
Result::ObjectList.new(transfers_data, fields: %w[id status start_spec.direction start_spec.remote_user start_spec.remote_host start_spec.destination_path])
|
|
1036
1044
|
end
|
|
1037
1045
|
|
|
1038
|
-
def action_transfer_sessions
|
|
1039
|
-
transfers_data =
|
|
1046
|
+
def action_transfer_sessions(**)
|
|
1047
|
+
transfers_data = api_node.read('ops/transfers', query_read_delete(schema: Schema::Registry.query_params(Schema::Registry::NODE, 'ops/transfers')))
|
|
1040
1048
|
sessions = transfers_data.flat_map { |t| t['sessions'] }
|
|
1041
1049
|
sessions.each do |session|
|
|
1042
1050
|
SESSION_TIME_FIELDS.each do |what|
|
|
@@ -1046,18 +1054,8 @@ module Aspera
|
|
|
1046
1054
|
Result::ObjectList.new(sessions, fields: %w[id status start_time end_time target_rate_kbps])
|
|
1047
1055
|
end
|
|
1048
1056
|
|
|
1049
|
-
def
|
|
1050
|
-
|
|
1051
|
-
Result::Status.new('Cancelled')
|
|
1052
|
-
end
|
|
1053
|
-
|
|
1054
|
-
def action_transfer_modify(update_value:, transfer_id:, **)
|
|
1055
|
-
@api_node.update("ops/transfers/#{transfer_id}", update_value)
|
|
1056
|
-
Result::Status.new('Modified')
|
|
1057
|
-
end
|
|
1058
|
-
|
|
1059
|
-
def action_transfer_bandwidth_average
|
|
1060
|
-
transfers_data = @api_node.read('ops/transfers', query_read_delete(schema: Schema::Registry.query_params(Schema::Registry::NODE, 'ops/transfers')))
|
|
1057
|
+
def action_transfer_bandwidth_average(**)
|
|
1058
|
+
transfers_data = api_node.read('ops/transfers', query_read_delete(schema: Schema::Registry.query_params(Schema::Registry::NODE, 'ops/transfers')))
|
|
1061
1059
|
bandwidth_period = {}
|
|
1062
1060
|
dir_info = %i[avg_kbps sessions].freeze
|
|
1063
1061
|
transfers_data.each do |t|
|
|
@@ -1086,17 +1084,6 @@ module Aspera
|
|
|
1086
1084
|
Result::ObjectList.new(result)
|
|
1087
1085
|
end
|
|
1088
1086
|
|
|
1089
|
-
# service sub-commands
|
|
1090
|
-
def action_service_create(creation_data:, **)
|
|
1091
|
-
resp = @api_node.create('rund/services', creation_data)
|
|
1092
|
-
Result::Status.new("#{resp['id']} created")
|
|
1093
|
-
end
|
|
1094
|
-
|
|
1095
|
-
def action_service_delete(service_id:, **)
|
|
1096
|
-
@api_node.delete("rund/services/#{service_id}")
|
|
1097
|
-
Result::Status.new("#{service_id} deleted")
|
|
1098
|
-
end
|
|
1099
|
-
|
|
1100
1087
|
# central: shared helper
|
|
1101
1088
|
def central_validation
|
|
1102
1089
|
validator_id = options.get_option(:validator)
|
|
@@ -1104,35 +1091,35 @@ module Aspera
|
|
|
1104
1091
|
end
|
|
1105
1092
|
|
|
1106
1093
|
# central > session > list
|
|
1107
|
-
def action_central_session_list(
|
|
1108
|
-
|
|
1094
|
+
def action_central_session_list(criteria:, **)
|
|
1095
|
+
criteria ||= {}
|
|
1109
1096
|
validation = central_validation
|
|
1110
|
-
|
|
1111
|
-
resp =
|
|
1097
|
+
criteria.deep_merge!({'validation' => validation}) unless validation.nil?
|
|
1098
|
+
resp = api_node.create('services/rest/transfers/v1/sessions', criteria)
|
|
1112
1099
|
Result::ObjectList.new(resp['session_info_result']['session_info'], fields: %w[session_uuid status transport direction bytes_transferred])
|
|
1113
1100
|
end
|
|
1114
1101
|
|
|
1115
1102
|
# central > file > list
|
|
1116
|
-
def action_central_file_list(
|
|
1117
|
-
|
|
1103
|
+
def action_central_file_list(criteria:, **)
|
|
1104
|
+
criteria ||= {}
|
|
1118
1105
|
validation = central_validation
|
|
1119
|
-
|
|
1120
|
-
resp =
|
|
1106
|
+
criteria.deep_merge!({'validation' => validation}) unless validation.nil?
|
|
1107
|
+
resp = api_node.create('services/rest/transfers/v1/files', criteria)
|
|
1121
1108
|
resp = JSON.parse(resp) if resp.is_a?(String)
|
|
1122
1109
|
Log.dump(:resp, resp)
|
|
1123
1110
|
Result::ObjectList.new(resp['file_transfer_info_result']['file_transfer_info'], fields: %w[session_uuid file_id status path])
|
|
1124
1111
|
end
|
|
1125
1112
|
|
|
1126
1113
|
# central > file > modify
|
|
1127
|
-
def action_central_file_modify(
|
|
1128
|
-
|
|
1114
|
+
def action_central_file_modify(file:, **)
|
|
1115
|
+
file ||= {}
|
|
1129
1116
|
validation = central_validation
|
|
1130
|
-
|
|
1131
|
-
|
|
1117
|
+
file.deep_merge!(validation) unless validation.nil?
|
|
1118
|
+
api_node.update('services/rest/transfers/v1/files', file)
|
|
1132
1119
|
Result::Status.new('updated')
|
|
1133
1120
|
end
|
|
1134
1121
|
|
|
1135
|
-
def action_asperabrowser
|
|
1122
|
+
def action_asperabrowser(**)
|
|
1136
1123
|
browse_params = {
|
|
1137
1124
|
'nodeUser' => options.get_option(:username, mandatory: true),
|
|
1138
1125
|
'nodePW' => options.get_option(:password, mandatory: true),
|
|
@@ -1144,12 +1131,6 @@ module Aspera
|
|
|
1144
1131
|
return Result::Status.new('done')
|
|
1145
1132
|
end
|
|
1146
1133
|
|
|
1147
|
-
def action_bearer_token(private_key_pem:, user_group_id:, **)
|
|
1148
|
-
private_key = OpenSSL::PKey::RSA.new(private_key_pem)
|
|
1149
|
-
access_key = options.get_option(:username, mandatory: true)
|
|
1150
|
-
Result::Text.new(Api::Node.bearer_token(payload: user_group_id, access_key: access_key, private_key: private_key))
|
|
1151
|
-
end
|
|
1152
|
-
|
|
1153
1134
|
def action_simulator(parameters: {}, **)
|
|
1154
1135
|
require 'aspera/node_simulator'
|
|
1155
1136
|
parameters = parameters.symbolize_keys
|
|
@@ -1169,8 +1150,8 @@ module Aspera
|
|
|
1169
1150
|
parameters[:interval] = 10 unless parameters.key?(:interval)
|
|
1170
1151
|
parameters[:hostname] = Socket.gethostname unless parameters.key?(:hostname)
|
|
1171
1152
|
interval = parameters[:interval].to_f
|
|
1172
|
-
Aspera.assert(interval
|
|
1173
|
-
otel_api = Rest.new(
|
|
1153
|
+
Aspera.assert(interval >= 0, type: Cli::BadArgument) { 'Interval must be a positive number in seconds, or 0 for single shot' }
|
|
1154
|
+
otel_api = Rest::Client.new(
|
|
1174
1155
|
base_url: "#{parameters[:url]}/v1",
|
|
1175
1156
|
headers: {
|
|
1176
1157
|
# 'Authorization' => "apiToken #{parameters[:key]}",
|
|
@@ -1225,7 +1206,7 @@ module Aspera
|
|
|
1225
1206
|
}
|
|
1226
1207
|
loop do
|
|
1227
1208
|
timestamp = Time.now
|
|
1228
|
-
transfers_data =
|
|
1209
|
+
transfers_data = api_node.read_with_paging('ops/transfers', {active_only: true})
|
|
1229
1210
|
datapoint[:asInt] = transfers_data.length
|
|
1230
1211
|
datapoint[:timeUnixNano] = timestamp.to_i * 1_000_000_000 + timestamp.nsec
|
|
1231
1212
|
Log.log.info("#{datapoint[:asInt]} active transfers")
|
|
@@ -1236,21 +1217,6 @@ module Aspera
|
|
|
1236
1217
|
end
|
|
1237
1218
|
end
|
|
1238
1219
|
|
|
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)
|
|
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.
|
|
1246
|
-
# @param command [Symbol] command already consumed from the argument stream
|
|
1247
|
-
# @param ctx [Hash] pre-resolved context (keyword args forwarded to dispatch)
|
|
1248
|
-
# @return [Object] CLI result
|
|
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)
|
|
1252
|
-
end
|
|
1253
|
-
|
|
1254
1220
|
private
|
|
1255
1221
|
|
|
1256
1222
|
# Response has key `paths`.
|