aspera-cli 4.9.0 → 4.10.0

Sign up to get free protection for your applications and to get access to all the features.
data/docs/test_env.conf CHANGED
@@ -6,8 +6,7 @@ default:
6
6
  aoc: tst_aoc1
7
7
  faspex: tst_faspex
8
8
  faspex5: tst_faspex5
9
- shares: tst_shares_1
10
- shares2: tst_shares2
9
+ shares: tst_shares
11
10
  node: tst_node
12
11
  server: tst_server
13
12
  orchestrator: tst_orch
@@ -74,11 +73,11 @@ tst_shares_1:
74
73
  url: your value here
75
74
  username: your value here
76
75
  password: your value here
77
- tst_shares2:
76
+ tst_node:
78
77
  url: your value here
79
78
  username: your value here
80
79
  password: your value here
81
- tst_node:
80
+ node_srv:
82
81
  url: your value here
83
82
  username: your value here
84
83
  password: your value here
@@ -118,6 +117,9 @@ tst_cos:
118
117
  crn: your value here
119
118
  bucket: your value here
120
119
  endpoint: your value here
120
+ sync:
121
+ local_path: your value here
122
+ remote_path: your value here
121
123
  misc:
122
124
  upload_folder: your value here
123
125
  syncuser: your value here
data/examples/dascli CHANGED
@@ -1,12 +1,16 @@
1
1
  #!/usr/bin/env bash
2
+ # set env var image to specify another docker image
3
+ # set env var version to specify another image version
4
+ # set env var docker_args to add options to docker run
2
5
  : ${image:=martinlaurent/ascli}
3
6
  # by default take latest version
4
7
  : ${version:=latest}
5
- imgtag=$image:$version
8
+ : ${docker:=docker}
9
+ : ${imgtag=$image:$version}
10
+ # transform var into array
11
+ add_dock_args=( $docker_args )
6
12
  # same location as in Dockerfile: main config folder for ascli in container
7
13
  ascli_home_container=/home/cliuser/.aspera/ascli
8
- # convenience: special argument to install the image
9
- case "$1" in install) docker pull $imgtag; exit 0; esac
10
14
  # set default location for config folder on host if necessary
11
15
  : ${ASCLI_HOME:=$HOME/.aspera/ascli}
12
16
  if test ! -d $ASCLI_HOME;then
@@ -14,10 +18,11 @@ if test ! -d $ASCLI_HOME;then
14
18
  # create it if necessary to allow mounting the volume in container
15
19
  mkdir -p "$ASCLI_HOME"
16
20
  fi
17
- exec docker run \
21
+ exec $docker run \
18
22
  --rm \
19
23
  --tty \
20
24
  --interactive \
21
25
  --volume "$ASCLI_HOME:$ascli_home_container" \
26
+ "${add_dock_args[@]}" \
22
27
  $imgtag \
23
28
  ascli "$@"
data/examples/faspex4.rb CHANGED
@@ -74,7 +74,7 @@ Aspera::Log.dump('job_id',job_id)
74
74
  result = transfer_client.wait_for_transfers_completion
75
75
  # notify of any transfer error
76
76
  result.reject{|i|i.eql?(:success)}.each do |e|
77
- Aspera::Log.log.error("A transfer error occured: #{e.message}")
77
+ Aspera::Log.log.error("A transfer error occurred: #{e.message}")
78
78
  end
79
79
 
80
80
  # 3: Faspex 4 API v4
data/examples/node.rb CHANGED
@@ -93,4 +93,4 @@ transfer_agent.start_transfer(transfer_spec)
93
93
  transfer_result = transfer_agent.wait_for_transfers_completion
94
94
  errors = transfer_result.reject{|i|i.eql?(:success)}
95
95
  # the transfer was not success, as there is at least one error
96
- raise "Error(s) occured: #{errors.join(',')}" if !errors.empty?
96
+ raise "Error(s) occurred: #{errors.join(',')}" if !errors.empty?
data/examples/server.rb CHANGED
@@ -90,4 +90,4 @@ $stdout.puts(JSON.generate(transfer_result))
90
90
  # get list of errors only
91
91
  errors = transfer_result.reject{|i|i.eql?(:success)}
92
92
  # the transfer was not success, as there is at least one error
