aspera-cli 4.9.0 → 4.11.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 (95) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/BUGS.md +20 -0
  4. data/CHANGELOG.md +509 -0
  5. data/CONTRIBUTING.md +118 -0
  6. data/README.md +1241 -916
  7. data/bin/ascli +4 -4
  8. data/bin/asession +11 -11
  9. data/docs/test_env.conf +32 -21
  10. data/examples/aoc.rb +4 -4
  11. data/examples/dascli +16 -9
  12. data/examples/faspex4.rb +8 -8
  13. data/examples/node.rb +12 -12
  14. data/examples/server.rb +10 -10
  15. data/lib/aspera/aoc.rb +273 -266
  16. data/lib/aspera/ascmd.rb +56 -54
  17. data/lib/aspera/ats_api.rb +4 -4
  18. data/lib/aspera/cli/basic_auth_plugin.rb +15 -12
  19. data/lib/aspera/cli/extended_value.rb +5 -5
  20. data/lib/aspera/cli/formater.rb +64 -64
  21. data/lib/aspera/cli/info.rb +2 -2
  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 +14 -19
  26. data/lib/aspera/cli/main.rb +66 -67
  27. data/lib/aspera/cli/manager.rb +112 -110
  28. data/lib/aspera/cli/plugin.rb +57 -36
  29. data/lib/aspera/cli/plugins/alee.rb +4 -4
  30. data/lib/aspera/cli/plugins/aoc.rb +309 -670
  31. data/lib/aspera/cli/plugins/ats.rb +44 -46
  32. data/lib/aspera/cli/plugins/bss.rb +10 -10
  33. data/lib/aspera/cli/plugins/config.rb +497 -378
  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 +112 -114
  37. data/lib/aspera/cli/plugins/faspex5.rb +71 -46
  38. data/lib/aspera/cli/plugins/node.rb +379 -283
  39. data/lib/aspera/cli/plugins/orchestrator.rb +46 -46
  40. data/lib/aspera/cli/plugins/preview.rb +122 -114
  41. data/lib/aspera/cli/plugins/server.rb +137 -83
  42. data/lib/aspera/cli/plugins/shares.rb +30 -29
  43. data/lib/aspera/cli/plugins/sync.rb +13 -33
  44. data/lib/aspera/cli/transfer_agent.rb +60 -59
  45. data/lib/aspera/cli/version.rb +1 -1
  46. data/lib/aspera/colors.rb +3 -3
  47. data/lib/aspera/command_line_builder.rb +27 -27
  48. data/lib/aspera/cos_node.rb +22 -20
  49. data/lib/aspera/data_repository.rb +1 -1
  50. data/lib/aspera/environment.rb +35 -15
  51. data/lib/aspera/fasp/agent_base.rb +15 -15
  52. data/lib/aspera/fasp/agent_connect.rb +23 -21
  53. data/lib/aspera/fasp/agent_direct.rb +66 -64
  54. data/lib/aspera/fasp/agent_httpgw.rb +141 -78
  55. data/lib/aspera/fasp/agent_node.rb +23 -21
  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 +79 -79
  60. data/lib/aspera/fasp/listener.rb +1 -1
  61. data/lib/aspera/fasp/parameters.rb +86 -71
  62. data/lib/aspera/fasp/parameters.yaml +7 -4
  63. data/lib/aspera/fasp/resume_policy.rb +8 -8
  64. data/lib/aspera/fasp/transfer_spec.rb +35 -2
  65. data/lib/aspera/fasp/uri.rb +7 -7
  66. data/lib/aspera/faspex_gw.rb +7 -5
  67. data/lib/aspera/hash_ext.rb +3 -3
  68. data/lib/aspera/id_generator.rb +5 -5
  69. data/lib/aspera/keychain/encrypted_hash.rb +38 -105
  70. data/lib/aspera/keychain/macos_security.rb +128 -57
  71. data/lib/aspera/log.rb +7 -7
  72. data/lib/aspera/nagios.rb +19 -18
  73. data/lib/aspera/node.rb +209 -35
  74. data/lib/aspera/oauth.rb +37 -36
  75. data/lib/aspera/open_application.rb +19 -11
  76. data/lib/aspera/persistency_action_once.rb +4 -4
  77. data/lib/aspera/persistency_folder.rb +16 -15
  78. data/lib/aspera/preview/file_types.rb +8 -8
  79. data/lib/aspera/preview/generator.rb +67 -67
  80. data/lib/aspera/preview/utils.rb +27 -27
  81. data/lib/aspera/proxy_auto_config.js +41 -41
  82. data/lib/aspera/proxy_auto_config.rb +21 -14
  83. data/lib/aspera/rest.rb +72 -67
  84. data/lib/aspera/rest_call_error.rb +2 -1
  85. data/lib/aspera/rest_error_analyzer.rb +18 -17
  86. data/lib/aspera/rest_errors_aspera.rb +16 -16
  87. data/lib/aspera/secret_hider.rb +15 -13
  88. data/lib/aspera/ssh.rb +11 -10
  89. data/lib/aspera/sync.rb +158 -44
  90. data/lib/aspera/temp_file_manager.rb +2 -2
  91. data/lib/aspera/uri_reader.rb +4 -4
  92. data/lib/aspera/web_auth.rb +14 -13
  93. data.tar.gz.sig +0 -0
  94. metadata +11 -36
  95. metadata.gz.sig +0 -0
