aspera-cli 4.2.1 → 4.5.0

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1580 -946
  3. data/bin/ascli +1 -1
  4. data/bin/asession +3 -5
  5. data/docs/Makefile +8 -11
  6. data/docs/README.erb.md +1521 -829
  7. data/docs/doc_tools.rb +58 -0
  8. data/docs/test_env.conf +3 -1
  9. data/examples/faspex4.rb +28 -19
  10. data/examples/transfer.rb +2 -2
  11. data/lib/aspera/aoc.rb +157 -134
  12. data/lib/aspera/cli/listener/progress_multi.rb +5 -5
  13. data/lib/aspera/cli/main.rb +106 -48
  14. data/lib/aspera/cli/manager.rb +19 -20
  15. data/lib/aspera/cli/plugin.rb +22 -7
  16. data/lib/aspera/cli/plugins/aoc.rb +260 -208
  17. data/lib/aspera/cli/plugins/ats.rb +11 -10
  18. data/lib/aspera/cli/plugins/bss.rb +2 -2
  19. data/lib/aspera/cli/plugins/config.rb +360 -189
  20. data/lib/aspera/cli/plugins/faspex.rb +119 -56
  21. data/lib/aspera/cli/plugins/faspex5.rb +32 -17
  22. data/lib/aspera/cli/plugins/node.rb +72 -31
  23. data/lib/aspera/cli/plugins/orchestrator.rb +5 -3
  24. data/lib/aspera/cli/plugins/preview.rb +94 -68
  25. data/lib/aspera/cli/plugins/server.rb +16 -5
  26. data/lib/aspera/cli/plugins/shares.rb +17 -0
  27. data/lib/aspera/cli/transfer_agent.rb +64 -82
  28. data/lib/aspera/cli/version.rb +1 -1
  29. data/lib/aspera/command_line_builder.rb +48 -31
  30. data/lib/aspera/cos_node.rb +4 -3
  31. data/lib/aspera/environment.rb +4 -4
  32. data/lib/aspera/fasp/{manager.rb → agent_base.rb} +7 -6
  33. data/lib/aspera/fasp/{connect.rb → agent_connect.rb} +46 -39
  34. data/lib/aspera/fasp/{local.rb → agent_direct.rb} +42 -38
  35. data/lib/aspera/fasp/{http_gw.rb → agent_httpgw.rb} +50 -29
  36. data/lib/aspera/fasp/{node.rb → agent_node.rb} +43 -4
  37. data/lib/aspera/fasp/agent_trsdk.rb +106 -0
  38. data/lib/aspera/fasp/default.rb +17 -0
  39. data/lib/aspera/fasp/installation.rb +64 -48
  40. data/lib/aspera/fasp/parameters.rb +78 -91
  41. data/lib/aspera/fasp/parameters.yaml +531 -0
  42. data/lib/aspera/fasp/uri.rb +1 -1
  43. data/lib/aspera/faspex_gw.rb +12 -11
  44. data/lib/aspera/id_generator.rb +22 -0
  45. data/lib/aspera/keychain/encrypted_hash.rb +120 -0
  46. data/lib/aspera/keychain/macos_security.rb +94 -0
  47. data/lib/aspera/log.rb +45 -32
  48. data/lib/aspera/node.rb +9 -4
  49. data/lib/aspera/oauth.rb +116 -100
  50. data/lib/aspera/persistency_action_once.rb +11 -7
  51. data/lib/aspera/persistency_folder.rb +6 -26
  52. data/lib/aspera/rest.rb +66 -50
  53. data/lib/aspera/sync.rb +40 -35
  54. data/lib/aspera/timer_limiter.rb +22 -0
  55. metadata +86 -29
  56. data/docs/transfer_spec.html +0 -99
  57. data/lib/aspera/api_detector.rb +0 -60
  58. data/lib/aspera/fasp/aoc.rb +0 -24
  59. data/lib/aspera/secrets.rb +0 -20
@@ -4,105 +4,82 @@ require 'aspera/temp_file_manager'
4
4
  require 'securerandom'
