aspera-cli 4.26.0 → 4.26.2

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 (99) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +36 -4
  4. data/CONTRIBUTING.md +2 -5
  5. data/bin/ascli +2 -2
  6. data/lib/aspera/agent/direct.rb +1 -1
  7. data/lib/aspera/agent/factory.rb +4 -0
  8. data/lib/aspera/agent/httpgw.rb +1 -1
  9. data/lib/aspera/agent/node.rb +2 -2
  10. data/lib/aspera/api/aoc.rb +45 -37
  11. data/lib/aspera/api/cos_node.rb +1 -1
  12. data/lib/aspera/api/faspex.rb +7 -6
  13. data/lib/aspera/api/node.rb +9 -9
  14. data/lib/aspera/ascmd.rb +4 -4
  15. data/lib/aspera/ascp/installation.rb +13 -6
  16. data/lib/aspera/assert.rb +17 -13
  17. data/lib/aspera/cli/context.rb +58 -0
  18. data/lib/aspera/cli/extended_value.rb +9 -4
  19. data/lib/aspera/cli/formatter.rb +91 -187
  20. data/lib/aspera/cli/http.rb +167 -0
  21. data/lib/aspera/cli/manager.rb +132 -77
  22. data/lib/aspera/cli/options.schema.yaml +82 -0
  23. data/lib/aspera/cli/plugins/alee.rb +2 -2
  24. data/lib/aspera/cli/plugins/aoc.rb +113 -77
  25. data/lib/aspera/cli/plugins/ats.rb +16 -16
  26. data/lib/aspera/cli/plugins/base.rb +64 -49
  27. data/lib/aspera/cli/plugins/config.rb +172 -444
  28. data/lib/aspera/cli/plugins/console.rb +7 -7
  29. data/lib/aspera/cli/plugins/cos.rb +2 -2
  30. data/lib/aspera/cli/plugins/factory.rb +3 -0
  31. data/lib/aspera/cli/plugins/faspex.rb +22 -22
  32. data/lib/aspera/cli/plugins/faspex5.rb +68 -49
  33. data/lib/aspera/cli/plugins/faspio.rb +1 -1
  34. data/lib/aspera/cli/plugins/httpgw.rb +2 -2
  35. data/lib/aspera/cli/plugins/node.rb +80 -80
  36. data/lib/aspera/cli/plugins/orchestrator.rb +21 -26
  37. data/lib/aspera/cli/plugins/preview.rb +9 -9
  38. data/lib/aspera/cli/plugins/server.rb +7 -7
  39. data/lib/aspera/cli/plugins/shares.rb +2 -2
  40. data/lib/aspera/cli/preset_manager.rb +235 -0
  41. data/lib/aspera/cli/result.rb +310 -0
  42. data/lib/aspera/cli/{main.rb → runner.rb} +48 -130
  43. data/lib/aspera/cli/sync_actions.rb +15 -11
  44. data/lib/aspera/cli/terminal_formatter.rb +65 -0
  45. data/lib/aspera/cli/transfer_agent.rb +17 -15
  46. data/lib/aspera/cli/transfer_progress.rb +6 -6
  47. data/lib/aspera/cli/version.rb +1 -1
  48. data/lib/aspera/cli/wizard.rb +5 -6
  49. data/lib/aspera/command_line_builder.rb +22 -18
  50. data/lib/aspera/data_repository.rb +4 -0
  51. data/lib/aspera/dot_container.rb +1 -1
  52. data/lib/aspera/environment.rb +25 -6
  53. data/lib/aspera/faspex_gw.rb +1 -1
  54. data/lib/aspera/formatter_interface.rb +14 -0
  55. data/lib/aspera/hash_ext.rb +6 -0
  56. data/lib/aspera/json_rpc.rb +6 -5
  57. data/lib/aspera/keychain/base.rb +1 -1
  58. data/lib/aspera/keychain/encrypted_hash.rb +1 -1
  59. data/lib/aspera/keychain/factory.rb +1 -1
  60. data/lib/aspera/keychain/macos_security.rb +1 -1
  61. data/lib/aspera/log.rb +10 -5
  62. data/lib/aspera/markdown.rb +4 -1
  63. data/lib/aspera/nagios.rb +2 -2
  64. data/lib/aspera/oauth/base.rb +5 -5
  65. data/lib/aspera/oauth/boot.rb +43 -0
  66. data/lib/aspera/oauth/factory.rb +38 -14
  67. data/lib/aspera/oauth/web.rb +2 -2
  68. data/lib/aspera/oauth.rb +1 -0
  69. data/lib/aspera/persistency_action_once.rb +2 -2
  70. data/lib/aspera/preview/file_types.rb +4 -0
  71. data/lib/aspera/products/connect.rb +3 -0
  72. data/lib/aspera/products/transferd.rb +2 -2
  73. data/lib/aspera/proxy_auto_config.rb +6 -3
  74. data/lib/aspera/rest.rb +9 -5
  75. data/lib/aspera/rest_error_analyzer.rb +4 -0
  76. data/lib/aspera/rest_list.rb +10 -3
  77. data/lib/aspera/schema/IBM Aspera Faspex API-5.0-enhanced.yaml +62811 -0
  78. data/lib/aspera/schema/IBM Aspera on Cloud API-0.2.6-enhanced.yaml +9637 -0
  79. data/lib/aspera/schema/async_tables.yaml +361 -0
  80. data/lib/aspera/schema/documentation.rb +107 -0
  81. data/lib/aspera/schema/reader.rb +75 -0
  82. data/lib/aspera/schema/registry.rb +70 -0
  83. data/lib/aspera/secret_hider.rb +4 -0
  84. data/lib/aspera/sync/conf.schema.yaml +0 -26
  85. data/lib/aspera/sync/database.rb +14 -10
  86. data/lib/aspera/sync/operations.rb +14 -10
  87. data/lib/aspera/temp_file_manager.rb +4 -0
  88. data/lib/aspera/transfer/faux_file.rb +1 -1
  89. data/lib/aspera/transfer/parameters.rb +4 -4
  90. data/lib/aspera/transfer/resumer.rb +2 -2
  91. data/lib/aspera/transfer/spec.rb +3 -3
  92. data/lib/aspera/transfer/spec.schema.yaml +18 -9
  93. data/lib/aspera/transfer/uri.rb +1 -1
  94. data/lib/aspera/uri_reader.rb +1 -1
  95. data/lib/aspera/yaml.rb +4 -2
  96. data.tar.gz.sig +0 -0
  97. metadata +28 -15
  98. metadata.gz.sig +1 -1
  99. data/lib/aspera/transfer/spec_doc.rb +0 -76