93
- raise "Error(s) occured: #{errors.join(',')}" if !errors.empty?
93
+ raise "Error(s) occurred: #{errors.join(',')}" if !errors.empty?
@@ -10,9 +10,9 @@ module Aspera
10
10
  GEM_URL = "https://rubygems.org/gems/#{GEM_NAME}"
11
11
  SRC_URL = 'https://github.com/IBM/aspera-cli'
12
12
  # set this to warn in advance when minimum required ruby version will increase
13
- # for example currently minimum version is 2.4 in gemspec, but future minimum will be 2.5
13
+ # for example currently minimum version is 2.4 in gemspec, but future minimum will be different
14
14
  # set to current minimum if there is no deprecation
15
15
  # the actual current minimum required version is in gemspec at required_ruby_version
16
- RUBY_FUTURE_MINIMUM_VERSION = '2.5'
16
+ RUBY_FUTURE_MINIMUM_VERSION = '2.7'
17
17
  end
18
18
  end
@@ -87,7 +87,7 @@ module Aspera
87
87
  if @option_insecure
88
88
  url=http.inspect.gsub(/^[^ ]* /,'https://').gsub(/ [^ ]*$/,'')
89
89
  if !@ssl_warned_urls.include?(url)
90
- @plugin_env[:formater].display_message(:error,"#{WARNING_FLASH} ignoring certificate for: #{url}. Only for tests, do not use in production.")
90
+ @plugin_env[:formater].display_message(:error,"#{WARNING_FLASH} ignoring certificate for: #{url}. Do not use unsafe certificates in production.")
91
91
  @ssl_warned_urls.push(url)
92
92
  end
93
93
  http.verify_mode = SELF_SIGNED_CERT
@@ -44,15 +44,17 @@ module Aspera
44
44
  # resolves on extended value syntax
45
45
  class Manager
46
46
  # boolean options are set to true/false from the following values
47
- TRUE_VALUES = [:yes,true].freeze
48
- BOOLEAN_VALUES = [TRUE_VALUES,:no,false].flatten.freeze
49
- BOOLEAN_SIMPLE = %i[yes no].freeze
47
+ BOOLEAN_SIMPLE = %i[no yes].freeze
48
+ FALSE_VALUES = [BOOLEAN_SIMPLE.first,false].freeze
49
+ TRUE_VALUES = [BOOLEAN_SIMPLE.last,true].freeze
50
+ BOOLEAN_VALUES = [TRUE_VALUES,FALSE_VALUES].flatten.freeze
51
+
50
52
  # option name separator on command line
51
53
  OPTION_SEP_LINE = '-'
52
54
  # option name separator in code (symbol)
53
55
  OPTION_SEP_NAME = '_'
54
56
 
55
- private_constant :TRUE_VALUES,:BOOLEAN_VALUES,:OPTION_SEP_LINE,:OPTION_SEP_NAME
57
+ private_constant :FALSE_VALUES,:TRUE_VALUES,:BOOLEAN_VALUES,:OPTION_SEP_LINE,:OPTION_SEP_NAME
56
58
 
57
59
  class << self
58
60
  def enum_to_bool(enum)
@@ -35,7 +35,9 @@ module Aspera
35
35
  options.add_opt_simple(:property,'name of property to set')
36
36
  options.add_opt_simple(:id,"resource identifier (#{INSTANCE_OPS.join(',')})")
37
37
  options.add_opt_boolean(:bulk,'Bulk operation (only some)')
38
+ options.add_opt_boolean(:bfail,'Bulk operation error handling')
38
39
  options.set_option(:bulk,:no)
40
+ options.set_option(:bfail,:yes)
39
41
  options.parse_options!
40
42
  @@options_created = true # rubocop:disable Style/ClassVars
41
43
  end
@@ -72,6 +74,7 @@ module Aspera
72
74
  result = res if param.is_a?(Hash)
73
75
  result['status'] = success_msg
74
76
  rescue StandardError => e
77
+ raise e if options.get_option(:bfail)
75
78
  result['status'] = e.to_s
76
79
  end
77
80
  result_list.push(result)
@@ -140,7 +143,8 @@ module Aspera
140
143
  end
141
144
  data = item_list
142
145
  end
143
- return {type: :object_list, data: data, fields: display_fields}
146
+ return {type: :object_list, data: data, fields: display_fields} if data.empty? || data.first.is_a?(Hash)
147
+ return {type: :value_list, data: data, name: 'id'}
144
148
  when :modify
145
149
  property = options.get_option(:property)
