aspera-cli 4.2.1 → 4.2.2
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 +187 -127
- data/docs/Makefile +4 -4
- data/docs/README.erb.md +206 -38
- data/docs/test_env.conf +2 -1
- data/examples/faspex4.rb +28 -17
- data/lib/aspera/cli/main.rb +47 -19
- data/lib/aspera/cli/plugins/aoc.rb +5 -13
- data/lib/aspera/cli/plugins/config.rb +47 -30
- data/lib/aspera/cli/plugins/faspex.rb +90 -52
- data/lib/aspera/cli/plugins/faspex5.rb +8 -7
- data/lib/aspera/cli/plugins/preview.rb +29 -25
- data/lib/aspera/cli/transfer_agent.rb +71 -44
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/command_line_builder.rb +49 -31
- data/lib/aspera/fasp/parameters.rb +57 -87
- data/lib/aspera/fasp/parameters.yaml +531 -0
- data/lib/aspera/fasp/uri.rb +1 -1
- data/lib/aspera/oauth.rb +4 -4
- data/lib/aspera/sync.rb +40 -35
- metadata +17 -3
- data/docs/transfer_spec.html +0 -99
data/docs/README.erb.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[comment1]: # (Do not edit this README.md, edit docs/README.erb.md, for details, read docs/README.md)
|
|
2
2
|
<%
|
|
3
3
|
# check that required env vars exist, and files
|
|
4
|
-
%w{EXENAME GEMSPEC INCL_USAGE INCL_COMMANDS INCL_ASESSION
|
|
4
|
+
%w{EXENAME GEMSPEC INCL_USAGE INCL_COMMANDS INCL_ASESSION INCL_DIR_GEM}.each do |e|
|
|
5
5
|
raise "missing env var #{e}" unless ENV.has_key?(e)
|
|
6
6
|
raise "missing file #{ENV[e]}" unless File.exist?(ENV[e]) or !e.start_with?('INCL_') #_
|
|
7
7
|
end
|
|
@@ -14,6 +14,29 @@ prsts='['+opprst+'s](#lprt)'
|
|
|
14
14
|
prstt=opprst.capitalize # in title
|
|
15
15
|
gemspec=Gem::Specification::load(ENV["GEMSPEC"]) or raise "error loading #{ENV["GEMSPEC"]}"
|
|
16
16
|
geminstadd=gemspec.version.to_s.match(/\.[^0-9]/)?' --pre':''
|
|
17
|
+
$LOAD_PATH.unshift(ENV["INCL_DIR_GEM"])
|
|
18
|
+
require 'aspera/fasp/parameters'
|
|
19
|
+
def spec_table
|
|
20
|
+
r='<table><tr><th>Field</th><th>Type</th>'
|
|
21
|
+
Aspera::Fasp::Parameters::SUPPORTED_AGENTS_SHORT.each do |c|
|
|
22
|
+
r << '<th>'<<c.to_s.upcase<<'</th>'
|
|
23
|
+
end
|
|
24
|
+
r << '<th>Description</th></tr>'
|
|
25
|
+
Aspera::Fasp::Parameters.man_table.each do |p|
|
|
26
|
+
p[:description] << (p[:description].empty? ? '' : "\n") << "(" << p[:cli] << ")" unless p[:cli].to_s.empty?
|
|
27
|
+
p.delete(:cli)
|
|
28
|
+
p.keys.each{|c|p[c]=' ' if p[c].to_s.empty?}
|
|
29
|
+
p[:description].gsub!("\n",'<br/>')
|
|
30
|
+
p[:type].gsub!(',','<br/>')
|
|
31
|
+
r << '<tr><td>'<<p[:name]<<'</td><td>'<<p[:type]<<'</td>'
|
|
32
|
+
Aspera::Fasp::Parameters::SUPPORTED_AGENTS_SHORT.each do |c|
|
|
33
|
+
r << '<td>'<<p[c]<<'</td>'
|
|
34
|
+
end
|
|
35
|
+
r << '<td>'<<p[:description]<<'</td></tr>'
|
|
36
|
+
end
|
|
37
|
+
r << '</table>'
|
|
38
|
+
return r
|
|
39
|
+
end
|
|
17
40
|
-%>
|
|
18
41
|
# <%=tool%> : Command Line Interface for IBM Aspera products
|
|
19
42
|
|
|
@@ -1283,11 +1306,31 @@ A [_transfer-spec_](#transferspec) is a Hash table, so it is described on the co
|
|
|
1283
1306
|
|
|
1284
1307
|
## <a name="transferparams"></a>Transfer Parameters
|
|
1285
1308
|
|
|
1286
|
-
All standard _transfer-spec_ parameters can be
|
|
1287
|
-
|
|
1288
|
-
|
|
1309
|
+
All standard _transfer-spec_ parameters can be speficied.
|
|
1310
|
+
[_transfer-spec_](#transferspec) can also be saved/overridden in the config file.
|
|
1311
|
+
|
|
1312
|
+
References:
|
|
1313
|
+
|
|
1314
|
+
* [Aspera Node API Documentation](https://developer.ibm.com/apis/catalog?search=%22aspera%20node%20api%22)→/opt/transfers
|
|
1315
|
+
* [Aspera Transfer SDK Documentation](https://developer.ibm.com/apis/catalog?search=%22aspera%20transfer%20sdk%22)→Guides→API Ref→Transfer Spec V1
|
|
1316
|
+
|
|
1317
|
+
Parameters can be displayed with commands:
|
|
1318
|
+
|
|
1319
|
+
```
|
|
1320
|
+
$ <%=cmd%> config ascp spec
|
|
1321
|
+
$ <%=cmd%> config ascp spec --select=@json:'{"f":"Y"}' --fields=-f,n,c
|
|
1322
|
+
```
|
|
1323
|
+
|
|
1324
|
+
Columns:
|
|
1325
|
+
|
|
1326
|
+
* D=Direct (local `ascp` execution)
|
|
1327
|
+
* N=Node API
|
|
1328
|
+
* C=Connect Client
|
|
1329
|
+
* arg=`ascp` argument or environment variable
|
|
1289
1330
|
|
|
1290
|
-
|
|
1331
|
+
Fields with EX_ prefix are extensions to transfer agent `direct`. (only in <%=tool%>).
|
|
1332
|
+
|
|
1333
|
+
<%= spec_table %>
|
|
1291
1334
|
|
|
1292
1335
|
### Destination folder for transfers
|
|
1293
1336
|
|
|
@@ -1369,7 +1412,7 @@ Source files are located on "Aspera on cloud", when :
|
|
|
1369
1412
|
|
|
1370
1413
|
### <a name="multisession"></a>Support of multi-session
|
|
1371
1414
|
|
|
1372
|
-
Multi session, i.e. starting a transfer of a file set using multiple sessions is supported on "direct" and "node" agents, not yet on connect.
|
|
1415
|
+
Multi session, i.e. starting a transfer of a file set using multiple sessions (one ascp process per session) is supported on "direct" and "node" agents, not yet on connect.
|
|
1373
1416
|
|
|
1374
1417
|
* when agent=node :
|
|
1375
1418
|
|
|
@@ -1390,6 +1433,7 @@ shall be preferred.
|
|
|
1390
1433
|
|
|
1391
1434
|
Multi-session spawn is done by <%=tool%>.
|
|
1392
1435
|
|
|
1436
|
+
When multi-session is used, one separate UDP port is used per session (refer to `ascp` manual page).
|
|
1393
1437
|
|
|
1394
1438
|
### Examples
|
|
1395
1439
|
|
|
@@ -1665,7 +1709,7 @@ To activate default use of JWT authentication for <%=tool%> using the <%=prst%>,
|
|
|
1665
1709
|
|
|
1666
1710
|
* change auth method to JWT
|
|
1667
1711
|
* provide location of private key
|
|
1668
|
-
* provide username to login as (
|
|
1712
|
+
* provide username to login as (OAuth "subject")
|
|
1669
1713
|
|
|
1670
1714
|
Execute:
|
|
1671
1715
|
|
|
@@ -2076,19 +2120,40 @@ The activity app can be queried with:
|
|
|
2076
2120
|
$ <%=cmd%> aoc admin analytics transfers
|
|
2077
2121
|
```
|
|
2078
2122
|
|
|
2079
|
-
It can also support filters and send notification
|
|
2123
|
+
It can also support filters and send notification using option `notif_to`. a template is defined using option `notif_template` :
|
|
2124
|
+
|
|
2125
|
+
`mytemplate.erb`:
|
|
2126
|
+
|
|
2127
|
+
```
|
|
2128
|
+
From: <%='<'%>%=from_name%> <<%='<'%>%=from_email%>>
|
|
2129
|
+
To: <<%='<'%>%=ev['user_email']%>>
|
|
2130
|
+
Subject: <%='<'%>%=ev['files_completed']%> files received
|
|
2131
|
+
|
|
2132
|
+
Dear <%='<'%>%=ev[:user_email.to_s]%>,
|
|
2133
|
+
We received <%='<'%>%=ev['files_completed']%> files for a total of <%='<'%>%=ev['transferred_bytes']%> bytes, starting with file:
|
|
2134
|
+
<%='<'%>%=ev['content']%>
|
|
2135
|
+
|
|
2136
|
+
Thank you.
|
|
2137
|
+
```
|
|
2138
|
+
The environment provided contains the following additional variable:
|
|
2139
|
+
|
|
2140
|
+
* ev : all details on the transfer event
|
|
2141
|
+
|
|
2142
|
+
Example:
|
|
2080
2143
|
|
|
2081
2144
|
```
|
|
2082
|
-
$ <%=cmd%> aoc admin analytics transfers --once-only=yes --lock-port=
|
|
2145
|
+
$ <%=cmd%> aoc admin analytics transfers --once-only=yes --lock-port=12345 \
|
|
2083
2146
|
--query=@json:'{"status":"completed","direction":"receive"}' \
|
|
2084
|
-
--
|
|
2147
|
+
--notif-to=active --notif-template=@file:mytemplate.erb
|
|
2085
2148
|
```
|
|
2086
2149
|
|
|
2150
|
+
Options:
|
|
2151
|
+
|
|
2087
2152
|
* `once_only` keep track of last date it was called, so next call will get only new events
|
|
2088
2153
|
* `query` filter (on API call)
|
|
2089
2154
|
* `notify` send an email as specified by template, this could be places in a file with the `@file` modifier.
|
|
2090
2155
|
|
|
2091
|
-
Note this must not be executed in less than 5 minutes because the analytics interface accepts only a period of time between 5 minutes and 6 months.
|
|
2156
|
+
Note this must not be executed in less than 5 minutes because the analytics interface accepts only a period of time between 5 minutes and 6 months. The period is [date of previous execution]..[now].
|
|
2092
2157
|
|
|
2093
2158
|
## Using specific transfer ports
|
|
2094
2159
|
|
|
@@ -2339,11 +2404,15 @@ $ <%=cmd%> node access_key create --value=@json:'{"id":"eudemo-sedemo","secret":
|
|
|
2339
2404
|
|
|
2340
2405
|
3 authentication methods are supported:
|
|
2341
2406
|
|
|
2342
|
-
* boot
|
|
2343
|
-
* web
|
|
2344
2407
|
* jwt
|
|
2408
|
+
* web
|
|
2409
|
+
* boot
|
|
2345
2410
|
|
|
2346
|
-
For
|
|
2411
|
+
For JWT, create an API client in Faspex with jwt support, and use: `--auth=jwt`.
|
|
2412
|
+
|
|
2413
|
+
For web method, create an API client in Faspex, and use: --auth=web
|
|
2414
|
+
|
|
2415
|
+
For boot method: (will be removed in future)
|
|
2347
2416
|
|
|
2348
2417
|
* open a browser
|
|
2349
2418
|
* start developer mode
|
|
@@ -2356,25 +2425,57 @@ Use it as password and use `--auth=boot`.
|
|
|
2356
2425
|
$ <%=cmd%> conf id f5boot update --url=https://localhost/aspera/faspex --auth=boot --password=ABC.DEF.GHI...
|
|
2357
2426
|
```
|
|
2358
2427
|
|
|
2359
|
-
For web method, create an API client in Faspex, and use: --auth=web
|
|
2360
|
-
|
|
2361
|
-
For JWT, create an API client in Faspex with jwt supporot, and use: --auth=jwt
|
|
2362
|
-
as of beta£3 this does not allow regular users.
|
|
2363
|
-
|
|
2364
2428
|
Ready to use Faspex5 with CLI.
|
|
2365
2429
|
|
|
2366
|
-
Once the graphical registration form exist, ther bootstrap method can be removed.
|
|
2367
|
-
|
|
2368
2430
|
# Plugin: IBM Aspera Faspex (4.x)
|
|
2369
2431
|
|
|
2370
2432
|
Notes:
|
|
2371
2433
|
|
|
2372
|
-
*
|
|
2373
|
-
*
|
|
2434
|
+
* The command "v4" requires the use of APIv4, refer to the Faspex Admin manual on how to activate.
|
|
2435
|
+
* For full details on Faspex API, refer to: [Reference on Developer Site](https://developer.ibm.com/apis/catalog/?search=faspex)
|
|
2436
|
+
|
|
2437
|
+
## Listing Packages
|
|
2438
|
+
|
|
2439
|
+
Command: `faspex package list`
|
|
2440
|
+
|
|
2441
|
+
### Option `box`
|
|
2442
|
+
|
|
2443
|
+
By default it looks in box `inbox`, but the following boxes are also supported: `archive` and `sent`, selected with option `box`.
|
|
2444
|
+
|
|
2445
|
+
### Option `recipient`
|
|
2446
|
+
|
|
2447
|
+
A user can receive a package because the recipient is:
|
|
2448
|
+
|
|
2449
|
+
* the user himself (default)
|
|
2450
|
+
* the user is part of a dropbox or a workgroup (select with option `recipient` with value `*<name of WG or DB>`
|
|
2451
|
+
|
|
2452
|
+
### Option `query`
|
|
2453
|
+
|
|
2454
|
+
As inboxes may be large, it is possible to use the following query parameters:
|
|
2455
|
+
|
|
2456
|
+
* `count` : (native) number items in one API call (default=0, equivalent to 10)
|
|
2457
|
+
* `page` : (native) id of page in call (default=0)
|
|
2458
|
+
* `startIndex` : (native) index of item to start, default=0, oldest index=0
|
|
2459
|
+
* `max` : maximum number of items
|
|
2460
|
+
* `pmax` : maximum number of pages
|
|
2461
|
+
|
|
2462
|
+
(SQL query is `LIMIT <startIndex>, <count>`)
|
|
2463
|
+
|
|
2464
|
+
The API is listed in [Faspex 4 API Reference](https://developer.ibm.com/apis/catalog/?search=faspex) under "Services (API v.3)".
|
|
2465
|
+
|
|
2466
|
+
If no parameter `max` or `pmax` is provided, then all packages will be listed in the inbox, which result in paged API calls (using parameter: `count` and `page`). By default page is `0` (`10`), it can be increased to have less calls.
|
|
2467
|
+
|
|
2468
|
+
### Example
|
|
2469
|
+
|
|
2470
|
+
```
|
|
2471
|
+
$ <%=cmd%> faspex package list --box=inbox --recipient='*my_dropbox' --query=@json:'{"max":20,"pmax":2,"count":20}'
|
|
2472
|
+
```
|
|
2473
|
+
|
|
2474
|
+
List a maximum of 20 items grouped by pages of 20, with maximum 2 pages in received box (inbox) when received in dropbox `*my_dropbox`.
|
|
2374
2475
|
|
|
2375
2476
|
## Receiving a Package
|
|
2376
2477
|
|
|
2377
|
-
The command is `package recv`, possible
|
|
2478
|
+
The command is `package recv`, possible methods are:
|
|
2378
2479
|
|
|
2379
2480
|
* provide a package id with option `id`
|
|
2380
2481
|
* provide a public link with option `link`
|
|
@@ -2391,7 +2492,7 @@ If the package is in a specific dropbox, add option `recipient` for both the `li
|
|
|
2391
2492
|
$ <%=cmd%> faspex package list --recipient='*thedropboxname'
|
|
2392
2493
|
```
|
|
2393
2494
|
|
|
2394
|
-
|
|
2495
|
+
if `id` is set to `ALL`, then all packages are downloaded, and if option `once_only`is used, then a persistency file is created to keep track of already downloaded packages.
|
|
2395
2496
|
|
|
2396
2497
|
## Sending a Package
|
|
2397
2498
|
|
|
@@ -2410,7 +2511,19 @@ Additional optional parameters in `delivery_info`:
|
|
|
2410
2511
|
* Package Note: : `"note":"note this and that"`
|
|
2411
2512
|
* Package Metadata: `"metadata":{"Meta1":"Val1","Meta2":"Val2"}`
|
|
2412
2513
|
|
|
2413
|
-
##
|
|
2514
|
+
## Email notification on transfer
|
|
2515
|
+
|
|
2516
|
+
Like for any transfer, a notification can be sent by email using parameters: `notif_to` and `notif_template` .
|
|
2517
|
+
|
|
2518
|
+
Example:
|
|
2519
|
+
|
|
2520
|
+
```
|
|
2521
|
+
$ <%=cmd%> faspex package send --delivery-info=@json:'{"title":"test pkg 1","recipients":["aspera.user1@gmail.com"]}' ~/Documents/Samples/200KB.1 --notif-to=aspera.user1@gmail.com --notif-template=@ruby:'%Q{From: <%='<'%>%=from_name%> <<%='<'%>%=from_email%>>\nTo: <<%='<'%>%=to%>>\nSubject: Package sent: <%='<'%>%=ts["tags"]["aspera"]["faspex"]["metadata"]["_pkg_name"]%> files received\n\nTo user: <%='<'%>%=ts["tags"]["aspera"]["faspex"]["recipients"].first["email"]%>}'
|
|
2522
|
+
```
|
|
2523
|
+
|
|
2524
|
+
In this example the notification template is directly provided on command line. Package information placed in the message are directly taken from the tags in transfer spec. The template can be placed in a file using modifier: `@file:`
|
|
2525
|
+
|
|
2526
|
+
## Operation on dropboxes
|
|
2414
2527
|
|
|
2415
2528
|
Example:
|
|
2416
2529
|
|
|
@@ -2828,14 +2941,14 @@ Aspera CLI can send email, for that setup SMTP configuration. This is done with
|
|
|
2828
2941
|
The `smtp` option is a hash table (extended value) with the following fields:
|
|
2829
2942
|
<table>
|
|
2830
2943
|
<tr><th>field</th><th>default</th><th>example</th><th>description</th></tr>
|
|
2831
|
-
<tr><td
|
|
2832
|
-
<tr><td
|
|
2833
|
-
<tr><td
|
|
2834
|
-
<tr><td
|
|
2835
|
-
<tr><td
|
|
2836
|
-
<tr><td
|
|
2837
|
-
<tr><td
|
|
2838
|
-
<tr><td
|
|
2944
|
+
<tr><td>`server`</td><td>-</td><td>smtp.gmail.com</td><td>SMTP server address</td></tr>
|
|
2945
|
+
<tr><td>`tls`</td><td>true</td><td>false</td><td>use of TLS</td></tr>
|
|
2946
|
+
<tr><td>`port`</td><td>587 for tls<br/>25 else</td><td>587</td><td>port for service</td></tr>
|
|
2947
|
+
<tr><td>`domain`</td><td>domain of server</td><td>gmail.com</td><td>email domain of user</td></tr>
|
|
2948
|
+
<tr><td>`username`</td><td>-</td><td>john@example.com</td><td>user to authenticate on SMTP server, leave empty for open auth.</td></tr>
|
|
2949
|
+
<tr><td>`password`</td><td>-</td><td>MyP@ssword</td><td>password for above username</td></tr>
|
|
2950
|
+
<tr><td>`from_email`</td><td>username if defined</td><td>laurent.martin.l@gmail.com</td><td>address used if received replies</td></tr>
|
|
2951
|
+
<tr><td>`from_name`</td><td>same as email</td><td>John Wayne</td><td>display name of sender</td></tr>
|
|
2839
2952
|
</table>
|
|
2840
2953
|
|
|
2841
2954
|
## Example of configuration:
|
|
@@ -2865,13 +2978,52 @@ $ <%=cmd%> config id cli_default set smtp @val:@preset:smtp_google
|
|
|
2865
2978
|
$ <%=cmd%> config id default set config cli_default
|
|
2866
2979
|
```
|
|
2867
2980
|
|
|
2981
|
+
## Email templates
|
|
2982
|
+
|
|
2983
|
+
Sent emails are built using a template that uses the [ERB](https://www.tutorialspoint.com/ruby/eruby.htm) syntax.
|
|
2984
|
+
|
|
2985
|
+
The template is the full SMTP message, including headers.
|
|
2986
|
+
|
|
2987
|
+
The following variables are defined by default:
|
|
2988
|
+
|
|
2989
|
+
* from_name
|
|
2990
|
+
* from_email
|
|
2991
|
+
* to
|
|
2992
|
+
|
|
2993
|
+
Other variables are defined depending on context.
|
|
2994
|
+
|
|
2868
2995
|
## Test
|
|
2869
2996
|
|
|
2870
2997
|
Check settings with `smtp_settings` command. Send test email with `email_test`.
|
|
2871
2998
|
|
|
2872
2999
|
```
|
|
2873
3000
|
$ <%=cmd%> config --smtp=@preset:smtp_google smtp
|
|
2874
|
-
$ <%=cmd%> config --smtp=@preset:smtp_google email sample.dest@example.com
|
|
3001
|
+
$ <%=cmd%> config --smtp=@preset:smtp_google email --notif-to=sample.dest@example.com
|
|
3002
|
+
```
|
|
3003
|
+
|
|
3004
|
+
## Notifications for transfer status
|
|
3005
|
+
|
|
3006
|
+
An e-mail notification can be sent upon transfer success and failure (one email per transfer job, one job being possibly multi session, and possibly after retry).
|
|
3007
|
+
|
|
3008
|
+
To activate, use option `notif_to`.
|
|
3009
|
+
|
|
3010
|
+
A default e-mail template is used, but it can be overriden with option `notif_template`.
|
|
3011
|
+
|
|
3012
|
+
The environment provided contains the following additional variables:
|
|
3013
|
+
|
|
3014
|
+
* subject
|
|
3015
|
+
* body
|
|
3016
|
+
* global_transfer_status
|
|
3017
|
+
* ts
|
|
3018
|
+
|
|
3019
|
+
Example of template:
|
|
3020
|
+
|
|
3021
|
+
```
|
|
3022
|
+
From: <%='<'%>%=from_name%> <<%='<'%>%=from_email%>>
|
|
3023
|
+
To: <<%='<'%>%=to%>>
|
|
3024
|
+
Subject: <%='<'%>%=subject%>
|
|
3025
|
+
|
|
3026
|
+
Transfer is: <%='<'%>%=global_transfer_status%>
|
|
2875
3027
|
```
|
|
2876
3028
|
|
|
2877
3029
|
# Tool: `asession`
|
|
@@ -2982,7 +3134,7 @@ Interesting ascp features are found in its arguments: (see ascp manual):
|
|
|
2982
3134
|
Note that:
|
|
2983
3135
|
|
|
2984
3136
|
* <%=tool%> takes transfer parameters exclusively as a transfer_spec, with `--ts` parameter.
|
|
2985
|
-
* not all native ascp arguments are available as standard transfer_spec parameters
|
|
3137
|
+
* most, but not all native ascp arguments are available as standard transfer_spec parameters
|
|
2986
3138
|
* native ascp arguments can be provided with the [_transfer-spec_](#transferspec) parameter: EX_ascp_args (array), only for the "local" transfer agent (not connect or node)
|
|
2987
3139
|
|
|
2988
3140
|
### server side and configuration
|
|
@@ -3081,6 +3233,18 @@ So, it evolved into <%=tool%>:
|
|
|
3081
3233
|
|
|
3082
3234
|
* <%= gemspec.version.to_s %>
|
|
3083
3235
|
|
|
3236
|
+
* new: `faspex package list` retrieves the whole list, not just first page
|
|
3237
|
+
* new: support web based auth to aoc and faspex 5 using HTTPS, new dependency on gem `webrick`
|
|
3238
|
+
* new: the error "Remote host is not who we expected" displays a special remediation message
|
|
3239
|
+
* new: `conf ascp spec` displays supported transfer spec
|
|
3240
|
+
* new: options `notif_to` and `notif_template` to send email notifications on transfer (and other events)
|
|
3241
|
+
* fix: space character in `faspe:` url are precent encoded if needed
|
|
3242
|
+
* fix: `preview scan`: if file_id is unknown, ignore and continue scan
|
|
3243
|
+
* change: for commands that potentially execute several transfers (`package recv --id=ALL`), if one transfer fails then <%=tool%> exits with code 1 (instead of zero=success)
|
|
3244
|
+
* change: (break) option `notify` or `aoc` replaced with `notif_to` and `notif_template`
|
|
3245
|
+
|
|
3246
|
+
* 4.2.1
|
|
3247
|
+
|
|
3084
3248
|
* new: command `faspex package recv` supports link of type: `faspe:`
|
|
3085
3249
|
* new: command `faspex package recv` supports option `recipient` to specify dropbox with leading `*`
|
|
3086
3250
|
|
|
@@ -3503,13 +3667,17 @@ You may either install the suggested Gems, or remove your ed25519 key from your
|
|
|
3503
3667
|
|
|
3504
3668
|
## Error "Remote host is not who we expected"
|
|
3505
3669
|
|
|
3506
|
-
`ascp`
|
|
3670
|
+
Cause: `ascp` >= 4.x checks fingerprint of highest server host key, including ECDSA. `ascp` < 4.0 (3.9.6 and earlier) support only to RSA level (and ignore ECDSA presented by server). `aspera.conf` supports a single fingerprint.
|
|
3671
|
+
|
|
3672
|
+
Workaround on client side: To ignore the certificate (SSH fingerprint) add option on client side (this option can also be added permanently to the config file):
|
|
3507
3673
|
|
|
3508
3674
|
```
|
|
3509
3675
|
--ts=@json:'{"sshfp":null}'
|
|
3510
3676
|
```
|
|
3511
3677
|
|
|
3512
|
-
|
|
3678
|
+
Workaround on server side: Either remove the fingerprint from `aspera.conf`, or keep only RSA host keys in `sshd_config`.
|
|
3679
|
+
|
|
3680
|
+
References: ES-1944 in release notes of 4.1 and to [HSTS admin manual section "Configuring Transfer Server Authentication With a Host-Key Fingerprint"](https://www.ibm.com/docs/en/ahts/4.2?topic=upgrades-configuring-ssh-server).
|
|
3513
3681
|
|
|
3514
3682
|
## Miscelaneous
|
|
3515
3683
|
|
data/docs/test_env.conf
CHANGED
|
@@ -5,7 +5,7 @@ default:
|
|
|
5
5
|
config: cli_default
|
|
6
6
|
aoc: tst_aoc1
|
|
7
7
|
faspex: tst_faspex
|
|
8
|
-
faspex5:
|
|
8
|
+
faspex5: tst_faspex5
|
|
9
9
|
shares: tst_shares_1
|
|
10
10
|
shares2: tst_shares2
|
|
11
11
|
node: tst_node
|
|
@@ -65,6 +65,7 @@ tst_faspex5:
|
|
|
65
65
|
client_secret: your value here
|
|
66
66
|
private_key: your value here
|
|
67
67
|
username: your value here
|
|
68
|
+
password: your value here
|
|
68
69
|
tst_shares:
|
|
69
70
|
url: your value here
|
|
70
71
|
username: your value here
|
data/examples/faspex4.rb
CHANGED
|
@@ -1,29 +1,37 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
+
# find Faspex API here: https://developer.ibm.com/apis/catalog/?search=faspex
|
|
3
|
+
# this example makes use of class Aspera::Rest for REST calls, alternatively class RestClient of gem rest-client could be used
|
|
4
|
+
# this example makes use of class Aspera::Fasp::Local for transfers, alternatively the official "Transfer SDK" could be used
|
|
5
|
+
# Aspera SDK can be downloaded with: `ascli conf ascp install` , it installs in $HOME/.aspera/ascli/sdk
|
|
2
6
|
require 'aspera/rest'
|
|
3
7
|
require 'aspera/log'
|
|
4
8
|
require 'aspera/fasp/local'
|
|
5
|
-
require 'aspera/cli/listener/line_dump'
|
|
6
|
-
require 'aspera/cli/extended_value'
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
tmpdir=ENV['tmp']||Dir.tmpdir || '.'
|
|
11
|
+
|
|
12
|
+
# Set high log level for the example, decrease to :warn usually
|
|
9
13
|
Aspera::Log.instance.level=:debug
|
|
10
14
|
|
|
11
|
-
#
|
|
15
|
+
# Set folder where SDK is installed (mandatory)
|
|
12
16
|
# (if ascp is not there, the lib will try to find in usual locations)
|
|
13
|
-
|
|
17
|
+
# (if data files are not there, they will be created)
|
|
18
|
+
Aspera::Fasp::Installation.instance.folder = tmpdir
|
|
14
19
|
|
|
15
20
|
if ! ARGV.length.eql?(3)
|
|
16
|
-
Aspera::Log.log.error("
|
|
21
|
+
Aspera::Log.log.error("Wrong number of args: #{ARGV.length}")
|
|
17
22
|
Aspera::Log.log.error("Usage: #{$0} <faspex URL> <faspex username> <faspex password>")
|
|
18
23
|
Aspera::Log.log.error("Example: #{$0} https://faspex.com/aspera/faspex john p@sSw0rd")
|
|
19
24
|
Process.exit(1)
|
|
20
25
|
end
|
|
21
26
|
|
|
22
|
-
faspex_url=ARGV[0]
|
|
27
|
+
faspex_url=ARGV[0] # typically: https://faspex.example.com/aspera/faspex
|
|
23
28
|
faspex_user=ARGV[1]
|
|
24
29
|
faspex_pass=ARGV[2]
|
|
25
30
|
|
|
26
|
-
#
|
|
31
|
+
# comment out this if certificate is valid, keep line to ignore certificate
|
|
32
|
+
Aspera::Rest.insecure=true
|
|
33
|
+
|
|
34
|
+
# 1: Faspex 4 API v3
|
|
27
35
|
#---------------
|
|
28
36
|
|
|
29
37
|
# create REST API object
|
|
@@ -35,34 +43,36 @@ api_v3=Aspera::Rest.new({
|
|
|
35
43
|
:password => faspex_pass
|
|
36
44
|
}})
|
|
37
45
|
|
|
46
|
+
# very simple api call
|
|
38
47
|
api_v3.read('me')
|
|
39
48
|
|
|
40
49
|
# 2: send a package
|
|
41
50
|
#---------------
|
|
42
51
|
|
|
43
52
|
# create a sample file to send
|
|
44
|
-
file_to_send='
|
|
53
|
+
file_to_send=File.join(tmpdir,'myfile.bin')
|
|
45
54
|
File.open(file_to_send, "w") {|f| f.write("sample data") }
|
|
46
55
|
# package creation parameters
|
|
47
56
|
package_create_params={'delivery'=>{'title'=>'test package','recipients'=>['aspera.user1@gmail.com'],'sources'=>[{'paths'=>[file_to_send]}]}}
|
|
48
57
|
pkg_created=api_v3.create('send',package_create_params)[:data]
|
|
49
|
-
# get transfer specification
|
|
58
|
+
# get transfer specification (normally: only one)
|
|
50
59
|
transfer_spec=pkg_created['xfer_sessions'].first
|
|
51
60
|
# set paths of files to send
|
|
52
|
-
transfer_spec['paths']=['source'=>file_to_send]
|
|
61
|
+
transfer_spec['paths']=[{'source'=>file_to_send}]
|
|
53
62
|
# get the local agent (i.e. ascp)
|
|
54
|
-
|
|
55
|
-
# disable ascp output on stdout
|
|
56
|
-
|
|
63
|
+
transfer_client=Aspera::Fasp::Local.new
|
|
64
|
+
# disable ascp output on stdout (optional)
|
|
65
|
+
transfer_client.quiet=true
|
|
57
66
|
# start transfer (asynchronous)
|
|
58
|
-
job_id=
|
|
59
|
-
|
|
67
|
+
job_id=transfer_client.start_transfer(transfer_spec)
|
|
68
|
+
# wait for all transfer completion (for the example)
|
|
69
|
+
result=transfer_client.wait_for_transfers_completion
|
|
60
70
|
# notify of any transfer error
|
|
61
71
|
result.select{|i|!i.eql?(:success)}.each do |e|
|
|
62
72
|
Aspera::Log.log.error("A transfer error occured: #{e.message}")
|
|
63
73
|
end
|
|
64
74
|
|
|
65
|
-
#
|
|
75
|
+
# 3: Faspex 4 API v4
|
|
66
76
|
#---------------
|
|
67
77
|
api_v4=Aspera::Rest.new({
|
|
68
78
|
:base_url => faspex_url+'/api',
|
|
@@ -75,4 +85,5 @@ api_v4=Aspera::Rest.new({
|
|
|
75
85
|
:scope => 'admin'
|
|
76
86
|
}})
|
|
77
87
|
|
|
88
|
+
# Use it. Note that Faspex 4 API v4 is totally different from Faspex 4 v3 APIs, see ref on line 2
|
|
78
89
|
Aspera::Log.dump('users',api_v4.read('users')[:data])
|
data/lib/aspera/cli/main.rb
CHANGED
|
@@ -21,15 +21,17 @@ module Aspera
|
|
|
21
21
|
private
|
|
22
22
|
# name of application, also foldername where config is stored
|
|
23
23
|
PROGRAM_NAME = 'ascli'
|
|
24
|
+
# name of the containing gem, same as in <gem name>.gemspec
|
|
24
25
|
GEM_NAME = 'aspera-cli'
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
HELP_URL = "http://www.rubydoc.info/gems/#{GEM_NAME}"
|
|
27
|
+
GEM_URL = "https://rubygems.org/gems/#{GEM_NAME}"
|
|
28
|
+
SRC_URL = "https://github.com/IBM/aspera-cli"
|
|
29
|
+
STATUS_FIELD = 'status'
|
|
28
30
|
|
|
31
|
+
private_constant :PROGRAM_NAME,:GEM_NAME,:HELP_URL,:GEM_URL
|
|
29
32
|
# =============================================================
|
|
30
33
|
# Parameter handlers
|
|
31
34
|
#
|
|
32
|
-
|
|
33
35
|
def option_insecure; Rest.insecure ; end
|
|
34
36
|
|
|
35
37
|
def option_insecure=(value); Rest.insecure = value; end
|
|
@@ -40,20 +42,19 @@ module Aspera
|
|
|
40
42
|
|
|
41
43
|
# minimum initialization
|
|
42
44
|
def initialize(argv)
|
|
43
|
-
# first thing : manage debug level (allows debugging
|
|
45
|
+
# first thing : manage debug level (allows debugging of option parser)
|
|
44
46
|
early_debug_setup(argv)
|
|
47
|
+
# compare $0 with expected name
|
|
45
48
|
current_prog_name=File.basename($PROGRAM_NAME)
|
|
46
49
|
unless current_prog_name.eql?(PROGRAM_NAME)
|
|
47
50
|
@plugin_env[:formater].display_message(:error,"#{"WARNING".bg_red.blink.gray} Please use '#{PROGRAM_NAME}' instead of '#{current_prog_name}', '#{current_prog_name}' will be removed in a future version")
|
|
48
51
|
end
|
|
49
|
-
# overriding parameters on transfer spec
|
|
50
52
|
@option_help=false
|
|
51
53
|
@bash_completion=false
|
|
52
54
|
@option_show_config=false
|
|
55
|
+
# environment provided to plugin for various capabilities
|
|
53
56
|
@plugin_env={}
|
|
54
|
-
|
|
55
|
-
@gem_url='https://rubygems.org/gems/'+GEM_NAME
|
|
56
|
-
# give command line arguments to option manager (no parsing)
|
|
57
|
+
# find out application main folder
|
|
57
58
|
app_main_folder=ENV[conf_dir_env_var]
|
|
58
59
|
# if env var undefined or empty
|
|
59
60
|
if app_main_folder.nil? or app_main_folder.empty?
|
|
@@ -61,20 +62,21 @@ module Aspera
|
|
|
61
62
|
raise CliError,"Home folder does not exist: #{user_home_folder}. Check your user environment or use #{conf_dir_env_var}." unless Dir.exist?(user_home_folder)
|
|
62
63
|
app_main_folder=File.join(user_home_folder,Plugins::Config::ASPERA_HOME_FOLDER_NAME,PROGRAM_NAME)
|
|
63
64
|
end
|
|
65
|
+
# give command line arguments to option manager (no parsing)
|
|
64
66
|
@plugin_env[:options]=@opt_mgr=Manager.new(PROGRAM_NAME,argv,app_banner())
|
|
65
67
|
@plugin_env[:formater]=Formater.new(@plugin_env[:options])
|
|
66
68
|
Rest.user_agent=PROGRAM_NAME
|
|
67
|
-
#
|
|
69
|
+
# declare and parse global options
|
|
68
70
|
init_global_options()
|
|
69
71
|
# secret manager
|
|
70
72
|
@plugin_env[:secret]=Aspera::Secrets.new
|
|
71
73
|
# the Config plugin adds the @preset parser
|
|
72
|
-
@plugin_env[:config]=Plugins::Config.new(@plugin_env,PROGRAM_NAME
|
|
74
|
+
@plugin_env[:config]=Plugins::Config.new(@plugin_env,PROGRAM_NAME,HELP_URL,Aspera::Cli::VERSION,app_main_folder)
|
|
73
75
|
# the TransferAgent plugin may use the @preset parser
|
|
74
76
|
@plugin_env[:transfer]=TransferAgent.new(@plugin_env)
|
|
75
|
-
Log.log.debug('created plugin env'.red)
|
|
76
77
|
# set application folder for modules
|
|
77
78
|
@plugin_env[:persistency]=PersistencyFolder.new(File.join(@plugin_env[:config].main_folder,'persist_store'))
|
|
79
|
+
Log.log.debug('plugin env created'.red)
|
|
78
80
|
Oauth.persist_mgr=@plugin_env[:persistency]
|
|
79
81
|
Fasp::Parameters.file_list_folder=File.join(@plugin_env[:config].main_folder,'filelists')
|
|
80
82
|
Aspera::RestErrorAnalyzer.instance.log_file=File.join(@plugin_env[:config].main_folder,'rest_exceptions.log')
|
|
@@ -88,9 +90,9 @@ module Aspera
|
|
|
88
90
|
banner << "\t#{PROGRAM_NAME} COMMANDS [OPTIONS] [ARGS]\n"
|
|
89
91
|
banner << "\nDESCRIPTION\n"
|
|
90
92
|
banner << "\tUse Aspera application to perform operations on command line.\n"
|
|
91
|
-
banner << "\tDocumentation and examples: #{
|
|
93
|
+
banner << "\tDocumentation and examples: #{GEM_URL}\n"
|
|
92
94
|
banner << "\texecute: #{PROGRAM_NAME} conf doc\n"
|
|
93
|
-
banner << "\tor visit: #{
|
|
95
|
+
banner << "\tor visit: #{HELP_URL}\n"
|
|
94
96
|
banner << "\nENVIRONMENT VARIABLES\n"
|
|
95
97
|
banner << "\t#{conf_dir_env_var} config folder, default: $HOME/#{Plugins::Config::ASPERA_HOME_FOLDER_NAME}/#{PROGRAM_NAME}\n"
|
|
96
98
|
banner << "\t#any option can be set as an environment variable, refer to the manual\n"
|
|
@@ -188,6 +190,8 @@ module Aspera
|
|
|
188
190
|
|
|
189
191
|
protected
|
|
190
192
|
|
|
193
|
+
# env var name to override the app's main folder
|
|
194
|
+
# default main folder is $HOME/<vendor main app folder>/<program name>
|
|
191
195
|
def conf_dir_env_var
|
|
192
196
|
return "#{PROGRAM_NAME}_home".upcase
|
|
193
197
|
end
|
|
@@ -219,10 +223,28 @@ module Aspera
|
|
|
219
223
|
return Main.result_nothing
|
|
220
224
|
end
|
|
221
225
|
|
|
226
|
+
# used when one command executes several transfer jobs (each job being possibly multi session)
|
|
227
|
+
# @param status_table [Array] [{STATUS_FIELD=>[status array],...},...]
|
|
228
|
+
# each element has a key STATUS_FIELD which contains the result of possibly mulmtiple sessions
|
|
229
|
+
def self.result_transfer_multiple(status_table)
|
|
230
|
+
global_status=:success
|
|
231
|
+
# transform status into string and find if there was problem
|
|
232
|
+
status_table.each do |item|
|
|
233
|
+
worst=TransferAgent.session_status(item[STATUS_FIELD])
|
|
234
|
+
global_status=worst unless worst.eql?(:success)
|
|
235
|
+
item[STATUS_FIELD]=item[STATUS_FIELD].map{|i|i.to_s}.join(',')
|
|
236
|
+
end
|
|
237
|
+
raise global_status unless global_status.eql?(:success)
|
|
238
|
+
return {:type=>:object_list,:data=>status_table}
|
|
239
|
+
end
|
|
240
|
+
|
|
222
241
|
# this is the main function called by initial script just after constructor
|
|
223
242
|
def process_command_line
|
|
224
243
|
Log.log.debug('process_command_line')
|
|
244
|
+
# catch exception information , if any
|
|
225
245
|
exception_info=nil
|
|
246
|
+
# false if command shall not be executed ("once_only")
|
|
247
|
+
execute_command=true
|
|
226
248
|
begin
|
|
227
249
|
# find plugins, shall be after parse! ?
|
|
228
250
|
@plugin_env[:config].add_plugins_from_lookup_folders
|
|
@@ -264,11 +286,12 @@ module Aspera
|
|
|
264
286
|
Log.log.debug("Opening lock port #{lock_port.to_i}")
|
|
265
287
|
@tcp_server=TCPServer.new('127.0.0.1',lock_port.to_i)
|
|
266
288
|
rescue => e
|
|
267
|
-
|
|
289
|
+
execute_command=false
|
|
290
|
+
Log.log.warn("Another instance is already running (#{e.message}).")
|
|
268
291
|
end
|
|
269
292
|
end
|
|
270
|
-
# execute and display
|
|
271
|
-
@plugin_env[:formater].display_results(command_plugin.execute_action)
|
|
293
|
+
# execute and display (if not exclusive execution)
|
|
294
|
+
@plugin_env[:formater].display_results(command_plugin.execute_action) if execute_command
|
|
272
295
|
# finish
|
|
273
296
|
@plugin_env[:transfer].shutdown
|
|
274
297
|
rescue CliBadArgument => e; exception_info=[e,'Argument',:usage]
|
|
@@ -286,10 +309,15 @@ module Aspera
|
|
|
286
309
|
unless exception_info.nil?
|
|
287
310
|
@plugin_env[:formater].display_message(:error,"ERROR:".bg_red.gray.blink+" "+exception_info[1]+": "+exception_info[0].message)
|
|
288
311
|
@plugin_env[:formater].display_message(:error,"Use '-h' option to get help.") if exception_info[2].eql?(:usage)
|
|
312
|
+
if exception_info.first.is_a?(Fasp::Error) and exception_info.first.message.eql?('Remote host is not who we expected')
|
|
313
|
+
@plugin_env[:formater].display_message(:error,"For this specific error, refer to:\n#{SRC_URL}#error-remote-host-is-not-who-we-expected\nAdd this to arguments:\n--ts=@json:'{\"sshfp\":null}'")
|
|
314
|
+
end
|
|
289
315
|
end
|
|
290
316
|
# 2- processing of command not processed (due to exception or bad command line)
|
|
291
|
-
|
|
292
|
-
@
|
|
317
|
+
if execute_command
|
|
318
|
+
@opt_mgr.final_errors.each do |msg|
|
|
319
|
+
@plugin_env[:formater].display_message(:error,"ERROR:".bg_red.gray.blink+" Argument: "+msg)
|
|
320
|
+
end
|
|
293
321
|
end
|
|
294
322
|
# 3- in case of error, fail the process status
|
|
295
323
|
unless exception_info.nil?
|