@@ -3,6 +3,7 @@
3
3
  require 'aspera/fasp/transfer_spec'
4
4
  require 'aspera/cli/listener/logger'
5
5
  require 'aspera/cli/listener/progress_multi'
6
+ require 'aspera/cli/info'
6
7
 
7
8
  module Aspera
8
9
  module Cli
@@ -14,7 +15,7 @@ module Aspera
14
15
  FILE_LIST_FROM_ARGS = '@args'
15
16
  # special value for --sources : read file list from transfer spec (--ts)
16
17
  FILE_LIST_FROM_TRANSFER_SPEC = '@ts'
17
- FILE_LIST_OPTIONS=[FILE_LIST_FROM_ARGS,FILE_LIST_FROM_TRANSFER_SPEC,'Array'].freeze
18
+ FILE_LIST_OPTIONS = [FILE_LIST_FROM_ARGS, FILE_LIST_FROM_TRANSFER_SPEC, 'Array'].freeze
18
19
  DEFAULT_TRANSFER_NOTIF_TMPL = <<~END_OF_TEMPLATE
19
20
  From: <%=from_name%> <<%=from_email%>>
20
21
  To: <<%=to%>>
@@ -24,8 +25,10 @@ module Aspera
24
25
 
25
26
  <%=ts.to_yaml%>
26
27
  END_OF_TEMPLATE
27
- #% (formating bug in eclipse)
28
- private_constant :FILE_LIST_FROM_ARGS,:FILE_LIST_FROM_TRANSFER_SPEC,:FILE_LIST_OPTIONS,
28
+ # % (formating bug in eclipse)
29
+ private_constant :FILE_LIST_FROM_ARGS,
30
+ :FILE_LIST_FROM_TRANSFER_SPEC,
31
+ :FILE_LIST_OPTIONS,
29
32
  :DEFAULT_TRANSFER_NOTIF_TMPL
30
33
  TRANSFER_AGENTS = %i[direct node connect httpgw trsdk].freeze
31
34
 
@@ -39,8 +42,10 @@ module Aspera
39
42
  end
40
43
  end
41
44
 
45
+ attr_accessor :token_regenerator
46
+
42
47
  # @param env external objects: option manager, config file manager
43
- def initialize(opt_mgr,config)
48
+ def initialize(opt_mgr, config)
44
49
  @opt_mgr = opt_mgr
45
50
  @config = config
46
51
  # command line can override transfer spec
@@ -50,19 +55,22 @@ module Aspera
50
55
  @progress_listener = Listener::ProgressMulti.new
51
56
  # source/destination pair, like "paths" of transfer spec
52
57
  @transfer_paths = nil
53
- @opt_mgr.set_obj_attr(:ts,self,:option_transfer_spec)
54
- @opt_mgr.add_opt_simple(:ts,"override transfer spec values (Hash, use @json: prefix), current=#{@opt_mgr.get_option(:ts)}")
55
- @opt_mgr.add_opt_simple(:local_resume,"set resume policy (Hash, use @json: prefix), current=#{@opt_mgr.get_option(:local_resume)}")
56
- @opt_mgr.add_opt_simple(:to_folder,'destination folder for transfered files')
57
- @opt_mgr.add_opt_simple(:sources,"how list of transfered files is provided (#{FILE_LIST_OPTIONS.join(',')})")
58
- @opt_mgr.add_opt_list(:src_type,%i[list pair],'type of file list')
59
- @opt_mgr.add_opt_list(:transfer,TRANSFER_AGENTS,'type of transfer agent')
60
- @opt_mgr.add_opt_simple(:transfer_info,'parameters for transfer agent')
61
- @opt_mgr.add_opt_list(:progress,%i[none native multi],'type of progress bar')
62
- @opt_mgr.set_option(:transfer,:direct)
63
- @opt_mgr.set_option(:src_type,:list)
64
- @opt_mgr.set_option(:progress,:native) # use native ascp progress bar as it is more reliable
58
+ # only used with agent "direct" allows to regenerate the token if it is expired
59
+ @token_regenerator = nil
60
+ @opt_mgr.set_obj_attr(:ts, self, :option_transfer_spec)
61
+ @opt_mgr.add_opt_simple(:ts, "Override transfer spec values (Hash, e.g. use @json: prefix), current=#{@opt_mgr.get_option(:ts)}")
62
+ @opt_mgr.add_opt_simple(:to_folder, 'Destination folder for transfered files')
63
+ @opt_mgr.add_opt_simple(:sources, "How list of transfered files is provided (#{FILE_LIST_OPTIONS.join(',')})")
64
+ @opt_mgr.add_opt_simple(:ascp_opts, 'Options for ascp in its native format')
65
+ @opt_mgr.add_opt_list(:src_type, %i[list pair], 'Type of file list')
66
+ @opt_mgr.add_opt_list(:transfer, TRANSFER_AGENTS, 'Type of transfer agent')
67
+ @opt_mgr.add_opt_simple(:transfer_info, 'Parameters for transfer agent')
68
+ @opt_mgr.add_opt_list(:progress, %i[none native multi], 'Type of progress bar')
69
+ @opt_mgr.set_option(:transfer, :direct)
70
+ @opt_mgr.set_option(:src_type, :list)
71
+ @opt_mgr.set_option(:progress, :native) # use native ascp progress bar as it is more reliable
65
72
  @opt_mgr.parse_options!
