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
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aspera/web_server_simple'
4
+ require 'aspera/assert'
5
+ require 'erb'
6
+
7
+ module Aspera
8
+ module WebAuth
9
+ # servlet called on callback: it records the callback request
10
+ class Servlet < WEBrick::HTTPServlet::AbstractServlet
11
+ # @param server [WEBrick::HTTPServer] the HTTP server instance
12
+ # @param web_auth [Server] the Server instance to record the callback
13
+ def initialize(server, web_auth)
14
+ Log.log.debug('Servlet initialize')
15
+ super(server)
16
+ @web_auth = web_auth
17
+ end
18
+
19
+ # called on request
20
+
21
+ def service(request, response)
22
+ Log.log.debug { "received request from browser #{request.request_method} #{request.path}" }
23
+ Aspera.assert_values(request.request_method, ['GET'], type: WEBrick::HTTPStatus::MethodNotAllowed) { "Unsupported method: #{req.request_method}" }
24
+ Aspera.assert_values(request.path, ['/'], type: WEBrick::HTTPStatus::NotFound) { "Unsupported path: #{req.request_method}" }
25
+ # response to browser
26
+ response.status = 200
27
+ response.content_type = 'text/html'
28
+ response.body = File.read("#{__dir__}/index.html").gsub('__ADD_INFO__', @web_auth.info_html)
29
+ # continue internal processing
30
+ @web_auth.signal_request(request)
31
+ nil
32
+ end
33
+ end
34
+
35
+ # start a local web server
36
+ # then start a browser that will callback the local server upon authentication
37
+ # store the final query
38
+ class Server < WebServerSimple
39
+ attr_reader :info_html
40
+
41
+ # @param endpoint_url [String] e.g. 'https://127.0.0.1:12345'
42
+ # @param additional_info [String] Information in web page
43
+ def initialize(endpoint_url, additional_info = nil)
44
+ uri = URI.parse(endpoint_url)
45
+ super(uri)
46
+ @mutex = Mutex.new
47
+ @cond = ConditionVariable.new
48
+ @expected_path = uri.path.empty? ? '/' : uri.path
49
+ @query = nil
50
+ @info_html = additional_info.to_s
51
+ @info_html = "<p>#{ERB::Util.html_escape(@info_html)}</p>" unless @info_html.empty?
52
+ # last argument (self) is provided to constructor of servlet
53
+ mount(@expected_path, Servlet, self)
54
+ # server runs in thread
55
+ Thread.new { start }
56
+ end
57
+
58
+ # Called by web server thread on received request
59
+ # @return [nil]
60
+ def signal_request(request)
61
+ raise WEBrick::HTTPStatus::NotFound, "unexpected path: #{request.path}" unless request.path.eql?(@expected_path)
62
+ # acquire lock and signal change
63
+ @mutex.synchronize do
64
+ @query = request.query
65
+ @cond.signal
66
+ end
67
+ nil
68
+ end
69
+
70
+ # wait for request on web server (main thread)
71
+ # @return [Hash] the query
72
+ def received_request
73
+ # wait for signal from thread
74
+ @mutex.synchronize { @cond.wait(@mutex) }
75
+ # tell server thread to stop
76
+ shutdown
77
+ return @query
78
+ end
79
+ end
80
+ end
81
+ end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aspera-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.27.2
4
+ version: 4.27.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Laurent Martin
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '2.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: json_schemer
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '2.4'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '2.4'
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: jwt
99
113
  requirement: !ruby/object:Gem::Requirement
@@ -346,9 +360,14 @@ files:
346
360
  - lib/aspera/cli/ascp_actions.rb
347
361
  - lib/aspera/cli/async_transfer_store.rb
348
362
  - lib/aspera/cli/bootstrapper.rb
363
+ - lib/aspera/cli/command_line.rb
349
364
  - lib/aspera/cli/command_registry.rb
350
365
  - lib/aspera/cli/command_spec.rb
366
+ - lib/aspera/cli/completion/ascli.bash
367
+ - lib/aspera/cli/completion/ascli.fish
368
+ - lib/aspera/cli/completion/ascli.zsh
351
369
  - lib/aspera/cli/context.rb
370
+ - lib/aspera/cli/deprecation.rb
352
371
  - lib/aspera/cli/error.rb
353
372
  - lib/aspera/cli/extended_value.rb
354
373
  - lib/aspera/cli/formatter.rb
@@ -359,6 +378,9 @@ files:
359
378
  - lib/aspera/cli/mailer.rb
