UNPKG

@aws-amplify/amplify-category-api

Version:
172 lines (145 loc) 5.8 kB
import * as v1Types from './compose-spec/v1'; import * as v2Types from './compose-spec/v2'; import * as v38Types from './compose-spec/v3.8'; import { dockerComposeToObject, dockerfileToObject, generateBuildSpec } from './DockerUtils'; import Container from './ecs-objects/container'; import { BuildHashMap, PortMappings } from './ecs-objects/types'; const isv1Schema = (obj: any): obj is v1Types.ConfigSchemaV1Json => { return obj && obj.version === undefined; }; const hasHealthCheck = (obj: any): obj is v2Types.DefinitionsHealthcheck => { return obj.healthcheck !== undefined; }; function isV38Service(obj: any): obj is v38Types.DefinitionsService { return obj && (<v38Types.DefinitionsService>obj).secrets !== undefined; } const mapComposeEntriesToContainer = (record: [string, v1Types.DefinitionsService | v2Types.DefinitionsService]): Container => { const [k, v] = record; const { image, ports, build, command, entrypoint, env_file, environment, working_dir, user } = v; const { container_name: name = k } = v; let healthcheck: v2Types.DefinitionsHealthcheck = {}; if (hasHealthCheck(v)) { Object.entries(v).forEach((item: [string, v2Types.DefinitionsHealthcheck]) => { const [, healthVal] = item; if (healthVal.test !== undefined) { healthcheck = healthVal; } }); } let portArray: PortMappings = []; ports?.forEach((item) => { // For task definitions that use the awsvpc network mode, you should only specify the containerPort. // The hostPort can be left blank or it must be the same value as the containerPort. const [containerPort, hostPort = containerPort] = item.toString().split(':'); portArray.push({ containerPort: parseInt(containerPort, 10), hostPort: parseInt(hostPort, 10), protocol: 'tcp', }); }); const secrets = new Set<string>(); if (isV38Service(v)) { v.secrets.filter((s) => typeof s === 'string').forEach((s) => secrets.add(<string>s)); } return new Container( build, name, portArray, command, entrypoint, env_file, environment, image, { command: healthcheck.test, ...healthcheck, }, working_dir, user, secrets, ); }; const convertDockerObjectToContainerArray = (yamlObject: v2Types.ConfigSchemaV24Json | v1Types.ConfigSchemaV1Json) => { let containerArr: Container[] = []; if (isv1Schema(yamlObject)) { Object.entries(yamlObject).forEach((record: [string, v1Types.DefinitionsService]) => { const container = mapComposeEntriesToContainer(record); containerArr.push(container); }); } else { Object.entries(yamlObject.services ?? {}).forEach((record: [string, v2Types.DefinitionsService]) => { const container = mapComposeEntriesToContainer(record); containerArr.push(container); }); } return containerArr; }; const findServiceDeployment = ( yamlObject: v38Types.ComposeSpecification | v2Types.ConfigSchemaV24Json | v1Types.ConfigSchemaV1Json, ): v38Types.DefinitionsDeployment2 => { let result: v38Types.DefinitionsDeployment2 = {}; Object.entries(yamlObject.services ?? {}).forEach((record: [string, v38Types.DefinitionsService]) => { const [, v] = record; const { deploy } = v; if (deploy !== undefined) { // TODO: This is returning the deploy obj of the last service that had it, it should probably be an array result = deploy!; } }); return result; }; type DockerServiceInfo = { buildspec: string; service: v38Types.DefinitionsDeployment; containers: Container[]; secrets: Record<string, string>; }; export function getContainers(composeContents?: string, dockerfileContents?: string): DockerServiceInfo { // Step 1: Detect if there is a docker-compose or just a Dockerfile. // Just Dockerfile-> create registry using function name, buildspec, zip and put on S3 // Compose file -> Begin by parsing it: const dockerCompose = composeContents ? dockerComposeToObject(composeContents) : dockerfileToObject(dockerfileContents); const secrets: Record<string, string> = {}; const { secrets: composeSecrets = {} }: { secrets?: v38Types.PropertiesSecrets } = <any>dockerCompose; for (const secretName of Object.keys(composeSecrets)) { if (composeSecrets[secretName].file) { secrets[composeSecrets[secretName].name ?? secretName] = composeSecrets[secretName].file; } } // Step 2: Take compose object and pull all the containers out: const containers = convertDockerObjectToContainerArray(dockerCompose); // Step 3: Populate Build mapping for creation of the buildpsec const buildmapping: BuildHashMap = {}; containers.forEach((res) => { if (typeof res.build === 'object') { // console.log(res.build.args); } if (typeof res.healthcheck === 'object') { // console.log(res.healthcheck.command) } // Step 4: Create ECR Entry if build is specified - TODO with Francisco..... - this will go in registryArn if (res.build != undefined) { let buildContext: string = ''; if (typeof res.build === 'object') { buildContext = res.build.context!; } else { buildContext = res.build; } // Wont need this if statement later, just using for testing /** This will look like this for each container where res.build != undefined: * let registryArn = new ecr.Repository(this, res.name, {}); * buildmapping[res.name] = {buildPath: buildContext, registryArn }; */ buildmapping[res.name] = buildContext; } }); // Step 5: Generate the buildfiles const buildspec = generateBuildSpec(buildmapping); const service = findServiceDeployment(dockerCompose); return { buildspec, service, containers, secrets, }; }