aspera-cli 4.10.0 → 4.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/BUGS.md +19 -0
  4. data/CHANGELOG.md +528 -0
  5. data/CONTRIBUTING.md +143 -0
  6. data/README.md +977 -589
  7. data/bin/ascli +4 -4
  8. data/bin/asession +12 -12
  9. data/docs/test_env.conf +29 -19
  10. data/examples/aoc.rb +6 -6
  11. data/examples/dascli +18 -16
  12. data/examples/faspex4.rb +15 -15
  13. data/examples/node.rb +12 -12
  14. data/examples/proxy.pac +2 -2
  15. data/examples/server.rb +12 -12
  16. data/lib/aspera/aoc.rb +344 -272
  17. data/lib/aspera/ascmd.rb +56 -54
  18. data/lib/aspera/ats_api.rb +4 -4
  19. data/lib/aspera/cli/basic_auth_plugin.rb +15 -12
  20. data/lib/aspera/cli/extended_value.rb +9 -9
  21. data/lib/aspera/cli/{formater.rb → formatter.rb} +69 -69
  22. data/lib/aspera/cli/listener/line_dump.rb +1 -1
  23. data/lib/aspera/cli/listener/logger.rb +1 -1
  24. data/lib/aspera/cli/listener/progress.rb +5 -6
  25. data/lib/aspera/cli/listener/progress_multi.rb +16 -21
  26. data/lib/aspera/cli/main.rb +72 -73
  27. data/lib/aspera/cli/manager.rb +112 -112
  28. data/lib/aspera/cli/plugin.rb +68 -48
  29. data/lib/aspera/cli/plugins/alee.rb +4 -4
  30. data/lib/aspera/cli/plugins/aoc.rb +322 -720
  31. data/lib/aspera/cli/plugins/ats.rb +50 -52
  32. data/lib/aspera/cli/plugins/bss.rb +10 -10
  33. data/lib/aspera/cli/plugins/config.rb +514 -410
  34. data/lib/aspera/cli/plugins/console.rb +12 -12
  35. data/lib/aspera/cli/plugins/cos.rb +18 -20
  36. data/lib/aspera/cli/plugins/faspex.rb +134 -136
  37. data/lib/aspera/cli/plugins/faspex5.rb +235 -70
  38. data/lib/aspera/cli/plugins/node.rb +378 -309
  39. data/lib/aspera/cli/plugins/orchestrator.rb +52 -49
  40. data/lib/aspera/cli/plugins/preview.rb +129 -120
  41. data/lib/aspera/cli/plugins/server.rb +137 -83
  42. data/lib/aspera/cli/plugins/shares.rb +77 -52
  43. data/lib/aspera/cli/plugins/sync.rb +13 -33
  44. data/lib/aspera/cli/transfer_agent.rb +61 -61
  45. data/lib/aspera/cli/version.rb +2 -1
  46. data/lib/aspera/colors.rb +3 -3
  47. data/lib/aspera/command_line_builder.rb +78 -74
  48. data/lib/aspera/cos_node.rb +31 -29
  49. data/lib/aspera/data_repository.rb +1 -1
  50. data/lib/aspera/environment.rb +30 -28
  51. data/lib/aspera/fasp/agent_base.rb +17 -15
  52. data/lib/aspera/fasp/agent_connect.rb +34 -32
  53. data/lib/aspera/fasp/agent_direct.rb +70 -73
  54. data/lib/aspera/fasp/agent_httpgw.rb +79 -74
  55. data/lib/aspera/fasp/agent_node.rb +26 -26
  56. data/lib/aspera/fasp/agent_trsdk.rb +20 -20
  57. data/lib/aspera/fasp/error.rb +3 -2
  58. data/lib/aspera/fasp/error_info.rb +11 -8
  59. data/lib/aspera/fasp/installation.rb +80 -80
  60. data/lib/aspera/fasp/listener.rb +2 -2
  61. data/lib/aspera/fasp/parameters.rb +103 -92
  62. data/lib/aspera/fasp/parameters.yaml +313 -214
  63. data/lib/aspera/fasp/resume_policy.rb +10 -10
  64. data/lib/aspera/fasp/transfer_spec.rb +22 -2
  65. data/lib/aspera/fasp/uri.rb +7 -7
  66. data/lib/aspera/faspex_gw.rb +80 -159
  67. data/lib/aspera/faspex_postproc.rb +77 -0
  68. data/lib/aspera/hash_ext.rb +3 -3
  69. data/lib/aspera/id_generator.rb +5 -5
  70. data/lib/aspera/keychain/encrypted_hash.rb +23 -28
  71. data/lib/aspera/keychain/macos_security.rb +21 -20
  72. data/lib/aspera/log.rb +13 -13
  73. data/lib/aspera/nagios.rb +24 -23
  74. data/lib/aspera/node.rb +217 -38
  75. data/lib/aspera/oauth.rb +78 -74
  76. data/lib/aspera/open_application.rb +19 -11
  77. data/lib/aspera/persistency_action_once.rb +4 -4
  78. data/lib/aspera/persistency_folder.rb +13 -13
  79. data/lib/aspera/preview/file_types.rb +8 -8
  80. data/lib/aspera/preview/generator.rb +67 -67
  81. data/lib/aspera/preview/utils.rb +27 -27
  82. data/lib/aspera/proxy_auto_config.js +63 -63
  83. data/lib/aspera/proxy_auto_config.rb +19 -19
  84. data/lib/aspera/rest.rb +65 -67
  85. data/lib/aspera/rest_call_error.rb +2 -1
  86. data/lib/aspera/rest_error_analyzer.rb +22 -21
  87. data/lib/aspera/rest_errors_aspera.rb +16 -16
  88. data/lib/aspera/secret_hider.rb +17 -14
  89. data/lib/aspera/ssh.rb +15 -14
  90. data/lib/aspera/sync.rb +177 -62
  91. data/lib/aspera/temp_file_manager.rb +2 -2
  92. data/lib/aspera/uri_reader.rb +4 -4
  93. data/lib/aspera/web_auth.rb +13 -64
  94. data/lib/aspera/web_server_simple.rb +76 -0
  95. data.tar.gz.sig +0 -0
  96. metadata +11 -6
  97. metadata.gz.sig +0 -0
