aspera-cli 4.7.0 → 4.9.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 (96) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +1267 -999
  4. data/bin/ascli +20 -1
  5. data/bin/asession +37 -34
  6. data/docs/test_env.conf +7 -3
  7. data/examples/aoc.rb +13 -12
  8. data/examples/dascli +23 -0
  9. data/examples/faspex4.rb +34 -29
  10. data/examples/{transfer.rb → node.rb} +31 -59
  11. data/examples/server.rb +93 -0
  12. data/lib/aspera/aoc.rb +153 -143
  13. data/lib/aspera/ascmd.rb +56 -45
  14. data/lib/aspera/ats_api.rb +9 -6
  15. data/lib/aspera/cli/basic_auth_plugin.rb +18 -16
  16. data/lib/aspera/cli/extended_value.rb +33 -30
  17. data/lib/aspera/cli/formater.rb +105 -111
  18. data/lib/aspera/cli/info.rb +3 -2
  19. data/lib/aspera/cli/listener/line_dump.rb +1 -0
  20. data/lib/aspera/cli/listener/logger.rb +1 -0
  21. data/lib/aspera/cli/listener/progress.rb +13 -12
  22. data/lib/aspera/cli/listener/progress_multi.rb +21 -20
  23. data/lib/aspera/cli/main.rb +110 -90
  24. data/lib/aspera/cli/manager.rb +99 -88
  25. data/lib/aspera/cli/plugin.rb +98 -39
  26. data/lib/aspera/cli/plugins/alee.rb +6 -5
  27. data/lib/aspera/cli/plugins/aoc.rb +581 -450
  28. data/lib/aspera/cli/plugins/ats.rb +84 -83
  29. data/lib/aspera/cli/plugins/bss.rb +30 -27
  30. data/lib/aspera/cli/plugins/config.rb +488 -397
  31. data/lib/aspera/cli/plugins/console.rb +17 -15
  32. data/lib/aspera/cli/plugins/cos.rb +26 -35
  33. data/lib/aspera/cli/plugins/faspex.rb +206 -172
  34. data/lib/aspera/cli/plugins/faspex5.rb +109 -74
  35. data/lib/aspera/cli/plugins/node.rb +379 -189
  36. data/lib/aspera/cli/plugins/orchestrator.rb +71 -65
  37. data/lib/aspera/cli/plugins/preview.rb +131 -122
  38. data/lib/aspera/cli/plugins/server.rb +50 -150
  39. data/lib/aspera/cli/plugins/shares.rb +61 -27
  40. data/lib/aspera/cli/plugins/sync.rb +15 -14
  41. data/lib/aspera/cli/transfer_agent.rb +75 -64
  42. data/lib/aspera/cli/version.rb +2 -1
  43. data/lib/aspera/colors.rb +29 -28
  44. data/lib/aspera/command_line_builder.rb +50 -43
  45. data/lib/aspera/cos_node.rb +64 -38
  46. data/lib/aspera/data_repository.rb +1 -0
  47. data/lib/aspera/environment.rb +33 -10
  48. data/lib/aspera/fasp/agent_base.rb +35 -30
  49. data/lib/aspera/fasp/agent_connect.rb +35 -30
  50. data/lib/aspera/fasp/agent_direct.rb +68 -60
  51. data/lib/aspera/fasp/agent_httpgw.rb +71 -64
  52. data/lib/aspera/fasp/agent_node.rb +24 -23
  53. data/lib/aspera/fasp/agent_trsdk.rb +19 -20
  54. data/lib/aspera/fasp/error.rb +2 -1
  55. data/lib/aspera/fasp/error_info.rb +79 -68
  56. data/lib/aspera/fasp/installation.rb +130 -126
  57. data/lib/aspera/fasp/listener.rb +1 -0
  58. data/lib/aspera/fasp/parameters.rb +71 -60
  59. data/lib/aspera/fasp/parameters.yaml +69 -17
  60. data/lib/aspera/fasp/resume_policy.rb +14 -11
  61. data/lib/aspera/fasp/transfer_spec.rb +6 -5
  62. data/lib/aspera/fasp/uri.rb +25 -24
  63. data/lib/aspera/faspex_gw.rb +83 -72
  64. data/lib/aspera/hash_ext.rb +23 -13
  65. data/lib/aspera/id_generator.rb +16 -13
  66. data/lib/aspera/keychain/encrypted_hash.rb +61 -46
  67. data/lib/aspera/keychain/macos_security.rb +26 -24
  68. data/lib/aspera/log.rb +35 -39
  69. data/lib/aspera/nagios.rb +36 -28
  70. data/lib/aspera/node.rb +19 -19
  71. data/lib/aspera/oauth.rb +120 -100
  72. data/lib/aspera/open_application.rb +25 -22
  73. data/lib/aspera/persistency_action_once.rb +9 -8
  74. data/lib/aspera/persistency_folder.rb +13 -9
  75. data/lib/aspera/preview/file_types.rb +261 -266
  76. data/lib/aspera/preview/generator.rb +74 -73
  77. data/lib/aspera/preview/image_error.png +0 -0
  78. data/lib/aspera/preview/options.rb +7 -6
  79. data/lib/aspera/preview/utils.rb +30 -33
  80. data/lib/aspera/preview/video_error.png +0 -0
  81. data/lib/aspera/proxy_auto_config.rb +27 -23
  82. data/lib/aspera/rest.rb +73 -74
  83. data/lib/aspera/rest_call_error.rb +1 -0
  84. data/lib/aspera/rest_error_analyzer.rb +23 -19
  85. data/lib/aspera/rest_errors_aspera.rb +43 -40
  86. data/lib/aspera/secret_hider.rb +74 -0
  87. data/lib/aspera/ssh.rb +13 -10
  88. data/lib/aspera/sync.rb +49 -47
  89. data/lib/aspera/temp_file_manager.rb +7 -5
  90. data/lib/aspera/timer_limiter.rb +9 -8
  91. data/lib/aspera/uri_reader.rb +17 -18
  92. data/lib/aspera/web_auth.rb +17 -15
  93. data.tar.gz.sig +5 -0
  94. metadata +119 -35
  95. metadata.gz.sig +0 -0
  96. data/bin/dascli +0 -13
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'aspera/fasp/transfer_spec'
3
4
  require 'aspera/cli/listener/logger'
