aspera-cli 4.27.2 → 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.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +50 -0
  4. data/bin/ascli +2 -1
  5. data/docs/README.md +804 -746
  6. data/lib/aspera/agent/connect.rb +6 -4
  7. data/lib/aspera/agent/desktop.rb +2 -2
  8. data/lib/aspera/agent/direct.rb +3 -1
  9. data/lib/aspera/agent/node.rb +3 -3
  10. data/lib/aspera/api/alee.rb +1 -1
  11. data/lib/aspera/api/aoc.rb +14 -12
  12. data/lib/aspera/api/ats.rb +1 -1
  13. data/lib/aspera/api/cos_node.rb +2 -2
  14. data/lib/aspera/api/faspex.rb +9 -7
  15. data/lib/aspera/api/httpgw.rb +37 -33
  16. data/lib/aspera/api/node.rb +38 -33
  17. data/lib/aspera/ascmd.rb +3 -1
  18. data/lib/aspera/ascp/installation.rb +62 -27
  19. data/lib/aspera/ascp/management.rb +1 -0
  20. data/lib/aspera/assert.rb +4 -0
  21. data/lib/aspera/cli/ascp_actions.rb +20 -41
  22. data/lib/aspera/cli/async_transfer_store.rb +2 -2
  23. data/lib/aspera/cli/bootstrapper.rb +11 -15
  24. data/lib/aspera/cli/command_line.rb +252 -0
  25. data/lib/aspera/cli/command_registry.rb +149 -33
  26. data/lib/aspera/cli/command_spec.rb +103 -14
  27. data/lib/aspera/cli/completion/ascli.bash +12 -0
  28. data/lib/aspera/cli/completion/ascli.fish +16 -0
  29. data/lib/aspera/cli/completion/ascli.zsh +19 -0
  30. data/lib/aspera/cli/context.rb +3 -0
  31. data/lib/aspera/cli/deprecation.rb +37 -0
  32. data/lib/aspera/cli/extended_value.rb +2 -0
  33. data/lib/aspera/cli/formatter.rb +87 -75
  34. data/lib/aspera/cli/gem_checker.rb +1 -1
  35. data/lib/aspera/cli/hints.rb +7 -6
  36. data/lib/aspera/cli/http.rb +21 -21
  37. data/lib/aspera/cli/info.rb +3 -0
  38. data/lib/aspera/cli/mcp_tool.rb +47 -83
  39. data/lib/aspera/cli/option_declarator.rb +33 -42
  40. data/lib/aspera/cli/option_registry.rb +69 -0
  41. data/lib/aspera/cli/option_types.rb +103 -0
  42. data/lib/aspera/cli/option_value.rb +281 -0
  43. data/lib/aspera/cli/options.schema.yaml +38 -5
  44. data/lib/aspera/cli/parser.rb +307 -848
  45. data/lib/aspera/cli/plugins/alee.rb +7 -4
  46. data/lib/aspera/cli/plugins/aoc.rb +430 -380
  47. data/lib/aspera/cli/plugins/ats.rb +58 -73
  48. data/lib/aspera/cli/plugins/base.rb +190 -240
  49. data/lib/aspera/cli/plugins/basic_auth.rb +2 -10
  50. data/lib/aspera/cli/plugins/config.rb +244 -178
  51. data/lib/aspera/cli/plugins/console.rb +102 -38
  52. data/lib/aspera/cli/plugins/cos.rb +6 -23
  53. data/lib/aspera/cli/plugins/factory.rb +3 -0
  54. data/lib/aspera/cli/plugins/faspex5.rb +176 -173
  55. data/lib/aspera/cli/plugins/faspio.rb +5 -10
  56. data/lib/aspera/cli/plugins/httpgw.rb +8 -11
  57. data/lib/aspera/cli/plugins/mcp.rb +20 -55
  58. data/lib/aspera/cli/plugins/node.rb +277 -311
  59. data/lib/aspera/cli/plugins/orchestrator.rb +90 -77
  60. data/lib/aspera/cli/plugins/preview.rb +79 -90
  61. data/lib/aspera/cli/plugins/server.rb +76 -50
  62. data/lib/aspera/cli/plugins/shares.rb +68 -116
  63. data/lib/aspera/cli/preset_actions.rb +17 -10
  64. data/lib/aspera/cli/preset_manager.rb +12 -2
  65. data/lib/aspera/cli/prompt.rb +35 -0
  66. data/lib/aspera/cli/result.rb +13 -18
  67. data/lib/aspera/cli/runner.rb +31 -54
  68. data/lib/aspera/cli/special_values.rb +5 -0
  69. data/lib/aspera/cli/sync_actions.rb +41 -37
  70. data/lib/aspera/cli/terminal_formatter.rb +9 -3
  71. data/lib/aspera/cli/transfer_actions.rb +0 -6
  72. data/lib/aspera/cli/transfer_agent.rb +29 -35
  73. data/lib/aspera/cli/vault_manager.rb +0 -17
  74. data/lib/aspera/cli/version.rb +1 -1
  75. data/lib/aspera/cli/wizard.rb +4 -2
  76. data/lib/aspera/coverage.rb +1 -0
  77. data/lib/aspera/environment.rb +6 -0
  78. data/lib/aspera/faspex_gw.rb +2 -1
  79. data/lib/aspera/faspex_postproc.rb +1 -0
  80. data/lib/aspera/graphql.rb +5 -5
  81. data/lib/aspera/json_rpc/client.rb +5 -5
  82. data/lib/aspera/keychain/encrypted_hash.rb +1 -1
  83. data/lib/aspera/keychain/one_password_api.rb +1 -1
  84. data/lib/aspera/link_header.rb +2 -2
  85. data/lib/aspera/log.rb +22 -25
  86. data/lib/aspera/markdown.rb +2 -0
  87. data/lib/aspera/mime.rb +25 -0
  88. data/lib/aspera/node_simulator.rb +1 -0
  89. data/lib/aspera/oauth/base.rb +35 -25
  90. data/lib/aspera/oauth/factory.rb +1 -0
  91. data/lib/aspera/oauth/generic.rb +1 -1
  92. data/lib/aspera/oauth/jwt.rb +1 -1
  93. data/lib/aspera/oauth/web.rb +9 -8
  94. data/lib/aspera/preview/file_types.rb +4 -4
  95. data/lib/aspera/preview/generator.rb +7 -0
  96. data/lib/aspera/preview/options.rb +4 -4
  97. data/lib/aspera/preview/terminal.rb +4 -3
  98. data/lib/aspera/preview/utils.rb +9 -6
  99. data/lib/aspera/products/connect.rb +1 -1
  100. data/lib/aspera/rainbow.rb +7 -0
  101. data/lib/aspera/rest/aspera_errors.rb +60 -0
  102. data/lib/aspera/rest/call_error.rb +27 -0
  103. data/lib/aspera/rest/client.rb +514 -0
  104. data/lib/aspera/rest/error_analyzer.rb +113 -0
  105. data/lib/aspera/rest/list.rb +143 -0
  106. data/lib/aspera/rest/parameters.rb +55 -0
  107. data/lib/aspera/rest/util.rb +176 -0
  108. data/lib/aspera/rest.rb +7 -621
  109. data/lib/aspera/schema/IBM Aspera Console-enhanced.yaml +1125 -0
  110. data/lib/aspera/schema/IBM Aspera on Cloud Automation API-1.0.5-enhanced.yaml +2395 -0
  111. data/lib/aspera/schema/documentation.rb +13 -3
  112. data/lib/aspera/schema/registry.rb +18 -1
  113. data/lib/aspera/schema/validator.rb +92 -0
  114. data/lib/aspera/secret_hider.rb +36 -25
  115. data/lib/aspera/string_ext.rb +15 -0
  116. data/lib/aspera/temp_file_manager.rb +6 -5
  117. data/lib/aspera/transfer/parameters.rb +2 -0
  118. data/lib/aspera/transfer/spec.rb +1 -0
  119. data/lib/aspera/uri_reader.rb +11 -11
  120. data/lib/aspera/web_auth/index.html +147 -0
  121. data/lib/aspera/web_auth/server.rb +81 -0
  122. data.tar.gz.sig +0 -0
  123. metadata +39 -7
  124. metadata.gz.sig +0 -0
  125. data/lib/aspera/colors.rb +0 -79
  126. data/lib/aspera/rest_call_error.rb +0 -25
  127. data/lib/aspera/rest_error_analyzer.rb +0 -111
  128. data/lib/aspera/rest_errors_aspera.rb +0 -58
  129. data/lib/aspera/rest_list.rb +0 -136
  130. data/lib/aspera/web_auth.rb +0 -211
