aspera-cli 4.10.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/BUGS.md +20 -0
- data/CHANGELOG.md +509 -0
- data/CONTRIBUTING.md +118 -0
- data/README.md +621 -378
- data/bin/ascli +4 -4
- data/bin/asession +11 -11
- data/docs/test_env.conf +28 -19
- data/examples/aoc.rb +4 -4
- data/examples/dascli +11 -9
- data/examples/faspex4.rb +8 -8
- data/examples/node.rb +11 -11
- data/examples/server.rb +9 -9
- data/lib/aspera/aoc.rb +273 -266
- data/lib/aspera/ascmd.rb +56 -54
- data/lib/aspera/ats_api.rb +4 -4
- data/lib/aspera/cli/basic_auth_plugin.rb +15 -12
- data/lib/aspera/cli/extended_value.rb +5 -5
- data/lib/aspera/cli/formater.rb +64 -64
- data/lib/aspera/cli/listener/line_dump.rb +1 -1
- data/lib/aspera/cli/listener/logger.rb +1 -1
- data/lib/aspera/cli/listener/progress.rb +5 -6
- data/lib/aspera/cli/listener/progress_multi.rb +14 -19
- data/lib/aspera/cli/main.rb +66 -67
- data/lib/aspera/cli/manager.rb +110 -110
- data/lib/aspera/cli/plugin.rb +54 -37
- data/lib/aspera/cli/plugins/alee.rb +4 -4
- data/lib/aspera/cli/plugins/aoc.rb +308 -669
- data/lib/aspera/cli/plugins/ats.rb +44 -46
- data/lib/aspera/cli/plugins/bss.rb +10 -10
- data/lib/aspera/cli/plugins/config.rb +447 -344
- data/lib/aspera/cli/plugins/console.rb +12 -12
- data/lib/aspera/cli/plugins/cos.rb +18 -20
- data/lib/aspera/cli/plugins/faspex.rb +110 -112
- data/lib/aspera/cli/plugins/faspex5.rb +67 -46
- data/lib/aspera/cli/plugins/node.rb +364 -288
- data/lib/aspera/cli/plugins/orchestrator.rb +46 -46
- data/lib/aspera/cli/plugins/preview.rb +122 -114
- data/lib/aspera/cli/plugins/server.rb +137 -83
- data/lib/aspera/cli/plugins/shares.rb +30 -29
- data/lib/aspera/cli/plugins/sync.rb +13 -33
- data/lib/aspera/cli/transfer_agent.rb +57 -57
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/colors.rb +3 -3
- data/lib/aspera/command_line_builder.rb +27 -27
- data/lib/aspera/cos_node.rb +22 -20
- data/lib/aspera/data_repository.rb +1 -1
- data/lib/aspera/environment.rb +30 -28
- data/lib/aspera/fasp/agent_base.rb +15 -15
- data/lib/aspera/fasp/agent_connect.rb +23 -21
- data/lib/aspera/fasp/agent_direct.rb +65 -67
- data/lib/aspera/fasp/agent_httpgw.rb +72 -68
- data/lib/aspera/fasp/agent_node.rb +23 -21
- data/lib/aspera/fasp/agent_trsdk.rb +20 -20
- data/lib/aspera/fasp/error.rb +3 -2
- data/lib/aspera/fasp/error_info.rb +11 -8
- data/lib/aspera/fasp/installation.rb +78 -78
- data/lib/aspera/fasp/listener.rb +1 -1
- data/lib/aspera/fasp/parameters.rb +75 -72
- data/lib/aspera/fasp/parameters.yaml +2 -2
- data/lib/aspera/fasp/resume_policy.rb +8 -8
- data/lib/aspera/fasp/transfer_spec.rb +35 -2
- data/lib/aspera/fasp/uri.rb +7 -7
- data/lib/aspera/faspex_gw.rb +7 -5
- data/lib/aspera/hash_ext.rb +3 -3
- data/lib/aspera/id_generator.rb +5 -5
- data/lib/aspera/keychain/encrypted_hash.rb +23 -28
- data/lib/aspera/keychain/macos_security.rb +21 -20
- data/lib/aspera/log.rb +7 -7
- data/lib/aspera/nagios.rb +19 -18
- data/lib/aspera/node.rb +209 -35
- data/lib/aspera/oauth.rb +37 -36
- data/lib/aspera/open_application.rb +19 -11
- data/lib/aspera/persistency_action_once.rb +4 -4
- data/lib/aspera/persistency_folder.rb +13 -13
- data/lib/aspera/preview/file_types.rb +8 -8
- data/lib/aspera/preview/generator.rb +67 -67
- data/lib/aspera/preview/utils.rb +27 -27
- data/lib/aspera/proxy_auto_config.js +41 -41
- data/lib/aspera/proxy_auto_config.rb +16 -16
- data/lib/aspera/rest.rb +56 -60
- data/lib/aspera/rest_call_error.rb +2 -1
- data/lib/aspera/rest_error_analyzer.rb +18 -17
- data/lib/aspera/rest_errors_aspera.rb +16 -16
- data/lib/aspera/secret_hider.rb +15 -13
- data/lib/aspera/ssh.rb +11 -10
- data/lib/aspera/sync.rb +158 -44
- data/lib/aspera/temp_file_manager.rb +2 -2
- data/lib/aspera/uri_reader.rb +4 -4
- data/lib/aspera/web_auth.rb +14 -13
- data.tar.gz.sig +0 -0
- metadata +8 -5
- metadata.gz.sig +0 -0
|
@@ -16,10 +16,43 @@ module Aspera
|
|
|
16
16
|
'fasp_port' => UDP_PORT
|
|
17
17
|
}.freeze
|
|
18
18
|
# define constants for enums of parameters: <paramater>_<enum>, e.g. CIPHER_AES_128
|
|
19
|
-
Aspera::Fasp::Parameters.description.each do |k,v|
|
|
19
|
+
Aspera::Fasp::Parameters.description.each do |k, v|
|
|
20
20
|
next unless v[:enum].is_a?(Array)
|
|
21
21
|
v[:enum].each do |enum|
|
|
22
|
-
TransferSpec.const_set("#{k.to_s.upcase}_#{enum.upcase.gsub(/[^A-Z0-9]/,'_')}", enum.freeze)
|
|
22
|
+
TransferSpec.const_set("#{k.to_s.upcase}_#{enum.upcase.gsub(/[^A-Z0-9]/, '_')}", enum.freeze)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
class << self
|
|
26
|
+
def ascp_opts_to_ts(tspec, opts)
|
|
27
|
+
return if opts.nil?
|
|
28
|
+
raise 'ascp options must be an Array' unless opts.is_a?(Array)
|
|
29
|
+
raise 'transfer spec must be a Hash' unless tspec.is_a?(Hash)
|
|
30
|
+
raise 'ascp options must be an Array or Strings' if opts.any?{|o|!o.is_a?(String)}
|
|
31
|
+
tspec['EX_ascp_args'] ||= []
|
|
32
|
+
raise 'EX_ascp_args must be an Array' unless tspec['EX_ascp_args'].is_a?(Array)
|
|
33
|
+
# TODO: translate command line args into transfer spec
|
|
34
|
+
# non translatable args are left in special ts parameter
|
|
35
|
+
tspec['EX_ascp_args'] = tspec['EX_ascp_args'].concat(opts)
|
|
36
|
+
return tspec
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def action_to_direction(tspec, command)
|
|
40
|
+
raise 'transfer spec must be a Hash' unless tspec.is_a?(Hash)
|
|
41
|
+
tspec['direction'] = case command.to_sym
|
|
42
|
+
when :upload then DIRECTION_SEND
|
|
43
|
+
when :download then DIRECTION_RECEIVE
|
|
44
|
+
else raise 'Error: upload or download only'
|
|
45
|
+
end
|
|
46
|
+
return tspec
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def action(tspec)
|
|
50
|
+
raise 'transfer spec must be a Hash' unless tspec.is_a?(Hash)
|
|
51
|
+
return case tspec['direction']
|
|
52
|
+
when DIRECTION_SEND then :upload
|
|
53
|
+
when DIRECTION_RECEIVE then :download
|
|
54
|
+
else raise 'Error: upload or download only'
|
|
55
|
+
end
|
|
23
56
|
end
|
|
24
57
|
end
|
|
25
58
|
end
|
data/lib/aspera/fasp/uri.rb
CHANGED
|
@@ -5,10 +5,10 @@ require 'aspera/command_line_builder'
|
|
|
5
5
|
|
|
6
6
|
module Aspera
|
|
7
7
|
module Fasp
|
|
8
|
-
# translates a "faspe:" URI (used in Faspex) into transfer spec hash
|
|
8
|
+
# translates a "faspe:" URI (used in Faspex 4) into transfer spec hash
|
|
9
9
|
class Uri
|
|
10
10
|
def initialize(fasplink)
|
|
11
|
-
@fasp_uri = URI.parse(fasplink.gsub(' ','%20'))
|
|
11
|
+
@fasp_uri = URI.parse(fasplink.gsub(' ', '%20'))
|
|
12
12
|
# TODO: check scheme is faspe
|
|
13
13
|
end
|
|
14
14
|
|
|
@@ -34,16 +34,16 @@ module Aspera
|
|
|
34
34
|
when 'minrate' then result_ts['min_rate_kbps'] = value.to_i
|
|
35
35
|
when 'port' then result_ts['fasp_port'] = value.to_i
|
|
36
36
|
when 'bwcap' then result_ts['target_rate_cap_kbps'] = value.to_i
|
|
37
|
-
when 'enc' then result_ts['cipher'] = value.gsub(/^aes/,'aes-').gsub(/cfb$/,'-cfb').gsub(/gcm$/,'-gcm').gsub(/--/,'-')
|
|
37
|
+
when 'enc' then result_ts['cipher'] = value.gsub(/^aes/, 'aes-').gsub(/cfb$/, '-cfb').gsub(/gcm$/, '-gcm').gsub(/--/, '-')
|
|
38
38
|
when 'tags64' then result_ts['tags'] = JSON.parse(Base64.strict_decode64(value))
|
|
39
39
|
when 'createpath' then result_ts['create_dir'] = CommandLineBuilder.yes_to_true(value)
|
|
40
40
|
when 'fallback' then result_ts['http_fallback'] = CommandLineBuilder.yes_to_true(value)
|
|
41
41
|
when 'lockpolicy' then result_ts['lock_rate_policy'] = CommandLineBuilder.yes_to_true(value)
|
|
42
42
|
when 'lockminrate' then result_ts['lock_min_rate'] = CommandLineBuilder.yes_to_true(value)
|
|
43
|
-
when 'auth' then Log.log.debug
|
|
44
|
-
when 'v' then Log.log.debug
|
|
45
|
-
when 'protect' then Log.log.debug
|
|
46
|
-
else Log.log.warn
|
|
43
|
+
when 'auth' then Log.log.debug{"ignoring auth #{name}=#{value}"} # TODO: translate into transfer spec ? yes/no
|
|
44
|
+
when 'v' then Log.log.debug{"ignoring v #{name}=#{value}"} # TODO: translate into transfer spec ? 2
|
|
45
|
+
when 'protect' then Log.log.debug{"ignoring protect #{name}=#{value}"} # TODO: translate into transfer spec ?
|
|
46
|
+
else Log.log.warn{"URI parameter ignored: #{name} = #{value}"}
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
49
|
return result_ts
|
data/lib/aspera/faspex_gw.rb
CHANGED
|
@@ -37,12 +37,13 @@ module Aspera
|
|
|
37
37
|
|
|
38
38
|
faspex_pkg_parameters = JSON.parse(request.body)
|
|
39
39
|
faspex_pkg_delivery = faspex_pkg_parameters['delivery']
|
|
40
|
-
Log.log.debug
|
|
40
|
+
Log.log.debug{"faspex pkg create parameters=#{faspex_pkg_parameters}"}
|
|
41
41
|
|
|
42
42
|
# get recipient ids
|
|
43
43
|
files_pkg_recipients = []
|
|
44
44
|
faspex_pkg_delivery['recipients'].each do |recipient_email|
|
|
45
|
-
user_lookup = @aoc_api_user.read(
|
|
45
|
+
user_lookup = @aoc_api_user.read(
|
|
46
|
+
'contacts',
|
|
46
47
|
{ 'current_workspace_id' => @aoc_workspace_id, 'q' => recipient_email })[:data]
|
|
47
48
|
raise StandardError,
|
|
48
49
|
"no such unique user: #{recipient_email} / #{user_lookup}" unless !user_lookup.nil? && user_lookup.length.eql?(1)
|
|
@@ -67,7 +68,8 @@ module Aspera
|
|
|
67
68
|
node_info = @aoc_api_user.read("nodes/#{the_package['node_id']}")[:data]
|
|
68
69
|
|
|
69
70
|
# get transfer token (for node)
|
|
70
|
-
node_auth_bearer_token = @aoc_api_user.oauth_token(scope: AoC.node_scope(
|
|
71
|
+
node_auth_bearer_token = @aoc_api_user.oauth_token(scope: AoC.node_scope(
|
|
72
|
+
node_info['access_key'],
|
|
71
73
|
AoC::SCOPE_NODE_USER))
|
|
72
74
|
|
|
73
75
|
# tell Files what to expect in package: 1 transfer (can also be done after transfer)
|
|
@@ -123,7 +125,7 @@ module Aspera
|
|
|
123
125
|
'links' => { 'status' => 'unused' },
|
|
124
126
|
'xfer_sessions' => [faspex_transfer_spec]
|
|
125
127
|
}
|
|
126
|
-
Log.log.info
|
|
128
|
+
Log.log.info{"faspex_package_create_result=#{faspex_package_create_result}"}
|
|
127
129
|
response.status = 200
|
|
128
130
|
response.content_type = 'application/json'
|
|
129
131
|
response.body = JSON.generate(faspex_package_create_result)
|
|
@@ -160,7 +162,7 @@ module Aspera
|
|
|
160
162
|
SSLEnable: true,
|
|
161
163
|
SSLCertName: [['CN', WEBrick::Utils.getservername]]
|
|
162
164
|
}
|
|
163
|
-
Log.log.info
|
|
165
|
+
Log.log.info{"Server started on port #{webrick_options[:Port]}"}
|
|
164
166
|
@server = WEBrick::HTTPServer.new(webrick_options)
|
|
165
167
|
@server.mount('/aspera/faspex', FxGwServlet, a_aoc_api_user, a_workspace_id)
|
|
166
168
|
@server.mount('/newuser', NewUserServlet)
|
data/lib/aspera/hash_ext.rb
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
class ::Hash
|
|
4
4
|
def deep_merge(second)
|
|
5
|
-
merge(second){|_key,v1,v2|Hash === v1 && Hash === v2 ? v1.deep_merge(v2) : v2}
|
|
5
|
+
merge(second){|_key, v1, v2|Hash === v1 && Hash === v2 ? v1.deep_merge(v2) : v2}
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
def deep_merge!(second)
|
|
9
|
-
merge!(second){|_key,v1,v2|Hash === v1 && Hash === v2 ? v1.deep_merge!(v2) : v2}
|
|
9
|
+
merge!(second){|_key, v1, v2|Hash === v1 && Hash === v2 ? v1.deep_merge!(v2) : v2}
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
12
|
|
|
@@ -14,7 +14,7 @@ end
|
|
|
14
14
|
unless Hash.method_defined?(:transform_keys)
|
|
15
15
|
class Hash
|
|
16
16
|
def transform_keys
|
|
17
|
-
return each_with_object({}){|(k,v),memo|memo[yield(k)]=v} if block_given?
|
|
17
|
+
return each_with_object({}){|(k, v), memo|memo[yield(k)] = v} if block_given?
|
|
18
18
|
raise 'missing block'
|
|
19
19
|
end
|
|
20
20
|
end
|
data/lib/aspera/id_generator.rb
CHANGED
|
@@ -7,7 +7,7 @@ module Aspera
|
|
|
7
7
|
ID_SEPARATOR = '_'
|
|
8
8
|
WINDOWS_PROTECTED_CHAR = %r{[/:"<>\\*?]}.freeze
|
|
9
9
|
PROTECTED_CHAR_REPLACE = '_'
|
|
10
|
-
private_constant :ID_SEPARATOR
|
|
10
|
+
private_constant :ID_SEPARATOR, :PROTECTED_CHAR_REPLACE, :WINDOWS_PROTECTED_CHAR
|
|
11
11
|
class << self
|
|
12
12
|
def from_list(object_id)
|
|
13
13
|
if object_id.is_a?(Array)
|
|
@@ -16,10 +16,10 @@ module Aspera
|
|
|
16
16
|
end.join(ID_SEPARATOR)
|
|
17
17
|
end
|
|
18
18
|
raise 'id must be a String' unless object_id.is_a?(String)
|
|
19
|
-
return object_id
|
|
20
|
-
gsub(WINDOWS_PROTECTED_CHAR,PROTECTED_CHAR_REPLACE)
|
|
21
|
-
gsub('.',PROTECTED_CHAR_REPLACE)
|
|
22
|
-
downcase
|
|
19
|
+
return object_id
|
|
20
|
+
.gsub(WINDOWS_PROTECTED_CHAR, PROTECTED_CHAR_REPLACE) # remove windows forbidden chars
|
|
21
|
+
.gsub('.', PROTECTED_CHAR_REPLACE) # keep dot for extension only (nicer)
|
|
22
|
+
.downcase
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'aspera/hash_ext'
|
|
4
|
+
require 'aspera/environment'
|
|
4
5
|
require 'symmetric_encryption/core'
|
|
5
6
|
require 'yaml'
|
|
6
7
|
|
|
@@ -8,65 +9,59 @@ module Aspera
|
|
|
8
9
|
module Keychain
|
|
9
10
|
# Manage secrets in a simple Hash
|
|
10
11
|
class EncryptedHash
|
|
11
|
-
CIPHER_NAME='aes-256-cbc'
|
|
12
|
-
|
|
13
|
-
def initialize(path,current_password)
|
|
14
|
-
@path=path
|
|
15
|
-
self.password=current_password
|
|
12
|
+
CIPHER_NAME = 'aes-256-cbc'
|
|
13
|
+
CONTENT_KEYS = %i[label username password url description].freeze
|
|
14
|
+
def initialize(path, current_password)
|
|
15
|
+
@path = path
|
|
16
|
+
self.password = current_password
|
|
16
17
|
raise 'path to vault file shall be String' unless @path.is_a?(String)
|
|
17
|
-
@all_secrets=File.exist?(@path) ? YAML.load_stream(@cipher.decrypt(File.read(@path))).first : {}
|
|
18
|
+
@all_secrets = File.exist?(@path) ? YAML.load_stream(@cipher.decrypt(File.read(@path))).first : {}
|
|
18
19
|
end
|
|
19
20
|
|
|
20
21
|
def password=(new_password)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
key
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
# number of bits in second position
|
|
23
|
+
key_bytes = CIPHER_NAME.split('-')[1].to_i / Environment::BITS_PER_BYTE
|
|
24
|
+
# derive key from passphrase, add trailing zeros
|
|
25
|
+
key = "#{new_password}#{"\x0" * key_bytes}"[0..(key_bytes - 1)]
|
|
26
|
+
Log.log.debug{"key=[#{key}],#{key.length}"}
|
|
27
|
+
SymmetricEncryption.cipher = @cipher = SymmetricEncryption::Cipher.new(cipher_name: CIPHER_NAME, key: key, encoding: :none)
|
|
26
28
|
end
|
|
27
29
|
|
|
28
30
|
def save
|
|
29
|
-
File.write(@path, @cipher.encrypt(YAML.dump(@all_secrets)),encoding: 'BINARY')
|
|
31
|
+
File.write(@path, @cipher.encrypt(YAML.dump(@all_secrets)), encoding: 'BINARY')
|
|
30
32
|
end
|
|
31
33
|
|
|
32
34
|
def set(options)
|
|
33
35
|
raise 'options shall be Hash' unless options.is_a?(Hash)
|
|
34
|
-
unsupported = options.keys -
|
|
36
|
+
unsupported = options.keys - CONTENT_KEYS
|
|
37
|
+
options.each_value {|v| raise 'value must be String' unless v.is_a?(String)}
|
|
35
38
|
raise "unsupported options: #{unsupported}" unless unsupported.empty?
|
|
36
39
|
label = options.delete(:label)
|
|
37
|
-
raise "secret #{label} already exist, delete first" if @all_secrets.
|
|
40
|
+
raise "secret #{label} already exist, delete first" if @all_secrets.key?(label)
|
|
38
41
|
@all_secrets[label] = options.symbolize_keys
|
|
39
42
|
save
|
|
40
43
|
end
|
|
41
44
|
|
|
42
45
|
def list
|
|
43
46
|
result = []
|
|
44
|
-
@all_secrets.each do |label,values|
|
|
47
|
+
@all_secrets.each do |label, values|
|
|
45
48
|
normal = values.symbolize_keys
|
|
46
49
|
normal[:label] = label
|
|
47
|
-
|
|
50
|
+
CONTENT_KEYS.each{|k|normal[k] = '' unless normal.key?(k)}
|
|
48
51
|
result.push(normal)
|
|
49
52
|
end
|
|
50
53
|
return result
|
|
51
54
|
end
|
|
52
55
|
|
|
53
|
-
def delete(
|
|
54
|
-
raise 'options shall be Hash' unless options.is_a?(Hash)
|
|
55
|
-
unsupported = options.keys - %i[label]
|
|
56
|
-
raise "unsupported options: #{unsupported}" unless unsupported.empty?
|
|
57
|
-
label=options[:label]
|
|
56
|
+
def delete(label:)
|
|
58
57
|
@all_secrets.delete(label)
|
|
59
58
|
save
|
|
60
59
|
end
|
|
61
60
|
|
|
62
|
-
def get(
|
|
63
|
-
raise
|
|
64
|
-
unsupported = options.keys - %i[label]
|
|
65
|
-
raise "unsupported options: #{unsupported}" unless unsupported.empty?
|
|
66
|
-
label=options[:label]
|
|
61
|
+
def get(label:, exception: true)
|
|
62
|
+
raise "Label not found: #{label}" unless @all_secrets.key?(label) || !exception
|
|
67
63
|
result = @all_secrets[label].clone
|
|
68
|
-
|
|
69
|
-
result[:label]=label
|
|
64
|
+
result[:label] = label if result.is_a?(Hash)
|
|
70
65
|
return result
|
|
71
66
|
end
|
|
72
67
|
end
|
|
@@ -10,10 +10,10 @@ module Aspera
|
|
|
10
10
|
# keychain based on macOS keychain, using `security` cmmand line
|
|
11
11
|
class Keychain
|
|
12
12
|
DOMAINS = %i[user system common dynamic].freeze
|
|
13
|
-
LIST_OPTIONS={
|
|
13
|
+
LIST_OPTIONS = {
|
|
14
14
|
domain: :c
|
|
15
15
|
}
|
|
16
|
-
ADD_PASS_OPTIONS={
|
|
16
|
+
ADD_PASS_OPTIONS = {
|
|
17
17
|
account: :a,
|
|
18
18
|
creator: :c,
|
|
19
19
|
type: :C,
|
|
@@ -32,7 +32,7 @@ module Aspera
|
|
|
32
32
|
getpass: :g
|
|
33
33
|
}.freeze
|
|
34
34
|
class << self
|
|
35
|
-
def execute(command,options=nil,supported=nil,lastopt=nil)
|
|
35
|
+
def execute(command, options=nil, supported=nil, lastopt=nil)
|
|
36
36
|
url = options&.delete(:url)
|
|
37
37
|
if !url.nil?
|
|
38
38
|
uri = URI.parse(url)
|
|
@@ -40,20 +40,20 @@ module Aspera
|
|
|
40
40
|
options[:protocol] = 'htps'
|
|
41
41
|
raise 'host required in URL' if uri.host.nil?
|
|
42
42
|
options[:server] = uri.host
|
|
43
|
-
options[:path] = uri.path unless ['','/'].include?(uri.path)
|
|
43
|
+
options[:path] = uri.path unless ['', '/'].include?(uri.path)
|
|
44
44
|
options[:port] = uri.port unless uri.port.eql?(443) && !url.include?(':443/')
|
|
45
45
|
end
|
|
46
|
-
cmd=['security',command]
|
|
47
|
-
options&.each do |k,v|
|
|
48
|
-
raise "unknown option: #{k}" unless supported.
|
|
46
|
+
cmd = ['security', command]
|
|
47
|
+
options&.each do |k, v|
|
|
48
|
+
raise "unknown option: #{k}" unless supported.key?(k)
|
|
49
49
|
next if v.nil?
|
|
50
50
|
cmd.push("-#{supported[k]}")
|
|
51
51
|
cmd.push(v.shellescape) unless v.empty?
|
|
52
52
|
end
|
|
53
53
|
cmd.push(lastopt) unless lastopt.nil?
|
|
54
|
-
Log.log.debug
|
|
55
|
-
result
|
|
56
|
-
Log.log.debug
|
|
54
|
+
Log.log.debug{"executing>>#{cmd.join(' ')}"}
|
|
55
|
+
result = %x(#{cmd.join(' ')} 2>&1)
|
|
56
|
+
Log.log.debug{"result>>[#{result}]"}
|
|
57
57
|
return result
|
|
58
58
|
end
|
|
59
59
|
|
|
@@ -70,8 +70,8 @@ module Aspera
|
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
def list(options={})
|
|
73
|
-
raise ArgumentError,"Invalid domain #{options[:domain]}, expected one of: #{DOMAINS}" unless options[:domain].nil? || DOMAINS.include?(options[:domain])
|
|
74
|
-
keychains(execute('list-keychains',options,LIST_OPTIONS))
|
|
73
|
+
raise ArgumentError, "Invalid domain #{options[:domain]}, expected one of: #{DOMAINS}" unless options[:domain].nil? || DOMAINS.include?(options[:domain])
|
|
74
|
+
keychains(execute('list-keychains', options, LIST_OPTIONS))
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
def by_name(name)
|
|
@@ -88,15 +88,15 @@ module Aspera
|
|
|
88
88
|
[string].pack('H*').force_encoding('UTF-8')
|
|
89
89
|
end
|
|
90
90
|
|
|
91
|
-
def password(operation,passtype,options)
|
|
91
|
+
def password(operation, passtype, options)
|
|
92
92
|
raise "wrong operation: #{operation}" unless %i[add find delete].include?(operation)
|
|
93
93
|
raise "wrong passtype: #{passtype}" unless %i[generic internet].include?(passtype)
|
|
94
94
|
raise 'options shall be Hash' unless options.is_a?(Hash)
|
|
95
|
-
missing=(operation.eql?(:add) ? %i[account service password] : %i[label])-options.keys
|
|
95
|
+
missing = (operation.eql?(:add) ? %i[account service password] : %i[label]) - options.keys
|
|
96
96
|
raise "missing options: #{missing}" unless missing.empty?
|
|
97
|
-
options[:getpass]='' if operation.eql?(:find)
|
|
98
|
-
output=self.class.execute("#{operation}-#{passtype}-password",options,ADD_PASS_OPTIONS
|
|
99
|
-
raise output.gsub(/^.*: /,'') if output.start_with?('security: ')
|
|
97
|
+
options[:getpass] = '' if operation.eql?(:find)
|
|
98
|
+
output = self.class.execute("#{operation}-#{passtype}-password", options, ADD_PASS_OPTIONS, @path)
|
|
99
|
+
raise output.gsub(/^.*: /, '') if output.start_with?('security: ')
|
|
100
100
|
return nil unless operation.eql?(:find)
|
|
101
101
|
attributes = {}
|
|
102
102
|
output.split("\n").each do |line|
|
|
@@ -121,7 +121,7 @@ module Aspera
|
|
|
121
121
|
end
|
|
122
122
|
|
|
123
123
|
class MacosSystem
|
|
124
|
-
def initialize(name=nil,
|
|
124
|
+
def initialize(name=nil, _password=nil)
|
|
125
125
|
@keychain = name.nil? ? MacosSecurity::Keychain.default_keychain : MacosSecurity::Keychain.by_name(name)
|
|
126
126
|
raise "no such keychain #{name}" if @keychain.nil?
|
|
127
127
|
end
|
|
@@ -130,7 +130,8 @@ module Aspera
|
|
|
130
130
|
raise 'options shall be Hash' unless options.is_a?(Hash)
|
|
131
131
|
unsupported = options.keys - %i[label username password url description]
|
|
132
132
|
raise "unsupported options: #{unsupported}" unless unsupported.empty?
|
|
133
|
-
@keychain.password(
|
|
133
|
+
@keychain.password(
|
|
134
|
+
:add, :generic, service: options[:label],
|
|
134
135
|
account: options[:username] || 'none', password: options[:password], comment: options[:description])
|
|
135
136
|
end
|
|
136
137
|
|
|
@@ -138,7 +139,7 @@ module Aspera
|
|
|
138
139
|
raise 'options shall be Hash' unless options.is_a?(Hash)
|
|
139
140
|
unsupported = options.keys - %i[label]
|
|
140
141
|
raise "unsupported options: #{unsupported}" unless unsupported.empty?
|
|
141
|
-
info = @keychain.password(:find
|
|
142
|
+
info = @keychain.password(:find, :generic, label: options[:label])
|
|
142
143
|
raise 'not found' if info.nil?
|
|
143
144
|
result = options.clone
|
|
144
145
|
result[:secret] = info['password']
|
data/lib/aspera/log.rb
CHANGED
|
@@ -14,25 +14,25 @@ module Aspera
|
|
|
14
14
|
# class methods
|
|
15
15
|
class << self
|
|
16
16
|
# levels are :debug,:info,:warn,:error,fatal,:unknown
|
|
17
|
-
def levels; Logger::Severity.constants.sort{|a,b|Logger::Severity.const_get(a) <=> Logger::Severity.const_get(b)}.map{|c|c.downcase.to_sym};end
|
|
17
|
+
def levels; Logger::Severity.constants.sort{|a, b|Logger::Severity.const_get(a) <=> Logger::Severity.const_get(b)}.map{|c|c.downcase.to_sym}; end
|
|
18
18
|
|
|
19
19
|
# where logs are sent to
|
|
20
|
-
def logtypes; %i[stderr stdout syslog];end
|
|
20
|
+
def logtypes; %i[stderr stdout syslog]; end
|
|
21
21
|
|
|
22
22
|
# get the logger object of singleton
|
|
23
|
-
def log; instance.logger;end
|
|
23
|
+
def log; instance.logger; end
|
|
24
24
|
|
|
25
25
|
# dump object in debug mode
|
|
26
26
|
# @param name string or symbol
|
|
27
27
|
# @param format either pp or json format
|
|
28
|
-
def dump(name,object,format=:json)
|
|
28
|
+
def dump(name, object, format=:json)
|
|
29
29
|
log.debug do
|
|
30
30
|
result =
|
|
31
31
|
case format
|
|
32
32
|
when :json
|
|
33
|
-
JSON.pretty_generate(object) rescue PP.pp(object
|
|
33
|
+
JSON.pretty_generate(object) rescue PP.pp(object, +'')
|
|
34
34
|
when :ruby
|
|
35
|
-
PP.pp(object
|
|
35
|
+
PP.pp(object, +'')
|
|
36
36
|
else
|
|
37
37
|
raise 'wrong parameter, expect pp or json'
|
|
38
38
|
end
|
|
@@ -70,7 +70,7 @@ module Aspera
|
|
|
70
70
|
# change underlying logger, but keep log level
|
|
71
71
|
def logger_type=(new_logtype)
|
|
72
72
|
current_severity_integer = @logger.level unless @logger.nil?
|
|
73
|
-
current_severity_integer = ENV['AS_LOG_LEVEL'] if current_severity_integer.nil? && ENV.
|
|
73
|
+
current_severity_integer = ENV['AS_LOG_LEVEL'] if current_severity_integer.nil? && ENV.key?('AS_LOG_LEVEL')
|
|
74
74
|
current_severity_integer = Logger::Severity::WARN if current_severity_integer.nil?
|
|
75
75
|
case new_logtype
|
|
76
76
|
when :stderr
|
data/lib/aspera/nagios.rb
CHANGED
|
@@ -10,32 +10,32 @@ module Aspera
|
|
|
10
10
|
# date offset levels
|
|
11
11
|
DATE_WARN_OFFSET = 2
|
|
12
12
|
DATE_CRIT_OFFSET = 5
|
|
13
|
-
private_constant :LEVELS
|
|
13
|
+
private_constant :LEVELS, :ADD_PREFIX, :DATE_WARN_OFFSET, :DATE_CRIT_OFFSET
|
|
14
14
|
|
|
15
15
|
# add methods to add nagios error levels, each take component name and message
|
|
16
16
|
LEVELS.each_index do |code|
|
|
17
17
|
name = "#{ADD_PREFIX}#{LEVELS[code]}".to_sym
|
|
18
|
-
define_method(name){|comp,msg|@data.push({code: code,comp: comp,msg: msg})}
|
|
18
|
+
define_method(name){|comp, msg|@data.push({code: code, comp: comp, msg: msg})}
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
class << self
|
|
22
22
|
# process results of a analysis and display status and exit with code
|
|
23
23
|
def process(data)
|
|
24
24
|
raise 'INTERNAL ERROR, result must be list and not empty' unless data.is_a?(Array) && !data.empty?
|
|
25
|
-
%w[status component message].each{|c|raise "INTERNAL ERROR, result must have #{c}" unless data.first.
|
|
25
|
+
%w[status component message].each{|c|raise "INTERNAL ERROR, result must have #{c}" unless data.first.key?(c)}
|
|
26
26
|
res_errors = data.reject{|s|s['status'].eql?('ok')}
|
|
27
27
|
# keep only errors in case of problem, other ok are assumed so
|
|
28
28
|
data = res_errors unless res_errors.empty?
|
|
29
29
|
# first is most critical
|
|
30
|
-
data.sort!{|a,b|LEVELS.index(a['status'].to_sym) <=> LEVELS.index(b['status'].to_sym)}
|
|
30
|
+
data.sort!{|a, b|LEVELS.index(a['status'].to_sym) <=> LEVELS.index(b['status'].to_sym)}
|
|
31
31
|
# build message: if multiple components: concatenate
|
|
32
|
-
#message = data.map{|i|"#{i['component']}:#{i['message']}"}.join(', ').gsub("\n",' ')
|
|
33
|
-
message = data
|
|
34
|
-
map{|i|i['component']}
|
|
35
|
-
uniq
|
|
36
|
-
map{|comp|comp + ':' + data.select{|d|d['component'].eql?(comp)}.map{|d|d['message']}.join(',')}
|
|
37
|
-
join(', ')
|
|
38
|
-
tr("\n",' ')
|
|
32
|
+
# message = data.map{|i|"#{i['component']}:#{i['message']}"}.join(', ').gsub("\n",' ')
|
|
33
|
+
message = data
|
|
34
|
+
.map{|i|i['component']}
|
|
35
|
+
.uniq
|
|
36
|
+
.map{|comp|comp + ':' + data.select{|d|d['component'].eql?(comp)}.map{|d|d['message']}.join(',')}
|
|
37
|
+
.join(', ')
|
|
38
|
+
.tr("\n", ' ')
|
|
39
39
|
status = data.first['status'].upcase
|
|
40
40
|
# display status for nagios
|
|
41
41
|
puts("#{status} - [#{message}]\n")
|
|
@@ -45,6 +45,7 @@ module Aspera
|
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
attr_reader :data
|
|
48
|
+
|
|
48
49
|
def initialize
|
|
49
50
|
@data = []
|
|
50
51
|
end
|
|
@@ -55,26 +56,26 @@ module Aspera
|
|
|
55
56
|
rtime = DateTime.strptime(remote_date)
|
|
56
57
|
diff_time = (rtime - DateTime.now).abs
|
|
57
58
|
diff_disp = diff_time.round(-2)
|
|
58
|
-
Log.log.debug
|
|
59
|
+
Log.log.debug{"DATE: #{remote_date} #{rtime} diff=#{diff_disp}"}
|
|
59
60
|
msg = "offset #{diff_disp} sec"
|
|
60
61
|
if diff_time >= DATE_CRIT_OFFSET
|
|
61
|
-
add_critical(component,msg)
|
|
62
|
+
add_critical(component, msg)
|
|
62
63
|
elsif diff_time >= DATE_WARN_OFFSET
|
|
63
|
-
add_warning(component,msg)
|
|
64
|
+
add_warning(component, msg)
|
|
64
65
|
else
|
|
65
|
-
add_ok(component,msg)
|
|
66
|
+
add_ok(component, msg)
|
|
66
67
|
end
|
|
67
68
|
end
|
|
68
69
|
|
|
69
70
|
def check_product_version(component, _product, version)
|
|
70
|
-
add_ok(component,"version #{version}")
|
|
71
|
-
# TODO check on database if latest version
|
|
71
|
+
add_ok(component, "version #{version}")
|
|
72
|
+
# TODO: check on database if latest version
|
|
72
73
|
end
|
|
73
74
|
|
|
74
75
|
# translate for display
|
|
75
76
|
def result
|
|
76
77
|
raise 'missing result' if @data.empty?
|
|
77
|
-
{type: :object_list,data: @data.map{|i|{'status' => LEVELS[i[:code]].to_s,'component' => i[:comp],'message' => i[:msg]}}}
|
|
78
|
+
{type: :object_list, data: @data.map{|i|{'status' => LEVELS[i[:code]].to_s, 'component' => i[:comp], 'message' => i[:msg]}}}
|
|
78
79
|
end
|
|
79
80
|
end
|
|
80
81
|
end
|