import { TDockerImageHerdDeclaration, TDockerImageHerdDeclarations, THerdSectionDeclaration, TImageInformation, } from "../../deployment-types" import { TDockerImageReference } from "@shepherdorg/docker-image-metadata-loader/dist/local-image-metadata" import { extractShepherdMetadata } from "../add-shepherd-metadata" import { TFileSystemPath } from "../../helpers/basic-types" import { ILoadDockerImageLabels } from "@shepherdorg/docker-image-metadata-loader" import { parseImageUrl, TDockerImageUrl, TDockerImageUrlStruct } from "../../helpers/parse-image-url" import { IDeploymentPlan, IDeploymentPlanFactory } from "../../deployment-plan/deployment-plan" import { newProgrammerOops } from "oops-error" import { IReleaseStateStore } from "@shepherdorg/state-store" import { ILog } from "@shepherdorg/logger" export function parseDockerImageUrl(dockerImageUrl: TDockerImageUrl): TDockerImageUrlStruct { return parseImageUrl(dockerImageUrl) } interface TImageDeclarationsLoaderDependencies { stateStore: IReleaseStateStore logger: ILog imageLabelsLoader: ILoadDockerImageLabels planFactory: IDeploymentPlanFactory } export function createImagesLoader(injected: TImageDeclarationsLoaderDependencies) { let derivedDeployments: TDockerImageHerdDeclarations = {} function loadImageDeploymentPlans(images: TDockerImageHerdDeclarations, sectionDeclaration: THerdSectionDeclaration) { function addMigrationImageToDependenciesPlan(imageMetaData: TImageInformation) { if (imageMetaData.shepherdMetadata && imageMetaData.shepherdMetadata.migrationImage) { let dockerImageTag = parseDockerImageUrl(imageMetaData.shepherdMetadata.migrationImage) derivedDeployments[imageMetaData.shepherdMetadata.migrationImage] = { sectionDeclaration: sectionDeclaration, ...dockerImageTag, } } return imageMetaData } function loadImageMetadata(imageDef: TDockerImageReference) { return injected.imageLabelsLoader.getImageLabels(imageDef) } return Object.entries(images).map(function([imgName, herdSpec]: [string, TDockerImageHerdDeclaration]) { herdSpec.key = imgName injected.logger.debug(`Deployment image - loading image meta data for docker image ${JSON.stringify(herdSpec)}`) if (!herdSpec.image && herdSpec.dockerImage) { Object.assign(herdSpec, parseDockerImageUrl(herdSpec.dockerImage)) } let promise: Promise = loadImageMetadata(herdSpec) .then(extractShepherdMetadata) .then(addMigrationImageToDependenciesPlan) .then(injected.planFactory.createDockerImageDeploymentPlan) .catch(function(e: Error | string) { let errorMessage: string if (typeof e === "string") { console.error("Thrown error of type STRING!") console.error(e) errorMessage = e } else { errorMessage = "When processing image " + imgName + "\n" + e.message } throw newProgrammerOops(errorMessage, {}, e) }) return promise }) } async function imagesLoader( herdSectionSpec: THerdSectionDeclaration, images: TDockerImageHerdDeclarations, _herdPath: TFileSystemPath ): Promise> { let planLoadingPromises: Array> = loadImageDeploymentPlans(images, herdSectionSpec) let imageDeploymentPlans: Array = await Promise.all(planLoadingPromises) // TODOLATER There should be no derived image deployment plans, migration actions should be a part of the image deployment plan let derivedPlanLoadingPromises = loadImageDeploymentPlans(derivedDeployments, herdSectionSpec) imageDeploymentPlans = imageDeploymentPlans.concat(await Promise.all(derivedPlanLoadingPromises)) return await Promise.all( imageDeploymentPlans.flatMap(async deploymentPlan => { return deploymentPlan }) ) } return { imagesLoader } }