4
5
  require 'aspera/cli/listener/progress_multi'
@@ -10,10 +11,11 @@ module Aspera
10
11
  # provides CLI options to select one of the transfer agents (FASP/ascp client)
11
12
  class TransferAgent
12
13
  # special value for --sources : read file list from arguments
13
- FILE_LIST_FROM_ARGS='@args'
14
+ FILE_LIST_FROM_ARGS = '@args'
14
15
  # special value for --sources : read file list from transfer spec (--ts)
15
- FILE_LIST_FROM_TRANSFER_SPEC='@ts'
16
- DEFAULT_TRANSFER_NOTIF_TMPL=<<~END_OF_TEMPLATE
16
+ FILE_LIST_FROM_TRANSFER_SPEC = '@ts'
17
+ FILE_LIST_OPTIONS=[FILE_LIST_FROM_ARGS,FILE_LIST_FROM_TRANSFER_SPEC,'Array'].freeze
18
+ DEFAULT_TRANSFER_NOTIF_TMPL = <<~END_OF_TEMPLATE
17
19
  From: <%=from_name%> <<%=from_email%>>
18
20
  To: <<%=to%>>
19
21
  Subject: <%=subject%>
@@ -23,29 +25,40 @@ module Aspera
23
25
  <%=ts.to_yaml%>
24
26
  END_OF_TEMPLATE
25
27
  #% (formating bug in eclipse)
26
- private_constant :FILE_LIST_FROM_ARGS,:FILE_LIST_FROM_TRANSFER_SPEC,:DEFAULT_TRANSFER_NOTIF_TMPL
27
- TRANSFER_AGENTS=[:direct,:node,:connect,:httpgw,:trsdk]
28
+ private_constant :FILE_LIST_FROM_ARGS,:FILE_LIST_FROM_TRANSFER_SPEC,:FILE_LIST_OPTIONS,
29
+ :DEFAULT_TRANSFER_NOTIF_TMPL
30
+ TRANSFER_AGENTS = %i[direct node connect httpgw trsdk].freeze
31
+
32
+ class << self
33
+ # @return :success if all sessions statuses returned by "start" are success
34
+ # else return the first error exception object
35
+ def session_status(statuses)
36
+ error_statuses = statuses.reject{|i|i.eql?(:success)}
37
+ return :success if error_statuses.empty?
38
+ return error_statuses.first
39
+ end
40
+ end
28
41
 
29
42
  # @param env external objects: option manager, config file manager
30
43
  def initialize(opt_mgr,config)
31
- @opt_mgr=opt_mgr
32
- @config=config
44
+ @opt_mgr = opt_mgr
45
+ @config = config
33
46
  # command line can override transfer spec
34
- @transfer_spec_cmdline={'create_dir'=>true}
47
+ @transfer_spec_cmdline = {'create_dir' => true}
35
48
  # the currently selected transfer agent
36
- @agent=nil
37
- @progress_listener=Listener::ProgressMulti.new
49
+ @agent = nil
50
+ @progress_listener = Listener::ProgressMulti.new
38
51
  # source/destination pair, like "paths" of transfer spec
39
- @transfer_paths=nil
52
+ @transfer_paths = nil
40
53
  @opt_mgr.set_obj_attr(:ts,self,:option_transfer_spec)
