aspera-cli 4.13.0 → 4.15.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +81 -7
- data/CONTRIBUTING.md +22 -6
- data/README.md +2038 -1080
- data/bin/ascli +18 -9
- data/bin/asession +12 -14
- data/examples/dascli +1 -1
- data/examples/proxy.pac +1 -1
- data/examples/rubyc +24 -0
- data/lib/aspera/aoc.rb +219 -159
- data/lib/aspera/ascmd.rb +25 -14
- data/lib/aspera/cli/basic_auth_plugin.rb +12 -9
- data/lib/aspera/cli/error.rb +17 -0
- data/lib/aspera/cli/extended_value.rb +47 -12
- data/lib/aspera/cli/formatter.rb +260 -179
- data/lib/aspera/cli/hints.rb +80 -0
- data/lib/aspera/cli/main.rb +104 -156
- data/lib/aspera/cli/manager.rb +259 -209
- data/lib/aspera/cli/plugin.rb +123 -63
- data/lib/aspera/cli/plugins/alee.rb +2 -3
- data/lib/aspera/cli/plugins/aoc.rb +341 -261
- data/lib/aspera/cli/plugins/ats.rb +22 -21
- data/lib/aspera/cli/plugins/bss.rb +5 -5
- data/lib/aspera/cli/plugins/config.rb +578 -627
- data/lib/aspera/cli/plugins/console.rb +44 -6
- data/lib/aspera/cli/plugins/cos.rb +15 -17
- data/lib/aspera/cli/plugins/faspex.rb +114 -100
- data/lib/aspera/cli/plugins/faspex5.rb +411 -264
- data/lib/aspera/cli/plugins/node.rb +354 -259
- data/lib/aspera/cli/plugins/orchestrator.rb +61 -29
- data/lib/aspera/cli/plugins/preview.rb +82 -90
- data/lib/aspera/cli/plugins/server.rb +79 -32
- data/lib/aspera/cli/plugins/shares.rb +55 -42
- data/lib/aspera/cli/sync_actions.rb +68 -0
- data/lib/aspera/cli/transfer_agent.rb +66 -73
- data/lib/aspera/cli/transfer_progress.rb +74 -0
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/colors.rb +12 -8
- data/lib/aspera/command_line_builder.rb +14 -11
- data/lib/aspera/cos_node.rb +3 -2
- data/lib/aspera/data/6 +0 -0
- data/lib/aspera/environment.rb +24 -9
- data/lib/aspera/fasp/agent_aspera.rb +126 -0
- data/lib/aspera/fasp/agent_base.rb +31 -77
- data/lib/aspera/fasp/agent_connect.rb +25 -21
- data/lib/aspera/fasp/agent_direct.rb +89 -103
- data/lib/aspera/fasp/agent_httpgw.rb +231 -149
- data/lib/aspera/fasp/agent_node.rb +41 -34
- data/lib/aspera/fasp/agent_trsdk.rb +75 -32
- data/lib/aspera/fasp/error_info.rb +4 -2
- data/lib/aspera/fasp/faux_file.rb +52 -0
- data/lib/aspera/fasp/installation.rb +53 -195
- data/lib/aspera/fasp/management.rb +244 -0
- data/lib/aspera/fasp/parameters.rb +71 -37
- data/lib/aspera/fasp/parameters.yaml +76 -8
- data/lib/aspera/fasp/products.rb +162 -0
- data/lib/aspera/fasp/resume_policy.rb +3 -3
- data/lib/aspera/fasp/transfer_spec.rb +7 -6
- data/lib/aspera/fasp/uri.rb +26 -24
- data/lib/aspera/faspex_gw.rb +2 -2
- data/lib/aspera/faspex_postproc.rb +2 -2
- data/lib/aspera/hash_ext.rb +14 -4
- data/lib/aspera/json_rpc.rb +49 -0
- data/lib/aspera/keychain/macos_security.rb +13 -13
- data/lib/aspera/line_logger.rb +23 -0
- data/lib/aspera/log.rb +58 -16
- data/lib/aspera/node.rb +157 -92
- data/lib/aspera/oauth.rb +37 -19
- data/lib/aspera/open_application.rb +4 -4
- data/lib/aspera/persistency_action_once.rb +1 -1
- data/lib/aspera/persistency_folder.rb +2 -2
- data/lib/aspera/preview/file_types.rb +4 -2
- data/lib/aspera/preview/generator.rb +22 -35
- data/lib/aspera/preview/options.rb +2 -0
- data/lib/aspera/preview/terminal.rb +73 -16
- data/lib/aspera/preview/utils.rb +21 -28
- data/lib/aspera/proxy_auto_config.js +2 -2
- data/lib/aspera/rest.rb +136 -68
- data/lib/aspera/rest_call_error.rb +1 -1
- data/lib/aspera/rest_error_analyzer.rb +15 -14
- data/lib/aspera/rest_errors_aspera.rb +37 -34
- data/lib/aspera/secret_hider.rb +18 -15
- data/lib/aspera/ssh.rb +5 -2
- data/lib/aspera/sync.rb +127 -119
- data/lib/aspera/temp_file_manager.rb +10 -3
- data/lib/aspera/web_auth.rb +10 -7
- data/lib/aspera/web_server_simple.rb +9 -4
- data.tar.gz.sig +0 -0
- metadata +34 -17
- metadata.gz.sig +0 -0
- data/docs/test_env.conf +0 -186
- data/lib/aspera/cli/listener/line_dump.rb +0 -19
- data/lib/aspera/cli/listener/logger.rb +0 -22
- data/lib/aspera/cli/listener/progress.rb +0 -50
- data/lib/aspera/cli/listener/progress_multi.rb +0 -84
- data/lib/aspera/cli/plugins/sync.rb +0 -44
- data/lib/aspera/data/7 +0 -0
- data/lib/aspera/fasp/listener.rb +0 -13
@@ -2,12 +2,13 @@
|
|
2
2
|
# accepted_types : accepted types for non-enum
|
3
3
|
# default : default value if not specified
|
4
4
|
# enum : set with list of values for enum types accepted in transfer spec
|
5
|
-
# agents : supported agents (for doc only)
|
5
|
+
# agents : supported agents (for doc only), if not specified: all
|
6
6
|
# required : optional, default: false
|
7
7
|
# cli.type : ascp: type of parameter, one of CLI_OPTION_TYPES
|
8
8
|
# cli.switch : ascp: switch for ascp command line
|
9
9
|
# cli.convert : ascp: transform value: either a Hash with conversion values, or name of class
|
10
10
|
# cli.variable : ascp: name of env var
|
11
|
+
# cspell:words dgram dnat dnats faspmgr asperanoded xattrs keepalive datagram
|
11
12
|
---
|
12
13
|
cipher:
|
13
14
|
:desc: "In transit encryption type."
|
@@ -78,7 +79,11 @@ destination_root:
|
|
78
79
|
:cli:
|
79
80
|
:type: :special
|
80
81
|
destination_root_id:
|
81
|
-
:desc:
|
82
|
+
:desc: |-
|
83
|
+
The file ID of the destination root directory.
|
84
|
+
Required when using Bearer token auth for the destination node.
|
85
|
+
|
86
|
+
|
82
87
|
:accepted_types: :string
|
83
88
|
:agents:
|
84
89
|
- :sdk
|
@@ -176,7 +181,7 @@ multi_session:
|
|
176
181
|
|
177
182
|
:accepted_types: :int
|
178
183
|
:cli:
|
179
|
-
:type: :
|
184
|
+
:type: :special
|
180
185
|
:switch: "-C"
|
181
186
|
multi_session_threshold:
|
182
187
|
:desc: |-
|
@@ -226,15 +231,37 @@ precalculate_job_size:
|
|
226
231
|
:cli:
|
227
232
|
:type: :opt_without_arg
|
228
233
|
preserve_access_time:
|
234
|
+
:desc: |-
|
235
|
+
Preserve the source-file access timestamps at the destination.
|
236
|
+
Because source access times are updated by the transfer operation,
|
237
|
+
the timestamp that is preserved is the one just before to the transfer.
|
238
|
+
|
239
|
+
|
229
240
|
:cli:
|
230
241
|
:type: :opt_without_arg
|
231
242
|
preserve_creation_time:
|
243
|
+
:desc: |-
|
244
|
+
(Windows only) Preserve source-file creation timestamps at the destination.
|
245
|
+
Only Windows systems retain information about creation time.
|
246
|
+
If the destination is not a Windows computer, this option is ignored.
|
247
|
+
|
248
|
+
|
232
249
|
:cli:
|
233
250
|
:type: :opt_without_arg
|
234
251
|
preserve_modification_time:
|
252
|
+
:desc: |-
|
253
|
+
Set the modification time, the last time a file or directory was modified (written), of a transferred file
|
254
|
+
to the modification of the source file or directory.
|
255
|
+
Preserve source-file modification timestamps at the destination.
|
256
|
+
|
257
|
+
|
235
258
|
:cli:
|
236
259
|
:type: :opt_without_arg
|
237
260
|
preserve_times:
|
261
|
+
:desc: Preserve file timestamps.
|
262
|
+
:agents:
|
263
|
+
- :sdk
|
264
|
+
- :node
|
238
265
|
:cli:
|
239
266
|
:type: :opt_without_arg
|
240
267
|
rate_policy:
|
@@ -436,6 +463,7 @@ use_ascp4:
|
|
436
463
|
:cli:
|
437
464
|
:type: :special
|
438
465
|
use_system_ssh:
|
466
|
+
:desc: TODO, comment...
|
439
467
|
:accepted_types: :string
|
440
468
|
:agents:
|
441
469
|
- :sdk
|
@@ -453,22 +481,46 @@ source_root:
|
|
453
481
|
:switch: "--source-prefix64"
|
454
482
|
:convert: Aspera::Fasp::Parameters.convert_base64
|
455
483
|
min_rate_cap_kbps:
|
484
|
+
:desc: |-
|
485
|
+
The highest minimum rate that an incoming transfer can request, in kilobits per second.
|
486
|
+
Client minimum rate requests that exceed the minimum rate cap are ignored.
|
487
|
+
The default value of unlimited applies no cap to the minimum rate. (Default: 0)
|
488
|
+
|
489
|
+
|
456
490
|
:accepted_types: :int
|
457
491
|
:cli:
|
458
492
|
:type: :ignore
|
459
493
|
lock_rate_policy:
|
494
|
+
:desc: If true, lock the rate policy to the default value.
|
460
495
|
:accepted_types: :bool
|
496
|
+
:agents:
|
497
|
+
- :sdk
|
498
|
+
- :connect
|
461
499
|
:cli:
|
462
500
|
:type: :ignore
|
463
501
|
lock_target_rate_kbps:
|
502
|
+
:desc: |-
|
503
|
+
If true, lock the target transfer rate to the default value set for target_rate_kbps.
|
504
|
+
If false, users can adjust the transfer rate up to the value set for target_rate_cap_kbps.
|
505
|
+
|
506
|
+
|
464
507
|
:accepted_types: :bool
|
465
508
|
:cli:
|
466
509
|
:type: :ignore
|
467
510
|
lock_min_rate_kbps:
|
511
|
+
:desc: |-
|
512
|
+
If true, lock the minimum transfer rate to the value set for min_rate_kbps.
|
513
|
+
If false, users can adjust the transfer rate up to the value set for target_rate_cap_kbps.
|
514
|
+
|
515
|
+
|
468
516
|
:accepted_types: :bool
|
517
|
+
:agents:
|
518
|
+
- :sdk
|
519
|
+
- :connect
|
469
520
|
:cli:
|
470
521
|
:type: :ignore
|
471
522
|
apply_local_docroot:
|
523
|
+
:desc: Apply local docroot to source paths.
|
472
524
|
:agents:
|
473
525
|
- :direct
|
474
526
|
- :sdk
|
@@ -560,7 +612,7 @@ remove_empty_source_directory:
|
|
560
612
|
:type: :opt_without_arg
|
561
613
|
EX_at_rest_password:
|
562
614
|
:desc: Content protection password
|
563
|
-
:deprecation: "Use standard spec parameter: content_protection_password"
|
615
|
+
:deprecation: "(4.13) Use standard spec parameter: content_protection_password"
|
564
616
|
:agents:
|
565
617
|
- :direct
|
566
618
|
:cli:
|
@@ -569,9 +621,10 @@ EX_at_rest_password:
|
|
569
621
|
EX_proxy_password:
|
570
622
|
:desc: |-
|
571
623
|
Password used for Aspera proxy server authentication.
|
572
|
-
May be overridden by password in URL
|
624
|
+
May be overridden by password in URL provided in parameter: proxy.
|
573
625
|
|
574
626
|
|
627
|
+
:deprecation: (4.14) Use env var ASPERA_PROXY_PASS
|
575
628
|
:agents:
|
576
629
|
- :direct
|
577
630
|
:cli:
|
@@ -579,14 +632,17 @@ EX_proxy_password:
|
|
579
632
|
:variable: ASPERA_PROXY_PASS
|
580
633
|
EX_license_text:
|
581
634
|
:desc: "License file text override.\nBy default ascp looks for license file near executable."
|
635
|
+
:deprecation: (4.14) Use env var ASPERA_SCP_LICENSE
|
582
636
|
:agents:
|
583
637
|
- :direct
|
584
638
|
:cli:
|
585
639
|
:type: :envvar
|
586
640
|
:variable: ASPERA_SCP_LICENSE
|
587
641
|
keepalive:
|
642
|
+
:desc: The session is running in persistent session mode.
|
588
643
|
:agents:
|
589
|
-
- :
|
644
|
+
- :sdk
|
645
|
+
- :direct
|
590
646
|
:cli:
|
591
647
|
:type: :opt_without_arg
|
592
648
|
dgram_size:
|
@@ -609,6 +665,7 @@ sshfp:
|
|
609
665
|
:switch: "--check-sshfp"
|
610
666
|
EX_http_proxy_url:
|
611
667
|
:desc: Specify the proxy server address used by HTTP Fallback
|
668
|
+
:deprecation: (4.14) TODO, use proxy option ?
|
612
669
|
:agents:
|
613
670
|
- :direct
|
614
671
|
:cli:
|
@@ -616,6 +673,7 @@ EX_http_proxy_url:
|
|
616
673
|
:switch: "-x"
|
617
674
|
EX_ssh_key_paths:
|
618
675
|
:desc: Use public key authentication for SSH and specify the private key file paths
|
676
|
+
:deprecation: (4.14) Use option transfer_info.ascp_args
|
619
677
|
:accepted_types: :array
|
620
678
|
:agents:
|
621
679
|
- :direct
|
@@ -624,6 +682,7 @@ EX_ssh_key_paths:
|
|
624
682
|
:switch: "-i"
|
625
683
|
EX_http_transfer_jpeg:
|
626
684
|
:desc: HTTP transfers as JPEG file
|
685
|
+
:deprecation: (4.14) Use option transfer_info.ascp_args
|
627
686
|
:accepted_types: :int
|
628
687
|
:default: '0'
|
629
688
|
:agents:
|
@@ -633,6 +692,7 @@ EX_http_transfer_jpeg:
|
|
633
692
|
:switch: "-j"
|
634
693
|
EX_no_read:
|
635
694
|
:desc: no read source
|
695
|
+
:deprecation: (4.14) Use option transfer_info.ascp_args
|
636
696
|
:agents:
|
637
697
|
- :direct
|
638
698
|
:cli:
|
@@ -640,12 +700,14 @@ EX_no_read:
|
|
640
700
|
:switch: "--no-read"
|
641
701
|
EX_no_write:
|
642
702
|
:desc: no write on destination
|
703
|
+
:deprecation: (4.14) Use option transfer_info.ascp_args
|
643
704
|
:agents:
|
644
705
|
- :direct
|
645
706
|
:cli:
|
646
707
|
:type: :opt_without_arg
|
647
708
|
:switch: "--no-write"
|
648
709
|
target_rate_percentage:
|
710
|
+
:desc: "TODO: remove ?"
|
649
711
|
:cli:
|
650
712
|
:type: :ignore
|
651
713
|
rate_policy_allowed:
|
@@ -660,15 +722,18 @@ rate_policy_allowed:
|
|
660
722
|
:cli:
|
661
723
|
:type: :ignore
|
662
724
|
fasp_url:
|
725
|
+
:desc: Only used in Faspex.
|
663
726
|
:agents:
|
664
727
|
- :unknown
|
665
728
|
:cli:
|
666
729
|
:type: :ignore
|
667
730
|
lock_min_rate:
|
731
|
+
:desc: "TODO: remove ?"
|
668
732
|
:accepted_types: :bool
|
669
733
|
:cli:
|
670
734
|
:type: :ignore
|
671
735
|
lock_target_rate:
|
736
|
+
:desc: "TODO: remove ?"
|
672
737
|
:accepted_types: :bool
|
673
738
|
:cli:
|
674
739
|
:type: :ignore
|
@@ -683,13 +748,15 @@ cipher_allowed:
|
|
683
748
|
:cli:
|
684
749
|
:type: :ignore
|
685
750
|
obfuscate_file_names:
|
751
|
+
:desc: HTTP Gateway obfuscates file names when set to true.
|
686
752
|
:accepted_types: :bool
|
687
753
|
:agents:
|
688
|
-
- :
|
754
|
+
- :httpgw
|
689
755
|
:cli:
|
690
756
|
:type: :ignore
|
691
757
|
EX_file_list:
|
692
758
|
:desc: source file list
|
759
|
+
:deprecation: (4.14) Use command line file list, or option transfer_info.ascp_args
|
693
760
|
:agents:
|
694
761
|
- :direct
|
695
762
|
:cli:
|
@@ -697,6 +764,7 @@ EX_file_list:
|
|
697
764
|
:switch: "--file-list"
|
698
765
|
EX_file_pair_list:
|
699
766
|
:desc: source file pair list
|
767
|
+
:deprecation: (4.14) Use command line file pair list, or option transfer_info.ascp_args
|
700
768
|
:agents:
|
701
769
|
- :direct
|
702
770
|
:cli:
|
@@ -704,7 +772,7 @@ EX_file_pair_list:
|
|
704
772
|
:switch: "--file-pair-list"
|
705
773
|
EX_ascp_args:
|
706
774
|
:desc: Add native command line arguments to ascp
|
707
|
-
:deprecation: Use
|
775
|
+
:deprecation: (4.13) Use option transfer_info.ascp_args
|
708
776
|
:accepted_types: :array
|
709
777
|
:agents:
|
710
778
|
- :direct
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# cspell:ignore LOCALAPPDATA
|
4
|
+
require 'aspera/environment'
|
5
|
+
|
6
|
+
module Aspera
|
7
|
+
module Fasp
|
8
|
+
# find Aspera standard products installation in standard paths
|
9
|
+
class Products
|
10
|
+
# known product names
|
11
|
+
CONNECT = 'IBM Aspera Connect'
|
12
|
+
ASPERA = 'IBM Aspera (Client)'
|
13
|
+
CLI_V1 = 'Aspera CLI (deprecated)'
|
14
|
+
DRIVE = 'Aspera Drive (deprecated)'
|
15
|
+
HSTS = 'IBM Aspera High-Speed Transfer Server'
|
16
|
+
# product information manifest: XML (part of aspera product)
|
17
|
+
INFO_META_FILE = 'product-info.mf'
|
18
|
+
BIN_SUBFOLDER = 'bin'
|
19
|
+
ETC_SUBFOLDER = 'etc'
|
20
|
+
VAR_RUN_SUBFOLDER = File.join('var', 'run')
|
21
|
+
|
22
|
+
@@found_products = nil # rubocop:disable Style/ClassVars
|
23
|
+
class << self
|
24
|
+
# @return product folders depending on OS fields
|
25
|
+
# :expected M app name is taken from the manifest if present, else defaults to this value
|
26
|
+
# :app_root M main folder for the application
|
27
|
+
# :log_root O location of log files (Linux uses syslog)
|
28
|
+
# :run_root O only for Connect Client, location of http port file
|
29
|
+
# :sub_bin O subfolder with executables, default : bin
|
30
|
+
def product_locations_on_current_os
|
31
|
+
result =
|
32
|
+
case Aspera::Environment.os
|
33
|
+
when Aspera::Environment::OS_WINDOWS then [{
|
34
|
+
expected: CONNECT,
|
35
|
+
app_root: File.join(ENV.fetch('LOCALAPPDATA', nil), 'Programs', 'Aspera', 'Aspera Connect'),
|
36
|
+
log_root: File.join(ENV.fetch('LOCALAPPDATA', nil), 'Aspera', 'Aspera Connect', 'var', 'log'),
|
37
|
+
run_root: File.join(ENV.fetch('LOCALAPPDATA', nil), 'Aspera', 'Aspera Connect')
|
38
|
+
}, {
|
39
|
+
expected: CLI_V1,
|
40
|
+
app_root: File.join('C:', 'Program Files', 'Aspera', 'cli'),
|
41
|
+
log_root: File.join('C:', 'Program Files', 'Aspera', 'cli', 'var', 'log')
|
42
|
+
}, {
|
43
|
+
expected: HSTS,
|
44
|
+
app_root: File.join('C:', 'Program Files', 'Aspera', 'Enterprise Server'),
|
45
|
+
log_root: File.join('C:', 'Program Files', 'Aspera', 'Enterprise Server', 'var', 'log')
|
46
|
+
}]
|
47
|
+
when Aspera::Environment::OS_X then [{
|
48
|
+
expected: CONNECT,
|
49
|
+
app_root: File.join(Dir.home, 'Applications', 'Aspera Connect.app'),
|
50
|
+
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Connect'),
|
51
|
+
run_root: File.join(Dir.home, 'Library', 'Application Support', 'Aspera', 'Aspera Connect'),
|
52
|
+
sub_bin: File.join('Contents', 'Resources')
|
53
|
+
}, {
|
54
|
+
expected: CONNECT,
|
55
|
+
app_root: File.join('', 'Applications', 'Aspera Connect.app'),
|
56
|
+
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Connect'),
|
57
|
+
run_root: File.join(Dir.home, 'Library', 'Application Support', 'Aspera', 'Aspera Connect'),
|
58
|
+
sub_bin: File.join('Contents', 'Resources')
|
59
|
+
}, {
|
60
|
+
expected: CLI_V1,
|
61
|
+
app_root: File.join(Dir.home, 'Applications', 'Aspera CLI'),
|
62
|
+
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera')
|
63
|
+
}, {
|
64
|
+
expected: HSTS,
|
65
|
+
app_root: File.join('', 'Library', 'Aspera'),
|
66
|
+
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera')
|
67
|
+
}, {
|
68
|
+
expected: DRIVE,
|
69
|
+
app_root: File.join('', 'Applications', 'Aspera Drive.app'),
|
70
|
+
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Drive'),
|
71
|
+
sub_bin: File.join('Contents', 'Resources')
|
72
|
+
}, {
|
73
|
+
expected: ASPERA,
|
74
|
+
app_root: File.join('', 'Applications', 'IBM Aspera.app'),
|
75
|
+
log_root: File.join(Dir.home, 'Library', 'Logs', 'IBM Aspera'),
|
76
|
+
sub_bin: File.join('Contents', 'Resources', 'sdk', 'aspera', 'bin')
|
77
|
+
}]
|
78
|
+
else [{ # other: Linux and Unix family
|
79
|
+
expected: CONNECT,
|
80
|
+
app_root: File.join(Dir.home, '.aspera', 'connect'),
|
81
|
+
run_root: File.join(Dir.home, '.aspera', 'connect')
|
82
|
+
}, {
|
83
|
+
expected: CLI_V1,
|
84
|
+
app_root: File.join(Dir.home, '.aspera', 'cli')
|
85
|
+
}, {
|
86
|
+
expected: HSTS,
|
87
|
+
app_root: File.join('', 'opt', 'aspera')
|
88
|
+
}]
|
89
|
+
end
|
90
|
+
result # .each {|item| item.deep_do {|h, _k, _v, _m|h.freeze}}.freeze
|
91
|
+
end
|
92
|
+
|
93
|
+
# @return the list of installed products in format of product_locations_on_current_os
|
94
|
+
def installed_products
|
95
|
+
if @@found_products.nil?
|
96
|
+
scan_locations = product_locations_on_current_os.clone
|
97
|
+
# add SDK as first search path
|
98
|
+
scan_locations.unshift({
|
99
|
+
expected: 'SDK',
|
100
|
+
app_root: Installation.instance.sdk_folder,
|
101
|
+
sub_bin: ''
|
102
|
+
})
|
103
|
+
# search installed products: with ascp
|
104
|
+
@@found_products = scan_locations.select! do |item| # rubocop:disable Style/ClassVars
|
105
|
+
# skip if not main folder
|
106
|
+
next false unless Dir.exist?(item[:app_root])
|
107
|
+
Log.log.debug{"Found #{item[:app_root]}"}
|
108
|
+
sub_bin = item[:sub_bin] || BIN_SUBFOLDER
|
109
|
+
item[:ascp_path] = File.join(item[:app_root], sub_bin, ascp_filename)
|
110
|
+
# skip if no ascp
|
111
|
+
next false unless File.exist?(item[:ascp_path])
|
112
|
+
# read info from product info file if present
|
113
|
+
product_info_file = "#{item[:app_root]}/#{INFO_META_FILE}"
|
114
|
+
if File.exist?(product_info_file)
|
115
|
+
res_s = XmlSimple.xml_in(File.read(product_info_file), {'ForceArray' => false})
|
116
|
+
item[:name] = res_s['name']
|
117
|
+
item[:version] = res_s['version']
|
118
|
+
else
|
119
|
+
item[:name] = item[:expected]
|
120
|
+
end
|
121
|
+
true # select this version
|
122
|
+
end
|
123
|
+
end
|
124
|
+
return @@found_products
|
125
|
+
end
|
126
|
+
|
127
|
+
# filename for ascp with optional extension (Windows)
|
128
|
+
def ascp_filename
|
129
|
+
return 'ascp' + Environment.exe_extension
|
130
|
+
end
|
131
|
+
|
132
|
+
# @return folder paths for specified applications
|
133
|
+
# @param name Connect or CLI
|
134
|
+
def folders(name)
|
135
|
+
found = Products.installed_products.select{|i|i[:expected].eql?(name) || i[:name].eql?(name)}
|
136
|
+
raise "Product: #{name} not found, please install." if found.empty?
|
137
|
+
return found.first
|
138
|
+
end
|
139
|
+
|
140
|
+
# @return the file path of local connect where API's URI can be read
|
141
|
+
def connect_uri
|
142
|
+
connect = folders(CONNECT)
|
143
|
+
folder = File.join(connect[:run_root], VAR_RUN_SUBFOLDER)
|
144
|
+
['', 's'].each do |ext|
|
145
|
+
uri_file = File.join(folder, "http#{ext}.uri")
|
146
|
+
Log.log.debug{"checking connect port file: #{uri_file}"}
|
147
|
+
if File.exist?(uri_file)
|
148
|
+
return File.open(uri_file, &:gets).strip
|
149
|
+
end
|
150
|
+
end
|
151
|
+
raise "no connect uri file found in #{folder}"
|
152
|
+
end
|
153
|
+
|
154
|
+
# @ return path to configuration file of aspera CLI
|
155
|
+
# def cli_conf_file
|
156
|
+
# connect = folders(PRODUCT_CLI_V1)
|
157
|
+
# return File.join(connect[:app_root], BIN_SUBFOLDER, '.aspera_cli_conf')
|
158
|
+
# end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -49,11 +49,11 @@ module Aspera
|
|
49
49
|
# failure in ascp
|
50
50
|
if e.retryable?
|
51
51
|
# exit if we exceed the max number of retry
|
52
|
-
raise Fasp::Error,
|
52
|
+
raise Fasp::Error, "Maximum number of retry reached (#{@parameters[:iter_max]})" if remaining_resumes <= 0
|
53
53
|
else
|
54
54
|
# give one chance only to non retryable errors
|
55
55
|
unless remaining_resumes.eql?(@parameters[:iter_max])
|
56
|
-
Log.log.error('non-retryable error')
|
56
|
+
Log.log.error('non-retryable error'.red.blink)
|
57
57
|
raise e
|
58
58
|
end
|
59
59
|
end
|
@@ -61,7 +61,7 @@ module Aspera
|
|
61
61
|
|
62
62
|
# take this retry in account
|
63
63
|
remaining_resumes -= 1
|
64
|
-
Log.log.warn{"
|
64
|
+
Log.log.warn{"Resuming in #{sleep_seconds} seconds (retry left:#{remaining_resumes})"}
|
65
65
|
|
66
66
|
# wait a bit before retrying, maybe network condition will be better
|
67
67
|
sleep(sleep_seconds)
|
@@ -17,11 +17,12 @@ module Aspera
|
|
17
17
|
}.freeze
|
18
18
|
# reserved tag for Aspera
|
19
19
|
TAG_RESERVED = 'aspera'
|
20
|
-
# define constants for enums of parameters: <parameter>_<enum>, e.g. CIPHER_AES_128
|
21
|
-
Aspera::Fasp::Parameters.description.each do |
|
22
|
-
next unless
|
23
|
-
|
24
|
-
|
20
|
+
# define constants for enums of parameters: <parameter>_<enum>, e.g. CIPHER_AES_128, DIRECTION_SEND, ...
|
21
|
+
Aspera::Fasp::Parameters.description.each do |name, description|
|
22
|
+
next unless description[:enum].is_a?(Array)
|
23
|
+
TransferSpec.const_set("#{name.to_s.upcase}_ENUM_VALUES", description[:enum])
|
24
|
+
description[:enum].each do |enum|
|
25
|
+
TransferSpec.const_set("#{name.to_s.upcase}_#{enum.upcase.gsub(/[^A-Z0-9]/, '_')}", enum.freeze)
|
25
26
|
end
|
26
27
|
end
|
27
28
|
class << self
|
@@ -40,7 +41,7 @@ module Aspera
|
|
40
41
|
return case tspec['direction']
|
41
42
|
when DIRECTION_SEND then :upload
|
42
43
|
when DIRECTION_RECEIVE then :download
|
43
|
-
else raise
|
44
|
+
else raise "Error: upload or download only, not #{tspec['direction']} (#{tspec['direction'].class})"
|
44
45
|
end
|
45
46
|
end
|
46
47
|
end
|
data/lib/aspera/fasp/uri.rb
CHANGED
@@ -1,14 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# cspell:words httpport targetrate minrate bwcap createpath lockpolicy lockminrate faspe
|
4
|
+
|
3
5
|
require 'aspera/log'
|
6
|
+
require 'aspera/rest'
|
4
7
|
require 'aspera/command_line_builder'
|
5
8
|
|
6
9
|
module Aspera
|
7
10
|
module Fasp
|
8
11
|
# translates a "faspe:" URI (used in Faspex 4) into transfer spec hash
|
9
12
|
class Uri
|
10
|
-
|
11
|
-
|
13
|
+
SCHEME = 'faspe'
|
14
|
+
def initialize(fasp_link)
|
15
|
+
@fasp_uri = URI.parse(fasp_link.gsub(' ', '%20'))
|
12
16
|
# TODO: check scheme is faspe
|
13
17
|
end
|
14
18
|
|
@@ -18,32 +22,30 @@ module Aspera
|
|
18
22
|
result_ts['remote_user'] = @fasp_uri.user
|
19
23
|
result_ts['ssh_port'] = @fasp_uri.port
|
20
24
|
result_ts['paths'] = [{'source' => URI.decode_www_form_component(@fasp_uri.path)}]
|
21
|
-
# faspex does not encode trailing base64
|
25
|
+
# faspex does not encode trailing base64 padding, fix that to be able to decode properly
|
22
26
|
fixed_query = @fasp_uri.query.gsub(/(=+)$/){|x|'%3D' * x.length}
|
23
27
|
|
24
|
-
|
25
|
-
name = i[0]
|
26
|
-
value = i[1]
|
28
|
+
Rest.decode_query(fixed_query).each do |name, value|
|
27
29
|
case name
|
28
|
-
when 'cookie'
|
29
|
-
when 'token'
|
30
|
-
when 'sshfp'
|
31
|
-
when 'policy'
|
32
|
-
when 'httpport'
|
33
|
-
when 'targetrate'
|
34
|
-
when 'minrate'
|
35
|
-
when 'port'
|
36
|
-
when 'bwcap'
|
37
|
-
when 'enc'
|
38
|
-
when 'tags64'
|
39
|
-
when 'createpath'
|
40
|
-
when 'fallback'
|
41
|
-
when 'lockpolicy'
|
30
|
+
when 'cookie' then result_ts['cookie'] = value
|
31
|
+
when 'token' then result_ts['token'] = value
|
32
|
+
when 'sshfp' then result_ts['sshfp'] = value
|
33
|
+
when 'policy' then result_ts['rate_policy'] = value
|
34
|
+
when 'httpport' then result_ts['http_fallback_port'] = value.to_i
|
35
|
+
when 'targetrate' then result_ts['target_rate_kbps'] = value.to_i
|
36
|
+
when 'minrate' then result_ts['min_rate_kbps'] = value.to_i
|
37
|
+
when 'port' then result_ts['fasp_port'] = value.to_i
|
38
|
+
when 'bwcap' then result_ts['target_rate_cap_kbps'] = value.to_i
|
39
|
+
when 'enc' then result_ts['cipher'] = value.gsub(/^aes/, 'aes-').gsub(/cfb$/, '-cfb').gsub(/gcm$/, '-gcm').gsub(/--/, '-')
|
40
|
+
when 'tags64' then result_ts['tags'] = JSON.parse(Base64.strict_decode64(value))
|
41
|
+
when 'createpath' then result_ts['create_dir'] = CommandLineBuilder.yes_to_true(value)
|
42
|
+
when 'fallback' then result_ts['http_fallback'] = CommandLineBuilder.yes_to_true(value)
|
43
|
+
when 'lockpolicy' then result_ts['lock_rate_policy'] = CommandLineBuilder.yes_to_true(value)
|
42
44
|
when 'lockminrate' then result_ts['lock_min_rate'] = CommandLineBuilder.yes_to_true(value)
|
43
|
-
when 'auth'
|
44
|
-
when 'v'
|
45
|
-
when 'protect'
|
46
|
-
else
|
45
|
+
when 'auth' then Log.log.debug{"ignoring #{name}=#{value}"} # Not used (yes/no)
|
46
|
+
when 'v' then Log.log.debug{"ignoring #{name}=#{value}"} # rubocop:disable Lint/DuplicateBranch Not used (2)
|
47
|
+
when 'protect' then Log.log.debug{"ignoring #{name}=#{value}"} # rubocop:disable Lint/DuplicateBranch TODO: what is this ?
|
48
|
+
else Log.log.warn{"URI parameter ignored: #{name} = #{value}"}
|
47
49
|
end
|
48
50
|
end
|
49
51
|
return result_ts
|
data/lib/aspera/faspex_gw.rb
CHANGED
@@ -68,9 +68,9 @@ module Aspera
|
|
68
68
|
faspex_pkg_parameters = JSON.parse(request.body)
|
69
69
|
Log.log.debug{"faspex pkg create parameters=#{faspex_pkg_parameters}"}
|
70
70
|
faspex_package_create_result =
|
71
|
-
if @app_api.
|
71
|
+
if @app_api.class.name.eql?('Aspera::AoC')
|
72
72
|
faspex4_send_to_aoc(faspex_pkg_parameters)
|
73
|
-
elsif @app_api.
|
73
|
+
elsif @app_api.class.name.eql?('Aspera::Rest')
|
74
74
|
faspex4_send_to_faspex5(faspex_pkg_parameters)
|
75
75
|
else
|
76
76
|
raise "No such adapter: #{@app_api.class}"
|
@@ -13,7 +13,7 @@ module Aspera
|
|
13
13
|
def initialize(server, parameters)
|
14
14
|
raise 'parameters must be Hash' unless parameters.is_a?(Hash)
|
15
15
|
@parameters = parameters.symbolize_keys
|
16
|
-
Log.dump(:
|
16
|
+
Log.log.debug{Log.dump(:post_proc_parameters, @parameters)}
|
17
17
|
raise "unexpected key in parameters config: only: #{ALLOWED_PARAMETERS.join(', ')}" if @parameters.keys.any?{|k|!ALLOWED_PARAMETERS.include?(k)}
|
18
18
|
@parameters[:script_folder] ||= '.'
|
19
19
|
@parameters[:fail_on_error] ||= false
|
@@ -44,7 +44,7 @@ module Aspera
|
|
44
44
|
script_path = File.join(@parameters[:script_folder], script_file)
|
45
45
|
Log.log.debug{"script=#{script_path}"}
|
46
46
|
webhook_parameters = JSON.parse(request.body)
|
47
|
-
Log.dump(:webhook_parameters, webhook_parameters)
|
47
|
+
Log.log.debug{Log.dump(:webhook_parameters, webhook_parameters)}
|
48
48
|
# env expects only strings
|
49
49
|
environment = webhook_parameters.each_with_object({}) { |(k, v), h| h[k] = v.to_s }
|
50
50
|
post_proc_pid = Process.spawn(environment, [script_path, script_path])
|
data/lib/aspera/hash_ext.rb
CHANGED
@@ -2,11 +2,21 @@
|
|
2
2
|
|
3
3
|
class ::Hash
|
4
4
|
def deep_merge(second)
|
5
|
-
merge(second){|_key, v1, v2|Hash
|
5
|
+
merge(second){|_key, v1, v2|v1.is_a?(Hash) && v2.is_a?(Hash) ? v1.deep_merge(v2) : v2}
|
6
6
|
end
|
7
7
|
|
8
8
|
def deep_merge!(second)
|
9
|
-
merge!(second){|_key, v1, v2|Hash
|
9
|
+
merge!(second){|_key, v1, v2|v1.is_a?(Hash) && v2.is_a?(Hash) ? v1.deep_merge!(v2) : v2}
|
10
|
+
end
|
11
|
+
|
12
|
+
def deep_do(memory=nil, &block)
|
13
|
+
each do |key, value|
|
14
|
+
if value.is_a?(Hash)
|
15
|
+
value.deep_do(memory, &block)
|
16
|
+
else
|
17
|
+
yield(self, key, value, memory)
|
18
|
+
end
|
19
|
+
end
|
10
20
|
end
|
11
21
|
end
|
12
22
|
|
@@ -14,8 +24,8 @@ end
|
|
14
24
|
unless Hash.method_defined?(:transform_keys)
|
15
25
|
class Hash
|
16
26
|
def transform_keys
|
17
|
-
|
18
|
-
|
27
|
+
raise 'missing block' unless block_given?
|
28
|
+
return each_with_object({}){|(k, v), memo|memo[yield(k)] = v}
|
19
29
|
end
|
20
30
|
end
|
21
31
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# cspell:ignore blankslate
|
4
|
+
|
5
|
+
require 'aspera/rest_error_analyzer'
|
6
|
+
require 'blankslate'
|
7
|
+
|
8
|
+
Aspera::RestErrorAnalyzer.instance.add_simple_handler(name: 'JSON RPC', path: %w[error message], always: true)
|
9
|
+
|
10
|
+
module Aspera
|
11
|
+
# a very simple JSON RPC client
|
12
|
+
class JsonRpcClient < BlankSlate
|
13
|
+
JSON_RPC_VERSION = '2.0'
|
14
|
+
reveal :instance_variable_get
|
15
|
+
reveal :inspect
|
16
|
+
reveal :to_s
|
17
|
+
|
18
|
+
def initialize(api, namespace = nil)
|
19
|
+
super()
|
20
|
+
@api = api
|
21
|
+
@namespace = namespace
|
22
|
+
@request_id = 0
|
23
|
+
end
|
24
|
+
|
25
|
+
def respond_to_missing?(sym, include_private = false)
|
26
|
+
true
|
27
|
+
end
|
28
|
+
|
29
|
+
def method_missing(method, *args, &block)
|
30
|
+
args = args.first if args.size == 1 && args.first.is_a?(Hash)
|
31
|
+
data = @api.create('', {
|
32
|
+
jsonrpc: JSON_RPC_VERSION,
|
33
|
+
method: "#{@namespace}#{method}",
|
34
|
+
params: args,
|
35
|
+
id: @request_id += 1
|
36
|
+
})[:data]
|
37
|
+
raise 'response shall be Hash' unless data.is_a?(Hash)
|
38
|
+
raise 'bad version in response' unless data['jsonrpc'] == JSON_RPC_VERSION
|
39
|
+
raise 'missing id in response' unless data.key?('id')
|
40
|
+
raise 'both error and response' if data.key?('error') && data.key?('result')
|
41
|
+
raise 'bad error response' unless
|
42
|
+
!data.key?('error') ||
|
43
|
+
data['error'].is_a?(Hash) &&
|
44
|
+
data['error']['code'].is_a?(Integer) &&
|
45
|
+
data['error']['message'].is_a?(String)
|
46
|
+
return data['result']
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|