@@ -22,7 +22,7 @@ module Aspera
22
22
  error = nil
23
23
  urls.each do |base_url|
24
24
  next unless base_url.start_with?('https://')
25
- api = Rest.new(base_url: base_url, redirect_max: 2)
25
+ api = Rest::Client.new(base_url: base_url, redirect_max: 2)
26
26
  test_endpoint = 'login'
27
27
  http = api.call(
28
28
  operation: 'GET',
@@ -67,27 +67,68 @@ module Aspera
67
67
  }
68
68
  end
69
69
 
70
- def initialize(**_)
71
- super
72
- end
73
-
74
70
  # --- DSL ---
75
71
 
76
- command :health, description: 'Check Console API health', setup: :setup_api
77
- command :transfer, description: 'Manage transfers', setup: :setup_api
72
+ command :health, description: 'Check Console API health'
73
+ command :transfer, description: 'Manage transfers'
74
+ command :endpoint, description: 'Manage endpoints'
75
+ command :ssh_key, description: 'Manage SSH keys'
76
+ command :admin, description: 'Administer Console'
78
77
 
79
78
  commands_under :transfer do
80
79
  command :current, description: 'Manage current transfers'
81
80
  command :smart, description: 'Manage smart transfers'
81
+ command :queue, description: 'Manage transfers of a queue',
82
+ arguments: [{name: :queue_id, type: :identifier}]
83
+ end
84
+
85
+ commands_under :endpoint do
86
+ command :list, description: operation_description(:list, 'endpoint'),
87
+ action: ->(**) { Result::ObjectList.new(api_console.read('endpoints')) }
88
+ end
89
+
90
+ # Payload is not documented in the API: optional
91
+ # command => name of argument
92
+ ADMIN_UPDATES = {email_server_update: :email_server, nodeapi_credentials_update: :credentials}.freeze
93
+ private_constant :ADMIN_UPDATES
94
+
95
+ commands_under :admin do
96
+ command :email_server_update, description: 'Update email server configuration',
97
+ arguments: [{name: ADMIN_UPDATES[:email_server_update], type: Hash, mandatory: false, default: {}}]
98
+ command :nodeapi_credentials_update, description: 'Update Node API credentials',
99
+ arguments: [{name: ADMIN_UPDATES[:nodeapi_credentials_update], type: Hash, mandatory: false, default: {}}]
100
+ end
101
+
102
+ # POST <verb>
103
+ ADMIN_UPDATES.each do |verb, arg|
104
+ define_action_method([:admin, verb]) do |**kwargs|
105
+ api_console.create(verb.to_s, kwargs.fetch(arg))
106
+ Result::Success.new
107
+ end
108
+ end
109
+
110
+ commands_under :ssh_key do
111
+ command :list, description: operation_description(:list, 'SSH key'),
112
+ action: ->(**) { Result::ObjectList.new(api_console.read('ssh_keys')) }
82
113
  end
