@sfdxy/anypoint-connect 0.15.0 → 0.16.2
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 +32 -14
- package/dist/analysis/LogAnalyzer.d.ts +9 -3
- package/dist/analysis/LogAnalyzer.d.ts.map +1 -1
- package/dist/analysis/LogAnalyzer.js +28 -17
- package/dist/analysis/LogAnalyzer.js.map +1 -1
- package/dist/analysis/error-context.d.ts +2 -0
- package/dist/analysis/error-context.d.ts.map +1 -1
- package/dist/analysis/error-context.js +2 -1
- package/dist/analysis/error-context.js.map +1 -1
- package/dist/analysis/filter.d.ts +54 -0
- package/dist/analysis/filter.d.ts.map +1 -0
- package/dist/analysis/filter.js +100 -0
- package/dist/analysis/filter.js.map +1 -0
- package/dist/analysis/parser.d.ts.map +1 -1
- package/dist/analysis/parser.js +31 -14
- package/dist/analysis/parser.js.map +1 -1
- package/dist/analysis/stats.d.ts +25 -0
- package/dist/analysis/stats.d.ts.map +1 -1
- package/dist/analysis/stats.js +34 -0
- package/dist/analysis/stats.js.map +1 -1
- package/dist/analysis/summary.d.ts +51 -0
- package/dist/analysis/summary.d.ts.map +1 -0
- package/dist/analysis/summary.js +47 -0
- package/dist/analysis/summary.js.map +1 -0
- package/dist/analysis/types.d.ts +14 -0
- package/dist/analysis/types.d.ts.map +1 -1
- package/dist/api/ApiManagerApi.d.ts +53 -0
- package/dist/api/ApiManagerApi.d.ts.map +1 -1
- package/dist/api/ApiManagerApi.js +53 -2
- package/dist/api/ApiManagerApi.js.map +1 -1
- package/dist/api/CloudHub2Api.d.ts +24 -4
- package/dist/api/CloudHub2Api.d.ts.map +1 -1
- package/dist/api/CloudHub2Api.js +10 -22
- package/dist/api/CloudHub2Api.js.map +1 -1
- package/dist/api/ExchangeApi.d.ts +15 -0
- package/dist/api/ExchangeApi.d.ts.map +1 -1
- package/dist/api/ExchangeApi.js +51 -0
- package/dist/api/ExchangeApi.js.map +1 -1
- package/dist/api/LogsApi.d.ts +50 -18
- package/dist/api/LogsApi.d.ts.map +1 -1
- package/dist/api/LogsApi.js +69 -98
- package/dist/api/LogsApi.js.map +1 -1
- package/dist/api/RuntimesApi.d.ts +56 -0
- package/dist/api/RuntimesApi.d.ts.map +1 -0
- package/dist/api/RuntimesApi.js +58 -0
- package/dist/api/RuntimesApi.js.map +1 -0
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/client/AnypointClient.d.ts +2 -0
- package/dist/client/AnypointClient.d.ts.map +1 -1
- package/dist/client/AnypointClient.js +3 -0
- package/dist/client/AnypointClient.js.map +1 -1
- package/dist/client/smoke-test.d.ts +111 -0
- package/dist/client/smoke-test.d.ts.map +1 -0
- package/dist/client/smoke-test.js +275 -0
- package/dist/client/smoke-test.js.map +1 -0
- package/dist/commands/api.d.ts +1 -1
- package/dist/commands/api.d.ts.map +1 -1
- package/dist/commands/api.js +147 -10
- package/dist/commands/api.js.map +1 -1
- package/dist/commands/app-change-cli.d.ts +52 -0
- package/dist/commands/app-change-cli.d.ts.map +1 -0
- package/dist/commands/app-change-cli.js +149 -0
- package/dist/commands/app-change-cli.js.map +1 -0
- package/dist/commands/apps.d.ts +1 -1
- package/dist/commands/apps.d.ts.map +1 -1
- package/dist/commands/apps.js +198 -17
- package/dist/commands/apps.js.map +1 -1
- package/dist/commands/compare.d.ts +8 -0
- package/dist/commands/compare.d.ts.map +1 -0
- package/dist/commands/compare.js +104 -0
- package/dist/commands/compare.js.map +1 -0
- package/dist/commands/deploy.d.ts +4 -3
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +59 -33
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +1 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/logs.d.ts +3 -2
- package/dist/commands/logs.d.ts.map +1 -1
- package/dist/commands/logs.js +142 -17
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/runtimes.d.ts +7 -0
- package/dist/commands/runtimes.d.ts.map +1 -0
- package/dist/commands/runtimes.js +66 -0
- package/dist/commands/runtimes.js.map +1 -0
- package/dist/config/profiles.d.ts +8 -0
- package/dist/config/profiles.d.ts.map +1 -1
- package/dist/config/profiles.js.map +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +2 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools/analysis.d.ts.map +1 -1
- package/dist/mcp/tools/analysis.js +74 -30
- package/dist/mcp/tools/analysis.js.map +1 -1
- package/dist/mcp/tools/anypoint-mq.d.ts.map +1 -1
- package/dist/mcp/tools/anypoint-mq.js +5 -2
- package/dist/mcp/tools/anypoint-mq.js.map +1 -1
- package/dist/mcp/tools/api-manager.d.ts +2 -1
- package/dist/mcp/tools/api-manager.d.ts.map +1 -1
- package/dist/mcp/tools/api-manager.js +127 -38
- package/dist/mcp/tools/api-manager.js.map +1 -1
- package/dist/mcp/tools/app-inputs.d.ts +92 -0
- package/dist/mcp/tools/app-inputs.d.ts.map +1 -0
- package/dist/mcp/tools/app-inputs.js +142 -0
- package/dist/mcp/tools/app-inputs.js.map +1 -0
- package/dist/mcp/tools/apps-deploy.d.ts +6 -1
- package/dist/mcp/tools/apps-deploy.d.ts.map +1 -1
- package/dist/mcp/tools/apps-deploy.js +279 -307
- package/dist/mcp/tools/apps-deploy.js.map +1 -1
- package/dist/mcp/tools/apps-lifecycle.d.ts +3 -0
- package/dist/mcp/tools/apps-lifecycle.d.ts.map +1 -1
- package/dist/mcp/tools/apps-lifecycle.js +105 -136
- package/dist/mcp/tools/apps-lifecycle.js.map +1 -1
- package/dist/mcp/tools/apps-read.d.ts +2 -1
- package/dist/mcp/tools/apps-read.d.ts.map +1 -1
- package/dist/mcp/tools/apps-read.js +177 -14
- package/dist/mcp/tools/apps-read.js.map +1 -1
- package/dist/mcp/tools/artifacts.d.ts +8 -0
- package/dist/mcp/tools/artifacts.d.ts.map +1 -0
- package/dist/mcp/tools/artifacts.js +81 -0
- package/dist/mcp/tools/artifacts.js.map +1 -0
- package/dist/mcp/tools/index.d.ts +1 -0
- package/dist/mcp/tools/index.d.ts.map +1 -1
- package/dist/mcp/tools/index.js +1 -0
- package/dist/mcp/tools/index.js.map +1 -1
- package/dist/mcp/tools/logs.d.ts +48 -2
- package/dist/mcp/tools/logs.d.ts.map +1 -1
- package/dist/mcp/tools/logs.js +205 -38
- package/dist/mcp/tools/logs.js.map +1 -1
- package/dist/mcp/tools/shared.d.ts +27 -0
- package/dist/mcp/tools/shared.d.ts.map +1 -1
- package/dist/mcp/tools/shared.js +42 -0
- package/dist/mcp/tools/shared.js.map +1 -1
- package/dist/safety/deployment.d.ts +47 -2
- package/dist/safety/deployment.d.ts.map +1 -1
- package/dist/safety/deployment.js +139 -6
- package/dist/safety/deployment.js.map +1 -1
- package/dist/safety/paths.d.ts +29 -0
- package/dist/safety/paths.d.ts.map +1 -0
- package/dist/safety/paths.js +76 -0
- package/dist/safety/paths.js.map +1 -0
- package/dist/safety/runtime.d.ts +24 -0
- package/dist/safety/runtime.d.ts.map +1 -0
- package/dist/safety/runtime.js +59 -0
- package/dist/safety/runtime.js.map +1 -0
- package/dist/safety/secret-sources.d.ts +51 -0
- package/dist/safety/secret-sources.d.ts.map +1 -0
- package/dist/safety/secret-sources.js +124 -0
- package/dist/safety/secret-sources.js.map +1 -0
- package/dist/safety/secrets.d.ts +32 -0
- package/dist/safety/secrets.d.ts.map +1 -0
- package/dist/safety/secrets.js +91 -0
- package/dist/safety/secrets.js.map +1 -0
- package/dist/utils/errors.d.ts +2 -1
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +5 -3
- package/dist/utils/errors.js.map +1 -1
- package/dist/workflows/app-change.d.ts +124 -0
- package/dist/workflows/app-change.d.ts.map +1 -0
- package/dist/workflows/app-change.js +305 -0
- package/dist/workflows/app-change.js.map +1 -0
- package/dist/workflows/app-state.d.ts +60 -0
- package/dist/workflows/app-state.d.ts.map +1 -0
- package/dist/workflows/app-state.js +95 -0
- package/dist/workflows/app-state.js.map +1 -0
- package/dist/workflows/artifact-compare.d.ts +134 -0
- package/dist/workflows/artifact-compare.d.ts.map +1 -0
- package/dist/workflows/artifact-compare.js +419 -0
- package/dist/workflows/artifact-compare.js.map +1 -0
- package/dist/workflows/asset-naming.d.ts +72 -0
- package/dist/workflows/asset-naming.d.ts.map +1 -0
- package/dist/workflows/asset-naming.js +116 -0
- package/dist/workflows/asset-naming.js.map +1 -0
- package/dist/workflows/jar-deployment.d.ts +76 -39
- package/dist/workflows/jar-deployment.d.ts.map +1 -1
- package/dist/workflows/jar-deployment.js +125 -64
- package/dist/workflows/jar-deployment.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret detection and redaction
|
|
3
|
+
* Keeps secret values out of tool responses, CLI output and error messages.
|
|
4
|
+
*/
|
|
5
|
+
/** The placeholder the platform returns for stored secure property values. */
|
|
6
|
+
export declare const MASKED = "******";
|
|
7
|
+
/**
|
|
8
|
+
* True when a property name looks like it holds a secret. The name is split on `.`, `_`, `-`
|
|
9
|
+
* and camel-case boundaries, so `db.password`, `clientSecret` and `API_KEY` all match while
|
|
10
|
+
* `tokenizer.mode` or `keystore.type` do not.
|
|
11
|
+
*/
|
|
12
|
+
export declare function looksSecret(key: string): boolean;
|
|
13
|
+
/** Mask a value, keeping the last two characters of long values so a caller can tell values apart. */
|
|
14
|
+
export declare function redactValue(value: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Mask secret-looking entries of a flat record. `keys` forces masking for extra names
|
|
17
|
+
* (for example every key of a secure property map).
|
|
18
|
+
*/
|
|
19
|
+
export declare function redactRecord(record: Record<string, string>, options?: {
|
|
20
|
+
keys?: Iterable<string>;
|
|
21
|
+
}): Record<string, string>;
|
|
22
|
+
/**
|
|
23
|
+
* Recursively mask secret-looking fields in an arbitrary JSON value, such as an API error
|
|
24
|
+
* body the platform echoed back.
|
|
25
|
+
*/
|
|
26
|
+
export declare function redactDeep(value: unknown, depth?: number): unknown;
|
|
27
|
+
/**
|
|
28
|
+
* Replace every occurrence of known secret values in free text. Values shorter than four
|
|
29
|
+
* characters are skipped because they would match ordinary text.
|
|
30
|
+
*/
|
|
31
|
+
export declare function redactText(text: string, knownSecrets: Iterable<string>): string;
|
|
32
|
+
//# sourceMappingURL=secrets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.d.ts","sourceRoot":"","sources":["../../src/safety/secrets.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,8EAA8E;AAC9E,eAAO,MAAM,MAAM,WAAW,CAAC;AAuB/B;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAWhD;AAED,sGAAsG;AACtG,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGjD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;CAAO,GAO7F,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAC9B;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,SAAI,GAAG,OAAO,CAY7D;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,CAM/E"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret detection and redaction
|
|
3
|
+
* Keeps secret values out of tool responses, CLI output and error messages.
|
|
4
|
+
*/
|
|
5
|
+
/** The placeholder the platform returns for stored secure property values. */
|
|
6
|
+
export const MASKED = '******';
|
|
7
|
+
const SECRET_SEGMENTS = new Set([
|
|
8
|
+
'password',
|
|
9
|
+
'passwd',
|
|
10
|
+
'pwd',
|
|
11
|
+
'secret',
|
|
12
|
+
'token',
|
|
13
|
+
'credential',
|
|
14
|
+
'credentials',
|
|
15
|
+
'passphrase',
|
|
16
|
+
'apikey',
|
|
17
|
+
'privatekey',
|
|
18
|
+
'clientsecret',
|
|
19
|
+
]);
|
|
20
|
+
const SECRET_PAIRS = [
|
|
21
|
+
['private', 'key'],
|
|
22
|
+
['api', 'key'],
|
|
23
|
+
['client', 'secret'],
|
|
24
|
+
['access', 'key'],
|
|
25
|
+
];
|
|
26
|
+
/**
|
|
27
|
+
* True when a property name looks like it holds a secret. The name is split on `.`, `_`, `-`
|
|
28
|
+
* and camel-case boundaries, so `db.password`, `clientSecret` and `API_KEY` all match while
|
|
29
|
+
* `tokenizer.mode` or `keystore.type` do not.
|
|
30
|
+
*/
|
|
31
|
+
export function looksSecret(key) {
|
|
32
|
+
const segments = key
|
|
33
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
34
|
+
.toLowerCase()
|
|
35
|
+
.split(/[\s._\-/:]+/)
|
|
36
|
+
.filter(Boolean);
|
|
37
|
+
if (segments.some((segment) => SECRET_SEGMENTS.has(segment)))
|
|
38
|
+
return true;
|
|
39
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
40
|
+
if (SECRET_PAIRS.some(([a, b]) => segments[i] === a && segments[i + 1] === b))
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
/** Mask a value, keeping the last two characters of long values so a caller can tell values apart. */
|
|
46
|
+
export function redactValue(value) {
|
|
47
|
+
if (value === MASKED)
|
|
48
|
+
return MASKED;
|
|
49
|
+
return value.length > 8 ? `${MASKED}…${value.slice(-2)}` : MASKED;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Mask secret-looking entries of a flat record. `keys` forces masking for extra names
|
|
53
|
+
* (for example every key of a secure property map).
|
|
54
|
+
*/
|
|
55
|
+
export function redactRecord(record, options = {}) {
|
|
56
|
+
const forced = new Set(options.keys ?? []);
|
|
57
|
+
return Object.fromEntries(Object.entries(record).map(([key, value]) => [
|
|
58
|
+
key,
|
|
59
|
+
forced.has(key) || looksSecret(key) ? redactValue(String(value)) : value,
|
|
60
|
+
]));
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Recursively mask secret-looking fields in an arbitrary JSON value, such as an API error
|
|
64
|
+
* body the platform echoed back.
|
|
65
|
+
*/
|
|
66
|
+
export function redactDeep(value, depth = 0) {
|
|
67
|
+
if (depth > 20)
|
|
68
|
+
return value;
|
|
69
|
+
if (Array.isArray(value))
|
|
70
|
+
return value.map((item) => redactDeep(item, depth + 1));
|
|
71
|
+
if (value && typeof value === 'object') {
|
|
72
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [
|
|
73
|
+
key,
|
|
74
|
+
looksSecret(key) && typeof item === 'string' ? redactValue(item) : redactDeep(item, depth + 1),
|
|
75
|
+
]));
|
|
76
|
+
}
|
|
77
|
+
return value;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Replace every occurrence of known secret values in free text. Values shorter than four
|
|
81
|
+
* characters are skipped because they would match ordinary text.
|
|
82
|
+
*/
|
|
83
|
+
export function redactText(text, knownSecrets) {
|
|
84
|
+
const values = [...new Set(knownSecrets)].filter((v) => v && v !== MASKED && v.length >= 4);
|
|
85
|
+
values.sort((a, b) => b.length - a.length);
|
|
86
|
+
let result = text;
|
|
87
|
+
for (const value of values)
|
|
88
|
+
result = result.split(value).join(MASKED);
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../src/safety/secrets.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/errors.d.ts
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* Extracts a human-readable message from an unknown error value.
|
|
7
7
|
* For AxiosErrors, prefers the API response body (which often contains
|
|
8
8
|
* a more descriptive message than the generic HTTP status).
|
|
9
|
-
* Safely handles Error instances, strings, and other types.
|
|
9
|
+
* Safely handles Error instances, strings, and other types. Secret-looking
|
|
10
|
+
* fields in an echoed response body are masked.
|
|
10
11
|
*/
|
|
11
12
|
export declare function errorMessage(error: unknown): string;
|
|
12
13
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAYnD;AAED;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,KAAK;IAGjC,QAAQ,CAAC,KAAK,EAAE,MAAM;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM;IACxB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM;gBAH/B,OAAO,EAAE,MAAM,EACN,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,YAAA,EACf,aAAa,CAAC,EAAE,MAAM,YAAA;IAMnC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc;CAc7D"}
|
package/dist/utils/errors.js
CHANGED
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
* Shared error formatting for CLI and MCP error handling
|
|
4
4
|
*/
|
|
5
5
|
import { AxiosError } from 'axios';
|
|
6
|
+
import { redactDeep } from '../safety/secrets.js';
|
|
6
7
|
/**
|
|
7
8
|
* Extracts a human-readable message from an unknown error value.
|
|
8
9
|
* For AxiosErrors, prefers the API response body (which often contains
|
|
9
10
|
* a more descriptive message than the generic HTTP status).
|
|
10
|
-
* Safely handles Error instances, strings, and other types.
|
|
11
|
+
* Safely handles Error instances, strings, and other types. Secret-looking
|
|
12
|
+
* fields in an echoed response body are masked.
|
|
11
13
|
*/
|
|
12
14
|
export function errorMessage(error) {
|
|
13
15
|
if (error instanceof AxiosError && error.response) {
|
|
@@ -17,8 +19,8 @@ export function errorMessage(error) {
|
|
|
17
19
|
if (data && typeof data === 'object') {
|
|
18
20
|
if ('message' in data)
|
|
19
21
|
return String(data.message);
|
|
20
|
-
// Some APIs return { error: '...' } or { status, ... } — show
|
|
21
|
-
return `HTTP ${error.response.status}: ${JSON.stringify(data)}`;
|
|
22
|
+
// Some APIs return { error: '...' } or { status, ... } — show the body, masked
|
|
23
|
+
return `HTTP ${error.response.status}: ${JSON.stringify(redactDeep(data))}`;
|
|
22
24
|
}
|
|
23
25
|
return `HTTP ${error.response.status || 'unknown'}`;
|
|
24
26
|
}
|
package/dist/utils/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,KAAc;IACvC,IAAI,KAAK,YAAY,UAAU,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QAChD,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;QACjC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAC7D,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YACnC,IAAI,SAAS,IAAI,IAAI;gBAAE,OAAO,MAAM,CAAE,IAA4B,CAAC,OAAO,CAAC,CAAC;YAC5E,+EAA+E;YAC/E,OAAO,QAAQ,KAAK,CAAC,QAAQ,CAAC,MAAM,KAAK,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QAChF,CAAC;QACD,OAAO,QAAQ,KAAK,CAAC,QAAQ,CAAC,MAAM,IAAI,SAAS,EAAE,CAAC;IACxD,CAAC;IACD,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAClE,CAAC;AAED;;;;GAIG;AACH,MAAM,OAAO,cAAe,SAAQ,KAAK;IAGxB;IACA;IACA;IAJb,YACI,OAAe,EACN,KAAa,EACb,MAAe,EACf,aAAsB;QAE/B,KAAK,CAAC,OAAO,CAAC,CAAC;QAJN,UAAK,GAAL,KAAK,CAAQ;QACb,WAAM,GAAN,MAAM,CAAS;QACf,kBAAa,GAAb,aAAa,CAAS;QAG/B,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IACjC,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,KAAc,EAAE,KAAa;QACrC,IAAI,KAAK,YAAY,UAAU,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YAChD,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAsE,CAAC;YACnG,MAAM,MAAM,GAAG,OAAO,IAAI,EAAE,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;YACtF,MAAM,aAAa,GAAG,OAAO,IAAI,EAAE,CAAC,iBAAiB,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAC1G,OAAO,IAAI,cAAc,CACrB,2BAA2B,KAAK,CAAC,QAAQ,CAAC,MAAM,MAAM,MAAM,EAAE,EAC9D,KAAK,EACL,KAAK,CAAC,QAAQ,CAAC,MAAM,EACrB,aAAa,CAChB,CAAC;QACN,CAAC;QACD,OAAO,IAAI,cAAc,CAAC,sBAAsB,YAAY,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAClF,CAAC;CACJ"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application change workflow
|
|
3
|
+
* One plan and one PATCH for every change to an existing CloudHub 2.0 application: artifact,
|
|
4
|
+
* runtime, settings and update strategy, applied in place or as stop, change, start. Shared by
|
|
5
|
+
* the MCP tools and the CLI so previews, runtime checks, secret handling and waits match.
|
|
6
|
+
*/
|
|
7
|
+
import type { AnypointClient } from '../client/AnypointClient.js';
|
|
8
|
+
import type { Environment } from '../api/AccessManagementApi.js';
|
|
9
|
+
import type { ArtifactRef, CH2Deployment, DeploymentPatch } from '../api/CloudHub2Api.js';
|
|
10
|
+
import { type DeploymentChange, type SettingsChange, type SettingsPlan } from '../safety/deployment.js';
|
|
11
|
+
import { type RuntimeSpec } from '../safety/runtime.js';
|
|
12
|
+
import { type SecretSource } from '../safety/secret-sources.js';
|
|
13
|
+
import { type PhaseSnapshot } from './app-state.js';
|
|
14
|
+
export type ChangeMode = 'inPlace' | 'stopStart';
|
|
15
|
+
export type UpdateStrategy = 'rolling' | 'recreate';
|
|
16
|
+
/** A settings change as callers express it: inline values plus server-side sources. */
|
|
17
|
+
export interface SettingsChangeInput extends SettingsChange {
|
|
18
|
+
propertiesFrom?: SecretSource[];
|
|
19
|
+
securePropertiesFrom?: SecretSource[];
|
|
20
|
+
}
|
|
21
|
+
/** Resolve file and environment sources into values. Returns the secret values for output scrubbing. */
|
|
22
|
+
export declare function resolveSettingsInput(input: SettingsChangeInput | undefined, options?: {
|
|
23
|
+
projectRoot?: string;
|
|
24
|
+
env?: NodeJS.ProcessEnv;
|
|
25
|
+
}): {
|
|
26
|
+
change: SettingsChange | undefined;
|
|
27
|
+
secretValues: string[];
|
|
28
|
+
};
|
|
29
|
+
export interface AppChangeRequest {
|
|
30
|
+
orgId: string;
|
|
31
|
+
env: Environment;
|
|
32
|
+
appName: string;
|
|
33
|
+
/** Prefetched deployment detail; looked up by name when omitted. */
|
|
34
|
+
existing?: CH2Deployment | null;
|
|
35
|
+
ref?: Partial<ArtifactRef>;
|
|
36
|
+
runtime?: RuntimeSpec;
|
|
37
|
+
settings?: SettingsChange;
|
|
38
|
+
updateStrategy?: UpdateStrategy;
|
|
39
|
+
mode?: ChangeMode;
|
|
40
|
+
/** Restart even when nothing else changes (stop then start). */
|
|
41
|
+
restart?: boolean;
|
|
42
|
+
/** Values to scrub from every response and error. */
|
|
43
|
+
secretValues?: string[];
|
|
44
|
+
}
|
|
45
|
+
export interface RuntimeCheck {
|
|
46
|
+
checked: boolean;
|
|
47
|
+
reason?: string;
|
|
48
|
+
targetId: string;
|
|
49
|
+
current: {
|
|
50
|
+
version: string;
|
|
51
|
+
java?: string;
|
|
52
|
+
releaseChannel?: string;
|
|
53
|
+
supported?: boolean;
|
|
54
|
+
};
|
|
55
|
+
requested?: {
|
|
56
|
+
version: string;
|
|
57
|
+
java?: string;
|
|
58
|
+
releaseChannel?: string;
|
|
59
|
+
supported?: boolean;
|
|
60
|
+
};
|
|
61
|
+
suggestions?: string[];
|
|
62
|
+
}
|
|
63
|
+
export interface AppChangePlan {
|
|
64
|
+
request: AppChangeRequest;
|
|
65
|
+
existing: CH2Deployment;
|
|
66
|
+
mode: ChangeMode;
|
|
67
|
+
patch: DeploymentPatch;
|
|
68
|
+
changes: DeploymentChange[];
|
|
69
|
+
settings?: SettingsPlan;
|
|
70
|
+
runtimeCheck: RuntimeCheck;
|
|
71
|
+
steps: string[];
|
|
72
|
+
warnings: string[];
|
|
73
|
+
/** Problems that stop the change before anything is written. */
|
|
74
|
+
blockers: string[];
|
|
75
|
+
production: boolean;
|
|
76
|
+
/** Nothing would change. */
|
|
77
|
+
noop: boolean;
|
|
78
|
+
}
|
|
79
|
+
/** Build the plan: what changes, the single PATCH body, the runtime check and the steps. Nothing is written. */
|
|
80
|
+
export declare function planAppChange(client: AnypointClient, request: AppChangeRequest): Promise<AppChangePlan>;
|
|
81
|
+
/** A serializable preview of the plan. Never contains secret values. */
|
|
82
|
+
export declare function describeAppChange(plan: AppChangePlan): {
|
|
83
|
+
preserved: string;
|
|
84
|
+
production?: boolean | undefined;
|
|
85
|
+
noop?: boolean | undefined;
|
|
86
|
+
blockers?: string[] | undefined;
|
|
87
|
+
warnings?: string[] | undefined;
|
|
88
|
+
runtimeCheck: RuntimeCheck;
|
|
89
|
+
steps: string[];
|
|
90
|
+
settings?: import("../safety/deployment.js").SettingsDiff | undefined;
|
|
91
|
+
app: string;
|
|
92
|
+
environment: string;
|
|
93
|
+
mode: ChangeMode;
|
|
94
|
+
current: {
|
|
95
|
+
ref: ArtifactRef;
|
|
96
|
+
runtime: {
|
|
97
|
+
version: string;
|
|
98
|
+
releaseChannel?: string;
|
|
99
|
+
java?: string;
|
|
100
|
+
} | undefined;
|
|
101
|
+
updateStrategy: string;
|
|
102
|
+
desiredState: string;
|
|
103
|
+
phase: import("./app-state.js").AppPhase;
|
|
104
|
+
};
|
|
105
|
+
changes: DeploymentChange[];
|
|
106
|
+
};
|
|
107
|
+
export interface AppChangeResult {
|
|
108
|
+
deployment: CH2Deployment;
|
|
109
|
+
performed: string[];
|
|
110
|
+
snapshot?: PhaseSnapshot;
|
|
111
|
+
timedOut?: boolean;
|
|
112
|
+
/** The stop step ran but the start step did not; the app is left stopped. */
|
|
113
|
+
leftStopped?: boolean;
|
|
114
|
+
}
|
|
115
|
+
export interface ExecuteOptions {
|
|
116
|
+
wait?: boolean;
|
|
117
|
+
timeoutMs?: number;
|
|
118
|
+
pollIntervalMs?: number;
|
|
119
|
+
graceMs?: number;
|
|
120
|
+
onStatus?: (step: string, snapshot: PhaseSnapshot) => void;
|
|
121
|
+
}
|
|
122
|
+
/** Apply a plan. Errors and results are scrubbed of the request's secret values. */
|
|
123
|
+
export declare function executeAppChange(client: AnypointClient, plan: AppChangePlan, options?: ExecuteOptions): Promise<AppChangeResult>;
|
|
124
|
+
//# sourceMappingURL=app-change.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-change.d.ts","sourceRoot":"","sources":["../../src/workflows/app-change.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application change workflow
|
|
3
|
+
* One plan and one PATCH for every change to an existing CloudHub 2.0 application: artifact,
|
|
4
|
+
* runtime, settings and update strategy, applied in place or as stop, change, start. Shared by
|
|
5
|
+
* the MCP tools and the CLI so previews, runtime checks, secret handling and waits match.
|
|
6
|
+
*/
|
|
7
|
+
import { isEmptySettingsChange, mergeForArtifactUpdate, planSettingsChange, } from '../safety/deployment.js';
|
|
8
|
+
import { isProductionEnv } from '../safety/guards.js';
|
|
9
|
+
import { parseRuntimeString, resolveRuntime, suggestRuntimes } from '../safety/runtime.js';
|
|
10
|
+
import { looksSecret, redactText } from '../safety/secrets.js';
|
|
11
|
+
import { resolveSecretSources } from '../safety/secret-sources.js';
|
|
12
|
+
import { errorMessage } from '../utils/errors.js';
|
|
13
|
+
import { deploymentPhase, waitForAppPhase } from './app-state.js';
|
|
14
|
+
/** Resolve file and environment sources into values. Returns the secret values for output scrubbing. */
|
|
15
|
+
export function resolveSettingsInput(input, options = {}) {
|
|
16
|
+
if (!input)
|
|
17
|
+
return { change: undefined, secretValues: [] };
|
|
18
|
+
const properties = { ...resolveSecretSources(input.propertiesFrom, options), ...(input.properties ?? {}) };
|
|
19
|
+
const secureProperties = {
|
|
20
|
+
...resolveSecretSources(input.securePropertiesFrom, options),
|
|
21
|
+
...(input.secureProperties ?? {}),
|
|
22
|
+
};
|
|
23
|
+
const change = {
|
|
24
|
+
...(Object.keys(properties).length ? { properties } : {}),
|
|
25
|
+
...(Object.keys(secureProperties).length ? { secureProperties } : {}),
|
|
26
|
+
...(input.removeProperties?.length ? { removeProperties: input.removeProperties } : {}),
|
|
27
|
+
...(input.removeSecureProperties?.length ? { removeSecureProperties: input.removeSecureProperties } : {}),
|
|
28
|
+
...(input.moveToSecure?.length ? { moveToSecure: input.moveToSecure } : {}),
|
|
29
|
+
};
|
|
30
|
+
const secretValues = [
|
|
31
|
+
...Object.values(secureProperties),
|
|
32
|
+
...Object.entries(properties)
|
|
33
|
+
.filter(([key]) => looksSecret(key))
|
|
34
|
+
.map(([, value]) => value),
|
|
35
|
+
];
|
|
36
|
+
return { change: isEmptySettingsChange(change) ? undefined : change, secretValues };
|
|
37
|
+
}
|
|
38
|
+
function refsDiffer(a, b) {
|
|
39
|
+
return (a.groupId !== b.groupId ||
|
|
40
|
+
a.artifactId !== b.artifactId ||
|
|
41
|
+
a.version !== b.version ||
|
|
42
|
+
a.packaging !== b.packaging);
|
|
43
|
+
}
|
|
44
|
+
async function loadCatalog(client, orgId, targetId) {
|
|
45
|
+
try {
|
|
46
|
+
const target = await client.runtimes.getTarget(orgId, targetId);
|
|
47
|
+
if (!target)
|
|
48
|
+
return { reason: `target ${targetId} is not in the organization's runtime catalog` };
|
|
49
|
+
if (target.runtimes.length === 0)
|
|
50
|
+
return { reason: `target ${targetId} lists no runtime versions` };
|
|
51
|
+
return { catalog: target.runtimes };
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
return { reason: `runtime catalog unavailable: ${errorMessage(error)}` };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/** Pick the Java version to send: requested, else the current one if still offered, else 17, else the newest offered. */
|
|
58
|
+
function chooseJava(resolved, requested, current) {
|
|
59
|
+
if (requested)
|
|
60
|
+
return requested;
|
|
61
|
+
if (!resolved || resolved.java.length === 0)
|
|
62
|
+
return current;
|
|
63
|
+
if (current && resolved.java.includes(current))
|
|
64
|
+
return current;
|
|
65
|
+
if (resolved.java.includes('17'))
|
|
66
|
+
return '17';
|
|
67
|
+
return resolved.java[resolved.java.length - 1];
|
|
68
|
+
}
|
|
69
|
+
/** Build the plan: what changes, the single PATCH body, the runtime check and the steps. Nothing is written. */
|
|
70
|
+
export async function planAppChange(client, request) {
|
|
71
|
+
const existing = request.existing ?? (await client.cloudHub2.findDetailByName(request.orgId, request.env.id, request.appName));
|
|
72
|
+
if (!existing)
|
|
73
|
+
throw new Error(`Application "${request.appName}" not found in ${request.env.name}`);
|
|
74
|
+
const mode = request.mode ?? (request.restart ? 'stopStart' : 'inPlace');
|
|
75
|
+
const changes = [];
|
|
76
|
+
const warnings = [];
|
|
77
|
+
const blockers = [];
|
|
78
|
+
const patch = {};
|
|
79
|
+
const settings = existing.target?.deploymentSettings ?? {};
|
|
80
|
+
// Artifact
|
|
81
|
+
if (request.ref && Object.values(request.ref).some((v) => v !== undefined)) {
|
|
82
|
+
const nextRef = mergeForArtifactUpdate(existing, request.ref).application.ref;
|
|
83
|
+
if (refsDiffer(existing.application.ref, nextRef)) {
|
|
84
|
+
patch.application = { ...patch.application, ref: nextRef };
|
|
85
|
+
for (const field of ['groupId', 'artifactId', 'version', 'packaging']) {
|
|
86
|
+
if (existing.application.ref[field] !== nextRef[field]) {
|
|
87
|
+
changes.push({ field: `ref.${field}`, from: existing.application.ref[field], to: nextRef[field] });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// Settings
|
|
93
|
+
let settingsPlan;
|
|
94
|
+
if (!isEmptySettingsChange(request.settings)) {
|
|
95
|
+
settingsPlan = planSettingsChange(existing, request.settings);
|
|
96
|
+
warnings.push(...settingsPlan.warnings);
|
|
97
|
+
if (settingsPlan.changed) {
|
|
98
|
+
patch.application = {
|
|
99
|
+
...patch.application,
|
|
100
|
+
configuration: { 'mule.agent.application.properties.service': settingsPlan.service },
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Runtime
|
|
105
|
+
const currentRuntime = settings.runtime ?? { version: 'unknown' };
|
|
106
|
+
const current = parseRuntimeString(currentRuntime.version, currentRuntime.java);
|
|
107
|
+
const { catalog, reason } = await loadCatalog(client, request.orgId, existing.target.targetId);
|
|
108
|
+
const runtimeCheck = {
|
|
109
|
+
checked: Boolean(catalog),
|
|
110
|
+
...(reason ? { reason } : {}),
|
|
111
|
+
targetId: existing.target.targetId,
|
|
112
|
+
current: {
|
|
113
|
+
version: current.version,
|
|
114
|
+
...(current.java ? { java: current.java } : {}),
|
|
115
|
+
...(currentRuntime.releaseChannel ? { releaseChannel: currentRuntime.releaseChannel } : {}),
|
|
116
|
+
...(catalog
|
|
117
|
+
? { supported: Boolean(resolveRuntime(catalog, { version: current.version, java: current.java })) }
|
|
118
|
+
: {}),
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
let nextRuntime;
|
|
122
|
+
if (request.runtime) {
|
|
123
|
+
const resolved = catalog ? resolveRuntime(catalog, request.runtime) : undefined;
|
|
124
|
+
runtimeCheck.requested = {
|
|
125
|
+
version: request.runtime.version,
|
|
126
|
+
...(request.runtime.java ? { java: request.runtime.java } : {}),
|
|
127
|
+
...(request.runtime.releaseChannel ? { releaseChannel: request.runtime.releaseChannel } : {}),
|
|
128
|
+
...(catalog ? { supported: Boolean(resolved) } : {}),
|
|
129
|
+
};
|
|
130
|
+
if (catalog && !resolved) {
|
|
131
|
+
runtimeCheck.suggestions = suggestRuntimes(catalog, request.runtime.java ? request.runtime : { ...request.runtime, java: current.java });
|
|
132
|
+
blockers.push(`Runtime ${request.runtime.version}${request.runtime.java ? ` (Java ${request.runtime.java})` : ''} is not offered by ${existing.target.targetId}. Nearest supported: ${runtimeCheck.suggestions.join('; ') || 'none listed'}`);
|
|
133
|
+
}
|
|
134
|
+
nextRuntime = {
|
|
135
|
+
version: resolved?.version ?? request.runtime.version,
|
|
136
|
+
...((request.runtime.releaseChannel ?? resolved?.releaseChannel ?? currentRuntime.releaseChannel)
|
|
137
|
+
? {
|
|
138
|
+
releaseChannel: request.runtime.releaseChannel ?? resolved?.releaseChannel ?? currentRuntime.releaseChannel,
|
|
139
|
+
}
|
|
140
|
+
: {}),
|
|
141
|
+
...(chooseJava(resolved, request.runtime.java, current.java)
|
|
142
|
+
? { java: chooseJava(resolved, request.runtime.java, current.java) }
|
|
143
|
+
: {}),
|
|
144
|
+
};
|
|
145
|
+
if (!catalog)
|
|
146
|
+
warnings.push(`Runtime ${nextRuntime.version} was not validated (${reason})`);
|
|
147
|
+
if (nextRuntime.version !== current.version)
|
|
148
|
+
changes.push({ field: 'runtime', from: current.version, to: nextRuntime.version });
|
|
149
|
+
if (nextRuntime.java && nextRuntime.java !== current.java)
|
|
150
|
+
changes.push({ field: 'java', from: current.java, to: nextRuntime.java });
|
|
151
|
+
if (nextRuntime.releaseChannel && nextRuntime.releaseChannel !== currentRuntime.releaseChannel) {
|
|
152
|
+
changes.push({
|
|
153
|
+
field: 'releaseChannel',
|
|
154
|
+
from: currentRuntime.releaseChannel,
|
|
155
|
+
to: nextRuntime.releaseChannel,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
if (changes.every((c) => !['runtime', 'java', 'releaseChannel'].includes(c.field)))
|
|
159
|
+
nextRuntime = undefined;
|
|
160
|
+
}
|
|
161
|
+
// Update strategy
|
|
162
|
+
const strategyChange = request.updateStrategy && request.updateStrategy !== (settings.updateStrategy ?? 'rolling')
|
|
163
|
+
? request.updateStrategy
|
|
164
|
+
: undefined;
|
|
165
|
+
if (strategyChange)
|
|
166
|
+
changes.push({ field: 'updateStrategy', from: settings.updateStrategy ?? 'rolling', to: strategyChange });
|
|
167
|
+
if (nextRuntime || strategyChange) {
|
|
168
|
+
// The live target is restated exactly as read, so only the runtime and strategy differ.
|
|
169
|
+
patch.target = {
|
|
170
|
+
provider: existing.target.provider,
|
|
171
|
+
targetId: existing.target.targetId,
|
|
172
|
+
replicas: existing.target.replicas,
|
|
173
|
+
deploymentSettings: {
|
|
174
|
+
...settings,
|
|
175
|
+
...(nextRuntime ? { runtime: nextRuntime } : {}),
|
|
176
|
+
...(strategyChange ? { updateStrategy: strategyChange } : {}),
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
const createsSpec = Boolean(patch.application?.ref || patch.application?.configuration || patch.target);
|
|
181
|
+
if (catalog && runtimeCheck.current.supported === false && !nextRuntime && createsSpec) {
|
|
182
|
+
runtimeCheck.suggestions = suggestRuntimes(catalog, current);
|
|
183
|
+
blockers.push(`The app's current runtime ${current.version}${current.java ? ` (Java ${current.java})` : ''} is no longer offered by ${existing.target.targetId}, so the platform will reject a new spec. Pass runtime with one of: ${runtimeCheck.suggestions.join('; ') || 'none listed'}`);
|
|
184
|
+
}
|
|
185
|
+
const noop = !createsSpec && !request.restart;
|
|
186
|
+
if (mode === 'stopStart' && !noop)
|
|
187
|
+
patch.application = { ...patch.application, desiredState: 'STARTED' };
|
|
188
|
+
if (settingsPlan?.changed)
|
|
189
|
+
warnings.push('Applying a settings change restarts the application.');
|
|
190
|
+
if (mode === 'inPlace' && createsSpec && (settings.updateStrategy ?? 'rolling') === 'rolling' && !strategyChange) {
|
|
191
|
+
warnings.push('Rolling update: old and new replicas overlap briefly. For apps with streaming or polling listeners use mode stopStart, or set updateStrategy recreate.');
|
|
192
|
+
}
|
|
193
|
+
if (mode === 'inPlace' && existing.application.desiredState === 'STOPPED' && createsSpec) {
|
|
194
|
+
warnings.push('The application is stopped; the change applies but it stays stopped until started.');
|
|
195
|
+
}
|
|
196
|
+
const steps = noop
|
|
197
|
+
? []
|
|
198
|
+
: mode === 'stopStart'
|
|
199
|
+
? [
|
|
200
|
+
...(existing.application.desiredState !== 'STOPPED'
|
|
201
|
+
? ['stop the application and wait until it is stopped']
|
|
202
|
+
: []),
|
|
203
|
+
createsSpec ? 'apply the change and start in one update' : 'start the application',
|
|
204
|
+
'wait until every replica runs the new spec',
|
|
205
|
+
]
|
|
206
|
+
: ['apply the change in one update (one new spec)', 'wait until every replica runs the new spec'];
|
|
207
|
+
return {
|
|
208
|
+
request,
|
|
209
|
+
existing,
|
|
210
|
+
mode,
|
|
211
|
+
patch,
|
|
212
|
+
changes,
|
|
213
|
+
...(settingsPlan ? { settings: settingsPlan } : {}),
|
|
214
|
+
runtimeCheck,
|
|
215
|
+
steps,
|
|
216
|
+
warnings,
|
|
217
|
+
blockers,
|
|
218
|
+
production: isProductionEnv(request.env.name, request.env.isProduction),
|
|
219
|
+
noop,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
/** A serializable preview of the plan. Never contains secret values. */
|
|
223
|
+
export function describeAppChange(plan) {
|
|
224
|
+
const { existing, request } = plan;
|
|
225
|
+
const preview = {
|
|
226
|
+
app: existing.name,
|
|
227
|
+
environment: request.env.name,
|
|
228
|
+
mode: plan.mode,
|
|
229
|
+
current: {
|
|
230
|
+
ref: existing.application.ref,
|
|
231
|
+
runtime: existing.target?.deploymentSettings?.runtime,
|
|
232
|
+
updateStrategy: existing.target?.deploymentSettings?.updateStrategy ?? 'rolling',
|
|
233
|
+
desiredState: existing.application.desiredState,
|
|
234
|
+
phase: deploymentPhase(existing).phase,
|
|
235
|
+
},
|
|
236
|
+
changes: plan.changes,
|
|
237
|
+
...(plan.settings ? { settings: plan.settings.diff } : {}),
|
|
238
|
+
runtimeCheck: plan.runtimeCheck,
|
|
239
|
+
steps: plan.steps,
|
|
240
|
+
...(plan.warnings.length ? { warnings: plan.warnings } : {}),
|
|
241
|
+
...(plan.blockers.length ? { blockers: plan.blockers } : {}),
|
|
242
|
+
...(plan.noop ? { noop: true } : {}),
|
|
243
|
+
...(plan.production ? { production: true } : {}),
|
|
244
|
+
preserved: 'target, replicas, resources, other settings and stored secure values',
|
|
245
|
+
};
|
|
246
|
+
return JSON.parse(redactText(JSON.stringify(preview), request.secretValues ?? []));
|
|
247
|
+
}
|
|
248
|
+
/** Apply a plan. Errors and results are scrubbed of the request's secret values. */
|
|
249
|
+
export async function executeAppChange(client, plan, options = {}) {
|
|
250
|
+
if (plan.blockers.length)
|
|
251
|
+
throw new Error(plan.blockers.join('\n'));
|
|
252
|
+
const { orgId, env, secretValues = [] } = plan.request;
|
|
253
|
+
const { existing } = plan;
|
|
254
|
+
const performed = [];
|
|
255
|
+
if (plan.noop)
|
|
256
|
+
return { deployment: existing, performed };
|
|
257
|
+
// `previous` enables the staleness check, needed only when the target state looks like the
|
|
258
|
+
// starting state (an in-place update of a running app). Stop and start are told apart by state.
|
|
259
|
+
const waitFor = (step, previous, sentAt, expectedSpecVersion) => waitForAppPhase(client.cloudHub2, orgId, env.id, existing.id, {
|
|
260
|
+
expectedSpecVersion,
|
|
261
|
+
previousModifiedDate: previous?.lastModifiedDate,
|
|
262
|
+
sinceChange: sentAt,
|
|
263
|
+
timeoutMs: options.timeoutMs,
|
|
264
|
+
pollIntervalMs: options.pollIntervalMs,
|
|
265
|
+
graceMs: options.graceMs,
|
|
266
|
+
onStatus: options.onStatus ? (snapshot) => options.onStatus?.(step, snapshot) : undefined,
|
|
267
|
+
});
|
|
268
|
+
try {
|
|
269
|
+
let before = existing;
|
|
270
|
+
if (plan.mode === 'stopStart' && existing.application.desiredState !== 'STOPPED') {
|
|
271
|
+
const sentAt = Date.now();
|
|
272
|
+
await client.cloudHub2.setDesiredState(orgId, env.id, existing.id, 'STOPPED');
|
|
273
|
+
performed.push('stop requested');
|
|
274
|
+
const stopped = await waitFor('stop', undefined, sentAt);
|
|
275
|
+
if (!stopped.snapshot.settled) {
|
|
276
|
+
throw new Error(`Stop did not complete (${stopped.snapshot.phase}${stopped.timedOut ? ', timed out' : ''}); the change was not applied. The app may still be stopping.`);
|
|
277
|
+
}
|
|
278
|
+
performed.push('stopped');
|
|
279
|
+
before = stopped.deployment;
|
|
280
|
+
}
|
|
281
|
+
const sentAt = Date.now();
|
|
282
|
+
const deployment = await client.cloudHub2.patchDeployment(orgId, env.id, existing.id, plan.patch);
|
|
283
|
+
performed.push(plan.mode === 'stopStart' ? 'change applied and start requested' : 'change applied');
|
|
284
|
+
if (!options.wait)
|
|
285
|
+
return { deployment, performed };
|
|
286
|
+
const expected = deployment.desiredVersion && deployment.desiredVersion !== before.desiredVersion
|
|
287
|
+
? deployment.desiredVersion
|
|
288
|
+
: undefined;
|
|
289
|
+
const wasRunning = before.application.desiredState !== 'STOPPED';
|
|
290
|
+
const result = await waitFor('apply', wasRunning ? before : undefined, sentAt, expected);
|
|
291
|
+
performed.push(result.snapshot.settled ? 'settled' : `wait ended in ${result.snapshot.phase}`);
|
|
292
|
+
return { deployment: result.deployment, performed, snapshot: result.snapshot, timedOut: result.timedOut };
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
const leftStopped = performed.includes('stopped') && !performed.some((step) => step.startsWith('change applied'));
|
|
296
|
+
const message = redactText(errorMessage(error), secretValues);
|
|
297
|
+
const err = new Error(leftStopped
|
|
298
|
+
? `${message}\nThe application was stopped and is still stopped. Steps done: ${performed.join(', ')}`
|
|
299
|
+
: performed.length
|
|
300
|
+
? `${message}\nSteps done: ${performed.join(', ')}`
|
|
301
|
+
: message);
|
|
302
|
+
throw err;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
//# sourceMappingURL=app-change.js.map
|