@@ -89,27 +89,27 @@ module Aspera
89
89
  end
90
90
  end
91
91
  res = ats_api.create('access_keys', params)
92
- return Main.result_single_object(res)
92
+ return Result::SingleObject.new(res)
93
93
  # TODO : action : modify, with "PUT"
94
94
  when :list
95
95
  params = query_read_delete(default: {'offset' => 0, 'max_results' => 1000})
96
96
  res = ats_api.read('access_keys', params)
97
- return Main.result_object_list(res['data'], fields: ['name', 'id', 'created.at', 'modified.at'])
97
+ return Result::ObjectList.new(res['data'], fields: ['name', 'id', 'created.at', 'modified.at'])
98
98
  when :show
99
99
  res = ats_api.read("access_keys/#{access_key_id}")
100
- return Main.result_single_object(res)
100
+ return Result::SingleObject.new(res)
101
101
  when :modify
102
102
  params = value_create_modify(command: command)
103
103
  params['id'] = access_key_id
104
104
  ats_api.update("access_keys/#{access_key_id}", params)
105
- return Main.result_status('modified')
105
+ return Result::Status.new('modified')
106
106
  when :entitlement
107
107
  ak = ats_api.read("access_keys/#{access_key_id}")
108
108
  api_bss = Api::Alee.new(ak['license']['entitlement_id'], ak['license']['customer_id'])