73
+ Fasp::TransferSpec.ascp_opts_to_ts(@transfer_spec_cmdline, @opt_mgr.get_option(:ascp_opts))
66
74
  end
67
75
 
68
76
  def option_transfer_spec; @transfer_spec_cmdline; end
@@ -76,8 +84,8 @@ module Aspera
76
84
  @agent = instance
77
85
  @agent.add_listener(Listener::Logger.new)
78
86
  # use local progress bar if asked so, or if native and non local ascp (because only local ascp has native progress bar)
79
- if @opt_mgr.get_option(:progress,is_type: :mandatory).eql?(:multi) ||
80
- (@opt_mgr.get_option(:progress,is_type: :mandatory).eql?(:native) && !instance.class.to_s.eql?('Aspera::Fasp::AgentDirect'))
87
+ if @opt_mgr.get_option(:progress, is_type: :mandatory).eql?(:multi) ||
88
+ (@opt_mgr.get_option(:progress, is_type: :mandatory).eql?(:native) && !instance.class.to_s.eql?('Aspera::Fasp::AgentDirect'))
81
89
  @agent.add_listener(@progress_listener)
82
90
  end
83
91
  end
@@ -85,20 +93,20 @@ module Aspera
85
93
  # analyze options and create new agent if not already created or set
86
94
  def set_agent_by_options
87
95
  return nil unless @agent.nil?
88
- agent_type = @opt_mgr.get_option(:transfer,is_type: :mandatory)
96
+ agent_type = @opt_mgr.get_option(:transfer, is_type: :mandatory)
89
97
  # agent plugin is loaded on demand to avoid loading unnecessary dependencies
90
98
  require "aspera/fasp/agent_#{agent_type}"
91
99
  agent_options = @opt_mgr.get_option(:transfer_info)
92
- raise CliBadArgument,"the transfer agent configuration shall be Hash, not #{agent_options.class} (#{agent_options}), "\
93
- 'use either @json:<json> or @preset:<parameter set name>' unless [Hash,NilClass].include?(agent_options.class)
100
+ raise CliBadArgument, "the transfer agent configuration shall be Hash, not #{agent_options.class} (#{agent_options}), "\
101
+ 'use either @json:<json> or @preset:<parameter set name>' unless [Hash, NilClass].include?(agent_options.class)
94
102
  # special case
95
103
  if agent_type.eql?(:node) && agent_options.nil?
96
104
  param_set_name = @config.get_plugin_default_config_name(:node)
97
- raise CliBadArgument,"No default node configured, Please specify --#{:transfer_info.to_s.tr('_','-')}" if param_set_name.nil?
105
+ raise CliBadArgument, "No default node configured, Please specify --#{:transfer_info.to_s.tr('_', '-')}" if param_set_name.nil?
98
106
  agent_options = @config.preset_by_name(param_set_name)
99
107
  end
100
108
  # special case
101
- if agent_type.eql?(:direct) && @opt_mgr.get_option(:progress,is_type: :mandatory).eql?(:native)
109
+ if agent_type.eql?(:direct) && @opt_mgr.get_option(:progress, is_type: :mandatory).eql?(:native)
102
110
  agent_options = {} if agent_options.nil?
103
111
  agent_options[:quiet] = false
104
112
  end
@@ -135,106 +143,99 @@ module Aspera
135
143
  # return cache if set
136
144
  return @transfer_paths unless @transfer_paths.nil?
137
145
  # start with lower priority : get paths from transfer spec on command line
138
- @transfer_paths = @transfer_spec_cmdline['paths'] if @transfer_spec_cmdline.has_key?('paths')
146
+ @transfer_paths = @transfer_spec_cmdline['paths'] if @transfer_spec_cmdline.key?('paths')
139
147
  # is there a source list option ?