146
150
  parameters = {property => parameters} unless property.nil?
@@ -673,7 +673,7 @@ module Aspera
673
673
  startdate_persistency&.save
674
674
  if !options.get_option(:notif_to).nil?
675
675
  events.each do |tr_event|
676
- config.send_email_template({ev: tr_event})
676
+ config.send_email_template(values: {ev: tr_event})
677
677
  end
678
678
  end
679
679
  return {type: :object_list,data: events}
@@ -4,6 +4,7 @@ require 'aspera/cli/basic_auth_plugin'
4
4
  require 'aspera/cli/extended_value'
5
5
  require 'aspera/cli/version'
6
6
  require 'aspera/cli/formater'
7
+ require 'aspera/cli/info'
7
8
  require 'aspera/fasp/installation'
8
9
  require 'aspera/fasp/parameters'
9
10
  require 'aspera/fasp/transfer_spec'
@@ -37,7 +38,6 @@ module Aspera
37
38
  CONF_PRESET_VERSION = 'version'
38
39
  CONF_PRESET_DEFAULT = 'default'
39
40
  CONF_PRESET_GLOBAL = 'global_common_defaults'
40
- CONF_PRESET_SECRETS = 'default_secrets' # pragma: allowlist secret
41
41
  CONF_PLUGIN_SYM = :config # Plugins::Config.name.split('::').last.downcase.to_sym
42
42
  CONF_GLOBAL_SYM = :config
43
43
  # old tool name
@@ -62,13 +62,14 @@ module Aspera
62
62
  EMAIL_TEST_TEMPLATE = <<~END_OF_TEMPLATE
63
63
  From: <%=from_name%> <<%=from_email%>>
64
64
  To: <<%=to%>>
65
- Subject: Amelia email test
65
+ Subject: #{GEM_NAME} email test
66
66
 
67
- It worked !
67
+ This email was sent to test #{PROGRAM_NAME}.
68
68
  END_OF_TEMPLATE
69
69
  # special extended values
70
70
  EXTV_INCLUDE_PRESETS = :incps
71
71
  EXTV_PRESET = :preset
72
+ EXTV_VAULT = :vault
72
73
  PRESET_DIG_SEPARATOR = '.'
73
74
  DEFAULT_CHECK_NEW_VERSION_DAYS = 7
74
75
  DEFAULT_PRIV_KEY_FILENAME = 'aspera_aoc_key' # pragma: allowlist secret
@@ -77,7 +78,7 @@ module Aspera
77
78
  :CONF_PRESET_GLOBAL,:PROGRAM_NAME_V1,:PROGRAM_NAME_V2,:DEFAULT_REDIRECT,:ASPERA_PLUGINS_FOLDERNAME,
78
79
  :RUBY_FILE_EXT,:AOC_COMMAND_V1,:AOC_COMMAND_V2,:AOC_COMMAND_V3,:AOC_COMMAND_CURRENT,:DEMO,
79
80
  :TRANSFER_SDK_ARCHIVE_URL,:AOC_PATH_API_CLIENTS,:DEMO_SERVER_PRESET,:EMAIL_TEST_TEMPLATE,:EXTV_INCLUDE_PRESETS,
80
- :EXTV_PRESET,:DEFAULT_CHECK_NEW_VERSION_DAYS,:DEFAULT_PRIV_KEY_FILENAME,:SERVER_COMMAND,:CONF_PRESET_SECRETS,
81
+ :EXTV_PRESET,:EXTV_VAULT,:DEFAULT_CHECK_NEW_VERSION_DAYS,:DEFAULT_PRIV_KEY_FILENAME,:SERVER_COMMAND,
81
82
  :PRESET_DIG_SEPARATOR
82
83
  def initialize(env,params)
83
84
  raise 'env and params must be Hash' unless env.is_a?(Hash) && params.is_a?(Hash)
@@ -107,6 +108,7 @@ module Aspera
107
108
  # add preset handler (needed for smtp)
108
109
  ExtendedValue.instance.set_handler(EXTV_PRESET,:reader,lambda{|v|preset_by_name(v)})
109
110
  ExtendedValue.instance.set_handler(EXTV_INCLUDE_PRESETS,:decoder,lambda{|v|expanded_with_preset_includes(v)})
111
+ ExtendedValue.instance.set_handler(EXTV_VAULT,:decoder,lambda{|v|vault_value(v)})
110
112
  # load defaults before it can be overriden