5
5
  require 'base64'
6
6
  require 'json'
7
+ require 'yaml'
7
8
  require 'securerandom'
8
9
  require 'fileutils'
10
+ require 'openssl'
9
11
 
10
12
  module Aspera
11
13
  module Fasp
12
14
  # translate transfer specification to ascp parameter list
13
15
  class Parameters
14
16
  private
15
- # temp folder for file lists, must contain only file lists
17
+ # Temp folder for file lists, must contain only file lists
16
18
  # because of garbage collection takes any file there
17
19
  # this could be refined, as , for instance, on macos, temp folder is already user specific
18
20
  @@file_list_folder=TempFileManager.instance.new_file_path_global('asession_filelists')
19
- PARAM_DEFINITION={
20
- # parameters with env vars
21
- 'remote_password' => { :type => :envvar, :variable=>'ASPERA_SCP_PASS'},
22
- 'token' => { :type => :envvar, :variable=>'ASPERA_SCP_TOKEN'},
23
- 'cookie' => { :type => :envvar, :variable=>'ASPERA_SCP_COOKIE'},
24
- 'ssh_private_key' => { :type => :envvar, :variable=>'ASPERA_SCP_KEY'},
25
- 'EX_at_rest_password' => { :type => :envvar, :variable=>'ASPERA_SCP_FILEPASS'},
26
- 'EX_proxy_password' => { :type => :envvar, :variable=>'ASPERA_PROXY_PASS'},
27
- 'EX_license_text' => { :type => :envvar, :variable=>'ASPERA_SCP_LICENSE'},
28
- # bool params
29
- 'create_dir' => { :type => :opt_without_arg, :option_switch=>'-d'},
30
- 'precalculate_job_size' => { :type => :opt_without_arg},
31
- 'keepalive' => { :type => :opt_without_arg},
32
- 'delete_before_transfer' => { :type => :opt_without_arg}, #TODO: doc readme
33
- 'preserve_access_time' => { :type => :opt_without_arg}, #TODO: doc
34
- 'preserve_creation_time' => { :type => :opt_without_arg}, #TODO: doc
35
- 'preserve_times' => { :type => :opt_without_arg}, #TODO: doc
36
- 'preserve_modification_time'=> { :type => :opt_without_arg}, #TODO: doc
37
- 'remove_empty_directories'=> { :type => :opt_without_arg}, #TODO: doc
38
- 'remove_after_transfer' => { :type => :opt_without_arg}, #TODO: doc
39
- 'remove_empty_source_directory'=> { :type => :opt_without_arg}, #TODO: doc
40
- # value params
41
- 'cipher' => { :type => :opt_with_arg, :option_switch=>'-c',:accepted_types=>String,:encode=>lambda{|cipher|cipher.tr('-','')}},
42
- 'resume_policy' => { :type => :opt_with_arg, :option_switch=>'-k',:accepted_types=>String,:default=>'sparse_csum',:translate_values=>{'none'=>0,'attrs'=>1,'sparse_csum'=>2,'full_csum'=>3}},
43
- 'direction' => { :type => :opt_with_arg, :option_switch=>'--mode',:accepted_types=>String,:translate_values=>{'receive'=>'recv','send'=>'send'}},
44
- 'remote_user' => { :type => :opt_with_arg, :option_switch=>'--user',:accepted_types=>String},
45
- 'remote_host' => { :type => :opt_with_arg, :option_switch=>'--host',:accepted_types=>String},
46
- 'ssh_port' => { :type => :opt_with_arg, :option_switch=>'-P',:accepted_types=>Integer},
47
- 'fasp_port' => { :type => :opt_with_arg, :option_switch=>'-O',:accepted_types=>Integer},
48
- 'dgram_size' => { :type => :opt_with_arg, :option_switch=>'-Z',:accepted_types=>Integer},
49
- 'target_rate_kbps' => { :type => :opt_with_arg, :option_switch=>'-l',:accepted_types=>Integer},
50
- 'min_rate_kbps' => { :type => :opt_with_arg, :option_switch=>'-m',:accepted_types=>Integer},
51
- 'rate_policy' => { :type => :opt_with_arg, :option_switch=>'--policy',:accepted_types=>String},
52
- 'http_fallback' => { :type => :opt_with_arg, :option_switch=>'-y',:accepted_types=>[String,*Aspera::CommandLineBuilder::BOOLEAN_CLASSES],:translate_values=>{'force'=>'F',true=>1,false=>0}},
53
- 'http_fallback_port' => { :type => :opt_with_arg, :option_switch=>'-t',:accepted_types=>Integer},
54
- 'source_root' => { :type => :opt_with_arg, :option_switch=>'--source-prefix64',:accepted_types=>String,:encode=>lambda{|prefix|Base64.strict_encode64(prefix)}},
55
- 'sshfp' => { :type => :opt_with_arg, :option_switch=>'--check-sshfp',:accepted_types=>String},
56
- 'symlink_policy' => { :type => :opt_with_arg, :option_switch=>'--symbolic-links',:accepted_types=>String},
57
- 'overwrite' => { :type => :opt_with_arg, :accepted_types=>String},
58
- 'exclude_newer_than' => { :type => :opt_with_arg, :accepted_types=>Integer},
59
- 'exclude_older_than' => { :type => :opt_with_arg, :accepted_types=>Integer},
60
- 'preserve_acls' => { :type => :opt_with_arg, :accepted_types=>String},
61
- 'move_after_transfer' => { :type => :opt_with_arg, :accepted_types=>String},
62
- 'multi_session_threshold' => { :type => :opt_with_arg, :accepted_types=>Integer},
63
- # non standard parameters
64
- 'EX_fasp_proxy_url' => { :type => :opt_with_arg, :option_switch=>'--proxy',:accepted_types=>String},
65
- 'EX_http_proxy_url' => { :type => :opt_with_arg, :option_switch=>'-x',:accepted_types=>String},
66
- 'EX_ssh_key_paths' => { :type => :opt_with_arg, :option_switch=>'-i',:accepted_types=>Array},
67
- 'EX_http_transfer_jpeg' => { :type => :opt_with_arg, :option_switch=>'-j',:accepted_types=>Integer},
68
- 'EX_multi_session_part' => { :type => :opt_with_arg, :option_switch=>'-C',:accepted_types=>String},
69
- 'EX_no_read' => { :type => :opt_without_arg, :option_switch=>'--no-read'},
70
- 'EX_no_write' => { :type => :opt_without_arg, :option_switch=>'--no-write'},
71
- 'EX_apply_local_docroot' => { :type => :opt_without_arg, :option_switch=>'--apply-local-docroot'},
72
- # TODO: manage those parameters, some are for connect only ? node api ?
73
- 'target_rate_cap_kbps' => { :type => :ignore, :accepted_types=>Integer},
74
- 'target_rate_percentage' => { :type => :ignore, :accepted_types=>String}, # -wf -l<rate>p
75
- 'min_rate_cap_kbps' => { :type => :ignore, :accepted_types=>Integer},
76
- 'rate_policy_allowed' => { :type => :ignore, :accepted_types=>String},
77
- 'fasp_url' => { :type => :ignore, :accepted_types=>String},
78
- 'lock_rate_policy' => { :type => :ignore, :accepted_types=>Aspera::CommandLineBuilder::BOOLEAN_CLASSES},
79
- 'lock_min_rate' => { :type => :ignore, :accepted_types=>Aspera::CommandLineBuilder::BOOLEAN_CLASSES},
80
- 'lock_target_rate' => { :type => :ignore, :accepted_types=>Aspera::CommandLineBuilder::BOOLEAN_CLASSES},
81
- 'authentication' => { :type => :ignore, :accepted_types=>String}, # value = token
82
- 'https_fallback_port' => { :type => :ignore, :accepted_types=>Integer}, # same as http fallback, option -t ?
83
- 'content_protection' => { :type => :ignore, :accepted_types=>String},
84
- 'cipher_allowed' => { :type => :ignore, :accepted_types=>String},
85
- 'multi_session' => { :type => :ignore, :accepted_types=>Integer}, # managed
86
- 'obfuscate_file_names' => { :type => :ignore, :accepted_types=>Aspera::CommandLineBuilder::BOOLEAN_CLASSES},
87
- # optional tags ( additional option to generate: {:space=>' ',:object_nl=>' ',:space_before=>'+',:array_nl=>'1'} )
88
- 'tags' => { :type => :opt_with_arg, :option_switch=>'--tags64',:accepted_types=>Hash,:encode=>lambda{|tags|Base64.strict_encode64(JSON.generate(tags))}},
89
- # special processing @builder.process_param( called individually
90
- 'use_ascp4' => { :type => :defer, :accepted_types=>Aspera::CommandLineBuilder::BOOLEAN_CLASSES},
91
- 'paths' => { :type => :defer, :accepted_types=>Array},
92
- 'EX_file_list' => { :type => :defer, :option_switch=>'--file-list', :accepted_types=>String},
93
- 'EX_file_pair_list' => { :type => :defer, :option_switch=>'--file-pair-list', :accepted_types=>String},
94
- 'EX_ascp_args' => { :type => :defer, :accepted_types=>Array},
95
- 'destination_root' => { :type => :defer, :accepted_types=>String},
96
- 'wss_enabled' => { :type => :defer, :accepted_types=>Aspera::CommandLineBuilder::BOOLEAN_CLASSES},
97
- 'wss_port' => { :type => :defer, :accepted_types=>Integer},
98
- }
99
-
100
- private_constant :PARAM_DEFINITION
21
+ @@param_description_cache=nil
22
+ # @return normaiwed description of transfer spec parameters
23
+ def self.description
24
+ return @@param_description_cache unless @@param_description_cache.nil?
25
+ # config file in same folder with same name as this source
26
+ @@param_description_cache=YAML.load_file("#{__FILE__[0..-3]}yaml")
27
+ Aspera::CommandLineBuilder.normalize_description(@@param_description_cache)
28
+ end
29
+
30
+ # Agents shown in manual for parameters (sub list)
31
+ SUPPORTED_AGENTS=[:direct,:node,:connect]
32
+ # Short names of columns in manual
33
+ SUPPORTED_AGENTS_SHORT=SUPPORTED_AGENTS.map{|a|a.to_s[0].to_sym}
34
+
35
+ # @return a table suitable to display a manual
36
+ def self.man_table
37
+ result=[]
38
+ description.keys.map do |k|
39
+ i=description[k]
40
+ param={name: k, type: [i[:accepted_types]].flatten.join(','),description: i[:desc]}
41
+ SUPPORTED_AGENTS.each do |a|
42
+ param[a.to_s[0].to_sym]=i[:context].nil? || i[:context].include?(a) ? 'Y' : ''
43
+ end
44
+ # only keep lines that are usable in supported agents
45
+ next if SUPPORTED_AGENTS_SHORT.inject(true){|m,i|m and param[i].empty?}
46
+ param[:cli]=case i[:cltype]
47
+ when :envvar; 'env:'+i[:clvarname]
48
+ when :opt_without_arg,:opt_with_arg; i[:option_switch]
49
+ else ''
50
+ end
51
+ if i.has_key?(:enum)
52
+ param[:description] << "\nAllowed values: #{i[:enum].join(', ')}"
53
+ end
54
+ result.push(param)
55
+ end
56
+ return result
57
+ end
58
+
59
+ # special encoding methods used in YAML (key: :encode)
60
+ def self.encode_cipher(v)
61
+ v.tr('-','')
62
+ end
63
+
64
+ # special encoding methods used in YAML (key: :encode)
65
+ def self.encode_source_root(v)
66
+ Base64.strict_encode64(v)
67
+ end
68
+
69
+ # special encoding methods used in YAML (key: :encode)
70
+ def self.encode_tags(v)
71
+ Base64.strict_encode64(JSON.generate(v))
72
+ end
73
+
74
+ def self.ts_has_file_list(ts)
75
+ ts.has_key?('EX_ascp_args') and ts['EX_ascp_args'].is_a?(Array) and ['--file-list','--file-pair-list'].any?{|i|ts['EX_ascp_args'].include?(i)}
76
+ end
101
77
 