109
- return Main.result_single_object(api_bss.read('entitlement'))
109
+ return Result::SingleObject.new(api_bss.read('entitlement'))
110
110
  when :delete
111
111
  ats_api.delete("access_keys/#{access_key_id}")
112
- return Main.result_status("deleted #{access_key_id}")
112
+ return Result::Status.new("deleted #{access_key_id}")
113
113
  when :node
114
114
  ak_data = ats_api.read("access_keys/#{access_key_id}")
115
115
  server_data = @ats_api_open.all_servers.find{ |i| i['id'].start_with?(ak_data['transfer_server_id'])}
@@ -135,7 +135,7 @@ module Aspera
135
135
  password: config.lookup_secret(url: ats_url, username: access_key_id)
136
136
  }
137
137
  )
138
- return Main.result_single_object(api_ak_auth.read('servers'))
138
+ return Result::SingleObject.new(api_ak_auth.read('servers'))
139
139
  else Aspera.error_unexpected_value(command)
140
140
  end
141
141
  end
@@ -144,9 +144,9 @@ module Aspera
144
144
  command = options.get_next_command(%i[clouds list show])
145
145
  case command
146
146
  when :clouds
147
- return Main.result_object_list(@ats_api_open.cloud_names.map{ |k, v| CLOUD_TABLE.zip([k, v]).to_h})
147
+ return Result::ObjectList.new(@ats_api_open.cloud_names.map{ |k, v| CLOUD_TABLE.zip([k, v]).to_h})
148
148
  when :list
149
- return Main.result_object_list(@ats_api_open.all_servers, fields: %w[id cloud region])
149
+ return Result::ObjectList.new(@ats_api_open.all_servers, fields: %w[id cloud region])
150
150
  when :show
151
151
  if options.get_option(:cloud) || options.get_option(:region)
152
152
  server_data = server_by_cloud_region
@@ -155,7 +155,7 @@ module Aspera
155
155
  server_data = @ats_api_open.all_servers.find{ |i| i['id'].eql?(server_id)}
156
156
  raise BadIdentifier.new('server', server_id) if server_data.nil?
157
157
  end
158
- return Main.result_single_object(server_data)
158
+ return Result::SingleObject.new(server_data)
159
159
  end
160
160
  end
161
161
 
@@ -195,19 +195,19 @@ module Aspera
195
195
  when :instances
196
196
  instances = ats_ibm_api.read('instances')
197
197
  Log.log.warn{"more instances remaining: #{instances['remaining']}"} unless instances['remaining'].to_i.eql?(0)
198
- return Main.result_value_list(instances['data'], name: 'instance')
198
+ return Result::ValueList.new(instances['data'], name: 'instance')
199
199
  when :create
200
200
  created_key = ats_ibm_api.create('api_keys', value_create_modify(command: command, default: {}))
201
- return Main.result_single_object(created_key)
201
+ return Result::SingleObject.new(created_key)
202
202
  when :list # list known api keys in ATS (this require an api_key ...)
203
203
  res = ats_ibm_api.read('api_keys', {'offset' => 0, 'max_results' => 1000})
204
- return Main.result_value_list(res['data'], name: 'ats_id')
204
+ return Result::ValueList.new(res['data'], name: 'ats_id')
205
205
  when :show # show one of api_key in ATS
206
206
  res = ats_ibm_api.read("api_keys/#{concerned_id}")
207
- return Main.result_single_object(res)
207
+ return Result::SingleObject.new(res)
208
208
  when :delete
209
209
  ats_ibm_api.delete("api_keys/#{concerned_id}")
210
- return Main.result_status("deleted #{concerned_id}")
210
+ return Result::Status.new("deleted #{concerned_id}")
211
211
  else Aspera.error_unexpected_value(command)