83
114
 
84
115
  commands_under %i[transfer current] do
85
116
  command :list, description: 'List current transfers'
117
+ command :submit, description: 'Submit a simple transfer',
118
+ arguments: [{name: :transfer, type: Hash, schema: Schema::Registry.req_body(Schema::Registry::CONSOLE, 'transfers.post')}],
119
+ action: ->(transfer:, **) { Result::SingleObject.new(api_console.create('transfers', transfer)) }
86
120
  command :show, description: 'Show a transfer',
87
121
  arguments: [{name: :transfer_id, type: :identifier}],
88
- action: ->(api_console:, transfer_id:, **) { Result::SingleObject.new(api_console.read("transfers/#{transfer_id}")) }
89
- command :files, description: 'List files in a transfer',
90
- arguments: [{name: :transfer_id, type: :identifier}]
122
+ action: ->(transfer_id:, **) { Result::SingleObject.new(api_console.read("transfers/#{transfer_id}")) }
123
+ command(
124
+ :files, description: 'List files in a transfer',
125
+ arguments: [{name: :transfer_id, type: :identifier}],
126
+ action: lambda do |transfer_id:, **|
127
+ query = query_read_delete(default: {})
128
+ query['limit'] ||= 100
129
+ Result::ObjectList.new(api_console.read("transfers/#{transfer_id}/files", query))
130
+ end
131
+ )
91
132
  command :start, description: 'Start a transfer',