41
- @opt_mgr.add_opt_simple(:ts,"override transfer spec values (Hash, use @json: prefix), current=#{@opt_mgr.get_option(:ts,:optional)}")
42
- @opt_mgr.add_opt_simple(:local_resume,"set resume policy (Hash, use @json: prefix), current=#{@opt_mgr.get_option(:local_resume,:optional)}")
43
- @opt_mgr.add_opt_simple(:to_folder,'destination folder for downloaded files')
44
- @opt_mgr.add_opt_simple(:sources,'list of source files (see doc)')
45
- @opt_mgr.add_opt_simple(:transfer_info,'parameters for transfer agent')
46
- @opt_mgr.add_opt_list(:src_type,[:list,:pair],'type of file list')
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')
47
59
  @opt_mgr.add_opt_list(:transfer,TRANSFER_AGENTS,'type of transfer agent')
48
- @opt_mgr.add_opt_list(:progress,[:none,:native,:multi],'type of progress bar')
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')
49
62
  @opt_mgr.set_option(:transfer,:direct)
50
63
  @opt_mgr.set_option(:src_type,:list)
51
64
  @opt_mgr.set_option(:progress,:native) # use native ascp progress bar as it is more reliable
@@ -60,11 +73,11 @@ module Aspera
60
73
  def option_transfer_spec_deep_merge(ts); @transfer_spec_cmdline.deep_merge!(ts); end
61
74
 
62
75
  def agent_instance=(instance)
63
- @agent=instance
76
+ @agent = instance
64
77
  @agent.add_listener(Listener::Logger.new)
65
78
  # use local progress bar if asked so, or if native and non local ascp (because only local ascp has native progress bar)
66
- if @opt_mgr.get_option(:progress,:mandatory).eql?(:multi) ||
67
- (@opt_mgr.get_option(:progress,:mandatory).eql?(:native) && !instance.class.to_s.eql?('Aspera::Fasp::AgentDirect'))
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'))
68
81
  @agent.add_listener(@progress_listener)
69
82
  end
70
83
  end
@@ -72,25 +85,27 @@ module Aspera
72
85
  # analyze options and create new agent if not already created or set
73
86
  def set_agent_by_options
74
87
  return nil unless @agent.nil?
75
- agent_type=@opt_mgr.get_option(:transfer,:mandatory)
88
+ agent_type = @opt_mgr.get_option(:transfer,is_type: :mandatory)
89
+ # agent plugin is loaded on demand to avoid loading unnecessary dependencies
76
90
  require "aspera/fasp/agent_#{agent_type}"
77
- agent_options=@opt_mgr.get_option(:transfer_info,:optional)
78
- raise CliBadArgument,"the transfer agent configuration shall be Hash, not #{agent_options.class} (#{agent_options}), use either @json:<json> or @preset:<parameter set name>" unless [Hash,NilClass].include?(agent_options.class)
91
+ 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)
79
94
  # special case
80
95
  if agent_type.eql?(:node) && agent_options.nil?
81
- param_set_name=@config.get_plugin_default_config_name(:node)
82
- raise CliBadArgument,"No default node configured, Please specify --#{:transfer_info.to_s.gsub('_','-')}" if param_set_name.nil?
83
- agent_options=@config.preset_by_name(param_set_name)
96
+ 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?
98
+ agent_options = @config.preset_by_name(param_set_name)
84
99
  end
85
100
  # special case
86
- if agent_type.eql?(:direct) && @opt_mgr.get_option(:progress,:mandatory).eql?(:native)
87
- agent_options={} if agent_options.nil?
88
- agent_options[:quiet]=false
101
+ if agent_type.eql?(:direct) && @opt_mgr.get_option(:progress,is_type: :mandatory).eql?(:native)
102
+ agent_options = {} if agent_options.nil?
103
+ agent_options[:quiet] = false
89
104
  end
90
- agent_options=agent_options.symbolize_keys if agent_options.is_a?(Hash)
105
+ agent_options = agent_options.symbolize_keys if agent_options.is_a?(Hash)
91
106
  # get agent instance
92
- new_agent=Kernel.const_get("Aspera::Fasp::Agent#{agent_type.capitalize}").new(agent_options)
93
- self.agent_instance=new_agent
107
+ new_agent = Kernel.const_get("Aspera::Fasp::Agent#{agent_type.capitalize}").new(agent_options)
108
+ self.agent_instance = new_agent
94
109
  return nil
95
110
  end
96
111
 
@@ -98,14 +113,15 @@ module Aspera
98
113
  # sets default if needed
99
114
  # param: 'send' or 'receive'
100
115
  def destination_folder(direction)