360
379
  - lib/aspera/cli/mcp_tool.rb
361
380
  - lib/aspera/cli/option_declarator.rb
381
+ - lib/aspera/cli/option_registry.rb
382
+ - lib/aspera/cli/option_types.rb
383
+ - lib/aspera/cli/option_value.rb
362
384
  - lib/aspera/cli/options.schema.yaml
363
385
  - lib/aspera/cli/parser.rb
364
386
  - lib/aspera/cli/plugins/alee.rb
@@ -382,6 +404,7 @@ files:
382
404
  - lib/aspera/cli/plugins/shares.rb
383
405
  - lib/aspera/cli/preset_actions.rb
384
406
  - lib/aspera/cli/preset_manager.rb
407
+ - lib/aspera/cli/prompt.rb
385
408
  - lib/aspera/cli/result.rb
386
409
  - lib/aspera/cli/runner.rb
387
410
  - lib/aspera/cli/secret_finder.rb
@@ -394,7 +417,6 @@ files:
394
417
  - lib/aspera/cli/vault_manager.rb
395
418
  - lib/aspera/cli/version.rb
396
419
  - lib/aspera/cli/wizard.rb
397
- - lib/aspera/colors.rb
398
420
  - lib/aspera/command_line_builder.rb
399
421
  - lib/aspera/command_line_converter.rb
400
422
  - lib/aspera/coverage.rb
@@ -428,6 +450,7 @@ files:
428
450
  - lib/aspera/link_header.rb
429
451
  - lib/aspera/log.rb
430
452
  - lib/aspera/markdown.rb
453
+ - lib/aspera/mime.rb
431
454
  - lib/aspera/nagios.rb
432
455
  - lib/aspera/node_simulator.rb
433
456
  - lib/aspera/oauth.rb
@@ -453,23 +476,31 @@ files:
453
476
  - lib/aspera/products/transferd.rb
454
477
  - lib/aspera/proxy_auto_config.js
455
478
  - lib/aspera/proxy_auto_config.rb
479
+ - lib/aspera/rainbow.rb
456
480
  - lib/aspera/rest.rb
457
- - lib/aspera/rest_call_error.rb
458
- - lib/aspera/rest_error_analyzer.rb
459
- - lib/aspera/rest_errors_aspera.rb
460
- - lib/aspera/rest_list.rb
481
+ - lib/aspera/rest/aspera_errors.rb
482
+ - lib/aspera/rest/call_error.rb
483
+ - lib/aspera/rest/client.rb
484
+ - lib/aspera/rest/error_analyzer.rb
485
+ - lib/aspera/rest/list.rb
486
+ - lib/aspera/rest/parameters.rb
487
+ - lib/aspera/rest/util.rb
488
+ - lib/aspera/schema/IBM Aspera Console-enhanced.yaml
461
489
  - lib/aspera/schema/IBM Aspera Faspex API-5.0-enhanced.yaml
462
490
  - lib/aspera/schema/IBM Aspera Node API-4.4.6.yaml
463
491
  - lib/aspera/schema/IBM Aspera faspio Gateway API-1.0.0.yaml
464
492
  - lib/aspera/schema/IBM Aspera on Cloud API-0.2.6-enhanced.yaml
493
+ - lib/aspera/schema/IBM Aspera on Cloud Automation API-1.0.5-enhanced.yaml
465
494
  - lib/aspera/schema/IBM_Aspera_Shares.yaml
466
495
  - lib/aspera/schema/async_tables.yaml
467
496
  - lib/aspera/schema/documentation.rb
468
497
  - lib/aspera/schema/reader.rb
469
498
  - lib/aspera/schema/registry.rb
499
+ - lib/aspera/schema/validator.rb
470
500
  - lib/aspera/secret_hider.rb
471
501
  - lib/aspera/ssh.rb
472
502
  - lib/aspera/ssl.rb
503
+ - lib/aspera/string_ext.rb
473
504
  - lib/aspera/sync/args.schema.yaml
474
505
  - lib/aspera/sync/conf.schema.yaml
475
506
  - lib/aspera/sync/database.rb
@@ -484,7 +515,8 @@ files:
484
515
  - lib/aspera/transfer/spec.rb
485
516
  - lib/aspera/transfer/spec.schema.yaml
486
517
  - lib/aspera/uri_reader.rb
487
- - lib/aspera/web_auth.rb
518
+ - lib/aspera/web_auth/index.html
519
+ - lib/aspera/web_auth/server.rb
488
520
  - lib/aspera/web_server_simple.rb
