aspera-cli 4.3.0 → 4.4.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
- 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