@@ -10,12 +10,16 @@ module Aspera
10
10
  OS_X = :osx
11
11
  OS_LINUX = :linux
12
12
  OS_AIX = :aix
13
- OS_LIST = [OS_WINDOWS,OS_X,OS_LINUX,OS_AIX].freeze
13
+ OS_LIST = [OS_WINDOWS, OS_X, OS_LINUX, OS_AIX].freeze
14
14
  CPU_X86_64 = :x86_64
15
15
  CPU_PPC64 = :ppc64
16
16
  CPU_PPC64LE = :ppc64le
17
17
  CPU_S390 = :s390
18
- CPU_LIST = [CPU_X86_64,CPU_PPC64,CPU_PPC64LE,CPU_S390].freeze
18
+ CPU_LIST = [CPU_X86_64, CPU_PPC64, CPU_PPC64LE, CPU_S390].freeze
19
+
20
+ BITS_PER_BYTE = 8
21
+ MEBI = 1024 * 1024
22
+ BYTES_PER_MEBIBIT = MEBI / BITS_PER_BYTE
19
23
 
20
24
  class << self
21
25
  def ruby_version
@@ -24,9 +28,9 @@ module Aspera
24
28
 
25
29
  def os
26
30
  case RbConfig::CONFIG['host_os']
27
- when /mswin/,/msys/,/mingw/,/cygwin/,/bccwin/,/wince/,/emc/
31
+ when /mswin/, /msys/, /mingw/, /cygwin/, /bccwin/, /wince/, /emc/
28
32
  return OS_WINDOWS
29
- when /darwin/,/mac os/
33
+ when /darwin/, /mac os/
30
34
  return OS_X
31
35
  when /linux/
32
36
  return OS_LINUX
@@ -39,9 +43,9 @@ module Aspera
39
43
 
40
44
  def cpu
41
45
  case RbConfig::CONFIG['host_cpu']