101
- dest_folder=@opt_mgr.get_option(:to_folder,:optional)
102
- return File.expand_path(dest_folder) unless dest_folder.nil?
103
- dest_folder=@transfer_spec_cmdline['destination_root']
116
+ dest_folder = @opt_mgr.get_option(:to_folder)
117
+ # do not expand path, if user wants to expand path: user @path:
118
+ return dest_folder unless dest_folder.nil?
119
+ dest_folder = @transfer_spec_cmdline['destination_root']
104
120
  return dest_folder unless dest_folder.nil?
105
121
  # default: / on remote, . on local
106
122
  case direction.to_s
107
- when Fasp::TransferSpec::DIRECTION_SEND then dest_folder='/'
108
- when Fasp::TransferSpec::DIRECTION_RECEIVE then dest_folder='.'
123
+ when Fasp::TransferSpec::DIRECTION_SEND then dest_folder = '/'
124
+ when Fasp::TransferSpec::DIRECTION_RECEIVE then dest_folder = '.'
109
125
  else raise "wrong direction: #{direction}"
110
126
  end
111
127
  return dest_folder
@@ -119,18 +135,21 @@ module Aspera
119
135
  # return cache if set
120
136
  return @transfer_paths unless @transfer_paths.nil?
121
137
  # start with lower priority : get paths from transfer spec on command line
122
- @transfer_paths=@transfer_spec_cmdline['paths'] if @transfer_spec_cmdline.has_key?('paths')
138
+ @transfer_paths = @transfer_spec_cmdline['paths'] if @transfer_spec_cmdline.has_key?('paths')
123
139
  # is there a source list option ?
124
- file_list=@opt_mgr.get_option(:sources,:optional)
140
+ file_list = @opt_mgr.get_option(:sources)
125
141
  case file_list
126
142
  when nil,FILE_LIST_FROM_ARGS
127
143
  Log.log.debug('getting file list as parameters')
128
144
  # get remaining arguments
129
- file_list=@opt_mgr.get_next_argument('source file list',:multiple)
130
- raise CliBadArgument,"specify at least one file on command line or use --sources=#{FILE_LIST_FROM_TRANSFER_SPEC} to use transfer spec" if !file_list.is_a?(Array) || file_list.empty?
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 '\
147
+ "--sources=#{FILE_LIST_FROM_TRANSFER_SPEC} to use transfer spec" if !file_list.is_a?(Array) || file_list.empty?
131
148
  when FILE_LIST_FROM_TRANSFER_SPEC
132
149
  Log.log.debug('assume list provided in transfer spec')
133
- special_case_direct_with_list=@opt_mgr.get_option(:transfer,:mandatory).eql?(:direct) and Fasp::Parameters.ts_has_file_list(@transfer_spec_cmdline)
150
+ special_case_direct_with_list =
151
+ @opt_mgr.get_option(:transfer,is_type: :mandatory).eql?(:direct) &&
152
+ Fasp::Parameters.ts_has_ascp_file_list(@transfer_spec_cmdline)
134
153
  raise CliBadArgument,'transfer spec on command line must have sources' if @transfer_paths.nil? && !special_case_direct_with_list
135
154
  # here we assume check of sources is made in transfer agent
136
155
  return @transfer_paths
@@ -144,13 +163,13 @@ module Aspera
144
163
  if !@transfer_paths.nil?
145
164
  Log.log.warn('--sources overrides paths from --ts')
146
165
  end
147
- case @opt_mgr.get_option(:src_type,:mandatory)
166
+ case @opt_mgr.get_option(:src_type,is_type: :mandatory)
148
167
  when :list
149
168
  # when providing a list, just specify source
150
- @transfer_paths=file_list.map{|i|{'source'=>i}}
169
+ @transfer_paths = file_list.map{|i|{'source' => i}}
151
170
  when :pair
152
171
  raise CliBadArgument,"When using pair, provide an even number of paths: #{file_list.length}" unless file_list.length.even?
153
- @transfer_paths=file_list.each_slice(2).to_a.map{|s,d|{'source'=>s,'destination'=>d}}
172
+ @transfer_paths = file_list.each_slice(2).to_a.map{|s,d|{'source' => s,'destination' => d}}
154
173
  else raise 'Unsupported src_type'
155
174
  end
156
175
  Log.log.debug("paths=#{@transfer_paths}")
@@ -170,12 +189,12 @@ module Aspera
170
189
  case transfer_spec['direction']
171
190
  when Fasp::TransferSpec::DIRECTION_RECEIVE
172
191
  # init default if required in any case
173
- @transfer_spec_cmdline['destination_root']||=destination_folder(transfer_spec['direction'])
192
+ @transfer_spec_cmdline['destination_root'] ||= destination_folder(transfer_spec['direction'])
174
193
  when Fasp::TransferSpec::DIRECTION_SEND
175
194
  case tr_opts[:src]
