clever-tools 4.0.2 → 4.2.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 +25 -74
- package/package.json +2 -2
- package/src/commands/accesslogs.js +1 -1
- package/src/commands/addon.js +119 -146
- package/src/commands/diag.js +33 -4
- package/src/commands/domain.js +67 -46
- package/src/commands/emails.js +1 -15
- package/src/commands/link.js +4 -4
- package/src/commands/ng.js +1 -1
- package/src/commands/ssh-keys.js +2 -13
- package/src/commands/status.js +5 -0
- package/src/commands/tcp-redirs.js +2 -31
- package/src/commands/tokens.js +1 -4
- package/src/experimental-features.js +5 -5
- package/src/lib/format-date.js +3 -0
- package/src/logger.js +10 -0
- package/src/models/app_configuration.js +10 -6
- package/src/models/emails.js +16 -0
- package/src/models/log-v4.js +3 -2
- package/src/models/ng-resources.js +16 -28
- package/src/models/ng.js +14 -15
- package/src/models/ssh-keys.js +10 -0
- package/src/parsers.js +3 -2
package/bin/clever.js
CHANGED
|
@@ -79,6 +79,10 @@ process.stdout.on('error', (error) => {
|
|
|
79
79
|
const cliparseCommand = cliparse.command;
|
|
80
80
|
|
|
81
81
|
cliparse.command = function (name, options, commandFunction) {
|
|
82
|
+
if (commandFunction == null) {
|
|
83
|
+
return cliparseCommand(name, options);
|
|
84
|
+
}
|
|
85
|
+
|
|
82
86
|
return cliparseCommand(name, options, (...args) => {
|
|
83
87
|
const promise = commandFunction(...args);
|
|
84
88
|
handleCommandPromise(promise);
|
|
@@ -103,10 +107,6 @@ async function run() {
|
|
|
103
107
|
}),
|
|
104
108
|
apiTokenId: cliparse.argument('api-token-id', { description: 'API token ID' }),
|
|
105
109
|
apiTokenName: cliparse.argument('api-token-name', { description: 'API token name' }),
|
|
106
|
-
ngId: cliparse.argument('id', {
|
|
107
|
-
description: 'Network Group ID',
|
|
108
|
-
parser: Parsers.ngResourceType,
|
|
109
|
-
}),
|
|
110
110
|
ngLabel: cliparse.argument('ng-label', {
|
|
111
111
|
description: 'Network Group label',
|
|
112
112
|
parser: Parsers.ngResourceType,
|
|
@@ -115,9 +115,6 @@ async function run() {
|
|
|
115
115
|
description: 'Network Group ID or label',
|
|
116
116
|
parser: Parsers.ngResourceType,
|
|
117
117
|
}),
|
|
118
|
-
ngDescription: cliparse.argument('ng-description', {
|
|
119
|
-
description: 'Network Group description',
|
|
120
|
-
}),
|
|
121
118
|
ngExternalPeerLabel: cliparse.argument('external-peer-label', {
|
|
122
119
|
description: 'External peer label',
|
|
123
120
|
parser: Parsers.ngResourceType,
|
|
@@ -127,12 +124,16 @@ async function run() {
|
|
|
127
124
|
parser: Parsers.ngResourceType,
|
|
128
125
|
}),
|
|
129
126
|
ngAnyIdOrLabel: cliparse.argument('id-or-label', {
|
|
130
|
-
description: 'ID or Label of a Network
|
|
127
|
+
description: 'ID or Label of a Network Group, a member or an (external) peer',
|
|
128
|
+
parser: Parsers.ngResourceType,
|
|
129
|
+
}),
|
|
130
|
+
ngResourceId: cliparse.argument('id', {
|
|
131
|
+
description: 'ID of a resource to (un)link to a Network Group',
|
|
131
132
|
parser: Parsers.ngResourceType,
|
|
132
133
|
}),
|
|
133
134
|
wgPublicKey: cliparse.argument('public-key', {
|
|
134
135
|
metavar: 'public_key',
|
|
135
|
-
description: '
|
|
136
|
+
description: 'WireGuard public key of the external peer to link to a Network Group',
|
|
136
137
|
}),
|
|
137
138
|
email: cliparse.argument('email', {
|
|
138
139
|
description: 'Email address',
|
|
@@ -213,18 +214,9 @@ async function run() {
|
|
|
213
214
|
ngMembersIdsToLink: cliparse.option('link', {
|
|
214
215
|
metavar: 'members_ids',
|
|
215
216
|
description:
|
|
216
|
-
|
|
217
|
+
'Comma separated list of members IDs to link to a Network Group (app_xxx, external_xxx, mysql_xxx, postgresql_xxx, redis_xxx, etc.)',
|
|
217
218
|
parser: Parsers.commaSeparated,
|
|
218
219
|
}),
|
|
219
|
-
ngMemberLabel: cliparse.option('label', {
|
|
220
|
-
required: false,
|
|
221
|
-
metavar: 'member_label',
|
|
222
|
-
description: 'The member label',
|
|
223
|
-
parser: Parsers.ngResourceType,
|
|
224
|
-
}),
|
|
225
|
-
ngPeerGetConfig: cliparse.flag('config', {
|
|
226
|
-
description: 'Get the Wireguard configuration of an external peer',
|
|
227
|
-
}),
|
|
228
220
|
ngResourceType: cliparse.option('type', {
|
|
229
221
|
metavar: 'type',
|
|
230
222
|
description: 'Type of resource to look for (NetworkGroup, Member, CleverPeer, ExternalPeer)',
|
|
@@ -265,10 +257,6 @@ async function run() {
|
|
|
265
257
|
metavar: 'TEXT',
|
|
266
258
|
description: 'Get only domains containing the provided text',
|
|
267
259
|
}),
|
|
268
|
-
naturalName: cliparse.flag('natural-name', {
|
|
269
|
-
aliases: ['n'],
|
|
270
|
-
description: 'Show the application names or aliases if possible',
|
|
271
|
-
}),
|
|
272
260
|
before: cliparse.option('before', {
|
|
273
261
|
metavar: 'before',
|
|
274
262
|
aliases: ['until'],
|
|
@@ -294,10 +282,6 @@ async function run() {
|
|
|
294
282
|
metavar: 'tag',
|
|
295
283
|
description: 'Tag to push (none by default)',
|
|
296
284
|
}),
|
|
297
|
-
databaseId: cliparse.option('database-id', {
|
|
298
|
-
metavar: 'database_id',
|
|
299
|
-
description: 'The Database ID (e.g.: postgresql_xxx)',
|
|
300
|
-
}),
|
|
301
285
|
deploymentId: cliparse.option('deployment-id', {
|
|
302
286
|
metavar: 'deployment_id',
|
|
303
287
|
description: 'Fetch logs for a given deployment',
|
|
@@ -534,45 +518,17 @@ async function run() {
|
|
|
534
518
|
aliases: ['y'],
|
|
535
519
|
description: 'Skip confirmation and remove all SSH keys directly',
|
|
536
520
|
}),
|
|
537
|
-
confirmTcpRedirCreation: cliparse.flag('yes', {
|
|
538
|
-
aliases: ['y'],
|
|
539
|
-
description: 'Skip confirmation even if the TCP redirection is not free',
|
|
540
|
-
}),
|
|
541
521
|
yes: cliparse.flag('yes', {
|
|
542
522
|
aliases: ['y'],
|
|
543
523
|
description: 'Skip confirmation',
|
|
544
524
|
}),
|
|
545
525
|
jsonFormat: cliparse.flag('json', { aliases: ['j'], description: 'Show result in JSON format' }),
|
|
546
526
|
humanJsonOutputFormat: getOutputFormatOption(),
|
|
547
|
-
tag: cliparse.option('tag', {
|
|
548
|
-
required: true,
|
|
549
|
-
metavar: 'tag',
|
|
550
|
-
description: 'A tag',
|
|
551
|
-
parser: Parsers.tag,
|
|
552
|
-
}),
|
|
553
|
-
tags: cliparse.option('tags', {
|
|
554
|
-
required: true,
|
|
555
|
-
metavar: 'tags',
|
|
556
|
-
description: 'List of tags, separated by a comma',
|
|
557
|
-
parser: Parsers.tags,
|
|
558
|
-
}),
|
|
559
527
|
optTags: cliparse.option('tags', {
|
|
560
528
|
metavar: 'tags',
|
|
561
529
|
description: 'List of tags, separated by a comma',
|
|
562
530
|
parser: Parsers.tags,
|
|
563
531
|
}),
|
|
564
|
-
optIpAddress: cliparse.option('ip', {
|
|
565
|
-
required: false,
|
|
566
|
-
metavar: 'ip_address',
|
|
567
|
-
description: 'An IP address',
|
|
568
|
-
parser: Parsers.ipAddress,
|
|
569
|
-
}),
|
|
570
|
-
optPortNumber: cliparse.option('port', {
|
|
571
|
-
required: false,
|
|
572
|
-
metavar: 'port_number',
|
|
573
|
-
description: 'A port number',
|
|
574
|
-
parser: Parsers.portNumber,
|
|
575
|
-
}),
|
|
576
532
|
};
|
|
577
533
|
|
|
578
534
|
// ACCESSLOGS COMMAND
|
|
@@ -855,6 +811,7 @@ async function run() {
|
|
|
855
811
|
{
|
|
856
812
|
description: 'Manage the favourite domain name for an application',
|
|
857
813
|
options: [opts.alias, opts.appIdOrName],
|
|
814
|
+
privateOptions: [opts.humanJsonOutputFormat],
|
|
858
815
|
commands: [domainSetFavouriteCommand, domainUnsetFavouriteCommand],
|
|
859
816
|
},
|
|
860
817
|
domain.getFavourite,
|
|
@@ -879,7 +836,7 @@ async function run() {
|
|
|
879
836
|
'domain',
|
|
880
837
|
{
|
|
881
838
|
description: 'Manage domain names for an application',
|
|
882
|
-
privateOptions: [opts.alias, opts.appIdOrName],
|
|
839
|
+
privateOptions: [opts.alias, opts.appIdOrName, opts.humanJsonOutputFormat],
|
|
883
840
|
commands: [
|
|
884
841
|
domainCreateCommand,
|
|
885
842
|
domainFavouriteCommands,
|
|
@@ -1464,16 +1421,18 @@ async function run() {
|
|
|
1464
1421
|
const ngLinkCommand = cliparse.command(
|
|
1465
1422
|
'link',
|
|
1466
1423
|
{
|
|
1467
|
-
description:
|
|
1468
|
-
|
|
1424
|
+
description:
|
|
1425
|
+
'Link a resource by its ID (app_xxx, external_xxx, mysql_xxx, postgresql_xxx, redis_xxx, etc.) to a Network Group',
|
|
1426
|
+
args: [args.ngResourceId, args.ngIdOrLabel],
|
|
1469
1427
|
},
|
|
1470
1428
|
ng.linkToNg,
|
|
1471
1429
|
);
|
|
1472
1430
|
const ngUnlinkCommand = cliparse.command(
|
|
1473
1431
|
'unlink',
|
|
1474
1432
|
{
|
|
1475
|
-
description:
|
|
1476
|
-
|
|
1433
|
+
description:
|
|
1434
|
+
'Unlink a resource by its ID (app_xxx, external_xxx, mysql_xxx, postgresql_xxx, redis_xxx, etc.) from a Network Group',
|
|
1435
|
+
args: [args.ngResourceId, args.ngIdOrLabel],
|
|
1477
1436
|
},
|
|
1478
1437
|
ng.unlinkFromNg,
|
|
1479
1438
|
);
|
|
@@ -1489,7 +1448,7 @@ async function run() {
|
|
|
1489
1448
|
const ngGetConfigCommand = cliparse.command(
|
|
1490
1449
|
'get-config',
|
|
1491
1450
|
{
|
|
1492
|
-
description: 'Get the
|
|
1451
|
+
description: 'Get the WireGuard configuration of a peer in a Network Group',
|
|
1493
1452
|
args: [args.ngExternalIdOrLabel, args.ngIdOrLabel],
|
|
1494
1453
|
options: [opts.humanJsonOutputFormat],
|
|
1495
1454
|
},
|
|
@@ -1907,7 +1866,7 @@ async function run() {
|
|
|
1907
1866
|
'add',
|
|
1908
1867
|
{
|
|
1909
1868
|
description: 'Add a new TCP redirection to the application',
|
|
1910
|
-
options: [opts.namespace
|
|
1869
|
+
options: [opts.namespace],
|
|
1911
1870
|
},
|
|
1912
1871
|
tcpRedirs.add,
|
|
1913
1872
|
);
|
|
@@ -2028,18 +1987,10 @@ async function run() {
|
|
|
2028
1987
|
},
|
|
2029
1988
|
database.listBackups,
|
|
2030
1989
|
);
|
|
2031
|
-
const databaseCommand = cliparse.command(
|
|
2032
|
-
'
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
commands: [backupsCommand],
|
|
2036
|
-
},
|
|
2037
|
-
async () => {
|
|
2038
|
-
console.info('This command is not available, you can try the following commands:');
|
|
2039
|
-
console.info('clever database backups');
|
|
2040
|
-
console.info('clever database backups download');
|
|
2041
|
-
},
|
|
2042
|
-
);
|
|
1990
|
+
const databaseCommand = cliparse.command('database', {
|
|
1991
|
+
description: 'Manage databases and backups',
|
|
1992
|
+
commands: [backupsCommand],
|
|
1993
|
+
});
|
|
2043
1994
|
|
|
2044
1995
|
// Patch help command description
|
|
2045
1996
|
cliparseCommands.helpCommand.description = 'Display help about the Clever Cloud CLI';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clever-tools",
|
|
3
|
-
"version": "4.0
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"description": "Command Line Interface for Clever Cloud.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"typecheck": "tsc -p tsconfig.json"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@clevercloud/client": "11.0
|
|
50
|
+
"@clevercloud/client": "11.2.0",
|
|
51
51
|
"@inquirer/prompts": "7.8.4",
|
|
52
52
|
"char-regex": "2.0.2",
|
|
53
53
|
"cliparse": "0.5.0",
|
|
@@ -34,7 +34,7 @@ export async function accessLogs(params) {
|
|
|
34
34
|
});
|
|
35
35
|
|
|
36
36
|
if (format === 'human') {
|
|
37
|
-
Logger.
|
|
37
|
+
Logger.println(styleText('yellow', '/!\\ This feature is in Beta testing phase'));
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
if (format === 'json' && !until) {
|
package/src/commands/addon.js
CHANGED
|
@@ -3,6 +3,7 @@ import { styleText } from '../lib/style-text.js';
|
|
|
3
3
|
import { getAllEnvVars } from '@clevercloud/client/esm/api/v2/addon.js';
|
|
4
4
|
import { toNameEqualsValueString } from '@clevercloud/client/esm/utils/env-vars.js';
|
|
5
5
|
import dedent from 'dedent';
|
|
6
|
+
import { getOperator } from '../clever-client/operators.js';
|
|
6
7
|
import { formatTable } from '../format-table.js';
|
|
7
8
|
import { Logger } from '../logger.js';
|
|
8
9
|
import * as Addon from '../models/addon.js';
|
|
@@ -53,6 +54,45 @@ export async function list(params) {
|
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
|
|
57
|
+
const ADDON_PROVIDERS = {
|
|
58
|
+
keycloak: {
|
|
59
|
+
name: 'Keycloak',
|
|
60
|
+
isOperator: true,
|
|
61
|
+
postCreateInstructions: `Learn more about Keycloak on Clever Cloud: ${conf.DOC_URL}/addons/keycloak/`,
|
|
62
|
+
},
|
|
63
|
+
kv: {
|
|
64
|
+
name: 'Materia KV',
|
|
65
|
+
isOperator: false,
|
|
66
|
+
status: 'beta',
|
|
67
|
+
postCreateInstructions: (addonId) => dedent`
|
|
68
|
+
${styleText('yellow', "You can easily use Materia KV with 'redis-cli', with such commands:")}
|
|
69
|
+
${styleText('blue', `source <(clever addon env ${addonId} -F shell)`)}
|
|
70
|
+
${styleText('blue', 'redis-cli -h $KV_HOST -p $KV_PORT --tls')}
|
|
71
|
+
Learn more about Materia KV on Clever Cloud: ${conf.DOC_URL}/addons/materia-kv/
|
|
72
|
+
`,
|
|
73
|
+
},
|
|
74
|
+
'addon-matomo': {
|
|
75
|
+
name: 'Matomo',
|
|
76
|
+
isOperator: true,
|
|
77
|
+
postCreateInstructions: `Learn more about Matomo on Clever Cloud: ${conf.DOC_URL}/addons/matomo/`,
|
|
78
|
+
},
|
|
79
|
+
metabase: {
|
|
80
|
+
name: 'Metabase',
|
|
81
|
+
isOperator: true,
|
|
82
|
+
postCreateInstructions: `Learn more about Metabase on Clever Cloud: ${conf.DOC_URL}/addons/metabase/`,
|
|
83
|
+
},
|
|
84
|
+
otoroshi: {
|
|
85
|
+
name: 'Otoroshi with LLM',
|
|
86
|
+
isOperator: true,
|
|
87
|
+
postCreateInstructions: `Learn more about Otoroshi with LLM on Clever Cloud: ${conf.DOC_URL}/addons/otoroshi/`,
|
|
88
|
+
},
|
|
89
|
+
'addon-pulsar': {
|
|
90
|
+
name: 'Pulsar',
|
|
91
|
+
isOperator: false,
|
|
92
|
+
postCreateInstructions: `Learn more about Pulsar on Clever Cloud: ${conf.DOC_URL}/addons/pulsar/`,
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
|
|
56
96
|
export async function create(params) {
|
|
57
97
|
const [providerName, name] = params.args;
|
|
58
98
|
const {
|
|
@@ -62,23 +102,21 @@ export async function create(params) {
|
|
|
62
102
|
yes: skipConfirmation,
|
|
63
103
|
org: orgaIdOrName,
|
|
64
104
|
format,
|
|
105
|
+
'addon-version': version,
|
|
106
|
+
option: addonOptions,
|
|
65
107
|
} = params.options;
|
|
66
|
-
const version = params.options['addon-version'];
|
|
67
|
-
const addonOptions = parseAddonOptions(params.options.option);
|
|
68
|
-
|
|
69
|
-
const ownerId = orgaIdOrName != null ? await Organisation.getId(orgaIdOrName) : await User.getCurrentId();
|
|
70
108
|
|
|
71
109
|
const addonToCreate = {
|
|
72
|
-
ownerId,
|
|
73
110
|
name,
|
|
74
111
|
providerName,
|
|
75
112
|
planName,
|
|
76
113
|
region,
|
|
77
114
|
skipConfirmation,
|
|
78
115
|
version,
|
|
79
|
-
addonOptions,
|
|
116
|
+
addonOptions: parseAddonOptions(addonOptions),
|
|
80
117
|
};
|
|
81
118
|
|
|
119
|
+
const ownerId = orgaIdOrName != null ? await Organisation.getId(orgaIdOrName) : await User.getCurrentId();
|
|
82
120
|
if (linkedAppAlias != null) {
|
|
83
121
|
const linkedAppData = await AppConfig.getAppDetails({ alias: linkedAppAlias });
|
|
84
122
|
if (orgaIdOrName != null && linkedAppData.ownerId !== ownerId && format === 'human') {
|
|
@@ -86,163 +124,98 @@ export async function create(params) {
|
|
|
86
124
|
'The specified application does not belong to the specified organisation. Ignoring the `--org` option',
|
|
87
125
|
);
|
|
88
126
|
}
|
|
89
|
-
|
|
90
|
-
...addonToCreate,
|
|
91
|
-
ownerId: linkedAppData.ownerId,
|
|
92
|
-
});
|
|
93
|
-
await Addon.link(linkedAppData.ownerId, linkedAppData.appId, { addon_id: newAddon.id });
|
|
94
|
-
displayAddon(
|
|
95
|
-
format,
|
|
96
|
-
newAddon,
|
|
97
|
-
providerName,
|
|
98
|
-
`Add-on created and linked to application ${linkedAppAlias} successfully!`,
|
|
99
|
-
);
|
|
127
|
+
addonToCreate.ownerId = linkedAppData.ownerId;
|
|
100
128
|
} else {
|
|
101
|
-
|
|
102
|
-
displayAddon(format, newAddon, providerName, 'Add-on created successfully!');
|
|
129
|
+
addonToCreate.ownerId = ownerId;
|
|
103
130
|
}
|
|
104
|
-
}
|
|
105
131
|
|
|
106
|
-
|
|
107
|
-
const PROVIDERS_WITH_URL = {
|
|
108
|
-
keycloak: {
|
|
109
|
-
name: 'Keycloak',
|
|
110
|
-
urlEnv: 'CC_KEYCLOAK_URL',
|
|
111
|
-
},
|
|
112
|
-
'addon-matomo': {
|
|
113
|
-
name: 'Matomo',
|
|
114
|
-
urlEnv: 'MATOMO_URL',
|
|
115
|
-
},
|
|
116
|
-
metabase: {
|
|
117
|
-
name: 'Metabase',
|
|
118
|
-
urlEnv: 'METABASE_URL',
|
|
119
|
-
},
|
|
120
|
-
otoroshi: {
|
|
121
|
-
name: 'Otoroshi with LLM',
|
|
122
|
-
urlEnv: 'CC_OTOROSHI_URL',
|
|
123
|
-
},
|
|
124
|
-
};
|
|
132
|
+
const newAddon = await Addon.create(addonToCreate);
|
|
125
133
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
Learn more about Keycloak on Clever Cloud: ${conf.DOC_URL}/addons/keycloak/,
|
|
131
|
-
`,
|
|
132
|
-
},
|
|
133
|
-
kv: {
|
|
134
|
-
status: 'alpha',
|
|
135
|
-
postCreateInstructions: dedent`
|
|
136
|
-
${styleText('yellow', "You can easily use Materia KV with 'redis-cli', with such commands:")}
|
|
137
|
-
${styleText('blue', `source <(clever addon env ${addon.id} -F shell)`)}
|
|
138
|
-
${styleText('blue', 'redis-cli -h $KV_HOST -p $KV_PORT --tls')}
|
|
139
|
-
Learn more about Materia KV on Clever Cloud: ${conf.DOC_URL}/addons/materia-kv/
|
|
140
|
-
`,
|
|
141
|
-
},
|
|
142
|
-
'addon-matomo': {
|
|
143
|
-
status: '',
|
|
144
|
-
postCreateInstructions: dedent`
|
|
145
|
-
Learn more about Matomo on Clever Cloud: ${conf.DOC_URL}/addons/matomo/
|
|
146
|
-
`,
|
|
147
|
-
},
|
|
148
|
-
metabase: {
|
|
149
|
-
status: '',
|
|
150
|
-
postCreateInstructions: dedent`
|
|
151
|
-
Learn more about Metabase on Clever Cloud: ${conf.DOC_URL}/addons/metabase/
|
|
152
|
-
`,
|
|
153
|
-
},
|
|
154
|
-
otoroshi: {
|
|
155
|
-
status: '',
|
|
156
|
-
postCreateInstructions: dedent`
|
|
157
|
-
Learn more about Otoroshi with LLM on Clever Cloud: ${conf.DOC_URL}/addons/otoroshi/
|
|
158
|
-
`,
|
|
159
|
-
},
|
|
160
|
-
'addon-pulsar': {
|
|
161
|
-
status: 'beta',
|
|
162
|
-
postCreateInstructions: dedent`
|
|
163
|
-
Learn more about Pulsar on Clever Cloud: ${conf.DOC_URL}/addons/pulsar/
|
|
164
|
-
`,
|
|
165
|
-
},
|
|
166
|
-
};
|
|
134
|
+
if (linkedAppAlias != null) {
|
|
135
|
+
const linkedAppData = await AppConfig.getAppDetails({ alias: linkedAppAlias });
|
|
136
|
+
await Addon.link(linkedAppData.ownerId, linkedAppData.appId, { addon_id: newAddon.id });
|
|
137
|
+
}
|
|
167
138
|
|
|
168
|
-
|
|
139
|
+
const provider = ADDON_PROVIDERS[providerName];
|
|
169
140
|
let statusMessage = '';
|
|
170
|
-
if (
|
|
171
|
-
|
|
141
|
+
if (provider?.status) {
|
|
142
|
+
statusMessage = `The ${provider.name} provider is in ${provider.status} testing phase`;
|
|
143
|
+
if (provider.status === 'alpha') {
|
|
144
|
+
statusMessage += ". Don't store sensitive or production grade data.";
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// JSON format
|
|
149
|
+
if (format === 'json') {
|
|
150
|
+
const jsonAddon = {
|
|
151
|
+
id: newAddon.id,
|
|
152
|
+
realId: newAddon.realId,
|
|
153
|
+
name: newAddon.name,
|
|
154
|
+
env: newAddon.env,
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
if (provider?.status) {
|
|
158
|
+
jsonAddon.availability = provider.status;
|
|
159
|
+
jsonAddon.message = statusMessage;
|
|
160
|
+
}
|
|
172
161
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
WIP_PROVIDERS[providerName].status === 'alpha' ? ". Don't store sensitive or production grade data." : '';
|
|
162
|
+
Logger.printJson(jsonAddon);
|
|
163
|
+
return;
|
|
176
164
|
}
|
|
177
165
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
env: addon.env,
|
|
185
|
-
};
|
|
166
|
+
// Human format
|
|
167
|
+
if (linkedAppAlias != null) {
|
|
168
|
+
Logger.println(`Add-on created and linked to application ${linkedAppAlias} successfully!`);
|
|
169
|
+
} else {
|
|
170
|
+
Logger.println('Add-on created successfully!');
|
|
171
|
+
}
|
|
186
172
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
: jsonAddon,
|
|
191
|
-
);
|
|
192
|
-
break;
|
|
193
|
-
}
|
|
173
|
+
Logger.println(`ID: ${newAddon.id}`);
|
|
174
|
+
Logger.println(`Real ID: ${newAddon.realId}`);
|
|
175
|
+
Logger.println(`Name: ${newAddon.name}`);
|
|
194
176
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (providerName in PROVIDERS_WITH_URL) {
|
|
200
|
-
const provider = PROVIDERS_WITH_URL[providerName];
|
|
201
|
-
const urlEnv = addon.env.find((entry) => entry.name === provider.urlEnv);
|
|
202
|
-
const urlToShow = urlEnv.value;
|
|
203
|
-
const urlToShowWithHttps = urlToShow.startsWith('http') ? urlToShow : `https://${urlToShow}`;
|
|
204
|
-
|
|
205
|
-
if (urlEnv) {
|
|
206
|
-
Logger.println();
|
|
207
|
-
Logger.println(`Your ${provider.name} is starting:`);
|
|
208
|
-
Logger.println(` - Access it: ${urlToShowWithHttps}`);
|
|
209
|
-
Logger.println(` - Manage it: ${conf.GOTO_URL}/${addon.id}`);
|
|
210
|
-
}
|
|
177
|
+
const operator = ADDON_PROVIDERS[providerName]?.isOperator
|
|
178
|
+
? await getOperator({ provider: providerName, realId: newAddon.realId }).then(sendToApi)
|
|
179
|
+
: null;
|
|
211
180
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
` - Temporary password: ${addon.env.find((e) => e.name === 'CC_KEYCLOAK_ADMIN_DEFAULT_PASSWORD').value}`,
|
|
220
|
-
);
|
|
221
|
-
}
|
|
181
|
+
if (operator) {
|
|
182
|
+
if (operator.accessUrl) {
|
|
183
|
+
Logger.println();
|
|
184
|
+
Logger.println(`Your ${ADDON_PROVIDERS[providerName].name} is starting:`);
|
|
185
|
+
Logger.println(` - Access it: ${operator.accessUrl}`);
|
|
186
|
+
Logger.println(` - Manage it: ${conf.GOTO_URL}/${newAddon.id}`);
|
|
187
|
+
}
|
|
222
188
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
` - Admin user name: ${addon.env.find((e) => e.name === 'CC_OTOROSHI_INITIAL_ADMIN_LOGIN').value}`,
|
|
230
|
-
);
|
|
231
|
-
Logger.println(
|
|
232
|
-
` - Initial password: ${addon.env.find((e) => e.name === 'CC_OTOROSHI_INITIAL_ADMIN_PASSWORD').value}`,
|
|
233
|
-
);
|
|
234
|
-
}
|
|
189
|
+
if (operator.initialCredentials) {
|
|
190
|
+
if (providerName === 'keycloak') {
|
|
191
|
+
Logger.println();
|
|
192
|
+
Logger.println("An initial account has been created, you'll be invited to change the password at first login:");
|
|
193
|
+
Logger.println(` - Admin user name: ${operator.initialCredentials.user}`);
|
|
194
|
+
Logger.println(` - Temporary password: ${operator.initialCredentials.password}`);
|
|
235
195
|
}
|
|
236
|
-
|
|
237
|
-
if (providerName in WIP_PROVIDERS) {
|
|
196
|
+
if (providerName === 'otoroshi') {
|
|
238
197
|
Logger.println();
|
|
198
|
+
Logger.println(
|
|
199
|
+
'An initial account has been created, change the password at first login (Security -> Administrators -> Edit user):',
|
|
200
|
+
);
|
|
201
|
+
Logger.println(` - Admin user name: ${operator.initialCredentials.user}`);
|
|
202
|
+
Logger.println(` - Password: ${operator.initialCredentials.password}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
239
206
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}
|
|
207
|
+
if (provider?.postCreateInstructions) {
|
|
208
|
+
Logger.println();
|
|
243
209
|
|
|
244
|
-
|
|
245
|
-
}
|
|
210
|
+
if (statusMessage !== '') {
|
|
211
|
+
Logger.println(styleText('yellow', `/!\\ ${statusMessage}`));
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (typeof provider.postCreateInstructions === 'function') {
|
|
215
|
+
Logger.println(provider.postCreateInstructions(newAddon.id));
|
|
216
|
+
} else {
|
|
217
|
+
Logger.println(provider.postCreateInstructions);
|
|
218
|
+
}
|
|
246
219
|
}
|
|
247
220
|
}
|
|
248
221
|
|
package/src/commands/diag.js
CHANGED
|
@@ -17,11 +17,9 @@ export async function diag(params) {
|
|
|
17
17
|
if (authDetails.token == null) {
|
|
18
18
|
return 'not connected';
|
|
19
19
|
}
|
|
20
|
-
|
|
21
20
|
if (userId == null) {
|
|
22
21
|
return 'authentication failed';
|
|
23
22
|
}
|
|
24
|
-
|
|
25
23
|
return 'authenticated';
|
|
26
24
|
}
|
|
27
25
|
|
|
@@ -32,7 +30,8 @@ export async function diag(params) {
|
|
|
32
30
|
platform: os.platform(),
|
|
33
31
|
release: os.release(),
|
|
34
32
|
arch: process.arch,
|
|
35
|
-
shell:
|
|
33
|
+
shell: getShell(),
|
|
34
|
+
terminal: getTerminal(),
|
|
36
35
|
isPackaged: process.pkg != null,
|
|
37
36
|
execPath: process.execPath,
|
|
38
37
|
configFile: conf.CONFIGURATION_FILE,
|
|
@@ -69,7 +68,8 @@ export async function diag(params) {
|
|
|
69
68
|
Logger.println('Linux ' + styleText('green', formattedDiag.linuxInfos));
|
|
70
69
|
}
|
|
71
70
|
Logger.println('Shell ' + styleText('green', formattedDiag.shell));
|
|
72
|
-
Logger.println('
|
|
71
|
+
Logger.println('Terminal ' + styleText('green', formattedDiag.terminal));
|
|
72
|
+
Logger.println('Packaged ' + styleText('green', formattedDiag.isPackaged));
|
|
73
73
|
Logger.println('Exec path ' + styleText('green', formattedDiag.execPath));
|
|
74
74
|
Logger.println('Config file ' + styleText('green', formattedDiag.configFile));
|
|
75
75
|
|
|
@@ -95,3 +95,32 @@ export async function diag(params) {
|
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
|
+
|
|
99
|
+
function getShell() {
|
|
100
|
+
const platform = os.platform();
|
|
101
|
+
|
|
102
|
+
if (platform === 'win32') {
|
|
103
|
+
if (process.env.PSModulePath) {
|
|
104
|
+
if (process.env.WT_SESSION) {
|
|
105
|
+
return 'PowerShell (Windows Terminal)';
|
|
106
|
+
}
|
|
107
|
+
if (process.env.PSVersionTable || process.env.POWERSHELL_DISTRIBUTION_CHANNEL) {
|
|
108
|
+
return 'PowerShell Core';
|
|
109
|
+
}
|
|
110
|
+
return 'Windows PowerShell';
|
|
111
|
+
}
|
|
112
|
+
if (process.env.WT_SESSION) {
|
|
113
|
+
return 'Windows Terminal (cmd)';
|
|
114
|
+
}
|
|
115
|
+
return process.env.ComSpec || 'cmd.exe';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return process.env.SHELL || 'unknown';
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function getTerminal() {
|
|
122
|
+
if (process.env.WT_SESSION) {
|
|
123
|
+
return 'Windows Terminal';
|
|
124
|
+
}
|
|
125
|
+
return process.env.TERM_PROGRAM || process.env.TERMINAL_EMULATOR || process.env.TERM;
|
|
126
|
+
}
|