clever-tools 2.10.1 → 2.11.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.
- package/CHANGELOG.md +15 -11
- package/README.md +7 -4
- package/bin/clever.js +57 -53
- package/package.json +1 -1
- package/src/commands/addon.js +46 -2
- package/src/commands/database.js +10 -42
- package/src/get-output-format-option.js +23 -0
- package/src/models/accesslogs.js +3 -5
- package/src/models/addon.js +23 -15
- package/src/models/configuration.js +37 -40
- package/src/models/format-ng-table.js +10 -10
- package/src/models/ids-resolver.js +110 -0
- package/src/parsers.js +0 -9
package/CHANGELOG.md
CHANGED
|
@@ -2,10 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## Unrelease (????-??-??)
|
|
4
4
|
|
|
5
|
+
* skip preorder step on addon creation
|
|
6
|
+
* add `clever addon env` command
|
|
7
|
+
* improve implicit ID params (owner and add-on ID / real ID) for `clever database`
|
|
8
|
+
|
|
5
9
|
## 2.10.1 (2023-02-20)
|
|
6
10
|
|
|
7
11
|
* `clever database` command
|
|
8
|
-
* Improve output when trying
|
|
12
|
+
* Improve output when trying
|
|
9
13
|
* `clever database backups` command
|
|
10
14
|
* Improve output when there are no backups yet
|
|
11
15
|
* Fix command with personal orga
|
|
@@ -13,8 +17,8 @@
|
|
|
13
17
|
|
|
14
18
|
## 2.10.0 (2023-02-16)
|
|
15
19
|
|
|
16
|
-
* add `clever database backups DATABASE-ID` command to list backups of a database
|
|
17
|
-
* add `clever database backups download DATABASE-ID BACKUP-IP` command to download a backup
|
|
20
|
+
* add `clever database backups DATABASE-ID` command to list backups of a database
|
|
21
|
+
* add `clever database backups download DATABASE-ID BACKUP-IP` command to download a backup
|
|
18
22
|
* add `clever curl` so we can prefix any `curl` command with `clever` and benefit from the local oAuth v1 auth
|
|
19
23
|
|
|
20
24
|
## 2.10.0-beta.2 (2022-09-13)
|
|
@@ -55,7 +59,7 @@
|
|
|
55
59
|
|
|
56
60
|
* Fix linux-release-info usage in `clever diag`
|
|
57
61
|
|
|
58
|
-
## 2.7.0 (2020-08-20)
|
|
62
|
+
## 2.7.0 (2020-08-20)
|
|
59
63
|
|
|
60
64
|
* Improve `clever deploy` perfs in several cases (partial push, force push...)
|
|
61
65
|
* NOTE: Pushing a brand new repo is still slow in some situations
|
|
@@ -64,8 +68,8 @@
|
|
|
64
68
|
* `clever domain favourite` just displays the favourite domain (no prefix)
|
|
65
69
|
* `clever domain favourite set example.com` sets the favourite domain to `example.com`
|
|
66
70
|
* `clever domain favourite unset` unsets the favourite domain for this app
|
|
67
|
-
* Add a message while waiting for deploy to start `clever deploy` and `clever restart`
|
|
68
|
-
* Add shallow detection with appropriate error message for `clever deploy`
|
|
71
|
+
* Add a message while waiting for deploy to start `clever deploy` and `clever restart`
|
|
72
|
+
* Add shallow detection with appropriate error message for `clever deploy`
|
|
69
73
|
* Fix `clever status` typo in output (Clément Delafargue)
|
|
70
74
|
* Fix `clever env` error message when JSON input is incorrect (Jean Baptiste Noblot)
|
|
71
75
|
* Update dependencies
|
|
@@ -86,7 +90,7 @@ This is the one with the latest isomorphic-git!!!
|
|
|
86
90
|
* Add `clever config` command to configure application options
|
|
87
91
|
* Existing supported options: `name`, `description`, `zero-downtime`, `sticky-sessions` and `cancel-on-push`
|
|
88
92
|
* New supported option: `force-https`
|
|
89
|
-
* Add `--follow` to `clever deploy` and `clever restart` so you can continue to follow logs after the deployment is finished
|
|
93
|
+
* Add `--follow` to `clever deploy` and `clever restart` so you can continue to follow logs after the deployment is finished
|
|
90
94
|
* Fix #318 where `clever deploy` and `clever restart` would sometimes never exit
|
|
91
95
|
* We changed the way we detect when a deployment is finished
|
|
92
96
|
* Fix #304 where `clever logs` would run endlessly even when using `--before/--until`
|
|
@@ -94,7 +98,7 @@ This is the one with the latest isomorphic-git!!!
|
|
|
94
98
|
### Internals
|
|
95
99
|
|
|
96
100
|
* We completely removed our dependency to Bacon.js, goodbye old friend 😘
|
|
97
|
-
* `@clevercloud/client` was updated to `6.0.0` so we can use the new event based API for logs and events
|
|
101
|
+
* `@clevercloud/client` was updated to `6.0.0` so we can use the new event based API for logs and events
|
|
98
102
|
|
|
99
103
|
## 2.4.0 (2020-04-16)
|
|
100
104
|
|
|
@@ -249,7 +253,7 @@ These release were only created for some tests on our CI pipeline.
|
|
|
249
253
|
|
|
250
254
|
- Log error trace in --verbose mode
|
|
251
255
|
- Update deps (rename opn => open)
|
|
252
|
-
- Fix logs with `clever deploy` (update @clevercloud/client to 2.0.0-beta.1)
|
|
256
|
+
- Fix logs with `clever deploy` (update @clevercloud/client to 2.0.0-beta.1)
|
|
253
257
|
- Fix typo "connexion" => "connection" in logs and README
|
|
254
258
|
|
|
255
259
|
## 1.5.0-beta.5 (2019-08-01)
|
|
@@ -279,7 +283,7 @@ These release were only created for some tests on our CI pipeline.
|
|
|
279
283
|
- Ease testing for preprod with comments in config
|
|
280
284
|
- Update @clevercloud/client to 2.0.0-beta.0
|
|
281
285
|
|
|
282
|
-
## 1.5.0-beta.4 (2019-07-25)
|
|
286
|
+
## 1.5.0-beta.4 (2019-07-25)
|
|
283
287
|
|
|
284
288
|
- Fix --add-export option for `clever env`
|
|
285
289
|
|
|
@@ -381,7 +385,7 @@ These release were only created for some tests on our CI pipeline.
|
|
|
381
385
|
|
|
382
386
|
- Replace [nodegit](https://github.com/nodegit/nodegit) with [isomorphic-git](https://github.com/isomorphic-git/isomorphic-git)
|
|
383
387
|
- Add ESLint config with a big refactoring to go along
|
|
384
|
-
- Always use the npm `colors` package in safe mode: no global `String` pollution
|
|
388
|
+
- Always use the npm `colors` package in safe mode: no global `String` pollution
|
|
385
389
|
- Build, package and publish with a multibranch pipeline project on Jenkins
|
|
386
390
|
|
|
387
391
|
### Packaging & distribution
|
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@ If you are using a GNU/Linux distribution that uses `.deb` packages like Debian
|
|
|
39
39
|
|
|
40
40
|
```sh
|
|
41
41
|
curl -fsSL https://clever-tools.clever-cloud.com/gpg/cc-nexus-deb.public.gpg.key | gpg --dearmor -o /usr/share/keyrings/cc-nexus-deb.gpg
|
|
42
|
-
echo "deb [signed-by=/usr/share/keyrings/cc-nexus-deb.gpg] https://nexus.clever-cloud.com/repository/deb stable main" | tee -a /etc/apt/sources.list
|
|
42
|
+
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/cc-nexus-deb.gpg] https://nexus.clever-cloud.com/repository/deb stable main" | tee -a /etc/apt/sources.list
|
|
43
43
|
apt-get update
|
|
44
44
|
apt-get install clever-tools
|
|
45
45
|
```
|
|
@@ -51,7 +51,7 @@ NOTES:
|
|
|
51
51
|
* If you want access to the beta channel, you can use this in your `sources.list`:
|
|
52
52
|
|
|
53
53
|
```sh
|
|
54
|
-
echo "deb [signed-by=/usr/share/keyrings/cc-nexus-deb.gpg] https://nexus.clever-cloud.com/repository/deb-beta beta main" | tee -a /etc/apt/sources.list
|
|
54
|
+
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/cc-nexus-deb.gpg] https://nexus.clever-cloud.com/repository/deb-beta beta main" | tee -a /etc/apt/sources.list
|
|
55
55
|
```
|
|
56
56
|
|
|
57
57
|
#### CentOS/Fedora (.rpm)
|
|
@@ -252,7 +252,7 @@ Where `type` is one of:
|
|
|
252
252
|
- `php`: for PHP applications
|
|
253
253
|
- `play1`: for Play1 applications
|
|
254
254
|
- `play2`: for Play2 applications
|
|
255
|
-
- `python`: for python27 applications
|
|
255
|
+
- `python`: for python27 and python3 applications
|
|
256
256
|
- `ruby`: for ruby applications
|
|
257
257
|
- `rust`: for rust applications
|
|
258
258
|
- `sbt`: for applications launched with SBT
|
|
@@ -334,9 +334,12 @@ ElasticSearch drains use the Elastic bulk API. To match this endpoint, specify `
|
|
|
334
334
|
|
|
335
335
|
Datadog has two zones, EU and COM. An account on one zone is not available on the other, make sure to target the good EU or COM intake endpoint.
|
|
336
336
|
|
|
337
|
-
To create a [Datadog](https://docs.datadoghq.com/api/?lang=python#send-logs-over-http) drain, you just need to use:
|
|
337
|
+
To create a [Datadog](https://docs.datadoghq.com/api/?lang=python#send-logs-over-http) drain, you just need to use one of the following command depending on your zone:
|
|
338
338
|
|
|
339
339
|
```sh
|
|
340
|
+
# EU
|
|
341
|
+
clever drain create DatadogHTTP "https://http-intake.logs.datadoghq.eu/v1/input/<API_KEY>?ddsource=clevercloud&service=<SERVICE>&host=<HOST>"
|
|
342
|
+
# US
|
|
340
343
|
clever drain create DatadogHTTP "https://http-intake.logs.datadoghq.com/v1/input/<API_KEY>?ddsource=clevercloud&service=<SERVICE>&host=<HOST>"
|
|
341
344
|
```
|
|
342
345
|
|
package/bin/clever.js
CHANGED
|
@@ -13,12 +13,15 @@ if (process.argv.includes('--autocomplete-index')) {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
const cliparse = require('cliparse');
|
|
16
|
+
const cliparseCommands = require('cliparse/src/command.js');
|
|
16
17
|
const updateNotifier = require('update-notifier');
|
|
18
|
+
const _sortBy = require('lodash/sortBy.js');
|
|
17
19
|
|
|
18
20
|
const git = require('../src/models/git.js');
|
|
19
21
|
const Parsers = require('../src/parsers.js');
|
|
20
22
|
const handleCommandPromise = require('../src/command-promise-handler.js');
|
|
21
23
|
const Formatter = require('../src/models/format-string.js');
|
|
24
|
+
const { getOutputFormatOption } = require('../src/get-output-format-option.js');
|
|
22
25
|
|
|
23
26
|
// Exit cleanly if the program we pipe to exits abruptly
|
|
24
27
|
process.stdout.on('error', (error) => {
|
|
@@ -63,7 +66,6 @@ function lazyRequire (modulePath) {
|
|
|
63
66
|
};
|
|
64
67
|
}
|
|
65
68
|
|
|
66
|
-
const AccessLogs = lazyRequire('../src/models/accesslogs.js');
|
|
67
69
|
const Addon = lazyRequire('../src/models/addon.js');
|
|
68
70
|
const Application = lazyRequire('../src/models/application.js');
|
|
69
71
|
const ApplicationConfiguration = lazyRequire('../src/models/application_configuration.js');
|
|
@@ -89,7 +91,7 @@ function run () {
|
|
|
89
91
|
}),
|
|
90
92
|
appNameCreation: cliparse.argument('app-name', { description: 'Application name' }),
|
|
91
93
|
backupId: cliparse.argument('backup-id', { description: 'A Database backup ID (format: UUID)' }),
|
|
92
|
-
databaseId: cliparse.argument('database-id', { description: '
|
|
94
|
+
databaseId: cliparse.argument('database-id', { description: 'Any database ID (format: addon_UUID, postgresql_UUID, mysql_UUID, ...)' }),
|
|
93
95
|
drainId: cliparse.argument('drain-id', { description: 'Drain ID' }),
|
|
94
96
|
drainType: cliparse.argument('drain-type', {
|
|
95
97
|
description: 'Drain type',
|
|
@@ -127,16 +129,8 @@ function run () {
|
|
|
127
129
|
// OPTIONS
|
|
128
130
|
const opts = {
|
|
129
131
|
sourceableEnvVarsList: cliparse.flag('add-export', { description: 'Display sourceable env variables setting' }),
|
|
130
|
-
accesslogsFormat:
|
|
131
|
-
|
|
132
|
-
metavar: 'format',
|
|
133
|
-
parser: Parsers.accessLogsFormat,
|
|
134
|
-
default: 'simple',
|
|
135
|
-
description: 'Output format (one of simple, extended, clf or json)',
|
|
136
|
-
complete () {
|
|
137
|
-
return cliparse.autocomplete.words(AccessLogs('listAvailableFormats')());
|
|
138
|
-
},
|
|
139
|
-
}),
|
|
132
|
+
accesslogsFormat: getOutputFormatOption(['simple', 'extended', 'clf']),
|
|
133
|
+
addonEnvFormat: getOutputFormatOption(['shell']),
|
|
140
134
|
accesslogsFollow: cliparse.flag('follow', {
|
|
141
135
|
aliases: ['f'],
|
|
142
136
|
description: 'Display access logs continuously (ignores before/until, after/since)',
|
|
@@ -581,10 +575,16 @@ function run () {
|
|
|
581
575
|
description: 'List available addon providers',
|
|
582
576
|
commands: [addonShowProviderCommand],
|
|
583
577
|
}, addon('listProviders'));
|
|
578
|
+
const addonEnvCommand = cliparse.command('env', {
|
|
579
|
+
description: 'List the environment variables for an add-on',
|
|
580
|
+
options: [opts.addonEnvFormat],
|
|
581
|
+
args: [opts.addonId],
|
|
582
|
+
}, addon('env'));
|
|
583
|
+
|
|
584
584
|
const addonCommands = cliparse.command('addon', {
|
|
585
585
|
description: 'Manage addons',
|
|
586
586
|
options: [opts.orgaIdOrName],
|
|
587
|
-
commands: [addonCreateCommand, addonDeleteCommand, addonRenameCommand, addonProvidersCommand],
|
|
587
|
+
commands: [addonCreateCommand, addonDeleteCommand, addonRenameCommand, addonProvidersCommand, addonEnvCommand],
|
|
588
588
|
}, addon('list'));
|
|
589
589
|
|
|
590
590
|
// APPLICATIONS COMMAND
|
|
@@ -1011,7 +1011,7 @@ function run () {
|
|
|
1011
1011
|
const downloadBackupCommand = cliparse.command('download', {
|
|
1012
1012
|
description: 'Download a database backup',
|
|
1013
1013
|
args: [args.databaseId, args.backupId],
|
|
1014
|
-
options: [opts.
|
|
1014
|
+
options: [opts.output],
|
|
1015
1015
|
}, database('downloadBackups'));
|
|
1016
1016
|
const backupsCommand = cliparse.command('backups', {
|
|
1017
1017
|
description: 'List available database backups',
|
|
@@ -1030,51 +1030,55 @@ function run () {
|
|
|
1030
1030
|
console.info('clever database backups download');
|
|
1031
1031
|
});
|
|
1032
1032
|
|
|
1033
|
+
const commands = _sortBy([
|
|
1034
|
+
accesslogsCommand,
|
|
1035
|
+
activityCommand,
|
|
1036
|
+
addonCommands,
|
|
1037
|
+
appCreateCommand,
|
|
1038
|
+
applicationsCommand,
|
|
1039
|
+
appLinkCommand,
|
|
1040
|
+
appUnlinkCommand,
|
|
1041
|
+
cancelDeployCommand,
|
|
1042
|
+
configCommands,
|
|
1043
|
+
databaseCommand,
|
|
1044
|
+
deleteCommand,
|
|
1045
|
+
deployCommand,
|
|
1046
|
+
diagCommand,
|
|
1047
|
+
domainCommands,
|
|
1048
|
+
drainCommands,
|
|
1049
|
+
emailNotificationsCommand,
|
|
1050
|
+
envCommands,
|
|
1051
|
+
cliparseCommands.helpCommand,
|
|
1052
|
+
loginCommand,
|
|
1053
|
+
logoutCommand,
|
|
1054
|
+
logsCommand,
|
|
1055
|
+
makeDefaultCommand,
|
|
1056
|
+
// Not ready for stable release yet
|
|
1057
|
+
// networkGroupsCommand,
|
|
1058
|
+
// ngCommand,
|
|
1059
|
+
openCommand,
|
|
1060
|
+
consoleCommand,
|
|
1061
|
+
profileCommand,
|
|
1062
|
+
publishedConfigCommands,
|
|
1063
|
+
restartCommand,
|
|
1064
|
+
scaleCommand,
|
|
1065
|
+
serviceCommands,
|
|
1066
|
+
sshCommand,
|
|
1067
|
+
statusCommand,
|
|
1068
|
+
stopCommand,
|
|
1069
|
+
tcpRedirsCommands,
|
|
1070
|
+
versionCommand,
|
|
1071
|
+
webhooksCommand,
|
|
1072
|
+
], 'name');
|
|
1073
|
+
|
|
1033
1074
|
// CLI PARSER
|
|
1034
1075
|
const cliParser = cliparse.cli({
|
|
1035
1076
|
name: 'clever',
|
|
1036
1077
|
description: 'CLI tool to manage Clever Cloud data and products',
|
|
1037
1078
|
version: pkg.version,
|
|
1038
1079
|
options: [opts.verbose, opts.noUpdateNotifier],
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
activityCommand,
|
|
1042
|
-
addonCommands,
|
|
1043
|
-
appCreateCommand,
|
|
1044
|
-
applicationsCommand,
|
|
1045
|
-
appLinkCommand,
|
|
1046
|
-
appUnlinkCommand,
|
|
1047
|
-
cancelDeployCommand,
|
|
1048
|
-
configCommands,
|
|
1049
|
-
databaseCommand,
|
|
1050
|
-
deleteCommand,
|
|
1051
|
-
deployCommand,
|
|
1052
|
-
diagCommand,
|
|
1053
|
-
domainCommands,
|
|
1054
|
-
drainCommands,
|
|
1055
|
-
emailNotificationsCommand,
|
|
1056
|
-
envCommands,
|
|
1057
|
-
loginCommand,
|
|
1058
|
-
logoutCommand,
|
|
1059
|
-
logsCommand,
|
|
1060
|
-
makeDefaultCommand,
|
|
1061
|
-
// Not ready for stable release yet
|
|
1062
|
-
// networkGroupsCommand,
|
|
1063
|
-
// ngCommand,
|
|
1064
|
-
openCommand,
|
|
1065
|
-
consoleCommand,
|
|
1066
|
-
profileCommand,
|
|
1067
|
-
publishedConfigCommands,
|
|
1068
|
-
restartCommand,
|
|
1069
|
-
scaleCommand,
|
|
1070
|
-
serviceCommands,
|
|
1071
|
-
sshCommand,
|
|
1072
|
-
statusCommand,
|
|
1073
|
-
stopCommand,
|
|
1074
|
-
tcpRedirsCommands,
|
|
1075
|
-
versionCommand,
|
|
1076
|
-
webhooksCommand,
|
|
1077
|
-
],
|
|
1080
|
+
helpCommand: false,
|
|
1081
|
+
commands,
|
|
1078
1082
|
});
|
|
1079
1083
|
|
|
1080
1084
|
// Make sure argv[0] is always "node"
|
package/package.json
CHANGED
package/src/commands/addon.js
CHANGED
|
@@ -9,7 +9,11 @@ const formatTable = require('../format-table')();
|
|
|
9
9
|
const Logger = require('../logger.js');
|
|
10
10
|
const Organisation = require('../models/organisation.js');
|
|
11
11
|
const User = require('../models/user.js');
|
|
12
|
-
const { parseAddonOptions } = require('../models/addon.js');
|
|
12
|
+
const { parseAddonOptions, findOwnerId } = require('../models/addon.js');
|
|
13
|
+
const { getAllEnvVars } = require('@clevercloud/client/cjs/api/v2/addon.js');
|
|
14
|
+
const { sendToApi } = require('../models/send-to-api.js');
|
|
15
|
+
const { toNameEqualsValueString } = require('@clevercloud/client/cjs/utils/env-vars.js');
|
|
16
|
+
const { resolveAddonId } = require('../models/ids-resolver.js');
|
|
13
17
|
|
|
14
18
|
async function list (params) {
|
|
15
19
|
const { org: orgaIdOrName } = params.options;
|
|
@@ -57,7 +61,16 @@ async function create (params) {
|
|
|
57
61
|
Logger.println(`Addon ${name} (id: ${newAddon.id}) successfully created and linked to the application`);
|
|
58
62
|
}
|
|
59
63
|
else {
|
|
60
|
-
const newAddon = await Addon.create({
|
|
64
|
+
const newAddon = await Addon.create({
|
|
65
|
+
ownerId,
|
|
66
|
+
name,
|
|
67
|
+
providerName,
|
|
68
|
+
planName,
|
|
69
|
+
region,
|
|
70
|
+
skipConfirmation,
|
|
71
|
+
version,
|
|
72
|
+
addonOptions,
|
|
73
|
+
});
|
|
61
74
|
Logger.println(`Addon ${name} (id: ${newAddon.id}) successfully created`);
|
|
62
75
|
}
|
|
63
76
|
}
|
|
@@ -142,6 +155,36 @@ async function showProvider (params) {
|
|
|
142
155
|
});
|
|
143
156
|
}
|
|
144
157
|
|
|
158
|
+
async function env (params) {
|
|
159
|
+
|
|
160
|
+
const { org, format } = params.options;
|
|
161
|
+
const [addonIdOrRealId] = params.args;
|
|
162
|
+
|
|
163
|
+
const addonId = await resolveAddonId(addonIdOrRealId);
|
|
164
|
+
const ownerId = await findOwnerId(org, addonId);
|
|
165
|
+
|
|
166
|
+
const envFromAddon = await getAllEnvVars({ id: ownerId, addonId }).then(sendToApi);
|
|
167
|
+
|
|
168
|
+
switch (format) {
|
|
169
|
+
|
|
170
|
+
case 'json': {
|
|
171
|
+
const envFromAddonJson = Object.fromEntries(
|
|
172
|
+
envFromAddon.map(({ name, value }) => [name, value]),
|
|
173
|
+
);
|
|
174
|
+
Logger.println(JSON.stringify(envFromAddonJson, null, 2));
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
case 'shell':
|
|
179
|
+
Logger.println(toNameEqualsValueString(envFromAddon, { addExports: true }));
|
|
180
|
+
break;
|
|
181
|
+
|
|
182
|
+
case 'human':
|
|
183
|
+
default:
|
|
184
|
+
Logger.println(toNameEqualsValueString(envFromAddon, { addExports: false }));
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
145
188
|
module.exports = {
|
|
146
189
|
list,
|
|
147
190
|
create,
|
|
@@ -149,4 +192,5 @@ module.exports = {
|
|
|
149
192
|
rename,
|
|
150
193
|
listProviders,
|
|
151
194
|
showProvider,
|
|
195
|
+
env,
|
|
152
196
|
};
|
package/src/commands/database.js
CHANGED
|
@@ -5,20 +5,19 @@ const { getBackups } = require('@clevercloud/client/cjs/api/v2/backups.js');
|
|
|
5
5
|
const { println } = require('../logger.js');
|
|
6
6
|
const formatTable = require('../format-table')();
|
|
7
7
|
const superagent = require('superagent');
|
|
8
|
-
const { getSummary } = require('@clevercloud/client/cjs/api/v2/user.js');
|
|
9
8
|
const fs = require('fs');
|
|
9
|
+
const { findOwnerId } = require('../models/addon.js');
|
|
10
|
+
const { resolveRealId } = require('../models/ids-resolver.js');
|
|
10
11
|
|
|
11
12
|
async function listBackups (params) {
|
|
12
13
|
|
|
13
|
-
const [databaseId] = params.args;
|
|
14
14
|
const { org } = params.options;
|
|
15
|
+
const [addonIdOrRealId] = params.args;
|
|
15
16
|
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
throw new Error('organisation ID is mandatory');
|
|
19
|
-
}
|
|
17
|
+
const addonId = await resolveRealId(addonIdOrRealId);
|
|
18
|
+
const ownerId = await findOwnerId(org, addonId);
|
|
20
19
|
|
|
21
|
-
const backups = await getBackups({ ownerId, ref:
|
|
20
|
+
const backups = await getBackups({ ownerId, ref: addonId }).then(sendToApi);
|
|
22
21
|
|
|
23
22
|
if (backups.length === 0) {
|
|
24
23
|
println('There are no backups yet');
|
|
@@ -47,15 +46,13 @@ async function listBackups (params) {
|
|
|
47
46
|
|
|
48
47
|
async function downloadBackups (params) {
|
|
49
48
|
|
|
50
|
-
const [databaseId, backupId] = params.args;
|
|
51
49
|
const { org, output } = params.options;
|
|
50
|
+
const [addonIdOrRealId, backupId] = params.args;
|
|
52
51
|
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
throw new Error('organisation ID is mandatory');
|
|
56
|
-
}
|
|
52
|
+
const addonId = await resolveRealId(addonIdOrRealId);
|
|
53
|
+
const ownerId = await findOwnerId(org, addonId);
|
|
57
54
|
|
|
58
|
-
const backups = await getBackups({ ownerId, ref:
|
|
55
|
+
const backups = await getBackups({ ownerId, ref: addonId }).then(sendToApi);
|
|
59
56
|
const backup = backups.find((backup) => backup.backup_id === backupId);
|
|
60
57
|
|
|
61
58
|
if (backup == null) {
|
|
@@ -74,33 +71,4 @@ async function downloadBackups (params) {
|
|
|
74
71
|
process.stdout.write(res.body);
|
|
75
72
|
}
|
|
76
73
|
|
|
77
|
-
/**
|
|
78
|
-
* Try to get an ownerId from the API
|
|
79
|
-
* @param {*} org cliparse param's option for orga
|
|
80
|
-
* @param {String} databaseId the resource which belong to the owner we are looking for
|
|
81
|
-
* @returns the owner ID (or null if cannot be found)
|
|
82
|
-
*/
|
|
83
|
-
async function resolveOwnerId (org, databaseId) {
|
|
84
|
-
|
|
85
|
-
if (org != null && org.orga_name != null) {
|
|
86
|
-
return org.orga_name;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const summary = await getSummary().then(sendToApi);
|
|
90
|
-
|
|
91
|
-
const userHasAddon = summary.user.addons.some((addon) => addon.realId === databaseId);
|
|
92
|
-
if (userHasAddon) {
|
|
93
|
-
return summary.user.id;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
for (const orga of summary.organisations) {
|
|
97
|
-
const orgaHasAddon = orga.addons.some((addon) => addon.realId === databaseId);
|
|
98
|
-
if (orgaHasAddon) {
|
|
99
|
-
return orga.id;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
74
|
module.exports = { listBackups, downloadBackups };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const cliparse = require('cliparse');
|
|
2
|
+
|
|
3
|
+
function getOutputFormatOption (formats = []) {
|
|
4
|
+
const availableFormats = ['human', 'json', ...formats];
|
|
5
|
+
return cliparse.option('format', {
|
|
6
|
+
aliases: ['F'],
|
|
7
|
+
metavar: 'format',
|
|
8
|
+
parser: (format) => {
|
|
9
|
+
return availableFormats.includes(format)
|
|
10
|
+
? cliparse.parsers.success(format)
|
|
11
|
+
: cliparse.parsers.error('The output format must be one of ' + availableFormats.join(', '));
|
|
12
|
+
},
|
|
13
|
+
default: 'human',
|
|
14
|
+
description: `Output format (${availableFormats.join(', ')})`,
|
|
15
|
+
complete () {
|
|
16
|
+
return cliparse.autocomplete.words(availableFormats);
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = {
|
|
22
|
+
getOutputFormatOption,
|
|
23
|
+
};
|
package/src/models/accesslogs.js
CHANGED
|
@@ -2,12 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
const clfDate = require('clf-date');
|
|
4
4
|
|
|
5
|
-
function listAvailableFormats () {
|
|
6
|
-
return ['simple', 'extended', 'clf', 'json'];
|
|
7
|
-
}
|
|
8
|
-
|
|
9
5
|
function getFormatter (format, isAddon) {
|
|
10
6
|
switch (format.toLowerCase()) {
|
|
7
|
+
// "simple" is the legacy default, "human" is the new one
|
|
8
|
+
case 'human':
|
|
11
9
|
case 'simple':
|
|
12
10
|
return isAddon ? formatSimpleAddon : formatSimple;
|
|
13
11
|
case 'extended':
|
|
@@ -53,4 +51,4 @@ function formatCLFAddon (l) {
|
|
|
53
51
|
return `${l.ipS} - - [${clfDate(new Date(l.t))}] "- - -" - ${l.bOut}`;
|
|
54
52
|
}
|
|
55
53
|
|
|
56
|
-
module.exports = {
|
|
54
|
+
module.exports = { getFormatter };
|
package/src/models/addon.js
CHANGED
|
@@ -2,8 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
const application = require('@clevercloud/client/cjs/api/v2/application.js');
|
|
4
4
|
const autocomplete = require('cliparse').autocomplete;
|
|
5
|
-
const
|
|
6
|
-
|
|
5
|
+
const {
|
|
6
|
+
get: getAddon,
|
|
7
|
+
getAll: getAllAddons,
|
|
8
|
+
remove: removeAddon,
|
|
9
|
+
create: createAddon,
|
|
10
|
+
update: updateAddon,
|
|
11
|
+
} = require('@clevercloud/client/cjs/api/v2/addon.js');
|
|
7
12
|
const { getAllAddonProviders } = require('@clevercloud/client/cjs/api/v2/product.js');
|
|
8
13
|
const { getSummary } = require('@clevercloud/client/cjs/api/v2/user.js');
|
|
9
14
|
const { getAddonProvider } = require('@clevercloud/client/cjs/api/v4/addon-providers.js');
|
|
@@ -11,6 +16,7 @@ const { getAddonProvider } = require('@clevercloud/client/cjs/api/v4/addon-provi
|
|
|
11
16
|
const Interact = require('./interact.js');
|
|
12
17
|
const Logger = require('../logger.js');
|
|
13
18
|
const { sendToApi } = require('../models/send-to-api.js');
|
|
19
|
+
const { resolveOwnerId } = require('./ids-resolver.js');
|
|
14
20
|
|
|
15
21
|
function listProviders () {
|
|
16
22
|
return getAllAddonProviders({}).then(sendToApi);
|
|
@@ -167,19 +173,6 @@ async function create ({ ownerId, name, providerName, planName, region, skipConf
|
|
|
167
173
|
options: createOptions,
|
|
168
174
|
};
|
|
169
175
|
|
|
170
|
-
const result = await preorderAddon({ id: ownerId }, addonToCreate).then(sendToApi);
|
|
171
|
-
|
|
172
|
-
if (result.totalTTC > 0 && !skipConfirmation) {
|
|
173
|
-
result.lines.forEach(({ description, VAT, price }) => Logger.println(`${description}\tVAT: ${VAT}%\tPrice: ${price}€`));
|
|
174
|
-
Logger.println(`Total (without taxes): ${result.totalHT}€`);
|
|
175
|
-
Logger.println(colors.bold(`Total (with taxes): ${result.totalTTC}€`));
|
|
176
|
-
|
|
177
|
-
await Interact.confirm(
|
|
178
|
-
`You're about to pay ${result.totalTTC}€, confirm? (yes or no) `,
|
|
179
|
-
'No confirmation, aborting addon creation',
|
|
180
|
-
);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
176
|
return createAddon({ id: ownerId }, addonToCreate).then(sendToApi);
|
|
184
177
|
}
|
|
185
178
|
|
|
@@ -255,6 +248,20 @@ async function findById (addonId) {
|
|
|
255
248
|
throw new Error(`Could not find add-on with ID: ${addonId}`);
|
|
256
249
|
}
|
|
257
250
|
|
|
251
|
+
async function findOwnerId (org, addonId) {
|
|
252
|
+
|
|
253
|
+
if (org != null && org.orga_id != null) {
|
|
254
|
+
return org.orga_id;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const ownerId = await resolveOwnerId(addonId);
|
|
258
|
+
if (ownerId != null) {
|
|
259
|
+
return ownerId;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
throw new Error(`Add-on ${addonId} does not exist`);
|
|
263
|
+
}
|
|
264
|
+
|
|
258
265
|
function parseAddonOptions (options) {
|
|
259
266
|
if (options == null) {
|
|
260
267
|
return {};
|
|
@@ -288,6 +295,7 @@ module.exports = {
|
|
|
288
295
|
create,
|
|
289
296
|
delete: deleteAddon,
|
|
290
297
|
findById,
|
|
298
|
+
findOwnerId,
|
|
291
299
|
getProvider,
|
|
292
300
|
getProviderInfos,
|
|
293
301
|
link,
|
|
@@ -10,44 +10,16 @@ const xdg = require('xdg');
|
|
|
10
10
|
const Logger = require('../logger.js');
|
|
11
11
|
const env = commonEnv(Logger);
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
else {
|
|
18
|
-
return xdg.basedir.configPath('clever-cloud');
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function getConfigPath () {
|
|
23
|
-
const configDir = getConfigDir();
|
|
24
|
-
return path.resolve(configDir, 'clever-tools.json');
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async function isFile (path) {
|
|
28
|
-
try {
|
|
29
|
-
const pathStat = await fs.stat(path);
|
|
30
|
-
return pathStat.isFile();
|
|
31
|
-
}
|
|
32
|
-
catch (e) {
|
|
33
|
-
return false;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async function maybeMigrateFromLegacyConfigurationPath () {
|
|
38
|
-
// This used to be a file
|
|
39
|
-
const configDir = getConfigDir();
|
|
40
|
-
const legacyConfig = await isFile(configDir);
|
|
41
|
-
// If it is still a file, we replace it with a dir and move it inside
|
|
42
|
-
if (legacyConfig) {
|
|
43
|
-
const tmpConfigFile = `${configDir}.tmp`;
|
|
44
|
-
const configFile = getConfigPath();
|
|
13
|
+
const CONFIG_FILES = {
|
|
14
|
+
MAIN: 'clever-tools.json',
|
|
15
|
+
IDS_CACHE: 'ids-cache.json',
|
|
16
|
+
};
|
|
45
17
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
18
|
+
function getConfigPath (configFile) {
|
|
19
|
+
const configDir = (process.platform === 'win32')
|
|
20
|
+
? path.resolve(process.env.APPDATA, 'clever-cloud')
|
|
21
|
+
: xdg.basedir.configPath('clever-cloud');
|
|
22
|
+
return path.resolve(configDir, configFile);
|
|
51
23
|
}
|
|
52
24
|
|
|
53
25
|
async function loadOAuthConf () {
|
|
@@ -59,7 +31,6 @@ async function loadOAuthConf () {
|
|
|
59
31
|
};
|
|
60
32
|
}
|
|
61
33
|
Logger.debug('Load configuration from ' + conf.CONFIGURATION_FILE);
|
|
62
|
-
await maybeMigrateFromLegacyConfigurationPath();
|
|
63
34
|
try {
|
|
64
35
|
const rawFile = await fs.readFile(conf.CONFIGURATION_FILE);
|
|
65
36
|
return JSON.parse(rawFile);
|
|
@@ -82,6 +53,32 @@ async function writeOAuthConf (oauthData) {
|
|
|
82
53
|
}
|
|
83
54
|
}
|
|
84
55
|
|
|
56
|
+
async function loadIdsCache () {
|
|
57
|
+
const cachePath = getConfigPath(CONFIG_FILES.IDS_CACHE);
|
|
58
|
+
try {
|
|
59
|
+
const rawFile = await fs.readFile(cachePath);
|
|
60
|
+
return JSON.parse(rawFile);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
Logger.info(`Cannot load IDs cache from ${cachePath}\n${error.message}`);
|
|
64
|
+
return {
|
|
65
|
+
owners: {},
|
|
66
|
+
addons: {},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function writeIdsCache (ids) {
|
|
72
|
+
const cachePath = getConfigPath(CONFIG_FILES.IDS_CACHE);
|
|
73
|
+
const idsJson = JSON.stringify(ids);
|
|
74
|
+
try {
|
|
75
|
+
await fs.writeFile(cachePath, idsJson);
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
throw new Error(`Cannot write IDs cache to ${cachePath}\n${error.message}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
85
82
|
const conf = env.getOrElseAll({
|
|
86
83
|
API_HOST: 'https://api.clever-cloud.com',
|
|
87
84
|
// API_HOST: 'https://ccapi-preprod.cleverapps.io',
|
|
@@ -94,7 +91,7 @@ const conf = env.getOrElseAll({
|
|
|
94
91
|
OAUTH_CONSUMER_SECRET: 'MgVMqTr6fWlf2M0tkC2MXOnhfqBWDT',
|
|
95
92
|
SSH_GATEWAY: 'ssh@sshgateway-clevercloud-customers.services.clever-cloud.com',
|
|
96
93
|
|
|
97
|
-
CONFIGURATION_FILE: getConfigPath(),
|
|
94
|
+
CONFIGURATION_FILE: getConfigPath(CONFIG_FILES.MAIN),
|
|
98
95
|
CONSOLE_TOKEN_URL: 'https://console.clever-cloud.com/cli-oauth',
|
|
99
96
|
// CONSOLE_TOKEN_URL: 'https://next-console.cleverapps.io/cli-oauth',
|
|
100
97
|
|
|
@@ -102,4 +99,4 @@ const conf = env.getOrElseAll({
|
|
|
102
99
|
APP_CONFIGURATION_FILE: path.resolve('.', '.clever.json'),
|
|
103
100
|
});
|
|
104
101
|
|
|
105
|
-
module.exports = { conf, loadOAuthConf, writeOAuthConf };
|
|
102
|
+
module.exports = { conf, loadOAuthConf, writeOAuthConf, loadIdsCache, writeIdsCache };
|
|
@@ -42,7 +42,7 @@ const membersTableColumnLengths = [
|
|
|
42
42
|
48, /* id length */
|
|
43
43
|
12, /* type length */
|
|
44
44
|
48, /* label length */
|
|
45
|
-
|
|
45
|
+
110, /* domain-name length */
|
|
46
46
|
];
|
|
47
47
|
const formatMembersTable = formatNgTable(membersTableColumnLengths);
|
|
48
48
|
async function formatMembersLine (member, showAliases = false) {
|
|
@@ -71,23 +71,23 @@ async function printMembersTableHeader (naturalName = false) {
|
|
|
71
71
|
|
|
72
72
|
const peersTableColumnLengths = [
|
|
73
73
|
45, /* id length */
|
|
74
|
+
15, /* ip */
|
|
75
|
+
36, /* hostname */
|
|
74
76
|
12, /* type length */
|
|
75
77
|
14, /* endpoint type length */
|
|
76
|
-
|
|
77
|
-
24, /* hostname */
|
|
78
|
-
15, /* ip */
|
|
78
|
+
36, /* label length */
|
|
79
79
|
];
|
|
80
80
|
const formatPeersTable = formatNgTable(peersTableColumnLengths);
|
|
81
|
-
function formatPeersLine
|
|
82
|
-
const ip = (peer.endpoint.type === 'ServerEndpoint') ? peer.endpoint.ng_term.
|
|
81
|
+
function formatPeersLine(peer) {
|
|
82
|
+
const ip = (peer.endpoint.type === 'ServerEndpoint') ? peer.endpoint.ng_term.host : peer.endpoint.ng_ip;
|
|
83
83
|
return formatPeersTable([
|
|
84
84
|
[
|
|
85
85
|
Formatter.formatId(peer.id),
|
|
86
|
+
Formatter.formatIp(ip),
|
|
87
|
+
Formatter.formatString(peer.hostname, false),
|
|
86
88
|
Formatter.formatString(peer.type, false),
|
|
87
89
|
Formatter.formatString(peer.endpoint.type, false),
|
|
88
90
|
Formatter.formatString(peer.label, false),
|
|
89
|
-
Formatter.formatString(peer.hostname, false),
|
|
90
|
-
Formatter.formatIp(ip),
|
|
91
91
|
],
|
|
92
92
|
]);
|
|
93
93
|
};
|
|
@@ -95,11 +95,11 @@ function printPeersTableHeader () {
|
|
|
95
95
|
Logger.println(colors.bold(formatPeersTable([
|
|
96
96
|
[
|
|
97
97
|
'Peer ID',
|
|
98
|
+
'IP Address',
|
|
99
|
+
'Hostname',
|
|
98
100
|
'Peer Type',
|
|
99
101
|
'Endpoint Type',
|
|
100
102
|
'Label',
|
|
101
|
-
'Hostname',
|
|
102
|
-
'IP Address',
|
|
103
103
|
],
|
|
104
104
|
])));
|
|
105
105
|
printSeparator(peersTableColumnLengths);
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
const { getSummary } = require('@clevercloud/client/cjs/api/v2/user.js');
|
|
2
|
+
const { sendToApi } = require('./send-to-api.js');
|
|
3
|
+
const { loadIdsCache, writeIdsCache } = require('./configuration.js');
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
This system uses a simplified representation of the summary to expose IDs links:
|
|
7
|
+
|
|
8
|
+
* app ID => owner ID
|
|
9
|
+
* add-on ID => owner ID
|
|
10
|
+
* real add-on ID => owner ID
|
|
11
|
+
* add-on ID => real add-on ID
|
|
12
|
+
* real add-on ID => add-on ID
|
|
13
|
+
|
|
14
|
+
{
|
|
15
|
+
owners: {
|
|
16
|
+
[appid]: [ownerId],
|
|
17
|
+
[addonId]: [ownerId],
|
|
18
|
+
[realId]: [ownerId],
|
|
19
|
+
},
|
|
20
|
+
addons: {
|
|
21
|
+
[addonId]: { realId: [realId], addonId: [addonId] },
|
|
22
|
+
[realId]: { realId: [realId], addonId: [addonId] },
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
async function resolveOwnerId (id) {
|
|
28
|
+
return getIdFromCacheOrSummary((ids) => ids.owners[id]);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function resolveAddonId (id) {
|
|
32
|
+
|
|
33
|
+
const addonId = await getIdFromCacheOrSummary((ids) => {
|
|
34
|
+
return (ids.addons[id] != null) ? ids.addons[id].addonId : null;
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if (addonId != null) {
|
|
38
|
+
return addonId;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
throw new Error(`Add-on ${id} does not exist`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function resolveRealId (id) {
|
|
45
|
+
|
|
46
|
+
const realId = await getIdFromCacheOrSummary((ids) => {
|
|
47
|
+
return (ids.addons[id] != null) ? ids.addons[id].realId : null;
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
if (realId != null) {
|
|
51
|
+
return realId;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
throw new Error(`Add-on ${id} does not exist foo`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function getIdFromCacheOrSummary (callback) {
|
|
58
|
+
|
|
59
|
+
const idsFromCache = await loadIdsCache();
|
|
60
|
+
const idFromCache = callback(idsFromCache);
|
|
61
|
+
if (idFromCache != null) {
|
|
62
|
+
return idFromCache;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const idsFromSummary = await getIdsFromSummary();
|
|
66
|
+
await writeIdsCache(idsFromSummary);
|
|
67
|
+
|
|
68
|
+
const idFromSummary = callback(idsFromSummary);
|
|
69
|
+
if (idFromSummary != null) {
|
|
70
|
+
return idFromSummary;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function getIdsFromSummary () {
|
|
77
|
+
|
|
78
|
+
const ids = {
|
|
79
|
+
owners: {},
|
|
80
|
+
addons: {},
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const summary = await getSummary().then(sendToApi);
|
|
84
|
+
|
|
85
|
+
const owners = [
|
|
86
|
+
summary.user,
|
|
87
|
+
...summary.organisations,
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
for (const owner of owners) {
|
|
91
|
+
for (const app of owner.applications) {
|
|
92
|
+
ids.owners[app.id] = owner.id;
|
|
93
|
+
}
|
|
94
|
+
for (const addon of owner.addons) {
|
|
95
|
+
ids.owners[addon.id] = owner.id;
|
|
96
|
+
ids.owners[addon.realId] = owner.id;
|
|
97
|
+
const addonIds = { addonId: addon.id, realId: addon.realId };
|
|
98
|
+
ids.addons[addon.id] = addonIds;
|
|
99
|
+
ids.addons[addon.realId] = addonIds;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return ids;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
module.exports = {
|
|
107
|
+
resolveOwnerId,
|
|
108
|
+
resolveAddonId,
|
|
109
|
+
resolveRealId,
|
|
110
|
+
};
|
package/src/parsers.js
CHANGED
|
@@ -79,14 +79,6 @@ function commaSeparated (string) {
|
|
|
79
79
|
return cliparse.parsers.success(string.split(','));
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
function accessLogsFormat (format) {
|
|
83
|
-
const availableFormats = AccessLogs.listAvailableFormats();
|
|
84
|
-
if (availableFormats.includes(format)) {
|
|
85
|
-
return cliparse.parsers.success(format);
|
|
86
|
-
}
|
|
87
|
-
return cliparse.parsers.error('The format must be one of ' + availableFormats.join(', '));
|
|
88
|
-
}
|
|
89
|
-
|
|
90
82
|
function integer (string) {
|
|
91
83
|
const integer = parseInt(string);
|
|
92
84
|
if (isNaN(integer)) {
|
|
@@ -162,7 +154,6 @@ module.exports = {
|
|
|
162
154
|
addonIdOrName,
|
|
163
155
|
ngIdOrLabel,
|
|
164
156
|
commaSeparated,
|
|
165
|
-
accessLogsFormat,
|
|
166
157
|
integer,
|
|
167
158
|
tag,
|
|
168
159
|
tags,
|