aspera-cli 4.13.0 → 4.15.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 (99) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +81 -7
  4. data/CONTRIBUTING.md +22 -6
  5. data/README.md +2038 -1080
  6. data/bin/ascli +18 -9
  7. data/bin/asession +12 -14
  8. data/examples/dascli +1 -1
  9. data/examples/proxy.pac +1 -1
  10. data/examples/rubyc +24 -0
  11. data/lib/aspera/aoc.rb +219 -159
  12. data/lib/aspera/ascmd.rb +25 -14
  13. data/lib/aspera/cli/basic_auth_plugin.rb +12 -9
  14. data/lib/aspera/cli/error.rb +17 -0
  15. data/lib/aspera/cli/extended_value.rb +47 -12
  16. data/lib/aspera/cli/formatter.rb +260 -179
  17. data/lib/aspera/cli/hints.rb +80 -0
  18. data/lib/aspera/cli/main.rb +104 -156
  19. data/lib/aspera/cli/manager.rb +259 -209
  20. data/lib/aspera/cli/plugin.rb +123 -63
  21. data/lib/aspera/cli/plugins/alee.rb +2 -3
  22. data/lib/aspera/cli/plugins/aoc.rb +341 -261
  23. data/lib/aspera/cli/plugins/ats.rb +22 -21
  24. data/lib/aspera/cli/plugins/bss.rb +5 -5
  25. data/lib/aspera/cli/plugins/config.rb +578 -627
  26. data/lib/aspera/cli/plugins/console.rb +44 -6
  27. data/lib/aspera/cli/plugins/cos.rb +15 -17
  28. data/lib/aspera/cli/plugins/faspex.rb +114 -100
  29. data/lib/aspera/cli/plugins/faspex5.rb +411 -264
  30. data/lib/aspera/cli/plugins/node.rb +354 -259
  31. data/lib/aspera/cli/plugins/orchestrator.rb +61 -29
  32. data/lib/aspera/cli/plugins/preview.rb +82 -90
  33. data/lib/aspera/cli/plugins/server.rb +79 -32
  34. data/lib/aspera/cli/plugins/shares.rb +55 -42
  35. data/lib/aspera/cli/sync_actions.rb +68 -0
  36. data/lib/aspera/cli/transfer_agent.rb +66 -73
  37. data/lib/aspera/cli/transfer_progress.rb +74 -0
  38. data/lib/aspera/cli/version.rb +1 -1
  39. data/lib/aspera/colors.rb +12 -8
  40. data/lib/aspera/command_line_builder.rb +14 -11
  41. data/lib/aspera/cos_node.rb +3 -2
  42. data/lib/aspera/data/6 +0 -0
  43. data/lib/aspera/environment.rb +24 -9
  44. data/lib/aspera/fasp/agent_aspera.rb +126 -0
  45. data/lib/aspera/fasp/agent_base.rb +31 -77
  46. data/lib/aspera/fasp/agent_connect.rb +25 -21
  47. data/lib/aspera/fasp/agent_direct.rb +89 -103
  48. data/lib/aspera/fasp/agent_httpgw.rb +231 -149
  49. data/lib/aspera/fasp/agent_node.rb +41 -34
  50. data/lib/aspera/fasp/agent_trsdk.rb +75 -32
  51. data/lib/aspera/fasp/error_info.rb +4 -2
  52. data/lib/aspera/fasp/faux_file.rb +52 -0
  53. data/lib/aspera/fasp/installation.rb +53 -195
  54. data/lib/aspera/fasp/management.rb +244 -0
  55. data/lib/aspera/fasp/parameters.rb +71 -37
  56. data/lib/aspera/fasp/parameters.yaml +76 -8
  57. data/lib/aspera/fasp/products.rb +162 -0
  58. data/lib/aspera/fasp/resume_policy.rb +3 -3
  59. data/lib/aspera/fasp/transfer_spec.rb +7 -6
  60. data/lib/aspera/fasp/uri.rb +26 -24
  61. data/lib/aspera/faspex_gw.rb +2 -2
  62. data/lib/aspera/faspex_postproc.rb +2 -2
  63. data/lib/aspera/hash_ext.rb +14 -4
  64. data/lib/aspera/json_rpc.rb +49 -0
  65. data/lib/aspera/keychain/macos_security.rb +13 -13
  66. data/lib/aspera/line_logger.rb +23 -0
  67. data/lib/aspera/log.rb +58 -16
  68. data/lib/aspera/node.rb +157 -92
  69. data/lib/aspera/oauth.rb +37 -19
  70. data/lib/aspera/open_application.rb +4 -4
  71. data/lib/aspera/persistency_action_once.rb +1 -1
  72. data/lib/aspera/persistency_folder.rb +2 -2
  73. data/lib/aspera/preview/file_types.rb +4 -2
  74. data/lib/aspera/preview/generator.rb +22 -35
  75. data/lib/aspera/preview/options.rb +2 -0
  76. data/lib/aspera/preview/terminal.rb +73 -16
  77. data/lib/aspera/preview/utils.rb +21 -28
  78. data/lib/aspera/proxy_auto_config.js +2 -2
  79. data/lib/aspera/rest.rb +136 -68
  80. data/lib/aspera/rest_call_error.rb +1 -1
  81. data/lib/aspera/rest_error_analyzer.rb +15 -14
  82. data/lib/aspera/rest_errors_aspera.rb +37 -34
  83. data/lib/aspera/secret_hider.rb +18 -15
  84. data/lib/aspera/ssh.rb +5 -2
  85. data/lib/aspera/sync.rb +127 -119
  86. data/lib/aspera/temp_file_manager.rb +10 -3
  87. data/lib/aspera/web_auth.rb +10 -7
  88. data/lib/aspera/web_server_simple.rb +9 -4
  89. data.tar.gz.sig +0 -0
  90. metadata +34 -17
  91. metadata.gz.sig +0 -0
  92. data/docs/test_env.conf +0 -186
  93. data/lib/aspera/cli/listener/line_dump.rb +0 -19
  94. data/lib/aspera/cli/listener/logger.rb +0 -22
  95. data/lib/aspera/cli/listener/progress.rb +0 -50
  96. data/lib/aspera/cli/listener/progress_multi.rb +0 -84
  97. data/lib/aspera/cli/plugins/sync.rb +0 -44
  98. data/lib/aspera/data/7 +0 -0
  99. data/lib/aspera/fasp/listener.rb +0 -13
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # cspell:ignore ascmd zmode zuid zgid fasping
3
4
  require 'aspera/cli/basic_auth_plugin'