176
195
  when :direct
177
196
  # init default if required
178
- @transfer_spec_cmdline['destination_root']||=destination_folder(transfer_spec['direction'])
197
+ @transfer_spec_cmdline['destination_root'] ||= destination_folder(transfer_spec['direction'])
179
198
  when :node_gen3
180
199
  # in that case, destination is set in return by application (API/upload_setup)
181
200
  # but to_folder was used in initial API call
@@ -191,7 +210,7 @@ module Aspera
191
210
  tr_opts.delete(:src)
192
211
 
193
212
  # update command line paths, unless destination already has one
194
- @transfer_spec_cmdline['paths']=transfer_spec['paths'] || ts_source_paths
213
+ @transfer_spec_cmdline['paths'] = transfer_spec['paths'] || ts_source_paths
195
214
 
196
215
  transfer_spec.merge!(@transfer_spec_cmdline)
197
216
  # create transfer agent
@@ -199,7 +218,7 @@ module Aspera
199
218
  Log.log.debug("transfer agent is a #{@agent.class}")
200
219
  @agent.start_transfer(transfer_spec,tr_opts)
201
220
  # list of : :success or error message
202
- result=@agent.wait_for_transfers_completion
221
+ result = @agent.wait_for_transfers_completion
203
222
  @progress_listener.reset
204
223
  Fasp::AgentBase.validate_status_list(result)
205
224
  send_email_transfer_notification(transfer_spec,result)
@@ -207,25 +226,17 @@ module Aspera
207
226
  end
208
227
 
209
228
  def send_email_transfer_notification(transfer_spec,statuses)
210
- return if @opt_mgr.get_option(:notif_to,:optional).nil?
211
- global_status=self.class.session_status(statuses)
212
- email_vars={
229
+ return if @opt_mgr.get_option(:notif_to).nil?
230
+ global_status = self.class.session_status(statuses)
231
+ email_vars = {
213
232
  global_transfer_status: global_status,
214
- subject: "ascli transfer: #{global_status}",
215
- body: "Transfer is: #{global_status}",
216
- ts: transfer_spec
233
+ subject: "ascli transfer: #{global_status}",
234
+ body: "Transfer is: #{global_status}",
235
+ ts: transfer_spec
217
236
  }
218
237
  @config.send_email_template(email_vars,DEFAULT_TRANSFER_NOTIF_TMPL)
219
238
  end
220
239
 
221
- # @return :success if all sessions statuses returned by "start" are success
222
- # else return the first error exception object
223
- def self.session_status(statuses)
224
- error_statuses=statuses.reject{|i|i.eql?(:success)}
225
- return :success if error_statuses.empty?
226
- return error_statuses.first
227
- end
228
-
229
240
  # shut down if agent requires it
230
241
  def shutdown
231
242
  @agent.shutdown if @agent.respond_to?(:shutdown)
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Aspera
3
4
  module Cli
4
- VERSION = '4.7.0'
5
+ VERSION = '4.9.0'
5
6
  end
6
7
  end
data/lib/aspera/colors.rb CHANGED
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # simple vt100 colors
3
4
  class String
4
- class<<self
5
+ class << self
5
6
  private
6
7
 
7
8
  def vtcmd(code);"\e[#{code}m";end
@@ -10,39 +11,39 @@ class String
10
11
  # symbol is the method name added to String
11
12
  # it adds control chars to set color (and reset at the end).
12
13
  VTSTYLES = {
13
- bold: 1,
14
- italic: 3,
15
- underline: 4,
16
- blink: 5,
14
+ bold: 1,
15
+ italic: 3,
16
+ underline: 4,
17
+ blink: 5,
17
18
  reverse_color: 7,
18
- black: 30,
19
- red: 31,
20
- green: 32,
21
- brown: 33,
22
- blue: 34,
23
- magenta: 35,
24
- cyan: 36,
25
- gray: 37,
26
- bg_black: 40,
27
- bg_red: 41,
28
- bg_green: 42,
29
- bg_brown: 43,
30
- bg_blue: 44,
31
- bg_magenta: 45,
32
- bg_cyan: 46,
33
- bg_gray: 47
34
- }
19
+ black: 30,
20
+ red: 31,
21
+ green: 32,
22
+ brown: 33,
23
+ blue: 34,
24
+ magenta: 35,
25
+ cyan: 36,
26
+ gray: 37,
27
+ bg_black: 40,
28
+ bg_red: 41,
29
+ bg_green: 42,
30
+ bg_brown: 43,
31
+ bg_blue: 44,
32
+ bg_magenta: 45,
33
+ bg_cyan: 46,
34
+ bg_gray: 47
35
+ }.freeze
35
36
  private_constant :VTSTYLES
36
37
  # defines methods to String, one per entry in VTSTYLES
