From 2cca4e0cec6905ec9309d9a18efdd23102bfbfa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bence=20Nagygy=C3=B6rgy?= Date: Mon, 16 Dec 2024 13:01:38 +0100 Subject: [PATCH] fix: env merge & deploy start validation --- web/crux-ui/src/models/container-merge.ts | 17 ++++++- .../interceptors/deploy.start.interceptor.ts | 49 ++++++++----------- web/crux/src/domain/container-merge.ts | 22 +++++++-- 3 files changed, 55 insertions(+), 33 deletions(-) diff --git a/web/crux-ui/src/models/container-merge.ts b/web/crux-ui/src/models/container-merge.ts index 5d7052faa..d2341ff5d 100644 --- a/web/crux-ui/src/models/container-merge.ts +++ b/web/crux-ui/src/models/container-merge.ts @@ -5,6 +5,7 @@ import { Marker, Port, UniqueKey, + UniqueKeyValue, UniqueSecretKey, UniqueSecretKeyValue, Volume, @@ -84,7 +85,7 @@ export const mergeSecrets = (strong: UniqueSecretKeyValue[], weak: UniqueSecretK export const mergeConfigs = (strong: ContainerConfigData, weak: ContainerConfigData): ContainerConfigData => ({ // common name: strong.name ?? weak.name, - environment: strong.environment ?? weak.environment, + environment: mergeUniqueKeyValues(strong.environment, weak.environment), secrets: mergeSecretKeys(strong.secrets, weak.secrets), user: mergeNumber(strong.user, weak.user), workingDirectory: strong.workingDirectory ?? weak.workingDirectory, @@ -154,6 +155,20 @@ const mergeUniqueKeys = (strong: T[], weak: T[]): T[] => { return [...strong, ...missing] } +// TODO(@robot9706): Validate +const mergeUniqueKeyValues = (strong: T[], weak: T[]): T[] => { + if (!strong) { + return weak ?? null + } + + if (!weak) { + return strong + } + + const missing = weak.filter(w => !strong.find(it => it.key === w.key)) + return [...strong, ...missing] +} + const mergePorts = (strong: Port[], weak: Port[]): Port[] => { if (!strong) { return weak ?? null diff --git a/web/crux/src/app/deploy/interceptors/deploy.start.interceptor.ts b/web/crux/src/app/deploy/interceptors/deploy.start.interceptor.ts index 63cb4986d..c79767d57 100644 --- a/web/crux/src/app/deploy/interceptors/deploy.start.interceptor.ts +++ b/web/crux/src/app/deploy/interceptors/deploy.start.interceptor.ts @@ -7,7 +7,7 @@ import { getConflictsForConcreteConfig } from 'src/domain/container-conflict' import { mergeConfigsWithConcreteConfig } from 'src/domain/container-merge' import { checkDeploymentDeployability } from 'src/domain/deployment' import { parseDyrectorioEnvRules } from 'src/domain/image' -import { missingSecretsOf } from 'src/domain/start-deployment' +import { deploymentConfigOf, instanceConfigOf, missingSecretsOf } from 'src/domain/start-deployment' import { createStartDeploymentSchema, nullifyUndefinedProperties, yupValidate } from 'src/domain/validation' import { CruxPreconditionFailedException } from 'src/exception/crux-exception' import PrismaService from 'src/services/prisma.service' @@ -110,25 +110,7 @@ export default class DeployStartValidationInterceptor implements NestInterceptor }) yupValidate(createStartDeploymentSchema(instanceValidations), target) - const missingSecrets = deployment.instances - .map(it => { - const imageConfig = it.image.config as any as ContainerConfigData - const instanceConfig = it.config as any as ConcreteContainerConfigData - const mergedConfig = mergeConfigsWithConcreteConfig([imageConfig], instanceConfig) - - return missingSecretsOf(it.configId, mergedConfig) - }) - .filter(it => !!it) - - if (missingSecrets.length > 0) { - throw new CruxPreconditionFailedException({ - message: 'Required secrets must have values!', - property: 'instanceSecrets', - value: missingSecrets, - }) - } - - // config bundles + // check config bundle conflicts if (deployment.configBundles.length > 0) { const configs = deployment.configBundles.map(it => it.configBundle.config as any as ContainerConfigDataWithId) const concreteConfig = deployment.config as any as ConcreteContainerConfigData @@ -140,16 +122,25 @@ export default class DeployStartValidationInterceptor implements NestInterceptor value: Object.keys(conflicts).join(', '), }) } + } - const mergedConfig = mergeConfigsWithConcreteConfig(configs, concreteConfig) - const missingInstanceSecrets = missingSecretsOf(deployment.configId, mergedConfig) - if (missingInstanceSecrets) { - throw new CruxPreconditionFailedException({ - message: 'Required secrets must have values!', - property: 'deploymentSecrets', - value: missingInstanceSecrets, - }) - } + // validate instance configs + const deploymentConfig = deploymentConfigOf(deployment) + + const missingSecrets = deployment.instances + .map(it => { + const instanceConfig = instanceConfigOf(deployment, deploymentConfig, it) + + return missingSecretsOf(it.configId, instanceConfig) + }) + .filter(it => !!it) + + if (missingSecrets.length > 0) { + throw new CruxPreconditionFailedException({ + message: 'Required secrets must have values!', + property: 'instanceSecrets', + value: missingSecrets, + }) } // node diff --git a/web/crux/src/domain/container-merge.ts b/web/crux/src/domain/container-merge.ts index a4f96f422..142a151bd 100644 --- a/web/crux/src/domain/container-merge.ts +++ b/web/crux/src/domain/container-merge.ts @@ -5,6 +5,7 @@ import { Marker, Port, UniqueKey, + UniqueKeyValue, UniqueSecretKey, UniqueSecretKeyValue, Volume, @@ -97,10 +98,11 @@ export const mergeSecrets = (strong: UniqueSecretKeyValue[], weak: UniqueSecretK weak = weak ?? [] strong = strong ?? [] - const overriddenIds: Set = new Set(strong?.map(it => it.id)) + // TODO(@robot9706): Validate this + const overriddenKeys: Set = new Set(strong?.map(it => it.key)) const missing: UniqueSecretKeyValue[] = weak - .filter(it => !overriddenIds.has(it.id)) + .filter(it => !overriddenKeys.has(it.key)) .map(it => ({ ...it, value: '', @@ -114,7 +116,7 @@ export const mergeSecrets = (strong: UniqueSecretKeyValue[], weak: UniqueSecretK export const mergeConfigs = (strong: ContainerConfigData, weak: ContainerConfigData): ContainerConfigData => ({ // common name: strong.name ?? weak.name, - environment: strong.environment ?? weak.environment, + environment: mergeUniqueKeyValues(strong.environment, weak.environment), secrets: mergeSecretKeys(strong.secrets, weak.secrets), user: mergeNumber(strong.user, weak.user), workingDirectory: strong.workingDirectory ?? weak.workingDirectory, @@ -184,6 +186,20 @@ const mergeUniqueKeys = (strong: T[], weak: T[]): T[] => { return [...strong, ...missing] } +// TODO(@robot9706): Validate +const mergeUniqueKeyValues = (strong: T[], weak: T[]): T[] => { + if (!strong) { + return weak ?? null + } + + if (!weak) { + return strong + } + + const missing = weak.filter(w => !strong.find(it => it.key === w.key)) + return [...strong, ...missing] +} + const mergePorts = (strong: Port[], weak: Port[]): Port[] => { if (!strong) { return weak ?? null