212
212
  end
213
213
  end
@@ -228,7 +228,7 @@ module Aspera
228
228
  return execute_action_api_key
229
229
  when :aws_trust_policy
230
230
  res = ats_api.read('aws/trustpolicy', {region: options.get_option(:region, mandatory: true)})
231
- return Main.result_single_object(res)
231
+ return Result::SingleObject.new(res)
232
232
  else Aspera.error_unexpected_value(command)
233
233
  end
234
234
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'aspera/cli/extended_value'
4
4
  require 'aspera/assert'
5
+ require 'aspera/cli/result'
5
6
 
6
7
  module Aspera
7
8
  module Cli
@@ -37,16 +38,20 @@ module Aspera
37
38
  # Global objects
38
39
  attr_reader :context
39
40
 
40
- # @return [Manager]
41
+ # @return [Aspera::Cli::Manager]
41
42
  def options; @context.options; end
42
- # @return [TransferAgent]
43
+ # @return [Aspera::Cli::TransferAgent]
43
44
  def transfer; @context.transfer; end
44
- # @return [Config]
45
+ # @return [Aspera::Cli::Plugins::Config]
45
46
  def config; @context.config; end
46
- # @return [Formatter]
47
+ # @return [Aspera::Cli::Formatter]
47
48
  def formatter; @context.formatter; end
48
- # @return [PersistencyFolder]
49
+ # @return [Aspera::PersistencyFolder]
49
50
  def persistency; @context.persistency; end
51
+ # @return [Aspera::Cli::PresetManager]
52
+ def presets; @context.presets; end
53
+ # @return [Aspera::Cli::Http]
54
+ def http_config; @context.http_config; end
50
55
 
51
56
  def add_manual_header(has_options = true)
52
57
  # Manual header for all plugins
@@ -57,20 +62,23 @@ module Aspera
57
62
  end
58
63
 
59
64
  # For create and delete operations: execute one action or multiple if bulk is yes
60
- # @param command [Symbol] Operation: :create, :delete, ...
61
- # @param descr [String] Description of the value
62
- # @param values [Object] Value(s), or type of value to get from user
63
- # @param id_result [String] Key in result hash to use as identifier
64
- # @param fields [Array] Fields to display
65
- # @param block [Proc] Block to execute for each value
66
- def do_bulk_operation(command:, descr: nil, values: Hash, id_result: 'id', fields: :default, &block)
67
- Aspera.assert(block_given?){'missing block'}
65
+ # @param command [Symbol] Operation: :create, :delete, ...
66
+ # @param descr [String, nil] Description of the value
67
+ # @param values [Class, Array, Symbol] Type, or list of values, or :identifier, result is given to the block in loop
68
+ # @param id_result [String] Key in result Hash to use as identifier
69
+ # @param fields [Symbol, Array] Fields to display
70
+ # @param schema [Hash, nil] JSON schema for validation
71
+ # @yieldparam param [Object] The parameter value to process
72
+ # @yieldreturn [Hash, nil] Result hash for the operation (optional)
73
+ # @return [Hash] Result suitable for CLI output
74
+ def do_bulk_operation(command:, descr: nil, values: Hash, id_result: 'id', fields: :default, schema: nil, &block)
75
+ Aspera.assert(block_given?, 'missing block')
68
76
  is_bulk = options.get_option(:bulk)
69
77
  case values
70
78
  when :identifier
71
79
  values = options.instance_identifier(description: descr)
72
80
  when Class
73
- values = value_create_modify(command: command, description: descr, type: values, bulk: is_bulk)
81
+ values = value_create_modify(command: command, description: descr, type: values, bulk: is_bulk, schema: schema)
74
82
  end
75
83
  # If not bulk, there is a single value
76
84
  params = is_bulk ? values : [values]
@@ -97,23 +105,25 @@ module Aspera
97
105
  end