4
- require 'aspera/cli/plugins/sync'
5
- require 'aspera/ascmd'
5
+ require 'aspera/cli/sync_actions'
6
6
  require 'aspera/fasp/transfer_spec'
7
+ require 'aspera/ascmd'
7
8
  require 'aspera/ssh'
8
9
  require 'aspera/nagios'
9
10
  require 'tempfile'
@@ -13,19 +14,12 @@ module Aspera
13
14
  module Cli
14
15
  module Plugins
15
16
  # implement basic remote access with FASP/SSH
16
- class SyncSpecServer
17
- def initialize(transfer_spec)
18
- @transfer_spec = transfer_spec
19
- end
20
-
21
- def transfer_spec(direction, local_path, remote_path)
22
- return @transfer_spec
23
- end
24
- end
25
-
26
17
  class Server < Aspera::Cli::BasicAuthPlugin
18
+ include SyncActions
27
19
  SSH_SCHEME = 'ssh'
28
- URI_SCHEMES = %w[https local].push(SSH_SCHEME).freeze
20
+ LOCAL_SCHEME = 'local'
21
+ HTTPS_SCHEME = 'https'
22
+ URI_SCHEMES = [SSH_SCHEME, LOCAL_SCHEME, HTTPS_SCHEME].freeze
29
23
  ASCMD_ALIASES = {
30
24
  browse: :ls,
31
25
  delete: :rm,
@@ -41,36 +35,88 @@ module Aspera
41
35
  cmd = cmd.map{|v|%Q("#{v}")}.join(' ') if cmd.is_a?(Array)
42
36
  Log.log.debug{"Executing: #{cmd} with '#{line}'"}
43
37
  stdout_str, stderr_str, status = Open3.capture3(cmd, stdin_data: line, binmode: true)
44
- Log.log.debug(">> #{status} -> #{stderr_str}")
38
+ Log.log.debug{"exec status: #{status} -> #{stderr_str}"}
45
39
  raise "command #{cmd} failed with code #{status.exitstatus} #{stderr_str}" unless status.success?
46
40
  return stdout_str
47
41
  end
48
42
  end
49
43
 
44
+ class << self
45
+ def application_name
46
+ 'HSTS Fasp/SSH'
47
+ end
48
+
49
+ def detect(address_or_url)
50
+ urls = if address_or_url.match?(%r{^[a-z]{1,6}://})
51
+ [address_or_url]
52
+ else
53
+ [
54
+ "ssh://#{address_or_url}:33001",
55
+ "ssh://#{address_or_url}:22"
56
+ ]
57
+ # wss not practical as it requires a token
58
+ end
59
+
60
+ urls.each do |base_url|
61
+ server_uri = URI.parse(base_url)
62
+ Log.log.debug{"URI=#{server_uri}, host=#{server_uri.hostname}, port=#{server_uri.port}, scheme=#{server_uri.scheme}"}
63
+ next unless server_uri.scheme.eql?(SSH_SCHEME)
64
+ begin
65
+ socket = TCPSocket.new(server_uri.hostname, server_uri.port)
66
+ socket.puts('SSH-2.0-Ascli_0.0')
67
+ version = socket.gets.chomp
68
+ if version.match?(/^SSH-2.0-/)
69
+ return {version: version.gsub(/^SSH-2.0-/, ''), url: base_url}
70
+ end
71
+ rescue StandardError => e
72
+ Log.log.debug{"detect error: #{e}"}
73
+ end
74
+ end
75
+ return nil
76
+ end
77
+
78
+ def wizard(object:, private_key_path: nil, pub_key_pem: nil)
79
+ options = object.options
80
+ return {
81
+ preset_value: {
82
+ url: options.get_option(:url, mandatory: true),
83
+ username: options.get_option(:username, mandatory: true),
84
+ password: options.get_option(:password, mandatory: true)
85
+ },
86
+ test_args: 'files br /'
87
+ }
88
+ end
89
+ end
90
+
50
91
  def initialize(env)
51
92
  super(env)
52
- options.add_opt_simple(:ssh_keys, 'SSH key path list (Array or single)')
53
- options.add_opt_simple(:ssh_options, 'SSH options (Hash)')
93
+ options.declare(:ssh_keys, 'SSH key path list (Array or single)')
94
+ options.declare(:passphrase, 'SSH private key passphrase')
95
+ options.declare(:ssh_options, 'SSH options', types: Hash, default: {})
96
+ SyncActions.declare_options(options)
54
97
  options.parse_options!
55
- @ssh_opts = nil
98
+ @ssh_opts = options.get_option(:ssh_options).symbolize_keys
56
99
  end
57
100
 
58
101
  # Read command line options
59
102
  # @return [Hash] transfer specification
60
103
  def options_to_base_transfer_spec
61
- url = options.get_option(:url, is_type: :mandatory)
104
+ url = options.get_option(:url, mandatory: true)
62
105
  server_transfer_spec = {}
63
106
  server_uri = URI.parse(url)
64
- Log.log.debug{"URI : #{server_uri}, port=#{server_uri.port}, scheme:#{server_uri.scheme}"}
107
+ Log.log.debug{"URI=#{server_uri}, host=#{server_uri.hostname}, port=#{server_uri.port}, scheme=#{server_uri.scheme}"}
65
108
  server_transfer_spec['remote_host'] = server_uri.hostname
66
109
  unless URI_SCHEMES.include?(server_uri.scheme)
67
110
  Log.log.warn{"Scheme [#{server_uri.scheme}] not supported in #{url}, use one of: #{URI_SCHEMES.join(', ')}. Defaulting to #{SSH_SCHEME}."}
68
111
  server_uri.scheme = SSH_SCHEME
69
112
  end
70
- if server_uri.scheme.eql?('local')
113
+ if server_uri.scheme.eql?(LOCAL_SCHEME)
71
114
  # Using local execution (mostly for testing)
115
+ server_transfer_spec['remote_host'] = 'localhost'
116
+ # simulate SSH environment, else ascp will fail
117
+ ENV['SSH_CLIENT'] = 'local 0 0'
72
118
  return server_transfer_spec
73
- elsif transfer.option_transfer_spec['token'].is_a?(String) && server_uri.scheme.eql?('https')
119
+ elsif transfer.option_transfer_spec['token'].is_a?(String) && server_uri.scheme.eql?(HTTPS_SCHEME)
74
120
  server_transfer_spec['wss_enabled'] = true
75
121
  server_transfer_spec['wss_port'] = server_uri.port
76
122
  # Using WSS
@@ -88,11 +134,7 @@ module Aspera
88
134
  options.set_option(:username, Aspera::Fasp::TransferSpec::ACCESS_KEY_TRANSFER_USER)
89
135
  Log.log.info{"No username provided: Assuming default transfer user: #{Aspera::Fasp::TransferSpec::ACCESS_KEY_TRANSFER_USER}"}
90
136
  end
91
- server_transfer_spec['remote_user'] = options.get_option(:username, is_type: :mandatory)
92
- ssh_args = options.get_option(:ssh_options)
93
- ssh_args = {} if ssh_args.nil?
94
- raise 'expecting a Hash for ssh_options' unless ssh_args.is_a?(Hash)
95
- @ssh_opts = ssh_args.symbolize_keys
137
+ server_transfer_spec['remote_user'] = options.get_option(:username, mandatory: true)
96
138
  if !server_uri.port.nil?
97
139
  @ssh_opts[:port] = server_uri.port
98
140
  server_transfer_spec['ssh_port'] = server_uri.port
@@ -119,6 +161,11 @@ module Aspera
119
161
  cred_set = true
120
162
  end
121
163
  end
164
+ ssh_passphrase = options.get_option(:passphrase)
165
+ if !ssh_passphrase.nil?
166
+ @ssh_opts[:passphrase] = ssh_passphrase
167
+ server_transfer_spec['ssh_private_key_passphrase'] = ssh_passphrase
168
+ end
122
169
  # if user provided transfer spec has a token, we will use bypass keys
123
170
  cred_set = true if transfer.option_transfer_spec['token'].is_a?(String)
124
171
  raise 'Either password, key , or transfer spec token must be provided' if !cred_set
@@ -131,8 +178,8 @@ module Aspera
131
178
  Fasp::TransferSpec.action_to_direction(transfer_spec, command)
132
179
  return Main.result_transfer(transfer.start(transfer_spec))
133
180
  when :sync
134
- sync_plugin = Plugins::Sync.new(@agents, sync_spec: SyncSpecServer.new(transfer_spec))
135
- return sync_plugin.execute_action
181
+ # lets ignore the arguments provided by execute_sync_action, we just give the transfer spec
182
+ return execute_sync_action {transfer_spec}
136
183
  end
137
184
  end
138
185
 
@@ -143,7 +190,7 @@ module Aspera
143
190
 
144
191
  def execute_action
145
192
  server_transfer_spec = options_to_base_transfer_spec
146
- ascmd_executor = if !@ssh_opts.nil?
193
+ ascmd_executor = if !@ssh_opts.empty?
147
194
  Ssh.new(server_transfer_spec['remote_host'], server_transfer_spec['remote_user'], @ssh_opts)
148
195
  elsif server_transfer_spec.key?('wss_enabled')
149
196
  nil
@@ -184,10 +231,10 @@ module Aspera
184
231
  when *TRANSFER_COMMANDS
185
232
  return execute_transfer(command, server_transfer_spec)
186
233
  when *Aspera::AsCmd::OPERATIONS
187
- args = options.get_next_argument('ascmd command arguments', expected: :multiple, mandatory: false)
234
+ command_arguments = options.get_next_argument('ascmd command arguments', expected: :multiple, mandatory: false)
188
235
  ascmd = Aspera::AsCmd.new(ascmd_executor)
189
236
  begin
190
- result = ascmd.send(:execute_single, command, args)
237
+ result = ascmd.send(:execute_single, command, command_arguments)
191
238
  case command
192
239
  when :mkdir, :mv, :cp, :rm
193
240
  return Main.result_success
@@ -199,7 +246,7 @@ module Aspera
199
246
  return {type: :single_object, data: result.stringify_keys}
200
247
  end
201
248
  rescue Aspera::AsCmd::Error => e
202
- raise CliBadArgument, e.extended_message
249
+ raise Cli::BadArgument, e.extended_message
203
250
  end
204
251
  else raise 'internal error: unexpected action'
205
252
  end
@@ -7,43 +7,67 @@ module Aspera
7
7
  module Plugins
8
8
  # Plugin for Aspera Shares v1
9
9
  class Shares < Aspera::Cli::BasicAuthPlugin
10
+ API_BASE = 'node_api'
10
11
  class << self
11
- def detect(base_url)
12
- api = Rest.new({base_url: base_url})
13
- # Shares
12
+ def detect(address_or_url)
13
+ address_or_url = "https://#{address_or_url}" unless address_or_url.match?(%r{^[a-z]{1,6}://})
14
+ api = Rest.new(base_url: address_or_url, redirect_max: 1)
15
+ found = false
14
16
  begin
15
17
  # shall fail: shares requires auth, but we check error message
16
18
  # TODO: use ping instead ?
17
- api.read('node_api/app')
19
+ api.read("#{API_BASE}/app")
18
20
  rescue RestCallError => e
19
21
  if e.response.code.to_s.eql?('401') && e.response.body.eql?('{"error":{"user_message":"API user authentication failed"}}')
20
- return {version: 'unknown'}
22
+ found = true
21
23
  end
22
24
  end
23
- nil
25
+ return nil unless found
26
+ version = 'unknown'
27
+ test_page = api.call({ operation: 'GET', subpath: 'login' })
28
+ if (m = test_page[:http].body.match(/\(v(1\..*)\)/))
29
+ version = m[1]
30
+ end
31
+ return {
32
+ version: version,
33
+ url: address_or_url
34
+ }
35
+ end
36
+
37
+ def wizard(object:, private_key_path: nil, pub_key_pem: nil)
38
+ options = object.options
39
+ return {
40
+ preset_value: {
41
+ url: options.get_option(:url, mandatory: true),
42
+ username: options.get_option(:username, mandatory: true),
43
+ password: options.get_option(:password, mandatory: true)
44
+ },
45
+ test_args: 'files br /'
46
+ }
24
47
  end
25
48
  end
26
49
 
27
50
  def initialize(env)
28
51
  super(env)
29
- options.add_opt_list(:type, %i[any local ldap saml], 'Type of user/group for operations')
30
- options.set_option(:type, :any)
52
+ options.declare(:type, 'Type of user/group for operations', values: %i[any local ldap saml], default: :any)
31
53
  options.parse_options!
32
54
  end
33
55
 
34
56
  SAML_IMPORT_MANDATORY = %w[id name_id].freeze
35
57
  SAML_IMPORT_ALLOWED = %w[email given_name surname].concat(SAML_IMPORT_MANDATORY).freeze
36
58
 
37
- ACTIONS = %i[health repository admin].freeze
59
+ ACTIONS = %i[health files admin].freeze
60
+ # common to users and groups
61
+ USR_GRP_SETTINGS = %i[transfer_settings app_authorizations share_permissions].freeze
38
62
 
39
63
  def execute_action
40
- command = options.get_next_command(ACTIONS)
64
+ command = options.get_next_command(ACTIONS, aliases: {repository: :files})
41
65
  case command
42
66
  when :health
43
67
  nagios = Nagios.new
44
68
  begin
45
69
  Rest
46
- .new(base_url: options.get_option(:url, is_type: :mandatory) + '/node_api')
70
+ .new(base_url: "#{options.get_option(:url, mandatory: true)}/#{API_BASE}")
47
71
  .call(
48
72
  operation: 'GET',
49
73
  subpath: 'ping',
@@ -54,25 +78,28 @@ module Aspera
54
78
  nagios.add_critical('node api', e.to_s)
55
79
  end
56
80
  return nagios.result
57
- when :repository
58
- api_shares_node = basic_auth_api('node_api')
81
+ when :repository, :files
82
+ api_shares_node = basic_auth_api(API_BASE)
59
83
  repo_command = options.get_next_command(Node::COMMANDS_SHARES)
60
- return Node.new(@agents.merge(skip_basic_auth_options: true, node_api: api_shares_node)).execute_action(repo_command)
84
+ return Node.new(@agents, api: api_shares_node).execute_action(repo_command)
61
85
  when :admin
62
86
  api_shares_admin = basic_auth_api('api/v1')
63
- admin_command = options.get_next_command(%i[user group share node])
87
+ admin_command = options.get_next_command(%i[user group share node].freeze)
64
88
  case admin_command
65
89
  when :node
66
90
  return entity_action(api_shares_admin, 'data/nodes')
67
91
  when :user, :group
68
92
  entity_type = admin_command
69
- entities_location = options.get_option(:type, is_type: :mandatory)
93
+ entities_location = options.get_option(:type, mandatory: true)
70
94
  entities_path = "data/#{entities_location}_#{entity_type}s"
71
95
  entity_action = nil
72
96
  case entities_location
73
97
  when :any
74
98
  entities_path = "data/#{entity_type}s"
75
- entity_action = %i[list show delete share_permissions app_authorizations].freeze
99
+ entity_action = %i[list show delete]
100
+ entity_action.concat(USR_GRP_SETTINGS)
101
+ entity_action.push(:users) if entity_type.eql?(:group)
102
+ entity_action.freeze
76
103
  when :local
77
104
  entity_action = %i[list show create modify delete].freeze
78
105
  when :ldap
@@ -80,31 +107,15 @@ module Aspera
80
107
  when :saml
81
108
  entity_action = %i[import].freeze
82
109
  end
83
- entity_command = options.get_next_command(entity_action)
84
- entity_path = "#{entities_path}/#{instance_identifier}" if %i[app_authorizations share_permissions].include?(entity_command)
85
- case entity_command
86
- when :list, :show, :create, :delete, :modify
110
+ entity_verb = options.get_next_command(entity_action)
111
+ # entity_path = "#{entities_path}/#{instance_identifier}" if %i[app_authorizations share_permissions].include?(entity_verb)
112
+ case entity_verb
113
+ when *Plugin::ALL_OPS
87
114
  display_fields = entity_type.eql?(:user) ? %w[id username first_name last_name email] : nil
88
115
  display_fields.push(:directory_user) if entity_type.eql?(:user) && entities_location.eql?(:any)
89
- return entity_command(entity_command, api_shares_admin, entities_path, display_fields: display_fields)
90
- when :app_authorizations
91
- case options.get_next_command(%i[modify show])
92
- when :show
93
- return {type: :single_object, data: api_shares_admin.read("#{entity_path}/app_authorizations")[:data]}
94
- when :modify
95
- parameters = options.get_option(:value, is_type: :mandatory)
96
- return {type: :single_object, data: api_shares_admin.update("#{entity_path}/app_authorizations", parameters)[:data]}
97
- end
98
- when :share_permissions
99
- case options.get_next_command(%i[list show])
100
- when :list
101
- return {type: :object_list, data: api_shares_admin.read("#{entity_path}/share_permissions")[:data]}
102
- when :show
103
- return {type: :single_object, data: api_shares_admin.read("#{entity_path}/share_permissions/#{instance_identifier}")[:data]}
104
- end
116
+ return entity_command(entity_verb, api_shares_admin, entities_path, display_fields: display_fields)
105
117
  when :import
106
- parameters = options.get_option(:value, is_type: :mandatory)
107
- return do_bulk_operation(parameters, 'created') do |entity_parameters|
118
+ return do_bulk_operation(command: entity_verb, descr: 'user information') do |entity_parameters|
108
119
  entity_parameters = entity_parameters.transform_keys{|k|k.gsub(/\s+/, '_').downcase}
109
120
  raise 'expecting Hash' unless entity_parameters.is_a?(Hash)
110
121
  SAML_IMPORT_MANDATORY.each{|p|raise "missing mandatory field: #{p}" if entity_parameters[p].nil?}
@@ -114,11 +125,13 @@ module Aspera
114
125
  api_shares_admin.create("#{entities_path}/import", entity_parameters)[:data]
115
126
  end
116
127
  when :add
117
- parameters = options.get_option(:value)
118
- return do_bulk_operation(parameters, 'created') do |entity_name|
119
- raise "expecting string (name), have #{entity_name.class}" unless entity_name.is_a?(String)
128
+ return do_bulk_operation(command: entity_verb, descr: "#{entity_type} name", values: String) do |entity_name|
120
129
  api_shares_admin.create(entities_path, {entity_type=>entity_name})[:data]
121
130
  end
131
+ when *USR_GRP_SETTINGS
132
+ group_id = instance_identifier
133
+ entities_path = "#{entities_path}/#{group_id}/#{entity_verb}"
134
+ return entity_action(api_shares_admin, entities_path, is_singleton: !entity_verb.eql?(:share_permissions))
122
135
  end
123
136
  when :share
124
137
  share_command = options.get_next_command(%i[user_permissions group_permissions].concat(Plugin::ALL_OPS))
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aspera/sync'
4
+
5
+ module Aspera
6
+ module Cli
7
+ # Module for sync actions
8
+ module SyncActions
9
+ SIMPLE_ARGUMENTS_SYNC = {
10
+ direction: Aspera::Sync::DIRECTIONS,
11
+ local_dir: String,
12
+ remote_dir: String
13
+ }.stringify_keys.freeze
14
+
15
+ class << self
16
+ def declare_options(options)
17
+ options.declare(:sync_info, 'Information for sync instance and sessions', types: Hash)
18
+ end
19
+ end
20
+
21
+ def execute_sync_action(&block)
22
+ # options = Aspera::Cli::Manager.new
23
+ raise 'Internal Error: No block given' unless block
24
+ command = options.get_next_command(%i[start admin])
25
+ # try to get 3 arguments as simple arguments
26
+ case command
27
+ when :start
28
+ simple_session_args = {}
29
+ SIMPLE_ARGUMENTS_SYNC.each do |arg, check|
30
+ value = options.get_next_argument(
31
+ arg,
32
+ type: check.is_a?(Class) ? check : nil,
33
+ expected: check.is_a?(Class) ? :single : check,
34
+ mandatory: false)
35
+ break if value.nil?
36
+ simple_session_args[arg] = value.to_s
37
+ end
38
+ async_params = nil
39
+ if simple_session_args.empty?
40
+ async_params = options.get_option(:sync_info, mandatory: true)
41
+ else
42
+ raise Cli::BadArgument,
43
+ "Provide zero or 3 arguments: #{SIMPLE_ARGUMENTS_SYNC.keys.join(',')}" unless simple_session_args.keys.sort == SIMPLE_ARGUMENTS_SYNC.keys.sort
44
+ async_params = options.get_option(
45
+ :sync_info,
46
+ mandatory: false,
47
+ default: {'sessions' => [{'name' => File.basename(simple_session_args['local_dir'])}]})
48
+ raise "sync_info shall be a Hash with key 'sessions' with Array of Hash: #{async_params}" unless async_params.is_a?(Hash) &&
49
+ async_params['sessions']&.is_a?(Array) &&
50
+ async_params['sessions'].first.is_a?(Hash)
51
+ async_params['sessions'].first.merge!(simple_session_args)
52
+ end
53
+ Log.log.debug{Log.dump('async_params', async_params)}
54
+ Aspera::Sync.start(async_params, &block)
55
+ return Main.result_success
56
+ when :admin
57
+ command2 = options.get_next_command([:status])
58
+ case command2
59
+ when :status
60
+ sync_session_name = options.get_next_argument('name of sync session', mandatory: false, type: String)
61
+ async_params = options.get_option(:sync_info, mandatory: true)
62
+ return {type: :single_object, data: Aspera::Sync.admin_status(async_params, sync_session_name)}
63
+ end # command2
64
+ end # command
65
+ end # execute_action
66
+ end # SyncActions
67
+ end # Cli
68
+ end # Aspera