37
38
  VTSTYLES.each do |name,code|
38
39
  if $stderr.tty?
39
- begin_seq=vtcmd(code)
40
- end_code=
41
- if code >= 10 then 0
42
- elsif code.eql?(1) then 22
43
- else code+20
40
+ begin_seq = vtcmd(code)
41
+ end_code = 0 # by default reset all
42
+ if code <= 7 then 20 + code
43
+ elsif code <= 37 then 39
44
+ elsif code <= 47 then 49
44
45
  end
45
- end_seq=vtcmd(end_code)
46
+ end_seq = vtcmd(end_code)
46
47
  define_method(name){"#{begin_seq}#{self}#{end_seq}"}
47
48
  else
48
49
  define_method(name){self}
@@ -1,38 +1,44 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Aspera
3
4
  # helper class to build command line from a parameter list (key-value hash)
4
5
  # constructor takes hash: { 'param1':'value1', ...}
5
6
  # process_param is called repeatedly with all known parameters
6
7
  # add_env_args is called to get resulting param list and env var (also checks that all params were used)
7
8
  class CommandLineBuilder
8
- # transform yes/no to true/false
9
- def self.yes_to_true(value)
10
- case value
11
- when 'yes' then return true
12
- when 'no' then return false
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
12
+ # transform yes/no to true/false
13
+ def yes_to_true(value)
14
+ case value
15
+ when 'yes' then return true
16
+ when 'no' then return false
17
+ end
18
+ raise "unsupported value: #{value}"
13
19
  end
14
- raise "unsupported value: #{value}"
15
- end
16
20
 
17
- # Called by provider of definition before constructor of this class so that params_definition has all mandatory fields
18
- def self.normalize_description(d)
19
- d.each do |param_name,options|
20
- raise "Expecting Hash, but have #{options.class} in #{param_name}" unless options.is_a?(Hash)
21
- #options[:accepted_types]=:bool if options[:cltype].eql?(:envvar) and !options.has_key?(:accepted_types)
22
- # by default : not mandatory
23
- options[:mandatory]||=false
24
- options[:desc]||=''
25
- # by default : string, unless it's without arg
26
- if !options.has_key?(:accepted_types)
27
- options[:accepted_types]=options[:cltype].eql?(:opt_without_arg) ? :bool : :string
28
- end
29
- # single type is placed in array
30
- options[:accepted_types]=[options[:accepted_types]] unless options[:accepted_types].is_a?(Array)
31
- if !options.has_key?(:clswitch) && options.has_key?(:cltype) && [:opt_without_arg,:opt_with_arg].include?(options[:cltype])
32
- options[:clswitch]='--'+param_name.to_s.gsub('_','-')
21
+ # Called by provider of definition before constructor of this class so that params_definition has all mandatory fields
22
+ def normalize_description(d)
23
+ d.each do |param_name,options|
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)
26
+ # by default : not mandatory
27
+ options[:mandatory] ||= false
28
+ options[:desc] ||= ''
29
+ # by default : string, unless it's without arg
30
+ if !options.has_key?(:accepted_types)
31
+ options[:accepted_types] = options[:cltype].eql?(:opt_without_arg) ? :bool : :string
32
+ end
33
+ # single type is placed in array
34
+ options[:accepted_types] = [options[:accepted_types]] unless options[:accepted_types].is_a?(Array)
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('_','-')
38
+ end
33
39
  end
34
40
  end
35
- end
41
+ end
36
42
 
37
43
  private
38
44
 
@@ -47,11 +53,11 @@ module Aspera
47
53
 
48
54
  # @param param_hash
49
55
  def initialize(param_hash,params_definition)
50
- @param_hash=param_hash # keep reference so that it can be modified by caller before calling `process_params`
51
- @params_definition=params_definition
52
- @result_env={}
53
- @result_args=[]
54
- @used_param_names=[]
56
+ @param_hash = param_hash # keep reference so that it can be modified by caller before calling `process_params`
57
+ @params_definition = params_definition
58
+ @result_env = {}
59
+ @result_args = []
60
+ @used_param_names = []
55
61
  end
56
62
 
57
63
  def warn_unrecognized_params
@@ -86,21 +92,21 @@ module Aspera
86
92
  # @param action : type of processing: ignore getvalue envvar opt_without_arg opt_with_arg defer
87
93
  # @param options : options for type
88
94
  def process_param(param_name,action=nil)
89
- options=@params_definition[param_name]
95
+ options = @params_definition[param_name]
90
96
  # should not happen
91
97
  if options.nil?
92
98
  Log.log.warn("Unknown parameter #{param_name}")
93
99
  return
94
100
  end
95
- action=options[:cltype] if action.nil?
101
+ action = options[:cltype] if action.nil?
96
102
  # check mandatory parameter (nil is valid value)