98
106
  display_fields = [id_result, 'status']
99
107
  if is_bulk
100
- return Main.result_object_list(result_list, fields: display_fields)
108
+ return Result::ObjectList.new(result_list, fields: display_fields)
101
109
  else
102
110
  display_fields = fields unless fields.eql?(:default)
103
- return Main.result_single_object(result_list.first, fields: display_fields)
111
+ return Result::SingleObject.new(result_list.first, fields: display_fields)
104
112
  end
105
113
  end
106
114
 
107
115
  # Operations: Create, Delete, Show, List, Modify
108
- # @param api [Rest] api to use
109
- # @param entity [String] sub path in URL to resource relative to base url
110
- # @param command [Symbol] command to execute: create show list modify delete
111
- # @param display_fields [Array] fields to display by default
112
- # @param items_key [String] result is in a sub key of the json
113
- # @param delete_style [String] If set, the delete operation by array in payload
114
- # @param id_as_arg [String] If set, the id is provided as url argument ?<id_as_arg>=<id>
115
- # @param is_singleton [Boolean] If `true`, entity is the full path to the resource
116
- # @param &block [Proc] Block to search for identifier based on attribute value
116
+ # @param api [Aspera::Rest] API to use
117
+ # @param entity [String] Sub path in URL to resource relative to base url
118
+ # @param command [Symbol, nil] Command to execute: :create, :show, :list, :modify, :delete
119
+ # @param display_fields [Array, nil] Fields to display by default
120
+ # @param items_key [String, nil] Result is in a sub key of the JSON
121
+ # @param delete_style [String, nil] If set, the delete operation by array in payload
122
+ # @param id_as_arg [Boolean, String] If set, the id is provided as url argument ?<id_as_arg>=<id>
123
+ # @param is_singleton [Boolean] If `true`, entity is the full path to the resource
124
+ # @param list_query [Hash, nil] Query parameters for list operation
125
+ # @yieldparam value [String] Value to search for identifier
126
+ # @yieldreturn [String] The identifier
117
127
  # @return [Hash] Result suitable for CLI result
118
128
  def entity_execute(
119
129
  api:,
@@ -125,6 +135,7 @@ module Aspera
125
135
  id_as_arg: false,
126
136
  is_singleton: false,
127
137
  list_query: nil,
138
+ schema: nil,
128
139
  &block
129
140
  )
130
141
  command = options.get_next_command(Operations::ALL) if command.nil?
@@ -139,7 +150,7 @@ module Aspera
139
150
  case command
140
151
  when :create
141
152
  raise BadArgument, 'cannot create singleton' if is_singleton
142
- return do_bulk_operation(command: command, descr: 'data', fields: display_fields) do |params|
153
+ return do_bulk_operation(command: command, descr: 'data', fields: display_fields, schema: schema) do |params|
143
154
  api.create(entity, params)
144
155
  end
145
156
  when :delete
@@ -153,17 +164,17 @@ module Aspera
153
164
  content_type: Mime::JSON,
154
165
  body: {delete_style => one_res_id}
155
166
  )
156
- return Main.result_status('deleted')
167
+ return Result::Status.new('deleted')
157
168
  end
158
169
  return do_bulk_operation(command: command, values: one_res_id) do |one_id|
159
170
  api.delete("#{entity}/#{one_id}", query_read_delete)
160
171
  {'id' => one_id}
161
172
  end
162
173
  when :show
163
- return Main.result_single_object(api.read(one_res_path), fields: display_fields)
174
+ return Result::SingleObject.new(api.read(one_res_path), fields: display_fields)
164
175
  when :list
165
176
  data, http = api.read(entity, query_read_delete, ret: :both)
166
- return Main.result_empty if http.code == '204'
177
+ return Result::Empty.new if http.code == '204'
167
178
  # TODO: not generic : which application is this for ?
168
179
  if http['Content-Type'].start_with?('application/vnd.api+json')
