aspera-cli 4.3.0 → 4.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +445 -194
- data/docs/README.erb.md +449 -239
- data/docs/doc_tools.rb +58 -0
- data/lib/aspera/aoc.rb +4 -3
- data/lib/aspera/cli/plugin.rb +13 -6
- data/lib/aspera/cli/plugins/aoc.rb +87 -51
- data/lib/aspera/cli/plugins/config.rb +79 -50
- data/lib/aspera/cli/plugins/faspex.rb +8 -6
- data/lib/aspera/cli/plugins/node.rb +51 -23
- data/lib/aspera/cli/plugins/preview.rb +9 -7
- data/lib/aspera/cli/plugins/server.rb +16 -5
- data/lib/aspera/cli/transfer_agent.rb +5 -20
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/fasp/http_gw.rb +47 -26
- data/lib/aspera/fasp/local.rb +0 -2
- data/lib/aspera/fasp/parameters.rb +16 -3
- data/lib/aspera/faspex_gw.rb +10 -9
- data/lib/aspera/node.rb +10 -0
- metadata +3 -3
- data/lib/aspera/fasp/aoc.rb +0 -24
@@ -45,6 +45,7 @@ module Aspera
|
|
45
45
|
AOC_COMMAND_V2='aspera'
|
46
46
|
AOC_COMMAND_V3='aoc'
|
47
47
|
AOC_COMMAND_CURRENT=AOC_COMMAND_V3
|
48
|
+
SERVER_COMMAND='server'
|
48
49
|
CONNECT_WEB_URL = 'https://d3gcli72yxqn2z.cloudfront.net/connect'
|
49
50
|
CONNECT_VERSIONS = 'connectversions.js'
|
50
51
|
TRANSFER_SDK_ARCHIVE_URL = 'https://ibm.biz/aspera_sdk'
|
@@ -58,14 +59,31 @@ Subject: Amelia email test
|
|
58
59
|
|
59
60
|
It worked !
|
60
61
|
END_OF_TEMPLATE
|
62
|
+
# special extended values
|
63
|
+
EXTV_INCLUDE_PRESETS='incps'
|
64
|
+
EXTV_PRESET='preset'
|
65
|
+
DEFAULT_CHECK_NEW_VERSION_DAYS=7
|
66
|
+
DEFAULT_PRIV_KEY_FILENAME='aspera_aoc_key'
|
67
|
+
DEFAULT_PRIVKEY_LENGTH=4096
|
68
|
+
private_constant :DEFAULT_CONFIG_FILENAME,:CONF_PRESET_CONFIG,:CONF_PRESET_VERSION,:CONF_PRESET_DEFAULT,
|
69
|
+
:CONF_PRESET_GLOBAL,:PROGRAM_NAME_V1,:PROGRAM_NAME_V2,:DEFAULT_REDIRECT,:ASPERA_PLUGINS_FOLDERNAME,
|
70
|
+
:RUBY_FILE_EXT,:AOC_COMMAND_V1,:AOC_COMMAND_V2,:AOC_COMMAND_V3,:AOC_COMMAND_CURRENT,:DEMO,
|
71
|
+
:TRANSFER_SDK_ARCHIVE_URL,:AOC_PATH_API_CLIENTS,:DEMO_SERVER_PRESET,:EMAIL_TEST_TEMPLATE,:EXTV_INCLUDE_PRESETS,
|
72
|
+
:EXTV_PRESET,:DEFAULT_CHECK_NEW_VERSION_DAYS,:DEFAULT_PRIV_KEY_FILENAME,:SERVER_COMMAND
|
61
73
|
def option_preset; nil; end
|
62
74
|
|
63
75
|
def option_preset=(value)
|
64
|
-
|
76
|
+
case value
|
77
|
+
when String
|
78
|
+
self.options.add_option_preset(preset_by_name(value))
|
79
|
+
when Hash
|
80
|
+
self.options.add_option_preset(value)
|
81
|
+
else
|
82
|
+
raise "Preset definition must be a String for name, or Hash for value"
|
83
|
+
end
|
84
|
+
nil
|
65
85
|
end
|
66
86
|
|
67
|
-
private_constant :DEFAULT_CONFIG_FILENAME,:CONF_PRESET_CONFIG,:CONF_PRESET_VERSION,:CONF_PRESET_DEFAULT,:CONF_PRESET_GLOBAL,:PROGRAM_NAME_V1,:PROGRAM_NAME_V2,:DEFAULT_REDIRECT,:ASPERA_PLUGINS_FOLDERNAME,:RUBY_FILE_EXT,:AOC_COMMAND_V1,:AOC_COMMAND_V2,:AOC_COMMAND_V3,:AOC_COMMAND_CURRENT,:DEMO,:TRANSFER_SDK_ARCHIVE_URL,:AOC_PATH_API_CLIENTS,:DEMO_SERVER_PRESET,:EMAIL_TEST_TEMPLATE
|
68
|
-
|
69
87
|
def initialize(env,tool_name,help_url,version,main_folder)
|
70
88
|
super(env)
|
71
89
|
raise 'missing secret manager' if @agents[:secret].nil?
|
@@ -93,35 +111,36 @@ END_OF_TEMPLATE
|
|
93
111
|
# add preset handler (needed for smtp)
|
94
112
|
ExtendedValue.instance.set_handler(EXTV_PRESET,:reader,lambda{|v|preset_by_name(v)})
|
95
113
|
ExtendedValue.instance.set_handler(EXTV_INCLUDE_PRESETS,:decoder,lambda{|v|expanded_with_preset_includes(v)})
|
96
|
-
self.options.set_obj_attr(:override,self,:option_override,:no)
|
97
114
|
self.options.set_obj_attr(:ascp_path,self,:option_ascp_path)
|
98
115
|
self.options.set_obj_attr(:use_product,self,:option_use_product)
|
99
116
|
self.options.set_obj_attr(:preset,self,:option_preset)
|
100
117
|
self.options.set_obj_attr(:secret,@agents[:secret],:default_secret)
|
101
118
|
self.options.set_obj_attr(:secrets,@agents[:secret],:all_secrets)
|
102
|
-
self.options.add_opt_boolean(:override,'override existing value')
|
103
119
|
self.options.add_opt_switch(:no_default,'-N','do not load default configuration for plugin') { @use_plugin_defaults=false }
|
104
|
-
self.options.add_opt_boolean(:
|
105
|
-
self.options.
|
120
|
+
self.options.add_opt_boolean(:override,'Wizard: override existing value')
|
121
|
+
self.options.add_opt_boolean(:use_generic_client,'Wizard: AoC: use global or org specific jwt client id')
|
122
|
+
self.options.add_opt_boolean(:default,'Wizard: set as default configuration for specified plugin (also: update)')
|
123
|
+
self.options.add_opt_boolean(:test_mode,'Wizard: skip private key check step')
|
124
|
+
self.options.add_opt_simple(:pkeypath,'Wizard: path to private key for JWT')
|
106
125
|
self.options.add_opt_simple(:ascp_path,'path to ascp')
|
107
126
|
self.options.add_opt_simple(:use_product,'use ascp from specified product')
|
108
127
|
self.options.add_opt_simple(:smtp,'smtp configuration (extended value: hash)')
|
109
128
|
self.options.add_opt_simple(:fpac,'proxy auto configuration URL')
|
110
129
|
self.options.add_opt_simple(:preset,'-PVALUE','load the named option preset from current config file')
|
111
|
-
self.options.add_opt_simple(:default,'set as default configuration for specified plugin')
|
112
130
|
self.options.add_opt_simple(:secret,'default secret')
|
113
131
|
self.options.add_opt_simple(:secrets,'secret repository (Hash)')
|
114
132
|
self.options.add_opt_simple(:sdk_url,'URL to get SDK')
|
115
|
-
self.options.add_opt_simple(:sdk_folder,'SDK folder
|
133
|
+
self.options.add_opt_simple(:sdk_folder,'SDK folder path')
|
116
134
|
self.options.add_opt_simple(:notif_to,'email recipient for notification of transfers')
|
117
135
|
self.options.add_opt_simple(:notif_template,'email ERB template for notification of transfers')
|
118
|
-
self.options.
|
119
|
-
self.options.add_opt_simple(:version_check_days,Integer,'period to check neew version in days (zero to disable)')
|
136
|
+
self.options.add_opt_simple(:version_check_days,Integer,'period in days to check new version (zero to disable)')
|
120
137
|
self.options.set_option(:use_generic_client,true)
|
121
138
|
self.options.set_option(:test_mode,false)
|
122
|
-
self.options.set_option(:
|
139
|
+
self.options.set_option(:default,true)
|
140
|
+
self.options.set_option(:version_check_days,DEFAULT_CHECK_NEW_VERSION_DAYS)
|
123
141
|
self.options.set_option(:sdk_url,TRANSFER_SDK_ARCHIVE_URL)
|
124
142
|
self.options.set_option(:sdk_folder,File.join(@main_folder,'sdk'))
|
143
|
+
self.options.set_option(:override,:no)
|
125
144
|
self.options.parse_options!
|
126
145
|
raise CliBadArgument,'secrets shall be Hash' unless @agents[:secret].all_secrets.is_a?(Hash)
|
127
146
|
Fasp::Installation.instance.folder=self.options.get_option(:sdk_folder,:mandatory)
|
@@ -198,9 +217,9 @@ END_OF_TEMPLATE
|
|
198
217
|
end
|
199
218
|
private
|
200
219
|
|
201
|
-
def
|
220
|
+
def generate_rsa_private_key(private_key_path,length)
|
202
221
|
require 'openssl'
|
203
|
-
priv_key = OpenSSL::PKey::RSA.new(
|
222
|
+
priv_key = OpenSSL::PKey::RSA.new(length)
|
204
223
|
File.write(private_key_path,priv_key.to_s)
|
205
224
|
File.write(private_key_path+'.pub',priv_key.public_key.to_s)
|
206
225
|
nil
|
@@ -253,12 +272,8 @@ END_OF_TEMPLATE
|
|
253
272
|
attr_reader :main_folder
|
254
273
|
attr_reader :gem_url
|
255
274
|
attr_reader :plugins
|
256
|
-
attr_accessor :option_override
|
257
275
|
attr_accessor :option_config_file
|
258
276
|
|
259
|
-
EXTV_INCLUDE_PRESETS='incps'
|
260
|
-
EXTV_PRESET='preset'
|
261
|
-
|
262
277
|
# @return the hash from name (also expands possible includes)
|
263
278
|
def preset_by_name(config_name, include_path=[])
|
264
279
|
raise CliError,"no such config preset: #{config_name}" unless @config_presets.has_key?(config_name)
|
@@ -343,11 +358,11 @@ END_OF_TEMPLATE
|
|
343
358
|
Log.log.warn("No config file found. Creating empty configuration file: #{@option_config_file}")
|
344
359
|
@config_presets={CONF_PRESET_CONFIG=>{CONF_PRESET_VERSION=>@program_version}}
|
345
360
|
else
|
346
|
-
Log.log.debug
|
361
|
+
Log.log.debug("loading #{@option_config_file}")
|
347
362
|
@config_presets=YAML.load_file(conf_file_to_load)
|
348
363
|
end
|
349
364
|
files_to_copy=[]
|
350
|
-
Log.log.debug
|
365
|
+
Log.log.debug("Available_presets: #{@config_presets}")
|
351
366
|
raise 'Expecting YAML Hash' unless @config_presets.is_a?(Hash)
|
352
367
|
# check there is at least the config section
|
353
368
|
if !@config_presets.has_key?(CONF_PRESET_CONFIG)
|
@@ -589,7 +604,7 @@ END_OF_TEMPLATE
|
|
589
604
|
save_presets_to_config_file
|
590
605
|
return Main.result_status("Modified: #{@option_config_file}")
|
591
606
|
when :update
|
592
|
-
default_for_plugin=self.options.get_option(:default,:
|
607
|
+
default_for_plugin=self.options.get_option(:default,:mandatory)
|
593
608
|
# get unprocessed options
|
594
609
|
theopts=self.options.get_options_table
|
595
610
|
Log.log.debug("opts=#{theopts}")
|
@@ -621,7 +636,7 @@ END_OF_TEMPLATE
|
|
621
636
|
return Main.result_nothing
|
622
637
|
when :genkey # generate new rsa key
|
623
638
|
private_key_path=self.options.get_next_argument('private key file path')
|
624
|
-
|
639
|
+
generate_rsa_private_key(private_key_path,DEFAULT_PRIVKEY_LENGTH)
|
625
640
|
return Main.result_status('Generated key: '+private_key_path)
|
626
641
|
when :echo # display the content of a value given on command line
|
627
642
|
result={:type=>:other_struct, :data=>self.options.get_next_argument('value')}
|
@@ -638,23 +653,32 @@ END_OF_TEMPLATE
|
|
638
653
|
when :overview
|
639
654
|
return {:type=>:object_list,:data=>self.class.flatten_all_config(@config_presets)}
|
640
655
|
when :wizard
|
656
|
+
# interactive mode
|
641
657
|
self.options.ask_missing_mandatory=true
|
642
658
|
# register url option
|
643
659
|
BasicAuthPlugin.new(@agents.merge(skip_option_header: true))
|
660
|
+
# get from option, or ask
|
644
661
|
instance_url=self.options.get_option(:url,:mandatory)
|
662
|
+
# allow user to tell the preset name
|
663
|
+
preset_name=self.options.get_option(:id,:optional)
|
645
664
|
appli=ApiDetector.discover_product(instance_url)
|
665
|
+
plugin_name="<replace per app>"
|
666
|
+
test_args="<replace per app>"
|
646
667
|
case appli[:product]
|
647
668
|
when :aoc
|
648
669
|
self.format.display_status('Detected: Aspera on Cloud'.bold)
|
670
|
+
plugin_name=AOC_COMMAND_CURRENT
|
649
671
|
organization,instance_domain=AoC.parse_url(instance_url)
|
650
|
-
|
651
|
-
|
672
|
+
# if not defined by user, generate name
|
673
|
+
preset_name=[appli[:product],organization].join('_') if preset_name.nil?
|
674
|
+
self.format.display_status("Preparing preset: #{preset_name}")
|
652
675
|
# init defaults if necessary
|
653
|
-
@config_presets[CONF_PRESET_DEFAULT]||=
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
676
|
+
@config_presets[CONF_PRESET_DEFAULT]||={}
|
677
|
+
option_override=self.options.get_option(:override,:mandatory)
|
678
|
+
option_default=self.options.get_option(:default,:mandatory)
|
679
|
+
Log.log.error("override=#{option_override} -> #{option_override.class}")
|
680
|
+
raise CliError,"A default configuration already exists for plugin '#{plugin_name}' (use --override=yes or --default=no)" if !option_override and option_default and @config_presets[CONF_PRESET_DEFAULT].has_key?(plugin_name)
|
681
|
+
raise CliError,"Preset already exists: #{preset_name} (use --override=yes or --id=<name>)" if !option_override and @config_presets.has_key?(preset_name)
|
658
682
|
# lets see if path to priv key is provided
|
659
683
|
private_key_path=self.options.get_option(:pkeypath,:optional)
|
660
684
|
# give a chance to provide
|
@@ -664,23 +688,23 @@ END_OF_TEMPLATE
|
|
664
688
|
end
|
665
689
|
# else generate path
|
666
690
|
if private_key_path.empty?
|
667
|
-
private_key_path=File.join(@main_folder,
|
691
|
+
private_key_path=File.join(@main_folder,DEFAULT_PRIV_KEY_FILENAME)
|
668
692
|
end
|
669
693
|
if File.exist?(private_key_path)
|
670
694
|
self.format.display_status('Using existing key:')
|
671
695
|
else
|
672
|
-
self.format.display_status(
|
673
|
-
|
696
|
+
self.format.display_status("Generating #{DEFAULT_PRIVKEY_LENGTH} bit RSA key...")
|
697
|
+
generate_rsa_private_key(private_key_path,DEFAULT_PRIVKEY_LENGTH)
|
674
698
|
self.format.display_status('Created:')
|
675
699
|
end
|
676
|
-
self.format.display_status(
|
700
|
+
self.format.display_status(private_key_path)
|
677
701
|
pub_key_pem=OpenSSL::PKey::RSA.new(File.read(private_key_path)).public_key.to_s
|
678
702
|
# declare command line options for AoC
|
679
703
|
require 'aspera/cli/plugins/aoc'
|
680
704
|
# make username mandatory for jwt, this triggers interactive input
|
681
705
|
self.options.get_option(:username,:mandatory)
|
682
706
|
# instanciate AoC plugin, so that command line options are known
|
683
|
-
files_plugin=self.class.plugin_new(
|
707
|
+
files_plugin=self.class.plugin_new(plugin_name,@agents.merge({skip_basic_auth_options: true, private_key_path: private_key_path}))
|
684
708
|
aoc_api=files_plugin.get_api
|
685
709
|
auto_set_pub_key=false
|
686
710
|
auto_set_jwt=false
|
@@ -723,7 +747,7 @@ END_OF_TEMPLATE
|
|
723
747
|
end
|
724
748
|
myself=aoc_api.read('self')[:data]
|
725
749
|
if auto_set_pub_key
|
726
|
-
raise CliError,'
|
750
|
+
raise CliError,'Public key is already set in profile (use --override=yes)' unless myself['public_key'].empty? or option_override
|
727
751
|
self.format.display_status('Updating profile with new key')
|
728
752
|
aoc_api.update("users/#{myself['id']}",{'public_key'=>pub_key_pem})
|
729
753
|
end
|
@@ -731,8 +755,8 @@ END_OF_TEMPLATE
|
|
731
755
|
self.format.display_status('Enabling JWT for client')
|
732
756
|
aoc_api.update("clients/#{self.options.get_option(:client_id)}",{'jwt_grant_enabled'=>true,'explicit_authorization_required'=>false})
|
733
757
|
end
|
734
|
-
self.format.display_status("
|
735
|
-
@config_presets[
|
758
|
+
self.format.display_status("Creating new config preset: #{preset_name}")
|
759
|
+
@config_presets[preset_name]={
|
736
760
|
:url.to_s =>self.options.get_option(:url),
|
737
761
|
:username.to_s =>myself['email'],
|
738
762
|
:auth.to_s =>:jwt.to_s,
|
@@ -741,16 +765,21 @@ END_OF_TEMPLATE
|
|
741
765
|
# set only if non nil
|
742
766
|
[:client_id,:client_secret].each do |s|
|
743
767
|
o=self.options.get_option(s)
|
744
|
-
@config_presets[s.to_s] = o unless o.nil?
|
768
|
+
@config_presets[preset_name][s.to_s] = o unless o.nil?
|
745
769
|
end
|
746
|
-
|
747
|
-
@config_presets[CONF_PRESET_DEFAULT][AOC_COMMAND_CURRENT]=aspera_preset_name
|
748
|
-
self.format.display_status('saving config file')
|
749
|
-
save_presets_to_config_file
|
750
|
-
return Main.result_status("Done.\nYou can test with:\n#{@tool_name} #{AOC_COMMAND_CURRENT} user info show")
|
770
|
+
test_args="#{plugin_name} user info show"
|
751
771
|
else
|
752
772
|
raise CliBadArgument,"Supports only: aoc. Detected: #{appli}"
|
773
|
+
end # product
|
774
|
+
if option_default
|
775
|
+
self.format.display_status("Setting config preset as default for #{plugin_name}")
|
776
|
+
@config_presets[CONF_PRESET_DEFAULT][plugin_name]=preset_name
|
777
|
+
else
|
778
|
+
test_args="-P#{preset_name} #{test_args}"
|
753
779
|
end
|
780
|
+
self.format.display_status('Saving config file.')
|
781
|
+
save_presets_to_config_file
|
782
|
+
return Main.result_status("Done.\nYou can test with:\n#{@tool_name} #{test_args}")
|
754
783
|
when :export_to_cli
|
755
784
|
self.format.display_status('Exporting: Aspera on Cloud')
|
756
785
|
require 'aspera/cli/plugins/aoc'
|
@@ -820,16 +849,16 @@ END_OF_TEMPLATE
|
|
820
849
|
@config_presets[DEMO_SERVER_PRESET]={'url'=>'ssh://'+DEMO+'.asperasoft.com:33001','username'=>AOC_COMMAND_V2,'ssAP'.downcase.reverse+'drow'.reverse=>DEMO+AOC_COMMAND_V2}
|
821
850
|
end
|
822
851
|
@config_presets[CONF_PRESET_DEFAULT]||={}
|
823
|
-
if @config_presets[CONF_PRESET_DEFAULT].has_key?(
|
824
|
-
Log.log.warn("
|
825
|
-
Log.log.warn("
|
852
|
+
if @config_presets[CONF_PRESET_DEFAULT].has_key?(SERVER_COMMAND)
|
853
|
+
Log.log.warn("Server default preset already set to: #{@config_presets[CONF_PRESET_DEFAULT][SERVER_COMMAND]}")
|
854
|
+
Log.log.warn("Use #{DEMO_SERVER_PRESET} for demo: -P#{DEMO_SERVER_PRESET}") unless DEMO_SERVER_PRESET.eql?(@config_presets[CONF_PRESET_DEFAULT][SERVER_COMMAND])
|
826
855
|
else
|
827
|
-
@config_presets[CONF_PRESET_DEFAULT][
|
828
|
-
Log.log.info("
|
856
|
+
@config_presets[CONF_PRESET_DEFAULT][SERVER_COMMAND]=DEMO_SERVER_PRESET
|
857
|
+
Log.log.info("Setting server default preset to : #{DEMO_SERVER_PRESET}")
|
829
858
|
end
|
830
859
|
save_presets_to_config_file
|
831
860
|
return Main.result_status("Done")
|
832
|
-
else raise '
|
861
|
+
else raise 'INTERNAL ERROR: wrong case'
|
833
862
|
end
|
834
863
|
end
|
835
864
|
|
@@ -888,7 +917,7 @@ END_OF_TEMPLATE
|
|
888
917
|
def save_presets_to_config_file
|
889
918
|
raise 'no configuration loaded' if @config_presets.nil?
|
890
919
|
FileUtils.mkdir_p(@main_folder) unless Dir.exist?(@main_folder)
|
891
|
-
Log.log.debug
|
920
|
+
Log.log.debug("Writing #{@option_config_file}")
|
892
921
|
File.write(@option_config_file,@config_presets.to_yaml)
|
893
922
|
end
|
894
923
|
|
@@ -23,12 +23,14 @@ module Aspera
|
|
23
23
|
PACKAGE_MATCH_FIELD='package_id'
|
24
24
|
# list of supported atoms
|
25
25
|
ATOM_MAILBOXES=[:inbox, :archive, :sent]
|
26
|
-
#
|
27
|
-
|
28
|
-
|
29
|
-
ATOM_PARAMS
|
26
|
+
# allowed parameters for inbox.atom
|
27
|
+
ATOM_PARAMS=['page', 'count', 'startIndex']
|
28
|
+
# with special parameters (from Plugin class)
|
29
|
+
ATOM_EXT_PARAMS=ATOM_PARAMS+[MAX_ITEMS, MAX_PAGES]
|
30
|
+
# sub path in url for public link delivery
|
30
31
|
PUB_LINK_EXTERNAL_MATCH='external_deliveries/'
|
31
|
-
private_constant :KEY_NODE,:KEY_PATH,:VAL_ALL,:PACKAGE_MATCH_FIELD,:ATOM_MAILBOXES
|
32
|
+
private_constant :KEY_NODE,:KEY_PATH,:VAL_ALL,:PACKAGE_MATCH_FIELD,:ATOM_MAILBOXES,
|
33
|
+
:ATOM_PARAMS,:ATOM_EXT_PARAMS,:PUB_LINK_EXTERNAL_MATCH
|
32
34
|
|
33
35
|
def initialize(env)
|
34
36
|
@api_v3=nil
|
@@ -126,7 +128,7 @@ module Aspera
|
|
126
128
|
result=[]
|
127
129
|
if !mailbox_query.nil?
|
128
130
|
raise "query: must be Hash or nil" unless mailbox_query.is_a?(Hash)
|
129
|
-
raise "query: supported params: #{
|
131
|
+
raise "query: supported params: #{ATOM_EXT_PARAMS}" unless (mailbox_query.keys-ATOM_EXT_PARAMS).empty?
|
130
132
|
raise "query: startIndex and page are exclusive" if mailbox_query.has_key?('startIndex') and mailbox_query.has_key?('page')
|
131
133
|
max_items=mailbox_query[MAX_ITEMS]
|
132
134
|
mailbox_query.delete(MAX_ITEMS)
|
@@ -13,22 +13,34 @@ module Aspera
|
|
13
13
|
private_constant :SAMPLE_SOAP_CALL
|
14
14
|
def initialize(env)
|
15
15
|
super(env)
|
16
|
-
# this is added to some requests , for instance to add tags
|
16
|
+
# this is added to some requests , for instance to add tags (COS)
|
17
17
|
@add_request_param = env[:add_request_param] || {}
|
18
18
|
unless env[:skip_basic_auth_options]
|
19
19
|
self.options.add_opt_simple(:validator,"identifier of validator (optional for central)")
|
20
20
|
self.options.add_opt_simple(:asperabrowserurl,"URL for simple aspera web ui")
|
21
21
|
self.options.add_opt_simple(:name,"sync name")
|
22
|
-
self.options.add_opt_list(:
|
22
|
+
self.options.add_opt_list(:token_type,[:aspera,:basic,:hybrid],'Type of token used for transfers')
|
23
23
|
self.options.set_option(:asperabrowserurl,'https://asperabrowser.mybluemix.net')
|
24
|
-
self.options.set_option(:
|
24
|
+
self.options.set_option(:token_type,:aspera)
|
25
25
|
self.options.parse_options!
|
26
26
|
end
|
27
27
|
return if env[:man_only]
|
28
28
|
if env.has_key?(:node_api)
|
29
29
|
@api_node=env[:node_api]
|
30
30
|
else
|
31
|
-
|
31
|
+
if self.options.get_option(:password,:mandatory).start_with?('Bearer ')
|
32
|
+
# info is provided like node_info of aoc
|
33
|
+
@api_node=Rest.new({
|
34
|
+
base_url: self.options.get_option(:url,:mandatory),
|
35
|
+
headers: {
|
36
|
+
'Authorization' => self.options.get_option(:password,:mandatory),
|
37
|
+
'X-Aspera-AccessKey' => self.options.get_option(:username,:mandatory),
|
38
|
+
}
|
39
|
+
})
|
40
|
+
else
|
41
|
+
# this is normal case
|
42
|
+
@api_node=basic_auth_api
|
43
|
+
end
|
32
44
|
end
|
33
45
|
end
|
34
46
|
|
@@ -191,22 +203,36 @@ module Aspera
|
|
191
203
|
#raise "unknown type: #{send_result['self']['type']}"
|
192
204
|
end
|
193
205
|
return c_result_remove_prefix_path(result,'path',prefix_path)
|
194
|
-
when :upload
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
206
|
+
when :upload,:download
|
207
|
+
token_type=self.options.get_option(:token_type,:optional)
|
208
|
+
# nil if Shares 1.x
|
209
|
+
token_type=:aspera if token_type.nil?
|
210
|
+
case token_type
|
211
|
+
when :aspera,:hybrid
|
212
|
+
transfer_paths=case command
|
213
|
+
when :upload;[ { :destination => self.transfer.destination_folder('send') } ]
|
214
|
+
when :download;self.transfer.ts_source_paths
|
215
|
+
end
|
216
|
+
# only one request, so only one answer
|
217
|
+
transfer_spec=@api_node.create("files/#{command}_setup",{:transfer_requests => [ { transfer_request: {
|
218
|
+
paths: transfer_paths
|
219
|
+
}.deep_merge(@add_request_param) } ] } )[:data]['transfer_specs'].first['transfer_spec']
|
220
|
+
# delete this part, as the returned value contains only destination, and not sources
|
221
|
+
transfer_spec.delete('paths') if command.eql?(:upload)
|
222
|
+
when :basic
|
223
|
+
raise "shall have auth" unless @api_node.params[:auth].is_a?(Hash)
|
224
|
+
raise "shall be basic auth" unless @api_node.params[:auth][:type].eql?(:basic)
|
225
|
+
transfer_spec={
|
226
|
+
'remote_host'=>URI.parse(@api_node.params[:base_url]).host,
|
227
|
+
'remote_user'=>Aspera::Node::ACCESS_KEY_TRANSFER_USER,
|
228
|
+
'ssh_port'=>Aspera::Node::SSH_PORT_DEFAULT,
|
229
|
+
'direction'=>case command;when :upload;'send';when :download;'recv';else raise "Error";end
|
230
|
+
}
|
231
|
+
else raise "ERROR: token_type #{tt}"
|
232
|
+
end
|
233
|
+
if [:basic,:hybrid].include?(token_type)
|
234
|
+
Aspera::Node.set_ak_basic_token(transfer_spec,@api_node.params[:auth][:username],@api_node.params[:auth][:password])
|
235
|
+
end
|
210
236
|
return Main.result_transfer(self.transfer.start(transfer_spec,{:src=>:node_gen3}))
|
211
237
|
when :api_details
|
212
238
|
return { :type=>:single_object, :data => @api_node.params }
|
@@ -409,9 +435,11 @@ module Aspera
|
|
409
435
|
command=self.options.get_next_command([ :list, :modify])
|
410
436
|
case command
|
411
437
|
when :list
|
412
|
-
request_data.deep_merge!({
|
413
|
-
resp=@api_node.create('services/rest/transfers/v1/files',request_data)
|
414
|
-
|
438
|
+
request_data.deep_merge!({'validation'=>validation}) unless validation.nil?
|
439
|
+
resp=@api_node.create('services/rest/transfers/v1/files',request_data)[:data]
|
440
|
+
resp=JSON.parse(resp) if resp.is_a?(String)
|
441
|
+
Log.dump(:resp,resp)
|
442
|
+
return {:type=>:object_list,:data=>resp['file_transfer_info_result']['file_transfer_info'],:fields=>["session_uuid","file_id","status","path"]}
|
415
443
|
when :modify
|
416
444
|
request_data.deep_merge!(validation) unless validation.nil?
|
417
445
|
@api_node.update('services/rest/transfers/v1/files',request_data)
|
@@ -202,15 +202,17 @@ module Aspera
|
|
202
202
|
if @default_transfer_spec.nil?
|
203
203
|
# make a dummy call to get some default transfer parameters
|
204
204
|
res=@api_node.create('files/upload_setup',{'transfer_requests'=>[{'transfer_request'=>{'paths'=>[{}],'destination_root'=>'/'}}]})
|
205
|
-
|
205
|
+
template_ts=res[:data]['transfer_specs'].first['transfer_spec']
|
206
206
|
# get ports, anyway that should be 33001 for both. add remote_user ?
|
207
|
-
@default_transfer_spec=['ssh_port','fasp_port'].inject({}){|h,e|h[e]=
|
207
|
+
@default_transfer_spec=['ssh_port','fasp_port'].inject({}){|h,e|h[e]=template_ts[e];h}
|
208
|
+
if ! @default_transfer_spec['remote_user'].eql?(Aspera::Node::ACCESS_KEY_TRANSFER_USER)
|
209
|
+
Log.log.warn("remote_user shall be xfer")
|
210
|
+
@default_transfer_spec['remote_user']=Aspera::Node::ACCESS_KEY_TRANSFER_USER
|
211
|
+
end
|
212
|
+
Aspera::Node::set_ak_basic_token(@default_transfer_spec,@access_key_self['id'],self.options.get_option(:password,:mandatory))
|
208
213
|
# note: we use the same address for ascp than for node api instead of the one from upload_setup
|
209
|
-
|
210
|
-
|
211
|
-
'remote_host' => @transfer_server_address,
|
212
|
-
'remote_user' => Fasp::ACCESS_KEY_TRANSFER_USER
|
213
|
-
})
|
214
|
+
# TODO: configurable ? useful ?
|
215
|
+
@default_transfer_spec['remote_host']=@transfer_server_address
|
214
216
|
end
|
215
217
|
tspec=@default_transfer_spec.merge({
|
216
218
|
'direction' => direction,
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'aspera/cli/basic_auth_plugin'
|
2
2
|
require 'aspera/ascmd'
|
3
|
+
require 'aspera/node'
|
3
4
|
require 'aspera/ssh'
|
4
5
|
require 'aspera/nagios'
|
5
6
|
require 'tempfile'
|
@@ -67,13 +68,15 @@ module Aspera
|
|
67
68
|
def execute_action
|
68
69
|
server_uri=URI.parse(self.options.get_option(:url,:mandatory))
|
69
70
|
Log.log.debug("URI : #{server_uri}, port=#{server_uri.port}, scheme:#{server_uri.scheme}")
|
71
|
+
server_transfer_spec={'remote_host'=>server_uri.hostname}
|
70
72
|
shell_executor=nil
|
71
73
|
case server_uri.scheme
|
72
74
|
when 'ssh'
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
75
|
+
if self.options.get_option(:username,:optional).nil?
|
76
|
+
self.options.set_option(:username,Aspera::Node::ACCESS_KEY_TRANSFER_USER)
|
77
|
+
Log.log.info("Using default transfer user: #{Aspera::Node::ACCESS_KEY_TRANSFER_USER}")
|
78
|
+
end
|
79
|
+
server_transfer_spec['remote_user']=self.options.get_option(:username,:mandatory)
|
77
80
|
ssh_options=self.options.get_option(:ssh_options,:optional)
|
78
81
|
raise 'expecting a Hash for ssh_options' unless ssh_options.is_a?(Hash)
|
79
82
|
if !server_uri.port.nil?
|
@@ -102,8 +105,16 @@ module Aspera
|
|
102
105
|
cred_set=true
|
103
106
|
end
|
104
107
|
end
|
105
|
-
|
108
|
+
# if user provided transfer spec has a token, we will use by pass keys
|
109
|
+
cred_set=true if self.transfer.option_transfer_spec['token'].is_a?(String)
|
110
|
+
raise 'either password, key , or transfer spec token must be provided' if !cred_set
|
106
111
|
shell_executor=Ssh.new(server_transfer_spec['remote_host'],server_transfer_spec['remote_user'],ssh_options)
|
112
|
+
when 'https'
|
113
|
+
raise "ERROR: transfer spec with token required" unless self.transfer.option_transfer_spec['token'].is_a?(String)
|
114
|
+
server_transfer_spec.merge!({
|
115
|
+
'wss_enabled'=>true,
|
116
|
+
'wss_port' =>server_uri.port
|
117
|
+
})
|
107
118
|
when 'local'
|
108
119
|
shell_executor=LocalExecutor.new
|
109
120
|
else
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'aspera/fasp/local'
|
2
|
+
require 'aspera/fasp/parameters'
|
2
3
|
require 'aspera/fasp/connect'
|
3
4
|
require 'aspera/fasp/node'
|
4
|
-
require 'aspera/fasp/aoc'
|
5
5
|
require 'aspera/fasp/http_gw'
|
6
6
|
require 'aspera/cli/listener/logger'
|
7
7
|
require 'aspera/cli/listener/progress_multi'
|
@@ -43,9 +43,9 @@ END_OF_TEMPLATE
|
|
43
43
|
options.add_opt_simple(:local_resume,"set resume policy (Hash, use @json: prefix), current=#{options.get_option(:local_resume,:optional)}")
|
44
44
|
options.add_opt_simple(:to_folder,"destination folder for downloaded files")
|
45
45
|
options.add_opt_simple(:sources,"list of source files (see doc)")
|
46
|
-
options.add_opt_simple(:transfer_info,"
|
46
|
+
options.add_opt_simple(:transfer_info,"parameters for transfer agent")
|
47
47
|
options.add_opt_list(:src_type,[:list,:pair],"type of file list")
|
48
|
-
options.add_opt_list(:transfer,[:direct,:httpgw,:connect,:node
|
48
|
+
options.add_opt_list(:transfer,[:direct,:httpgw,:connect,:node],"type of transfer agent")
|
49
49
|
options.add_opt_list(:progress,[:none,:native,:multi],"type of progress bar")
|
50
50
|
options.set_option(:transfer,:direct)
|
51
51
|
options.set_option(:src_type,:list)
|
@@ -124,22 +124,6 @@ END_OF_TEMPLATE
|
|
124
124
|
new_agent=Fasp::Node.new(node_api)
|
125
125
|
# add root id if it's an access key
|
126
126
|
new_agent.options={root_id: node_config[:root_id]} if node_config.has_key?(:root_id)
|
127
|
-
when :aoc
|
128
|
-
aoc_config=options.get_option(:transfer_info,:optional)
|
129
|
-
if aoc_config.nil?
|
130
|
-
param_set_name=config.get_plugin_default_config_name(:aspera)
|
131
|
-
raise CliBadArgument,"No default AoC configured, Please specify --#{:transfer_info.to_s.gsub('_','-')}" if param_set_name.nil?
|
132
|
-
aoc_config=config.preset_by_name(param_set_name)
|
133
|
-
end
|
134
|
-
Log.log.debug("aoc=#{aoc_config}")
|
135
|
-
raise CliBadArgument,"the aoc configuration shall be Hash, not #{aoc_config.class} (#{aoc_config}), refer to manual" if !aoc_config.is_a?(Hash)
|
136
|
-
# convert keys from string (config) to symbol (agent)
|
137
|
-
aoc_config=aoc_config.symbolize_keys
|
138
|
-
# convert auth value from string (config) to symbol (agent)
|
139
|
-
aoc_config[:auth]=aoc_config[:auth].to_sym if aoc_config[:auth].is_a?(String)
|
140
|
-
# private key could be @file:... in config
|
141
|
-
aoc_config[:private_key]=ExtendedValue.instance.evaluate(aoc_config[:private_key])
|
142
|
-
new_agent=Fasp::Aoc.new(aoc_config)
|
143
127
|
else
|
144
128
|
raise "Unexpected transfer agent type: #{agent_type}"
|
145
129
|
end
|
@@ -183,7 +167,8 @@ END_OF_TEMPLATE
|
|
183
167
|
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) or file_list.empty?
|
184
168
|
when FILE_LIST_FROM_TRANSFER_SPEC
|
185
169
|
Log.log.debug("assume list provided in transfer spec")
|
186
|
-
|
170
|
+
special_case_direct_with_list=options.get_option(:transfer,:mandatory).eql?(:direct) and Fasp::Parameters.ts_has_file_list(@transfer_spec_cmdline)
|
171
|
+
raise CliBadArgument,"transfer spec on command line must have sources" if @transfer_paths.nil? and !special_case_direct_with_list
|
187
172
|
# here we assume check of sources is made in transfer agent
|
188
173
|
return @transfer_paths
|
189
174
|
when Array
|
data/lib/aspera/cli/version.rb
CHANGED