aspera-cli 4.24.1 → 4.24.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 (87) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +15 -2
  4. data/README.md +745 -436
  5. data/bin/ascli +20 -1
  6. data/bin/asession +23 -27
  7. data/lib/aspera/agent/base.rb +10 -21
  8. data/lib/aspera/agent/connect.rb +2 -3
  9. data/lib/aspera/agent/desktop.rb +2 -2
  10. data/lib/aspera/agent/direct.rb +49 -32
  11. data/lib/aspera/agent/factory.rb +31 -0
  12. data/lib/aspera/api/aoc.rb +79 -49
  13. data/lib/aspera/api/faspex.rb +212 -0
  14. data/lib/aspera/api/node.rb +99 -84
  15. data/lib/aspera/ascp/installation.rb +22 -21
  16. data/lib/aspera/ascp/management.rb +119 -23
  17. data/lib/aspera/assert.rb +14 -8
  18. data/lib/aspera/cli/extended_value.rb +15 -15
  19. data/lib/aspera/cli/formatter.rb +7 -5
  20. data/lib/aspera/cli/hints.rb +8 -0
  21. data/lib/aspera/cli/info.rb +4 -4
  22. data/lib/aspera/cli/main.rb +55 -70
  23. data/lib/aspera/cli/manager.rb +7 -4
  24. data/lib/aspera/cli/plugins/alee.rb +2 -1
  25. data/lib/aspera/cli/plugins/aoc.rb +110 -186
  26. data/lib/aspera/cli/plugins/ats.rb +4 -4
  27. data/lib/aspera/cli/plugins/base.rb +335 -0
  28. data/lib/aspera/cli/plugins/basic_auth.rb +45 -0
  29. data/lib/aspera/cli/plugins/config.rb +249 -220
  30. data/lib/aspera/cli/plugins/console.rb +15 -15
  31. data/lib/aspera/cli/plugins/cos.rb +2 -2
  32. data/lib/aspera/cli/plugins/factory.rb +78 -0
  33. data/lib/aspera/cli/plugins/faspex.rb +17 -20
  34. data/lib/aspera/cli/plugins/faspex5.rb +79 -193
  35. data/lib/aspera/cli/plugins/faspio.rb +14 -13
  36. data/lib/aspera/cli/plugins/httpgw.rb +13 -12
  37. data/lib/aspera/cli/plugins/node.rb +34 -32
  38. data/lib/aspera/cli/plugins/oauth.rb +48 -0
  39. data/lib/aspera/cli/plugins/orchestrator.rb +15 -13
  40. data/lib/aspera/cli/plugins/preview.rb +4 -4
  41. data/lib/aspera/cli/plugins/server.rb +15 -13
  42. data/lib/aspera/cli/plugins/shares.rb +18 -15
  43. data/lib/aspera/cli/sync_actions.rb +1 -1
  44. data/lib/aspera/cli/transfer_agent.rb +24 -20
  45. data/lib/aspera/cli/transfer_progress.rb +6 -6
  46. data/lib/aspera/cli/version.rb +3 -3
  47. data/lib/aspera/cli/wizard.rb +65 -53
  48. data/lib/aspera/colors.rb +6 -0
  49. data/lib/aspera/command_line_builder.rb +45 -50
  50. data/lib/aspera/command_line_converter.rb +2 -1
  51. data/lib/aspera/coverage.rb +1 -1
  52. data/lib/aspera/data_repository.rb +1 -1
  53. data/lib/aspera/environment.rb +10 -7
  54. data/lib/aspera/faspex_gw.rb +6 -4
  55. data/lib/aspera/faspex_postproc.rb +1 -1
  56. data/lib/aspera/keychain/macos_security.rb +1 -1
  57. data/lib/aspera/log.rb +37 -9
  58. data/lib/aspera/nagios.rb +1 -1
  59. data/lib/aspera/oauth/base.rb +17 -10
  60. data/lib/aspera/oauth/factory.rb +8 -8
  61. data/lib/aspera/oauth/web.rb +2 -2
  62. data/lib/aspera/products/connect.rb +4 -3
  63. data/lib/aspera/products/desktop.rb +1 -4
  64. data/lib/aspera/products/other.rb +9 -1
  65. data/lib/aspera/products/transferd.rb +0 -1
  66. data/lib/aspera/rest.rb +126 -83
  67. data/lib/aspera/ssh.rb +3 -3
  68. data/lib/aspera/sync/args.schema.yaml +46 -3
  69. data/lib/aspera/sync/conf.schema.yaml +130 -94
  70. data/lib/aspera/sync/operations.rb +16 -16
  71. data/lib/aspera/temp_file_manager.rb +17 -5
  72. data/lib/aspera/transfer/error.rb +16 -7
  73. data/lib/aspera/transfer/parameters.rb +34 -20
  74. data/lib/aspera/transfer/resumer.rb +74 -0
  75. data/lib/aspera/transfer/spec.rb +4 -3
  76. data/lib/aspera/transfer/spec.schema.yaml +132 -51
  77. data/lib/aspera/transfer/spec_doc.rb +41 -35
  78. data/lib/aspera/uri_reader.rb +1 -1
  79. data/lib/aspera/web_auth.rb +6 -6
  80. data.tar.gz.sig +0 -0
  81. metadata +9 -7
  82. metadata.gz.sig +0 -0
  83. data/lib/aspera/cli/basic_auth_plugin.rb +0 -43
  84. data/lib/aspera/cli/plugin.rb +0 -333
  85. data/lib/aspera/cli/plugin_factory.rb +0 -81
  86. data/lib/aspera/resumer.rb +0 -77
  87. data/lib/aspera/transfer/error_info.rb +0 -91