140
148
  file_list = @opt_mgr.get_option(:sources)
141
149
  case file_list
142
- when nil,FILE_LIST_FROM_ARGS
150
+ when nil, FILE_LIST_FROM_ARGS
143
151
  Log.log.debug('getting file list as parameters')
144
152
  # get remaining arguments
145
- file_list = @opt_mgr.get_next_argument('source file list',expected: :multiple)
146
- raise CliBadArgument,'specify at least one file on command line or use '\
153
+ file_list = @opt_mgr.get_next_argument('source file list', expected: :multiple)
154
+ raise CliBadArgument, 'specify at least one file on command line or use '\
147
155
  "--sources=#{FILE_LIST_FROM_TRANSFER_SPEC} to use transfer spec" if !file_list.is_a?(Array) || file_list.empty?
148
156
  when FILE_LIST_FROM_TRANSFER_SPEC
149
157
  Log.log.debug('assume list provided in transfer spec')
150
158
  special_case_direct_with_list =
151
- @opt_mgr.get_option(:transfer,is_type: :mandatory).eql?(:direct) &&
159
+ @opt_mgr.get_option(:transfer, is_type: :mandatory).eql?(:direct) &&
152
160
  Fasp::Parameters.ts_has_ascp_file_list(@transfer_spec_cmdline)
153
- raise CliBadArgument,'transfer spec on command line must have sources' if @transfer_paths.nil? && !special_case_direct_with_list
161
+ raise CliBadArgument, 'transfer spec on command line must have sources' if @transfer_paths.nil? && !special_case_direct_with_list
154
162
  # here we assume check of sources is made in transfer agent
155
163
  return @transfer_paths
156
164
  when Array
157
165
  Log.log.debug('getting file list as extended value')
158
- raise CliBadArgument,'sources must be a Array of String' if !file_list.reject{|f|f.is_a?(String)}.empty?
166
+ raise CliBadArgument, 'sources must be a Array of String' if !file_list.reject{|f|f.is_a?(String)}.empty?
159
167
  else
160
- raise CliBadArgument,"sources must be a Array, not #{file_list.class}"
168
+ raise CliBadArgument, "sources must be a Array, not #{file_list.class}"
161
169
  end
162
170
  # here, file_list is an Array or String
163
171
  if !@transfer_paths.nil?
164
172
  Log.log.warn('--sources overrides paths from --ts')
165
173
  end
166
- case @opt_mgr.get_option(:src_type,is_type: :mandatory)
174
+ case @opt_mgr.get_option(:src_type, is_type: :mandatory)
167
175
  when :list
168
176
  # when providing a list, just specify source
169
177
  @transfer_paths = file_list.map{|i|{'source' => i}}
170
178
  when :pair
171
- raise CliBadArgument,"When using pair, provide an even number of paths: #{file_list.length}" unless file_list.length.even?
172
- @transfer_paths = file_list.each_slice(2).to_a.map{|s,d|{'source' => s,'destination' => d}}
179
+ raise CliBadArgument, "When using pair, provide an even number of paths: #{file_list.length}" unless file_list.length.even?
180
+ @transfer_paths = file_list.each_slice(2).to_a.map{|s, d|{'source' => s, 'destination' => d}}
173
181
  else raise 'Unsupported src_type'
174
182
  end
175
- Log.log.debug("paths=#{@transfer_paths}")
183
+ Log.log.debug{"paths=#{@transfer_paths}"}
176
184
  return @transfer_paths
177
185
  end
178
186
 
179
187
  # start a transfer and wait for completion, plugins shall use this method
180
188
  # @param transfer_spec
181
- # @param tr_opts specific options for the transfer_agent
182
- # tr_opts[:src] specifies how destination_root is set (how transfer spec was generated)
183
- # other options are carried to specific agent
184
- def start(transfer_spec,tr_opts)
189
+ def start(transfer_spec)
185
190
  # check parameters
186
191
  raise 'transfer_spec must be hash' unless transfer_spec.is_a?(Hash)
187
- raise 'tr_opts must be hash' unless tr_opts.is_a?(Hash)
188
192
  # process :src option
189
193
  case transfer_spec['direction']
190
194
  when Fasp::TransferSpec::DIRECTION_RECEIVE
191
195
  # init default if required in any case
192
196
  @transfer_spec_cmdline['destination_root'] ||= destination_folder(transfer_spec['direction'])
193
197
  when Fasp::TransferSpec::DIRECTION_SEND