92
133
  arguments: [{name: :transfer_id, type: :identifier}]
93
134
  command :pause, description: 'Pause a transfer',
@@ -97,44 +138,77 @@ module Aspera
97
138
  command :resume, description: 'Resume a transfer',
98
139
  arguments: [{name: :transfer_id, type: :identifier}]
99
140
  command :rerun, description: 'Rerun a transfer',
100
- arguments: [{name: :transfer_id, type: :identifier}]
141
+ arguments: [{name: :transfer_id, type: :identifier}],
142
+ action: ->(transfer_id:, **) { Result::SingleObject.new(api_console.create("transfers/#{transfer_id}/rerun", {})) }
101
143
  command :change_rate, description: 'Change transfer rate',
102
- arguments: [{name: :transfer_id, type: :identifier}]
144
+ arguments: [{name: :transfer_id, type: :identifier},
145
+ {name: :rate, type: Hash, schema: Schema::Registry.req_body(Schema::Registry::CONSOLE, 'transfers/{id}/change_rate.put')}]
103
146
  command :change_policy, description: 'Change transfer policy',
147
+ arguments: [{name: :transfer_id, type: :identifier},
148
+ {name: :policy, type: Hash, schema: Schema::Registry.req_body(Schema::Registry::CONSOLE, 'transfers/{id}/change_policy.put')}]
149
+ end
150
+
151
+ commands_under %i[transfer queue] do
152
+ command :list, description: 'List transfers in queue, frontmost first',
153
+ action: ->(queue_id:, **) { Result::ObjectList.new(api_console.read("queues/#{queue_id}/items")) }
154
+ command :move_forwards, description: 'Move transfer forwards in queue',
104
155
  arguments: [{name: :transfer_id, type: :identifier}]
105
- command :move_forwards, description: 'Move transfer forwards',
106
- arguments: [{name: :transfer_id, type: :identifier}]
107
- command :move_back, description: 'Move transfer backwards',
156
+ command :move_back, description: 'Move transfer backwards in queue',
108
157
  arguments: [{name: :transfer_id, type: :identifier}]
109
158
  end
110
159
 
160
+ # PUT queues/<queue_id>/items/<id>/<verb>
161
+ %i[move_forwards move_back].each do |verb|
162
+ define_action_method([:transfer, :queue, verb]) do |queue_id:, transfer_id:, **|
163
+ Result::SingleObject.new(api_console.update("queues/#{queue_id}/items/#{transfer_id}/#{verb}", {}))
164
+ end
165
+ end
166
+
111
167
  # Generate one handler per transfer/current action.
