clever-tools 3.11.0 → 3.13.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/bin/clever.js +416 -3
- package/package.json +4 -3
- package/src/clever-client/auth-bridge.js +61 -0
- package/src/clever-client/ng.js +18 -0
- package/src/clever-client/operators.js +121 -0
- package/src/commands/addon.js +34 -28
- package/src/commands/cancel-deploy.js +3 -4
- package/src/commands/config.js +16 -20
- package/src/commands/console.js +4 -10
- package/src/commands/create.js +76 -9
- package/src/commands/curl.js +17 -17
- package/src/commands/database.js +9 -9
- package/src/commands/delete.js +11 -10
- package/src/commands/deploy.js +35 -21
- package/src/commands/domain.js +13 -16
- package/src/commands/emails.js +174 -0
- package/src/commands/env.js +15 -8
- package/src/commands/keycloak.js +138 -0
- package/src/commands/kv.js +1 -1
- package/src/commands/link.js +7 -3
- package/src/commands/makeDefault.js +2 -1
- package/src/commands/matomo.js +85 -0
- package/src/commands/metabase.js +112 -0
- package/src/commands/ng.js +202 -0
- package/src/commands/open.js +2 -5
- package/src/commands/otoroshi.js +138 -0
- package/src/commands/profile.js +11 -10
- package/src/commands/published-config.js +7 -7
- package/src/commands/restart.js +1 -1
- package/src/commands/ssh-keys.js +159 -0
- package/src/commands/stop.js +3 -3
- package/src/commands/tcp-redirs.js +8 -8
- package/src/commands/tokens.js +146 -0
- package/src/commands/unlink.js +2 -1
- package/src/experimental-features.js +47 -2
- package/src/lib/ng-print.js +195 -0
- package/src/lib/operator-commands.js +281 -0
- package/src/lib/prompts.js +30 -0
- package/src/lib/slugify.js +10 -0
- package/src/logger.js +3 -0
- package/src/models/activity.js +2 -3
- package/src/models/addon.js +9 -6
- package/src/models/app_configuration.js +12 -9
- package/src/models/application.js +44 -22
- package/src/models/application_configuration.js +72 -72
- package/src/models/configuration.js +1 -0
- package/src/models/git.js +29 -1
- package/src/models/ids-resolver.js +37 -1
- package/src/models/interact.js +0 -24
- package/src/models/log-v4.js +13 -4
- package/src/models/namespaces.js +3 -2
- package/src/models/ng-resources.js +270 -0
- package/src/models/ng.js +276 -0
- package/src/models/operator.js +48 -0
- package/src/models/send-to-api.js +18 -0
- package/src/models/utils.js +21 -0
- package/src/parsers.js +71 -3
package/bin/clever.js
CHANGED
|
@@ -16,7 +16,7 @@ import * as Application from '../src/models/application.js';
|
|
|
16
16
|
import { AVAILABLE_ZONES } from '../src/models/application.js';
|
|
17
17
|
import { EXPERIMENTAL_FEATURES } from '../src/experimental-features.js';
|
|
18
18
|
import { getExitOnOption, getOutputFormatOption, getSameCommitPolicyOption } from '../src/command-options.js';
|
|
19
|
-
import { getFeatures } from '../src/models/configuration.js';
|
|
19
|
+
import { getFeatures, conf } from '../src/models/configuration.js';
|
|
20
20
|
|
|
21
21
|
import * as Addon from '../src/models/addon.js';
|
|
22
22
|
import * as ApplicationConfiguration from '../src/models/application_configuration.js';
|
|
@@ -36,26 +36,34 @@ import * as deploy from '../src/commands/deploy.js';
|
|
|
36
36
|
import * as diag from '../src/commands/diag.js';
|
|
37
37
|
import * as domain from '../src/commands/domain.js';
|
|
38
38
|
import * as drain from '../src/commands/drain.js';
|
|
39
|
+
import * as emails from '../src/commands/emails.js';
|
|
39
40
|
import * as env from '../src/commands/env.js';
|
|
40
41
|
import * as features from '../src/commands/features.js';
|
|
42
|
+
import * as keycloak from '../src/commands/keycloak.js';
|
|
41
43
|
import * as kv from '../src/commands/kv.js';
|
|
42
44
|
import * as link from '../src/commands/link.js';
|
|
43
45
|
import * as login from '../src/commands/login.js';
|
|
44
46
|
import * as logout from '../src/commands/logout.js';
|
|
45
47
|
import * as logs from '../src/commands/logs.js';
|
|
48
|
+
import * as matomo from '../src/commands/matomo.js';
|
|
49
|
+
import * as metabase from '../src/commands/metabase.js';
|
|
46
50
|
import * as makeDefault from '../src/commands/makeDefault.js';
|
|
51
|
+
import * as ng from '../src/commands/ng.js';
|
|
47
52
|
import * as notifyEmail from '../src/commands/notify-email.js';
|
|
48
53
|
import * as open from '../src/commands/open.js';
|
|
49
54
|
import * as consoleModule from '../src/commands/console.js';
|
|
55
|
+
import * as otoroshi from '../src/commands/otoroshi.js';
|
|
50
56
|
import * as profile from '../src/commands/profile.js';
|
|
51
57
|
import * as publishedConfig from '../src/commands/published-config.js';
|
|
52
58
|
import * as restart from '../src/commands/restart.js';
|
|
53
59
|
import * as scale from '../src/commands/scale.js';
|
|
54
60
|
import * as service from '../src/commands/service.js';
|
|
55
61
|
import * as ssh from '../src/commands/ssh.js';
|
|
62
|
+
import * as sshKeys from '../src/commands/ssh-keys.js';
|
|
56
63
|
import * as status from '../src/commands/status.js';
|
|
57
64
|
import * as stop from '../src/commands/stop.js';
|
|
58
65
|
import * as tcpRedirs from '../src/commands/tcp-redirs.js';
|
|
66
|
+
import * as tokens from '../src/commands/tokens.js';
|
|
59
67
|
import * as unlink from '../src/commands/unlink.js';
|
|
60
68
|
import * as version from '../src/commands/version.js';
|
|
61
69
|
import * as webhooks from '../src/commands/webhooks.js';
|
|
@@ -94,6 +102,45 @@ async function run () {
|
|
|
94
102
|
kvIdOrName: cliparse.argument('kv-id', {
|
|
95
103
|
description: 'Add-on/Real ID (or name, if unambiguous) of a Materia KV or Redis® add-on',
|
|
96
104
|
}),
|
|
105
|
+
apiTokenId: cliparse.argument('api-token-id', { description: 'API token ID' }),
|
|
106
|
+
apiTokenName: cliparse.argument('api-token-name', { description: 'API token name' }),
|
|
107
|
+
ngId: cliparse.argument('id', {
|
|
108
|
+
description: 'Network Group ID',
|
|
109
|
+
parser: Parsers.ngResourceType,
|
|
110
|
+
}),
|
|
111
|
+
ngLabel: cliparse.argument('ng-label', {
|
|
112
|
+
description: 'Network Group label',
|
|
113
|
+
parser: Parsers.ngResourceType,
|
|
114
|
+
}),
|
|
115
|
+
ngIdOrLabel: cliparse.argument('ng-id-or-label', {
|
|
116
|
+
description: 'Network Group ID or label',
|
|
117
|
+
parser: Parsers.ngResourceType,
|
|
118
|
+
}),
|
|
119
|
+
ngDescription: cliparse.argument('ng-description', {
|
|
120
|
+
description: 'Network Group description',
|
|
121
|
+
}),
|
|
122
|
+
ngExternalPeerLabel: cliparse.argument('external-peer-label', {
|
|
123
|
+
description: 'External peer label',
|
|
124
|
+
parser: Parsers.ngResourceType,
|
|
125
|
+
}),
|
|
126
|
+
ngExternalIdOrLabel: cliparse.argument('external-peer-id-or-label', {
|
|
127
|
+
description: 'External peer ID or label',
|
|
128
|
+
parser: Parsers.ngResourceType,
|
|
129
|
+
}),
|
|
130
|
+
ngAnyIdOrLabel: cliparse.argument('id-or-label', {
|
|
131
|
+
description: 'ID or Label of a Network group, a member or an (external) peer',
|
|
132
|
+
parser: Parsers.ngResourceType,
|
|
133
|
+
}),
|
|
134
|
+
wgPublicKey: cliparse.argument('public-key', {
|
|
135
|
+
metavar: 'public_key',
|
|
136
|
+
description: 'Wireguard public key of the external peer to link to a Network Group',
|
|
137
|
+
}),
|
|
138
|
+
email: cliparse.argument('email', {
|
|
139
|
+
description: 'Email address',
|
|
140
|
+
parser: Parsers.email,
|
|
141
|
+
}),
|
|
142
|
+
sshKeyName: cliparse.argument('ssh-key-name', { description: 'SSH key name' }),
|
|
143
|
+
sshKeyPath: cliparse.argument('ssh-key-path', { description: 'SSH public key path (.pub)' }),
|
|
97
144
|
addonIdOrName: cliparse.argument('addon-id', {
|
|
98
145
|
description: 'Add-on ID (or name, if unambiguous)',
|
|
99
146
|
parser: Parsers.addonIdOrName,
|
|
@@ -137,7 +184,7 @@ async function run () {
|
|
|
137
184
|
parser: Parsers.integer,
|
|
138
185
|
}),
|
|
139
186
|
configurationName: cliparse.argument('configuration-name', {
|
|
140
|
-
description:
|
|
187
|
+
description: `Configuration to manage: ${ApplicationConfiguration.listAvailableIds(true)}`,
|
|
141
188
|
complete () {
|
|
142
189
|
return cliparse.autocomplete.words(ApplicationConfiguration.listAvailableIds());
|
|
143
190
|
},
|
|
@@ -147,6 +194,40 @@ async function run () {
|
|
|
147
194
|
|
|
148
195
|
// OPTIONS
|
|
149
196
|
const opts = {
|
|
197
|
+
targetVersion: cliparse.option('target', {
|
|
198
|
+
metavar: 'version',
|
|
199
|
+
description: 'Target version to upgrade to (e.g.: 24, 2.4, 2.4.1)',
|
|
200
|
+
}),
|
|
201
|
+
apiTokenExpiration: cliparse.option('expiration', {
|
|
202
|
+
aliases: ['e'],
|
|
203
|
+
metavar: 'expiration',
|
|
204
|
+
parser: Parsers.futureDateOrDuration,
|
|
205
|
+
description: 'Duration until API token expiration (e.g.: 1h, 4d, 2w, 6M), default 1y',
|
|
206
|
+
}),
|
|
207
|
+
// Network Groups options
|
|
208
|
+
ngDescription: cliparse.option('description', {
|
|
209
|
+
metavar: 'description',
|
|
210
|
+
description: 'Network Group description',
|
|
211
|
+
}),
|
|
212
|
+
ngMembersIdsToLink: cliparse.option('link', {
|
|
213
|
+
metavar: 'members_ids',
|
|
214
|
+
description: "Comma separated list of members IDs to link to a Network Group ('app_xxx', 'addon_xxx', 'external_xxx')",
|
|
215
|
+
parser: Parsers.commaSeparated,
|
|
216
|
+
}),
|
|
217
|
+
ngMemberLabel: cliparse.option('label', {
|
|
218
|
+
required: false,
|
|
219
|
+
metavar: 'member_label',
|
|
220
|
+
description: 'The member label',
|
|
221
|
+
parser: Parsers.ngResourceType,
|
|
222
|
+
}),
|
|
223
|
+
ngPeerGetConfig: cliparse.flag('config', {
|
|
224
|
+
description: 'Get the Wireguard configuration of an external peer',
|
|
225
|
+
}),
|
|
226
|
+
ngResourceType: cliparse.option('type', {
|
|
227
|
+
metavar: 'type',
|
|
228
|
+
description: 'Type of resource to look for (NetworkGroup, Member, CleverPeer, ExternalPeer)',
|
|
229
|
+
parser: Parsers.ngValidType,
|
|
230
|
+
}),
|
|
150
231
|
sourceableEnvVarsList: cliparse.flag('add-export', { description: 'Display sourceable env variables setting' }),
|
|
151
232
|
logsFormat: getOutputFormatOption(['json-stream']),
|
|
152
233
|
activityFormat: getOutputFormatOption(['json-stream']),
|
|
@@ -443,10 +524,18 @@ async function run () {
|
|
|
443
524
|
aliases: ['y'],
|
|
444
525
|
description: 'Skip confirmation and delete the application directly',
|
|
445
526
|
}),
|
|
527
|
+
confirmSshKeyClean: cliparse.flag('yes', {
|
|
528
|
+
aliases: ['y'],
|
|
529
|
+
description: 'Skip confirmation and remove all SSH keys directly',
|
|
530
|
+
}),
|
|
446
531
|
confirmTcpRedirCreation: cliparse.flag('yes', {
|
|
447
532
|
aliases: ['y'],
|
|
448
533
|
description: 'Skip confirmation even if the TCP redirection is not free',
|
|
449
534
|
}),
|
|
535
|
+
yes: cliparse.flag('yes', {
|
|
536
|
+
aliases: ['y'],
|
|
537
|
+
description: 'Skip confirmation',
|
|
538
|
+
}),
|
|
450
539
|
jsonFormat: cliparse.flag('json', { aliases: ['j'], description: 'Show result in JSON format' }),
|
|
451
540
|
humanJsonOutputFormat: getOutputFormatOption(),
|
|
452
541
|
tag: cliparse.option('tag', {
|
|
@@ -567,7 +656,7 @@ async function run () {
|
|
|
567
656
|
description: 'Display or edit the configuration of your application',
|
|
568
657
|
options: [opts.alias, opts.appIdOrName],
|
|
569
658
|
commands: [configGetCommand, configSetCommand, configUpdateCommand],
|
|
570
|
-
}, config.
|
|
659
|
+
}, config.list);
|
|
571
660
|
|
|
572
661
|
// CREATE COMMAND
|
|
573
662
|
const appCreateCommand = cliparse.command('create', {
|
|
@@ -663,6 +752,32 @@ async function run () {
|
|
|
663
752
|
commands: [drainCreateCommand, drainRemoveCommand, drainEnableCommand, drainDisableCommand],
|
|
664
753
|
}, drain.list);
|
|
665
754
|
|
|
755
|
+
// EMAILS COMMANDS
|
|
756
|
+
const emailsAddCommand = cliparse.command('add', {
|
|
757
|
+
description: 'Add a new secondary email address to the current user',
|
|
758
|
+
args: [args.email],
|
|
759
|
+
}, emails.addSecondary);
|
|
760
|
+
const emailsPrimaryCommand = cliparse.command('primary', {
|
|
761
|
+
description: 'Set the primary email address of the current user',
|
|
762
|
+
args: [args.email],
|
|
763
|
+
}, emails.setPrimary);
|
|
764
|
+
const emailsRemoveCommand = cliparse.command('remove', {
|
|
765
|
+
description: 'Remove a secondary email address from the current user',
|
|
766
|
+
args: [args.email],
|
|
767
|
+
}, emails.removeSecondary);
|
|
768
|
+
const emailsClearCommand = cliparse.command('remove-all', {
|
|
769
|
+
description: 'Remove all secondary email addresses from the current user',
|
|
770
|
+
options: [opts.yes],
|
|
771
|
+
}, emails.removeAllSecondary);
|
|
772
|
+
const emailsOpenConsoleCommand = cliparse.command('open', {
|
|
773
|
+
description: 'Open the email addresses management page in the Console',
|
|
774
|
+
}, emails.openConsole);
|
|
775
|
+
const emailsCommands = cliparse.command('emails', {
|
|
776
|
+
description: 'Manage email addresses of the current user',
|
|
777
|
+
privateOptions: [opts.humanJsonOutputFormat],
|
|
778
|
+
commands: [emailsAddCommand, emailsPrimaryCommand, emailsRemoveCommand, emailsClearCommand, emailsOpenConsoleCommand],
|
|
779
|
+
}, emails.list);
|
|
780
|
+
|
|
666
781
|
// ENV COMMANDS
|
|
667
782
|
const envSetCommand = cliparse.command('set', {
|
|
668
783
|
description: 'Add or update an environment variable named <variable-name> with the value <variable-value>',
|
|
@@ -709,6 +824,63 @@ async function run () {
|
|
|
709
824
|
commands: [enableFeatureCommand, disableFeatureCommand, listFeaturesCommand, infoFeaturesCommand],
|
|
710
825
|
}, features.list);
|
|
711
826
|
|
|
827
|
+
// KEYCLOAK COMMAND
|
|
828
|
+
const keycloakGetCommand = cliparse.command('get', {
|
|
829
|
+
description: 'Get information about a deployed Keycloak',
|
|
830
|
+
args: [args.addonIdOrName],
|
|
831
|
+
options: [opts.humanJsonOutputFormat],
|
|
832
|
+
}, keycloak.get);
|
|
833
|
+
const keycloakEnableNgCommand = cliparse.command('enable-ng', {
|
|
834
|
+
description: 'Link Keycloak to a Network Group, used for multi-instances secure communication',
|
|
835
|
+
args: [args.addonIdOrName],
|
|
836
|
+
}, keycloak.ngEnable);
|
|
837
|
+
const keycloakDisableNgCommand = cliparse.command('disable-ng', {
|
|
838
|
+
description: 'Unlink Keycloak from its Network Group',
|
|
839
|
+
args: [args.addonIdOrName],
|
|
840
|
+
}, keycloak.ngDisable);
|
|
841
|
+
const keycloakOpenLogsCommand = cliparse.command('logs', {
|
|
842
|
+
description: 'Open the Keycloak application logs in Clever Cloud Console',
|
|
843
|
+
args: [args.addonIdOrName],
|
|
844
|
+
}, keycloak.openLogs);
|
|
845
|
+
const keycloakOpenWebUiCommand = cliparse.command('webui', {
|
|
846
|
+
description: 'Open the Keycloak admin console in your browser',
|
|
847
|
+
args: [args.addonIdOrName],
|
|
848
|
+
}, keycloak.openWebUi);
|
|
849
|
+
const keycloakOpenCommand = cliparse.command('open', {
|
|
850
|
+
description: 'Open the Keycloak dashboard in Clever Cloud Console',
|
|
851
|
+
args: [args.addonIdOrName],
|
|
852
|
+
commands: [keycloakOpenLogsCommand, keycloakOpenWebUiCommand],
|
|
853
|
+
}, keycloak.open);
|
|
854
|
+
const keycloakRestartCommand = cliparse.command('restart', {
|
|
855
|
+
description: 'Restart Keycloak',
|
|
856
|
+
args: [args.addonIdOrName],
|
|
857
|
+
}, keycloak.reboot);
|
|
858
|
+
const keycloakRebuildCommand = cliparse.command('rebuild', {
|
|
859
|
+
description: 'Rebuild Keycloak',
|
|
860
|
+
args: [args.addonIdOrName],
|
|
861
|
+
}, keycloak.rebuild);
|
|
862
|
+
const keycloakVersionCheckCommand = cliparse.command('check', {
|
|
863
|
+
description: 'Check Keycloak deployed version',
|
|
864
|
+
args: [args.addonIdOrName],
|
|
865
|
+
options: [opts.humanJsonOutputFormat],
|
|
866
|
+
}, keycloak.checkVersion);
|
|
867
|
+
const keycloakVersionUpdateCommand = cliparse.command('update', {
|
|
868
|
+
description: 'Update Keycloak deployed version',
|
|
869
|
+
args: [args.addonIdOrName],
|
|
870
|
+
options: [opts.targetVersion],
|
|
871
|
+
}, keycloak.updateVersion);
|
|
872
|
+
const keycloakVersionsCommands = cliparse.command('version', {
|
|
873
|
+
description: 'Check Keycloak deployed version',
|
|
874
|
+
args: [args.addonIdOrName],
|
|
875
|
+
options: [opts.humanJsonOutputFormat],
|
|
876
|
+
commands: [keycloakVersionCheckCommand, keycloakVersionUpdateCommand],
|
|
877
|
+
}, keycloak.checkVersion);
|
|
878
|
+
const keycloakCommand = cliparse.command('keycloak', {
|
|
879
|
+
description: 'Manage Clever Cloud Keycloak services',
|
|
880
|
+
privateOptions: [opts.humanJsonOutputFormat],
|
|
881
|
+
commands: [keycloakGetCommand, keycloakEnableNgCommand, keycloakDisableNgCommand, keycloakOpenCommand, keycloakRestartCommand, keycloakRebuildCommand, keycloakVersionsCommands],
|
|
882
|
+
}, keycloak.list);
|
|
883
|
+
|
|
712
884
|
// KV COMMAND
|
|
713
885
|
const kvRawCommand = cliparse.command('kv', {
|
|
714
886
|
description: 'Send a raw command to a Materia KV or Redis® add-on',
|
|
@@ -746,6 +918,138 @@ async function run () {
|
|
|
746
918
|
args: [args.alias],
|
|
747
919
|
}, makeDefault.makeDefault);
|
|
748
920
|
|
|
921
|
+
// MATOMO COMMAND
|
|
922
|
+
const matomoGetCommand = cliparse.command('get', {
|
|
923
|
+
description: 'Get information about a deployed Matomo',
|
|
924
|
+
args: [args.addonIdOrName],
|
|
925
|
+
options: [opts.humanJsonOutputFormat],
|
|
926
|
+
}, matomo.get);
|
|
927
|
+
const matomoOpenLogsCommand = cliparse.command('logs', {
|
|
928
|
+
description: 'Open the Matomo application logs in Clever Cloud Console',
|
|
929
|
+
args: [args.addonIdOrName],
|
|
930
|
+
}, matomo.openLogs);
|
|
931
|
+
const matomoOpenWebUiCommand = cliparse.command('webui', {
|
|
932
|
+
description: 'Open the Matomo admin console in your browser',
|
|
933
|
+
args: [args.addonIdOrName],
|
|
934
|
+
}, matomo.openWebUi);
|
|
935
|
+
const matomoOpenCommand = cliparse.command('open', {
|
|
936
|
+
description: 'Open the Matomo dashboard in Clever Cloud Console',
|
|
937
|
+
args: [args.addonIdOrName],
|
|
938
|
+
commands: [matomoOpenLogsCommand, matomoOpenWebUiCommand],
|
|
939
|
+
}, matomo.open);
|
|
940
|
+
const matomoRestartCommand = cliparse.command('restart', {
|
|
941
|
+
description: 'Restart Matomo',
|
|
942
|
+
args: [args.addonIdOrName],
|
|
943
|
+
}, matomo.reboot);
|
|
944
|
+
const matomoRebuildCommand = cliparse.command('rebuild', {
|
|
945
|
+
description: 'Rebuild Matomo',
|
|
946
|
+
args: [args.addonIdOrName],
|
|
947
|
+
}, matomo.rebuild);
|
|
948
|
+
const matomoCommand = cliparse.command('matomo', {
|
|
949
|
+
description: 'Manage Clever Cloud Matomo services',
|
|
950
|
+
privateOptions: [opts.humanJsonOutputFormat],
|
|
951
|
+
commands: [matomoGetCommand, matomoOpenCommand, matomoRestartCommand, matomoRebuildCommand],
|
|
952
|
+
}, matomo.list);
|
|
953
|
+
|
|
954
|
+
// METABASE COMMAND
|
|
955
|
+
const metabaseGetCommand = cliparse.command('get', {
|
|
956
|
+
description: 'Get information about a deployed Metabase',
|
|
957
|
+
args: [args.addonIdOrName],
|
|
958
|
+
options: [opts.humanJsonOutputFormat],
|
|
959
|
+
}, metabase.get);
|
|
960
|
+
const metabaseOpenLogsCommand = cliparse.command('logs', {
|
|
961
|
+
description: 'Open the Metabase application logs in Clever Cloud Console',
|
|
962
|
+
args: [args.addonIdOrName],
|
|
963
|
+
}, metabase.openLogs);
|
|
964
|
+
const metabaseOpenWebUiCommand = cliparse.command('webui', {
|
|
965
|
+
description: 'Open the Metabase admin console in your browser',
|
|
966
|
+
args: [args.addonIdOrName],
|
|
967
|
+
}, metabase.openWebUi);
|
|
968
|
+
const metabaseOpenCommand = cliparse.command('open', {
|
|
969
|
+
description: 'Open the Metabase dashboard in Clever Cloud Console',
|
|
970
|
+
args: [args.addonIdOrName],
|
|
971
|
+
commands: [metabaseOpenLogsCommand, metabaseOpenWebUiCommand],
|
|
972
|
+
}, metabase.open);
|
|
973
|
+
const metabaseRestartCommand = cliparse.command('restart', {
|
|
974
|
+
description: 'Restart Metabase',
|
|
975
|
+
args: [args.addonIdOrName],
|
|
976
|
+
}, metabase.reboot);
|
|
977
|
+
const metabaseRebuildCommand = cliparse.command('rebuild', {
|
|
978
|
+
description: 'Rebuild Metabase',
|
|
979
|
+
args: [args.addonIdOrName],
|
|
980
|
+
}, metabase.rebuild);
|
|
981
|
+
const metabaseVersionCheckCommand = cliparse.command('check', {
|
|
982
|
+
description: 'Check Metabase deployed version',
|
|
983
|
+
args: [args.addonIdOrName],
|
|
984
|
+
options: [opts.humanJsonOutputFormat],
|
|
985
|
+
}, metabase.checkVersion);
|
|
986
|
+
const metabaseVersionUpdateCommand = cliparse.command('update', {
|
|
987
|
+
description: 'Update Metabase deployed version',
|
|
988
|
+
args: [args.addonIdOrName],
|
|
989
|
+
options: [opts.targetVersion],
|
|
990
|
+
}, metabase.updateVersion);
|
|
991
|
+
const metabaseVersionsCommands = cliparse.command('version', {
|
|
992
|
+
description: 'Manage Metabase deployed version',
|
|
993
|
+
args: [args.addonIdOrName],
|
|
994
|
+
options: [opts.humanJsonOutputFormat],
|
|
995
|
+
commands: [metabaseVersionCheckCommand, metabaseVersionUpdateCommand],
|
|
996
|
+
}, metabase.checkVersion);
|
|
997
|
+
const metabaseCommand = cliparse.command('metabase', {
|
|
998
|
+
description: 'Manage Clever Cloud Metabase services',
|
|
999
|
+
privateOptions: [opts.humanJsonOutputFormat],
|
|
1000
|
+
commands: [metabaseGetCommand, metabaseOpenCommand, metabaseRestartCommand, metabaseRebuildCommand, metabaseVersionsCommands],
|
|
1001
|
+
}, metabase.list);
|
|
1002
|
+
|
|
1003
|
+
// NETWORK GROUP COMMANDS
|
|
1004
|
+
const ngCreateExternalPeerCommand = cliparse.command('external', {
|
|
1005
|
+
description: 'Create an external peer in a Network Group',
|
|
1006
|
+
args: [args.ngExternalPeerLabel, args.ngIdOrLabel, args.wgPublicKey],
|
|
1007
|
+
}, ng.createExternalPeer);
|
|
1008
|
+
const ngDeleteExternalPeerCommand = cliparse.command('external', {
|
|
1009
|
+
description: 'Delete an external peer from a Network Group',
|
|
1010
|
+
args: [args.ngExternalIdOrLabel, args.ngIdOrLabel],
|
|
1011
|
+
}, ng.deleteExternalPeer);
|
|
1012
|
+
const ngCreateCommand = cliparse.command('create', {
|
|
1013
|
+
description: 'Create a Network Group',
|
|
1014
|
+
args: [args.ngLabel],
|
|
1015
|
+
privateOptions: [opts.ngMembersIdsToLink, opts.ngDescription, opts.optTags],
|
|
1016
|
+
commands: [ngCreateExternalPeerCommand],
|
|
1017
|
+
}, ng.createNg);
|
|
1018
|
+
const ngDeleteCommand = cliparse.command('delete', {
|
|
1019
|
+
description: 'Delete a Network Group',
|
|
1020
|
+
args: [args.ngIdOrLabel],
|
|
1021
|
+
commands: [ngDeleteExternalPeerCommand],
|
|
1022
|
+
}, ng.deleteNg);
|
|
1023
|
+
const ngLinkCommand = cliparse.command('link', {
|
|
1024
|
+
description: 'Link an application or a database add-on by its ID to a Network Group',
|
|
1025
|
+
args: [args.ngAnyIdOrLabel, args.ngIdOrLabel],
|
|
1026
|
+
}, ng.linkToNg);
|
|
1027
|
+
const ngUnlinkCommand = cliparse.command('unlink', {
|
|
1028
|
+
description: 'Unlink an application or a database add-on by its ID from a Network Group',
|
|
1029
|
+
args: [args.ngAnyIdOrLabel, args.ngIdOrLabel],
|
|
1030
|
+
}, ng.unlinkFromNg);
|
|
1031
|
+
const ngGetCommand = cliparse.command('get', {
|
|
1032
|
+
description: 'Get details about a Network Group, a member or a peer',
|
|
1033
|
+
args: [args.ngAnyIdOrLabel],
|
|
1034
|
+
options: [opts.ngResourceType, opts.humanJsonOutputFormat],
|
|
1035
|
+
}, ng.get);
|
|
1036
|
+
const ngGetConfigCommand = cliparse.command('get-config', {
|
|
1037
|
+
description: 'Get the Wireguard configuration of a peer in a Network Group',
|
|
1038
|
+
args: [args.ngExternalIdOrLabel, args.ngIdOrLabel],
|
|
1039
|
+
options: [opts.humanJsonOutputFormat],
|
|
1040
|
+
}, ng.getPeerConfig);
|
|
1041
|
+
const ngSearchCommand = cliparse.command('search', {
|
|
1042
|
+
description: 'Search Network Groups, members or peers and get their details',
|
|
1043
|
+
args: [args.ngAnyIdOrLabel],
|
|
1044
|
+
options: [opts.ngResourceType, opts.humanJsonOutputFormat],
|
|
1045
|
+
}, ng.search);
|
|
1046
|
+
const networkGroupsCommand = cliparse.command('ng', {
|
|
1047
|
+
description: 'List Network Groups',
|
|
1048
|
+
options: [opts.orgaIdOrName],
|
|
1049
|
+
privateOptions: [opts.humanJsonOutputFormat],
|
|
1050
|
+
commands: [ngCreateCommand, ngDeleteCommand, ngLinkCommand, ngUnlinkCommand, ngGetCommand, ngGetConfigCommand, ngSearchCommand],
|
|
1051
|
+
}, ng.listNg);
|
|
1052
|
+
|
|
749
1053
|
// NOTIFY-EMAIL COMMAND
|
|
750
1054
|
const addEmailNotificationCommand = cliparse.command('add', {
|
|
751
1055
|
description: 'Add a new email notification',
|
|
@@ -769,6 +1073,63 @@ async function run () {
|
|
|
769
1073
|
options: [opts.alias, opts.appIdOrName],
|
|
770
1074
|
}, open.open);
|
|
771
1075
|
|
|
1076
|
+
// OTOROSHI COMMAND
|
|
1077
|
+
const otoroshiGetCommand = cliparse.command('get', {
|
|
1078
|
+
description: 'Get information about a deployed Otoroshi',
|
|
1079
|
+
args: [args.addonIdOrName],
|
|
1080
|
+
options: [opts.humanJsonOutputFormat],
|
|
1081
|
+
}, otoroshi.get);
|
|
1082
|
+
const otoroshiEnableNgCommand = cliparse.command('enable-ng', {
|
|
1083
|
+
description: 'Link Otoroshi to a Network Group',
|
|
1084
|
+
args: [args.addonIdOrName],
|
|
1085
|
+
}, otoroshi.ngEnable);
|
|
1086
|
+
const otoroshiDisableNgCommand = cliparse.command('disable-ng', {
|
|
1087
|
+
description: 'Unlink Otoroshi from its Network Group',
|
|
1088
|
+
args: [args.addonIdOrName],
|
|
1089
|
+
}, otoroshi.ngDisable);
|
|
1090
|
+
const otoroshiOpenLogsCommand = cliparse.command('logs', {
|
|
1091
|
+
description: 'Open the Otoroshi application logs in Clever Cloud Console',
|
|
1092
|
+
args: [args.addonIdOrName],
|
|
1093
|
+
}, otoroshi.openLogs);
|
|
1094
|
+
const otoroshiOpenWebUiCommand = cliparse.command('webui', {
|
|
1095
|
+
description: 'Open the Otoroshi admin console in your browser',
|
|
1096
|
+
args: [args.addonIdOrName],
|
|
1097
|
+
}, otoroshi.openWebUi);
|
|
1098
|
+
const otoroshiOpenCommand = cliparse.command('open', {
|
|
1099
|
+
description: 'Open the Otoroshi dashboard in Clever Cloud Console',
|
|
1100
|
+
args: [args.addonIdOrName],
|
|
1101
|
+
commands: [otoroshiOpenLogsCommand, otoroshiOpenWebUiCommand],
|
|
1102
|
+
}, otoroshi.open);
|
|
1103
|
+
const otoroshiRestartCommand = cliparse.command('restart', {
|
|
1104
|
+
description: 'Restart Otoroshi',
|
|
1105
|
+
args: [args.addonIdOrName],
|
|
1106
|
+
}, otoroshi.reboot);
|
|
1107
|
+
const otoroshiRebuildCommand = cliparse.command('rebuild', {
|
|
1108
|
+
description: 'Rebuild Otoroshi',
|
|
1109
|
+
args: [args.addonIdOrName],
|
|
1110
|
+
}, otoroshi.rebuild);
|
|
1111
|
+
const otoroshiVersionCheckCommand = cliparse.command('check', {
|
|
1112
|
+
description: 'Check Otoroshi deployed version',
|
|
1113
|
+
args: [args.addonIdOrName],
|
|
1114
|
+
options: [opts.humanJsonOutputFormat],
|
|
1115
|
+
}, otoroshi.checkVersion);
|
|
1116
|
+
const otoroshiVersionUpdateCommand = cliparse.command('update', {
|
|
1117
|
+
description: 'Update Otoroshi deployed version',
|
|
1118
|
+
args: [args.addonIdOrName],
|
|
1119
|
+
options: [opts.targetVersion],
|
|
1120
|
+
}, otoroshi.updateVersion);
|
|
1121
|
+
const otoroshiVersionsCommands = cliparse.command('version', {
|
|
1122
|
+
description: 'Manage Otoroshi deployed version',
|
|
1123
|
+
args: [args.addonIdOrName],
|
|
1124
|
+
options: [opts.humanJsonOutputFormat],
|
|
1125
|
+
commands: [otoroshiVersionCheckCommand, otoroshiVersionUpdateCommand],
|
|
1126
|
+
}, otoroshi.checkVersion);
|
|
1127
|
+
const otoroshiCommand = cliparse.command('otoroshi', {
|
|
1128
|
+
description: 'Manage Clever Cloud Otoroshi services',
|
|
1129
|
+
privateOptions: [opts.humanJsonOutputFormat],
|
|
1130
|
+
commands: [otoroshiGetCommand, otoroshiEnableNgCommand, otoroshiDisableNgCommand, otoroshiOpenCommand, otoroshiRestartCommand, otoroshiRebuildCommand, otoroshiVersionsCommands],
|
|
1131
|
+
}, otoroshi.list);
|
|
1132
|
+
|
|
772
1133
|
// CONSOLE COMMAND
|
|
773
1134
|
const consoleCommand = cliparse.command('console', {
|
|
774
1135
|
description: 'Open an application in the Console',
|
|
@@ -847,6 +1208,28 @@ async function run () {
|
|
|
847
1208
|
options: [opts.alias, opts.appIdOrName, opts.sshIdentityFile],
|
|
848
1209
|
}, ssh.ssh);
|
|
849
1210
|
|
|
1211
|
+
// SSH KEYS COMMANDS
|
|
1212
|
+
const sshKeysAddCommand = cliparse.command('add', {
|
|
1213
|
+
description: 'Add a new SSH key to the current user',
|
|
1214
|
+
args: [args.sshKeyName, args.sshKeyPath],
|
|
1215
|
+
}, sshKeys.add);
|
|
1216
|
+
const sshKeysRemoveCommand = cliparse.command('remove', {
|
|
1217
|
+
description: 'Remove a SSH key from the current user',
|
|
1218
|
+
args: [args.sshKeyName],
|
|
1219
|
+
}, sshKeys.remove);
|
|
1220
|
+
const sshKeysRemoveAllCommand = cliparse.command('remove-all', {
|
|
1221
|
+
description: 'Remove all SSH keys from the current user',
|
|
1222
|
+
options: [opts.confirmSshKeyClean],
|
|
1223
|
+
}, sshKeys.removeAll);
|
|
1224
|
+
const sshKeysOpenConsoleCommand = cliparse.command('open', {
|
|
1225
|
+
description: 'Open the SSH keys management page in the Console',
|
|
1226
|
+
}, sshKeys.openConsole);
|
|
1227
|
+
const sshKeysCommands = cliparse.command('ssh-keys', {
|
|
1228
|
+
description: 'Manage SSH keys of the current user',
|
|
1229
|
+
privateOptions: [opts.humanJsonOutputFormat],
|
|
1230
|
+
commands: [sshKeysAddCommand, sshKeysRemoveCommand, sshKeysRemoveAllCommand, sshKeysOpenConsoleCommand],
|
|
1231
|
+
}, sshKeys.list);
|
|
1232
|
+
|
|
850
1233
|
// STATUS COMMAND
|
|
851
1234
|
const statusCommand = cliparse.command('status', {
|
|
852
1235
|
description: 'See the status of an application',
|
|
@@ -880,6 +1263,22 @@ async function run () {
|
|
|
880
1263
|
commands: [tcpRedirsListNamespacesCommand, tcpRedirsAddCommand, tcpRedirsRemoveCommand],
|
|
881
1264
|
}, tcpRedirs.list);
|
|
882
1265
|
|
|
1266
|
+
// TOKENS COMMANDS
|
|
1267
|
+
const apiTokenCreateCommand = cliparse.command('create', {
|
|
1268
|
+
description: 'Create an API token',
|
|
1269
|
+
args: [args.apiTokenName],
|
|
1270
|
+
options: [opts.apiTokenExpiration, opts.humanJsonOutputFormat],
|
|
1271
|
+
}, tokens.create);
|
|
1272
|
+
const apiTokenRevokeCommand = cliparse.command('revoke', {
|
|
1273
|
+
description: 'Revoke an API token',
|
|
1274
|
+
args: [args.apiTokenId],
|
|
1275
|
+
}, tokens.revoke);
|
|
1276
|
+
const tokensCommands = cliparse.command('tokens', {
|
|
1277
|
+
description: `Manage API tokens to query Clever Cloud API from ${conf.AUTH_BRIDGE_HOST}`,
|
|
1278
|
+
commands: [apiTokenCreateCommand, apiTokenRevokeCommand],
|
|
1279
|
+
privateOptions: [opts.humanJsonOutputFormat],
|
|
1280
|
+
}, tokens.list);
|
|
1281
|
+
|
|
883
1282
|
// UNLINK COMMAND
|
|
884
1283
|
const appUnlinkCommand = cliparse.command('unlink', {
|
|
885
1284
|
description: 'Unlink this repo from an existing application',
|
|
@@ -953,6 +1352,7 @@ async function run () {
|
|
|
953
1352
|
domainCommands,
|
|
954
1353
|
drainCommands,
|
|
955
1354
|
emailNotificationsCommand,
|
|
1355
|
+
emailsCommands,
|
|
956
1356
|
envCommands,
|
|
957
1357
|
featuresCommands,
|
|
958
1358
|
cliparseCommands.helpCommand,
|
|
@@ -968,9 +1368,11 @@ async function run () {
|
|
|
968
1368
|
scaleCommand,
|
|
969
1369
|
serviceCommands,
|
|
970
1370
|
sshCommand,
|
|
1371
|
+
sshKeysCommands,
|
|
971
1372
|
statusCommand,
|
|
972
1373
|
stopCommand,
|
|
973
1374
|
tcpRedirsCommands,
|
|
1375
|
+
tokensCommands,
|
|
974
1376
|
versionCommand,
|
|
975
1377
|
webhooksCommand,
|
|
976
1378
|
];
|
|
@@ -978,10 +1380,21 @@ async function run () {
|
|
|
978
1380
|
// Add experimental features only if they are enabled through the configuration file
|
|
979
1381
|
const featuresFromConf = await getFeatures();
|
|
980
1382
|
|
|
1383
|
+
if (featuresFromConf.operators) {
|
|
1384
|
+
commands.push(colorizeExperimentalCommand(keycloakCommand, 'operators'));
|
|
1385
|
+
commands.push(colorizeExperimentalCommand(matomoCommand, 'operators'));
|
|
1386
|
+
commands.push(colorizeExperimentalCommand(metabaseCommand, 'operators'));
|
|
1387
|
+
commands.push(colorizeExperimentalCommand(otoroshiCommand, 'operators'));
|
|
1388
|
+
}
|
|
1389
|
+
|
|
981
1390
|
if (featuresFromConf.kv) {
|
|
982
1391
|
commands.push(colorizeExperimentalCommand(kvRawCommand, 'kv'));
|
|
983
1392
|
}
|
|
984
1393
|
|
|
1394
|
+
if (featuresFromConf.ng) {
|
|
1395
|
+
commands.push(colorizeExperimentalCommand(networkGroupsCommand, 'ng'));
|
|
1396
|
+
}
|
|
1397
|
+
|
|
985
1398
|
// CLI PARSER
|
|
986
1399
|
const cliParser = cliparse.cli({
|
|
987
1400
|
name: 'clever',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clever-tools",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.13.0",
|
|
4
4
|
"description": "Command Line Interface for Clever Cloud.",
|
|
5
5
|
"main": "bin/clever.js",
|
|
6
6
|
"type": "module",
|
|
@@ -26,12 +26,13 @@
|
|
|
26
26
|
"scripts/*.sh"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@clevercloud/client": "9.
|
|
29
|
+
"@clevercloud/client": "9.2.0",
|
|
30
|
+
"@inquirer/prompts": "7.3.2",
|
|
30
31
|
"cliparse": "0.5.0",
|
|
31
32
|
"colors": "1.4.0",
|
|
32
33
|
"common-env": "6.4.0",
|
|
33
34
|
"curlconverter": "3.21.0",
|
|
34
|
-
"
|
|
35
|
+
"dedent": "1.5.3",
|
|
35
36
|
"eventsource": "1.1.0",
|
|
36
37
|
"ioredis": "5.4.1",
|
|
37
38
|
"iso8601-duration": "2.1.2",
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export function createApiToken ({ email, password, mfaCode, name, description = '', expirationDate }) {
|
|
2
|
+
return Promise.resolve({
|
|
3
|
+
method: 'post',
|
|
4
|
+
url: '/api-tokens',
|
|
5
|
+
headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
|
|
6
|
+
body: { email, password, mfaCode, name, description, expirationDate },
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function listApiTokens () {
|
|
11
|
+
return Promise.resolve({
|
|
12
|
+
method: 'get',
|
|
13
|
+
url: '/api-tokens',
|
|
14
|
+
headers: { Accept: 'application/json' },
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function updateApiToken (apiTokenId, { name, description }) {
|
|
19
|
+
return Promise.resolve({
|
|
20
|
+
method: 'put',
|
|
21
|
+
url: `/api-tokens/${apiTokenId}`,
|
|
22
|
+
headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
|
|
23
|
+
body: { name, description },
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function deleteApiToken (apiTokenId) {
|
|
28
|
+
return Promise.resolve({
|
|
29
|
+
method: 'delete',
|
|
30
|
+
url: `/api-tokens/${apiTokenId}`,
|
|
31
|
+
headers: { Accept: 'application/json' },
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function addOauthHeaderPlaintext (tokens) {
|
|
36
|
+
|
|
37
|
+
return async function (requestParams) {
|
|
38
|
+
|
|
39
|
+
const authorizationHeader = (
|
|
40
|
+
'OAuth '
|
|
41
|
+
+ [
|
|
42
|
+
`oauth_consumer_key="${tokens.OAUTH_CONSUMER_KEY}"`,
|
|
43
|
+
`oauth_token="${tokens.API_OAUTH_TOKEN}"`,
|
|
44
|
+
// %26 is URL escaped character "&"
|
|
45
|
+
`oauth_signature="${tokens.OAUTH_CONSUMER_SECRET}%26${tokens.API_OAUTH_TOKEN_SECRET}"`,
|
|
46
|
+
// oauth_nonce is not mandatory
|
|
47
|
+
// oauth_signature_method is not mandatory, it defaults to PLAINTEXT
|
|
48
|
+
// oauth_timestamp is not mandatory
|
|
49
|
+
// oauth_version is not mandatory, it defaults to 1.0
|
|
50
|
+
].join(', ')
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
...requestParams,
|
|
55
|
+
headers: {
|
|
56
|
+
authorization: authorizationHeader,
|
|
57
|
+
...requestParams.headers,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// TODO: Move this to the Clever Cloud JS Client
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* GET /networkgroups/organisations/{ownerId}/networkgroups/search?query
|
|
5
|
+
* @param {Object} params
|
|
6
|
+
* @param {String} params.ownerId
|
|
7
|
+
* @param {String} params.query
|
|
8
|
+
*/
|
|
9
|
+
export function searchNetworkGroupOrResource (params) {
|
|
10
|
+
// no multipath for /self or /organisations/{id}
|
|
11
|
+
return Promise.resolve({
|
|
12
|
+
method: 'get',
|
|
13
|
+
url: `/v4/networkgroups/organisations/${params.ownerId}/networkgroups/search`,
|
|
14
|
+
headers: { Accept: 'application/json' },
|
|
15
|
+
queryParams: { query: params.query },
|
|
16
|
+
// no body
|
|
17
|
+
});
|
|
18
|
+
}
|