From 94db24ac83cbf7639df1ddce3997f4a7fdbcc97d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93lafur=20Torfi=20Yngvason?= Date: Wed, 11 Dec 2024 16:16:15 +0000 Subject: [PATCH 1/4] await shepherd deployer --- packages/deployer/src/shepherd.ts | 167 +++++++++--------- ...eate-upstream-trigger-deployment-config.ts | 6 +- 2 files changed, 85 insertions(+), 88 deletions(-) diff --git a/packages/deployer/src/shepherd.ts b/packages/deployer/src/shepherd.ts index b8a703e..b806e04 100755 --- a/packages/deployer/src/shepherd.ts +++ b/packages/deployer/src/shepherd.ts @@ -143,7 +143,7 @@ function loginToRegistryWithPrompt() { } } -function main() { +async function main() { if (process.argv.indexOf("--version") > 0) { printVersions() process.exit(0) @@ -238,96 +238,89 @@ function main() { printUsage() process.exit(255) } + try { + await stateStoreBackend.connect() + let releaseStateStore = ReleaseStateStore({ + storageBackend: stateStoreBackend, + }) + let upstreamDeploymentConfig = createUpstreamTriggerDeploymentConfig(logger) + upstreamDeploymentConfig.loadFromEnvironment(herdFilePath, process.env) - stateStoreBackend - .connect() - .then(function() { - let releaseStateStore = ReleaseStateStore({ - storageBackend: stateStoreBackend, - }) - let upstreamDeploymentConfig = createUpstreamTriggerDeploymentConfig(logger) - upstreamDeploymentConfig.loadFromEnvironment(herdFilePath, process.env) - - if (upstreamDeploymentConfig.herdFileEditNeeded()) { - upgradeOrAddDeploymentInFile(upstreamDeploymentConfig, logger) - } - - let loaderContext = createLoaderContext({ - stateStore: releaseStateStore, - logger: logger, - featureDeploymentConfig: upstreamDeploymentConfig, - uiPusher: uiDataPusher, - environment: environment, - exec: exec, - }) + if (upstreamDeploymentConfig.herdFileEditNeeded()) { + upgradeOrAddDeploymentInFile(upstreamDeploymentConfig, logger) + } - logger.info("Calculating deployment of herd from file " + herdFilePath + " for environment " + environment) - - loaderContext.loader - .loadHerd(herdFilePath) - .then(function(plan: IDeploymentOrchestration) { - plan.printPlan(logger) - if (exportDocuments) { - logger.info("Testrun mode set - exporting all deployment documents to " + outputDirectory) - logger.info("Testrun mode set - no deployments will be performed") - plan - .exportDeploymentActions(outputDirectory as TFileSystemPath) - .then(function() { - terminateProcess(0) - }) - .catch(function(writeError: Error) { - logger.error("Error exporting deployment document! ", writeError) - terminateProcess(255) - }) - } else { - // TODOLATER Rollback on kube config - - let dryRunString = `${dryRun ? " dryrun" : ""}` - - logger.info(`Executing deployment plan${dryRunString}... `) - plan - .executePlans({ - dryRun: dryRun, - dryRunOutputDir: outputDirectory, - pushToUi: pushToUi, - waitForRollout: waitForRollout, - rolloutWaitSeconds: rolloutTimeout, - logContext: defaultLogContext, - }) - .then(function(planResults: IDeploymentPlanExecutionResult[]) { - // Exceptions from plan execution are logged immediately. Here we render only a summary of deployment results. - const failedPlans = planResults.filter(planExecutionResult => { - return planExecutionResult.actionExecutionError !== undefined - }) - if (failedPlans.length > 0) { - renderPlanFailureSummary(logger, failedPlans) - return terminateProcess(failedPlans.length) - } - logger.info(`...plan${dryRunString} execution complete. Exiting shepherd.`) - setTimeout(() => { - terminateProcess(0) - }, 1000) - }) - .catch(function(err: Error) { - renderPlanExecutionError(logger, err, defaultLogContext) - terminateProcess(255) - }) - } - }) - .catch(function(loadError) { - logger.debug(`Plan load error, with stack`, loadError) - logger.error(`Plan load error. ${loadError.message}`) - if (loadError.context) { - logger.error(` ${JSON.stringify(loadError.context)}`) - } - stateStoreBackend.disconnect() - process.exit(255) - }) + let loaderContext = createLoaderContext({ + stateStore: releaseStateStore, + logger: logger, + featureDeploymentConfig: upstreamDeploymentConfig, + uiPusher: uiDataPusher, + environment: environment, + exec: exec, }) - .catch(function(err: Error) { - console.error("Connection/migration error", err) + logger.info("Calculating deployment of herd from file " + herdFilePath + " for environment " + environment) + + try { + const plan: IDeploymentOrchestration = await loaderContext.loader.loadHerd(herdFilePath) + + plan.printPlan(logger) + if (exportDocuments) { + logger.info("Testrun mode set - exporting all deployment documents to " + outputDirectory) + logger.info("Testrun mode set - no deployments will be performed") + plan + .exportDeploymentActions(outputDirectory as TFileSystemPath) + .then(function() { + terminateProcess(0) + }) + .catch(function(writeError: Error) { + logger.error("Error exporting deployment document! ", writeError) + terminateProcess(255) + }) + } else { + // TODOLATER Rollback on kube config + + let dryRunString = `${dryRun ? " dryrun" : ""}` + + logger.info(`Executing deployment plan${dryRunString}... `) + try { + const planResults: IDeploymentPlanExecutionResult[] = await plan.executePlans({ + dryRun: dryRun, + dryRunOutputDir: outputDirectory, + pushToUi: pushToUi, + waitForRollout: waitForRollout, + rolloutWaitSeconds: rolloutTimeout, + logContext: defaultLogContext, + }) + // Exceptions from plan execution are logged immediately. Here we render only a summary of deployment results. + const failedPlans = planResults.filter(planExecutionResult => { + return planExecutionResult.actionExecutionError !== undefined + }) + if (failedPlans.length > 0) { + renderPlanFailureSummary(logger, failedPlans) + return terminateProcess(failedPlans.length) + } + logger.info(`...plan${dryRunString} execution complete. Exiting shepherd.`) + setTimeout(() => { + terminateProcess(0) + }, 1000) + } catch (execError) { + renderPlanExecutionError(logger, execError, defaultLogContext) + terminateProcess(255) + } + } + } catch (loadError) { + logger.debug(`Plan load error, with stack`, loadError) + logger.error(`Plan load error. ${loadError.message}`) + if (loadError.context) { + logger.error(` ${JSON.stringify(loadError.context)}`) + } + stateStoreBackend.disconnect() process.exit(255) - }) + } + } catch (connError) { + console.error("Connection/migration error", connError) + process.exit(255) + } } main() diff --git a/packages/deployer/src/triggered-deployment/create-upstream-trigger-deployment-config.ts b/packages/deployer/src/triggered-deployment/create-upstream-trigger-deployment-config.ts index 7c7e639..3018359 100644 --- a/packages/deployer/src/triggered-deployment/create-upstream-trigger-deployment-config.ts +++ b/packages/deployer/src/triggered-deployment/create-upstream-trigger-deployment-config.ts @@ -74,12 +74,16 @@ export function createUpstreamTriggerDeploymentConfig(logger: ILog): IConfigureU }, loadFromEnvironment(herdFilePath: TFileSystemPath, environment: typeof process.env = process.env): void { let upstreamImageUrl: string = "" - if (environment.UPSTREAM_IMAGE_NAME && environment.UPSTREAM_IMAGE_TAG) { upstreamImageUrl = environment.UPSTREAM_IMAGE_NAME + ":" + environment.UPSTREAM_IMAGE_TAG } else if (environment.UPSTREAM_IMAGE_URL) { upstreamImageUrl = environment.UPSTREAM_IMAGE_URL } + logger.info( + `Look for the herd up stream. upstreamImageUrl: ${ + environment.UPSTREAM_IMAGE_URL + }, hasUpstreamHerdKey: ${Boolean(environment.UPSTREAM_HERD_KEY)}` + ) if (Boolean(upstreamImageUrl) && environment.UPSTREAM_HERD_KEY) { logger.info("Upstream information available, using to modify deployment.") const dockerUrl = parseImageUrl(upstreamImageUrl) From 3b50d60bbe1f8521ae4624c0e642ed17efb010a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93lafur=20Torfi=20Yngvason?= Date: Wed, 11 Dec 2024 16:19:31 +0000 Subject: [PATCH 2/4] bump deployer version --- packages/deployer/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/deployer/package.json b/packages/deployer/package.json index e60fe7c..3467c35 100644 --- a/packages/deployer/package.json +++ b/packages/deployer/package.json @@ -1,6 +1,6 @@ { "name": "@shepherdorg/deployer", - "version": "5.2.5", + "version": "5.3.0", "description": "Deployer application", "main": "dist/shepherd.js", "engines": { From 053b65d5fb29f93a433be8589f64020ebb5addd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93lafur=20Torfi=20Yngvason?= Date: Thu, 12 Dec 2024 01:59:14 +0000 Subject: [PATCH 3/4] initialize uiDatePusher in every case --- packages/deployer/src/shepherd.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/deployer/src/shepherd.ts b/packages/deployer/src/shepherd.ts index b806e04..ff1e03b 100755 --- a/packages/deployer/src/shepherd.ts +++ b/packages/deployer/src/shepherd.ts @@ -190,8 +190,13 @@ async function main() { } let stateStoreBackend: IStorageBackend - - let uiDataPusher: IPushToShepherdUI + const mockUiPusher = { + pushDeploymentStateToUI: async () => { + logger.info("Would have pushed to ui, were it not a dryrun") + return undefined + }, + } + let uiDataPusher: IPushToShepherdUI = mockUiPusher if (dryRun) { logger.info(`NOTE: Dryrun does not take deployment state into account and assumes everything needs to be deployed.`) From 79a57ed9f2fbc9634a840d6d3533416b038f44d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93lafur=20Torfi=20Yngvason?= Date: Thu, 12 Dec 2024 02:00:56 +0000 Subject: [PATCH 4/4] move initalization inside conditionals --- packages/deployer/src/shepherd.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/deployer/src/shepherd.ts b/packages/deployer/src/shepherd.ts index ff1e03b..9a957de 100755 --- a/packages/deployer/src/shepherd.ts +++ b/packages/deployer/src/shepherd.ts @@ -193,14 +193,15 @@ async function main() { const mockUiPusher = { pushDeploymentStateToUI: async () => { logger.info("Would have pushed to ui, were it not a dryrun") - return undefined + return }, } - let uiDataPusher: IPushToShepherdUI = mockUiPusher + let uiDataPusher: IPushToShepherdUI if (dryRun) { logger.info(`NOTE: Dryrun does not take deployment state into account and assumes everything needs to be deployed.`) stateStoreBackend = InMemoryStore() + uiDataPusher = mockUiPusher } else { if (process.env.SHEPHERD_PG_HOST) { logger.info(`Using postgres state store on ${process.env.SHEPHERD_PG_HOST}`) @@ -219,6 +220,8 @@ async function main() { if (Boolean(process.env.SHEPHERD_UI_API_ENDPOINT)) { logger.info(`Shepherd UI API endpoint configured ${process.env.SHEPHERD_UI_API_ENDPOINT}`) uiDataPusher = CreatePushApi(process.env.SHEPHERD_UI_API_ENDPOINT, console) + } else { + uiDataPusher = mockUiPusher } }