489
521
  - lib/aspera/yaml.rb
490
522
  - lib/transferd_pb.rb
metadata.gz.sig CHANGED
Binary file
data/lib/aspera/colors.rb DELETED
@@ -1,79 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # cspell:words
4
-
5
- # simple vt100 colors
6
- class String
7
- class << self
8
- private
9
-
10
- def vt_cmd(code); "\e[#{code}m"; end
11
- end
12
- # see https://en.wikipedia.org/wiki/ANSI_escape_code
13
- # symbol is the method name added to String, e.g. "hello".bold
14
- # it adds control chars to set color (and reset at the end).
15
- VT_STYLES = {
16
- bold: 1,
17
- dim: 2,
18
- italic: 3,
19
- underline: 4,
20
- blink: 5,
21
- reverse_color: 7,
22
- invisible: 8,
23
- strike: 9,
24
- black: 30,
25
- red: 31,
26
- green: 32,
27
- brown: 33,
28
- blue: 34,
29
- magenta: 35,
30
- cyan: 36,
31
- gray: 37,
32
- bg_black: 40,
33
- bg_red: 41,
34
- bg_green: 42,
35
- bg_brown: 43,
36
- bg_blue: 44,
37
- bg_magenta: 45,
38
- bg_cyan: 46,
39
- bg_gray: 47
40
- }.freeze
41
- private_constant :VT_STYLES
42
- # Defines methods to String, one per entry in VT_STYLES
43
- VT_STYLES.each do |name, code|
44
- if $stdout.tty?
45
- begin_seq = vt_cmd(code)
46
- end_seq = vt_cmd(
47
- if code <= 2 then 22
48
- elsif code <= 8 then code + 20
49
- elsif code <= 37 then 39
50
- elsif code <= 47 then 49
51
- else
52
- 0 # by default reset all
53
- end
54
- )
55
- define_method(name) { "#{begin_seq}#{self}#{end_seq}" }
56
- else
57
- define_method(name) { self }
58
- end
59
- end
60
-
61
- # Applies the provided list of string decoration (colors).
62
- # @param colors [Array<Symbol>] List of decorations.
63
- # @return [String] Enhanced String.
64
- def apply(*colors)
65
- colors.reduce(self) { |s, c| s.public_send(c) }
66
- end
67
-
68
- # Transform capitalized to snake case
69
- def capital_to_snake
70
- return gsub(/([a-z\d])([A-Z])/, '\1_\2')
71
- .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
72
- .downcase
73
- end
74
-
75
- # Transform snake case to capitalized
76
- def snake_to_capital
77
- split('_').map(&:capitalize).join
78
- end
79
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Aspera
4
- # raised on error after REST call
5
- class RestCallError < StandardError
6
- def request
7
- @context[:request]
8
- end
9
-
10
- def response
11
- @context[:response]
12
- end
13
-
14
- def data
15
- @context[:data]
16
- end
17
-
18
- # @param context [Hash,String] with keys :messages, :request, :response, :data
19
- def initialize(context)
20
- context = {messages: [context]} if context.is_a?(String)
21
- @context = context
22
- super(@context[:messages].join("\n"))
23
- end
24
- end
25
- end
@@ -1,111 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'aspera/rest_call_error'
4
- require 'aspera/log'
5
- require 'singleton'
6
- require 'net/http'
7
-
8
- module Aspera
9
- # analyze error codes returned by REST calls and raise ruby exception
10
- #
11
- # @!method self.instance
12
- # Returns the singleton instance of RestErrorAnalyzer
13
- # @return [RestErrorAnalyzer] the singleton instance
14
- class RestErrorAnalyzer
15
- include Singleton
16
-
17
- attr_accessor :log_file
18
-
19
- # the singleton object is registered with application specific handlers
20
- def initialize
21
- # list of handlers
22
- @error_handlers = []
23
- @log_file = nil
24
- add_handler('Type Generic') do |type, context|
25
- if !context[:response].code.start_with?('2')
26
- # add generic information
27
- RestErrorAnalyzer.add_error(context, type, "#{context[:request]['host']} #{context[:response].code} #{context[:response].message}")
28
- end
29
- end
30
- end
31
-
32
- # Use this method to analyze a EST result and raise an exception
33
- # Analyzes REST call response and raises a RestCallError exception
34
- # if HTTP result code is not 2XX
35
- # @param req [Net::HTTPRequest] the HTTP request
36
- # @param data [Object] the parsed response body
37
- # @param http [Net::HTTPResponse] the raw HTTP response
38
- def raise_on_error(req, data, http)
39
- Log.log.debug { "raise_on_error #{req.method} #{req.path} #{http.code}" }
40
- context = {
41
- messages: [],
42
- request: req,
43
- response: http,
44
- data: data
45
- }
46
- # multiple error messages can be found
47
- # analyze errors from provided handlers
48
- # note that there can be an error even if code is 2XX
49
- @error_handlers.each do |handler|
50
- handler[:block].call(handler[:name], context)
51
- rescue StandardError => e
52
- Log.log.error { "ERROR in handler:\n#{e.message}\n#{e.backtrace}" }
53
- end
54
- raise RestCallError, context unless context[:messages].empty?
55
- end
56
-
57
- # Add a new error handler (done at application initialization)
58
- # @param name [String] name of error handler (for logs)
59
- # @param block [Proc] processing of response: takes two parameters: `name`, `context`
60
- # name is the one provided here
61
- # context is built in method raise_on_error
62
- def add_handler(name, &block)
63
- @error_handlers.unshift({name: name, block: block})
64
- nil
65
- end
66
-
67
- # Add a simple error handler
68
- # Check that key exists and is string under specified path (hash)
69
- # Adds other keys as secondary information
70
- # @param name [String] name of error handler (for logs)
71
- # @param always [Boolean] if true, always add error message, even if response code is 2XX
72
- # @param path [Array] path to error message in response
73
- def add_simple_handler(name:, always: false, path:)
74
- path.freeze
75
- add_handler(name) do |type, context|
76
- if context[:data].is_a?(Hash) && (!context[:response].code.start_with?('2') || always)
77
- # Log.log.debug{"simple_handler: #{type} #{path} #{path.last}"}
78
- # dig and find hash containing error message
79
- error_struct = path.length.eql?(1) ? context[:data] : context[:data].dig(*path[0..-2])
80
- # Log.log.debug{"found: #{error_struct.class} #{error_struct}"}
81
- if error_struct.is_a?(Hash) && error_struct[path.last].is_a?(String)
82
- RestErrorAnalyzer.add_error(context, type, error_struct[path.last])
83
- error_struct.each do |k, v|
84
- next if k.eql?(path.last)
85
- RestErrorAnalyzer.add_error(context, "#{type}(sub)", "#{k}: #{v}") if [String, Integer].include?(v.class)
86
- end
87
- end
88
- end
89
- end
90
- end
91
-
92
- class << self
93
- # Used by handler to add an error description to list of errors
94
- # For logging and tracing : collect error descriptions (create file to activate)
95
- # @param context [Hash] the result context, provided to handler
96
- # @param type [String] type of exception, for logging purpose
97
- # @param message [String] one error message to add to list
98
- def add_error(context, type, message)
99
- context[:messages].push(message)
100
- Log.log.trace1 { "Found error: #{type}: #{message}" }
101
- log_file = instance.log_file
102
- # log error for further analysis (file must exist to activate)
103
- return if log_file.nil? || !File.exist?(log_file)
104
- File.open(log_file, 'a+') do |f|
105
- f.write("\n=#{type}=====\n#{context[:request].method} #{context[:request].path}\n#{context[:response].code}\n" \
106
- "#{JSON.generate(context[:data])}\n#{context[:messages].join("\n")}")
107
- end
108
- end
109
- end
110
- end
111
- end
@@ -1,58 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'aspera/rest_error_analyzer'
4
- require 'aspera/log'
5
-
6
- module Aspera
7
- # REST error handlers for various Aspera REST APIs
8
- class RestErrorsAspera
9
- class << self
10
- # handlers should probably be defined by plugins for modularity
11
- def register_handlers
12
- Log.log.debug('registering Aspera REST error handlers')
13
- # Faspex 4: both user_message and internal_message, and code 200
14
- # example: missing meta data on package creation
15
- RestErrorAnalyzer.instance.add_simple_handler(name: 'Type 1: error:user_message', path: %w[error user_message], always: true)
16
- RestErrorAnalyzer.instance.add_simple_handler(name: 'Type 2: error:description', path: %w[error description])
17
- RestErrorAnalyzer.instance.add_simple_handler(name: 'Type 3: error:internal_message', path: %w[error internal_message])
18
- RestErrorAnalyzer.instance.add_simple_handler(name: 'Type 5', path: ['error_description'])
19
- RestErrorAnalyzer.instance.add_simple_handler(name: 'Type 6', path: ['message'])
20
- RestErrorAnalyzer.instance.add_simple_handler(name: 'Type 6', path: ['failure'], always: true)
21
- # AoC Automation
22
- RestErrorAnalyzer.instance.add_simple_handler(name: 'AoC Automation', path: ['error'])
23
- RestErrorAnalyzer.instance.add_handler('Type 7: errors[]') do |type, context|
24
- next unless context[:data].is_a?(Hash) && context[:data]['errors'].is_a?(Hash)
25
- # special for Shares: false positive ? (update global transfer_settings)
26
- next if context[:data].key?('min_connect_version')
27
- context[:data]['errors'].each do |k, v|
28
- RestErrorAnalyzer.add_error(context, type, "#{k}: #{v}")
29
- end
30
- end
31
- # call to upload_setup and download_setup of node api
32
- RestErrorAnalyzer.instance.add_handler('T8:node: *_setup') do |type, context|
33
- next unless context[:data].is_a?(Hash)
34
- d_t_s = context[:data]['transfer_specs']
35
- next unless d_t_s.is_a?(Array)
36
- d_t_s.each do |res|
37
- r_err = res.dig(*%w[transfer_spec error]) || res['error']
38
- next unless r_err.is_a?(Hash)
39
- RestErrorAnalyzer.add_error(context, type, r_err.values.join(': '))
40
- end
41
- end
42
- RestErrorAnalyzer.instance.add_simple_handler(name: 'T9:IBM cloud IAM', path: ['errorMessage'])
43
- RestErrorAnalyzer.instance.add_simple_handler(name: 'T10:faspex v4', path: ['user_message'])
44
- RestErrorAnalyzer.instance.add_handler('Orchestrator') do |type, context|
45
- next if context[:response].code.start_with?('2')
46
- data = context[:data]
47
- next unless data.is_a?(Hash)
48
- work_order = data['work_order']
49
- next unless work_order.is_a?(Hash)
50
- RestErrorAnalyzer.add_error(context, type, work_order['statusDetails'])
51
- data['missing_parameters']&.each do |param|
52
- RestErrorAnalyzer.add_error(context, type, "missing parameter: #{param}")
53
- end
54
- end
55
- end
56
- end
57
- end
58
- end
@@ -1,136 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Aspera
4
- # List and lookup methods for Rest
5
- # To be included in classes inheriting Rest that require those methods.
6
- module RestList
7
- # `max`: special query parameter: max number of items for list command
8
- MAX_ITEMS = 'max'
9
- # `pmax`: special query parameter: max number of pages for list command
10
- MAX_PAGES = 'pmax'
11
-
12
- # Query entity by general search (read with parameter `q`)
13
- #
14
- # @param entity [String] Path of entity in API
15
- # @param value [String] Value of field of searched entity
16
- # @param field [String] Field of searched entity
17
- # @param query [Hash] Optional additional search query parameters
18
- # @return [Hash] A single entity matching the search, or an exception if not found or multiple found
19
- def lookup_with_q(entity, value:, field: 'name', query: {})
20
- Aspera.assert_type(query, Hash) { 'query' }
21
- Aspera.assert_type(field, String) { 'field' }
22
- # returns entities matching the query (it matches against several fields in case insensitive way)
23
- # We don't do paging, as anyway, we look for only one match
24
- matching_items = read(entity, query.merge({'q' => value}))
25
- # API style: {totalcount:, ...} cspell: disable-line: TODO: is that total_count ?
26
- # @type [Array<Hash{String => String}>]
27
- matching_items = matching_items[entity] if matching_items.is_a?(Hash)
28
- Aspera.assert_type(matching_items, Array)
29
- case matching_items.length
30
- when 1 then return matching_items.first
31
- when 0 then raise EntityNotFound, %Q{No such #{entity}: "#{value}"}
32
- else
33
- # multiple case insensitive partial matches, try case insensitive full match
34
- # (anyway AoC does not allow creation of 2 entities with same case insensitive field value)
35
- value_matches = matching_items.select { |i| i[field].casecmp?(value) }
36
- case value_matches.length
37
- when 1 then return value_matches.first
38
- when 0 then raise Error, "#{entity}: Multiple case insensitive partial match for: \"#{value}\" in #{matching_items.map { |i| i[field] }.join(', ')} but no case insensitive full match. Please be more specific or give exact #{field}."
39
- else raise Error, "Two entities cannot have the same case insensitive #{field}: #{value_matches.map { |i| i[field] }}"
40
- end
41
- end
42
- end
43
-
44
- # Get a (full or partial) list of all entities of a given type.
45
- # Using query: `offset` + `limit`
46
- # And response `total_count`
47
- # @param entity [String,Symbol] API endpoint of entity to list
48
- # @param items_key [String] Key in the result to get the list of items (Default: same as `entity`)
49
- # @param query [Hash,nil] Additional query parameters
50
- # @return [Array<(Array<Hash>, Integer)>] items, total_count
51
- def list_entities_limit_offset_total_count(
52
- entity:,
53
- operation: 'GET',
54
- items_key: nil,
55
- query: nil
56
- )
57
- entity = entity.to_s if entity.is_a?(Symbol)
58
- items_key = entity.split('/').last if items_key.nil?
59
- query = {} if query.nil?
60
- Aspera.assert_type(entity, String)
61
- Aspera.assert_type(items_key, String)
62
- Aspera.assert_type(query, Hash)
63
- Log.log.debug { "list_entities t=#{entity} k=#{items_key}" }
64
- Log.dump(:query, query)
65
- result = []
66
- offset = 0
67
- max_items = query.delete(MAX_ITEMS)
68
- remain_pages = query.delete(MAX_PAGES)
69
- # Merge default parameters, by default 100 per page
70
- query = {'limit'=> PER_PAGE_DEFAULT}.merge(query)
71
- total_count = nil
72
- call_args = {
73
- operation: operation,
74
- subpath: entity,
75
- query: query,
76
- headers: {'Accept' => Mime::JSON}
77
- }
78
- loop do
79
- query['offset'] = offset
80
- page_result = call(**call_args)
81
- Aspera.assert_type(page_result[items_key], Array)
82
- result.concat(page_result[items_key])
83
- # Reach the limit set by user ?
84
- if !max_items.nil? && (result.length >= max_items)
85
- result = result.slice(0, max_items)
86
- break
87
- end
88
- total_count ||= page_result['total_count']
89
- break if result.length >= total_count
90
- remain_pages -= 1 unless remain_pages.nil?
91
- break if remain_pages == 0
92
- offset += page_result[items_key].length
93
- RestParameters.instance.spinner_cb.call("#{result.length} / #{total_count || '?'}")
94
- end
95
- RestParameters.instance.spinner_cb.call(action: :success)
96
- return result, total_count
97
- end
98
-
99
- # Lookup an entity id from its name.
100
- # Uses query `q` if `query` is `:default` and `field` is `name`.
101
- # @param entity [String] Type of entity to lookup, by default it is the path, and it is also the field name in result
102
- # @param value [String] Value to lookup
103
- # @param field [String] Field to match, by default it is `'name'`
104
- # @param items_key [String] Key in the result to get the list of items (override entity)
105
- # @param query [Hash] Additional query parameters (Default: `:default`)
106
- def lookup_entity_by_field(entity:, value:, field: 'name', items_key: nil, query: :default)
107
- if query.eql?(:default)
108
- Aspera.assert_values(field, ['name']) { 'Default query field' }
109
- query = {'q'=> value}
110
- end
111
- lookup_entity_generic(entity: entity, field: field, value: value) { list_entities_limit_offset_total_count(entity: entity, items_key: items_key, query: query).first }
112
- end
113
-
114
- # Lookup entity by field and value.
115
- # Extracts a single result from the list returned by the block.
116
- #
117
- # @param entity [String] Type of entity to lookup (path, and by default it is also the field name in result)
118
- # @param value [String] Value to match against the field.
119
- # @param field [String] Field to match in the hashes (defaults to 'name').
120
- # @yield [] A mandatory block that returns an Array of Hashes.
121
- # @return [Hash] The unique matching object.
122
- # @raise [Cli::BadIdentifier] If 0 or >1 matches are found.
123
- def lookup_entity_generic(entity:, value:, field: 'name')
124
- Aspera.assert(block_given?, 'block required for lookup_entity_generic')
125
- found = yield
126
- Aspera.assert_array_all(found, Hash)
127
- found = found.select { |i| i[field].eql?(value) }
128
- return found.first if found.length.eql?(1)
129
- raise Cli::BadIdentifier.new(entity, value, field: field, count: found.length)
130
- end
131
-
132
- PER_PAGE_DEFAULT = 1000
133
- private_constant :PER_PAGE_DEFAULT
134
- module_function :lookup_entity_generic
135
- end
136
- end