112
168
  # Convention: action_transfer_current_<verb>
113
- # All share the same REST pattern: PATCH transfers/<id>/<verb>.
114
- %i[start pause cancel resume rerun change_rate change_policy move_forwards move_back].each do |verb|
115
- define_action_method([:transfer, :current, verb]) do |api_console:, transfer_id:, **|
116
- Result::SingleObject.new(api_console.update("transfers/#{transfer_id}/#{verb}", query_read_delete))
169
+ # All share the same REST pattern: PUT transfers/<id>/<verb>.
170
+ %i[start pause cancel resume].each do |verb|
171
+ define_action_method([:transfer, :current, verb]) do |transfer_id:, **|
172
+ Result::SingleObject.new(api_console.update("transfers/#{transfer_id}/#{verb}", {}))
173
+ end
174
+ end
175
+
176
+ # PUT transfers/<id>/<verb> with request body
177
+ {change_rate: :rate, change_policy: :policy}.each do |verb, arg|
178
+ define_action_method([:transfer, :current, verb]) do |transfer_id:, **kwargs|
179
+ Result::SingleObject.new(api_console.update("transfers/#{transfer_id}/#{verb}", kwargs.fetch(arg)))
117
180
  end
118
181
  end
119
182
 
120
183
  commands_under %i[transfer smart] do
121
- command :list, description: 'List smart transfers', action: ->(api_console:) { Result::ObjectList.new(api_console.read('smart_transfers')) }
184
+ command :list, description: 'List smart transfers', action: ->(**) { Result::ObjectList.new(api_console.read('smart_transfers')) }
122
185
  command :submit, description: 'Submit a smart transfer',
123
- arguments: [{name: :smart_id}, {name: :transfer_params, type: Hash}]
186
+ arguments: [{name: :smart_id, type: :identifier}, {name: :transfer, type: Hash, schema: Schema::Registry.req_body(Schema::Registry::CONSOLE, 'smart_transfers/{id}.post')}],
187
+ action: ->(smart_id:, transfer:, **) { Result::ObjectList.new(api_console.create("smart_transfers/#{smart_id}", transfer)) }
188
+ command :pause, description: 'Pause a smart transfer',
189
+ arguments: [{name: :smart_id, type: :identifier}],
190
+ action: ->(smart_id:, **) { Result::SingleObject.new(api_console.update("smart_transfers/#{smart_id}/pause", {})) }
124
191
  end
125
192
 
126
- # --- setup ---
193
+ # --- API ---
127
194
 
128
- # Build the Console REST API.
129
- # @return [Hash] ctx with :api_console
130
- def setup_api(**)
131
- {api_console: basic_auth_api('api')}
195
+ # Console REST API, built from CLI options on first use.
196
+ # @return [Rest::Client]
197
+ def api_console
198
+ @api_console ||= basic_auth_api('api')
132
199
  end
133
200
 
134
201
  # --- health ---
135
202
 
136
- def action_health(api_console:)
203
+ def action_health(**)
137
204
  nagios = Nagios.new
205
+ begin
206
+ # Unauthenticated, outside of the API prefix
207
+ Rest::Client.new(base_url: options.get_option(:url, mandatory: true)).read('health/up')
208
+ nagios.add_ok('console process', 'up')
209
+ rescue StandardError => e
210
+ nagios.add_critical('console process', e.to_s)
211
+ end
138
212
  begin
139
213
  api_console.read('ssh_keys')
140
214
  nagios.add_ok('console api', 'accessible')
@@ -146,7 +220,7 @@ module Aspera
146
220
 
147
221
  # --- transfer current ---
148
222
 
149
- def action_transfer_current_list(api_console:)
223
+ def action_transfer_current_list(**)
150
224
  query = query_read_delete(default: {})
