clever-tools 3.14.0 → 4.0.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 +130 -37
- package/bin/clever.js +1427 -718
- package/package.json +61 -77
- package/src/clever-client/auth-bridge.js +9 -12
- package/src/clever-client/ng.js +1 -1
- package/src/clever-client/operators.js +7 -7
- package/src/command-options.js +6 -6
- package/src/command-promise-handler.js +6 -6
- package/src/commands/accesslogs.js +38 -29
- package/src/commands/activity.js +62 -40
- package/src/commands/addon.js +65 -69
- package/src/commands/applications.js +33 -31
- package/src/commands/cancel-deploy.js +7 -7
- package/src/commands/config.js +9 -7
- package/src/commands/console.js +3 -3
- package/src/commands/create.js +32 -31
- package/src/commands/curl.js +14 -36
- package/src/commands/database.js +10 -30
- package/src/commands/delete.js +8 -8
- package/src/commands/deploy.js +60 -46
- package/src/commands/diag.js +27 -25
- package/src/commands/domain.js +89 -91
- package/src/commands/drain.js +26 -14
- package/src/commands/emails.js +24 -28
- package/src/commands/env.js +18 -18
- package/src/commands/features.js +12 -18
- package/src/commands/keycloak.js +11 -11
- package/src/commands/kv.js +13 -13
- package/src/commands/link.js +9 -8
- package/src/commands/login.js +19 -27
- package/src/commands/logout.js +1 -1
- package/src/commands/logs.js +20 -12
- package/src/commands/makeDefault.js +5 -5
- package/src/commands/matomo.js +7 -7
- package/src/commands/metabase.js +9 -9
- package/src/commands/ng.js +32 -32
- package/src/commands/notify-email.js +11 -15
- package/src/commands/open.js +1 -1
- package/src/commands/otoroshi.js +11 -11
- package/src/commands/profile.js +8 -8
- package/src/commands/published-config.js +11 -11
- package/src/commands/restart.js +15 -8
- package/src/commands/scale.js +25 -16
- package/src/commands/service.js +18 -9
- package/src/commands/ssh-keys.js +25 -29
- package/src/commands/ssh.js +1 -2
- package/src/commands/status.js +31 -22
- package/src/commands/stop.js +3 -3
- package/src/commands/tcp-redirs.js +27 -26
- package/src/commands/tokens.js +44 -43
- package/src/commands/unlink.js +7 -5
- package/src/commands/version.js +2 -4
- package/src/commands/webhooks.js +8 -10
- package/src/experimental-features.js +7 -5
- package/src/format-table.js +46 -15
- package/src/initial-setup.js +2 -32
- package/src/initial-update-notifier.js +18 -0
- package/src/lib/has-param.js +16 -0
- package/src/lib/ng-print.js +21 -24
- package/src/lib/operator-commands.js +58 -53
- package/src/lib/prompts.js +5 -5
- package/src/lib/slugify.js +1 -1
- package/src/logger.js +24 -22
- package/src/models/activity.js +3 -3
- package/src/models/addon.js +52 -53
- package/src/models/app_configuration.js +34 -32
- package/src/models/application.js +90 -77
- package/src/models/application_configuration.js +19 -27
- package/src/models/configuration.js +30 -32
- package/src/models/deployments.js +9 -19
- package/src/models/domain.js +10 -9
- package/src/models/drain.js +16 -15
- package/src/models/exit-strategy-option.js +15 -5
- package/src/models/fs-utils.js +4 -3
- package/src/models/git.js +26 -32
- package/src/models/ids-resolver.js +37 -41
- package/src/models/isomorphic-http-with-agent.js +3 -3
- package/src/models/json-array.js +5 -6
- package/src/models/log-v4.js +44 -52
- package/src/models/log.js +40 -45
- package/src/models/namespaces.js +4 -4
- package/src/models/ng-resources.js +49 -39
- package/src/models/ng.js +41 -40
- package/src/models/node-dns-resolver.js +3 -3
- package/src/models/notification.js +7 -10
- package/src/models/operator.js +8 -10
- package/src/models/organisation.js +5 -8
- package/src/models/send-to-api.js +18 -11
- package/src/models/user.js +6 -5
- package/src/models/utils.js +5 -8
- package/src/models/variables.js +18 -20
- package/src/parsers.js +34 -34
- package/src/load-package-json.cjs +0 -5
package/src/models/log-v4.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import { Deferred } from './utils.js';
|
|
1
|
+
import { ApplicationLogStream } from '@clevercloud/client/esm/streams/application-logs.js';
|
|
2
|
+
import { styleText } from 'node:util';
|
|
4
3
|
import { Logger } from '../logger.js';
|
|
4
|
+
import { conf } from './configuration.js';
|
|
5
5
|
import { waitForDeploymentEnd, waitForDeploymentStart } from './deployments.js';
|
|
6
|
-
import { ApplicationLogStream } from '@clevercloud/client/esm/streams/application-logs.js';
|
|
7
|
-
import { JsonArray } from './json-array.js';
|
|
8
|
-
import * as ExitStrategy from '../models/exit-strategy-option.js';
|
|
9
6
|
import { getBest } from './domain.js';
|
|
10
|
-
import
|
|
7
|
+
import * as ExitStrategy from './exit-strategy-option.js';
|
|
8
|
+
import { JsonArray } from './json-array.js';
|
|
9
|
+
import { getHostAndTokens, processError } from './send-to-api.js';
|
|
10
|
+
import { Deferred } from './utils.js';
|
|
11
11
|
|
|
12
12
|
const RESET_COLOR = '\x1B[0m';
|
|
13
13
|
|
|
@@ -20,8 +20,7 @@ const retryConfiguration = {
|
|
|
20
20
|
maxRetryCount: 6,
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
-
export async function displayLogs
|
|
24
|
-
|
|
23
|
+
export async function displayLogs(params) {
|
|
25
24
|
const deferred = params.deferred || new Deferred();
|
|
26
25
|
const { apiHost, tokens } = await getHostAndTokens();
|
|
27
26
|
const { ownerId, appId, filter, since, until, deploymentId, format } = params;
|
|
@@ -50,14 +49,14 @@ export async function displayLogs (params) {
|
|
|
50
49
|
const jsonArray = new JsonArray();
|
|
51
50
|
|
|
52
51
|
logStream
|
|
53
|
-
.on('open', (
|
|
54
|
-
Logger.debug(
|
|
52
|
+
.on('open', () => {
|
|
53
|
+
Logger.debug(styleText('blue', `Logs stream (open) ${JSON.stringify({ appId, filter, deploymentId })}`));
|
|
55
54
|
if (format === 'json') {
|
|
56
55
|
jsonArray.open();
|
|
57
56
|
}
|
|
58
57
|
})
|
|
59
58
|
.on('error', (event) => {
|
|
60
|
-
Logger.debug(
|
|
59
|
+
Logger.debug(styleText('red', `Logs stream (error) ${event.error.message}`));
|
|
61
60
|
})
|
|
62
61
|
.onLog((log) => {
|
|
63
62
|
switch (format) {
|
|
@@ -69,14 +68,17 @@ export async function displayLogs (params) {
|
|
|
69
68
|
return;
|
|
70
69
|
case 'human':
|
|
71
70
|
default:
|
|
72
|
-
if (log.message === RESET_COLOR)
|
|
71
|
+
if (log.message === RESET_COLOR) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
73
74
|
Logger.println(formatLogLine(log));
|
|
74
75
|
}
|
|
75
76
|
});
|
|
76
77
|
|
|
77
78
|
// start() is blocking until end of stream
|
|
78
|
-
logStream
|
|
79
|
-
.
|
|
79
|
+
logStream
|
|
80
|
+
.start()
|
|
81
|
+
.then(() => {
|
|
80
82
|
if (format === 'json') {
|
|
81
83
|
jsonArray.close();
|
|
82
84
|
}
|
|
@@ -88,26 +90,16 @@ export async function displayLogs (params) {
|
|
|
88
90
|
return logStream;
|
|
89
91
|
}
|
|
90
92
|
|
|
91
|
-
export async function watchDeploymentAndDisplayLogs
|
|
92
|
-
|
|
93
|
-
const {
|
|
94
|
-
ownerId,
|
|
95
|
-
appId,
|
|
96
|
-
deploymentId,
|
|
97
|
-
commitId,
|
|
98
|
-
knownDeployments,
|
|
99
|
-
quiet,
|
|
100
|
-
redeployDate,
|
|
101
|
-
exitStrategy,
|
|
102
|
-
} = options;
|
|
93
|
+
export async function watchDeploymentAndDisplayLogs(options) {
|
|
94
|
+
const { ownerId, appId, deploymentId, commitId, knownDeployments, quiet, redeployDate, exitStrategy } = options;
|
|
103
95
|
|
|
104
96
|
ExitStrategy.plotQuietWarning(exitStrategy, quiet);
|
|
105
97
|
// If in quiet mode, we only log start/finished deployment messages
|
|
106
98
|
if (!quiet) {
|
|
107
|
-
Logger.println(` ${
|
|
99
|
+
Logger.println(` ${styleText('blue', '→ Waiting for deployment to start…')}`);
|
|
108
100
|
}
|
|
109
101
|
const deployment = await waitForDeploymentStart({ ownerId, appId, deploymentId, commitId, knownDeployments });
|
|
110
|
-
Logger.println(` ${
|
|
102
|
+
Logger.println(` ${styleText('green', `✓ Deployment started ${styleText('grey', `(${deployment.uuid})`)}`)}`);
|
|
111
103
|
|
|
112
104
|
if (exitStrategy === 'deploy-start') {
|
|
113
105
|
return;
|
|
@@ -127,7 +119,7 @@ export async function watchDeploymentAndDisplayLogs (options) {
|
|
|
127
119
|
}
|
|
128
120
|
|
|
129
121
|
if (!quiet) {
|
|
130
|
-
Logger.println(` ${
|
|
122
|
+
Logger.println(` ${styleText('blue', '→ Waiting for application logs…')}`);
|
|
131
123
|
}
|
|
132
124
|
|
|
133
125
|
// Wait for deployment end (or an error thrown by logs with the deferred)
|
|
@@ -143,43 +135,43 @@ export async function watchDeploymentAndDisplayLogs (options) {
|
|
|
143
135
|
if (deploymentEnded.state === 'OK') {
|
|
144
136
|
const favouriteDomain = await getBest(appId, ownerId);
|
|
145
137
|
Logger.println('');
|
|
146
|
-
Logger.println(
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
138
|
+
Logger.println(
|
|
139
|
+
`${styleText(['bold', 'green'], '✓ Access your application:')} ${styleText(['underline', 'bold'], `https://${favouriteDomain.fqdn}`)}`,
|
|
140
|
+
);
|
|
141
|
+
Logger.println(
|
|
142
|
+
`${styleText(['bold', 'blue'], '→ Manage your application:')} ${styleText(['underline', 'bold'], `${conf.GOTO_URL}/${appId}`)}`,
|
|
143
|
+
);
|
|
144
|
+
} else if (deploymentEnded.state === 'CANCELLED') {
|
|
150
145
|
throw new Error('Deployment was cancelled. Please check the activity');
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
146
|
+
} else {
|
|
153
147
|
throw new Error('Deployment failed. Please check the logs');
|
|
154
148
|
}
|
|
155
149
|
}
|
|
156
150
|
|
|
157
|
-
function formatLogLine
|
|
151
|
+
function formatLogLine(log) {
|
|
158
152
|
const { date, message } = log;
|
|
159
153
|
if (isDeploymentSuccessMessage(log)) {
|
|
160
|
-
return `${date.toISOString()}: ${
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
else if (isBuildSucessMessage(log)) {
|
|
166
|
-
return `${date.toISOString()}: ${colors.bold.blue(message)}`;
|
|
154
|
+
return `${date.toISOString()}: ${styleText(['bold', 'green'], message)}`;
|
|
155
|
+
} else if (isDeploymentFailedMessage(log)) {
|
|
156
|
+
return `${date.toISOString()}: ${styleText(['bold', 'red'], message)}`;
|
|
157
|
+
} else if (isBuildSucessMessage(log)) {
|
|
158
|
+
return `${date.toISOString()}: ${styleText(['bold', 'blue'], message)}`;
|
|
167
159
|
}
|
|
168
160
|
return `${date.toISOString()}: ${message}${RESET_COLOR}`;
|
|
169
161
|
}
|
|
170
162
|
|
|
171
|
-
function isCleverMessage
|
|
163
|
+
function isCleverMessage(log) {
|
|
172
164
|
return log.service !== 'bas-deploy.service';
|
|
173
|
-
}
|
|
165
|
+
}
|
|
174
166
|
|
|
175
|
-
function isDeploymentSuccessMessage
|
|
167
|
+
function isDeploymentSuccessMessage(log) {
|
|
176
168
|
return isCleverMessage(log) && log.message.toLowerCase().startsWith('successfully deployed in');
|
|
177
|
-
}
|
|
169
|
+
}
|
|
178
170
|
|
|
179
|
-
function isDeploymentFailedMessage
|
|
171
|
+
function isDeploymentFailedMessage(log) {
|
|
180
172
|
return isCleverMessage(log) && log.message.toLowerCase().startsWith('deploy failed in');
|
|
181
|
-
}
|
|
173
|
+
}
|
|
182
174
|
|
|
183
|
-
function isBuildSucessMessage
|
|
175
|
+
function isBuildSucessMessage(log) {
|
|
184
176
|
return isCleverMessage(log) && log.message.toLowerCase().startsWith('build succeeded in');
|
|
185
|
-
}
|
|
177
|
+
}
|
package/src/models/log.js
CHANGED
|
@@ -1,49 +1,42 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
|
-
import colors from 'colors/safe.js';
|
|
3
|
-
|
|
4
|
-
import { Logger } from '../logger.js';
|
|
5
|
-
import { Deferred } from './utils.js';
|
|
6
1
|
import { getOldLogs } from '@clevercloud/client/esm/api/v2/log.js';
|
|
7
2
|
import { LogsStream } from '@clevercloud/client/esm/streams/logs.node.js';
|
|
8
|
-
import
|
|
3
|
+
import _ from 'lodash';
|
|
4
|
+
import { styleText } from 'node:util';
|
|
5
|
+
import { Logger } from '../logger.js';
|
|
9
6
|
import { waitForDeploymentEnd, waitForDeploymentStart } from './deployments.js';
|
|
10
|
-
import * as ExitStrategy from '
|
|
7
|
+
import * as ExitStrategy from './exit-strategy-option.js';
|
|
8
|
+
import { getHostAndTokens, sendToApi } from './send-to-api.js';
|
|
9
|
+
import { Deferred } from './utils.js';
|
|
11
10
|
|
|
12
|
-
function isCleverMessage
|
|
11
|
+
function isCleverMessage(line) {
|
|
13
12
|
return line._source.syslog_program === '/home/bas/rubydeployer/deployer.rb';
|
|
14
|
-
}
|
|
13
|
+
}
|
|
15
14
|
|
|
16
|
-
function isDeploymentSuccessMessage
|
|
17
|
-
return isCleverMessage(line)
|
|
18
|
-
|
|
19
|
-
};
|
|
15
|
+
function isDeploymentSuccessMessage(line) {
|
|
16
|
+
return isCleverMessage(line) && _.startsWith(line._source['@message'].toLowerCase(), 'successfully deployed in');
|
|
17
|
+
}
|
|
20
18
|
|
|
21
|
-
function isDeploymentFailedMessage
|
|
22
|
-
return isCleverMessage(line)
|
|
23
|
-
|
|
24
|
-
};
|
|
19
|
+
function isDeploymentFailedMessage(line) {
|
|
20
|
+
return isCleverMessage(line) && _.startsWith(line._source['@message'].toLowerCase(), 'deploy failed in');
|
|
21
|
+
}
|
|
25
22
|
|
|
26
|
-
function isBuildSucessMessage
|
|
27
|
-
return isCleverMessage(line)
|
|
28
|
-
|
|
29
|
-
};
|
|
23
|
+
function isBuildSucessMessage(line) {
|
|
24
|
+
return isCleverMessage(line) && _.startsWith(line._source['@message'].toLowerCase(), 'build succeeded in');
|
|
25
|
+
}
|
|
30
26
|
|
|
31
|
-
function formatLogLine
|
|
27
|
+
function formatLogLine(line) {
|
|
32
28
|
const { '@timestamp': timestamp, '@message': message } = line._source;
|
|
33
29
|
if (isDeploymentSuccessMessage(line)) {
|
|
34
|
-
return `${timestamp}: ${
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
else if (isBuildSucessMessage(line)) {
|
|
40
|
-
return `${timestamp}: ${colors.bold.blue(message)}`;
|
|
30
|
+
return `${timestamp}: ${styleText(['bold', 'green'], message)}`;
|
|
31
|
+
} else if (isDeploymentFailedMessage(line)) {
|
|
32
|
+
return `${timestamp}: ${styleText(['bold', 'red'], message)}`;
|
|
33
|
+
} else if (isBuildSucessMessage(line)) {
|
|
34
|
+
return `${timestamp}: ${styleText(['bold', 'blue'], message)}`;
|
|
41
35
|
}
|
|
42
36
|
return `${timestamp}: ${message}`;
|
|
43
37
|
}
|
|
44
38
|
|
|
45
|
-
async function displayLiveLogs
|
|
46
|
-
|
|
39
|
+
async function displayLiveLogs({ appId, filter, until, deploymentId }, deferred) {
|
|
47
40
|
const { apiHost, tokens } = await getHostAndTokens();
|
|
48
41
|
const logsStream = new LogsStream({ apiHost, tokens, appId, filter, deploymentId });
|
|
49
42
|
|
|
@@ -53,8 +46,7 @@ async function displayLiveLogs ({ appId, filter, until, deploymentId }, deferred
|
|
|
53
46
|
const { '@timestamp': timestamp } = line._source;
|
|
54
47
|
if (until != null && new Date(timestamp) > until) {
|
|
55
48
|
logsStream.close();
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
49
|
+
} else {
|
|
58
50
|
Logger.println(formatLogLine(line));
|
|
59
51
|
}
|
|
60
52
|
})
|
|
@@ -67,13 +59,11 @@ async function displayLiveLogs ({ appId, filter, until, deploymentId }, deferred
|
|
|
67
59
|
return logsStream;
|
|
68
60
|
}
|
|
69
61
|
|
|
70
|
-
export async function displayLogs
|
|
71
|
-
|
|
62
|
+
export async function displayLogs({ appAddonId, until, since, filter, deploymentId }) {
|
|
72
63
|
const now = new Date();
|
|
73
64
|
|
|
74
|
-
const fetchOldLogs =
|
|
65
|
+
const fetchOldLogs = since == null || since < now;
|
|
75
66
|
if (fetchOldLogs) {
|
|
76
|
-
|
|
77
67
|
const oldLogs = await getOldLogs({
|
|
78
68
|
appId: appAddonId,
|
|
79
69
|
before: until != null ? until.toISOString() : null,
|
|
@@ -99,13 +89,20 @@ export async function displayLogs ({ appAddonId, until, since, filter, deploymen
|
|
|
99
89
|
return deferred.promise;
|
|
100
90
|
}
|
|
101
91
|
|
|
102
|
-
export async function watchDeploymentAndDisplayLogs
|
|
103
|
-
|
|
92
|
+
export async function watchDeploymentAndDisplayLogs({
|
|
93
|
+
ownerId,
|
|
94
|
+
appId,
|
|
95
|
+
deploymentId,
|
|
96
|
+
commitId,
|
|
97
|
+
knownDeployments,
|
|
98
|
+
quiet,
|
|
99
|
+
exitStrategy,
|
|
100
|
+
}) {
|
|
104
101
|
ExitStrategy.plotQuietWarning(exitStrategy, quiet);
|
|
105
102
|
// If in quiet mode, we only log start/finished deployment messages
|
|
106
103
|
Logger.println('Waiting for deployment to start…');
|
|
107
104
|
const deployment = await waitForDeploymentStart({ ownerId, appId, deploymentId, commitId, knownDeployments });
|
|
108
|
-
Logger.println(
|
|
105
|
+
Logger.println(styleText(['bold', 'blue'], `Deployment started (${deployment.uuid})`));
|
|
109
106
|
|
|
110
107
|
if (exitStrategy === 'deploy-start') {
|
|
111
108
|
return;
|
|
@@ -137,12 +134,10 @@ export async function watchDeploymentAndDisplayLogs ({ ownerId, appId, deploymen
|
|
|
137
134
|
}
|
|
138
135
|
|
|
139
136
|
if (deploymentEnded.state === 'OK') {
|
|
140
|
-
Logger.println(
|
|
141
|
-
}
|
|
142
|
-
else if (deploymentEnded.state === 'CANCELLED') {
|
|
137
|
+
Logger.println(styleText(['bold', 'green'], 'Deployment successful'));
|
|
138
|
+
} else if (deploymentEnded.state === 'CANCELLED') {
|
|
143
139
|
throw new Error('Deployment was cancelled. Please check the activity');
|
|
144
|
-
}
|
|
145
|
-
else {
|
|
140
|
+
} else {
|
|
146
141
|
throw new Error('Deployment failed. Please check the logs');
|
|
147
142
|
}
|
|
148
143
|
}
|
package/src/models/namespaces.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import * as Application from './application.js';
|
|
2
1
|
import { getNamespaces as getTcpRedirNamespaces } from '@clevercloud/client/esm/api/v2/organisation.js';
|
|
3
|
-
import { sendToApi } from './send-to-api.js';
|
|
4
2
|
import cliparse from 'cliparse';
|
|
3
|
+
import * as Application from './application.js';
|
|
4
|
+
import { sendToApi } from './send-to-api.js';
|
|
5
5
|
|
|
6
|
-
export async function getNamespaces
|
|
6
|
+
export async function getNamespaces(ownerId) {
|
|
7
7
|
return getTcpRedirNamespaces({ id: ownerId }).then(sendToApi);
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
export async function completeNamespaces
|
|
10
|
+
export async function completeNamespaces() {
|
|
11
11
|
// Sadly we do not have access to current params in complete as of now
|
|
12
12
|
const { ownerId } = await Application.resolveId(null, null);
|
|
13
13
|
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
import * as networkGroup from './ng.js';
|
|
1
|
+
import { getSummary } from '@clevercloud/client/esm/api/v2/user.js';
|
|
3
2
|
import * as networkGroupApi from '@clevercloud/client/esm/api/v4/network-group.js';
|
|
4
|
-
|
|
5
3
|
import crypto from 'node:crypto';
|
|
6
4
|
import { setTimeout } from 'node:timers/promises';
|
|
5
|
+
import { styleText } from 'node:util';
|
|
7
6
|
import { Logger } from '../logger.js';
|
|
7
|
+
import * as networkGroup from './ng.js';
|
|
8
8
|
import { sendToApi } from './send-to-api.js';
|
|
9
|
-
import { getSummary } from '@clevercloud/client/esm/api/v2/user.js';
|
|
10
9
|
|
|
11
10
|
/**
|
|
12
11
|
* Create an external peer and link its parent member to the Network Group
|
|
@@ -19,8 +18,7 @@ import { getSummary } from '@clevercloud/client/esm/api/v2/user.js';
|
|
|
19
18
|
* @throws {Error} If the parent member is not linked to the Network Group
|
|
20
19
|
* @throws {Error} If the external peer is not linked to the Network Group
|
|
21
20
|
*/
|
|
22
|
-
export async function createExternalPeerWithParent
|
|
23
|
-
|
|
21
|
+
export async function createExternalPeerWithParent(ngIdOrLabel, peerLabel, publicKey, org) {
|
|
24
22
|
if (!peerLabel) {
|
|
25
23
|
throw new Error('A valid peer label is required');
|
|
26
24
|
}
|
|
@@ -28,7 +26,7 @@ export async function createExternalPeerWithParent (ngIdOrLabel, peerLabel, publ
|
|
|
28
26
|
const [ng] = await networkGroup.searchNgOrResource(ngIdOrLabel, org, 'NetworkGroup');
|
|
29
27
|
|
|
30
28
|
if (!ng) {
|
|
31
|
-
throw new Error(`Network Group ${
|
|
29
|
+
throw new Error(`Network Group ${styleText('red', ngIdOrLabel.ngId || ngIdOrLabel.ngResourceLabel)} not found`);
|
|
32
30
|
}
|
|
33
31
|
|
|
34
32
|
// We define a parent member for the external peer
|
|
@@ -45,7 +43,9 @@ export async function createExternalPeerWithParent (ngIdOrLabel, peerLabel, publ
|
|
|
45
43
|
|
|
46
44
|
const checkParentMember = await checkResource(ng.id, org, parentMember.id, true);
|
|
47
45
|
if (!checkParentMember) {
|
|
48
|
-
throw new Error(
|
|
46
|
+
throw new Error(
|
|
47
|
+
`Parent member ${styleText('red', parentMember.id)} not linked to Network Group ${styleText('red', ng.id)}`,
|
|
48
|
+
);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
Logger.info(`Parent member ${parentMember.id} created and linked to Network Group ${ng.id}`);
|
|
@@ -60,11 +60,15 @@ export async function createExternalPeerWithParent (ngIdOrLabel, peerLabel, publ
|
|
|
60
60
|
|
|
61
61
|
Logger.info(`Adding external peer to Member ${parentMember.id} of Network Group ${ng.id}`);
|
|
62
62
|
Logger.debug('Sending body: ' + JSON.stringify(body, null, 2));
|
|
63
|
-
await networkGroupApi
|
|
63
|
+
await networkGroupApi
|
|
64
|
+
.createNetworkGroupExternalPeer({ ownerId: ng.ownerId, networkGroupId: ng.id }, body)
|
|
65
|
+
.then(sendToApi);
|
|
64
66
|
|
|
65
67
|
const checkExternalPeer = await checkResource(ng.id, org, peerLabel, true, 'peer', 'label');
|
|
66
68
|
if (!checkExternalPeer) {
|
|
67
|
-
throw new Error(
|
|
69
|
+
throw new Error(
|
|
70
|
+
`External peer ${styleText('red', peerLabel)} not linked to Network Group ${styleText('red', ng.id)}`,
|
|
71
|
+
);
|
|
68
72
|
}
|
|
69
73
|
|
|
70
74
|
Logger.info(`External peer ${peerLabel} added to Member ${parentMember.id} of Network Group ${ng.id}`);
|
|
@@ -80,12 +84,11 @@ export async function createExternalPeerWithParent (ngIdOrLabel, peerLabel, publ
|
|
|
80
84
|
* @throws {Error} If the External Peer is still linked to the Network Group
|
|
81
85
|
* @throws {Error} If the Parent Member is still linked to the Network Group
|
|
82
86
|
*/
|
|
83
|
-
export async function deleteExternalPeerWithParent
|
|
84
|
-
|
|
87
|
+
export async function deleteExternalPeerWithParent(ngIdOrLabel, peerIdOrLabel, org) {
|
|
85
88
|
const [ng] = await networkGroup.searchNgOrResource(ngIdOrLabel, org, 'NetworkGroup');
|
|
86
89
|
|
|
87
90
|
if (!ng) {
|
|
88
|
-
throw new Error(`Network Group ${
|
|
91
|
+
throw new Error(`Network Group ${styleText('red', ngIdOrLabel.ngId || ngIdOrLabel.ngResourceLabel)} not found`);
|
|
89
92
|
}
|
|
90
93
|
|
|
91
94
|
const externalPeer = ng.peers.find((p) => {
|
|
@@ -93,15 +96,19 @@ export async function deleteExternalPeerWithParent (ngIdOrLabel, peerIdOrLabel,
|
|
|
93
96
|
});
|
|
94
97
|
|
|
95
98
|
if (!externalPeer) {
|
|
96
|
-
throw new Error(`External peer ${
|
|
99
|
+
throw new Error(`External peer ${styleText('red', peerIdOrLabel)} not found`);
|
|
97
100
|
}
|
|
98
101
|
|
|
99
102
|
Logger.info(`Deleting external peer ${externalPeer.id} from Network Group ${ng.id}`);
|
|
100
|
-
await networkGroupApi
|
|
103
|
+
await networkGroupApi
|
|
104
|
+
.deleteNetworkGroupExternalPeer({ ownerId: ng.ownerId, networkGroupId: ng.id, peerId: externalPeer.id })
|
|
105
|
+
.then(sendToApi);
|
|
101
106
|
|
|
102
107
|
const checkPeer = await checkResource(ng.id, org, externalPeer.id, false, 'peer');
|
|
103
108
|
if (!checkPeer) {
|
|
104
|
-
throw new Error(
|
|
109
|
+
throw new Error(
|
|
110
|
+
`External peer ${styleText('red', externalPeer.id)} still linked to Network Group ${styleText('red', ng.id)}`,
|
|
111
|
+
);
|
|
105
112
|
}
|
|
106
113
|
|
|
107
114
|
Logger.info(`External peer ${externalPeer.id} deleted from Network Group ${ng.id}`);
|
|
@@ -111,7 +118,9 @@ export async function deleteExternalPeerWithParent (ngIdOrLabel, peerIdOrLabel,
|
|
|
111
118
|
|
|
112
119
|
const checkParentMember = await checkResource(ng.id, org, externalPeer.parentMember, false);
|
|
113
120
|
if (!checkParentMember) {
|
|
114
|
-
throw new Error(
|
|
121
|
+
throw new Error(
|
|
122
|
+
`Parent member ${styleText('red', externalPeer.parentMember)} still linked to Network Group ${styleText('red', ng.id)}`,
|
|
123
|
+
);
|
|
115
124
|
}
|
|
116
125
|
|
|
117
126
|
Logger.info(`Parent member ${externalPeer.parentMember} unlinked from Network Group ${ng.id}`);
|
|
@@ -124,7 +133,7 @@ export async function deleteExternalPeerWithParent (ngIdOrLabel, peerIdOrLabel,
|
|
|
124
133
|
* @param {object} org Organisation ID or name
|
|
125
134
|
* @param {string} label Label of the Member
|
|
126
135
|
*/
|
|
127
|
-
export async function linkMember
|
|
136
|
+
export async function linkMember(ngIdOrLabel, memberId, org, label) {
|
|
128
137
|
if (!memberId) {
|
|
129
138
|
throw new Error('A valid member ID is required (addon_xxx, app_xxx, external_xxx)');
|
|
130
139
|
}
|
|
@@ -132,14 +141,16 @@ export async function linkMember (ngIdOrLabel, memberId, org, label) {
|
|
|
132
141
|
const [ng] = await networkGroup.searchNgOrResource(ngIdOrLabel, org, 'NetworkGroup');
|
|
133
142
|
|
|
134
143
|
if (!ng) {
|
|
135
|
-
throw new Error(`Network Group ${
|
|
144
|
+
throw new Error(`Network Group ${styleText('red', ngIdOrLabel.ngId || ngIdOrLabel.ngResourceLabel)} not found`);
|
|
136
145
|
}
|
|
137
146
|
|
|
138
147
|
await checkMembersToLink([memberId], ng.ownerId);
|
|
139
148
|
|
|
140
149
|
const alreadyMember = ng.members.find((m) => m.id === memberId);
|
|
141
150
|
if (alreadyMember) {
|
|
142
|
-
throw new Error(
|
|
151
|
+
throw new Error(
|
|
152
|
+
`Member ${styleText('red', memberId)} is already linked to Network Group ${styleText('red', ng.id)}`,
|
|
153
|
+
);
|
|
143
154
|
}
|
|
144
155
|
|
|
145
156
|
const [member] = networkGroup.constructMembers(ng.id, [memberId]);
|
|
@@ -157,7 +168,7 @@ export async function linkMember (ngIdOrLabel, memberId, org, label) {
|
|
|
157
168
|
|
|
158
169
|
const check = await checkResource(ng.id, org, member.id, true);
|
|
159
170
|
if (!check) {
|
|
160
|
-
throw new Error(`Member ${
|
|
171
|
+
throw new Error(`Member ${styleText('red', member.id)} not linked to Network Group ${styleText('red', ng.id)}`);
|
|
161
172
|
}
|
|
162
173
|
|
|
163
174
|
Logger.info(`Member ${member.id} linked to Network Group ${ng.id}`);
|
|
@@ -173,7 +184,7 @@ export async function linkMember (ngIdOrLabel, memberId, org, label) {
|
|
|
173
184
|
* @throws {Error} If the Member is not found in the Network Group
|
|
174
185
|
* @throws {Error} If the Member is still linked to the Network Group
|
|
175
186
|
*/
|
|
176
|
-
export async function unlinkMember
|
|
187
|
+
export async function unlinkMember(ngIdOrLabel, memberId, org) {
|
|
177
188
|
if (!memberId) {
|
|
178
189
|
throw new Error('A valid member ID is required (addon_xxx, app_xxx, external_xxx)');
|
|
179
190
|
}
|
|
@@ -181,20 +192,22 @@ export async function unlinkMember (ngIdOrLabel, memberId, org) {
|
|
|
181
192
|
const [ng] = await networkGroup.searchNgOrResource(ngIdOrLabel, org, 'NetworkGroup');
|
|
182
193
|
|
|
183
194
|
if (!ng) {
|
|
184
|
-
throw new Error(`Network Group ${
|
|
195
|
+
throw new Error(`Network Group ${styleText('red', ngIdOrLabel.ngId || ngIdOrLabel.ngLabel)} not found`);
|
|
185
196
|
}
|
|
186
197
|
|
|
187
198
|
const member = ng.members.find((m) => m.id === memberId);
|
|
188
199
|
if (!member) {
|
|
189
|
-
throw new Error(`Member ${
|
|
200
|
+
throw new Error(`Member ${styleText('red', memberId)} not found in Network Group ${styleText('red', ng.id)}`);
|
|
190
201
|
}
|
|
191
202
|
|
|
192
203
|
Logger.info(`Unlinking member ${memberId} from Network Group ${ng.id}`);
|
|
193
|
-
await networkGroupApi
|
|
204
|
+
await networkGroupApi
|
|
205
|
+
.deleteNetworkGroupMember({ ownerId: ng.ownerId, networkGroupId: ng.id, memberId })
|
|
206
|
+
.then(sendToApi);
|
|
194
207
|
|
|
195
208
|
const check = await checkResource(ng.id, org, memberId, false);
|
|
196
209
|
if (!check) {
|
|
197
|
-
throw new Error(`Member ${
|
|
210
|
+
throw new Error(`Member ${styleText('red', memberId)} still linked to Network Group ${styleText('red', ng.id)}`);
|
|
198
211
|
}
|
|
199
212
|
|
|
200
213
|
Logger.info(`Member ${memberId} unlinked from Network Group ${ng.id}`);
|
|
@@ -205,14 +218,8 @@ export async function unlinkMember (ngIdOrLabel, memberId, org) {
|
|
|
205
218
|
* @param {Array<string>} members Members to check
|
|
206
219
|
* @throws {Error} If members can't be linked to a Network Group
|
|
207
220
|
*/
|
|
208
|
-
export async function checkMembersToLink
|
|
209
|
-
const VALID_ADDON_PROVIDERS = [
|
|
210
|
-
'es-addon',
|
|
211
|
-
'mongodb-addon',
|
|
212
|
-
'mysql-addon',
|
|
213
|
-
'postgresql-addon',
|
|
214
|
-
'redis-addon',
|
|
215
|
-
];
|
|
221
|
+
export async function checkMembersToLink(members, ownerId) {
|
|
222
|
+
const VALID_ADDON_PROVIDERS = ['es-addon', 'mongodb-addon', 'mysql-addon', 'postgresql-addon', 'redis-addon'];
|
|
216
223
|
|
|
217
224
|
const summary = await getSummary().then(sendToApi);
|
|
218
225
|
|
|
@@ -225,20 +232,23 @@ export async function checkMembersToLink (members, ownerId) {
|
|
|
225
232
|
let source = data.applications;
|
|
226
233
|
|
|
227
234
|
for (const memberId of members) {
|
|
228
|
-
if (memberId.startsWith('addon_'))
|
|
235
|
+
if (memberId.startsWith('addon_')) {
|
|
236
|
+
source = data.addons;
|
|
237
|
+
}
|
|
229
238
|
|
|
230
239
|
const foundRessource = source.find((r) => r.id === memberId);
|
|
231
240
|
|
|
232
241
|
if (foundRessource && memberId.startsWith('addon_') && !VALID_ADDON_PROVIDERS.includes(foundRessource.providerId)) {
|
|
233
242
|
membersNotOK.push(memberId);
|
|
234
|
-
}
|
|
235
|
-
else if (!foundRessource && !memberId.startsWith('external_')) {
|
|
243
|
+
} else if (!foundRessource && !memberId.startsWith('external_')) {
|
|
236
244
|
membersNotOK.push(memberId);
|
|
237
245
|
}
|
|
238
246
|
}
|
|
239
247
|
|
|
240
248
|
if (membersNotOK.length > 0) {
|
|
241
|
-
throw new Error(
|
|
249
|
+
throw new Error(
|
|
250
|
+
`Member(s) ${styleText('red', membersNotOK.join(', '))} can't be linked to the Network Group, check Organisation ID or name`,
|
|
251
|
+
);
|
|
242
252
|
}
|
|
243
253
|
}
|
|
244
254
|
|
|
@@ -252,7 +262,7 @@ export async function checkMembersToLink (members, ownerId) {
|
|
|
252
262
|
* @param {string} [searchBy] Search by 'id' or 'label', default is 'id'
|
|
253
263
|
* @returns {Promise<boolean>} True if the resource is present, false otherwise
|
|
254
264
|
*/
|
|
255
|
-
async function checkResource
|
|
265
|
+
async function checkResource(ngId, org, resource, shouldBePresent, resourceType = 'member', searchBy = 'id') {
|
|
256
266
|
const endTime = Date.now() + networkGroup.POLLING_TIMEOUT_MS;
|
|
257
267
|
|
|
258
268
|
while (Date.now() < endTime) {
|