97
103
  raise Fasp::Error, "Missing mandatory parameter: #{param_name}" if options[:mandatory] && !@param_hash.has_key?(param_name)
98
- parameter_value=@param_hash[param_name]
104
+ parameter_value = @param_hash[param_name]
99
105
 
100
106
  #parameter_value=options[:default] if parameter_value.nil? and options.has_key?(:default)
101
107
 
102
108
  # Check parameter type
103
- expected_classes=options[:accepted_types].map do |s|
109
+ expected_classes = options[:accepted_types].map do |s|
104
110
  case s
105
111
  when :string then String
106
112
  when :array then Array
@@ -110,7 +116,8 @@ module Aspera
110
116
  else raise "INTERNAL: unexpected value: #{s}"
111
117
  end
112
118
  end.flatten
113
- raise Fasp::Error,"#{param_name} is : #{parameter_value.class} (#{parameter_value}), shall be #{options[:accepted_types]}, " unless parameter_value.nil? || expected_classes.include?(parameter_value.class)
119
+ raise Fasp::Error,"#{param_name} is : #{parameter_value.class} (#{parameter_value}), shall be #{options[:accepted_types]}, " \
120
+ unless parameter_value.nil? || expected_classes.include?(parameter_value.class)
114
121
  @used_param_names.push(param_name) unless action.eql?(:defer)
115
122
 
116
123
  # process only non-nil values
@@ -123,15 +130,15 @@ module Aspera
123
130
  case options[:clconvert]
124
131
  when Hash
125
132
  # translate using conversion table
126
- new_value=options[:clconvert][parameter_value]
133
+ new_value = options[:clconvert][parameter_value]
127
134
  raise "unsupported value: #{parameter_value}, expect: #{options[:clconvert].keys.join(', ')}" if new_value.nil?
128
- parameter_value=new_value
135
+ parameter_value = new_value
129
136
  when String
130
137
  # :clconvert has name of class and encoding method
131
- convclass,convmethod=options[:clconvert].split('.')
132
- 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)
133
140
  raise Fasp::Error, "unsupported #{param_name}: #{parameter_value}" if newvalue.nil?
134
- parameter_value=newvalue
141
+ parameter_value = newvalue
135
142
  when NilClass
136
143
  else raise "not expected type for clconvert #{options[:clconvert].class} for #{param_name}"
137
144
  end
@@ -145,17 +152,17 @@ module Aspera
145
152
  # define ascp parameter in env var from transfer spec
146
153
  @result_env[env_name(param_name,options)] = parameter_value
147
154
  when :opt_without_arg # if present and true : just add option without value
148
- add_param=false
155
+ add_param = false
149
156
  case parameter_value
150
157
  when false then nil # nothing to put on command line, no creation by default
151
- when true then add_param=true
158
+ when true then add_param = true
152
159
  else raise Fasp::Error, "unsupported #{param_name}: #{parameter_value}"
153
160
  end
154
- add_param= !add_param if options[:add_on_false]
161
+ add_param = !add_param if options[:add_on_false]
155
162
  add_command_line_options([options[:clswitch]]) if add_param
156
163
  when :opt_with_arg # transform into command line option with value
157
164
  #parameter_value=parameter_value.to_s if parameter_value.is_a?(Integer)
158
- parameter_value=[parameter_value] unless parameter_value.is_a?(Array)
165
+ parameter_value = [parameter_value] unless parameter_value.is_a?(Array)
159
166
  # if transfer_spec value is an array, applies option many times
160
167
  parameter_value.each{|v|add_command_line_options([options[:clswitch],v])}
161
168
  when NilClass
@@ -1,64 +1,90 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'aspera/log'
3
4
  require 'aspera/rest'
4
5
  require 'xmlsimple'
5
6
 
6
7
  module Aspera
7
8
  class CosNode < Rest
9
+ class << self
10
+ def parameters_from_svc_creds(service_credentials,bucket_region)
11
+ # check necessary contents
12
+ raise 'service_credentials must be a Hash' unless service_credentials.is_a?(Hash)
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)
15
+ end
16
+ Aspera::Log.dump('service_credentials',service_credentials)
17
+ # read endpoints from service provided in service credentials
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)
21
+ raise "no such region: #{bucket_region}" if storage_endpoint.nil?
22
+ return {
23
+ instance_id: service_credentials['resource_instance_id'],
24
+ service_api_key: service_credentials['apikey'],
25
+ storage_endpoint: "https://#{storage_endpoint}"
26
+ }
27
+ end
28
+ end
29
+ IBM_CLOUD_TOKEN_URL = 'https://iam.cloud.ibm.com/identity'
30
+ TOKEN_FIELD = 'delegated_refresh_token'
8
31
  attr_reader :add_ts