151
225
  if query['from'].nil? && query['to'].nil?
152
226
  time_now = Time.now
@@ -160,18 +234,8 @@ module Aspera
160
234
  )
161
235
  end
162
236
 
163
- def action_transfer_current_files(api_console:, transfer_id:, **)
164
- query = query_read_delete(default: {})
165
- query['limit'] ||= 100
166
- Result::ObjectList.new(api_console.read("transfers/#{transfer_id}/files", query))
167
- end
168
-
169
237
  # --- transfer smart ---
170
238
 
171
- def action_transfer_smart_submit(api_console:, smart_id:, transfer_params:, **)
172
- Result::ObjectList.new(api_console.create("smart_transfers/#{smart_id}", transfer_params))
173
- end
174
-
175
239
  private
176
240
 
177
241
  def parse_extended_filter(filter, query)
@@ -11,13 +11,8 @@ module Aspera
11
11
  class Cos < Base
12
12
  application_name 'IBM Cloud Object Storage'
13
13
 
14
- command :node, description: 'Execute COS node commands', setup: :setup_cos_node
15
-
16
- commands_under :node do
17
- Node::COMMANDS_COS.each do |cmd|
18
- command cmd, description: "Node #{cmd} command"
19
- end
20
- end
14
+ command :node, description: 'Execute COS node commands',
15
+ mount: {plugin: Node, instance: :cos_node_plugin, only: Node::COMMANDS_COS}
21
16
 
22
17
  option :bucket, description: 'Bucket name'
23
18
  option :endpoint, description: 'Storage endpoint (URL)'
@@ -29,14 +24,9 @@ module Aspera
29
24
 
30
25
  use_options Node
31
26
 
32
- def initialize(**_)
33
- super
34
- options.parse_options!
35
- end
36
-
37
- # Build the COS Node API and plugin from CLI options.
38
- # @return [Hash] context hash containing :node_plugin
39
- def setup_cos_node(**)
27
+ # node - mount target: build the COS Node API and plugin from CLI options.
28
+ # @return [Node] Node plugin instance on the COS bucket
29
+ def cos_node_plugin(**)
40
30
  # get service credentials, Hash, e.g. @json:@file:...
41
31
  service_credentials = options.get_option(:service_credentials)
42
32
  cos_node_params = {
@@ -53,14 +43,7 @@ module Aspera
53
43
  cos_node_params.merge!(Api::CosNode.parameters_from_svc_credentials(service_credentials, options.get_option(:region, mandatory: true)))
54
44
  end
55
45
  api_node = Api::CosNode.new(**cos_node_params)
56
- {node_plugin: Node.new(context: context, api: api_node)}
57
- end
58
-
59
- # One handler per COMMANDS_COS command - delegates to the Node plugin's dispatch_v3_command.
60
- Node::COMMANDS_COS.each do |cmd|
61
- define_action_method([:node, cmd]) do |node_plugin:|
62
- node_plugin.dispatch_v3_command(cmd)
63
- end
46
+ Node.new(context: context, api: api_node)
64
47
  end
65
48
  end
66
49
  end
@@ -4,6 +4,7 @@ require 'singleton'
4
4
  require 'aspera/assert'
5
5
  require 'aspera/cli/error'
6
6
  require 'aspera/environment'
7
+ require 'aspera/string_ext'
7
8
 
8
9
  module Aspera
9
10
  module Cli
@@ -29,7 +30,9 @@ module Aspera
29
30
  end
30
31
 
31
32
  # add a folder to the list of folders to look for plugins
33
+ # (absolute, as `require` resolves a relative path against $LOAD_PATH)
32
34
  def add_lookup_folder(folder)
35
+ folder = File.expand_path(folder)
33
36
  @lookup_folders.unshift(folder) unless @lookup_folders.include?(folder)
34
37
  end
35
38