@pulumix/core 0.8.0 → 0.10.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/dist/dev/env-compute.d.ts +15 -0
- package/dist/dev/env-compute.d.ts.map +1 -0
- package/dist/dev/env-compute.js +92 -0
- package/dist/dev/env-compute.js.map +1 -0
- package/dist/dev/index.d.ts +1 -9
- package/dist/dev/index.d.ts.map +1 -1
- package/dist/dev/index.js +91 -211
- package/dist/dev/index.js.map +1 -1
- package/dist/dev/local-runner.d.ts.map +1 -1
- package/dist/dev/local-runner.js +0 -1
- package/dist/dev/local-runner.js.map +1 -1
- package/dist/dev/port-forward.d.ts +1 -1
- package/dist/dev/port-forward.d.ts.map +1 -1
- package/dist/dev/port-forward.js +43 -28
- package/dist/dev/port-forward.js.map +1 -1
- package/dist/dev/types.d.ts +4 -22
- package/dist/dev/types.d.ts.map +1 -1
- package/dist/dev/types.js +1 -24
- package/dist/dev/types.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/k8s/client.d.ts +8 -0
- package/dist/k8s/client.d.ts.map +1 -0
- package/dist/k8s/client.js +48 -0
- package/dist/k8s/client.js.map +1 -0
- package/dist/k8s/index.d.ts +5 -0
- package/dist/k8s/index.d.ts.map +1 -0
- package/dist/k8s/index.js +12 -0
- package/dist/k8s/index.js.map +1 -0
- package/dist/k8s/inspect.d.ts +40 -0
- package/dist/k8s/inspect.d.ts.map +1 -0
- package/dist/k8s/inspect.js +133 -0
- package/dist/k8s/inspect.js.map +1 -0
- package/dist/orchestrator/events.d.ts +1 -1
- package/dist/orchestrator/events.d.ts.map +1 -1
- package/dist/orchestrator/events.js +3 -2
- package/dist/orchestrator/events.js.map +1 -1
- package/dist/orchestrator/index.d.ts +10 -0
- package/dist/orchestrator/index.d.ts.map +1 -1
- package/dist/orchestrator/index.js +247 -165
- package/dist/orchestrator/index.js.map +1 -1
- package/dist/types/events.d.ts +1 -0
- package/dist/types/events.d.ts.map +1 -1
- package/dist/types/events.js.map +1 -1
- package/package.json +3 -2
|
@@ -16,6 +16,12 @@ export interface OrchestratorResult {
|
|
|
16
16
|
readonly duration: number;
|
|
17
17
|
readonly outputs: Record<string, Record<string, unknown>>;
|
|
18
18
|
}
|
|
19
|
+
export interface PreviewResult {
|
|
20
|
+
readonly success: boolean;
|
|
21
|
+
readonly stack: string;
|
|
22
|
+
readonly changeSummary: Record<string, number>;
|
|
23
|
+
readonly duration: number;
|
|
24
|
+
}
|
|
19
25
|
export declare const discoverServices: (rootPath: string) => Promise<Either<DeployError, readonly DiscoveredService[]>>;
|
|
20
26
|
export declare const discoverPublishedServices: (rootPath: string, allowlist: string[]) => Promise<Either<DeployError, readonly DiscoveredService[]>>;
|
|
21
27
|
export declare const sortByDependencies: (services: readonly DiscoveredService[]) => readonly DiscoveredService[];
|
|
@@ -25,7 +31,11 @@ export declare class Orchestrator {
|
|
|
25
31
|
constructor(eventEmitter?: OrchestratorEventEmitter);
|
|
26
32
|
getEventEmitter(): OrchestratorEventEmitter;
|
|
27
33
|
private validateEnvironment;
|
|
34
|
+
private prepareDeployment;
|
|
28
35
|
deploy(config: OrchestratorConfig): EitherAsync<DeployError, OrchestratorResult>;
|
|
36
|
+
preview(config: OrchestratorConfig): EitherAsync<DeployError, PreviewResult>;
|
|
37
|
+
status(config: OrchestratorConfig): EitherAsync<DeployError, OrchestratorResult>;
|
|
38
|
+
refresh(config: OrchestratorConfig): EitherAsync<DeployError, OrchestratorResult>;
|
|
29
39
|
destroy(config: OrchestratorConfig): EitherAsync<DeployError, OrchestratorResult>;
|
|
30
40
|
}
|
|
31
41
|
export declare const createOrchestrator: (eventEmitter?: OrchestratorEventEmitter) => Orchestrator;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/orchestrator/index.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACnD,OAAO,EAAE,MAAM,EAAe,MAAM,kBAAkB,CAAA;AAItD,OAAO,EAGL,WAAW,EACZ,MAAM,iBAAiB,CAAA;AAGxB,OAAO,EAAE,wBAAwB,EAAsB,MAAM,UAAU,CAAA;AACvE,OAAO,EACL,iBAAiB,EACjB,eAAe,EAGhB,MAAM,kBAAkB,CAAA;AAgCzB,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAE7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CAC9C;AAKD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;CAC1D;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/orchestrator/index.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACnD,OAAO,EAAE,MAAM,EAAe,MAAM,kBAAkB,CAAA;AAItD,OAAO,EAGL,WAAW,EACZ,MAAM,iBAAiB,CAAA;AAGxB,OAAO,EAAE,wBAAwB,EAAsB,MAAM,UAAU,CAAA;AACvE,OAAO,EACL,iBAAiB,EACjB,eAAe,EAGhB,MAAM,kBAAkB,CAAA;AAgCzB,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAE7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CAC9C;AAKD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;CAC1D;AAKD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B;AAoND,eAAO,MAAM,gBAAgB,GAAU,UAAU,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,iBAAiB,EAAE,CAAC,CAqGlH,CAAA;AAqBD,eAAO,MAAM,yBAAyB,GACpC,UAAU,MAAM,EAChB,WAAW,MAAM,EAAE,KAClB,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,iBAAiB,EAAE,CAAC,CAwH3D,CAAA;AAKD,eAAO,MAAM,kBAAkB,GAC7B,UAAU,SAAS,iBAAiB,EAAE,KACrC,SAAS,iBAAiB,EAwB5B,CAAA;AAKD,eAAO,MAAM,kBAAkB,GAC7B,SAAS,iBAAiB,EAC1B,WAAW,MAAM,KAChB,eAUF,CAAA;AAmKD,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA0B;gBAE3C,YAAY,CAAC,EAAE,wBAAwB;IAInD,eAAe,IAAI,wBAAwB;IAO3C,OAAO,CAAC,mBAAmB;YAyBb,iBAAiB;IAoQ/B,MAAM,CAAC,MAAM,EAAE,kBAAkB,GAAG,WAAW,CAAC,WAAW,EAAE,kBAAkB,CAAC;IAqFhF,OAAO,CAAC,MAAM,EAAE,kBAAkB,GAAG,WAAW,CAAC,WAAW,EAAE,aAAa,CAAC;IAyC5E,MAAM,CAAC,MAAM,EAAE,kBAAkB,GAAG,WAAW,CAAC,WAAW,EAAE,kBAAkB,CAAC;IAkChF,OAAO,CAAC,MAAM,EAAE,kBAAkB,GAAG,WAAW,CAAC,WAAW,EAAE,kBAAkB,CAAC;IA2CjF,OAAO,CAAC,MAAM,EAAE,kBAAkB,GAAG,WAAW,CAAC,WAAW,EAAE,kBAAkB,CAAC;CAyDlF;AAKD,eAAO,MAAM,kBAAkB,GAAI,eAAe,wBAAwB,KAAG,YAC7C,CAAA"}
|
|
@@ -65,9 +65,10 @@ const resolveBackendUrl = (rootPath, projectConfig, stackName) => {
|
|
|
65
65
|
switch (backend.type) {
|
|
66
66
|
case 'file': {
|
|
67
67
|
const backendPath = backend.path ?? 'dist/';
|
|
68
|
-
const
|
|
68
|
+
const base = path.isAbsolute(backendPath)
|
|
69
69
|
? backendPath
|
|
70
70
|
: path.join(rootPath, backendPath);
|
|
71
|
+
const absolutePath = path.join(base, stackName);
|
|
71
72
|
return `file://${absolutePath}`;
|
|
72
73
|
}
|
|
73
74
|
case 's3': {
|
|
@@ -90,7 +91,7 @@ const resolveBackendUrl = (rootPath, projectConfig, stackName) => {
|
|
|
90
91
|
return 'https://app.pulumi.com';
|
|
91
92
|
}
|
|
92
93
|
default: {
|
|
93
|
-
const defaultPath = path.join(rootPath, 'dist/');
|
|
94
|
+
const defaultPath = path.join(rootPath, 'dist/', stackName);
|
|
94
95
|
return `file://${defaultPath}`;
|
|
95
96
|
}
|
|
96
97
|
}
|
|
@@ -100,11 +101,12 @@ const resolveWorkDir = (rootPath, projectConfig, stackName) => {
|
|
|
100
101
|
const backend = stackConfig?.backend ?? projectConfig.backend ?? DEFAULT_BACKEND;
|
|
101
102
|
if (backend.type === 'file') {
|
|
102
103
|
const backendPath = backend.path ?? 'dist/';
|
|
103
|
-
|
|
104
|
+
const base = path.isAbsolute(backendPath)
|
|
104
105
|
? backendPath
|
|
105
106
|
: path.join(rootPath, backendPath);
|
|
107
|
+
return path.join(base, stackName);
|
|
106
108
|
}
|
|
107
|
-
return path.join(rootPath, 'dist/');
|
|
109
|
+
return path.join(rootPath, 'dist/', stackName);
|
|
108
110
|
};
|
|
109
111
|
const parseYamlFile = (filePath) => {
|
|
110
112
|
try {
|
|
@@ -444,148 +446,187 @@ class Orchestrator {
|
|
|
444
446
|
}
|
|
445
447
|
return (0, Either_1.Right)(undefined);
|
|
446
448
|
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
];
|
|
467
|
-
const
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
449
|
+
async prepareDeployment(config, liftEither, throwE) {
|
|
450
|
+
this.eventEmitter.emitPhaseStart('configuration');
|
|
451
|
+
const rootConfigPath = path.join(config.rootPath, 'pulumix.yaml');
|
|
452
|
+
const rawConfig = await liftEither(parseYamlFile(rootConfigPath));
|
|
453
|
+
const rootConfig = await liftEither((0, project_1.validateProjectConfig)(rawConfig, rootConfigPath));
|
|
454
|
+
const stacks = rootConfig.stacks ?? {};
|
|
455
|
+
const globalConfig = stacks[config.stackName] ?? {};
|
|
456
|
+
this.eventEmitter.emitPhaseComplete('configuration');
|
|
457
|
+
this.eventEmitter.emitPhaseStart('discovery');
|
|
458
|
+
const localServices = await liftEither(await (0, exports.discoverServices)(config.rootPath));
|
|
459
|
+
const allowlist = rootConfig.services?.allowed ?? [];
|
|
460
|
+
const publishedServices = await liftEither(await (0, exports.discoverPublishedServices)(config.rootPath, allowlist));
|
|
461
|
+
const localServiceNames = new Set(localServices.map(s => s.name));
|
|
462
|
+
const mergedServices = [
|
|
463
|
+
...localServices,
|
|
464
|
+
...publishedServices.filter(s => !localServiceNames.has(s.name))
|
|
465
|
+
];
|
|
466
|
+
const services = filterServices(mergedServices, config.servicesToDeploy);
|
|
467
|
+
for (let i = 0; i < services.length; i++) {
|
|
468
|
+
const service = services[i];
|
|
469
|
+
const isLast = i === services.length - 1;
|
|
470
|
+
const prefix = isLast ? '└─' : '├─';
|
|
471
|
+
const source = localServiceNames.has(service.name) ? 'local' : 'published';
|
|
472
|
+
this.eventEmitter.emitLog('info', `${prefix} ${service.name} (${source})`, undefined, 'Discovery');
|
|
473
|
+
}
|
|
474
|
+
this.eventEmitter.emitPhaseComplete('discovery');
|
|
475
|
+
this.eventEmitter.emitPhaseStart('dependency-analysis');
|
|
476
|
+
const sorted = (0, exports.sortByDependencies)(services);
|
|
477
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
478
|
+
const service = sorted[i];
|
|
479
|
+
const isLast = i === sorted.length - 1;
|
|
480
|
+
const prefix = isLast ? '└─' : '├─';
|
|
481
|
+
const deps = service.dependencies.length > 0
|
|
482
|
+
? ` (requires: ${service.dependencies.join(', ')})`
|
|
483
|
+
: '';
|
|
484
|
+
this.eventEmitter.emitLog('info', `${prefix} ${service.name}${deps}`, undefined, 'DependencyGraph');
|
|
485
|
+
}
|
|
486
|
+
this.eventEmitter.emitPhaseComplete('dependency-analysis');
|
|
487
|
+
const hostRegistry = getConfigValue(globalConfig, 'hostRegistry').orDefault('localhost:5001');
|
|
488
|
+
const clusterRegistry = getConfigValue(globalConfig, 'clusterRegistry').orDefault(hostRegistry);
|
|
489
|
+
const platformConfig = getConfigValue(globalConfig, 'platform').extract();
|
|
490
|
+
const platforms = platformConfig
|
|
491
|
+
? (Array.isArray(platformConfig) ? platformConfig : [platformConfig])
|
|
492
|
+
: undefined;
|
|
493
|
+
const hooks = (0, hooks_1.getHooksForStack)(rootConfig.hooks, config.stackName);
|
|
494
|
+
const servicesToBuild = sorted.filter(s => s.hasDockerfile);
|
|
495
|
+
const preBuildHooks = hooks.filter(h => h.stage === 'pre-build');
|
|
496
|
+
if (preBuildHooks.length > 0) {
|
|
497
|
+
this.eventEmitter.emitPhaseStart('bootstrap');
|
|
498
|
+
const hookResult = await (0, hooks_1.executeHooksForStage)('pre-build', hooks, config.rootPath, this.eventEmitter);
|
|
499
|
+
if (hookResult.isLeft()) {
|
|
500
|
+
this.eventEmitter.emitPhaseComplete('bootstrap', false);
|
|
501
|
+
throw throwE(hookResult.extract());
|
|
474
502
|
}
|
|
475
|
-
this.eventEmitter.emitPhaseComplete('
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
this.eventEmitter.
|
|
503
|
+
this.eventEmitter.emitPhaseComplete('bootstrap');
|
|
504
|
+
}
|
|
505
|
+
const builtImages = {};
|
|
506
|
+
if (servicesToBuild.length > 0) {
|
|
507
|
+
this.eventEmitter.emitPhaseStart('image-build');
|
|
508
|
+
const preparedBuilds = await Promise.all(servicesToBuild.map(service => prepareBuild(service, hostRegistry, config.rootPath)));
|
|
509
|
+
const cachedBuilds = preparedBuilds.filter(b => b.cached);
|
|
510
|
+
const uncachedBuilds = preparedBuilds.filter(b => !b.cached);
|
|
511
|
+
for (const build of cachedBuilds) {
|
|
512
|
+
this.eventEmitter.emitTaskStart(build.service.name, build.service.name, 'image-build', build.contentHash);
|
|
513
|
+
this.eventEmitter.emitTaskUpdate(build.service.name, `unchanged (${build.contentHash})`);
|
|
514
|
+
const imageWithoutRegistry = (build.imageRef || build.imageTag).replace(`${hostRegistry}/`, '');
|
|
515
|
+
builtImages[build.service.name] = `${clusterRegistry}/${imageWithoutRegistry}`;
|
|
516
|
+
this.eventEmitter.emitTaskComplete(build.service.name, true, true, build.contentHash);
|
|
486
517
|
}
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
const platforms = platformConfig
|
|
492
|
-
? (Array.isArray(platformConfig) ? platformConfig : [platformConfig])
|
|
493
|
-
: undefined;
|
|
494
|
-
const hooks = (0, hooks_1.getHooksForStack)(rootConfig.hooks, config.stackName);
|
|
495
|
-
const servicesToBuild = sorted.filter(s => s.hasDockerfile);
|
|
496
|
-
const preBuildHooks = hooks.filter(h => h.stage === 'pre-build');
|
|
497
|
-
if (preBuildHooks.length > 0) {
|
|
498
|
-
this.eventEmitter.emitPhaseStart('bootstrap');
|
|
499
|
-
const hookResult = await (0, hooks_1.executeHooksForStage)('pre-build', hooks, config.rootPath, this.eventEmitter);
|
|
500
|
-
if (hookResult.isLeft()) {
|
|
501
|
-
this.eventEmitter.emitPhaseComplete('bootstrap', false);
|
|
502
|
-
throw throwE(hookResult.extract());
|
|
518
|
+
if (uncachedBuilds.length > 0) {
|
|
519
|
+
for (const build of uncachedBuilds) {
|
|
520
|
+
this.eventEmitter.emitTaskStart(build.service.name, build.service.name, 'image-build', build.contentHash);
|
|
521
|
+
this.eventEmitter.emitTaskUpdate(build.service.name, 'building');
|
|
503
522
|
}
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
builtImages[build.service.name] = `${clusterRegistry}/${imageWithoutRegistry}`;
|
|
517
|
-
this.eventEmitter.emitTaskComplete(build.service.name, true, true, build.contentHash);
|
|
523
|
+
const bakeServices = uncachedBuilds.map(build => ({
|
|
524
|
+
name: build.service.name,
|
|
525
|
+
contextPath: build.contextPath,
|
|
526
|
+
dockerfile: build.dockerfile,
|
|
527
|
+
tag: build.imageTag,
|
|
528
|
+
contentHash: build.contentHash,
|
|
529
|
+
platforms,
|
|
530
|
+
}));
|
|
531
|
+
const bakeConfig = (0, docker_1.generateBakeConfig)(bakeServices);
|
|
532
|
+
const bakeFilePath = path.join(config.rootPath, 'dist', 'docker-bake.json');
|
|
533
|
+
if (!fs.existsSync(path.dirname(bakeFilePath))) {
|
|
534
|
+
fs.mkdirSync(path.dirname(bakeFilePath), { recursive: true });
|
|
518
535
|
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
536
|
+
fs.writeFileSync(bakeFilePath, JSON.stringify(bakeConfig, null, 2));
|
|
537
|
+
const lastStepShown = new Map();
|
|
538
|
+
const completedTargets = new Set();
|
|
539
|
+
const buildHashMap = new Map(uncachedBuilds.map(b => [b.service.name, b.contentHash]));
|
|
540
|
+
const bakeResult = await (0, docker_1.runBake)(bakeFilePath, bakeServices, (progress) => {
|
|
541
|
+
if (!progress.target || progress.target.startsWith('_'))
|
|
542
|
+
return;
|
|
543
|
+
const isExportStep = progress.message.includes('exporting');
|
|
544
|
+
if (progress.done && isExportStep) {
|
|
545
|
+
completedTargets.add(progress.target);
|
|
546
|
+
const contentHash = buildHashMap.get(progress.target);
|
|
547
|
+
this.eventEmitter.emitTaskComplete(progress.target, !progress.error, false, contentHash);
|
|
548
|
+
return;
|
|
523
549
|
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
dockerfile: build.dockerfile,
|
|
528
|
-
tag: build.imageTag,
|
|
529
|
-
contentHash: build.contentHash,
|
|
530
|
-
platforms,
|
|
531
|
-
}));
|
|
532
|
-
const bakeConfig = (0, docker_1.generateBakeConfig)(bakeServices);
|
|
533
|
-
const bakeFilePath = path.join(config.rootPath, 'dist', 'docker-bake.json');
|
|
534
|
-
if (!fs.existsSync(path.dirname(bakeFilePath))) {
|
|
535
|
-
fs.mkdirSync(path.dirname(bakeFilePath), { recursive: true });
|
|
550
|
+
let message = progress.message;
|
|
551
|
+
if (progress.step) {
|
|
552
|
+
message = `[${progress.step.current}/${progress.step.total}] ${progress.message}`;
|
|
536
553
|
}
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
completedTargets.add(progress.target);
|
|
546
|
-
this.eventEmitter.emitTaskComplete(progress.target, !progress.error);
|
|
547
|
-
return;
|
|
548
|
-
}
|
|
549
|
-
let message = progress.message;
|
|
550
|
-
if (progress.step) {
|
|
551
|
-
message = `[${progress.step.current}/${progress.step.total}] ${progress.message}`;
|
|
552
|
-
}
|
|
553
|
-
const lastShown = lastStepShown.get(progress.target);
|
|
554
|
-
if (lastShown === message)
|
|
555
|
-
return;
|
|
556
|
-
lastStepShown.set(progress.target, message);
|
|
557
|
-
this.eventEmitter.emitTaskUpdate(progress.target, message);
|
|
558
|
-
});
|
|
559
|
-
if (bakeResult.isLeft()) {
|
|
560
|
-
const error = bakeResult.extract();
|
|
561
|
-
for (const build of uncachedBuilds) {
|
|
562
|
-
if (!completedTargets.has(build.service.name)) {
|
|
563
|
-
this.eventEmitter.emitTaskComplete(build.service.name, false);
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
this.eventEmitter.emitLog('error', error.message, undefined, 'Build');
|
|
567
|
-
this.eventEmitter.emitPhaseComplete('image-build', false);
|
|
568
|
-
throw error;
|
|
569
|
-
}
|
|
570
|
-
const imageRefs = bakeResult.unsafeCoerce();
|
|
554
|
+
const lastShown = lastStepShown.get(progress.target);
|
|
555
|
+
if (lastShown === message)
|
|
556
|
+
return;
|
|
557
|
+
lastStepShown.set(progress.target, message);
|
|
558
|
+
this.eventEmitter.emitTaskUpdate(progress.target, message);
|
|
559
|
+
});
|
|
560
|
+
if (bakeResult.isLeft()) {
|
|
561
|
+
const error = bakeResult.extract();
|
|
571
562
|
for (const build of uncachedBuilds) {
|
|
572
|
-
const imageRef = imageRefs.get(build.service.name) || build.imageTag;
|
|
573
|
-
const imageWithoutRegistry = imageRef.replace(`${hostRegistry}/`, '');
|
|
574
|
-
builtImages[build.service.name] = `${clusterRegistry}/${imageWithoutRegistry}`;
|
|
575
563
|
if (!completedTargets.has(build.service.name)) {
|
|
576
|
-
this.eventEmitter.emitTaskComplete(build.service.name,
|
|
564
|
+
this.eventEmitter.emitTaskComplete(build.service.name, false, false, build.contentHash);
|
|
577
565
|
}
|
|
578
566
|
}
|
|
567
|
+
this.eventEmitter.emitLog('error', error.message, undefined, 'Build');
|
|
568
|
+
this.eventEmitter.emitPhaseComplete('image-build', false);
|
|
569
|
+
throw error;
|
|
570
|
+
}
|
|
571
|
+
const imageRefs = bakeResult.unsafeCoerce();
|
|
572
|
+
for (const build of uncachedBuilds) {
|
|
573
|
+
const imageRef = imageRefs.get(build.service.name) || build.imageTag;
|
|
574
|
+
const imageWithoutRegistry = imageRef.replace(`${hostRegistry}/`, '');
|
|
575
|
+
builtImages[build.service.name] = `${clusterRegistry}/${imageWithoutRegistry}`;
|
|
576
|
+
if (!completedTargets.has(build.service.name)) {
|
|
577
|
+
this.eventEmitter.emitTaskComplete(build.service.name, true, false, build.contentHash);
|
|
578
|
+
}
|
|
579
579
|
}
|
|
580
|
-
this.eventEmitter.emitPhaseComplete('image-build');
|
|
581
580
|
}
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
581
|
+
this.eventEmitter.emitPhaseComplete('image-build');
|
|
582
|
+
}
|
|
583
|
+
const postBuildHooks = hooks.filter(h => h.stage === 'post-build');
|
|
584
|
+
if (postBuildHooks.length > 0) {
|
|
585
|
+
const hookResult = await (0, hooks_1.executeHooksForStage)('post-build', hooks, config.rootPath, this.eventEmitter);
|
|
586
|
+
if (hookResult.isLeft()) {
|
|
587
|
+
throw throwE(hookResult.extract());
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
const backendUrl = resolveBackendUrl(config.rootPath, rootConfig, config.stackName);
|
|
591
|
+
const workDir = resolveWorkDir(config.rootPath, rootConfig, config.stackName);
|
|
592
|
+
if (!fs.existsSync(workDir)) {
|
|
593
|
+
fs.mkdirSync(workDir, { recursive: true });
|
|
594
|
+
}
|
|
595
|
+
const projectName = rootConfig.name ?? 'pulumix-project';
|
|
596
|
+
const outputs = {};
|
|
597
|
+
const program = async () => {
|
|
598
|
+
for (const service of sorted) {
|
|
599
|
+
const resolved = (0, exports.resolveStackConfig)(service, config.stackName);
|
|
600
|
+
const ctx = {
|
|
601
|
+
stackName: config.stackName,
|
|
602
|
+
serviceName: service.name,
|
|
603
|
+
metadata: service.metadata,
|
|
604
|
+
observability: service.observability,
|
|
605
|
+
security: service.security,
|
|
606
|
+
config: resolved.stackConfig,
|
|
607
|
+
globalConfig,
|
|
608
|
+
dependencies: outputs,
|
|
609
|
+
image: builtImages[service.name]
|
|
610
|
+
};
|
|
611
|
+
const deployFnResult = await loadDeployFunction(service);
|
|
612
|
+
if (deployFnResult.isLeft()) {
|
|
613
|
+
throw deployFnResult.extract();
|
|
614
|
+
}
|
|
615
|
+
const deployFn = deployFnResult.unsafeCoerce();
|
|
616
|
+
const result = await deployFn(ctx);
|
|
617
|
+
if (result?.outputs) {
|
|
618
|
+
outputs[service.name] = result.outputs;
|
|
587
619
|
}
|
|
588
620
|
}
|
|
621
|
+
return outputs;
|
|
622
|
+
};
|
|
623
|
+
return { sorted, builtImages, globalConfig, rootConfig, hooks, backendUrl, workDir, projectName, program, outputs };
|
|
624
|
+
}
|
|
625
|
+
deploy(config) {
|
|
626
|
+
const startTime = Date.now();
|
|
627
|
+
return (0, EitherAsync_1.EitherAsync)(async ({ liftEither, throwE }) => {
|
|
628
|
+
await liftEither(this.validateEnvironment(config.stackName));
|
|
629
|
+
const { sorted, hooks, backendUrl, workDir, projectName, program, outputs } = await this.prepareDeployment(config, liftEither, throwE);
|
|
589
630
|
const preDeployHooks = hooks.filter(h => h.stage === 'pre-deploy');
|
|
590
631
|
if (preDeployHooks.length > 0) {
|
|
591
632
|
const hookResult = await (0, hooks_1.executeHooksForStage)('pre-deploy', hooks, config.rootPath, this.eventEmitter);
|
|
@@ -594,39 +635,6 @@ class Orchestrator {
|
|
|
594
635
|
}
|
|
595
636
|
}
|
|
596
637
|
this.eventEmitter.emitPhaseStart('deployment');
|
|
597
|
-
const outputs = {};
|
|
598
|
-
const program = async () => {
|
|
599
|
-
for (const service of sorted) {
|
|
600
|
-
const resolved = (0, exports.resolveStackConfig)(service, config.stackName);
|
|
601
|
-
const ctx = {
|
|
602
|
-
stackName: config.stackName,
|
|
603
|
-
serviceName: service.name,
|
|
604
|
-
metadata: service.metadata,
|
|
605
|
-
observability: service.observability,
|
|
606
|
-
security: service.security,
|
|
607
|
-
config: resolved.stackConfig,
|
|
608
|
-
globalConfig,
|
|
609
|
-
dependencies: outputs,
|
|
610
|
-
image: builtImages[service.name]
|
|
611
|
-
};
|
|
612
|
-
const deployFnResult = await loadDeployFunction(service);
|
|
613
|
-
if (deployFnResult.isLeft()) {
|
|
614
|
-
throw deployFnResult.extract();
|
|
615
|
-
}
|
|
616
|
-
const deployFn = deployFnResult.unsafeCoerce();
|
|
617
|
-
const result = await deployFn(ctx);
|
|
618
|
-
if (result?.outputs) {
|
|
619
|
-
outputs[service.name] = result.outputs;
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
return outputs;
|
|
623
|
-
};
|
|
624
|
-
const backendUrl = resolveBackendUrl(config.rootPath, rootConfig, config.stackName);
|
|
625
|
-
const workDir = resolveWorkDir(config.rootPath, rootConfig, config.stackName);
|
|
626
|
-
if (!fs.existsSync(workDir)) {
|
|
627
|
-
fs.mkdirSync(workDir, { recursive: true });
|
|
628
|
-
}
|
|
629
|
-
const projectName = rootConfig.name ?? 'pulumix-project';
|
|
630
638
|
const stack = await automation_1.LocalWorkspace.createOrSelectStack({
|
|
631
639
|
stackName: config.stackName,
|
|
632
640
|
projectName,
|
|
@@ -671,6 +679,77 @@ class Orchestrator {
|
|
|
671
679
|
};
|
|
672
680
|
});
|
|
673
681
|
}
|
|
682
|
+
preview(config) {
|
|
683
|
+
const startTime = Date.now();
|
|
684
|
+
return (0, EitherAsync_1.EitherAsync)(async ({ liftEither, throwE }) => {
|
|
685
|
+
await liftEither(this.validateEnvironment(config.stackName));
|
|
686
|
+
const { backendUrl, workDir, projectName, program } = await this.prepareDeployment(config, liftEither, throwE);
|
|
687
|
+
this.eventEmitter.emitPhaseStart('deployment');
|
|
688
|
+
const stack = await automation_1.LocalWorkspace.createOrSelectStack({ stackName: config.stackName, projectName, program }, { workDir, projectSettings: { name: projectName, runtime: 'nodejs', backend: { url: backendUrl } } });
|
|
689
|
+
try {
|
|
690
|
+
const previewResult = await stack.preview({
|
|
691
|
+
onOutput: config.onOutput || ((msg) => this.eventEmitter.emitLog('info', msg, undefined, 'Deploy')),
|
|
692
|
+
});
|
|
693
|
+
this.eventEmitter.emitPhaseComplete('deployment');
|
|
694
|
+
return {
|
|
695
|
+
success: true,
|
|
696
|
+
stack: config.stackName,
|
|
697
|
+
changeSummary: previewResult.changeSummary ?? {},
|
|
698
|
+
duration: Date.now() - startTime
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
catch (err) {
|
|
702
|
+
this.eventEmitter.emitPhaseComplete('deployment', false);
|
|
703
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
704
|
+
throw new Error(`Pulumi preview failed: ${message}`);
|
|
705
|
+
}
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
status(config) {
|
|
709
|
+
return (0, EitherAsync_1.EitherAsync)(async ({ liftEither }) => {
|
|
710
|
+
await liftEither(this.validateEnvironment(config.stackName));
|
|
711
|
+
const rootConfigPath = path.join(config.rootPath, 'pulumix.yaml');
|
|
712
|
+
const rawConfig = await liftEither(parseYamlFile(rootConfigPath));
|
|
713
|
+
const rootConfig = await liftEither((0, project_1.validateProjectConfig)(rawConfig, rootConfigPath));
|
|
714
|
+
const backendUrl = resolveBackendUrl(config.rootPath, rootConfig, config.stackName);
|
|
715
|
+
const workDir = resolveWorkDir(config.rootPath, rootConfig, config.stackName);
|
|
716
|
+
if (!fs.existsSync(workDir)) {
|
|
717
|
+
fs.mkdirSync(workDir, { recursive: true });
|
|
718
|
+
}
|
|
719
|
+
const projectName = rootConfig.name ?? 'pulumix-project';
|
|
720
|
+
const stack = await automation_1.LocalWorkspace.createOrSelectStack({ stackName: config.stackName, projectName, program: async () => { } }, { workDir, projectSettings: { name: projectName, runtime: 'nodejs', backend: { url: backendUrl } } });
|
|
721
|
+
const stackOutputs = await stack.outputs();
|
|
722
|
+
const outputs = Object.fromEntries(Object.entries(stackOutputs).map(([k, v]) => [k, v.value]));
|
|
723
|
+
return { success: true, stack: config.stackName, servicesDeployed: 0, duration: 0, outputs };
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
refresh(config) {
|
|
727
|
+
const startTime = Date.now();
|
|
728
|
+
return (0, EitherAsync_1.EitherAsync)(async ({ liftEither }) => {
|
|
729
|
+
await liftEither(this.validateEnvironment(config.stackName));
|
|
730
|
+
const rootConfigPath = path.join(config.rootPath, 'pulumix.yaml');
|
|
731
|
+
const rawConfig = await liftEither(parseYamlFile(rootConfigPath));
|
|
732
|
+
const rootConfig = await liftEither((0, project_1.validateProjectConfig)(rawConfig, rootConfigPath));
|
|
733
|
+
const backendUrl = resolveBackendUrl(config.rootPath, rootConfig, config.stackName);
|
|
734
|
+
const workDir = resolveWorkDir(config.rootPath, rootConfig, config.stackName);
|
|
735
|
+
if (!fs.existsSync(workDir)) {
|
|
736
|
+
fs.mkdirSync(workDir, { recursive: true });
|
|
737
|
+
}
|
|
738
|
+
const projectName = rootConfig.name ?? 'pulumix-project';
|
|
739
|
+
const program = async () => { };
|
|
740
|
+
const stack = await automation_1.LocalWorkspace.createOrSelectStack({ stackName: config.stackName, projectName, program }, { workDir, projectSettings: { name: projectName, runtime: 'nodejs', backend: { url: backendUrl } } });
|
|
741
|
+
await stack.refresh({
|
|
742
|
+
onOutput: config.onOutput || ((msg) => this.eventEmitter.emitLog('info', msg, undefined, 'Deploy')),
|
|
743
|
+
});
|
|
744
|
+
return {
|
|
745
|
+
success: true,
|
|
746
|
+
stack: config.stackName,
|
|
747
|
+
servicesDeployed: 0,
|
|
748
|
+
duration: Date.now() - startTime,
|
|
749
|
+
outputs: {}
|
|
750
|
+
};
|
|
751
|
+
});
|
|
752
|
+
}
|
|
674
753
|
destroy(config) {
|
|
675
754
|
const startTime = Date.now();
|
|
676
755
|
return (0, EitherAsync_1.EitherAsync)(async ({ liftEither }) => {
|
|
@@ -680,6 +759,9 @@ class Orchestrator {
|
|
|
680
759
|
const rootConfig = await liftEither((0, project_1.validateProjectConfig)(rawConfig, rootConfigPath));
|
|
681
760
|
const backendUrl = resolveBackendUrl(config.rootPath, rootConfig, config.stackName);
|
|
682
761
|
const workDir = resolveWorkDir(config.rootPath, rootConfig, config.stackName);
|
|
762
|
+
if (!fs.existsSync(workDir)) {
|
|
763
|
+
fs.mkdirSync(workDir, { recursive: true });
|
|
764
|
+
}
|
|
683
765
|
const projectName = rootConfig.name ?? 'pulumix-project';
|
|
684
766
|
const program = async () => {
|
|
685
767
|
};
|