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
|
@@ -8,6 +8,8 @@ require 'aspera/api/ats'
|
|
|
8
8
|
require 'aspera/api/aoc'
|
|
9
9
|
require 'aspera/api/alee'
|
|
10
10
|
require 'aspera/assert'
|
|
11
|
+
require 'aspera/rainbow'
|
|
12
|
+
using Rainbow
|
|
11
13
|
|
|
12
14
|
module Aspera
|
|
13
15
|
module Cli
|
|
@@ -33,26 +35,26 @@ module Aspera
|
|
|
33
35
|
super(**base_args)
|
|
34
36
|
@ats_api_open = Api::Ats.new
|
|
35
37
|
@ats_api_auth = api
|
|
36
|
-
options.parse_options!
|
|
37
38
|
end
|
|
38
39
|
|
|
39
40
|
# --- DSL ---
|
|
40
41
|
|
|
41
|
-
command :cluster, description: '
|
|
42
|
+
command :cluster, description: 'Show general ATS cluster information (public API, no auth)'
|
|
42
43
|
command :access_key, description: 'Manage ATS access keys'
|
|
43
44
|
command :api_key, description: 'Manage credential to access ATS API', condition: :api_key_available?
|
|
44
|
-
command :aws_trust_policy, description: 'Show AWS trust policy', action:
|
|
45
|
+
command :aws_trust_policy, description: 'Show AWS trust policy', action: ->(**) { Result::SingleObject.new(ats_api.read('aws/trustpolicy', {region: options.get_option(:region, mandatory: true)})) }
|
|
45
46
|
|
|
46
|
-
commands_under
|
|
47
|
-
command :clouds, description: 'List cloud providers', action:
|
|
48
|
-
command :list, description: 'List ATS servers', action:
|
|
49
|
-
command :show, description: 'Show a specific server'
|
|
47
|
+
commands_under :cluster do
|
|
48
|
+
command :clouds, description: 'List cloud providers', action: ->(**) { Result::ObjectList.new(@ats_api_open.cloud_names.map { |k, v| CLOUD_TABLE.zip([k, v]).to_h }) }
|
|
49
|
+
command :list, description: 'List ATS servers', action: ->(**) { Result::ObjectList.new(@ats_api_open.all_servers, fields: %w[id cloud region]) }
|
|
50
|
+
command :show, description: 'Show a specific server (or use options cloud and region)',
|
|
51
|
+
arguments: [{name: :server_id, mandatory: false, default: nil}]
|
|
50
52
|
end
|
|
51
53
|
|
|
52
|
-
commands_under
|
|
54
|
+
commands_under :access_key do
|
|
53
55
|
command :create, description: 'Create an access key',
|
|
54
|
-
arguments: [{name: :
|
|
55
|
-
command(:list, description: 'List access keys', action: lambda do
|
|
56
|
+
arguments: [{name: :access_key, type: Hash, mandatory: false, default: {}}]
|
|
57
|
+
command(:list, description: 'List access keys', action: lambda do |**|
|
|
56
58
|
res = ats_api.read('access_keys', query_read_delete(default: {'offset' => 0, 'max_results' => 1000}))
|
|
57
59
|
Result::ObjectList.new(res['data'], fields: ['name', 'id', 'created.at', 'modified.at'])
|
|
58
60
|
end)
|
|
@@ -60,41 +62,52 @@ module Aspera
|
|
|
60
62
|
arguments: [{name: :access_key_id, type: :identifier}],
|
|
61
63
|
action: ->(access_key_id:, **) { Result::SingleObject.new(ats_api.read("access_keys/#{access_key_id}")) }
|
|
62
64
|
command :modify, description: 'Modify an access key',
|
|
63
|
-
arguments: [{name: :access_key_id, type: :identifier}, {name: :
|
|
64
|
-
command
|
|
65
|
-
|
|
65
|
+
arguments: [{name: :access_key_id, type: :identifier}, {name: :access_key, type: Hash}]
|
|
66
|
+
command(
|
|
67
|
+
:delete, description: 'Delete an access key',
|
|
68
|
+
arguments: [{name: :access_key_id, type: :identifier}],
|
|
69
|
+
action: lambda do |access_key_id:, **|
|
|
70
|
+
ats_api.delete("access_keys/#{access_key_id}")
|
|
71
|
+
Result::Status.new("deleted #{access_key_id}")
|
|
72
|
+
end
|
|
73
|
+
)
|
|
66
74
|
command :node, description: 'Execute node commands via ATS access key',
|
|
67
75
|
arguments: [{name: :access_key_id, type: :identifier}],
|
|
68
|
-
|
|
76
|
+
mount: {plugin: Node, at: %i[access_keys do], instance: :ak_node_plugin}
|
|
69
77
|
command :cluster, description: 'Show cluster info for an access key',
|
|
70
78
|
arguments: [{name: :access_key_id, type: :identifier}]
|
|
71
|
-
command
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
end
|
|
79
|
+
command(
|
|
80
|
+
:entitlement, description: 'Show ATS entitlement for an access key',
|
|
81
|
+
arguments: [{name: :access_key_id, type: :identifier}],
|
|
82
|
+
action: lambda do |access_key_id:, **|
|
|
83
|
+
ak = ats_api.read("access_keys/#{access_key_id}")
|
|
84
|
+
api_bss = Api::Alee.new(ak['license']['entitlement_id'], ak['license']['customer_id'])
|
|
85
|
+
return Result::SingleObject.new(api_bss.read('entitlement'))
|
|
86
|
+
end
|
|
87
|
+
)
|
|
81
88
|
end
|
|
82
89
|
|
|
83
|
-
commands_under
|
|
84
|
-
command(:instances, description: 'List ATS instances in IBM Cloud', action: lambda do
|
|
90
|
+
commands_under :api_key do
|
|
91
|
+
command(:instances, description: 'List ATS instances in IBM Cloud', action: lambda do |**|
|
|
85
92
|
instances = ats_api_v2_auth_ibm.read('instances')
|
|
86
93
|
Log.log.warn { "more instances remaining: #{instances['remaining']}" } unless instances['remaining'].to_i.eql?(0)
|
|
87
94
|
Result::ValueList.new(instances['data'], name: 'instance')
|
|
88
95
|
end)
|
|
89
96
|
command :create, description: 'Create an ATS API key',
|
|
90
|
-
arguments: [{name: :
|
|
91
|
-
action: ->(
|
|
92
|
-
command :list, description: 'List ATS API keys', action:
|
|
97
|
+
arguments: [{name: :api_key, type: Hash, mandatory: false, default: {}}],
|
|
98
|
+
action: ->(api_key:, **) { Result::SingleObject.new(build_ats_ibm_api_with_instance.create('api_keys', api_key)) }
|
|
99
|
+
command :list, description: 'List ATS API keys', action: ->(**) { Result::ValueList.new(build_ats_ibm_api_with_instance.read('api_keys', {'offset' => 0, 'max_results' => 1000})['data'], name: 'ats_id') }
|
|
93
100
|
command :show, description: 'Show an ATS API key',
|
|
94
101
|
arguments: [{name: :api_key_id, type: :identifier}],
|
|
95
102
|
action: ->(api_key_id:, **) { Result::SingleObject.new(build_ats_ibm_api_with_instance.read("api_keys/#{api_key_id}")) }
|
|
96
|
-
command
|
|
97
|
-
|
|
103
|
+
command(
|
|
104
|
+
:delete, description: 'Delete an ATS API key',
|
|
105
|
+
arguments: [{name: :api_key_id, type: :identifier}],
|
|
106
|
+
action: lambda do |api_key_id:, **|
|
|
107
|
+
build_ats_ibm_api_with_instance.delete("api_keys/#{api_key_id}")
|
|
108
|
+
Result::Status.new("deleted #{api_key_id}")
|
|
109
|
+
end
|
|
110
|
+
)
|
|
98
111
|
end
|
|
99
112
|
|
|
100
113
|
# --- conditions ---
|
|
@@ -116,7 +129,7 @@ module Aspera
|
|
|
116
129
|
# require api key only if needed
|
|
117
130
|
def ats_api
|
|
118
131
|
return @ats_api_auth unless @ats_api_auth.nil?
|
|
119
|
-
@ats_api_auth = Rest.new(
|
|
132
|
+
@ats_api_auth = Rest::Client.new(
|
|
120
133
|
base_url: "#{Api::Ats::SERVICE_BASE_URL}/pub/v1",
|
|
121
134
|
auth: {
|
|
122
135
|
type: :basic,
|
|
@@ -127,7 +140,7 @@ module Aspera
|
|
|
127
140
|
end
|
|
128
141
|
|
|
129
142
|
def ats_api_v2_auth_ibm(rest_add_headers = {})
|
|
130
|
-
return Rest.new(
|
|
143
|
+
return Rest::Client.new(
|
|
131
144
|
base_url: "#{Api::Ats::SERVICE_BASE_URL}/v2",
|
|
132
145
|
headers: rest_add_headers,
|
|
133
146
|
auth: {
|
|
@@ -144,25 +157,26 @@ module Aspera
|
|
|
144
157
|
)
|
|
145
158
|
end
|
|
146
159
|
|
|
147
|
-
def action_cluster_show
|
|
160
|
+
def action_cluster_show(server_id: nil, **)
|
|
148
161
|
if options.get_option(:cloud) || options.get_option(:region)
|
|
149
162
|
server_data = server_by_cloud_region
|
|
150
163
|
else
|
|
151
|
-
server_id
|
|
164
|
+
Aspera.assert(server_id, type: Cli::MissingArgument) { 'server_id (or options cloud and region)' }
|
|
152
165
|
server_data = @ats_api_open.all_servers.find { |i| i['id'].eql?(server_id) }
|
|
153
166
|
raise BadIdentifier.new('server', server_id) if server_data.nil?
|
|
154
167
|
end
|
|
155
168
|
Result::SingleObject.new(server_data)
|
|
156
169
|
end
|
|
157
170
|
|
|
158
|
-
def action_access_key_create(
|
|
171
|
+
def action_access_key_create(access_key: {}, **)
|
|
172
|
+
params = access_key
|
|
159
173
|
server_data = nil
|
|
160
174
|
# if transfer_server_id not provided, get it from command line options
|
|
161
175
|
if !params.key?('transfer_server_id')
|
|
162
176
|
server_data = server_by_cloud_region
|
|
163
177
|
params['transfer_server_id'] = server_data['id']
|
|
164
178
|
end
|
|
165
|
-
Log.log.debug { "using params: #{params}".
|
|
179
|
+
Log.log.debug { "using params: #{params}".bg(:red).white }
|
|
166
180
|
if params.key?('storage')
|
|
167
181
|
case params['storage']['type']
|
|
168
182
|
# here we need somehow to map storage type to field to get for auth end point
|
|
@@ -189,27 +203,17 @@ module Aspera
|
|
|
189
203
|
# TODO : action : modify, with "PUT"
|
|
190
204
|
end
|
|
191
205
|
|
|
192
|
-
def action_access_key_modify(
|
|
206
|
+
def action_access_key_modify(access_key:, access_key_id:, **)
|
|
207
|
+
params = access_key
|
|
193
208
|
params['id'] = access_key_id
|
|
194
209
|
ats_api.update("access_keys/#{access_key_id}", params)
|
|
195
210
|
return Result::Status.new('modified')
|
|
196
211
|
end
|
|
197
212
|
|
|
198
|
-
|
|
199
|
-
ats_api.delete("access_keys/#{access_key_id}")
|
|
200
|
-
Result::Status.new("deleted #{access_key_id}")
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
def action_access_key_entitlement(access_key_id:, **)
|
|
204
|
-
ak = ats_api.read("access_keys/#{access_key_id}")
|
|
205
|
-
api_bss = Api::Alee.new(ak['license']['entitlement_id'], ak['license']['customer_id'])
|
|
206
|
-
return Result::SingleObject.new(api_bss.read('entitlement'))
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
# Build the Node plugin for an ATS access key.
|
|
213
|
+
# access_key > node - mount target: Node plugin for an ATS access key.
|
|
210
214
|
# access_key_id: is already in ctx via arguments: on the :node command.
|
|
211
|
-
# @return [Hash]
|
|
212
|
-
def
|
|
215
|
+
# @return [Array(Node, Hash)] Node plugin and seed ctx for `access_keys do`
|
|
216
|
+
def ak_node_plugin(access_key_id:, **)
|
|
213
217
|
ak_data = ats_api.read("access_keys/#{access_key_id}")
|
|
214
218
|
server_data = @ats_api_open.all_servers.find { |i| i['id'].start_with?(ak_data['transfer_server_id']) }
|
|
215
219
|
Aspera.assert(!server_data.nil?, type: Cli::Error) { 'no such server found' }
|
|
@@ -222,21 +226,7 @@ module Aspera
|
|
|
222
226
|
password: context.secret_finder.lookup(url: node_url, username: access_key_id)
|
|
223
227
|
}
|
|
224
228
|
)
|
|
225
|
-
{
|
|
226
|
-
ak_node_plugin: Node.new(context: context, api: api_node),
|
|
227
|
-
ak_root_file_id: ak_data['root_file_id']
|
|
228
|
-
}
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
# One handler per COMMANDS_GEN4 - delegates to the Node plugin's DSL registry.
|
|
232
|
-
# Pre-resolved arguments (e.g. path:) are forwarded via **ctx to avoid double token consumption.
|
|
233
|
-
Node::COMMANDS_GEN4.each do |cmd|
|
|
234
|
-
define_action_method([:access_key, :node, cmd]) do |ak_node_plugin:, ak_root_file_id:, **ctx|
|
|
235
|
-
# For permission: the handler consumes the path first then re-dispatches to sub-commands.
|
|
236
|
-
# Calling dispatch_from_registry with skip_setup would bypass path consumption and fail.
|
|
237
|
-
next ak_node_plugin.send(:"action_access_keys_do_#{cmd}", do_root_file_id: ak_root_file_id, **ctx) if cmd.eql?(:permission)
|
|
238
|
-
ak_node_plugin.dispatch_from_registry([:access_keys, :do, cmd], {do_root_file_id: ak_root_file_id, **ctx}, skip_setup: true)
|
|
239
|
-
end
|
|
229
|
+
[Node.new(context: context, api: api_node), {do_root_file_id: ak_data['root_file_id']}]
|
|
240
230
|
end
|
|
241
231
|
|
|
242
232
|
def action_api_key_instances
|
|
@@ -245,14 +235,9 @@ module Aspera
|
|
|
245
235
|
Result::ValueList.new(instances['data'], name: 'instance')
|
|
246
236
|
end
|
|
247
237
|
|
|
248
|
-
def action_api_key_delete(api_key_id:, **)
|
|
249
|
-
build_ats_ibm_api_with_instance.delete("api_keys/#{api_key_id}")
|
|
250
|
-
Result::Status.new("deleted #{api_key_id}")
|
|
251
|
-
end
|
|
252
|
-
|
|
253
238
|
def action_access_key_cluster(access_key_id:, **)
|
|
254
239
|
ats_url = ats_api.base_url
|
|
255
|
-
api_ak_auth = Rest.new(
|
|
240
|
+
api_ak_auth = Rest::Client.new(
|
|
256
241
|
base_url: ats_url,
|
|
257
242
|
auth: {
|
|
258
243
|
type: :basic,
|