111
113
  add_plugin_default_preset(CONF_GLOBAL_SYM)
112
114
  options.parse_options!
@@ -122,18 +124,20 @@ module Aspera
122
124
  options.add_opt_boolean(:test_mode,'Wizard: skip private key check step')
123
125
  options.add_opt_simple(:preset,'-PVALUE','load the named option preset from current config file')
124
126
  options.add_opt_simple(:pkeypath,'Wizard: path to private key for JWT')
125
- options.add_opt_simple(:ascp_path,'path to ascp')
126
- options.add_opt_simple(:use_product,'use ascp from specified product')
127
- options.add_opt_simple(:smtp,'smtp configuration (extended value: hash)')
128
- options.add_opt_simple(:fpac,'proxy auto configuration script')
129
- options.add_opt_simple(:secret,'default secret')
130
- options.add_opt_simple(:secrets,'secret vault')
127
+ options.add_opt_simple(:ascp_path,'Path to ascp')
128
+ options.add_opt_simple(:use_product,'Use ascp from specified product')
129
+ options.add_opt_simple(:smtp,'SMTP configuration (extended value: hash)')
130
+ options.add_opt_simple(:fpac,'Proxy auto configuration script')
131
+ options.add_opt_simple(:proxy_credentials,'HTTP proxy credentials (Array with user and password)')
132
+ options.add_opt_simple(:secret,'Secret for access keys')
133
+ options.add_opt_simple(:vault,'Vault for secrets')
134
+ options.add_opt_simple(:vault_password,'Vault password')
131
135
  options.add_opt_simple(:sdk_url,'URL to get SDK')
132
136
  options.add_opt_simple(:sdk_folder,'SDK folder path')
133
- options.add_opt_simple(:notif_to,'email recipient for notification of transfers')
134
- options.add_opt_simple(:notif_template,'email ERB template for notification of transfers')
135
- options.add_opt_simple(:version_check_days,Integer,'period in days to check new version (zero to disable)')
136
- options.add_opt_simple(:plugin_folder,'folder where to find additional plugins')
137
+ options.add_opt_simple(:notif_to,'Email recipient for notification of transfers')
138
+ options.add_opt_simple(:notif_template,'Email ERB template for notification of transfers')
139
+ options.add_opt_simple(:version_check_days,Integer,'Period in days to check new version (zero to disable)')
140
+ options.add_opt_simple(:plugin_folder,'Folder where to find additional plugins')
137
141
  options.set_option(:use_generic_client,true)
138
142
  options.set_option(:test_mode,false)
139
143
  options.set_option(:default,true)
@@ -145,6 +149,13 @@ module Aspera
145
149
  pac_script = options.get_option(:fpac)
146
150
  # create PAC executor
147
151
  @pac_exec = Aspera::ProxyAutoConfig.new(pac_script).register_uri_generic unless pac_script.nil?
152
+ proxy_creds=options.get_option(:proxy_credentials)
153
+ if !proxy_creds.nil?
154
+ raise CliBadArgument,'proxy credentials shall be an array (#{proxy_creds.class})' unless proxy_creds.is_a?(Array)
155
+ raise CliBadArgument,'proxy credentials shall have two elements (#{proxy_creds.length})' unless proxy_creds.length.eql?(2)
156
+ @pac_exec.proxy_user=Rest.proxy_user=proxy_creds[0]
157
+ @pac_exec.proxy_pass=Rest.proxy_pass=proxy_creds[1]
158
+ end
148
159
  end
149
160
 
150
161
  # env var name to override the app's main folder
@@ -251,9 +262,9 @@ module Aspera
251
262
  require 'openssl'
252
263
  priv_key = OpenSSL::PKey::RSA.new(length)
253
264
  File.write(private_key_path,priv_key.to_s)
254
- File.chmod(0400,private_key_path)
255
265
  File.write(private_key_path + '.pub',priv_key.public_key.to_s)
256
- File.chmod(0400,private_key_path + '.pub')
266
+ Environment.restrict_file_access(private_key_path)
267
+ Environment.restrict_file_access(private_key_path + '.pub')
257
268
  nil
258
269
  end
259
270
 
@@ -479,11 +490,14 @@ module Aspera
479
490
  Log.log.error('YAML error in config file')
480
491
  raise e
481
492
  rescue StandardError => e
