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 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 different channels depending on your system setup.
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
- Bintray is ending on May 1st 2021, we will migrate hosting as soon as possible. Please refer to the dedicated [issue](https://github.com/CleverCloud/clever-tools/issues/454) to track the migration.
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
- apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys "379CE192D401AB61"
41
- echo "deb https://dl.bintray.com/clevercloud/deb stable main" | tee -a /etc/apt/sources.list
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 Bintray (their GPG key is required to trust their signed packages).
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://dl.bintray.com/clevercloud/deb unstable beta" | tee -a /etc/apt/sources.list
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
- Bintray is ending on May 1st 2021, we will migrate hosting as soon as possible. Please refer to the dedicated [issue](https://github.com/CleverCloud/clever-tools/issues/454) to track the migration.
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://bintray.com/clevercloud/rpm/rpm > /etc/yum.repos.d/bintray-clevercloud-rpm.repo
69
- echo "exclude=*beta*" >> /etc/yum.repos.d/bintray-clevercloud-rpm.repo
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 Bintray.
76
- * If you want access to the beta channel, you can omit the second line which contains an exclude option.
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 MacOS
120
+ ### On macOS
118
121
 
119
122
  #### Using homebrew
120
123
 
121
- If you are using MacOS and you have [homebrew](https://brew.sh) installed, you can run:
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 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`:
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
- Bintray is ending on May 1st 2021, we will migrate hosting as soon as possible. Please refer to the dedicated [issue](https://github.com/CleverCloud/clever-tools/issues/454) to track the migration.
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://api.bintray.com/nuget/clevercloud/nupkg'
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 install --pre clever-tools` instead.
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 Github repository: https://github.com/fretlink/clever-tools-nix
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 (or you can copy and paste the URL displayed in the console.
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', { description: 'Import variables as JSON (an array of { "name": "THE_NAME", "value": "the value" } objects)' }),
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.9.0",
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": "./bin/clever.js",
19
- "install-clever-completion": "./scripts/install-autocomplete.sh",
20
- "uninstall-clever-completion": "./scripts/uninstall-autocomplete.sh"
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": "^7.4.0",
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
- "opn": "^6.0.0",
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 (onlyAliases) {
20
- return apps.map((a) => a.alis).join('\n');
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 };
@@ -2,7 +2,7 @@
2
2
 
3
3
  const AppConfig = require('../models/app_configuration.js');
4
4
  const Logger = require('../logger.js');
5
- const openPage = require('opn');
5
+ const openPage = require('open');
6
6
 
7
7
  async function openConsole (params) {
8
8
  const { alias } = params.options;
@@ -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('opn');
9
+ const open = require('open');
10
10
  const superagent = require('superagent');
11
11
 
12
12
  const Logger = require('../logger.js');
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ module.exports = {
4
+ ...require('./index.js'),
5
+ ...require('./members.js'),
6
+ ...require('./peers.js'),
7
+ };
@@ -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
+ };