102
78
  def initialize(job_spec,options)
103
79
  @job_spec=job_spec
104
- @builder=Aspera::CommandLineBuilder.new(@job_spec,PARAM_DEFINITION)
105
80
  @options=options
81
+ @builder=Aspera::CommandLineBuilder.new(@job_spec,self.class.description)
82
+ Log.log.debug("agent options: #{@options}")
106
83
  end
107
84
 
108
85
  public
@@ -125,8 +102,8 @@ module Aspera
125
102
  # special cases
126
103
  @job_spec.delete('source_root') if @job_spec.has_key?('source_root') and @job_spec['source_root'].empty?
127
104
 
128
- # use web socket initiation ?
129
- if @builder.process_param('wss_enabled',:get_value) and @options[:wss]
105
+ # use web socket session initiation ?
106
+ if @builder.process_param('wss_enabled',:get_value) and ( @options[:wss] or !@job_spec.has_key?('fasp_port') )
130
107
  # by default use web socket session if available, unless removed by user
131
108
  @builder.add_command_line_options(['--ws-connect'])
132
109
  # TODO: option to give order ssh,ws (legacy http is implied bu ssh)
@@ -135,6 +112,9 @@ module Aspera
135
112
  @job_spec.delete('fasp_port')
136
113
  @job_spec.delete('EX_ssh_key_paths')