482
- Log.log.debug("-> #{e}")
483
- new_name = "#{@option_config_file}.pre#{@info[:version]}.manual_conversion_needed"
484
- File.rename(@option_config_file,new_name)
485
- Log.log.warn("Renamed config file to #{new_name}.")
486
- Log.log.warn('Manual Conversion is required. Next time, a new empty file will be created.')
493
+ Log.log.debug("-> #{e.class.name} : #{e}")
494
+ if File.exist?(@option_config_file)
495
+ # then there is a problem with that file.
496
+ new_name = "#{@option_config_file}.pre#{@info[:version]}.manual_conversion_needed"
497
+ File.rename(@option_config_file,new_name)
498
+ Log.log.warn("Renamed config file to #{new_name}.")
499
+ Log.log.warn('Manual Conversion is required. Next time, a new empty file will be created.')
500
+ end
487
501
  raise CliError,e.to_s
488
502
  end
489
503
  end
@@ -621,7 +635,8 @@ module Aspera
621
635
  last_line = line
622
636
  case line
623
637
  when %r{^DBG Path ([^ ]+) (dir|file) +: (.*)$} then data[Regexp.last_match(1)] = Regexp.last_match(3)
624
- when %r{^DBG Added module group:"([^"]+)" name:"([^"]+)", version:"([^"]+)" interface:"([^"]+)"$} then data[Regexp.last_match(2)] = Regexp.last_match(4)
638
+ when %r{^DBG Added module group:"([^"]+)" name:"([^"]+)", version:"([^"]+)" interface:"([^"]+)"$}
639
+ data[Regexp.last_match(2)] = "#{Regexp.last_match(4)} #{Regexp.last_match(1)} v#{Regexp.last_match(3)}"
625
640
  when %r{^DBG License result \(/license/(\S+)\): (.+)$} then data[Regexp.last_match(1)] = Regexp.last_match(2)
626
641
  when %r{^LOG (.+) version ([0-9.]+)$} then data['product_name'] = Regexp.last_match(1);data['product_version'] = Regexp.last_match(2)
627
642
  when %r{^LOG Initializing FASP version ([^,]+),} then data['ascp_version'] = Regexp.last_match(1)
@@ -891,7 +906,7 @@ module Aspera
891
906
  when :file
892
907
  return Main.result_status(@option_config_file)
893
908
  when :email_test
894
- send_email_template({},EMAIL_TEST_TEMPLATE)
909
+ send_email_template(email_template_default: EMAIL_TEST_TEMPLATE)
895
910
  return Main.result_nothing
896
911
  when :smtp_settings
897
912
  return {type: :single_object, data: email_settings}
@@ -924,46 +939,7 @@ module Aspera
924
939
  end
925
940
  save_presets_to_config_file
926
941
  return Main.result_status('Done')
927
- when :vault
928
- command = options.get_next_command(%i[init list get set delete])
929
- case command
930
- when :init
931
- type = options.get_option(:value)
932
- case type
933
- when 'config',NilClass
934
- raise 'default secrets already exists' if @config_presets.has_key?(CONF_PRESET_SECRETS)
935
- @config_presets[CONF_PRESET_SECRETS] = {}
936
- set_global_default(:secrets,"@preset:#{CONF_PRESET_SECRETS}")
937
- else raise 'no such vault type'
938
- end
939
- return Main.result_status('Done')
940
- when :list
941
- return {type: :object_list, data: vault.list}
942
- when :set
943
- # register url option
944
- BasicAuthPlugin.register_options(@agents)
945
- username = options.get_option(:username,is_type: :mandatory)
946
- url = options.get_option(:url,is_type: :mandatory)
947
- description = options.get_option(:value)
948
- secret = options.get_next_argument('secret')
949
- vault.set(username: username, url: url, description: description, secret: secret)
950
- save_presets_to_config_file if vault.is_a?(Keychain::EncryptedHash)
951
- return Main.result_status('Done')
952
- when :get
953
- # register url option
954
- BasicAuthPlugin.register_options(@agents)
955
- username = options.get_option(:username,is_type: :mandatory)
956
- url = options.get_option(:url)
957
- result = vault.get(username: username, url: url)
958
- return {type: :single_object, data: result}
959
- when :delete
960
- # register url option
961
- BasicAuthPlugin.register_options(@agents)
962
- username = options.get_option(:username,is_type: :mandatory)
963
- url = options.get_option(:url)
964
- vault.delete(username: username, url: url)
965
- return Main.result_status('Done')
966
- end
942
+ when :vault then execute_vault
967
943
  else raise 'INTERNAL ERROR: wrong case'
968
944
  end
969
945
  end
@@ -992,21 +968,21 @@ module Aspera
992
968
  Kernel.binding
993
969
  end
994
970
 
995
- def send_email_template(vars,email_template_default=nil)
996
- vars[:to] ||= options.get_option(:notif_to,is_type: :mandatory)
971
+ def send_email_template(email_template_default: nil, values: {})
972
+ values[:to] ||= options.get_option(:notif_to,is_type: :mandatory)
997
973
  notif_template = options.get_option(:notif_template,is_type: email_template_default.nil? ? :mandatory : :optional) || email_template_default
998
974
  mail_conf = email_settings
999
- vars[:from_name] ||= mail_conf[:from_name]
1000
- vars[:from_email] ||= mail_conf[:from_email]
975
+ values[:from_name] ||= mail_conf[:from_name]
976
+ values[:from_email] ||= mail_conf[:from_email]
1001
977
  %i[from_name from_email].each do |n|
1002
- raise "Missing email parameter: #{n}" unless vars.has_key?(n)
978
+ raise "Missing email parameter: #{n}" unless values.has_key?(n)
1003
979
  end
1004
980
  start_options = [mail_conf[:domain]]
1005
981
  start_options.push(mail_conf[:username],mail_conf[:password],:login) if mail_conf.has_key?(:username) && mail_conf.has_key?(:password)
1006
- # create a binding with only variables defined in vars
982
+ # create a binding with only variables defined in values
1007
983
  template_binding = empty_binding
1008
984
  # add variables to binding
1009
- vars.each do |k,v|
985
+ values.each do |k,v|
1010
986
  raise "key (#{k.class}) must be Symbol" unless k.is_a?(Symbol)
1011
987
  template_binding.local_variable_set(k,v)
1012
988
  end
@@ -1016,17 +992,17 @@ module Aspera
1016
992
  smtp = Net::SMTP.new(mail_conf[:server], mail_conf[:port])
1017
993
  smtp.enable_starttls if mail_conf[:tls]
1018
994
  smtp.start(*start_options) do |smtp_session|
1019
- smtp_session.send_message(msg_with_headers, vars[:from_email], vars[:to])
995
+ smtp_session.send_message(msg_with_headers, values[:from_email], values[:to])
1020
996
  end
1021
997
  end
1022
998
 
1023
999
  def save_presets_to_config_file
1024
1000
  raise 'no configuration loaded' if @config_presets.nil?
1025
1001
  FileUtils.mkdir_p(@main_folder) unless Dir.exist?(@main_folder)
1026
- File.chmod(0700,@main_folder)
1027
1002
  Log.log.debug("Writing #{@option_config_file}")
1028
1003
  File.write(@option_config_file,@config_presets.to_yaml)
1029
- File.chmod(0600,@option_config_file)
1004
+ Environment.restrict_file_access(@main_folder)
1005
+ Environment.restrict_file_access(@option_config_file)
1030
1006
  end
1031
1007
 
1032
1008
  # returns [String] name if config_presets has default
@@ -1051,25 +1027,65 @@ module Aspera
1051
1027
  return nil
1052
1028
  end # get_plugin_default_config_name
1053
1029
 
1030
+ ALLOWED_KEYS=%i[password username description].freeze
1031
+ def execute_vault
1032
+ command = options.get_next_command(%i[list show create delete password])
1033
+ case command
1034
+ when :list
1035
+ return {type: :object_list, data: vault.list}
1036
+ when :show
1037
+ return {type: :single_object, data: vault.get(label: options.get_next_argument('label'))}
1038
+ when :create
1039
+ label=options.get_next_argument('label')
1040
+ info=options.get_next_argument('info Hash')
1041
+ raise 'info must be Hash' unless info.is_a?(Hash)
1042
+ info=info.symbolize_keys
1043
+ info[:label]=label
1044
+ vault.set(info)
1045
+ return Main.result_status('Password added')
1046
+ when :delete
1047
+ vault.delete(label: options.get_next_argument('label'))
1048
+ return Main.result_status('Password deleted')
1049
+ when :password
1050
+ raise 'Vault does not support password change' unless vault.respond_to?(:password=)
1051
+ new_password=options.get_next_argument('new_password')
1052
+ vault.password=new_password
1053
+ vault.save
1054
+ return Main.result_status('Password updated')
1055
+ end
1056
+ end
1057
+
1058
+ def vault_value(name)
1059
+ m=name.match(/^(.+)\.(.+)$/)
1060
+ raise 'vault name shall match <name>.<param>' if m.nil?
1061
+ info=vault.get(label: m[1])
1062
+ #raise "no such vault entry: #{m[1]}" if info.nil?
1063
+ value=info[m[2].to_sym]
1064
+ raise "no such entry value: #{m[2]}" if value.nil?
1065
+ return value
1066
+ end
1067
+
1054
1068
  def vault
1055
1069
  if @vault.nil?
1056
- vault_info = options.get_option(:secrets)
1057
- case vault_info
1058
- when Hash
1059
- @vault = Keychain::EncryptedHash.new(vault_info)
1060
- when /^system/
1061
- name = vault_info.start_with?('system:') ? vault_info[7..-1] : nil
1070
+ vault_info = options.get_option(:vault) || {'type'=>'file','name'=>'vault.bin'}
1071
+ vault_password = options.get_option(:vault_password,is_type: :mandatory)
1072
+ raise 'vault must be Hash' unless vault_info.is_a?(Hash)
1073
+ vault_type = vault_info['type'] || 'file'
1074
+ vault_name = vault_info['name'] || (vault_type.eql?('file') ? 'vault.bin' : PROGRAM_NAME)
1075
+ case vault_type
1076
+ when 'file'
1077
+ vault_path=vault_name
1078
+ @vault = Keychain::EncryptedHash.new(vault_path,vault_password)
1079
+ when 'system'
1062
1080
  case Environment.os
1063
1081
  when Environment::OS_X
1064
- @vault = Keychain::MacosSecurity.new(name)
1082
+ @vault = Keychain::MacosSystem.new(vault_name,vault_password)
1065
1083
  when Environment::OS_WINDOWS,Environment::OS_LINUX,Environment::OS_AIX
1066
1084
  raise 'not implemented'
1067
- else raise 'Error'
1085
+ else raise 'Error, OS not supported'
1068
1086
  end
1069
- when NilClass
1070
- # keep nil
1071
1087
  else
1072
- raise CliBadArgument,'secrets shall be Hash'
1088
+ raise CliBadArgument,"Unknown vault type: #{vault_type}"
1073
1089
  end
1074
1090
  end
1075
1091
  raise 'No vault defined' if @vault.nil?
@@ -56,7 +56,7 @@ module Aspera
56
56
  # extract elements from anonymous faspex link
57
57
  def get_link_data(publink)
58
58
  publink_uri = URI.parse(publink)
59
- raise CliBadArgument, 'public link does not match Faspex format' unless (m = publink_uri.path.match(/^(.*)\/(external.*)$/))
59
+ raise CliBadArgument, 'Public link does not match Faspex format' unless (m = publink_uri.path.match(/^(.*)\/(external.*)$/))
60
60
  base = m[1]
61
61
  subpath = m[2]
62
62
  port_add = publink_uri.port.eql?(publink_uri.default_port) ? '' : ":#{publink_uri.port}"
@@ -236,7 +236,7 @@ module Aspera
236
236
  begin
237
237
  pkgdatares = JSON.parse("[#{pkgdatares}]")
238
238
  rescue JSON::ParserError # => e
239
- raise 'Link not valid'
239
+ raise 'Unexpected response: missing metadata ?'
240
240
  end
241
241
  return pkgdatares.first
242
242
  end
@@ -357,7 +357,7 @@ module Aspera
357
357
  headers: {'Accept' => 'application/xml'})