42
- when /x86_64/,/x64/
46
+ when /x86_64/, /x64/
43
47
  return CPU_X86_64
44
- when /powerpc/,/ppc64/
48
+ when /powerpc/, /ppc64/
45
49
  return CPU_PPC64LE if os.eql?(OS_LINUX)
46
50
  return CPU_PPC64
47
51
  when /s390/
@@ -65,9 +69,9 @@ module Aspera
65
69
  # on Windows, the env var %USERPROFILE% provides the path to user's home more reliably than %HOMEDRIVE%%HOMEPATH%
66
70
  # so, tell Ruby the right way
67
71
  def fix_home
68
- return unless os.eql?(OS_WINDOWS) && ENV.has_key?('USERPROFILE') && Dir.exist?(ENV['USERPROFILE'])
72
+ return unless os.eql?(OS_WINDOWS) && ENV.key?('USERPROFILE') && Dir.exist?(ENV['USERPROFILE'])
69
73
  ENV['HOME'] = ENV['USERPROFILE']
70
- Log.log.debug("Windows: set home to USERPROFILE: #{ENV['HOME']}")
74
+ Log.log.debug{"Windows: set home to USERPROFILE: #{ENV['HOME']}"}
71
75
  end
72
76
 
73
77
  def empty_binding
@@ -76,37 +80,35 @@ module Aspera
76
80
 
77
81
  # secure execution of Ruby code
78
82
  def secure_eval(code)
79
- Kernel.send('lave'.reverse,code,empty_binding, __FILE__, __LINE__)
83
+ Kernel.send('lave'.reverse, code, empty_binding, __FILE__, __LINE__)
80
84
  end
81
85
 
82
86
  # value is provided in block
83
- def write_file_restricted(path,force: false)
87
+ def write_file_restricted(path, force: false)
84
88
  raise 'coding error, missing content block' unless block_given?
85
89
  if force || !File.exist?(path)
86
90
  File.unlink(path) rescue nil # Windows may give error
87
- File.write(path,yield)
91
+ File.write(path, yield)
88
92
  restrict_file_access(path)
89
93
  end
90
94
  return path
91
95
  end
92
96
 
93
- def restrict_file_access(path,mode: nil)
94
- begin
95
- if mode.nil?
96
- # or FileUtils ?
97
- if File.file?(path)
98
- mode=0600
99
- elsif File.directory?(path)
100
- mode=0700
101
- else
102
- Log.log.debug("No restriction can be set for #{path}");
103
- end
97
+ def restrict_file_access(path, mode: nil)
98
+ if mode.nil?
99
+ # or FileUtils ?
100
+ if File.file?(path)
101
+ mode = 0o600
102
+ elsif File.directory?(path)
103
+ mode = 0o700
104
+ else
105
+ Log.log.debug{"No restriction can be set for #{path}"}
104
106
  end
105
- File.chmod(mode,path) unless mode.nil?
106
- rescue => e
107
- Log.log.warn(e.message)
108
107
  end
108
+ File.chmod(mode, path) unless mode.nil?
109
+ rescue => e
110
+ Log.log.warn(e.message)
109
111
  end
110
- end
111
- end
112
- end
112
+ end # self
113
+ end # Environment
114
+ end # Aspera
@@ -6,6 +6,7 @@ module Aspera
6
6
  # sub classes shall implement start_transfer and shutdown
7
7
  class AgentBase
8
8
  # fields description for JSON generation