194
- case tr_opts[:src]
195
- when :direct
196
- # init default if required
197
- @transfer_spec_cmdline['destination_root'] ||= destination_folder(transfer_spec['direction'])
198
- when :node_gen3
198
+ if transfer_spec.dig('tags', 'aspera', 'node', 'access_key')
199
+ # gen4
200
+ @transfer_spec_cmdline.delete('destination_root') if @transfer_spec_cmdline.key?('destination_root_id')
201
+ elsif transfer_spec.key?('token')
202
+ # gen3
199
203
  # in that case, destination is set in return by application (API/upload_setup)
200
204
  # but to_folder was used in initial API call
201
205
  @transfer_spec_cmdline.delete('destination_root')
202
- when :node_gen4
203
- @transfer_spec_cmdline.delete('destination_root') if @transfer_spec_cmdline.has_key?('destination_root_id')
204
206
  else
205
- raise StandardError,"InternalError: unsupported value: #{tr_opts[:src]}"
207
+ # init default if required
208
+ @transfer_spec_cmdline['destination_root'] ||= destination_folder(transfer_spec['direction'])
206
209
  end
207
210
  end
208
-
209
- # only used here
210
- tr_opts.delete(:src)
211
-
212
211
  # update command line paths, unless destination already has one
213
212
  @transfer_spec_cmdline['paths'] = transfer_spec['paths'] || ts_source_paths
214
-
215
213
  transfer_spec.merge!(@transfer_spec_cmdline)
214
+ # remove values that are nil (user wants to delete)
215
+ transfer_spec.delete_if { |_key, value| value.nil? }
216
216
  # create transfer agent
217
217
  set_agent_by_options
218
- Log.log.debug("transfer agent is a #{@agent.class}")
219
- @agent.start_transfer(transfer_spec,tr_opts)
218
+ Log.log.debug{"transfer agent is a #{@agent.class}"}
219
+ @agent.token_regenerator = @token_regenerator if @agent.respond_to?(:token_regenerator=)
220
+ @agent.start_transfer(transfer_spec)
220
221
  # list of : :success or error message
221
222
  result = @agent.wait_for_transfers_completion
222
223
  @progress_listener.reset
223
224
  Fasp::AgentBase.validate_status_list(result)
224
- send_email_transfer_notification(transfer_spec,result)
225
+ send_email_transfer_notification(transfer_spec, result)
225
226
  return result
226
227
  end
227
228
 
228
- def send_email_transfer_notification(transfer_spec,statuses)
229
+ def send_email_transfer_notification(transfer_spec, statuses)
229
230
  return if @opt_mgr.get_option(:notif_to).nil?
230
231
  global_status = self.class.session_status(statuses)
231
232
  email_vars = {
232
233
  global_transfer_status: global_status,
233
- subject: "ascli transfer: #{global_status}",
234
+ subject: "#{PROGRAM_NAME} transfer: #{global_status}",
234
235
  body: "Transfer is: #{global_status}",
235
236
  ts: transfer_spec
236
237
  }
237
- @config.send_email_template(email_vars,DEFAULT_TRANSFER_NOTIF_TMPL)
238
+ @config.send_email_template(email_template_default: DEFAULT_TRANSFER_NOTIF_TMPL, values: email_vars)
238
239
  end
239
240
 
240
241
  # shut down if agent requires it
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Aspera
4
4
  module Cli
5
- VERSION = '4.9.0'
5
+ VERSION = '4.11.0'
6
6
  end
7
7
  end
data/lib/aspera/colors.rb CHANGED
@@ -5,7 +5,7 @@ class String
5
5
  class << self
6
6
  private
7
7
 
8
- def vtcmd(code);"\e[#{code}m";end
8
+ def vtcmd(code); "\e[#{code}m"; end
9
9
  end
10
10
  # see https://en.wikipedia.org/wiki/ANSI_escape_code
11
11
  # symbol is the method name added to String
@@ -35,11 +35,11 @@ class String
35
35
  }.freeze
36
36
  private_constant :VTSTYLES
37
37
  # defines methods to String, one per entry in VTSTYLES
38
- VTSTYLES.each do |name,code|
38
+ VTSTYLES.each do |name, code|
39
39
  if $stderr.tty?
40
40
  begin_seq = vtcmd(code)
41
41
  end_code = 0 # by default reset all
42
- if code <= 7 then 20 + code
42
+ if code <= 7 then code + 20
43
43
  elsif code <= 37 then 39
44
44
  elsif code <= 47 then 49
45
45
  end
@@ -7,8 +7,8 @@ module Aspera
7
7
  # add_env_args is called to get resulting param list and env var (also checks that all params were used)
8
8
  class CommandLineBuilder
9
9
  # parameter with onne of those tags is an ascp command line option with --
10
- CLTYPE_OPTIONS=%i[opt_without_arg opt_with_arg].freeze
11
- class<<self
10
+ CLTYPE_OPTIONS = %i[opt_without_arg opt_with_arg].freeze
11
+ class << self
12
12
  # transform yes/no to true/false
13
13
  def yes_to_true(value)
14
14
  case value