358
358
  if !pkgdatares[:http].body.start_with?('<?xml ')
359
359
  OpenApplication.instance.uri(link_url)
360
- raise CliError, 'no such package'
360
+ raise CliError, 'Unexpected response: package not found ?'
361
361
  end
362
362
  package_entry = XmlSimple.xml_in(pkgdatares[:http].body, {'ForceArray' => false})
363
363
  Log.dump(:package_entry,package_entry)
@@ -82,12 +82,14 @@ module Aspera
82
82
  end
83
83
  end
84
84
 
85
- ACTIONS = %i[health package admin user].freeze
85
+ ACTIONS = %i[health version user bearer_token package admin].freeze
86
86
 
87
87
  def execute_action
88
88
  set_api
89
89
  command = options.get_next_command(ACTIONS)
90
90
  case command
91
+ when :version
92
+ return { type: :single_object, data: @api_v5.read('version')[:data] }
91
93
  when :health
92
94
  nagios = Nagios.new
93
95
  begin
@@ -110,6 +112,8 @@ module Aspera
110
112
  return Main.result_status('modified')
111
113
  end
112
114
  end
115
+ when :bearer_token
116
+ return {type: :text,data: @api_v5.oauth_token}
113
117
  when :package
114
118
  command = options.get_next_command(%i[list show send receive])