137
114
  @job_spec.delete('sshfp')
115
+ # set default location for CA bundle, see env var SSL_CERT_FILE / SSL_CERT_DIR
116
+ @job_spec['EX_ssh_key_paths']=[OpenSSL::X509::DEFAULT_CERT_FILE]
117
+ Log.log.debug("CA certs: EX_ssh_key_paths <- DEFAULT_CERT_FILE from openssl")
138
118
  else
139
119
  # remove unused parameter (avoid warning)
140
120
  @job_spec.delete('wss_port')
@@ -151,10 +131,17 @@ module Aspera
151
131
  # destination will be base64 encoded, put before path arguments
152
132
  @builder.add_command_line_options(['--dest64'])
153
133
  end
154
-
155
- PARAM_DEFINITION['paths'][:mandatory]=!@job_spec.has_key?('keepalive')
134
+ # paths is mandatory, unless ...
135
+ file_list_provided=self.class.ts_has_file_list(@job_spec)
136
+ @builder.params_definition['paths'][:mandatory]=!@job_spec.has_key?('keepalive') and !file_list_provided
156
137
  paths_array=@builder.process_param('paths',:get_value)
157
- unless paths_array.nil?
138
+ if file_list_provided and ! paths_array.nil?
139
+ Log.log.warn("file list provided both in transfer spec and ascp file list. Keeping file list only.")
140
+ paths_array=nil
141
+ end
142
+ if ! paths_array.nil?
143
+ # it's an array
144
+ raise "paths is empty in transfer spec" if paths_array.empty?
158
145
  # use file list if there is storage defined for it.
159
146
  if @@file_list_folder.nil?
160
147
  # not safe for special characters ? (maybe not, depends on OS)
@@ -180,8 +167,8 @@ module Aspera
180
167
  lines=paths_array.map{|i|i['source']}
181
168
  end
182
169
  file_list_file=Aspera::TempFileManager.instance.new_file_path_in_folder(@@file_list_folder)
183
- File.open(file_list_file, 'w+'){|f|f.puts(lines)}
184
- Log.log.debug("#{option}=\n#{File.read(file_list_file)}".red)
170
+ File.open(file_list_file, 'w+'){|f|f.write(lines.join("\n"))}
171
+ Log.log.debug{"#{option}=\n#{File.read(file_list_file)}".red}
185
172
  end
186
173
  end
187
174
  @builder.add_command_line_options(["#{option}=#{file_list_file}"])