@@ -20,21 +20,21 @@ module Aspera
20
20
 
21
21
  # Called by provider of definition before constructor of this class so that params_definition has all mandatory fields
22
22
  def normalize_description(d)
23
- d.each do |param_name,options|
23
+ d.each do |param_name, options|
24
24
  raise "Expecting Hash, but have #{options.class} in #{param_name}" unless options.is_a?(Hash)
25
- #options[:accepted_types]=:bool if options[:cltype].eql?(:envvar) and !options.has_key?(:accepted_types)
25
+ # options[:accepted_types]=:bool if options[:cltype].eql?(:envvar) and !options.has_key?(:accepted_types)
26
26
  # by default : not mandatory
27
27
  options[:mandatory] ||= false
28
28
  options[:desc] ||= ''
29
29
  # by default : string, unless it's without arg
30
- if !options.has_key?(:accepted_types)
30
+ if !options.key?(:accepted_types)
31
31
  options[:accepted_types] = options[:cltype].eql?(:opt_without_arg) ? :bool : :string
32
32
  end
33
33
  # single type is placed in array
34
34
  options[:accepted_types] = [options[:accepted_types]] unless options[:accepted_types].is_a?(Array)
35
35
  # add default switch name if not present
36
- if !options.has_key?(:clswitch) && options.has_key?(:cltype) && CLTYPE_OPTIONS.include?(options[:cltype])
37
- options[:clswitch] = '--' + param_name.to_s.tr('_','-')
36
+ if !options.key?(:clswitch) && options.key?(:cltype) && CLTYPE_OPTIONS.include?(options[:cltype])
37
+ options[:clswitch] = '--' + param_name.to_s.tr('_', '-')
38
38
  end
39
39
  end
40
40
  end
@@ -43,7 +43,7 @@ module Aspera
43
43
  private
44
44
 
45
45
  # clvarname : command line variable name
46
- def env_name(_param_name,options)
46
+ def env_name(_param_name, options)
47
47
  return options[:clvarname]
48
48
  end
49
49
 
@@ -52,7 +52,7 @@ module Aspera
52
52
  attr_reader :params_definition
53
53
 
54
54
  # @param param_hash
55
- def initialize(param_hash,params_definition)
55
+ def initialize(param_hash, params_definition)
56
56
  @param_hash = param_hash # keep reference so that it can be modified by caller before calling `process_params`
57
57
  @params_definition = params_definition
58
58
  @result_env = {}
@@ -62,13 +62,13 @@ module Aspera
62
62
 
63
63
  def warn_unrecognized_params
64
64
  # warn about non translated arguments
65
- @param_hash.each_pair{|key,val|Log.log.warn("unrecognized parameter: #{key} = \"#{val}\"") if !@used_param_names.include?(key)}
65
+ @param_hash.each_pair{|key, val|Log.log.warn{"unrecognized parameter: #{key} = \"#{val}\""} if !@used_param_names.include?(key)}
66
66
  end
67
67
 
68
68
  # adds keys :env :args with resulting values after processing
69
69
  # warns if some parameters were not used
70
- def add_env_args(env,args)
71
- Log.log.debug("ENV=#{@result_env}, ARGS=#{@result_args}")
70
+ def add_env_args(env, args)
71
+ Log.log.debug{"ENV=#{@result_env}, ARGS=#{@result_args}"}
72
72
  warn_unrecognized_params
73
73
  env.merge!(@result_env)
74
74
  args.push(*@result_args)
@@ -82,7 +82,7 @@ module Aspera
82
82
  end
83
83
 
84
84
  def process_params
85
- @params_definition.keys.each do |k|
85
+ @params_definition.each_key do |k|
86
86
  process_param(k)
87
87
  end
88
88
  end
@@ -91,19 +91,19 @@ module Aspera
91
91
  # @param param_name : key in transfer spec
92
92
  # @param action : type of processing: ignore getvalue envvar opt_without_arg opt_with_arg defer
93
93
  # @param options : options for type
94
- def process_param(param_name,action=nil)
94
+ def process_param(param_name, action=nil)
95
95
  options = @params_definition[param_name]
96
96
  # should not happen
97
97
  if options.nil?
98
- Log.log.warn("Unknown parameter #{param_name}")
98
+ Log.log.warn{"Unknown parameter #{param_name}"}
99
99
  return
100
100
  end
101
101
  action = options[:cltype] if action.nil?
102
102
  # check mandatory parameter (nil is valid value)
103
- raise Fasp::Error, "Missing mandatory parameter: #{param_name}" if options[:mandatory] && !@param_hash.has_key?(param_name)
103
+ raise Fasp::Error, "Missing mandatory parameter: #{param_name}" if options[:mandatory] && !@param_hash.key?(param_name)
104
104
  parameter_value = @param_hash[param_name]
105
105
 
