aspera-cli 4.26.2 → 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 +310 -21
- data/CONTRIBUTING.md +99 -14
- data/TODO.md +50 -0
- data/bin/ascli +3 -3
- data/docs/README.md +10977 -0
- data/docs/test-mcp-with-ai.md +202 -0
- data/lib/aspera/agent/base.rb +29 -7
- data/lib/aspera/agent/connect.rb +58 -21
- data/lib/aspera/agent/desktop.rb +53 -18
- data/lib/aspera/agent/direct.rb +71 -40
- data/lib/aspera/agent/factory.rb +3 -3
- data/lib/aspera/agent/httpgw.rb +55 -14
- data/lib/aspera/agent/node.rb +34 -2
- data/lib/aspera/agent/transferd.rb +48 -12
- data/lib/aspera/api/alee.rb +1 -1
- data/lib/aspera/api/aoc.rb +42 -44
- data/lib/aspera/api/cos_node.rb +10 -9
- data/lib/aspera/api/faspex.rb +16 -15
- data/lib/aspera/api/httpgw.rb +23 -23
- data/lib/aspera/api/node.rb +51 -70
- data/lib/aspera/api/queries/bss_subscription_account.graphql +18 -0
- data/lib/aspera/api/queries/bss_subscription_usage.graphql +18 -0
- data/lib/aspera/ascmd.rb +32 -30
- data/lib/aspera/ascp/installation.rb +75 -69
- data/lib/aspera/ascp/management.rb +7 -8
- data/lib/aspera/assert.rb +12 -13
- data/lib/aspera/cli/ascp_actions.rb +155 -0
- data/lib/aspera/cli/async_transfer_store.rb +125 -0
- data/lib/aspera/cli/bootstrapper.rb +197 -0
- data/lib/aspera/cli/command_registry.rb +145 -0
- data/lib/aspera/cli/command_spec.rb +141 -0
- data/lib/aspera/cli/context.rb +19 -6
- data/lib/aspera/cli/error.rb +16 -0
- data/lib/aspera/cli/extended_value.rb +27 -26
- data/lib/aspera/cli/formatter.rb +95 -59
- data/lib/aspera/cli/gem_checker.rb +65 -0
- data/lib/aspera/cli/hints.rb +3 -3
- data/lib/aspera/cli/http.rb +74 -30
- data/lib/aspera/cli/info.rb +2 -0
- data/lib/aspera/cli/mailer.rb +97 -0
- data/lib/aspera/cli/mcp_tool.rb +225 -0
- data/lib/aspera/cli/option_declarator.rb +77 -0
- data/lib/aspera/cli/options.schema.yaml +634 -7
- data/lib/aspera/cli/parser.rb +1217 -0
- data/lib/aspera/cli/plugins/alee.rb +20 -22
- data/lib/aspera/cli/plugins/aoc.rb +1178 -881
- data/lib/aspera/cli/plugins/ats.rb +205 -162
- data/lib/aspera/cli/plugins/base.rb +703 -175
- data/lib/aspera/cli/plugins/basic_auth.rb +7 -9
- data/lib/aspera/cli/plugins/config.rb +434 -757
- data/lib/aspera/cli/plugins/console.rb +107 -65
- data/lib/aspera/cli/plugins/cos.rb +46 -33
- data/lib/aspera/cli/plugins/factory.rb +6 -6
- data/lib/aspera/cli/plugins/faspex5.rb +627 -388
- data/lib/aspera/cli/plugins/faspio.rb +54 -51
- data/lib/aspera/cli/plugins/httpgw.rb +18 -25
- data/lib/aspera/cli/plugins/mcp.rb +279 -0
- data/lib/aspera/cli/plugins/node.rb +988 -840
- data/lib/aspera/cli/plugins/oauth.rb +7 -10
- data/lib/aspera/cli/plugins/orchestrator.rb +112 -135
- data/lib/aspera/cli/plugins/preview.rb +195 -157
- data/lib/aspera/cli/plugins/server.rb +141 -91
- data/lib/aspera/cli/plugins/shares.rb +343 -110
- data/lib/aspera/cli/preset_actions.rb +159 -0
- data/lib/aspera/cli/preset_manager.rb +82 -39
- data/lib/aspera/cli/result.rb +78 -26
- data/lib/aspera/cli/runner.rb +323 -153
- data/lib/aspera/cli/secret_finder.rb +40 -0
- data/lib/aspera/cli/special_values.rb +1 -0
- data/lib/aspera/cli/sync_actions.rb +89 -64
- data/lib/aspera/cli/terminal_formatter.rb +3 -3
- data/lib/aspera/cli/transfer_actions.rb +90 -0
- data/lib/aspera/cli/transfer_agent.rb +129 -64
- data/lib/aspera/cli/transfer_progress.rb +9 -9
- data/lib/aspera/cli/vault_manager.rb +79 -0
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/cli/wizard.rb +28 -30
- data/lib/aspera/colors.rb +3 -3
- data/lib/aspera/command_line_builder.rb +34 -34
- data/lib/aspera/command_line_converter.rb +1 -1
- data/lib/aspera/coverage.rb +1 -2
- data/lib/aspera/data_repository.rb +2 -1
- data/lib/aspera/dot_container.rb +12 -12
- data/lib/aspera/environment.rb +30 -23
- data/lib/aspera/exec_spec.rb +13 -0
- data/lib/aspera/faspex_gw.rb +5 -5
- data/lib/aspera/faspex_postproc.rb +16 -10
- data/lib/aspera/graphql.rb +37 -0
- data/lib/aspera/hash_ext.rb +8 -2
- data/lib/aspera/json_rpc/client.rb +62 -0
- data/lib/aspera/json_rpc/version.rb +7 -0
- data/lib/aspera/keychain/base.rb +10 -3
- data/lib/aspera/keychain/encrypted_hash.rb +92 -17
- data/lib/aspera/keychain/factory.rb +20 -8
- 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 +82 -0
- data/lib/aspera/log.rb +29 -15
- data/lib/aspera/markdown.rb +90 -7
- data/lib/aspera/nagios.rb +8 -8
- data/lib/aspera/node_simulator.rb +35 -27
- data/lib/aspera/oauth/base.rb +9 -10
- data/lib/aspera/oauth/boot.rb +5 -5
- data/lib/aspera/oauth/factory.rb +12 -10
- data/lib/aspera/oauth/jwt.rb +9 -11
- data/lib/aspera/oauth/web.rb +6 -6
- data/lib/aspera/persistency_action_once.rb +12 -12
- data/lib/aspera/persistency_folder.rb +18 -11
- data/lib/aspera/preview/file_types.rb +5 -5
- data/lib/aspera/preview/generator.rb +52 -49
- data/lib/aspera/preview/options.rb +3 -2
- data/lib/aspera/preview/terminal.rb +5 -5
- data/lib/aspera/preview/utils.rb +66 -19
- data/lib/aspera/products/connect.rb +2 -2
- data/lib/aspera/products/desktop.rb +1 -1
- data/lib/aspera/products/other.rb +3 -3
- data/lib/aspera/products/transferd.rb +4 -4
- data/lib/aspera/proxy_auto_config.rb +15 -14
- data/lib/aspera/rest.rb +159 -151
- data/lib/aspera/rest_error_analyzer.rb +6 -6
- data/lib/aspera/rest_errors_aspera.rb +0 -10
- data/lib/aspera/rest_list.rb +11 -10
- 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 on Cloud API-0.2.6-enhanced.yaml +1853 -510
- data/lib/aspera/schema/IBM_Aspera_Shares.yaml +4653 -0
- data/lib/aspera/schema/documentation.rb +65 -28
- data/lib/aspera/schema/reader.rb +136 -13
- data/lib/aspera/schema/registry.rb +60 -8
- data/lib/aspera/secret_hider.rb +12 -7
- data/lib/aspera/ssh.rb +64 -31
- data/lib/aspera/ssl.rb +5 -5
- data/lib/aspera/sync/conf.schema.yaml +2 -2
- data/lib/aspera/sync/database.rb +2 -2
- data/lib/aspera/sync/operations.rb +22 -25
- data/lib/aspera/temp_file_manager.rb +25 -5
- data/lib/aspera/timer_limiter.rb +1 -1
- data/lib/aspera/transfer/faux_file.rb +24 -11
- data/lib/aspera/transfer/parameters.rb +36 -34
- data/lib/aspera/transfer/result.rb +74 -0
- data/lib/aspera/transfer/resumer.rb +10 -10
- data/lib/aspera/transfer/spec.rb +18 -1
- data/lib/aspera/transfer/spec.schema.yaml +12 -3
- data/lib/aspera/uri_reader.rb +52 -15
- data/lib/aspera/web_auth.rb +8 -7
- data/lib/aspera/web_server_simple.rb +15 -12
- data/lib/aspera/yaml.rb +5 -4
- data.tar.gz.sig +0 -0
- metadata +34 -6
- metadata.gz.sig +0 -0
- data/lib/aspera/cli/manager.rb +0 -766
- data/lib/aspera/cli/plugins/faspex.rb +0 -539
- data/lib/aspera/json_rpc.rb +0 -52
- data/lib/aspera/transfer/uri.rb +0 -56
|
@@ -15,23 +15,97 @@ module Aspera
|
|
|
15
15
|
# Access Aspera Transfer Service
|
|
16
16
|
# https://developer.ibm.com/aspera/docs/ats-api-reference/creating-ats-api-keys/
|
|
17
17
|
class Ats < Base
|
|
18
|
+
application_name 'Aspera Transfer Service'
|
|
18
19
|
# columns for list of cloud providers
|
|
19
20
|
CLOUD_TABLE = %w[id name].freeze
|
|
20
21
|
private_constant :CLOUD_TABLE
|
|
22
|
+
|
|
23
|
+
option :ibm_api_key, description: 'IBM API key, see https://cloud.ibm.com/iam/apikeys'
|
|
24
|
+
option :instance, description: 'ATS instance in ibm cloud'
|
|
25
|
+
option :ats_key, description: 'ATS key identifier (ats_xxx)'
|
|
26
|
+
option :ats_secret, description: 'ATS key secret'
|
|
27
|
+
option :cloud, description: 'Cloud provider'
|
|
28
|
+
option :region, description: 'Cloud region'
|
|
29
|
+
|
|
30
|
+
use_options Node
|
|
31
|
+
|
|
21
32
|
def initialize(api: nil, **base_args)
|
|
22
33
|
super(**base_args)
|
|
23
34
|
@ats_api_open = Api::Ats.new
|
|
24
35
|
@ats_api_auth = api
|
|
25
|
-
options.declare(:ibm_api_key, 'IBM API key, see https://cloud.ibm.com/iam/apikeys')
|
|
26
|
-
options.declare(:instance, 'ATS instance in ibm cloud')
|
|
27
|
-
options.declare(:ats_key, 'ATS key identifier (ats_xxx)')
|
|
28
|
-
options.declare(:ats_secret, 'ATS key secret')
|
|
29
|
-
options.declare(:cloud, 'Cloud provider')
|
|
30
|
-
options.declare(:region, 'Cloud region')
|
|
31
36
|
options.parse_options!
|
|
32
|
-
Node.declare_options(options)
|
|
33
37
|
end
|
|
34
38
|
|
|
39
|
+
# --- DSL ---
|
|
40
|
+
|
|
41
|
+
command :cluster, description: 'Display general ATS cluster information (public API, no auth)'
|
|
42
|
+
command :access_key, description: 'Manage ATS access keys'
|
|
43
|
+
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: lambda { Result::SingleObject.new(ats_api.read('aws/trustpolicy', {region: options.get_option(:region, mandatory: true)})) }
|
|
45
|
+
|
|
46
|
+
commands_under(:cluster) do
|
|
47
|
+
command :clouds, description: 'List cloud providers', action: lambda { Result::ObjectList.new(@ats_api_open.cloud_names.map { |k, v| CLOUD_TABLE.zip([k, v]).to_h }) }
|
|
48
|
+
command :list, description: 'List ATS servers', action: lambda { Result::ObjectList.new(@ats_api_open.all_servers, fields: %w[id cloud region]) }
|
|
49
|
+
command :show, description: 'Show a specific server'
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
commands_under(:access_key) do
|
|
53
|
+
command :create, description: 'Create an access key',
|
|
54
|
+
arguments: [{name: :params, type: Hash, mandatory: false, default: {}}]
|
|
55
|
+
command(:list, description: 'List access keys', action: lambda do
|
|
56
|
+
res = ats_api.read('access_keys', query_read_delete(default: {'offset' => 0, 'max_results' => 1000}))
|
|
57
|
+
Result::ObjectList.new(res['data'], fields: ['name', 'id', 'created.at', 'modified.at'])
|
|
58
|
+
end)
|
|
59
|
+
command :show, description: 'Show an access key',
|
|
60
|
+
arguments: [{name: :access_key_id, type: :identifier}],
|
|
61
|
+
action: ->(access_key_id:, **) { Result::SingleObject.new(ats_api.read("access_keys/#{access_key_id}")) }
|
|
62
|
+
command :modify, description: 'Modify an access key',
|
|
63
|
+
arguments: [{name: :access_key_id, type: :identifier}, {name: :params, type: Hash}]
|
|
64
|
+
command :delete, description: 'Delete an access key',
|
|
65
|
+
arguments: [{name: :access_key_id, type: :identifier}]
|
|
66
|
+
command :node, description: 'Execute node commands via ATS access key',
|
|
67
|
+
arguments: [{name: :access_key_id, type: :identifier}],
|
|
68
|
+
setup: :setup_ak_node
|
|
69
|
+
command :cluster, description: 'Show cluster info for an access key',
|
|
70
|
+
arguments: [{name: :access_key_id, type: :identifier}]
|
|
71
|
+
command :entitlement, description: 'Show ATS entitlement for an access key',
|
|
72
|
+
arguments: [{name: :access_key_id, type: :identifier}]
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
commands_under %i[access_key node] do
|
|
76
|
+
command :permission, description: 'Manage permissions'
|
|
77
|
+
command :sync, description: 'Synchronize folders'
|
|
78
|
+
Node::COMMANDS_GEN4_SPEC.each do |cmd, spec|
|
|
79
|
+
command cmd, **spec
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
commands_under(:api_key) do
|
|
84
|
+
command(:instances, description: 'List ATS instances in IBM Cloud', action: lambda do
|
|
85
|
+
instances = ats_api_v2_auth_ibm.read('instances')
|
|
86
|
+
Log.log.warn { "more instances remaining: #{instances['remaining']}" } unless instances['remaining'].to_i.eql?(0)
|
|
87
|
+
Result::ValueList.new(instances['data'], name: 'instance')
|
|
88
|
+
end)
|
|
89
|
+
command :create, description: 'Create an ATS API key',
|
|
90
|
+
arguments: [{name: :params, type: Hash, mandatory: false, default: {}}],
|
|
91
|
+
action: ->(params:, **) { Result::SingleObject.new(build_ats_ibm_api_with_instance.create('api_keys', params)) }
|
|
92
|
+
command :list, description: 'List ATS API keys', action: lambda { Result::ValueList.new(build_ats_ibm_api_with_instance.read('api_keys', {'offset' => 0, 'max_results' => 1000})['data'], name: 'ats_id') }
|
|
93
|
+
command :show, description: 'Show an ATS API key',
|
|
94
|
+
arguments: [{name: :api_key_id, type: :identifier}],
|
|
95
|
+
action: ->(api_key_id:, **) { Result::SingleObject.new(build_ats_ibm_api_with_instance.read("api_keys/#{api_key_id}")) }
|
|
96
|
+
command :delete, description: 'Delete an ATS API key',
|
|
97
|
+
arguments: [{name: :api_key_id, type: :identifier}]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# --- conditions ---
|
|
101
|
+
|
|
102
|
+
# api_key sub-tree is only available when authenticated via ATS key (not injected API)
|
|
103
|
+
def api_key_available?
|
|
104
|
+
@ats_api_auth.nil?
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# --- helpers ---
|
|
108
|
+
|
|
35
109
|
def server_by_cloud_region
|
|
36
110
|
# TODO: provide list ?
|
|
37
111
|
cloud = options.get_option(:cloud, mandatory: true).upcase
|
|
@@ -52,113 +126,6 @@ module Aspera
|
|
|
52
126
|
)
|
|
53
127
|
end
|
|
54
128
|
|
|
55
|
-
def execute_action_access_key
|
|
56
|
-
commands = %i[create list show modify delete node cluster entitlement]
|
|
57
|
-
command = options.get_next_command(commands)
|
|
58
|
-
# those do not require access key id
|
|
59
|
-
access_key_id = options.instance_identifier unless %i[create list].include?(command)
|
|
60
|
-
case command
|
|
61
|
-
when :create
|
|
62
|
-
params = value_create_modify(command: command, default: {})
|
|
63
|
-
server_data = nil
|
|
64
|
-
# if transfer_server_id not provided, get it from command line options
|
|
65
|
-
if !params.key?('transfer_server_id')
|
|
66
|
-
server_data = server_by_cloud_region
|
|
67
|
-
params['transfer_server_id'] = server_data['id']
|
|
68
|
-
end
|
|
69
|
-
Log.log.debug{"using params: #{params}".bg_red.gray}
|
|
70
|
-
if params.key?('storage')
|
|
71
|
-
case params['storage']['type']
|
|
72
|
-
# here we need somehow to map storage type to field to get for auth end point
|
|
73
|
-
when 'ibm-s3'
|
|
74
|
-
server_data2 = nil
|
|
75
|
-
if server_data.nil?
|
|
76
|
-
server_data2 = @ats_api_open.all_servers.find{ |s| s['id'].eql?(params['transfer_server_id'])}
|
|
77
|
-
raise "no such transfer server id: #{params['transfer_server_id']}" if server_data2.nil?
|
|
78
|
-
else
|
|
79
|
-
server_data2 = @ats_api_open.all_servers.find do |s|
|
|
80
|
-
s['cloud'].eql?(server_data['cloud']) &&
|
|
81
|
-
s['region'].eql?(server_data['region']) &&
|
|
82
|
-
s.key?('s3_authentication_endpoint')
|
|
83
|
-
end
|
|
84
|
-
raise "no such transfer server id: #{params['transfer_server_id']}" if server_data2.nil?
|
|
85
|
-
# specific one do not have s3 end point in id
|
|
86
|
-
params['transfer_server_id'] = server_data2['id']
|
|
87
|
-
end
|
|
88
|
-
params['storage']['endpoint'] = server_data2['s3_authentication_endpoint'] if !params['storage'].key?('authentication_endpoint')
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
res = ats_api.create('access_keys', params)
|
|
92
|
-
return Result::SingleObject.new(res)
|
|
93
|
-
# TODO : action : modify, with "PUT"
|
|
94
|
-
when :list
|
|
95
|
-
params = query_read_delete(default: {'offset' => 0, 'max_results' => 1000})
|
|
96
|
-
res = ats_api.read('access_keys', params)
|
|
97
|
-
return Result::ObjectList.new(res['data'], fields: ['name', 'id', 'created.at', 'modified.at'])
|
|
98
|
-
when :show
|
|
99
|
-
res = ats_api.read("access_keys/#{access_key_id}")
|
|
100
|
-
return Result::SingleObject.new(res)
|
|
101
|
-
when :modify
|
|
102
|
-
params = value_create_modify(command: command)
|
|
103
|
-
params['id'] = access_key_id
|
|
104
|
-
ats_api.update("access_keys/#{access_key_id}", params)
|
|
105
|
-
return Result::Status.new('modified')
|
|
106
|
-
when :entitlement
|
|
107
|
-
ak = ats_api.read("access_keys/#{access_key_id}")
|
|
108
|
-
api_bss = Api::Alee.new(ak['license']['entitlement_id'], ak['license']['customer_id'])
|
|
109
|
-
return Result::SingleObject.new(api_bss.read('entitlement'))
|
|
110
|
-
when :delete
|
|
111
|
-
ats_api.delete("access_keys/#{access_key_id}")
|
|
112
|
-
return Result::Status.new("deleted #{access_key_id}")
|
|
113
|
-
when :node
|
|
114
|
-
ak_data = ats_api.read("access_keys/#{access_key_id}")
|
|
115
|
-
server_data = @ats_api_open.all_servers.find{ |i| i['id'].start_with?(ak_data['transfer_server_id'])}
|
|
116
|
-
raise Cli::Error, 'no such server found' if server_data.nil?
|
|
117
|
-
node_url = server_data['transfer_setup_url']
|
|
118
|
-
api_node = Api::Node.new(
|
|
119
|
-
base_url: node_url,
|
|
120
|
-
auth: {
|
|
121
|
-
type: :basic,
|
|
122
|
-
username: access_key_id,
|
|
123
|
-
password: config.lookup_secret(url: node_url, username: access_key_id)
|
|
124
|
-
}
|
|
125
|
-
)
|
|
126
|
-
command = options.get_next_command(Node::COMMANDS_GEN4)
|
|
127
|
-
return Node.new(context: context, api: api_node).execute_command_gen4(command, ak_data['root_file_id'])
|
|
128
|
-
when :cluster
|
|
129
|
-
ats_url = ats_api.base_url
|
|
130
|
-
api_ak_auth = Rest.new(
|
|
131
|
-
base_url: ats_url,
|
|
132
|
-
auth: {
|
|
133
|
-
type: :basic,
|
|
134
|
-
username: access_key_id,
|
|
135
|
-
password: config.lookup_secret(url: ats_url, username: access_key_id)
|
|
136
|
-
}
|
|
137
|
-
)
|
|
138
|
-
return Result::SingleObject.new(api_ak_auth.read('servers'))
|
|
139
|
-
else Aspera.error_unexpected_value(command)
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
def execute_action_cluster_open
|
|
144
|
-
command = options.get_next_command(%i[clouds list show])
|
|
145
|
-
case command
|
|
146
|
-
when :clouds
|
|
147
|
-
return Result::ObjectList.new(@ats_api_open.cloud_names.map{ |k, v| CLOUD_TABLE.zip([k, v]).to_h})
|
|
148
|
-
when :list
|
|
149
|
-
return Result::ObjectList.new(@ats_api_open.all_servers, fields: %w[id cloud region])
|
|
150
|
-
when :show
|
|
151
|
-
if options.get_option(:cloud) || options.get_option(:region)
|
|
152
|
-
server_data = server_by_cloud_region
|
|
153
|
-
else
|
|
154
|
-
server_id = options.instance_identifier
|
|
155
|
-
server_data = @ats_api_open.all_servers.find{ |i| i['id'].eql?(server_id)}
|
|
156
|
-
raise BadIdentifier.new('server', server_id) if server_data.nil?
|
|
157
|
-
end
|
|
158
|
-
return Result::SingleObject.new(server_data)
|
|
159
|
-
end
|
|
160
|
-
end
|
|
161
|
-
|
|
162
129
|
def ats_api_v2_auth_ibm(rest_add_headers = {})
|
|
163
130
|
return Rest.new(
|
|
164
131
|
base_url: "#{Api::Ats::SERVICE_BASE_URL}/v2",
|
|
@@ -177,60 +144,136 @@ module Aspera
|
|
|
177
144
|
)
|
|
178
145
|
end
|
|
179
146
|
|
|
180
|
-
def
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
if
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
147
|
+
def action_cluster_show
|
|
148
|
+
if options.get_option(:cloud) || options.get_option(:region)
|
|
149
|
+
server_data = server_by_cloud_region
|
|
150
|
+
else
|
|
151
|
+
server_id = options.instance_identifier
|
|
152
|
+
server_data = @ats_api_open.all_servers.find { |i| i['id'].eql?(server_id) }
|
|
153
|
+
raise BadIdentifier.new('server', server_id) if server_data.nil?
|
|
154
|
+
end
|
|
155
|
+
Result::SingleObject.new(server_data)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def action_access_key_create(params: {}, **)
|
|
159
|
+
server_data = nil
|
|
160
|
+
# if transfer_server_id not provided, get it from command line options
|
|
161
|
+
if !params.key?('transfer_server_id')
|
|
162
|
+
server_data = server_by_cloud_region
|
|
163
|
+
params['transfer_server_id'] = server_data['id']
|
|
164
|
+
end
|
|
165
|
+
Log.log.debug { "using params: #{params}".bg_red.gray }
|
|
166
|
+
if params.key?('storage')
|
|
167
|
+
case params['storage']['type']
|
|
168
|
+
# here we need somehow to map storage type to field to get for auth end point
|
|
169
|
+
when 'ibm-s3'
|
|
170
|
+
server_data2 = nil
|
|
171
|
+
if server_data.nil?
|
|
172
|
+
server_data2 = @ats_api_open.all_servers.find { |s| s['id'].eql?(params['transfer_server_id']) }
|
|
173
|
+
raise "no such transfer server id: #{params['transfer_server_id']}" if server_data2.nil?
|
|
174
|
+
else
|
|
175
|
+
server_data2 = @ats_api_open.all_servers.find do |s|
|
|
176
|
+
s['cloud'].eql?(server_data['cloud']) &&
|
|
177
|
+
s['region'].eql?(server_data['region']) &&
|
|
178
|
+
s.key?('s3_authentication_endpoint')
|
|
179
|
+
end
|
|
180
|
+
raise "no such transfer server id: #{params['transfer_server_id']}" if server_data2.nil?
|
|
181
|
+
# specific one do not have s3 end point in id
|
|
182
|
+
params['transfer_server_id'] = server_data2['id']
|
|
183
|
+
end
|
|
184
|
+
params['storage']['endpoint'] = server_data2['s3_authentication_endpoint'] if !params['storage'].key?('authentication_endpoint')
|
|
190
185
|
end
|
|
191
|
-
rest_add_header = {'X-ATS-Service-Instance-Id' => instance}
|
|
192
186
|
end
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
187
|
+
res = ats_api.create('access_keys', params)
|
|
188
|
+
return Result::SingleObject.new(res)
|
|
189
|
+
# TODO : action : modify, with "PUT"
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def action_access_key_modify(params:, access_key_id:, **)
|
|
193
|
+
params['id'] = access_key_id
|
|
194
|
+
ats_api.update("access_keys/#{access_key_id}", params)
|
|
195
|
+
return Result::Status.new('modified')
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def action_access_key_delete(access_key_id:, **)
|
|
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.
|
|
210
|
+
# access_key_id: is already in ctx via arguments: on the :node command.
|
|
211
|
+
# @return [Hash] context hash containing :ak_node_plugin and :ak_root_file_id
|
|
212
|
+
def setup_ak_node(access_key_id:, **)
|
|
213
|
+
ak_data = ats_api.read("access_keys/#{access_key_id}")
|
|
214
|
+
server_data = @ats_api_open.all_servers.find { |i| i['id'].start_with?(ak_data['transfer_server_id']) }
|
|
215
|
+
Aspera.assert(!server_data.nil?, type: Cli::Error) { 'no such server found' }
|
|
216
|
+
node_url = server_data['transfer_setup_url']
|
|
217
|
+
api_node = Api::Node.new(
|
|
218
|
+
base_url: node_url,
|
|
219
|
+
auth: {
|
|
220
|
+
type: :basic,
|
|
221
|
+
username: access_key_id,
|
|
222
|
+
password: context.secret_finder.lookup(url: node_url, username: access_key_id)
|
|
223
|
+
}
|
|
224
|
+
)
|
|
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)
|
|
212
239
|
end
|
|
213
240
|
end
|
|
214
241
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
242
|
+
def action_api_key_instances
|
|
243
|
+
instances = ats_api_v2_auth_ibm.read('instances')
|
|
244
|
+
Log.log.warn { "more instances remaining: #{instances['remaining']}" } unless instances['remaining'].to_i.eql?(0)
|
|
245
|
+
Result::ValueList.new(instances['data'], name: 'instance')
|
|
246
|
+
end
|
|
247
|
+
|
|
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
|
+
def action_access_key_cluster(access_key_id:, **)
|
|
254
|
+
ats_url = ats_api.base_url
|
|
255
|
+
api_ak_auth = Rest.new(
|
|
256
|
+
base_url: ats_url,
|
|
257
|
+
auth: {
|
|
258
|
+
type: :basic,
|
|
259
|
+
username: access_key_id,
|
|
260
|
+
password: context.secret_finder.lookup(url: ats_url, username: access_key_id)
|
|
261
|
+
}
|
|
262
|
+
)
|
|
263
|
+
return Result::SingleObject.new(api_ak_auth.read('servers'))
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
private
|
|
267
|
+
|
|
268
|
+
# Build the IBM Cloud ATS v2 API with an instance header.
|
|
269
|
+
# Reads instance from options; falls back to first available instance.
|
|
270
|
+
def build_ats_ibm_api_with_instance
|
|
271
|
+
instance = options.get_option(:instance)
|
|
272
|
+
if instance.nil?
|
|
273
|
+
instance = ats_api_v2_auth_ibm.read('instances')['data'].first
|
|
274
|
+
formatter.display_status("using first instance: #{instance}")
|
|
233
275
|
end
|
|
276
|
+
ats_api_v2_auth_ibm({'X-ATS-Service-Instance-Id' => instance})
|
|
234
277
|
end
|
|
235
278
|
end
|
|
236
279
|
end
|