9
+ # spellchecker: disable
9
10
  INTEGER_FIELDS = %w[Bytescont FaspFileArgIndex StartByte Rate MinRate Port Priority RateCap MinRateCap TCPPort CreatePolicy TimePolicy
10
11
  DatagramSize XoptFlags VLinkVersion PeerVLinkVersion DSPipelineDepth PeerDSPipelineDepth ReadBlockSize WriteBlockSize
11
12
  ClusterNumNodes ClusterNodeId Size Written Loss FileBytes PreTransferBytes TransferBytes PMTU Elapsedusec ArgScansAttempted
@@ -13,7 +14,8 @@ module Aspera
13
14
  BOOLEAN_FIELDS = %w[Encryption Remote RateLock MinRateLock PolicyLock FilesEncrypt FilesDecrypt VLinkLocalEnabled VLinkRemoteEnabled
14
15
  MoveRange Keepalive TestLogin UseProxy Precalc RTTAutocorrect].freeze
15
16
  EXPECTED_METHODS = %i[text struct enhanced].freeze
16
- private_constant :INTEGER_FIELDS,:BOOLEAN_FIELDS,:EXPECTED_METHODS
17
+ private_constant :INTEGER_FIELDS, :BOOLEAN_FIELDS, :EXPECTED_METHODS
18
+ # spellchecker: enable
17
19
 
18
20
  class << self
19
21
  # This checks the validity of the value returned by wait_for_transfers_completion
@@ -28,13 +30,13 @@ module Aspera
28
30
 
29
31
  # translates legacy event into enhanced (JSON) event
30
32
  def enhanced_event_format(event)
31
- return event.keys.each_with_object({}) do |e,h|
33
+ return event.keys.each_with_object({}) do |e, h|
32
34
  # capital_to_snake_case
33
- new_name = e.
34
- gsub(/([a-z\d])([A-Z])/,'\1_\2').
35
- gsub(/([a-z\d])(usec)$/,'\1_\2').
36
- gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
37
- downcase
35
+ new_name = e
36
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
37
+ .gsub(/([a-z\d])(usec)$/, '\1_\2')
38
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
39
+ .downcase
38
40
  value = event[e]
39
41
  value = value.to_i if INTEGER_FIELDS.include?(e)
40
42
  value = value.eql?('Yes') if BOOLEAN_FIELDS.include?(e)
@@ -46,7 +48,7 @@ module Aspera
46
48
  @listeners = []
47
49
  end
48
50
 
49
- def notify_listeners(current_event_text,current_event_data)
51
+ def notify_listeners(current_event_text, current_event_data)
50
52
  Log.log.debug('send event to listeners')
51
53
  enhanced_event = nil
52
54
  @listeners.each do |listener|
@@ -59,16 +61,16 @@ module Aspera
59
61
  end
60
62
  end # notify_listeners
61
63
 
62
- def notify_begin(id,size)
63
- notify_listeners('emulated',{LISTENER_SESSION_ID_B => id,'Type' => 'NOTIFICATION','PreTransferBytes' => size})
64
+ def notify_begin(id, size)
65
+ notify_listeners('emulated', {LISTENER_SESSION_ID_B => id, 'Type' => 'NOTIFICATION', 'PreTransferBytes' => size})
64
66
  end
65
67
 
66
- def notify_progress(id,size)
67
- notify_listeners('emulated',{LISTENER_SESSION_ID_B => id,'Type' => 'STATS','Bytescont' => size})
68
+ def notify_progress(id, size)
69
+ notify_listeners('emulated', {LISTENER_SESSION_ID_B => id, 'Type' => 'STATS', 'Bytescont' => size})
68
70
  end
69
71
 
70
72
  def notify_end(id)
71
- notify_listeners('emulated',{LISTENER_SESSION_ID_B => id,'Type' => 'DONE'})
73
+ notify_listeners('emulated', {LISTENER_SESSION_ID_B => id, 'Type' => 'DONE'})
72
74
  end
73
75
 
74
76
  public
@@ -78,13 +80,13 @@ module Aspera
78
80
 
79
81
  # listener receives events
80
82
  def add_listener(listener)
81
- raise "expect one of #{EXPECTED_METHODS}" if EXPECTED_METHODS.inject(0){|m,e|m += listener.respond_to?("event_#{e}") ? 1 : 0;m}.eql?(0)
83
+ raise "expect one of #{EXPECTED_METHODS}" if EXPECTED_METHODS.inject(0){|m, e|m + (listener.respond_to?("event_#{e}") ? 1 : 0)}.eql?(0)
82
84
  @listeners.push(listener)
83
85
  self
84
86
  end
85
87
 
86
88
  # the following methods must be implemented by subclass:
87
- # start_transfer(transfer_spec,options) : start and wait for completion
89
+ # start_transfer(transfer_spec, token_regenerator: nil) : start transfer
88
90
  # wait_for_transfers_completion : wait for termination of all transfers, @return list of : :success or error message
89
91
  # optional: shutdown
90
92
  end
@@ -8,52 +8,54 @@ require 'tty-spinner'
8
8
 
9
9
  module Aspera
10
10
  module Fasp
11
- class AgentConnect < AgentBase
12
- MAX_CONNECT_START_RETRY = 3
13
- SLEEP_SEC_BETWEEN_RETRY = 2
14
- private_constant :MAX_CONNECT_START_RETRY,:SLEEP_SEC_BETWEEN_RETRY
11
+ class AgentConnect < Aspera::Fasp::AgentBase
12
+ CONNECT_START_URIS = ['fasp://initialize', 'fasp://initialize', 'aspera-drive://initialize', 'https://test-connect.ibmaspera.com/']
13
+ SLEEP_SEC_BETWEEN_RETRY = 3
14
+ private_constant :CONNECT_START_URIS, :SLEEP_SEC_BETWEEN_RETRY
15
15
  def initialize(_options)
16
16
  super()
17
17
  @connect_settings = {
18
18
  'app_id' => SecureRandom.uuid
19
19
  }
20
20
  raise 'Using connect requires a graphical environment' if !OpenApplication.default_gui_mode.eql?(:graphical)
21
- trynumber = 0
21
+ method_index = 0
22
22
  begin
23
23
  connect_url = Installation.instance.connect_uri
24
- Log.log.debug("found: #{connect_url}")
25
- @connect_api = Rest.new({base_url: "#{connect_url}/v5/connect",headers: {'Origin' => Rest.user_agent}}) # could use v6 also now
26
- cinfo = @connect_api.read('info/version')[:data]
27
- Log.dump(:connect_version,cinfo)
24
+ Log.log.debug{"found: #{connect_url}"}
25
+ @connect_api = Rest.new({base_url: "#{connect_url}/v5/connect", headers: {'Origin' => Rest.user_agent}}) # could use v6 also now
26
+ connect_info = @connect_api.read('info/version')[:data]
27
+ Log.log.info('Connect was reached') if method_index > 0
28
+ Log.dump(:connect_version, connect_info)
28
29
  rescue StandardError => e # Errno::ECONNREFUSED
29
- raise StandardError,"Unable to start connect after #{trynumber} try" if trynumber >= MAX_CONNECT_START_RETRY
30
- Log.log.warn("connect is not started. Retry ##{trynumber}, err=#{e}")
31
- trynumber += 1
32
- if !OpenApplication.uri_graphical('fasp://initialize')
30
+ start_url = CONNECT_START_URIS[method_index]
31
+ method_index += 1
32
+ raise StandardError, "Unable to start connect #{method_index} times" if start_url.nil?
33
+ Log.log.warn{"Aspera Connect is not started (#{e}). Trying to start it ##{method_index}..."}
34
+ if !OpenApplication.uri_graphical(start_url)
33
35
  OpenApplication.uri_graphical('https://downloads.asperasoft.com/connect2/')
34
- raise StandardError,'Connect is not installed'
36
+ raise StandardError, 'Connect is not installed'
35
37
  end
36
38
  sleep(SLEEP_SEC_BETWEEN_RETRY)
37
39
  retry
38
40
  end
39
41
  end
40
42
 
41
- def start_transfer(transfer_spec,_options=nil)
43
+ def start_transfer(transfer_spec, token_regenerator: nil)
42
44
  if transfer_spec['direction'] == 'send'
43
- Log.log.warn("Connect requires upload selection using GUI, ignoring #{transfer_spec['paths']}".red)
45
+ Log.log.warn{"Connect requires upload selection using GUI, ignoring #{transfer_spec['paths']}".red}
44
46
  transfer_spec.delete('paths')
45
- resdata = @connect_api.create('windows/select-open-file-dialog/',{
47
+ selection = @connect_api.create('windows/select-open-file-dialog/', {
46
48
  'aspera_connect_settings' => @connect_settings,
47
49
  'title' => 'Select Files',
48
50
  'suggestedName' => '',
49
51
  'allowMultipleSelection' => true,
50
52
  'allowedFileTypes' => ''})[:data]
51
- transfer_spec['paths'] = resdata['dataTransfer']['files'].map { |i| {'source' => i['name']}}
53
+ transfer_spec['paths'] = selection['dataTransfer']['files'].map { |i| {'source' => i['name']}}
52
54
  end
53
55
  @request_id = SecureRandom.uuid
54
56
  # if there is a token, we ask connect client to use well known ssh private keys
55
57
  # instead of asking password
56
- transfer_spec['authentication'] = 'token' if transfer_spec.has_key?('token')
58
+ transfer_spec['authentication'] = 'token' if transfer_spec.key?('token')
57
59
  connect_transfer_args = {
58
60
  'aspera_connect_settings' => @connect_settings.merge({
59
61
  'request_id' => @request_id,
@@ -63,7 +65,7 @@ module Aspera
63
65
  'transfer_spec' => transfer_spec
64
66
  }]}
65
67
  # asynchronous anyway
66
- res = @connect_api.create('transfers/start',connect_transfer_args)[:data]
68
+ res = @connect_api.create('transfers/start', connect_transfer_args)[:data]
67
69
  @xfer_id = res['transfer_specs'].first['transfer_spec']['tags']['aspera']['xfer_id']
68
70
  end
69
71
 
@@ -73,39 +75,39 @@ module Aspera
73
75
  spinner = nil
74
76
  begin
75
77
  loop do
76
- tr_info = @connect_api.create("transfers/info/#{@xfer_id}",connect_activity_args)[:data]
78
+ tr_info = @connect_api.create("transfers/info/#{@xfer_id}", connect_activity_args)[:data]
77
79
  if tr_info['transfer_info'].is_a?(Hash)
78
- trdata = tr_info['transfer_info']
79
- if trdata.nil?
80
+ transfer = tr_info['transfer_info']
81
+ if transfer.nil?
80
82
  Log.log.warn('no session in Connect')
81
83
  break
82
84
  end
83
85
  # TODO: get session id
84
- case trdata['status']
86
+ case transfer['status']
85
87
  when 'completed'
86
88
  notify_end(@connect_settings['app_id'])
87
89
  break
88
- when 'initiating','queued'
90
+ when 'initiating', 'queued'
89
91
  if spinner.nil?
90
92
  spinner = TTY::Spinner.new('[:spinner] :title', format: :classic)
91
93
  spinner.start
92
94
  end
93
- spinner.update(title: trdata['status'])
95
+ spinner.update(title: transfer['status'])
94
96
  spinner.spin
95
97
  when 'running'
96
- #puts "running: sessions:#{trdata['sessions'].length}, #{trdata['sessions'].map{|i| i['bytes_transferred']}.join(',')}"
97
- if !started && (trdata['bytes_expected'] != 0)
98
+ # puts "running: sessions:#{transfer['sessions'].length}, #{transfer['sessions'].map{|i| i['bytes_transferred']}.join(',')}"
99
+ if !started && (transfer['bytes_expected'] != 0)
98
100
  spinner&.success
99
- notify_begin(@connect_settings['app_id'],trdata['bytes_expected'])
101
+ notify_begin(@connect_settings['app_id'], transfer['bytes_expected'])
100
102
  started = true
101
103
  else
102
- notify_progress(@connect_settings['app_id'],trdata['bytes_written'])
104
+ notify_progress(@connect_settings['app_id'], transfer['bytes_written'])
103
105
  end
104
106
  when 'failed'
105
107
  spinner&.error
106
- raise Fasp::Error, trdata['error_desc']
108
+ raise Fasp::Error, transfer['error_desc']
107
109
  else
108
- raise Fasp::Error, "unknown status: #{trdata['status']}: #{trdata['error_desc']}"
110
+ raise Fasp::Error, "unknown status: #{transfer['status']}: #{transfer['error_desc']}"
109
111
  end
110
112
  end
111
113
  sleep(1)