115
119
  case command
@@ -427,6 +427,7 @@ module Aspera
427
427
  raise 'ERR'
428
428
  end # execute_node_gen4_command
429
429
 
430
+ # This is older API
430
431
  def execute_async
431
432
  command = options.get_next_command(%i[list delete files show counters bandwidth])
432
433
  unless command.eql?(:list)
@@ -504,13 +505,27 @@ module Aspera
504
505
  end
505
506
  end
506
507
 
507
- ACTIONS = %i[postprocess stream transfer cleanup forward access_key watch_folder service async central asperabrowser basic_token].concat(COMMON_ACTIONS).freeze
508
+ ACTIONS = %i[postprocess stream transfer cleanup forward access_key watch_folder service async sync central asperabrowser
509
+ basic_token].concat(COMMON_ACTIONS).freeze
508
510
 
509
511
  def execute_action(command=nil,prefix_path=nil)
510
512
  command ||= options.get_next_command(ACTIONS)
511
513
  case command
512
514
  when *COMMON_ACTIONS then return execute_simple_common(command,prefix_path)
513
515
  when :async then return execute_async
516
+ when :sync
517
+ sync_command = options.get_next_command([Plugin::ALL_OPS,%i[bandwidth counters files start state stop summary]].flatten-%i[modify])
518
+ case sync_command
519
+ when *Plugin::ALL_OPS then return entity_command(sync_command,@api_node,'asyncs',item_list_key: 'ids')
520
+ else
521
+ parameters = options.get_option(:value)
522
+ asyncs_id=instance_identifier
523
+ if %i[start stop].include?(sync_command)
524
+ @api_node.create("asyncs/#{asyncs_id}/#{sync_command}",parameters)
525
+ return Main.result_status('ok')
526
+ end
527
+ return { type: :single_object, data: @api_node.read("asyncs/#{asyncs_id}/#{sync_command}",parameters)[:data] }
528
+ end
514
529
  when :stream
