aspera-cli 4.26.1 → 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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +19 -1
- data/CONTRIBUTING.md +2 -5
- data/bin/ascli +2 -2
- data/lib/aspera/agent/direct.rb +1 -1
- data/lib/aspera/agent/factory.rb +4 -0
- data/lib/aspera/agent/httpgw.rb +1 -1
- data/lib/aspera/agent/node.rb +2 -2
- data/lib/aspera/api/aoc.rb +43 -36
- data/lib/aspera/api/cos_node.rb +1 -1
- data/lib/aspera/api/faspex.rb +7 -6
- data/lib/aspera/api/node.rb +7 -7
- data/lib/aspera/ascmd.rb +4 -4
- data/lib/aspera/ascp/installation.rb +6 -2
- data/lib/aspera/cli/context.rb +58 -0
- data/lib/aspera/cli/extended_value.rb +3 -2
- data/lib/aspera/cli/formatter.rb +83 -184
- data/lib/aspera/cli/http.rb +167 -0
- data/lib/aspera/cli/manager.rb +3 -2
- data/lib/aspera/cli/plugins/alee.rb +2 -2
- data/lib/aspera/cli/plugins/aoc.rb +78 -67
- data/lib/aspera/cli/plugins/ats.rb +16 -16
- data/lib/aspera/cli/plugins/base.rb +18 -12
- data/lib/aspera/cli/plugins/config.rb +166 -438
- data/lib/aspera/cli/plugins/console.rb +7 -7
- data/lib/aspera/cli/plugins/cos.rb +2 -2
- data/lib/aspera/cli/plugins/factory.rb +3 -0
- data/lib/aspera/cli/plugins/faspex.rb +21 -21
- data/lib/aspera/cli/plugins/faspex5.rb +64 -44
- data/lib/aspera/cli/plugins/faspio.rb +1 -1
- data/lib/aspera/cli/plugins/httpgw.rb +2 -2
- data/lib/aspera/cli/plugins/node.rb +79 -79
- data/lib/aspera/cli/plugins/orchestrator.rb +21 -26
- data/lib/aspera/cli/plugins/preview.rb +9 -9
- data/lib/aspera/cli/plugins/server.rb +7 -7
- data/lib/aspera/cli/plugins/shares.rb +2 -2
- data/lib/aspera/cli/preset_manager.rb +235 -0
- data/lib/aspera/cli/result.rb +310 -0
- data/lib/aspera/cli/{main.rb → runner.rb} +14 -155
- data/lib/aspera/cli/sync_actions.rb +14 -10
- data/lib/aspera/cli/terminal_formatter.rb +65 -0
- data/lib/aspera/cli/transfer_progress.rb +6 -6
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/cli/wizard.rb +5 -6
- data/lib/aspera/command_line_builder.rb +1 -1
- data/lib/aspera/data_repository.rb +4 -0
- data/lib/aspera/dot_container.rb +1 -1
- data/lib/aspera/environment.rb +22 -3
- data/lib/aspera/faspex_gw.rb +1 -1
- data/lib/aspera/json_rpc.rb +6 -5
- data/lib/aspera/keychain/base.rb +1 -1
- data/lib/aspera/keychain/encrypted_hash.rb +1 -1
- data/lib/aspera/keychain/factory.rb +1 -1
- data/lib/aspera/keychain/macos_security.rb +1 -1
- data/lib/aspera/log.rb +6 -2
- data/lib/aspera/nagios.rb +2 -2
- data/lib/aspera/oauth/base.rb +5 -5
- data/lib/aspera/oauth/boot.rb +43 -0
- data/lib/aspera/oauth/factory.rb +37 -13
- data/lib/aspera/oauth/web.rb +2 -2
- data/lib/aspera/oauth.rb +1 -0
- data/lib/aspera/persistency_action_once.rb +2 -2
- data/lib/aspera/preview/file_types.rb +4 -0
- data/lib/aspera/products/connect.rb +3 -0
- data/lib/aspera/products/transferd.rb +2 -2
- data/lib/aspera/proxy_auto_config.rb +3 -3
- data/lib/aspera/rest.rb +8 -4
- data/lib/aspera/rest_error_analyzer.rb +4 -0
- data/lib/aspera/rest_list.rb +10 -3
- data/lib/aspera/schema/IBM Aspera Faspex API-5.0-enhanced.yaml +14 -4
- data/lib/aspera/schema/IBM Aspera on Cloud API-0.2.6-enhanced.yaml +827 -88
- data/lib/aspera/schema/async_tables.yaml +361 -0
- data/lib/aspera/schema/reader.rb +1 -1
- data/lib/aspera/schema/registry.rb +13 -6
- data/lib/aspera/secret_hider.rb +4 -0
- data/lib/aspera/sync/database.rb +14 -10
- data/lib/aspera/sync/operations.rb +5 -5
- data/lib/aspera/temp_file_manager.rb +4 -0
- data/lib/aspera/transfer/parameters.rb +4 -4
- data/lib/aspera/transfer/resumer.rb +1 -1
- data/lib/aspera/transfer/spec.schema.yaml +17 -8
- data/lib/aspera/transfer/uri.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +21 -14
- metadata.gz.sig +0 -0
data/lib/aspera/cli/formatter.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# cspell:ignore jsonpp
|
|
4
4
|
require 'aspera/cli/special_values'
|
|
5
|
+
require 'aspera/cli/terminal_formatter'
|
|
5
6
|
require 'aspera/preview/terminal'
|
|
6
7
|
require 'aspera/secret_hider'
|
|
7
8
|
require 'aspera/environment'
|
|
@@ -9,7 +10,6 @@ require 'aspera/log'
|
|
|
9
10
|
require 'aspera/assert'
|
|
10
11
|
require 'aspera/markdown'
|
|
11
12
|
require 'aspera/dot_container'
|
|
12
|
-
require 'aspera/formatter_interface'
|
|
13
13
|
require 'terminal-table'
|
|
14
14
|
require 'tty-spinner'
|
|
15
15
|
require 'yaml'
|
|
@@ -19,75 +19,8 @@ require 'word_wrap'
|
|
|
19
19
|
|
|
20
20
|
module Aspera
|
|
21
21
|
module Cli
|
|
22
|
-
# Terminal formatter with ANSI colors and Unicode support
|
|
23
|
-
# @see FormatterInterface
|
|
24
|
-
# @see MarkdownFormatter (in build/lib/doc_helper.rb)
|
|
25
|
-
module TerminalFormatter
|
|
26
|
-
include FormatterInterface
|
|
27
|
-
|
|
28
|
-
# Format boolean with colored symbol (✓/✗ or Y/ )
|
|
29
|
-
def tick(yes)
|
|
30
|
-
result =
|
|
31
|
-
if Environment.terminal_supports_unicode?
|
|
32
|
-
yes ? "\u2713" : "\u2717"
|
|
33
|
-
else
|
|
34
|
-
yes ? 'Y' : ' '
|
|
35
|
-
end
|
|
36
|
-
return result.green if yes
|
|
37
|
-
return result.red
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
# Format special values with colors (dim for empty, reverse for others)
|
|
41
|
-
def special_format(what)
|
|
42
|
-
result = "<#{what}>"
|
|
43
|
-
return %w[null empty].any?{ |s| what.include?(s)} ? result.dim : result.reverse_color
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# Prepare table row for terminal display (word wrap arrays)
|
|
47
|
-
def check_row(row)
|
|
48
|
-
row.each_key do |k|
|
|
49
|
-
row[k] = row[k].map{ |i| WordWrap.ww(i.to_s, 120).chomp}.join("\n") if row[k].is_a?(Array)
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# Convert Markdown to terminal format (**bold** -> blue, `code` -> bold)
|
|
54
|
-
# @param match [MatchData, String]
|
|
55
|
-
def markdown_text(match)
|
|
56
|
-
if match.is_a?(String)
|
|
57
|
-
match = Markdown::FORMATS.match(match)
|
|
58
|
-
Aspera.assert(match)
|
|
59
|
-
end
|
|
60
|
-
Aspera.assert_type(match, MatchData)
|
|
61
|
-
if match[:entity]
|
|
62
|
-
Aspera.assert_values(match[:entity], %w[bsol])
|
|
63
|
-
'\\'
|
|
64
|
-
elsif match[:bold]
|
|
65
|
-
match[:bold].to_s.blue
|
|
66
|
-
elsif match[:code]
|
|
67
|
-
match[:code].to_s.bold
|
|
68
|
-
else
|
|
69
|
-
Aspera.error_unexpected_value(match.to_s)
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
module_function :tick, :special_format, :check_row, :markdown_text
|
|
74
|
-
end
|
|
75
|
-
|
|
76
22
|
# Take care of CLI output on terminal
|
|
77
23
|
class Formatter
|
|
78
|
-
# remove a fields from the list
|
|
79
|
-
FIELDS_LESS = '-'
|
|
80
|
-
# supported output formats
|
|
81
|
-
DISPLAY_FORMATS = %i[text nagios ruby json jsonpp yaml table csv image].freeze
|
|
82
|
-
# user output levels
|
|
83
|
-
DISPLAY_LEVELS = %i[info data error].freeze
|
|
84
|
-
# column names for single object display in table
|
|
85
|
-
SINGLE_OBJECT_COLUMN_NAMES = %i[field value].freeze
|
|
86
|
-
# Terminal: vertical separator for list of strings.
|
|
87
|
-
STR_LST_SEP_VERT = "\n"
|
|
88
|
-
|
|
89
|
-
private_constant :FIELDS_LESS, :DISPLAY_FORMATS, :DISPLAY_LEVELS, :SINGLE_OBJECT_COLUMN_NAMES, :STR_LST_SEP_VERT
|
|
90
|
-
|
|
91
24
|
class << self
|
|
92
25
|
# Replace special values with a readable version on terminal
|
|
93
26
|
def replace_specific_for_terminal(input_hash, string_list_separator)
|
|
@@ -134,6 +67,17 @@ module Aspera
|
|
|
134
67
|
@spinner = nil
|
|
135
68
|
end
|
|
136
69
|
|
|
70
|
+
# Display item count if total is provided
|
|
71
|
+
def display_item_count(count, total)
|
|
72
|
+
return if total.nil?
|
|
73
|
+
count = count.to_i
|
|
74
|
+
total = total.to_i
|
|
75
|
+
return if total.eql?(0) && count.eql?(0)
|
|
76
|
+
count_msg = "Items: #{count}/#{total}"
|
|
77
|
+
count_msg = count_msg.bg_red unless count.eql?(total)
|
|
78
|
+
display_status(count_msg)
|
|
79
|
+
end
|
|
80
|
+
|
|
137
81
|
def long_operation(title = nil, action: :spin)
|
|
138
82
|
return unless Environment.terminal?
|
|
139
83
|
return if %i[error data].include?(@options[:display])
|
|
@@ -214,10 +158,16 @@ module Aspera
|
|
|
214
158
|
nil
|
|
215
159
|
end
|
|
216
160
|
|
|
217
|
-
# Main output method
|
|
218
|
-
#
|
|
219
|
-
#
|
|
220
|
-
#
|
|
161
|
+
# Main output method for displaying messages to the user
|
|
162
|
+
# This method is used by Result classes to output formatted data
|
|
163
|
+
# @param message_level [Symbol] The level of the message - must be one of: :data, :info, :error
|
|
164
|
+
# @param message [String] The message to display
|
|
165
|
+
# @param hide_secrets [Boolean] Whether to hide secrets in the message (default: true)
|
|
166
|
+
# @return [void]
|
|
167
|
+
# @note Message display behavior depends on the message_level:
|
|
168
|
+
# - +:data+ messages are displayed unless display level is +:error+
|
|
169
|
+
# - +:info+ messages are only displayed when display level is +:info+
|
|
170
|
+
# - +:error+ messages are always displayed on stderr
|
|
221
171
|
def display_message(message_level, message, hide_secrets: true)
|
|
222
172
|
message = SecretHider.instance.hide_secrets_in_string(message) if hide_secrets && message.is_a?(String) && hide_secrets?
|
|
223
173
|
case message_level
|
|
@@ -232,15 +182,7 @@ module Aspera
|
|
|
232
182
|
display_message(:info, status, **kwargs)
|
|
233
183
|
end
|
|
234
184
|
|
|
235
|
-
|
|
236
|
-
number = number.to_i
|
|
237
|
-
total = total.to_i
|
|
238
|
-
return if total.eql?(0) && number.eql?(0)
|
|
239
|
-
count_msg = "Items: #{number}/#{total}"
|
|
240
|
-
count_msg = count_msg.bg_red unless number.eql?(total)
|
|
241
|
-
display_status(count_msg)
|
|
242
|
-
end
|
|
243
|
-
|
|
185
|
+
# Check if secrets should be hidden
|
|
244
186
|
def hide_secrets?
|
|
245
187
|
!@options[:show_secrets] && !@options[:display].eql?(:data)
|
|
246
188
|
end
|
|
@@ -250,111 +192,55 @@ module Aspera
|
|
|
250
192
|
SecretHider.instance.deep_remove_secret(data) if hide_secrets?
|
|
251
193
|
end
|
|
252
194
|
|
|
253
|
-
# Display results
|
|
254
|
-
#
|
|
255
|
-
#
|
|
256
|
-
# @param
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
Log.
|
|
262
|
-
Log.dump(:
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
hide_secrets(data)
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
data =
|
|
297
|
-
begin
|
|
298
|
-
# just validate
|
|
299
|
-
URI.parse(data)
|
|
300
|
-
if Environment.instance.url_method.eql?(:text)
|
|
301
|
-
UriReader.read(data)
|
|
302
|
-
else
|
|
303
|
-
Environment.instance.open_uri(data)
|
|
304
|
-
display_message(:info, "Opened URL in browser: #{data}")
|
|
305
|
-
:done
|
|
306
|
-
end
|
|
307
|
-
rescue URI::InvalidURIError
|
|
308
|
-
data
|
|
309
|
-
end
|
|
310
|
-
# try base64
|
|
311
|
-
data = begin
|
|
312
|
-
Base64.strict_decode64(data)
|
|
313
|
-
rescue
|
|
314
|
-
data
|
|
315
|
-
end
|
|
316
|
-
# here, data is the image blob
|
|
317
|
-
display_message(:data, Preview::Terminal.build(data, **@options[:image].symbolize_keys)) unless data.eql?(:done)
|
|
318
|
-
when :table, :csv
|
|
319
|
-
case type
|
|
320
|
-
when :single_object
|
|
321
|
-
# :single_object is a Hash, where key=column name
|
|
322
|
-
Aspera.assert_type(data, Hash){'result'}
|
|
323
|
-
if data.empty?
|
|
324
|
-
display_message(:data, TerminalFormatter.special_format('empty dict'))
|
|
325
|
-
else
|
|
326
|
-
data = DotContainer.new(data).to_dotted if @options[:flat_hash]
|
|
327
|
-
display_table([data], compute_fields([data], fields), single: true)
|
|
328
|
-
end
|
|
329
|
-
when :object_list
|
|
330
|
-
# :object_list is an Array of Hash, where key=column name
|
|
331
|
-
Aspera.assert_array_all(data, Hash){'result'}
|
|
332
|
-
data = data.map{ |obj| DotContainer.new(obj).to_dotted} if @options[:flat_hash]
|
|
333
|
-
display_table(data, compute_fields(data, fields), single: type.eql?(:single_object))
|
|
334
|
-
when :value_list
|
|
335
|
-
# :value_list is a simple array of values, name of column provided in `name`
|
|
336
|
-
display_table(data.map{ |i| {name => i}}, [name])
|
|
337
|
-
when :special # no table
|
|
338
|
-
if data.eql?(:nothing)
|
|
339
|
-
Log.log.debug('no result expected')
|
|
340
|
-
return
|
|
341
|
-
end
|
|
342
|
-
display_message(:info, TerminalFormatter.special_format(data.to_s))
|
|
343
|
-
return
|
|
344
|
-
when :status # no table
|
|
345
|
-
# :status displays a simple message
|
|
346
|
-
display_message(:info, data)
|
|
347
|
-
when :text # no table
|
|
348
|
-
# :status displays a simple message
|
|
349
|
-
display_message(:data, data)
|
|
350
|
-
else Aspera.error_unexpected_value(type){'data type'}
|
|
351
|
-
end
|
|
352
|
-
else Aspera.error_unexpected_value(@options[:format]){'format'}
|
|
353
|
-
end
|
|
195
|
+
# Display results using the Visitor pattern
|
|
196
|
+
# Each Result subclass knows how to format itself by calling the appropriate
|
|
197
|
+
# formatter method, eliminating the need for type checking in the formatter.
|
|
198
|
+
# @param result [Result] Result object to display
|
|
199
|
+
def display_results(result)
|
|
200
|
+
require 'aspera/cli/result'
|
|
201
|
+
Aspera.assert_type(result, Cli::Result){'result must be a Result object'}
|
|
202
|
+
|
|
203
|
+
Log.log.debug{"display_results: result class=#{result.class.name}"}
|
|
204
|
+
Log.dump(:data, result.data, level: :trace1)
|
|
205
|
+
Log.dump(:fields, result.fields, level: :trace1)
|
|
206
|
+
|
|
207
|
+
# Hide secrets in data
|
|
208
|
+
hide_secrets(result.data)
|
|
209
|
+
|
|
210
|
+
# Use the Visitor pattern: delegate formatting to the result object
|
|
211
|
+
result.format(self)
|
|
212
|
+
end
|
|
213
|
+
# Public methods exposed to Result classes for formatting
|
|
214
|
+
|
|
215
|
+
# Get the current format type
|
|
216
|
+
def format_type
|
|
217
|
+
@options[:format]
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Set the format type (used by Image result)
|
|
221
|
+
def set_format_type(format)
|
|
222
|
+
@options[:format] = format
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Hide secrets in a string
|
|
226
|
+
def hide_secrets_in_string(string)
|
|
227
|
+
SecretHider.instance.hide_secrets_in_string(string)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# Get special format string
|
|
231
|
+
def special_format(text)
|
|
232
|
+
TerminalFormatter.special_format(text)
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Check if flat_hash option is enabled
|
|
236
|
+
def flat_hash?
|
|
237
|
+
@options[:flat_hash]
|
|
354
238
|
end
|
|
355
|
-
#==========================================================================================
|
|
356
239
|
|
|
357
|
-
|
|
240
|
+
# Get image options
|
|
241
|
+
def image_options
|
|
242
|
+
@options[:image].symbolize_keys
|
|
243
|
+
end
|
|
358
244
|
|
|
359
245
|
# @return all fields of all objects in list of objects
|
|
360
246
|
def all_fields(data)
|
|
@@ -506,6 +392,19 @@ module Aspera
|
|
|
506
392
|
end
|
|
507
393
|
nil
|
|
508
394
|
end
|
|
395
|
+
|
|
396
|
+
# remove a fields from the list
|
|
397
|
+
FIELDS_LESS = '-'
|
|
398
|
+
# supported output formats
|
|
399
|
+
DISPLAY_FORMATS = %i[text nagios ruby json jsonpp yaml table csv image].freeze
|
|
400
|
+
# user output levels
|
|
401
|
+
DISPLAY_LEVELS = %i[info data error].freeze
|
|
402
|
+
# column names for single object display in table
|
|
403
|
+
SINGLE_OBJECT_COLUMN_NAMES = %i[field value].freeze
|
|
404
|
+
# Terminal: vertical separator for list of strings.
|
|
405
|
+
STR_LST_SEP_VERT = "\n"
|
|
406
|
+
|
|
407
|
+
private_constant :FIELDS_LESS, :DISPLAY_FORMATS, :DISPLAY_LEVELS, :SINGLE_OBJECT_COLUMN_NAMES, :STR_LST_SEP_VERT
|
|
509
408
|
end
|
|
510
409
|
end
|
|
511
410
|
end
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'aspera/cli/special_values'
|
|
4
|
+
require 'aspera/log'
|
|
5
|
+
require 'aspera/assert'
|
|
6
|
+
require 'aspera/line_logger'
|
|
7
|
+
require 'openssl'
|
|
8
|
+
|
|
9
|
+
module Aspera
|
|
10
|
+
module Cli
|
|
11
|
+
# Encapsulates all HTTP/S and TLS runtime configuration options.
|
|
12
|
+
# Extracted from Plugins::Config so it can be referenced independently
|
|
13
|
+
# via Context#http_config without coupling to the plugin machinery.
|
|
14
|
+
class Http
|
|
15
|
+
# Certificate file extensions recognized when scanning a folder
|
|
16
|
+
CERT_EXT = %w[crt cer pem der].freeze
|
|
17
|
+
# OpenSSL constant that disables peer verification (VERIFY_NONE)
|
|
18
|
+
SELF_SIGNED_CERT = OpenSSL::SSL.const_get(:enon_yfirev.to_s.upcase.reverse) # cspell: disable-line
|
|
19
|
+
|
|
20
|
+
private_constant :CERT_EXT, :SELF_SIGNED_CERT
|
|
21
|
+
|
|
22
|
+
def initialize
|
|
23
|
+
@insecure = false
|
|
24
|
+
@warn_insecure = true
|
|
25
|
+
@ignore_cert_host_port = []
|
|
26
|
+
@http_options = {}
|
|
27
|
+
@ssl_warned_urls = []
|
|
28
|
+
@certificate_store = nil
|
|
29
|
+
@certificate_paths = nil
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
attr_accessor :insecure, :warn_insecure, :http_options
|
|
33
|
+
attr_reader :ignore_cert_host_port
|
|
34
|
+
|
|
35
|
+
# Declare all HTTP/S CLI options, with handlers pointing to self.
|
|
36
|
+
# Called once from Config#initialize after this object is instantiated.
|
|
37
|
+
# @param options [Aspera::Cli::Manager]
|
|
38
|
+
def declare_options(options)
|
|
39
|
+
options.declare(:insecure, 'HTTP/S: Do not validate any certificate', allowed: Allowed::TYPES_BOOLEAN, handler: {o: self, m: :insecure}, default: false)
|
|
40
|
+
options.declare(:ignore_certificate, 'HTTP/S: Do not validate certificate for these URLs', allowed: [Array, NilClass], handler: {o: self, m: :ignore_cert_host_port})
|
|
41
|
+
options.declare(:warn_insecure, 'HTTP/S: Issue a warning if certificate is ignored', allowed: Allowed::TYPES_BOOLEAN, handler: {o: self, m: :warn_insecure}, default: true)
|
|
42
|
+
options.declare(:cert_stores, 'HTTP/S: List of folder with trusted certificates', allowed: Allowed::TYPES_STRING_ARRAY, handler: {o: self, m: :trusted_cert_locations})
|
|
43
|
+
options.declare(:http_options, 'HTTP/S: Options for HTTP/S socket', allowed: Hash, handler: {o: self, m: :http_options}, default: {})
|
|
44
|
+
options.declare(:http_proxy, 'HTTP/S: URL for proxy with optional credentials', handler: {o: self, m: :http_proxy})
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# ------------------------------------------------------------------
|
|
48
|
+
# Proxy
|
|
49
|
+
# ------------------------------------------------------------------
|
|
50
|
+
|
|
51
|
+
def http_proxy
|
|
52
|
+
ENV['http_proxy']
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def http_proxy=(value)
|
|
56
|
+
URI.parse(value)
|
|
57
|
+
ENV['http_proxy'] = value
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# ------------------------------------------------------------------
|
|
61
|
+
# Per-URL certificate ignore list
|
|
62
|
+
# ------------------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
def ignore_cert_host_port=(url_list)
|
|
65
|
+
url_list.each do |url|
|
|
66
|
+
uri = URI.parse(url)
|
|
67
|
+
raise "Expecting https scheme: #{url}" unless uri.scheme.eql?('https')
|
|
68
|
+
@ignore_cert_host_port.push([uri.host, uri.port].freeze)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Should the certificate be ignored for this host/port?
|
|
73
|
+
# Also logs a warning the first time (if warn_insecure is set).
|
|
74
|
+
def ignore_cert?(address, port)
|
|
75
|
+
endpoint = [address, port].freeze
|
|
76
|
+
ignore_cert = @insecure || @ignore_cert_host_port.any?(endpoint)
|
|
77
|
+
if ignore_cert && @warn_insecure
|
|
78
|
+
base_url = "https://#{address}:#{port}"
|
|
79
|
+
unless @ssl_warned_urls.include?(base_url)
|
|
80
|
+
Log.log.warn{"Ignoring certificate for: #{base_url}. Do not deactivate certificate verification in production."}
|
|
81
|
+
@ssl_warned_urls.push(base_url)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
Log.log.debug{"ignore cert? #{endpoint} -> #{ignore_cert}"}
|
|
85
|
+
ignore_cert
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# ------------------------------------------------------------------
|
|
89
|
+
# Trusted certificate store / paths
|
|
90
|
+
# ------------------------------------------------------------------
|
|
91
|
+
|
|
92
|
+
# Add files, folders or the default OS locations to the cert store.
|
|
93
|
+
# @param path_list [Array<String>]
|
|
94
|
+
def trusted_cert_locations=(path_list)
|
|
95
|
+
Aspera.assert_type(path_list, Array){'cert locations'}
|
|
96
|
+
if @certificate_store.nil?
|
|
97
|
+
Log.log.debug('Creating SSL Cert store')
|
|
98
|
+
@certificate_store = OpenSSL::X509::Store.new
|
|
99
|
+
@certificate_paths = []
|
|
100
|
+
end
|
|
101
|
+
path_list.each do |path|
|
|
102
|
+
Aspera.assert_type(path, String){'Expecting a String for certificate location'}
|
|
103
|
+
paths_to_add = [path]
|
|
104
|
+
Log.log.debug{"Adding cert location: #{path}"}
|
|
105
|
+
if path.eql?(SpecialValues::DEF)
|
|
106
|
+
@certificate_store.set_default_paths
|
|
107
|
+
paths_to_add = [OpenSSL::X509::DEFAULT_CERT_DIR]
|
|
108
|
+
paths_to_add.push(OpenSSL::X509::DEFAULT_CERT_FILE) unless defined?(JRUBY_VERSION)
|
|
109
|
+
paths_to_add.select!{ |f| File.exist?(f)}
|
|
110
|
+
elsif File.file?(path)
|
|
111
|
+
@certificate_store.add_file(path)
|
|
112
|
+
elsif File.directory?(path)
|
|
113
|
+
@certificate_store.add_path(path)
|
|
114
|
+
else
|
|
115
|
+
raise "No such file or folder: #{path}"
|
|
116
|
+
end
|
|
117
|
+
paths_to_add.each do |p|
|
|
118
|
+
pp = [File.realpath(p)]
|
|
119
|
+
if File.directory?(p)
|
|
120
|
+
pp = Dir.entries(p)
|
|
121
|
+
.map{ |e| File.realpath(File.join(p, e))}
|
|
122
|
+
.select{ |entry| File.file?(entry)}
|
|
123
|
+
.select{ |entry| CERT_EXT.any?{ |ext| entry.end_with?(ext)}}
|
|
124
|
+
end
|
|
125
|
+
@certificate_paths.concat(pp)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
@certificate_paths.uniq!
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Return cert file paths (computes OS defaults lazily if never set).
|
|
132
|
+
def trusted_cert_locations
|
|
133
|
+
if @certificate_paths.nil?
|
|
134
|
+
self.trusted_cert_locations = [SpecialValues::DEF]
|
|
135
|
+
locations = @certificate_paths
|
|
136
|
+
# Restore to "lazy" state so next call recomputes if store was reset
|
|
137
|
+
@certificate_paths = @certificate_store = nil
|
|
138
|
+
return locations
|
|
139
|
+
end
|
|
140
|
+
@certificate_paths
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# ------------------------------------------------------------------
|
|
144
|
+
# HTTP session callback
|
|
145
|
+
# Called every time a new Net::HTTP session is opened.
|
|
146
|
+
# ------------------------------------------------------------------
|
|
147
|
+
|
|
148
|
+
# @param http_session [Net::HTTP]
|
|
149
|
+
def update_session(http_session)
|
|
150
|
+
http_session.set_debug_output(LineLogger.new(:trace2)) if Log.instance.logger.trace2?
|
|
151
|
+
if http_session.use_ssl? && ignore_cert?(http_session.address, http_session.port)
|
|
152
|
+
http_session.verify_mode = SELF_SIGNED_CERT
|
|
153
|
+
end
|
|
154
|
+
http_session.cert_store = @certificate_store if @certificate_store
|
|
155
|
+
Log.log.debug{"Using cert store #{http_session.cert_store} (#{@certificate_store})"} unless http_session.cert_store.nil?
|
|
156
|
+
@http_options.each do |k, v|
|
|
157
|
+
method = "#{k}=".to_sym
|
|
158
|
+
if http_session.respond_to?(method)
|
|
159
|
+
http_session.send(method, v)
|
|
160
|
+
else
|
|
161
|
+
Log.log.error{"Unknown HTTP session attribute: #{k}"}
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
data/lib/aspera/cli/manager.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'aspera/cli/extended_value'
|
|
4
4
|
require 'aspera/cli/error'
|
|
5
|
+
require 'aspera/cli/terminal_formatter'
|
|
5
6
|
require 'aspera/colors'
|
|
6
7
|
require 'aspera/secret_hider'
|
|
7
8
|
require 'aspera/log'
|
|
@@ -325,7 +326,7 @@ module Aspera
|
|
|
325
326
|
Aspera.assert(description[0] == description[0].upcase){"#{option_symbol} description does not start with an uppercase"}
|
|
326
327
|
Aspera.assert(!['hash', 'extended value'].any?{ |s| description.downcase.include?(s)}){"#{option_symbol} shall use :allowed instead of hash/extended value in option description"}
|
|
327
328
|
Aspera.assert_type(handler, Hash) if handler
|
|
328
|
-
Aspera.assert(handler.keys.sort.eql?(%i[m o])) if handler
|
|
329
|
+
Aspera.assert(handler.keys.sort.eql?(%i[m o]), 'handler must have keys :m and :o') if handler
|
|
329
330
|
option_attrs = @declared_options[option_symbol] = OptionValue.new(
|
|
330
331
|
option: option_symbol,
|
|
331
332
|
description: description,
|
|
@@ -647,7 +648,7 @@ module Aspera
|
|
|
647
648
|
if !@ask_missing_mandatory
|
|
648
649
|
message = "Missing #{default_prompt}"
|
|
649
650
|
message = self.class.multi_choice_assert_msg(message, accept_list) if accept_list
|
|
650
|
-
message += "\
|
|
651
|
+
message += "\n#{TerminalFormatter::HINT}Give `#{HELP}` as argument to retrieve the schema of the missing argument." if schema
|
|
651
652
|
raise Cli::MissingArgument, message
|
|
652
653
|
end
|
|
653
654
|
# ask interactively
|
|
@@ -23,12 +23,12 @@ module Aspera
|
|
|
23
23
|
rescue StandardError => e
|
|
24
24
|
nagios.add_critical('api', e.to_s)
|
|
25
25
|
end
|
|
26
|
-
|
|
26
|
+
Result::ObjectList.new(nagios.status_list)
|
|
27
27
|
when :entitlement
|
|
28
28
|
entitlement_id = options.get_option(:username, mandatory: true)
|
|
29
29
|
customer_id = options.get_option(:password, mandatory: true)
|
|
30
30
|
api_metering = Api::Alee.new(entitlement_id, customer_id)
|
|
31
|
-
return
|
|
31
|
+
return Result::SingleObject.new(api_metering.read('entitlement'))
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
34
|
end
|