106
- #parameter_value=options[:default] if parameter_value.nil? and options.has_key?(:default)
106
+ # parameter_value=options[:default] if parameter_value.nil? and options.has_key?(:default)
107
107
 
108
108
  # Check parameter type
109
109
  expected_classes = options[:accepted_types].map do |s|
@@ -112,11 +112,11 @@ module Aspera
112
112
  when :array then Array
113
113
  when :hash then Hash
114
114
  when :int then Integer
115
- when :bool then [TrueClass,FalseClass]
115
+ when :bool then [TrueClass, FalseClass]
116
116
  else raise "INTERNAL: unexpected value: #{s}"
117
117
  end
118
118
  end.flatten
119
- raise Fasp::Error,"#{param_name} is : #{parameter_value.class} (#{parameter_value}), shall be #{options[:accepted_types]}, " \
119
+ raise Fasp::Error, "#{param_name} is : #{parameter_value.class} (#{parameter_value}), shall be #{options[:accepted_types]}, " \
120
120
  unless parameter_value.nil? || expected_classes.include?(parameter_value.class)
121
121
  @used_param_names.push(param_name) unless action.eql?(:defer)
122
122
 
@@ -124,7 +124,7 @@ module Aspera
124
124
  return nil if parameter_value.nil?
125
125
 
126
126
  # check that value is of an accepted type (string, int bool)
127
- raise "Value #{parameter_value} is not allowed for #{param_name}" if options.has_key?(:enum) && !options[:enum].include?(parameter_value)
127
+ raise "Value #{parameter_value} is not allowed for #{param_name}" if options.key?(:enum) && !options[:enum].include?(parameter_value)
128
128
 
129
129
  # convert some values if value on command line needs processing from value in structure
130
130
  case options[:clconvert]
@@ -135,8 +135,8 @@ module Aspera
135
135
  parameter_value = new_value
136
136
  when String
137
137
  # :clconvert has name of class and encoding method
138
- convclass,convmethod = options[:clconvert].split('.')
139
- newvalue = Kernel.const_get(convclass).send(convmethod,parameter_value)
138
+ convclass, convmethod = options[:clconvert].split('.')
139
+ newvalue = Kernel.const_get(convclass).send(convmethod, parameter_value)
140
140
  raise Fasp::Error, "unsupported #{param_name}: #{parameter_value}" if newvalue.nil?
141
141
  parameter_value = newvalue
142
142
  when NilClass
@@ -144,13 +144,13 @@ module Aspera
144
144
  end
145
145
 
146
146
  case action
147
- when :ignore,:defer # ignore this parameter or process later
147
+ when :ignore, :defer # ignore this parameter or process later
148
148
  return
149
149
  when :get_value # just get value
150
150
  return parameter_value
151
151
  when :envvar # set in env var
152
152
  # define ascp parameter in env var from transfer spec
153
- @result_env[env_name(param_name,options)] = parameter_value
153
+ @result_env[env_name(param_name, options)] = parameter_value
154
154
  when :opt_without_arg # if present and true : just add option without value
155
155
  add_param = false
156
156
  case parameter_value
@@ -161,12 +161,12 @@ module Aspera
161
161
  add_param = !add_param if options[:add_on_false]
162
162
  add_command_line_options([options[:clswitch]]) if add_param
163
163
  when :opt_with_arg # transform into command line option with value
164
- #parameter_value=parameter_value.to_s if parameter_value.is_a?(Integer)
164
+ # parameter_value=parameter_value.to_s if parameter_value.is_a?(Integer)
165
165
  parameter_value = [parameter_value] unless parameter_value.is_a?(Array)
166
166
  # if transfer_spec value is an array, applies option many times
167
- parameter_value.each{|v|add_command_line_options([options[:clswitch],v])}
167
+ parameter_value.each{|v|add_command_line_options([options[:clswitch], v])}
168
168
  when NilClass
169
- Log.log.debug("Ignoring parameter: #{param_name}")
169
+ Log.log.debug{"Ignoring parameter: #{param_name}"}
170
170
  else
171
171
  raise "ERROR: unknown action: #{action}/#{action.class}"
172
172
  end
@@ -5,19 +5,19 @@ require 'aspera/rest'
5
5
  require 'xmlsimple'
6
6
 
7
7
  module Aspera
8
- class CosNode < Rest
8
+ class CosNode < Aspera::Node
9
9
  class << self
10
- def parameters_from_svc_creds(service_credentials,bucket_region)
10
+ def parameters_from_svc_creds(service_credentials, bucket_region)
11
11
  # check necessary contents
12
12
  raise 'service_credentials must be a Hash' unless service_credentials.is_a?(Hash)
13
13
  %w[apikey resource_instance_id endpoints].each do |field|
14
- raise "service_credentials must have a field: #{field}" unless service_credentials.has_key?(field)
14
+ raise "service_credentials must have a field: #{field}" unless service_credentials.key?(field)
15
15
  end