515
530
  command = options.get_next_command(%i[list create show modify cancel])
516
531
  case command
@@ -545,7 +560,9 @@ module Aspera
545
560
  case command
546
561
  when :list
547
562
  # could use ? subpath: 'transfers'
548
- resp = @api_node.read(res_class_path,options.get_option(:value))
563
+ query=options.get_option(:value) || options.get_option(:query)
564
+ raise 'Query must be a Hash' unless query.nil? || query.is_a?(Hash)
565
+ resp = @api_node.read(res_class_path,query)
549
566
  return {
550
567
  type: :object_list,
551
568
  data: resp[:data],
@@ -635,8 +652,11 @@ module Aspera
635
652
  when :list
636
653
  request_data.deep_merge!({'validation' => validation}) unless validation.nil?
637
654
  resp = @api_node.create('services/rest/transfers/v1/sessions',request_data)
638
- return { type: :object_list, data: resp[:data]['session_info_result']['session_info'],
639
- fields: %w[session_uuid status transport direction bytes_transferred]}
655
+ return {
656
+ type: :object_list,
657
+ data: resp[:data]['session_info_result']['session_info'],
658
+ fields: %w[session_uuid status transport direction bytes_transferred]
659
+ }
640
660
  end
641
661
  when :file
642
662
  command = options.get_next_command(%i[list modify])
@@ -397,7 +397,7 @@ module Aspera
397
397
  Log.log.warn("unknown entry type: #{entry['type']}")
398
398
  end
399
399
  rescue StandardError => e
400
- Log.log.warn("An error occured: #{e}, ignoring")
400
+ Log.log.warn("An error occurred: #{e}, ignoring")
401
401
  end
402
402
  end
403
403
  end
@@ -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
@@ -230,11 +231,11 @@ module Aspera
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.10.0'
6
6
  end
7
7
  end