clever-tools 2.9.0 → 2.10.0-beta.1
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 +10 -0
- package/README.md +24 -20
- package/bin/clever.js +248 -3
- package/package.json +7 -6
- package/src/commands/applications.js +24 -15
- package/src/commands/console.js +1 -1
- package/src/commands/login.js +1 -1
- package/src/commands/networkgroups/commands.js +7 -0
- package/src/commands/networkgroups/index.js +67 -0
- package/src/commands/networkgroups/members.js +80 -0
- package/src/commands/networkgroups/peers.js +83 -0
- package/src/commands/open.js +1 -1
- package/src/models/app_configuration.js +38 -0
- package/src/models/format-ng-table.js +115 -0
- package/src/models/format-string.js +44 -0
- package/src/models/networkgroup.js +62 -0
- package/src/models/wireguard-conf.js +95 -0
- package/src/models/wireguard.js +75 -0
- package/src/parsers.js +76 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# clever-tools changelog
|
|
2
2
|
|
|
3
|
+
## Unrelease (????-??-??)
|
|
4
|
+
|
|
5
|
+
## 2.10.0-beta.0 (2022-09-06)
|
|
6
|
+
|
|
7
|
+
* Add NetworkGroups commands `clever ng --help`
|
|
8
|
+
|
|
9
|
+
## 2.9.1 (2022-02-28)
|
|
10
|
+
|
|
11
|
+
* Upgrade opn to open
|
|
12
|
+
|
|
3
13
|
## 2.9.0 (2022-01-12)
|
|
4
14
|
|
|
5
15
|
* Add NewRelic support in `clever drains`
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Command Line Interface for Clever Cloud.
|
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
9
|
-
The clever-tools CLI can be installed through many
|
|
9
|
+
The clever-tools CLI can be installed through many channels depending on your system setup.
|
|
10
10
|
|
|
11
11
|
### Via npm
|
|
12
12
|
|
|
@@ -30,26 +30,28 @@ npm install -g clever-tools@beta
|
|
|
30
30
|
|
|
31
31
|
##### Warning
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
We recently moved from Bintray to a self-hosted Nexus repository available at [https://nexus.clever-cloud.com](https://nexus.clever-cloud.com).
|
|
34
|
+
If you were using Bintray to install our `.deb` packages, you will need to edit your `/etc/apt/sources.list` and remove the old entry with `https://dl.bintray.com/clevercloud/deb` before going further.
|
|
34
35
|
|
|
35
36
|
---
|
|
36
37
|
|
|
37
38
|
If you are using a GNU/Linux distribution that uses `.deb` packages like Debian or Ubuntu, you can run:
|
|
38
39
|
|
|
39
40
|
```sh
|
|
40
|
-
|
|
41
|
-
echo "deb https://
|
|
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
43
|
apt-get update
|
|
43
44
|
apt-get install clever-tools
|
|
44
45
|
```
|
|
45
46
|
|
|
46
47
|
NOTES:
|
|
47
48
|
|
|
48
|
-
* The `.deb` packages are hosted on
|
|
49
|
+
* The `.deb` packages are hosted on Clever Cloud's public Nexus instance available at [https://nexus.clever-cloud.com](https://nexus.clever-cloud.com).
|
|
50
|
+
* Our PGP key is required to trust the repository.
|
|
49
51
|
* If you want access to the beta channel, you can use this in your `sources.list`:
|
|
50
52
|
|
|
51
53
|
```sh
|
|
52
|
-
echo "deb https://
|
|
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
|
|
53
55
|
```
|
|
54
56
|
|
|
55
57
|
#### CentOS/Fedora (.rpm)
|
|
@@ -58,22 +60,23 @@ echo "deb https://dl.bintray.com/clevercloud/deb unstable beta" | tee -a /etc/ap
|
|
|
58
60
|
|
|
59
61
|
##### Warning
|
|
60
62
|
|
|
61
|
-
|
|
63
|
+
We recently moved from Bintray to a self-hosted Nexus repository available at [https://nexus.clever-cloud.com](https://nexus.clever-cloud.com).
|
|
64
|
+
If you were using Bintray to install our `.rpm` packages, you will need to remove the old `/etc/yum.repos.d/bintray-clevercloud-rpm.repo` before going further.
|
|
62
65
|
|
|
63
66
|
---
|
|
64
67
|
|
|
65
68
|
If you are using a GNU/Linux distribution that uses `.rpm` packages like CentOS or Fedora, you can run:
|
|
66
69
|
|
|
67
70
|
```sh
|
|
68
|
-
curl https://
|
|
69
|
-
|
|
71
|
+
curl -s https://clever-tools.clever-cloud.com/repos/cc-nexus-rpm.repo > /etc/yum.repos.d/cc-nexus-rpm.repo
|
|
72
|
+
yum update
|
|
70
73
|
yum install clever-tools
|
|
71
74
|
```
|
|
72
75
|
|
|
73
76
|
NOTES:
|
|
74
77
|
|
|
75
|
-
* The `.rpm` packages are hosted on
|
|
76
|
-
* If you want access to the beta channel, you
|
|
78
|
+
* The `.rpm` packages are hosted on Clever Cloud's public Nexus instance available at [https://nexus.clever-cloud.com](https://nexus.clever-cloud.com).
|
|
79
|
+
* If you want access to the beta channel, you will need to edit `/etc/yum.repos.d/cc-nexus-rpm.repo` and set `enabled=1` for the `[clever-tools-beta]`.
|
|
77
80
|
|
|
78
81
|
#### Arch Linux
|
|
79
82
|
|
|
@@ -114,11 +117,11 @@ NOTES:
|
|
|
114
117
|
* The packages are available on Clever Cloud's Cellar bucket: [clever-tools-latest_linux.tar.gz](https://clever-tools.clever-cloud.com/releases/latest/clever-tools-latest_linux.tar.gz).
|
|
115
118
|
* You can also retrieve any release (including beta) on this Cellar bucket by replacing `latest` (path and filename) with the version number you need.
|
|
116
119
|
|
|
117
|
-
### On
|
|
120
|
+
### On macOS
|
|
118
121
|
|
|
119
122
|
#### Using homebrew
|
|
120
123
|
|
|
121
|
-
If you are using
|
|
124
|
+
If you are using macOS and you have [homebrew](https://brew.sh) installed, you can run:
|
|
122
125
|
|
|
123
126
|
```sh
|
|
124
127
|
brew install CleverCloud/homebrew-tap/clever-tools
|
|
@@ -130,7 +133,7 @@ NOTES:
|
|
|
130
133
|
|
|
131
134
|
#### Using the `.tar.gz` archive
|
|
132
135
|
|
|
133
|
-
If you are using
|
|
136
|
+
If you are using macOS, but you don't have [homebrew](https://brew.sh) installed, you can download a `.tar.gz` archive and extract the binary in your `PATH`:
|
|
134
137
|
|
|
135
138
|
```sh
|
|
136
139
|
curl -O https://clever-tools.clever-cloud.com/releases/latest/clever-tools-latest_macos.tar.gz
|
|
@@ -151,24 +154,25 @@ NOTES:
|
|
|
151
154
|
|
|
152
155
|
##### Warning
|
|
153
156
|
|
|
154
|
-
|
|
157
|
+
We recently moved from Bintray to a self-hosted Nexus repository available at [https://nexus.clever-cloud.com](https://nexus.clever-cloud.com).
|
|
158
|
+
If you were using Bintray to install our `.nupkg` packages, you will need to remove the old source.
|
|
155
159
|
|
|
156
160
|
---
|
|
157
161
|
|
|
158
162
|
If you are using Windows and you have [chocolatey](https://chocolatey.org) installed, you can run:
|
|
159
163
|
|
|
160
164
|
```bash
|
|
161
|
-
choco sources add -n=clevercloud -s='https://
|
|
165
|
+
choco sources add -n=clevercloud -s='https://nexus.clever-cloud.com/repository/nupkg/'
|
|
162
166
|
choco install clever-tools
|
|
163
167
|
```
|
|
164
168
|
|
|
165
169
|
NOTES:
|
|
166
170
|
|
|
167
|
-
* If you want access to the beta channel, you can use `choco
|
|
171
|
+
* If you want access to the beta channel, you can use `choco sources add -n=clevercloud -s='https://nexus.clever-cloud.com/repository/nupkg-beta/'` instead.
|
|
168
172
|
|
|
169
173
|
#### Using the `.zip` archive
|
|
170
174
|
|
|
171
|
-
If you are using Windows but you don't have [chocolatey](https://chocolatey.org) installed, you can download a `.zip` archive and extract the binary in your `PATH`.
|
|
175
|
+
If you are using Windows, but you don't have [chocolatey](https://chocolatey.org) installed, you can download a `.zip` archive and extract the binary in your `PATH`.
|
|
172
176
|
|
|
173
177
|
NOTES:
|
|
174
178
|
|
|
@@ -194,7 +198,7 @@ COPY --from=clevercloud/clever-tools /bin/clever /usr/local/bin/clever
|
|
|
194
198
|
|
|
195
199
|
### Via Nix
|
|
196
200
|
|
|
197
|
-
If you are using Nix, you will find a Nix derivation on Fretlink's
|
|
201
|
+
If you are using Nix, you will find a Nix derivation on Fretlink's GitHub repository: https://github.com/fretlink/clever-tools-nix
|
|
198
202
|
|
|
199
203
|
## Enabling autocompletion
|
|
200
204
|
|
|
@@ -225,7 +229,7 @@ clever login
|
|
|
225
229
|
It will open the Web console in your browser and reuse your existing session if you're already logged in.
|
|
226
230
|
|
|
227
231
|
`clever login` tries to open a browser through `xdg-open` on GNU/Linux systems (and in bash for windows).
|
|
228
|
-
Make sure you have `xdg-utils` available as well as a default browser set
|
|
232
|
+
Make sure you have `xdg-utils` available as well as a default browser set, or you can copy and paste the URL displayed in the console.
|
|
229
233
|
|
|
230
234
|
### Create an application
|
|
231
235
|
|
package/bin/clever.js
CHANGED
|
@@ -18,6 +18,7 @@ const updateNotifier = require('update-notifier');
|
|
|
18
18
|
const git = require('../src/models/git.js');
|
|
19
19
|
const Parsers = require('../src/parsers.js');
|
|
20
20
|
const handleCommandPromise = require('../src/command-promise-handler.js');
|
|
21
|
+
const Formatter = require('../src/models/format-string.js');
|
|
21
22
|
|
|
22
23
|
// Exit cleanly if the program we pipe to exits abruptly
|
|
23
24
|
process.stdout.on('error', (error) => {
|
|
@@ -69,6 +70,7 @@ const ApplicationConfiguration = lazyRequire('../src/models/application_configur
|
|
|
69
70
|
const Drain = lazyRequire('../src/models/drain.js');
|
|
70
71
|
const Notification = lazyRequire('../src/models/notification.js');
|
|
71
72
|
const Organisation = lazyRequire('../src/models/organisation.js');
|
|
73
|
+
const NetworkGroup = lazyRequire('../src/models/networkgroup.js');
|
|
72
74
|
|
|
73
75
|
function run () {
|
|
74
76
|
|
|
@@ -113,6 +115,11 @@ function run () {
|
|
|
113
115
|
},
|
|
114
116
|
}),
|
|
115
117
|
configurationValue: cliparse.argument('configuration-value', { description: 'The new value of the configuration' }),
|
|
118
|
+
ngId: cliparse.argument('ng-id', { description: 'The Network Group id' }),
|
|
119
|
+
ngIdOrLabel: cliparse.argument('ng', {
|
|
120
|
+
description: 'Network Group ID or label',
|
|
121
|
+
parser: Parsers.ngIdOrLabel,
|
|
122
|
+
}),
|
|
116
123
|
};
|
|
117
124
|
|
|
118
125
|
// OPTIONS
|
|
@@ -132,7 +139,9 @@ function run () {
|
|
|
132
139
|
aliases: ['f'],
|
|
133
140
|
description: 'Display access logs continuously (ignores before/until, after/since)',
|
|
134
141
|
}),
|
|
135
|
-
importAsJson: cliparse.flag('json', {
|
|
142
|
+
importAsJson: cliparse.flag('json', {
|
|
143
|
+
description: 'Import variables as JSON (an array of { "name": "THE_NAME", "value": "the value" } objects)',
|
|
144
|
+
}),
|
|
136
145
|
addonId: cliparse.option('addon', { metavar: 'addon_id', description: 'Addon ID' }),
|
|
137
146
|
after: cliparse.option('after', {
|
|
138
147
|
metavar: 'after',
|
|
@@ -151,6 +160,10 @@ function run () {
|
|
|
151
160
|
description: 'Short name for the application',
|
|
152
161
|
complete: Application('listAvailableAliases'),
|
|
153
162
|
}),
|
|
163
|
+
naturalName: cliparse.flag('natural-name', {
|
|
164
|
+
aliases: ['n'],
|
|
165
|
+
description: 'Show application names or aliases if possible',
|
|
166
|
+
}),
|
|
154
167
|
before: cliparse.option('before', {
|
|
155
168
|
metavar: 'before',
|
|
156
169
|
aliases: ['until'],
|
|
@@ -270,7 +283,7 @@ function run () {
|
|
|
270
283
|
onlyAliases: cliparse.flag('only-aliases', { description: 'List only application aliases' }),
|
|
271
284
|
onlyApps: cliparse.flag('only-apps', { description: 'Only show app dependencies' }),
|
|
272
285
|
orgaIdOrName: cliparse.option('org', {
|
|
273
|
-
aliases: ['o'],
|
|
286
|
+
aliases: ['o', 'owner'],
|
|
274
287
|
description: 'Organisation ID (or name, if unambiguous)',
|
|
275
288
|
parser: Parsers.orgaIdOrName,
|
|
276
289
|
}),
|
|
@@ -366,6 +379,158 @@ function run () {
|
|
|
366
379
|
aliases: ['y'],
|
|
367
380
|
description: 'Skip confirmation even if the TCP redirection is not free',
|
|
368
381
|
}),
|
|
382
|
+
ngLabel: cliparse.option('label', {
|
|
383
|
+
required: true,
|
|
384
|
+
metavar: 'ng_label',
|
|
385
|
+
description: 'Network Group label, also used for dns context',
|
|
386
|
+
}),
|
|
387
|
+
ngIdOrLabel: cliparse.option('ng', {
|
|
388
|
+
required: true,
|
|
389
|
+
metavar: 'ng',
|
|
390
|
+
description: 'Network Group ID or label',
|
|
391
|
+
parser: Parsers.ngIdOrLabel,
|
|
392
|
+
// complete: NetworkGroup('xxx'),
|
|
393
|
+
}),
|
|
394
|
+
ngDescription: cliparse.option('description', {
|
|
395
|
+
required: true,
|
|
396
|
+
metavar: 'ng_description',
|
|
397
|
+
description: 'Network Group description',
|
|
398
|
+
}),
|
|
399
|
+
ngMemberId: cliparse.option('member-id', {
|
|
400
|
+
aliases: ['m'],
|
|
401
|
+
required: true,
|
|
402
|
+
metavar: 'member_id',
|
|
403
|
+
description: `The member ID: an app ID (i.e. ${Formatter.formatCode('app_xxx')}), add-on ID (i.e. ${Formatter.formatCode('addon_xxx')}) or external node category ID`,
|
|
404
|
+
// complete: NetworkGroup('xxx'),
|
|
405
|
+
}),
|
|
406
|
+
ngMemberDomainName: cliparse.option('domain-name', {
|
|
407
|
+
required: true,
|
|
408
|
+
metavar: 'domain_name',
|
|
409
|
+
description: `Member name used in the ${Formatter.formatUrl('<memberName>.m.<ngID>.ng.clever-cloud.com', false)} domain name alias`,
|
|
410
|
+
}),
|
|
411
|
+
ngPeerId: cliparse.option('peer-id', {
|
|
412
|
+
required: true,
|
|
413
|
+
metavar: 'peer_id',
|
|
414
|
+
description: 'The peer ID',
|
|
415
|
+
// complete: NetworkGroup('xxx'),
|
|
416
|
+
}),
|
|
417
|
+
ngPeerRole: cliparse.option('role', {
|
|
418
|
+
required: true,
|
|
419
|
+
metavar: 'peer_role',
|
|
420
|
+
description: `The peer role, (${Formatter.formatString('client')} or ${Formatter.formatString('server')})`,
|
|
421
|
+
parser: Parsers.ngPeerRole,
|
|
422
|
+
complete: NetworkGroup('listAvailablePeerRoles'),
|
|
423
|
+
}),
|
|
424
|
+
// FIXME: Add "internal" member type
|
|
425
|
+
ngMemberType: cliparse.option('type', {
|
|
426
|
+
required: true,
|
|
427
|
+
metavar: 'member_type',
|
|
428
|
+
description: `The member type (${Formatter.formatString('application')}, ${Formatter.formatString('addon')} or ${Formatter.formatString('external')})`,
|
|
429
|
+
parser: Parsers.ngMemberType,
|
|
430
|
+
complete: NetworkGroup('listAvailableMemberTypes'),
|
|
431
|
+
}),
|
|
432
|
+
ngMemberLabel: cliparse.option('label', {
|
|
433
|
+
required: true,
|
|
434
|
+
metavar: 'member_label',
|
|
435
|
+
description: 'Network Group member label',
|
|
436
|
+
}),
|
|
437
|
+
ngNodeCategoryId: cliparse.option('node-category-id', {
|
|
438
|
+
required: true,
|
|
439
|
+
aliases: ['c'],
|
|
440
|
+
metavar: 'node_category_id',
|
|
441
|
+
description: 'The external node category ID',
|
|
442
|
+
// complete: NetworkGroup('xxx'),
|
|
443
|
+
}),
|
|
444
|
+
ngPeerLabel: cliparse.option('label', {
|
|
445
|
+
required: true,
|
|
446
|
+
metavar: 'peer_label',
|
|
447
|
+
description: 'Network Group peer label',
|
|
448
|
+
}),
|
|
449
|
+
ngPeerParentMemberId: cliparse.option('parent', {
|
|
450
|
+
required: true,
|
|
451
|
+
metavar: 'member_id',
|
|
452
|
+
description: 'Network Group peer category ID (parent member ID)',
|
|
453
|
+
// complete: NetworkGroup('xxx'),
|
|
454
|
+
}),
|
|
455
|
+
optNgIdOrLabel: cliparse.option('ng', {
|
|
456
|
+
required: false,
|
|
457
|
+
metavar: 'ng',
|
|
458
|
+
description: 'Network Group ID or label',
|
|
459
|
+
parser: Parsers.ngIdOrLabel,
|
|
460
|
+
// complete: NetworkGroup('xxx'),
|
|
461
|
+
}),
|
|
462
|
+
optNgMemberLabel: cliparse.option('label', {
|
|
463
|
+
required: false,
|
|
464
|
+
metavar: 'member_label',
|
|
465
|
+
description: 'The member label',
|
|
466
|
+
}),
|
|
467
|
+
optNgNodeCategoryId: cliparse.option('node-category-id', {
|
|
468
|
+
required: false,
|
|
469
|
+
aliases: ['c'],
|
|
470
|
+
metavar: 'node_category_id',
|
|
471
|
+
description: 'The external node category ID',
|
|
472
|
+
// complete: NetworkGroup('xxx'),
|
|
473
|
+
}),
|
|
474
|
+
optNgPeerId: cliparse.option('peer-id', {
|
|
475
|
+
required: false,
|
|
476
|
+
metavar: 'peer_id',
|
|
477
|
+
description: 'The peer ID',
|
|
478
|
+
// complete: NetworkGroup('xxx'),
|
|
479
|
+
}),
|
|
480
|
+
optNgPeerRole: cliparse.option('role', {
|
|
481
|
+
required: false,
|
|
482
|
+
default: 'client',
|
|
483
|
+
metavar: 'peer_role',
|
|
484
|
+
description: `The peer role, (${Formatter.formatString('client')} or ${Formatter.formatString('server')})`,
|
|
485
|
+
parser: Parsers.ngPeerRole,
|
|
486
|
+
complete: NetworkGroup('listAvailablePeerRoles'),
|
|
487
|
+
}),
|
|
488
|
+
optNgSearchAppId: cliparse.option('app-id', {
|
|
489
|
+
required: false,
|
|
490
|
+
metavar: 'app_id',
|
|
491
|
+
description: 'The app id to search',
|
|
492
|
+
// complete: NetworkGroup('xxx'),
|
|
493
|
+
}),
|
|
494
|
+
wgPublicKey: cliparse.option('public-key', {
|
|
495
|
+
required: true,
|
|
496
|
+
metavar: 'public_key',
|
|
497
|
+
description: 'A WireGuard® public key',
|
|
498
|
+
}),
|
|
499
|
+
optWgPrivateKey: cliparse.option('private-key', {
|
|
500
|
+
required: false,
|
|
501
|
+
metavar: 'private_key',
|
|
502
|
+
description: 'A WireGuard® private key',
|
|
503
|
+
}),
|
|
504
|
+
jsonFormat: cliparse.flag('json', { aliases: ['j'], description: 'Show result in JSON format' }),
|
|
505
|
+
tag: cliparse.option('tag', {
|
|
506
|
+
required: true,
|
|
507
|
+
metavar: 'tag',
|
|
508
|
+
description: 'A tag',
|
|
509
|
+
parser: Parsers.tag,
|
|
510
|
+
}),
|
|
511
|
+
tags: cliparse.option('tags', {
|
|
512
|
+
required: true,
|
|
513
|
+
metavar: 'tags',
|
|
514
|
+
description: 'List of tags separated by a comma',
|
|
515
|
+
parser: Parsers.tags,
|
|
516
|
+
}),
|
|
517
|
+
optTags: cliparse.option('tags', {
|
|
518
|
+
metavar: 'tags',
|
|
519
|
+
description: 'List of tags separated by a comma',
|
|
520
|
+
parser: Parsers.tags,
|
|
521
|
+
}),
|
|
522
|
+
optIpAddress: cliparse.option('ip', {
|
|
523
|
+
required: false,
|
|
524
|
+
metavar: 'ip_address',
|
|
525
|
+
description: 'An IP address',
|
|
526
|
+
parser: Parsers.ipAddress,
|
|
527
|
+
}),
|
|
528
|
+
optPortNumber: cliparse.option('port', {
|
|
529
|
+
required: false,
|
|
530
|
+
metavar: 'port_number',
|
|
531
|
+
description: 'A port number',
|
|
532
|
+
parser: Parsers.portNumber,
|
|
533
|
+
}),
|
|
369
534
|
};
|
|
370
535
|
|
|
371
536
|
// ACCESSLOGS COMMAND
|
|
@@ -416,7 +581,7 @@ function run () {
|
|
|
416
581
|
const applications = lazyRequirePromiseModule('../src/commands/applications.js');
|
|
417
582
|
const applicationsCommand = cliparse.command('applications', {
|
|
418
583
|
description: 'List linked applications',
|
|
419
|
-
options: [opts.onlyAliases],
|
|
584
|
+
options: [opts.onlyAliases, opts.jsonFormat],
|
|
420
585
|
}, applications('list'));
|
|
421
586
|
|
|
422
587
|
// CANCEL DEPLOY COMMAND
|
|
@@ -586,6 +751,84 @@ function run () {
|
|
|
586
751
|
args: [args.alias],
|
|
587
752
|
}, makeDefault('makeDefault'));
|
|
588
753
|
|
|
754
|
+
// NETWORK GROUPS COMMANDS
|
|
755
|
+
const networkgroups = lazyRequirePromiseModule('../src/commands/networkgroups/commands.js');
|
|
756
|
+
|
|
757
|
+
// network group category - start
|
|
758
|
+
const networkGroupsListCommand = cliparse.command('list', {
|
|
759
|
+
description: 'List Network Groups with their labels',
|
|
760
|
+
options: [opts.jsonFormat],
|
|
761
|
+
}, networkgroups('listNetworkGroups'));
|
|
762
|
+
const networkGroupsCreateCommand = cliparse.command('create', {
|
|
763
|
+
description: 'Create a Network Group',
|
|
764
|
+
options: [opts.ngLabel, opts.ngDescription, opts.optTags, opts.jsonFormat],
|
|
765
|
+
}, networkgroups('createNg'));
|
|
766
|
+
const networkGroupsDeleteCommand = cliparse.command('delete', {
|
|
767
|
+
description: 'Delete a Network Group',
|
|
768
|
+
options: [opts.ngIdOrLabel],
|
|
769
|
+
}, networkgroups('deleteNg'));
|
|
770
|
+
// network group category - end
|
|
771
|
+
|
|
772
|
+
// member category - start
|
|
773
|
+
const networkGroupsMemberListCommand = cliparse.command('list', {
|
|
774
|
+
description: 'List members of a Network Group',
|
|
775
|
+
// Add option opts.optNgSearchAppId ?
|
|
776
|
+
options: [opts.ngIdOrLabel, opts.naturalName, opts.jsonFormat],
|
|
777
|
+
}, networkgroups('listMembers'));
|
|
778
|
+
const networkGroupsMemberGetCommand = cliparse.command('get', {
|
|
779
|
+
description: 'Get a Network Group member details',
|
|
780
|
+
options: [opts.ngIdOrLabel, opts.ngMemberId, opts.naturalName, opts.jsonFormat],
|
|
781
|
+
}, networkgroups('getMember'));
|
|
782
|
+
const networkGroupsMemberAddCommand = cliparse.command('add', {
|
|
783
|
+
description: 'Add an app or addon as a Network Group member',
|
|
784
|
+
options: [opts.ngIdOrLabel, opts.ngMemberId, opts.ngMemberType, opts.ngMemberDomainName, opts.optNgMemberLabel],
|
|
785
|
+
}, networkgroups('addMember'));
|
|
786
|
+
const networkGroupsMemberRemoveCommand = cliparse.command('remove', {
|
|
787
|
+
description: 'Remove an app or addon from a Network Group',
|
|
788
|
+
options: [opts.ngIdOrLabel, opts.ngMemberId],
|
|
789
|
+
}, networkgroups('removeMember'));
|
|
790
|
+
|
|
791
|
+
const networkGroupsMembersCategoryCommand = cliparse.command('members', {
|
|
792
|
+
description: 'List commands for interacting with Network Group members',
|
|
793
|
+
commands: [networkGroupsMemberListCommand, networkGroupsMemberGetCommand, networkGroupsMemberAddCommand, networkGroupsMemberRemoveCommand],
|
|
794
|
+
});
|
|
795
|
+
// member category - end
|
|
796
|
+
|
|
797
|
+
// peer category - start
|
|
798
|
+
const networkGroupsPeerListCommand = cliparse.command('list', {
|
|
799
|
+
description: 'List peers of a Network Group',
|
|
800
|
+
options: [opts.ngIdOrLabel, opts.jsonFormat],
|
|
801
|
+
}, networkgroups('listPeers'));
|
|
802
|
+
const networkGroupsPeerGetCommand = cliparse.command('get', {
|
|
803
|
+
description: 'Get a Network Group peer details',
|
|
804
|
+
options: [opts.ngIdOrLabel, opts.ngPeerId, opts.jsonFormat],
|
|
805
|
+
}, networkgroups('getPeer'));
|
|
806
|
+
const networkGroupsPeerAddCommand = cliparse.command('add-external', {
|
|
807
|
+
description: 'Add an external node as a Network Group peer',
|
|
808
|
+
options: [opts.ngIdOrLabel, opts.ngPeerRole, opts.wgPublicKey, opts.ngPeerLabel, opts.ngPeerParentMemberId],
|
|
809
|
+
}, networkgroups('addExternalPeer'));
|
|
810
|
+
const networkGroupsPeerRemoveExternalCommand = cliparse.command('remove-external', {
|
|
811
|
+
description: 'Remove an external node from a Network Group',
|
|
812
|
+
options: [opts.ngIdOrLabel, opts.ngPeerId],
|
|
813
|
+
}, networkgroups('removeExternalPeer'));
|
|
814
|
+
|
|
815
|
+
const networkGroupsPeersCategoryCommand = cliparse.command('peers', {
|
|
816
|
+
description: 'List commands for interacting with Network Group peers',
|
|
817
|
+
commands: [networkGroupsPeerListCommand, networkGroupsPeerGetCommand, networkGroupsPeerAddCommand, networkGroupsPeerRemoveExternalCommand],
|
|
818
|
+
});
|
|
819
|
+
// peer category - end
|
|
820
|
+
|
|
821
|
+
const networkGroupsCommand = cliparse.command('networkgroups', {
|
|
822
|
+
description: 'List Network Group commands',
|
|
823
|
+
options: [opts.orgaIdOrName, opts.alias],
|
|
824
|
+
commands: [networkGroupsListCommand, networkGroupsCreateCommand, networkGroupsDeleteCommand, networkGroupsMembersCategoryCommand, networkGroupsPeersCategoryCommand],
|
|
825
|
+
});
|
|
826
|
+
const ngCommand = cliparse.command('ng', {
|
|
827
|
+
description: `Alias for ${Formatter.formatCommand('clever networkgroups')}`,
|
|
828
|
+
options: [opts.orgaIdOrName, opts.alias],
|
|
829
|
+
commands: [networkGroupsListCommand, networkGroupsCreateCommand, networkGroupsDeleteCommand, networkGroupsMembersCategoryCommand, networkGroupsPeersCategoryCommand],
|
|
830
|
+
});
|
|
831
|
+
|
|
589
832
|
// NOTIFY-EMAIL COMMAND
|
|
590
833
|
const notifyEmail = lazyRequirePromiseModule('../src/commands/notify-email.js');
|
|
591
834
|
const addEmailNotificationCommand = cliparse.command('add', {
|
|
@@ -780,6 +1023,8 @@ function run () {
|
|
|
780
1023
|
logoutCommand,
|
|
781
1024
|
logsCommand,
|
|
782
1025
|
makeDefaultCommand,
|
|
1026
|
+
networkGroupsCommand,
|
|
1027
|
+
ngCommand,
|
|
783
1028
|
openCommand,
|
|
784
1029
|
consoleCommand,
|
|
785
1030
|
profileCommand,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clever-tools",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.0-beta.1",
|
|
4
4
|
"description": "Command Line Interface for Clever Cloud.",
|
|
5
5
|
"main": "bin/clever.js",
|
|
6
6
|
"keywords": [
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
"author": "Clever Cloud <ci@clever-cloud.com>",
|
|
16
16
|
"license": "Apache-2.0",
|
|
17
17
|
"bin": {
|
|
18
|
-
"clever": "
|
|
19
|
-
"install-clever-completion": "
|
|
20
|
-
"uninstall-clever-completion": "
|
|
18
|
+
"clever": "bin/clever.js",
|
|
19
|
+
"install-clever-completion": "scripts/install-autocomplete.sh",
|
|
20
|
+
"uninstall-clever-completion": "scripts/uninstall-autocomplete.sh"
|
|
21
21
|
},
|
|
22
22
|
"files": [
|
|
23
23
|
"bin",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"scripts/*.sh"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@clevercloud/client": "
|
|
28
|
+
"@clevercloud/client": "7.9.0",
|
|
29
29
|
"clf-date": "^0.2.0",
|
|
30
30
|
"cliparse": "^0.3.3",
|
|
31
31
|
"colors": "1.4.0",
|
|
@@ -36,12 +36,13 @@
|
|
|
36
36
|
"lodash": "^4.17.21",
|
|
37
37
|
"mkdirp": "^1.0.4",
|
|
38
38
|
"moment": "^2.29.1",
|
|
39
|
-
"
|
|
39
|
+
"open": "^8.4.0",
|
|
40
40
|
"slugify": "^1.5.3",
|
|
41
41
|
"string-length": "^4.0.2",
|
|
42
42
|
"superagent": "^6.1.0",
|
|
43
43
|
"text-table": "^0.2.0",
|
|
44
44
|
"update-notifier": "^5.1.0",
|
|
45
|
+
"uuid": "^8.3.2",
|
|
45
46
|
"ws": "^7.4.6",
|
|
46
47
|
"xdg": "^0.1.1"
|
|
47
48
|
},
|
|
@@ -6,29 +6,38 @@ const AppConfig = require('../models/app_configuration.js');
|
|
|
6
6
|
const Logger = require('../logger.js');
|
|
7
7
|
|
|
8
8
|
async function list (params) {
|
|
9
|
-
const { 'only-aliases': onlyAliases } = params.options;
|
|
9
|
+
const { 'only-aliases': onlyAliases, json } = params.options;
|
|
10
10
|
|
|
11
11
|
const { apps } = await AppConfig.loadApplicationConf();
|
|
12
12
|
|
|
13
|
-
const formattedApps = formatApps(apps, onlyAliases);
|
|
13
|
+
const formattedApps = formatApps(apps, onlyAliases, json);
|
|
14
14
|
Logger.println(formattedApps);
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
function formatApps (apps, onlyAliases) {
|
|
17
|
+
function formatApps (apps, onlyAliases, json) {
|
|
18
18
|
|
|
19
|
-
if (
|
|
20
|
-
|
|
19
|
+
if (json) {
|
|
20
|
+
if (onlyAliases) {
|
|
21
|
+
apps = apps.map((a) => a.alias);
|
|
22
|
+
}
|
|
23
|
+
return JSON.stringify(apps, null, 2);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
if (onlyAliases) {
|
|
27
|
+
return apps.map((a) => a.alias).join('\n');
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
return apps
|
|
31
|
+
.map((app) =>
|
|
32
|
+
[
|
|
33
|
+
`Application ${app.name}`,
|
|
34
|
+
` alias: ${colors.bold(app.alias)}`,
|
|
35
|
+
` id: ${app.app_id}`,
|
|
36
|
+
` deployment url: ${app.deploy_url}`].join('\n'),
|
|
37
|
+
)
|
|
38
|
+
.join('\n\n');
|
|
39
|
+
}
|
|
21
40
|
}
|
|
22
|
-
|
|
23
|
-
return apps
|
|
24
|
-
.map((app) => {
|
|
25
|
-
return [
|
|
26
|
-
`Application ${app.name}`,
|
|
27
|
-
` alias: ${colors.bold(app.alias)}`,
|
|
28
|
-
` id: ${app.app_id}`,
|
|
29
|
-
` deployment url: ${app.deploy_url}`].join('\n');
|
|
30
|
-
})
|
|
31
|
-
.join('\n\n');
|
|
32
41
|
}
|
|
33
42
|
|
|
34
43
|
module.exports = { list };
|
package/src/commands/console.js
CHANGED
package/src/commands/login.js
CHANGED
|
@@ -6,7 +6,7 @@ const util = require('util');
|
|
|
6
6
|
const delay = util.promisify(setTimeout);
|
|
7
7
|
|
|
8
8
|
const colors = require('colors/safe');
|
|
9
|
-
const open = require('
|
|
9
|
+
const open = require('open');
|
|
10
10
|
const superagent = require('superagent');
|
|
11
11
|
|
|
12
12
|
const Logger = require('../logger.js');
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const ngApi = require('@clevercloud/client/cjs/api/v4/network-group.js');
|
|
4
|
+
|
|
5
|
+
const { sendToApi } = require('../../models/send-to-api.js');
|
|
6
|
+
|
|
7
|
+
const Logger = require('../../logger.js');
|
|
8
|
+
const NetworkGroup = require('../../models/networkgroup.js');
|
|
9
|
+
const Formatter = require('../../models/format-string.js');
|
|
10
|
+
const TableFormatter = require('../../models/format-ng-table.js');
|
|
11
|
+
|
|
12
|
+
async function listNetworkGroups(params) {
|
|
13
|
+
const { org: orgaIdOrName, alias, json } = params.options;
|
|
14
|
+
const ownerId = await NetworkGroup.getOwnerId(orgaIdOrName, alias);
|
|
15
|
+
|
|
16
|
+
Logger.info(`Listing Network Groups from owner ${Formatter.formatString(ownerId)}`);
|
|
17
|
+
const result = await ngApi.listNetworkGroups({ ownerId }).then(sendToApi);
|
|
18
|
+
|
|
19
|
+
if (json) {
|
|
20
|
+
Logger.println(JSON.stringify(result, null, 2));
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
if (result.length === 0) {
|
|
24
|
+
Logger.println(`No Network Group found for ${ownerId}. You can create one with ${Formatter.formatCommand('clever networkgroups create')}.`);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
TableFormatter.printNetworkGroupsTableHeader();
|
|
28
|
+
result
|
|
29
|
+
.map((ng) => TableFormatter.formatNetworkGroupsLine(ng))
|
|
30
|
+
.forEach((ng) => Logger.println(ng));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function createNg(params) {
|
|
36
|
+
const { org: orgaIdOrName, alias, label, description, tags, json } = params.options;
|
|
37
|
+
const ownerId = await NetworkGroup.getOwnerId(orgaIdOrName, alias);
|
|
38
|
+
|
|
39
|
+
Logger.info(`Creating Network Group from owner ${Formatter.formatString(ownerId)}`);
|
|
40
|
+
const body = { ownerId: ownerId, label, description, tags };
|
|
41
|
+
Logger.debug('Sending body: ' + JSON.stringify(body, null, 2));
|
|
42
|
+
const result = await ngApi.createNetworkGroup({ ownerId }, body).then(sendToApi);
|
|
43
|
+
|
|
44
|
+
if (json) {
|
|
45
|
+
Logger.println(JSON.stringify(result, null, 2));
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
Logger.println(`Network Group ${Formatter.formatString(label)} creation will be performed asynchronously.`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function deleteNg(params) {
|
|
53
|
+
const { org: orgaIdOrName, alias, ng: networkGroupIdOrLabel } = params.options;
|
|
54
|
+
const ownerId = await NetworkGroup.getOwnerId(orgaIdOrName, alias);
|
|
55
|
+
const networkGroupId = await NetworkGroup.getId(ownerId, networkGroupIdOrLabel);
|
|
56
|
+
|
|
57
|
+
Logger.info(`Deleting Network Group ${Formatter.formatString(networkGroupId)} from owner ${Formatter.formatString(ownerId)}`);
|
|
58
|
+
await ngApi.deleteNetworkGroup({ ownerId, networkGroupId }).then(sendToApi);
|
|
59
|
+
|
|
60
|
+
Logger.println(`Network Group ${Formatter.formatString(networkGroupId)} deletion will be performed asynchronously.`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
module.exports = {
|
|
64
|
+
listNetworkGroups,
|
|
65
|
+
createNg,
|
|
66
|
+
deleteNg,
|
|
67
|
+
};
|