clever-tools 3.7.0 → 3.8.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/README.md +1 -1
- package/bin/clever.js +99 -47
- package/package.json +47 -47
- package/src/command-options.js +19 -0
- package/src/commands/accesslogs.js +114 -34
- package/src/commands/activity.js +64 -12
- package/src/commands/addon.js +152 -57
- package/src/commands/applications.js +83 -1
- package/src/commands/cancel-deploy.js +3 -3
- package/src/commands/config.js +6 -7
- package/src/commands/console.js +16 -4
- package/src/commands/delete.js +16 -6
- package/src/commands/deploy.js +9 -6
- package/src/commands/diag.js +68 -28
- package/src/commands/domain.js +13 -13
- package/src/commands/drain.js +42 -27
- package/src/commands/env.js +53 -24
- package/src/commands/logs.js +3 -3
- package/src/commands/notify-email.js +33 -18
- package/src/commands/open.js +3 -3
- package/src/commands/profile.js +29 -9
- package/src/commands/published-config.js +26 -15
- package/src/commands/restart.js +12 -5
- package/src/commands/scale.js +2 -3
- package/src/commands/service.js +42 -15
- package/src/commands/ssh.js +3 -3
- package/src/commands/status.js +72 -46
- package/src/commands/stop.js +3 -3
- package/src/commands/tcp-redirs.js +54 -18
- package/src/commands/webhooks.js +28 -13
- package/src/logger.js +9 -6
- package/src/models/app_configuration.js +11 -3
- package/src/models/application.js +106 -7
- package/src/models/exit-strategy-option.js +24 -0
- package/src/models/json-array.js +28 -0
- package/src/models/log-v4.js +9 -29
- package/src/models/log.js +9 -2
- package/src/models/namespaces.js +20 -0
- package/src/models/organisation.js +0 -20
- package/src/models/utils.js +8 -1
- package/src/models/accesslogs.js +0 -54
|
@@ -8,34 +8,49 @@ const { getOwnerAndApp, getOrgaIdOrUserId } = require('../models/notification.js
|
|
|
8
8
|
const { getEmailhooks, createEmailhook, deleteEmailhook } = require('@clevercloud/client/cjs/api/v2/notification.js');
|
|
9
9
|
const { sendToApi } = require('../models/send-to-api.js');
|
|
10
10
|
|
|
11
|
-
function displayEmailhook (hook) {
|
|
12
|
-
Logger.println((hook.name && colors.bold(hook.name)) || hook.id);
|
|
13
|
-
Logger.println(` id: ${hook.id}`);
|
|
14
|
-
Logger.println(` services: ${(hook.scope && hook.scope.join(', ')) || hook.ownerId}`);
|
|
15
|
-
Logger.println(` events: ${(hook.events && hook.events.join(', ')) || colors.bold('ALL')}`);
|
|
16
|
-
if (hook.notified) {
|
|
17
|
-
Logger.println(' to:');
|
|
18
|
-
hook.notified.forEach((target) => Logger.println(` ${target.target || 'whole team'}`));
|
|
19
|
-
}
|
|
20
|
-
else {
|
|
21
|
-
Logger.println(' to: whole team');
|
|
22
|
-
}
|
|
23
|
-
Logger.println();
|
|
24
|
-
}
|
|
25
|
-
|
|
26
11
|
async function list (params) {
|
|
27
|
-
const { org, 'list-all': listAll } = params.options;
|
|
12
|
+
const { org, 'list-all': listAll, format } = params.options;
|
|
28
13
|
|
|
29
14
|
// TODO: fix alias option
|
|
30
15
|
const { ownerId, appId } = await getOwnerAndApp(null, org, !listAll);
|
|
31
16
|
const hooks = await getEmailhooks({ ownerId }).then(sendToApi);
|
|
32
17
|
|
|
33
|
-
hooks
|
|
18
|
+
const formattedHooks = hooks
|
|
34
19
|
.filter((hook) => {
|
|
35
20
|
const emptyScope = !hook.scope || hook.scope.length === 0;
|
|
36
21
|
return !appId || emptyScope || hook.scope.includes(appId);
|
|
37
22
|
})
|
|
38
|
-
.
|
|
23
|
+
.map((hook) => ({
|
|
24
|
+
id: hook.id,
|
|
25
|
+
name: hook.name,
|
|
26
|
+
ownerId: hook.ownerId,
|
|
27
|
+
services: hook.scope ?? [hook.ownerId],
|
|
28
|
+
events: hook.events ?? ['ALL'],
|
|
29
|
+
notified: hook.notified ? hook.notified.map(({ target }) => target ?? 'whole team') : ['whole team'],
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
switch (format) {
|
|
33
|
+
case 'json': {
|
|
34
|
+
Logger.printJson(formattedHooks);
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
case 'human':
|
|
38
|
+
default: {
|
|
39
|
+
formattedHooks.forEach((hook, i) => {
|
|
40
|
+
Logger.println(colors.bold(hook.name ?? hook.id));
|
|
41
|
+
Logger.println(` id: ${hook.id}`);
|
|
42
|
+
Logger.println(` services: ${hook.services.join(', ')}`);
|
|
43
|
+
Logger.println(` events: ${hook.events.join(', ')}`);
|
|
44
|
+
if (hook.notified.length > 1) {
|
|
45
|
+
Logger.println(' to:');
|
|
46
|
+
hook.notified.forEach((target) => Logger.println(` ${target}`));
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
Logger.println(` to: ${hook.notified[0]}`);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
39
54
|
}
|
|
40
55
|
|
|
41
56
|
function getEmailNotificationTargets (notifTargets) {
|
package/src/commands/open.js
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
const openPage = require('open');
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const Application = require('../models/application.js');
|
|
6
6
|
const Domain = require('../models/domain.js');
|
|
7
7
|
const Logger = require('../logger.js');
|
|
8
8
|
|
|
9
9
|
async function open (params) {
|
|
10
|
-
const { alias } = params.options;
|
|
11
|
-
const { ownerId, appId } = await
|
|
10
|
+
const { alias, app: appIdOrName } = params.options;
|
|
11
|
+
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
12
12
|
|
|
13
13
|
const vhost = await Domain.getBest(appId, ownerId);
|
|
14
14
|
const url = 'https://' + vhost.fqdn;
|
package/src/commands/profile.js
CHANGED
|
@@ -5,15 +5,35 @@ const colors = require('colors/safe');
|
|
|
5
5
|
const Logger = require('../logger.js');
|
|
6
6
|
const User = require('../models/user.js');
|
|
7
7
|
|
|
8
|
-
async function profile () {
|
|
9
|
-
const {
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
8
|
+
async function profile (params) {
|
|
9
|
+
const { format } = params.options;
|
|
10
|
+
|
|
11
|
+
const user = await User.getCurrent();
|
|
12
|
+
|
|
13
|
+
const formattedUser = {
|
|
14
|
+
id: user.id,
|
|
15
|
+
email: user.email,
|
|
16
|
+
name: user.name,
|
|
17
|
+
avatar: user.avatar,
|
|
18
|
+
creationDate: new Date(user.creationDate),
|
|
19
|
+
lang: user.lang,
|
|
20
|
+
has2FA: (user.preferredMFA != null && user.preferredMFA !== 'NONE'),
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
switch (format) {
|
|
24
|
+
case 'json': {
|
|
25
|
+
Logger.printJson(formattedUser);
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
case 'human':
|
|
29
|
+
default: {
|
|
30
|
+
Logger.println('You\'re currently logged in as:');
|
|
31
|
+
Logger.println(`User id ${formattedUser.id}`);
|
|
32
|
+
Logger.println(`Name ${formattedUser.name ?? colors.red.bold('[not specified]')}`);
|
|
33
|
+
Logger.println(`Email ${formattedUser.email}`);
|
|
34
|
+
Logger.println(`Two factor auth ${formattedUser.has2FA ? 'yes' : 'no'}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
17
37
|
};
|
|
18
38
|
|
|
19
39
|
module.exports = { profile };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const Application = require('../models/application.js');
|
|
4
4
|
const Logger = require('../logger.js');
|
|
5
5
|
const variables = require('../models/variables.js');
|
|
6
6
|
const { sendToApi } = require('../models/send-to-api.js');
|
|
@@ -8,27 +8,38 @@ const { toNameEqualsValueString, validateName } = require('@clevercloud/client/c
|
|
|
8
8
|
const application = require('@clevercloud/client/cjs/api/v2/application.js');
|
|
9
9
|
|
|
10
10
|
async function list (params) {
|
|
11
|
-
const { alias } = params.options;
|
|
12
|
-
const { ownerId, appId } = await
|
|
11
|
+
const { alias, app: appIdOrName, format } = params.options;
|
|
12
|
+
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
13
13
|
|
|
14
14
|
const publishedConfigs = await application.getAllExposedEnvVars({ id: ownerId, appId }).then(sendToApi);
|
|
15
|
-
const pairs = Object.entries(publishedConfigs)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
const pairs = Object.entries(publishedConfigs).map(([name, value]) => ({ name, value }));
|
|
16
|
+
|
|
17
|
+
switch (format) {
|
|
18
|
+
case 'json': {
|
|
19
|
+
Logger.printJson(pairs);
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
case 'shell':
|
|
23
|
+
Logger.println(toNameEqualsValueString(pairs, { addExports: true }));
|
|
24
|
+
break;
|
|
25
|
+
case 'human':
|
|
26
|
+
default: {
|
|
27
|
+
Logger.println('# Published configs');
|
|
28
|
+
Logger.println(toNameEqualsValueString(pairs, { addExports: false }));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
21
32
|
|
|
22
33
|
async function set (params) {
|
|
23
34
|
const [varName, varValue] = params.args;
|
|
24
|
-
const { alias } = params.options;
|
|
35
|
+
const { alias, app: appIdOrName } = params.options;
|
|
25
36
|
|
|
26
37
|
const nameIsValid = validateName(varName);
|
|
27
38
|
if (!nameIsValid) {
|
|
28
39
|
throw new Error(`Published config name ${varName} is invalid`);
|
|
29
40
|
}
|
|
30
41
|
|
|
31
|
-
const { ownerId, appId } = await
|
|
42
|
+
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
32
43
|
|
|
33
44
|
const publishedConfigs = await application.getAllExposedEnvVars({ id: ownerId, appId }).then(sendToApi);
|
|
34
45
|
publishedConfigs[varName] = varValue;
|
|
@@ -39,8 +50,8 @@ async function set (params) {
|
|
|
39
50
|
|
|
40
51
|
async function rm (params) {
|
|
41
52
|
const [varName] = params.args;
|
|
42
|
-
const { alias } = params.options;
|
|
43
|
-
const { ownerId, appId } = await
|
|
53
|
+
const { alias, app: appIdOrName } = params.options;
|
|
54
|
+
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
44
55
|
|
|
45
56
|
const publishedConfigs = await application.getAllExposedEnvVars({ id: ownerId, appId }).then(sendToApi);
|
|
46
57
|
delete publishedConfigs[varName];
|
|
@@ -50,9 +61,9 @@ async function rm (params) {
|
|
|
50
61
|
};
|
|
51
62
|
|
|
52
63
|
async function importEnv (params) {
|
|
53
|
-
const { alias, json } = params.options;
|
|
64
|
+
const { alias, app: appIdOrName, json } = params.options;
|
|
54
65
|
const format = json ? 'json' : 'name-equals-value';
|
|
55
|
-
const { ownerId, appId } = await
|
|
66
|
+
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
56
67
|
|
|
57
68
|
const publishedConfigs = await variables.readVariablesFromStdin(format);
|
|
58
69
|
await application.updateAllExposedEnvVars({ id: ownerId, appId }, publishedConfigs).then(sendToApi);
|
package/src/commands/restart.js
CHANGED
|
@@ -2,26 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
const colors = require('colors/safe');
|
|
4
4
|
|
|
5
|
-
const AppConfig = require('../models/app_configuration.js');
|
|
6
5
|
const Application = require('../models/application.js');
|
|
7
6
|
const git = require('../models/git.js');
|
|
8
7
|
const Log = require('../models/log-v4.js');
|
|
9
8
|
const Logger = require('../logger.js');
|
|
9
|
+
const ExitStrategy = require('../models/exit-strategy-option.js');
|
|
10
10
|
|
|
11
11
|
// Once the API call to redeploy() has been triggerred successfully,
|
|
12
12
|
// the rest (waiting for deployment state to evolve and displaying logs) is done with auto retry (resilient to network pb)
|
|
13
13
|
async function restart (params) {
|
|
14
|
-
const { alias, quiet, commit, 'without-cache': withoutCache, follow } = params.options;
|
|
14
|
+
const { alias, app: appIdOrName, quiet, commit, 'without-cache': withoutCache, follow, 'exit-on': exitOnDeploy } = params.options;
|
|
15
15
|
|
|
16
|
-
const
|
|
16
|
+
const exitStrategy = ExitStrategy.get(follow, exitOnDeploy);
|
|
17
|
+
|
|
18
|
+
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
17
19
|
const fullCommitId = await git.resolveFullCommitId(commit);
|
|
18
20
|
const app = await Application.get(ownerId, appId);
|
|
21
|
+
|
|
22
|
+
if (app == null) {
|
|
23
|
+
throw new Error('The application doesn\'t exist');
|
|
24
|
+
}
|
|
25
|
+
|
|
19
26
|
const remoteCommitId = app.commitId;
|
|
20
27
|
|
|
21
28
|
const commitId = fullCommitId || remoteCommitId;
|
|
22
29
|
if (commitId != null) {
|
|
23
30
|
const cacheSuffix = withoutCache ? ' without using cache' : '';
|
|
24
|
-
Logger.println(`Restarting ${
|
|
31
|
+
Logger.println(`Restarting ${app.name} on commit ${colors.green(commitId)}${cacheSuffix}`);
|
|
25
32
|
}
|
|
26
33
|
|
|
27
34
|
// This should be handled by the API when a deployment ID is set but we'll do this for now
|
|
@@ -34,8 +41,8 @@ async function restart (params) {
|
|
|
34
41
|
appId,
|
|
35
42
|
deploymentId: redeploy.deploymentId,
|
|
36
43
|
quiet,
|
|
37
|
-
follow,
|
|
38
44
|
redeployDate,
|
|
45
|
+
exitStrategy,
|
|
39
46
|
});
|
|
40
47
|
}
|
|
41
48
|
|
package/src/commands/scale.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const AppConfig = require('../models/app_configuration.js');
|
|
4
3
|
const Application = require('../models/application.js');
|
|
5
4
|
const Logger = require('../logger.js');
|
|
6
5
|
|
|
@@ -45,9 +44,9 @@ function validateOptions (options) {
|
|
|
45
44
|
}
|
|
46
45
|
|
|
47
46
|
async function scale (params) {
|
|
48
|
-
const { alias } = params.options;
|
|
47
|
+
const { alias, app: appIdOrName } = params.options;
|
|
49
48
|
const { minFlavor, maxFlavor, minInstances, maxInstances, buildFlavor } = validateOptions(params.options);
|
|
50
|
-
const { ownerId, appId } = await
|
|
49
|
+
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
51
50
|
|
|
52
51
|
await Application.setScalability(appId, ownerId, {
|
|
53
52
|
minFlavor,
|
package/src/commands/service.js
CHANGED
|
@@ -1,62 +1,89 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const Addon = require('../models/addon.js');
|
|
4
|
-
const AppConfig = require('../models/app_configuration.js');
|
|
5
4
|
const Application = require('../models/application.js');
|
|
6
5
|
const Logger = require('../logger.js');
|
|
7
6
|
|
|
8
7
|
async function list (params) {
|
|
9
|
-
const { alias, 'show-all': showAll, 'only-apps': onlyApps, 'only-addons': onlyAddons } = params.options;
|
|
8
|
+
const { alias, app: appIdOrName, 'show-all': showAll, 'only-apps': onlyApps, 'only-addons': onlyAddons, format } = params.options;
|
|
10
9
|
if (onlyApps && onlyAddons) {
|
|
11
10
|
throw new Error('--only-apps and --only-addons are mutually exclusive');
|
|
12
11
|
}
|
|
13
12
|
|
|
14
|
-
const { ownerId, appId } = await
|
|
13
|
+
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
14
|
+
|
|
15
|
+
const formattedServices = {};
|
|
15
16
|
|
|
16
17
|
if (!onlyAddons) {
|
|
17
18
|
const apps = await Application.listDependencies(ownerId, appId, showAll);
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
formattedServices.applications = apps.map((app) => ({
|
|
20
|
+
id: app.id,
|
|
21
|
+
name: app.name,
|
|
22
|
+
isLinked: app.isLinked,
|
|
23
|
+
}));
|
|
20
24
|
}
|
|
21
25
|
|
|
22
26
|
if (!onlyApps) {
|
|
23
27
|
const addons = await Addon.list(ownerId, appId, showAll);
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
formattedServices.addons = addons.map((addon) => ({
|
|
29
|
+
id: addon.id,
|
|
30
|
+
realId: addon.realId,
|
|
31
|
+
name: addon.name,
|
|
32
|
+
isLinked: addon.isLinked,
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
switch (format) {
|
|
37
|
+
case 'json': {
|
|
38
|
+
Logger.printJson(formattedServices);
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
case 'human':
|
|
42
|
+
default: {
|
|
43
|
+
if (formattedServices.applications) {
|
|
44
|
+
Logger.println('Applications:');
|
|
45
|
+
formattedServices.applications.forEach(({ isLinked, name }) => Logger.println(`${isLinked ? '*' : ' '} ${name}`));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (formattedServices.addons) {
|
|
49
|
+
Logger.println('Addons:');
|
|
50
|
+
formattedServices.addons.forEach(({ isLinked, name, realId }) => Logger.println(`${isLinked ? '*' : ' '} ${name} (${realId})`));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
26
53
|
}
|
|
27
54
|
}
|
|
28
55
|
|
|
29
56
|
async function linkApp (params) {
|
|
30
|
-
const { alias } = params.options;
|
|
57
|
+
const { alias, app: appIdOrName } = params.options;
|
|
31
58
|
const [dependency] = params.args;
|
|
32
|
-
const { ownerId, appId } = await
|
|
59
|
+
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
33
60
|
|
|
34
61
|
await Application.link(ownerId, appId, dependency);
|
|
35
62
|
Logger.println(`App ${dependency.app_id || dependency.app_name} successfully linked`);
|
|
36
63
|
}
|
|
37
64
|
|
|
38
65
|
async function unlinkApp (params) {
|
|
39
|
-
const { alias } = params.options;
|
|
66
|
+
const { alias, app: appIdOrName } = params.options;
|
|
40
67
|
const [dependency] = params.args;
|
|
41
|
-
const { ownerId, appId } = await
|
|
68
|
+
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
42
69
|
|
|
43
70
|
await Application.unlink(ownerId, appId, dependency);
|
|
44
71
|
Logger.println(`App ${dependency.app_id || dependency.app_name} successfully unlinked`);
|
|
45
72
|
}
|
|
46
73
|
|
|
47
74
|
async function linkAddon (params) {
|
|
48
|
-
const { alias } = params.options;
|
|
75
|
+
const { alias, app: appIdOrName } = params.options;
|
|
49
76
|
const [addon] = params.args;
|
|
50
|
-
const { ownerId, appId } = await
|
|
77
|
+
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
51
78
|
|
|
52
79
|
await Addon.link(ownerId, appId, addon);
|
|
53
80
|
Logger.println(`Addon ${addon.addon_id || addon.addon_name} successfully linked`);
|
|
54
81
|
}
|
|
55
82
|
|
|
56
83
|
async function unlinkAddon (params) {
|
|
57
|
-
const { alias } = params.options;
|
|
84
|
+
const { alias, app: appIdOrName } = params.options;
|
|
58
85
|
const [addon] = params.args;
|
|
59
|
-
const { ownerId, appId } = await
|
|
86
|
+
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
60
87
|
|
|
61
88
|
await Addon.unlink(ownerId, appId, addon);
|
|
62
89
|
Logger.println(`Addon ${addon.addon_id || addon.addon_name} successfully unlinked`);
|
package/src/commands/ssh.js
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
const { spawn } = require('child_process');
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const Application = require('../models/application.js');
|
|
6
6
|
const { conf } = require('../models/configuration.js');
|
|
7
7
|
|
|
8
8
|
async function ssh (params) {
|
|
9
|
-
const { alias, 'identity-file': identityFile } = params.options;
|
|
9
|
+
const { alias, app: appIdOrName, 'identity-file': identityFile } = params.options;
|
|
10
10
|
|
|
11
|
-
const { appId } = await
|
|
11
|
+
const { appId } = await Application.resolveId(appIdOrName, alias);
|
|
12
12
|
const sshParams = ['-t', conf.SSH_GATEWAY, appId];
|
|
13
13
|
if (identityFile != null) {
|
|
14
14
|
sshParams.push('-i', identityFile);
|
package/src/commands/status.js
CHANGED
|
@@ -3,22 +3,49 @@
|
|
|
3
3
|
const _ = require('lodash');
|
|
4
4
|
const colors = require('colors/safe');
|
|
5
5
|
|
|
6
|
-
const
|
|
6
|
+
const Application = require('../models/application.js');
|
|
7
7
|
const Logger = require('../logger.js');
|
|
8
8
|
|
|
9
9
|
const { get: getApplication, getAllInstances } = require('@clevercloud/client/cjs/api/v2/application.js');
|
|
10
10
|
const { sendToApi } = require('../models/send-to-api.js');
|
|
11
11
|
|
|
12
|
-
function
|
|
13
|
-
|
|
12
|
+
async function status (params) {
|
|
13
|
+
const { alias, app: appIdOrName, format } = params.options;
|
|
14
|
+
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
15
|
+
|
|
16
|
+
const instances = await getAllInstances({ id: ownerId, appId }).then(sendToApi);
|
|
17
|
+
const app = await getApplication({ id: ownerId, appId }).then(sendToApi);
|
|
18
|
+
|
|
19
|
+
const status = computeStatus(instances, app);
|
|
20
|
+
|
|
21
|
+
switch (format) {
|
|
22
|
+
case 'json': {
|
|
23
|
+
Logger.printJson(status);
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
case 'human':
|
|
27
|
+
default: {
|
|
28
|
+
const statusMessage = status.status === 'running'
|
|
29
|
+
? `${colors.bold.green('running')} ${displayInstances(status.instances, status.commit)}`
|
|
30
|
+
: colors.bold.red('stopped');
|
|
31
|
+
|
|
32
|
+
Logger.println(`${status.name}: ${statusMessage}`);
|
|
33
|
+
Logger.println(`Executed as: ${colors.bold(status.lifetime)}`);
|
|
34
|
+
if (status.deploymentInProgress) {
|
|
35
|
+
Logger.println(`Deployment in progress ${displayInstances(status.deploymentInProgress.instances, status.deploymentInProgress.commit)}`);
|
|
36
|
+
}
|
|
37
|
+
Logger.println();
|
|
38
|
+
Logger.println('Scalability:');
|
|
39
|
+
Logger.println(` Auto scalability: ${status.scalability.enabled ? colors.green('enabled') : colors.red('disabled')}`);
|
|
40
|
+
Logger.println(` Scalers: ${colors.bold(formatScalability(status.scalability.horizontal))}`);
|
|
41
|
+
Logger.println(` Sizes: ${colors.bold(formatScalability(status.scalability.vertical))}`);
|
|
42
|
+
Logger.println(` Dedicated build: ${status.separateBuild ? colors.bold(status.buildFlavor) : colors.red('disabled')}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
14
45
|
}
|
|
15
46
|
|
|
16
|
-
function
|
|
17
|
-
return
|
|
18
|
-
.groupBy((i) => i.flavor.name)
|
|
19
|
-
.map((instances, flavorName) => `${instances.length}*${flavorName}`)
|
|
20
|
-
.value()
|
|
21
|
-
.join(', ');
|
|
47
|
+
function displayInstances (instances, commit) {
|
|
48
|
+
return `(${instances.map((instance) => `${instance.count}*${instance.flavor}`)}, Commit: ${commit || 'N/A'})`;
|
|
22
49
|
}
|
|
23
50
|
|
|
24
51
|
function computeStatus (instances, app) {
|
|
@@ -30,50 +57,49 @@ function computeStatus (instances, app) {
|
|
|
30
57
|
const isDeploying = !_.isEmpty(deployingInstances);
|
|
31
58
|
const deployingCommit = _(deployingInstances).map('commit').head();
|
|
32
59
|
|
|
33
|
-
const statusMessage = isUp
|
|
34
|
-
? `${colors.bold.green('running')} ${displayGroupInfo(upInstances, upCommit)}`
|
|
35
|
-
: colors.bold.red('stopped');
|
|
36
|
-
|
|
37
|
-
const statusLine = `${app.name}: ${statusMessage}`;
|
|
38
|
-
const taskLine = `Executed as: ${colors.bold(app.instance.lifetime)}`;
|
|
39
|
-
const deploymentLine = isDeploying
|
|
40
|
-
? `Deployment in progress ${displayGroupInfo(deployingInstances, deployingCommit)}`
|
|
41
|
-
: '';
|
|
42
|
-
|
|
43
|
-
return [statusLine, taskLine, deploymentLine].join('\n');
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function displayScalability (app) {
|
|
47
|
-
|
|
48
60
|
const { minFlavor, maxFlavor, minInstances, maxInstances } = app.instance;
|
|
49
61
|
|
|
50
|
-
const
|
|
51
|
-
? minFlavor.name
|
|
52
|
-
: `${minFlavor.name} to ${maxFlavor.name}`;
|
|
53
|
-
|
|
54
|
-
const horizontal = (minInstances === maxInstances)
|
|
55
|
-
? minInstances
|
|
56
|
-
: `${minInstances} to ${maxInstances}`;
|
|
57
|
-
|
|
58
|
-
const enabled = (minFlavor.name !== maxFlavor.name)
|
|
62
|
+
const scalabilityEnabled = (minFlavor.name !== maxFlavor.name)
|
|
59
63
|
|| (minInstances !== maxInstances);
|
|
60
64
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
const status = {
|
|
66
|
+
id: app.id,
|
|
67
|
+
name: app.name,
|
|
68
|
+
lifetime: app.instance.lifetime,
|
|
69
|
+
status: isUp ? 'running' : 'stopped',
|
|
70
|
+
commit: upCommit,
|
|
71
|
+
instances: groupInstances(upInstances),
|
|
72
|
+
scalability: {
|
|
73
|
+
enabled: scalabilityEnabled,
|
|
74
|
+
vertical: { min: minFlavor.name, max: maxFlavor.name },
|
|
75
|
+
horizontal: { min: minInstances, max: maxInstances },
|
|
76
|
+
},
|
|
77
|
+
separateBuild: app.separateBuild,
|
|
78
|
+
buildFlavor: app.buildFlavor.name,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
if (isDeploying) {
|
|
82
|
+
status.deploymentInProgress = {
|
|
83
|
+
commit: deployingCommit,
|
|
84
|
+
instances: groupInstances(deployingInstances),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return status;
|
|
66
89
|
}
|
|
67
90
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const instances = await getAllInstances({ id: ownerId, appId }).then(sendToApi);
|
|
73
|
-
const app = await getApplication({ id: ownerId, appId }).then(sendToApi);
|
|
91
|
+
function formatScalability ({ min, max }) {
|
|
92
|
+
return (min === max) ? min : `${min} to ${max}`;
|
|
93
|
+
}
|
|
74
94
|
|
|
75
|
-
|
|
76
|
-
|
|
95
|
+
function groupInstances (instances) {
|
|
96
|
+
return _(instances)
|
|
97
|
+
.groupBy((i) => i.flavor.name)
|
|
98
|
+
.map((instances, flavorName) => ({
|
|
99
|
+
flavor: flavorName,
|
|
100
|
+
count: instances.length,
|
|
101
|
+
}))
|
|
102
|
+
.value();
|
|
77
103
|
}
|
|
78
104
|
|
|
79
105
|
module.exports = { status };
|
package/src/commands/stop.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const Application = require('../models/application.js');
|
|
4
4
|
const application = require('@clevercloud/client/cjs/api/v2/application.js');
|
|
5
5
|
const Logger = require('../logger.js');
|
|
6
6
|
const { sendToApi } = require('../models/send-to-api.js');
|
|
7
7
|
|
|
8
8
|
async function stop (params) {
|
|
9
|
-
const { alias } = params.options;
|
|
10
|
-
const { ownerId, appId } = await
|
|
9
|
+
const { alias, app: appIdOrName } = params.options;
|
|
10
|
+
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
11
11
|
|
|
12
12
|
await application.undeploy({ id: ownerId, appId }).then(sendToApi);
|
|
13
13
|
Logger.println('App successfully stopped!');
|