169
180
  Log.log.debug('is vnd.api')
@@ -172,23 +183,25 @@ module Aspera
172
183
  data = data[items_key] if items_key
173
184
  case data
174
185
  when Hash
175
- return Main.result_single_object(data, fields: display_fields)
186
+ return Result::SingleObject.new(data, fields: display_fields)
176
187
  when Array
177
- return Main.result_object_list(data, fields: display_fields) if data.empty? || data.first.is_a?(Hash)
178
- return Main.result_value_list(data)
188
+ return Result::ObjectList.new(data, fields: display_fields) if data.empty? || data.first.is_a?(Hash)
189
+ return Result::ValueList.new(data)
179
190
  else
180
191
  Aspera.error_unexpected_value(data.class.name){'list type'}
181
192
  end
182
193
  when :modify
183
- parameters = value_create_modify(command: command)
194
+ parameters = value_create_modify(command: command, schema: schema)
184
195
  api.update(one_res_path, parameters)
185
- return Main.result_status('modified')
196
+ return Result::Status.new('modified')
186
197
  else
187
198
  Aspera.error_unexpected_value(command){'command'}
188
199
  end
189
200
  end
190
201
 
191
202
  # Query parameters in URL suitable for REST: list/`GET` and delete/`DELETE`
203
+ # @param default [Hash, nil] Default query parameters
204
+ # @return [Hash, nil] Query parameters
192
205
  def query_read_delete(default: nil)
193
206
  # Dup default, as it could be frozen
194
207
  query = options.get_option(:query) || default.dup
@@ -202,27 +215,29 @@ module Aspera
202
215
  return query
203
216
  end
204
217
 
205
- # Retrieves an extended value from command line, used for creation or modification of entities
206
- # @param command [Symbol] command name for error message
207
- # @param type [Class] expected type of value, either a Class, an Array of Class
208
- # @param bulk [Boolean] if true, value must be an Array of <type>
209
- # @param default [Object] default value if not provided
210
- def value_create_modify(command:, description: nil, type: Hash, bulk: false, default: nil)
218
+ # Retrieves an extended value from command line.
219
+ # Used for creation or modification of entities.
220
+ # @param command [Symbol] Command name for error message
221
+ # @param description [String, nil] Description of the value
222
+ # @param type [Class, nil] Expected type of value
223
+ # @param bulk [Boolean] If `true`, value must be an Array of `type`
224
+ # @param default [Object, nil] Default value if not provided
225
+ # @param schema [Hash, nil] JSON schema for validation
226
+ # @return [Hash, Array<Hash>] The value(s) to create object(s)
227
+ def value_create_modify(command:, description: nil, type: Hash, bulk: false, default: nil, schema: nil)
211
228
  value = options.get_next_argument(
212
- "parameters for #{command}#{" (#{description})" unless description.nil?}", mandatory: default.nil?,
213
- validation: bulk ? Array : type
229
+ "parameters for #{command}#{" (#{description})" unless description.nil?}",
230
+ mandatory: default.nil?,
231
+ validation: bulk ? Array : type,
232
+ schema: schema
214
233
  )
215
234
  value = default if value.nil?
216
235
  unless type.nil?
217
- type = [type] unless type.is_a?(Array)
218
- Aspera.assert_array_all(type, Class){'check types'}
236
+ Aspera.assert_type(type, Class){'type'}
219
237
  if bulk
220
- Aspera.assert_type(value, Array, type: Cli::BadArgument)
221
- value.each do |v|
222
- Aspera.assert_values(v.class, type, type: Cli::BadArgument)
223
- end
238
+ Aspera.assert_array_all(value, type, type: Cli::BadArgument){'type'}
224
239
  else
225
- Aspera.assert_values(value.class, type, type: Cli::BadArgument)
240
+ Aspera.assert_type(value, type, type: Cli::BadArgument){'type'}
226
241
  end
227
242
  end
228
243
  return value