9
- IBM_CLOUD_TOKEN_URL='https://iam.cloud.ibm.com/identity'
10
- TOKEN_FIELD='delegated_refresh_token'
11
32
  def initialize(bucket_name,storage_endpoint,instance_id,api_key,auth_url=IBM_CLOUD_TOKEN_URL)
12
- @auth_url=auth_url
13
- @api_key=api_key
14
- s3_api=Aspera::Rest.new({
15
- base_url: storage_endpoint,
16
- not_auth_codes: ['401','403'], # error codes when not authorized
17
- headers: {'ibm-service-instance-id' => instance_id},
18
- auth: {
19
- type: :oauth2,
20
- base_url: @auth_url,
21
- crtype: :generic,
22
- generic: {
23
- grant_type: 'urn:ibm:params:oauth:grant-type:apikey',
24
- response_type: 'cloud_iam',
25
- apikey: @api_key
26
- }}})
33
+ @auth_url = auth_url
34
+ @api_key = api_key
35
+ s3_api = Aspera::Rest.new({
36
+ base_url: storage_endpoint,
37
+ not_auth_codes: %w[401 403], # error codes when not authorized
38
+ headers: {'ibm-service-instance-id' => instance_id},
39
+ auth: {
40
+ type: :oauth2,
41
+ base_url: @auth_url,
42
+ crtype: :generic,
43
+ generic: {
44
+ grant_type: 'urn:ibm:params:oauth:grant-type:apikey',
45
+ response_type: 'cloud_iam',
46
+ apikey: @api_key
47
+ }}})
27
48
  # read FASP connection information for bucket
28
- xml_result_text=s3_api.call({operation: 'GET',subpath: bucket_name,headers: {'Accept'=>'application/xml'},url_params: {'faspConnectionInfo'=>nil}})[:http].body
29
- ats_info=XmlSimple.xml_in(xml_result_text, {'ForceArray' => false})
49
+ xml_result_text = s3_api.call(
50
+ operation: 'GET',
51
+ subpath: bucket_name,
52
+ headers: {'Accept' => 'application/xml'},
53
+ url_params: {'faspConnectionInfo' => nil}
54
+ )[:http].body
55
+ ats_info = XmlSimple.xml_in(xml_result_text, {'ForceArray' => false})
30
56
  Aspera::Log.dump('ats_info',ats_info)
31
57
  super({
32
- base_url: ats_info['ATSEndpoint'],
33
- auth: {
34
- type: :basic,
35
- username: ats_info['AccessKey']['Id'],
36
- password: ats_info['AccessKey']['Secret']}})
58
+ base_url: ats_info['ATSEndpoint'],
59
+ auth: {
60
+ type: :basic,
61
+ username: ats_info['AccessKey']['Id'],
62
+ password: ats_info['AccessKey']['Secret']}})
37
63
  # prepare transfer spec addition
38
- @add_ts={'tags'=>{'aspera'=>{'node'=>{'storage_credentials'=>{
64
+ @add_ts = {'tags' => {'aspera' => {'node' => {'storage_credentials' => {
39
65
  'type' => 'token',
40
- 'token' => {TOKEN_FIELD=>nil}
41
- }}}}}
66
+ 'token' => {TOKEN_FIELD => nil}
67
+ }}}}}
42
68
  generate_token
43
69
  end
44
70
 
45
71
  # potentially call this if delegated token is expired
46
72
  def generate_token
47
73
  # OAuth API to get delegated token
48
- delegated_oauth=Oauth.new({
74
+ delegated_oauth = Oauth.new({
49
75
  type: :oauth2,
50
76
  base_url: @auth_url,
51
77
  token_field: TOKEN_FIELD,
52
- crtype: :generic,
53
- generic: {
54
- grant_type: 'urn:ibm:params:oauth:grant-type:apikey',
55
- response_type: 'delegated_refresh_token',
56
- apikey: @api_key,
57
- receiver_client_ids: 'aspera_ats'
58
- }})
59
- # get delagated token to be placed in rest call header and in transfer tags
60
- @add_ts['tags']['aspera']['node']['storage_credentials']['token'][TOKEN_FIELD]=delegated_oauth.get_authorization().gsub(/^Bearer /,'')
61
- @params[:headers]={'X-Aspera-Storage-Credentials'=>JSON.generate(@add_ts['tags']['aspera']['node']['storage_credentials'])}
78
+ crtype: :generic,
79
+ generic: {
80
+ grant_type: 'urn:ibm:params:oauth:grant-type:apikey',
81
+ response_type: 'delegated_refresh_token',
82
+ apikey: @api_key,
83
+ receiver_client_ids: 'aspera_ats'
84
+ }})
85
+ # 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'])}
62
88
  end
63
89
  end
64
90
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'aspera/log'
3
4
  require 'singleton'
4
5