@@ -1,81 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'singleton'
4
- module Aspera
5
- module Cli
6
- # Instantiate plugin from well-known locations
7
- class PluginFactory
8
- include Singleton
9
-
10
- RUBY_FILE_EXT = '.rb'
11
- PLUGINS_MODULE = 'Plugins'
12
- private_constant :RUBY_FILE_EXT, :PLUGINS_MODULE
13
-
14
- attr_reader :lookup_folders
15
-
16
- def initialize
17
- @lookup_folders = []
18
- # information on plugins
19
- @plugins = {}
20
- end
21
-
22
- # @return list of registered plugins
23
- def plugin_list
24
- @plugins.keys
25
- end
26
-
27
- # @return path to source file of plugin
28
- def plugin_source(plugin_name_sym)
29
- @plugins[plugin_name_sym][:source]
30
- end
31
-
32
- # add a folder to the list of folders to look for plugins
33
- def add_lookup_folder(folder)
34
- @lookup_folders.unshift(folder)
35
- end
36
-
37
- # find plugins in defined paths
38
- def add_plugins_from_lookup_folders
39
- @lookup_folders.each do |folder|
40
- next unless File.directory?(folder)
41
- # TODO: add gem root to load path ? and require short folder ?
42
- # $LOAD_PATH.push(folder) if i[:add_path]
43
- Dir.entries(folder).select{ |file| file.end_with?(RUBY_FILE_EXT)}.each do |source|
44
- add_plugin_info(File.join(folder, source))
45
- end
46
- end
47
- end
48
-
49
- # @return Class object for plugin
50
- def plugin_class(plugin_name_sym)
51
- raise NoSuchElement, "plugin not found: #{plugin_name_sym}" unless @plugins.key?(plugin_name_sym)
52
- require @plugins[plugin_name_sym][:require_stanza]
53
- # Module.nesting[1] is Aspera::Cli
54
- return Object.const_get("#{Module.nesting[1]}::#{PLUGINS_MODULE}::#{plugin_name_sym.to_s.capitalize}")
55
- end
56
-
57
- # Create specified plugin
58
- # @param plugin_name_sym [Symbol] name of plugin
59
- # @param args [Hash] arguments to pass to plugin constructor
60
- def create(plugin_name_sym, **args)
61
- # TODO: check that ancestor is Plugin?
62
- plugin_class(plugin_name_sym).new(**args)
63
- end
64
-
65
- private
66
-
67
- # add plugin information to list
68
- # @param path [String] path to plugin source file
69
- def add_plugin_info(path)
70
- raise Error, "plugin path must end with #{RUBY_FILE_EXT}" if !path.end_with?(RUBY_FILE_EXT)
71
- plugin_symbol = File.basename(path, RUBY_FILE_EXT).to_sym
72
- req = path.sub(/#{RUBY_FILE_EXT}$/o, '')
73
- if @plugins.key?(plugin_symbol)
74
- Log.log.warn{"skipping plugin already registered: #{plugin_symbol}"}
75
- return
76
- end
77
- @plugins[plugin_symbol] = {source: path, require_stanza: req}
78
- end
79
- end
80
- end
81
- end
@@ -1,77 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'singleton'
4
- require 'aspera/log'
5
- require 'aspera/assert'
6
-
7
- module Aspera
8
- # implements a simple resume policy
9
- class Resumer
10
- # list of supported parameters and default values
11
- DEFAULTS = {
12
- iter_max: 7,
13
- sleep_initial: 2,
14
- sleep_factor: 2,
15
- sleep_max: 60
16
- }.freeze
17
-
18
- # @param params see DEFAULTS
19
- def initialize(params = nil)
20
- @parameters = DEFAULTS.dup
21
- if !params.nil?
22
- Aspera.assert_type(params, Hash)
23
- params.each do |k, v|
24
- Aspera.assert_values(k, DEFAULTS.keys){'resume parameter'}
25
- Aspera.assert_type(v, Integer){k}
26
- @parameters[k] = v
27
- end
28
- end
29
- Log.log.debug{"resume params=#{@parameters}"}
30
- end
31
-
32
- # calls block a number of times (resumes) until success or limit reached
33
- # this is re-entrant, one resumer can handle multiple transfers in //
34
- def execute_with_resume
35
- Aspera.assert(block_given?)
36
- # maximum of retry
37
- remaining_resumes = @parameters[:iter_max]
38
- sleep_seconds = @parameters[:sleep_initial]
39
- Log.log.debug{"retries=#{remaining_resumes}"}
40
- # try to send the file until ascp is successful
41
- loop do
42
- Log.log.debug('transfer starting')
43
- begin
44
- # call provided block
45
- yield
46
- # exit retry loop if success
47
- break
48
- rescue Transfer::Error => e
49
- Log.log.warn{"An error occurred during transfer: #{e.message}"}
50
- # failure in ascp
51
- if e.retryable?
52
- # exit if we exceed the max number of retry
53
- raise Transfer::Error, "Maximum number of retry reached (#{@parameters[:iter_max]})" if remaining_resumes <= 0
54
- else
55
- # give one chance only to non retryable errors
56
- unless remaining_resumes.eql?(@parameters[:iter_max])
57
- Log.log.error('non-retryable error'.red.blink)
58
- raise e
59
- end
60
- end
61
- end
62
-
63
- # take this retry in account
64
- remaining_resumes -= 1
65
- Log.log.warn{"Resuming in #{sleep_seconds} seconds (retry left:#{remaining_resumes})"}
66
-
67
- # wait a bit before retrying, maybe network condition will be better
68
- sleep(sleep_seconds)
69
-
70
- # increase retry period
71
- sleep_seconds *= @parameters[:sleep_factor]
72
- # cap value
73
- sleep_seconds = @parameters[:sleep_max] if sleep_seconds > @parameters[:sleep_max]
74
- end
75
- end
76
- end
77
- end
@@ -1,91 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # cspell:words mnemo PROTO RCVR NOLIC PMTU BRTT VLINK BWMEAS SSEAR FIPS
4
-
5
- module Aspera
6
- module Transfer
7
- # from https://www.google.com/search?q=FASP+error+codes
8
- # Note that the fact that an error is retry-able is not internally defined by protocol, it's client-side responsibility
9
- # rubocop:disable Layout/FirstHashElementLineBreak
10
- ERROR_INFO = {
11
- # id retry-able mnemo message additional info
12
- 1 => {r: false, c: 'FASP_PROTO', m: 'Generic fasp(tm) protocol error', a: 'fasp(tm) error'},
13
- 2 => {r: false, c: 'ASCP', m: 'Generic SCP error', a: 'ASCP error'},
14
- 3 => {r: false, c: 'AMBIGUOUS_TARGET', m: 'Target incorrectly specified', a: 'Ambiguous target'},
15
- 4 => {r: false, c: 'NO_SUCH_FILE', m: 'No such file or directory', a: 'No such file or directory'},
16
- 5 => {r: false, c: 'NO_PERMS', m: 'Insufficient permission to read or write', a: 'Insufficient permissions'},
17
- 6 => {r: false, c: 'NOT_DIR', m: 'Target is not a directory', a: 'Target must be a directory'},
18
- 7 => {r: false, c: 'IS_DIR', m: 'File is a directory - expected regular file', a: 'Expected regular file'},
19
- 8 => {r: false, c: 'USAGE', m: 'Incorrect usage of scp command', a: 'Incorrect usage of Aspera scp command'},
20
- 9 => {r: false, c: 'LIC_DUP', m: 'Duplicate license', a: 'Duplicate license'},
21
- 10 => {r: false, c: 'LIC_RATE_EXCEEDED', m: 'Rate exceeds the cap imposed by license', a: 'Rate exceeds cap imposed by license'},
22
- 11 => {r: false, c: 'INTERNAL_ERROR', m: 'Internal error (unexpected error)', a: 'Internal error'},
23
- 12 => {r: true, c: 'TRANSFER_ERROR', m: 'Error establishing control connection',
24
- a: 'Error establishing SSH connection (check SSH port and firewall)'},
25
- 13 => {r: true, c: 'TRANSFER_TIMEOUT', m: 'Timeout establishing control connection',
26
- a: 'Timeout establishing SSH connection (check SSH port and firewall)'},
27
- 14 => {r: true, c: 'CONNECTION_ERROR', m: 'Error establishing data connection',
28
- a: 'Error establishing UDP connection (check UDP port and firewall)'},
29
- 15 => {r: true, c: 'CONNECTION_TIMEOUT', m: 'Timeout establishing data connection',
30
- a: 'Timeout establishing UDP connection (check UDP port and firewall)'},
31
- 16 => {r: true, c: 'CONNECTION_LOST', m: 'Connection lost', a: 'Connection lost'},
32
- 17 => {r: true, c: 'RCVR_SEND_ERROR', m: 'Receiver fails to send feedback', a: 'Network failure (receiver can\'t send feedback)'},
33
- 18 => {r: true, c: 'RCVR_RECV_ERROR', m: 'Receiver fails to receive data packets', a: 'Network failure (receiver can\'t receive UDP data)'},
34
- 19 => {r: false, c: 'AUTH', m: 'Authentication failure', a: 'Authentication failure'},
35
- 20 => {r: false, c: 'NOTHING', m: 'Nothing to transfer', a: 'Nothing to transfer'},
36
- 21 => {r: false, c: 'NOT_REGULAR', m: 'Not a regular file (special file)', a: 'Not a regular file'},
37
- 22 => {r: false, c: 'FILE_TABLE_OVR', m: 'File table overflow', a: 'File table overflow'},
38
- 23 => {r: true, c: 'TOO_MANY_FILES', m: 'Too many files open', a: 'Too many files open'},
39
- 24 => {r: false, c: 'FILE_TOO_BIG', m: 'File too big for file system', a: 'File too big for filesystem'},
40
- 25 => {r: false, c: 'NO_SPACE_LEFT', m: 'No space left on disk', a: 'No space left on disk'},
41
- 26 => {r: false, c: 'READ_ONLY_FS', m: 'Read only file system', a: 'Read only filesystem'},
42
- 27 => {r: false, c: 'SOME_FILE_ERRS', m: 'Some individual files failed', a: 'One or more files failed'},
43
- 28 => {r: false, c: 'USER_CANCEL', m: 'Cancelled by user', a: 'Cancelled by user'},
44
- 29 => {r: false, c: 'LIC_NOLIC', m: 'License not found or unable to access', a: 'Unable to access license info'},
45
- 30 => {r: false, c: 'LIC_EXPIRED', m: 'License expired', a: 'License expired'},
46
- 31 => {r: false, c: 'SOCK_SETUP', m: 'Unable to setup socket (create, bind, etc ...)', a: 'Unable to set up socket'},
47
- 32 => {r: true, c: 'OUT_OF_MEMORY', m: 'Out of memory, unable to allocate', a: 'Out of memory'},
48
- 33 => {r: true, c: 'THREAD_SPAWN', m: 'Can\'t spawn thread', a: 'Unable to spawn thread'},
49
- 34 => {r: false, c: 'UNAUTHORIZED', m: 'Unauthorized by external auth server', a: 'Unauthorized'},
50
- 35 => {r: true, c: 'DISK_READ', m: 'Error reading source file from disk', a: 'Disk read error'},
51
- 36 => {r: true, c: 'DISK_WRITE', m: 'Error writing to disk', a: 'Disk write error'},
52
- 37 => {r: true, c: 'AUTHORIZATION', m: 'Used interchangeably with ERR_UNAUTHORIZED', a: 'Authorization failure'},
53
- 38 => {r: false, c: 'LIC_ILLEGAL', m: 'Operation not permitted by license', a: 'Operation not permitted by license'},
54
- 39 => {r: true, c: 'PEER_ABORTED_SESSION', m: 'Remote peer terminated session', a: 'Peer aborted session'},
55
- 40 => {r: true, c: 'DATA_TRANSFER_TIMEOUT', m: 'Transfer stalled, timed out', a: 'Data transfer stalled, timed out'},
56
- 41 => {r: false, c: 'BAD_PATH', m: 'Path violates docroot containment', a: 'File location is outside \'docroot\' hierarchy'},
57
- 42 => {r: false, c: 'ALREADY_EXISTS', m: 'File or directory already exists', a: 'File or directory already exists'},
58
- 43 => {r: false, c: 'STAT_FAILS', m: 'Cannot stat file', a: 'Cannot collect details about file or directory'},
59
- 44 => {r: true, c: 'PMTU_BRTT_ERROR', m: 'UDP session initiation fatal error', a: 'UDP session initiation fatal error'},
60
- 45 => {r: true, c: 'BWMEAS_ERROR', m: 'Bandwidth measurement fatal error', a: 'Bandwidth measurement fatal error'},
61
- 46 => {r: false, c: 'VLINK_ERROR', m: 'Virtual link error', a: 'Virtual link error'},
62
- 47 => {r: false, c: 'CONNECTION_ERROR_HTTP', m: 'Error establishing HTTP connection',
63
- a: 'Error establishing HTTP connection (check HTTP port and firewall)'},
64
- 48 => {r: false, c: 'FILE_ENCRYPTION_ERROR', m: 'File encryption error, e.g. corrupt file',
65
- a: 'File encryption/decryption error, e.g. corrupt file'},
66
- 49 => {r: false, c: 'FILE_DECRYPTION_PASS', m: 'File encryption/decryption error, e.g. corrupt file', a: 'File decryption error, bad passphrase'},
67
- 50 => {r: false, c: 'BAD_CONFIGURATION', m: 'Aspera.conf contains invalid data and was rejected', a: 'Invalid configuration'},
68
- 51 => {r: false, c: 'INSECURE_CONNECTION', m: 'Remote-host key check failure', a: 'Remote host is not who we expected'},
69
- 52 => {r: false, c: 'START_VALIDATION_FAILED', m: 'File start validation failed', a: 'File start validation failed'},
70
- 53 => {r: false, c: 'STOP_VALIDATION_FAILED', m: 'File stop validation failed', a: 'File stop validation failed'},
71
- 54 => {r: false, c: 'THRESHOLD_VALIDATION_FAILED', m: 'File threshold validation failed', a: 'File threshold validation failed'},
72
- 55 => {r: false, c: 'FILEPATH_TOO_LONG', m: 'File path/name too long for underlying file system', a: 'File path exceeds underlying file system limit'},
73
- 56 => {r: false, c: 'ILLEGAL_CHARS_IN_PATH', m: 'Windows path contains illegal characters',
74
- a: 'Path being written to Windows file system contains illegal characters'},
75
- 57 => {r: false, c: 'CHUNK_MUST_MATCH_ALIGNMENT', m: 'Chunk size/start must be aligned with storage', a: 'Chunk size/start must be aligned with storage'},
76
- 58 => {r: false, c: 'VALIDATION_SESSION_ABORT', m: 'Session aborted to due to validation error', a: 'Session aborted to due validation error'},
77
- 59 => {r: false, c: 'REMOTE_STORAGE_ERROR', m: 'Remote storage errored', a: 'Remote storage errored'},
78
- 60 => {r: false, c: 'LUA_SCRIPT_ABORTED_SESSION', m: 'Session aborted due to Lua script abort', a: 'Session aborted due to Lua script abort'},
79
- 61 => {r: true, c: 'SSEAR_RETRYABLE', m: 'Transfer failed because of a retryable Encryption at Rest error',
80
- a: 'Transfer failed because of a retryable Encryption at Rest error'},
81
- 62 => {r: false, c: 'SSEAR_FATAL', m: 'Transfer failed because of a fatal Encryption at Rest error',
82
- a: 'Transfer failed because of a fatal Encryption at Rest error'},
83
- 63 => {r: false, c: 'LINK_LOOP', m: 'Path refers to a symbolic link loop', a: 'Path refers to a symbolic link loop'},
84
- 64 => {r: false, c: 'CANNOT_RENAME_PARTIAL_FILES', m: 'Can\'t rename a partial file', a: 'Can\'t rename a partial file.'},
85
- 65 => {r: false, c: 'CIPHER_NON_COMPAT_FIPS', m: 'Can\'t use this cipher with FIPS mode enabled', a: 'Can\'t use this cipher with FIPS mode enabled'},
86
- 66 => {r: false, c: 'PEER_REQUIRES_FIPS', m: 'Peer rejects cipher due to FIPS mode enabled on peer',
87
- a: 'Peer rejects cipher due to FIPS mode enabled on peer'}
88
- }.freeze
89
- # rubocop:enable Layout/FirstHashElementLineBreak
90
- end
91
- end