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.
- 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
|