16
- Aspera::Log.dump('service_credentials',service_credentials)
16
+ Aspera::Log.dump('service_credentials', service_credentials)
17
17
  # read endpoints from service provided in service credentials
18
18
  endpoints = Aspera::Rest.new({base_url: service_credentials['endpoints']}).read('')[:data]
19
- Aspera::Log.dump('endpoints',endpoints)
20
- storage_endpoint = endpoints.dig('service-endpoints','regional',bucket_region,'public',bucket_region)
19
+ Aspera::Log.dump('endpoints', endpoints)
20
+ storage_endpoint = endpoints.dig('service-endpoints', 'regional', bucket_region, 'public', bucket_region)
21
21
  raise "no such region: #{bucket_region}" if storage_endpoint.nil?
22
22
  return {
23
23
  instance_id: service_credentials['resource_instance_id'],
@@ -28,8 +28,8 @@ module Aspera
28
28
  end
29
29
  IBM_CLOUD_TOKEN_URL = 'https://iam.cloud.ibm.com/identity'
30
30
  TOKEN_FIELD = 'delegated_refresh_token'
31
- attr_reader :add_ts
32
- def initialize(bucket_name,storage_endpoint,instance_id,api_key,auth_url=IBM_CLOUD_TOKEN_URL)
31
+
32
+ def initialize(bucket_name, storage_endpoint, instance_id, api_key, auth_url= IBM_CLOUD_TOKEN_URL)
33
33
  @auth_url = auth_url
34
34
  @api_key = api_key
35
35
  s3_api = Aspera::Rest.new({
@@ -53,18 +53,20 @@ module Aspera
53
53
  url_params: {'faspConnectionInfo' => nil}
54
54
  )[:http].body
55
55
  ats_info = XmlSimple.xml_in(xml_result_text, {'ForceArray' => false})
56
- Aspera::Log.dump('ats_info',ats_info)
57
- super({
58
- base_url: ats_info['ATSEndpoint'],
59
- auth: {
60
- type: :basic,
61
- username: ats_info['AccessKey']['Id'],
62
- password: ats_info['AccessKey']['Secret']}})
63
- # prepare transfer spec addition
64
- @add_ts = {'tags' => {'aspera' => {'node' => {'storage_credentials' => {
56
+ Aspera::Log.dump('ats_info', ats_info)
57
+ @storage_credentials = {
65
58
  'type' => 'token',
66
59
  'token' => {TOKEN_FIELD => nil}
67
- }}}}}
60
+ }
61
+ super(
62
+ params: {
63
+ base_url: ats_info['ATSEndpoint'],
64
+ auth: {
65
+ type: :basic,
66
+ username: ats_info['AccessKey']['Id'],
67
+ password: ats_info['AccessKey']['Secret']}},
68
+ add_tspec: {'tags'=>{'aspera'=>{'node'=>{'storage_credentials'=>@storage_credentials}}}})
69
+ # update storage_credentials AND Rest params
68
70
  generate_token
69
71
  end
70
72
 
@@ -83,8 +85,8 @@ module Aspera
83
85
  receiver_client_ids: 'aspera_ats'
84
86
  }})
85
87
  # get delegated token to be placed in rest call header and in transfer tags
86
- @add_ts['tags']['aspera']['node']['storage_credentials']['token'][TOKEN_FIELD] = delegated_oauth.get_authorization.gsub(/^Bearer /,'')
87
- @params[:headers] = {'X-Aspera-Storage-Credentials' => JSON.generate(@add_ts['tags']['aspera']['node']['storage_credentials'])}
88
+ @storage_credentials['token'][TOKEN_FIELD] = delegated_oauth.get_authorization.gsub(/^Bearer /, '')
89
+ @params[:headers] = {'X-Aspera-Storage-Credentials' => JSON.generate(@storage_credentials)}
88
90
  end
89
91
  end
90
92
  end
@@ -9,7 +9,7 @@ module Aspera
9
9
  include Singleton
10
10
  # get binary value from data repository
11
11
  def data(id)
12
- File.read(File.join(__dir__,'data',id.to_s),mode: 'rb')
12
+ File.read(File.join(__dir__, 'data', id.to_s), mode: 'rb')
13
13
  end
14
14
  end
15
15
  end
@@ -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,19 +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)
88
- File.chmod(0400,path)
91
+ File.write(path, yield)
92
+ restrict_file_access(path)
89
93
  end
90
94
  return path
91
95
  end
92
- end
93
- end
94
- end
96
+
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}"}
106
+ end
107
+ end
108
+ File.chmod(mode, path) unless mode.nil?
109
+ rescue => e
110
+ Log.log.warn(e.message)
111
+ end
112
+ end # self
113
+ end # Environment
114
+ end # Aspera