import * as aws from "@pulumi/aws" ; import * as docker from "@pulumi/docker" ; import * as pulumi from "@pulumi/pulumi" ; import * as ecs from "." ; import * as utils from "../utils" ; export abstract class Image implements ecs . ContainerImageProvider { public abstract image ( name , parent ) ; public abstract environment ( name , parent ) ; /**
     * Creates an [Image] given a path to a folder in which a Docker build should be run.
     *
     * Either a [name] or [repository] needs to be provided where the built image will be pushed
     * to.  If [repository] is provided, it will be used as-is.  Otherwise, a new one will be
     * created on-demand, using the [name] value.
     */ public static fromPath ( name , path ) ; public static fromPath ( repository , path ) ; public static fromPath ( nameOrRepository , path ) { if ( path === undefined ) { throw new Error ( "'build' was undefined" ) ; } return new AssetImage ( nameOrRepository , path ) ; } /**
     * Creates an [Image] using the detailed build instructions provided in [build].
     *
     * Either a [name] or [repository] needs to be provided where the built image will be pushed
     * to.  If [repository] is provided, it will be used as-is.  Otherwise, a new one will be
     * created on-demand, using the [name] value.
     */ public static fromDockerBuild ( name , build ) ; public static fromDockerBuild ( repository , build ) ; public static fromDockerBuild ( nameOrRepository , build ) { if ( build === undefined ) { throw new Error ( "'path' was undefined" ) ; } return new AssetImage ( nameOrRepository , build ) ; } /**
     * Creates an [Image] given function code to use as the implementation of the container.
     */ public static fromFunction ( func ) { return new FunctionImage ( func ) ; } } class FunctionImage extends Image { constructor ( private readonly func ) { super ( ) ; } public image ( ) { return "lukehoban/nodejsrunner" ; } public environment ( ) { return pulumi . runtime . serializeFunction ( this . func ) . then ( value => [ { name : "PULUMI_SRC" , value : value . text , } ] ) ; } } class AssetImage extends Image { private readonly nameOrRepository : string | aws . ecr . Repository ; private readonly pathOrBuild : pulumi . Output < string | docker . DockerBuild > ; private imageResult : pulumi . Output < string > | undefined ; constructor ( nameOrRepository , pathOrBuild ) { super ( ) ; this . nameOrRepository = nameOrRepository ; this . pathOrBuild = pulumi . output ( pathOrBuild ) ; } public environment ( name , parent ) { return [ ] ; } public image ( name , parent ) { if ( ! this . imageResult ) { const repository = typeof this . nameOrRepository === "string" ? AssetImage . createRepository ( this . nameOrRepository , { parent } ) : this . nameOrRepository ; const { repositoryUrl , registryId } = repository ; this . imageResult = pulumi . all ( [ this . pathOrBuild , repositoryUrl , registryId ] ) . apply ( ( [ pathOrBuild , repositoryUrl , registryId ] ) => computeImageFromAsset ( pathOrBuild , repositoryUrl , registryId , parent ) ) ; } return this . imageResult ; } private static createRepository ( name , opts ) { const repository = new aws . ecr . Repository ( name . toLowerCase ( ) , { } , opts ) ; const lifecyclePolicyDocument = { rules : [ { rulePriority : 10 , description : "remove untagged images" , selection : { tagStatus : "untagged" , countType : "imageCountMoreThan" , countNumber : 1 , } , action : { type : "expire" , } , } ] , } ; const lifecyclePolicy = new aws . ecr . LifecyclePolicy ( name . toLowerCase ( ) , { policy : JSON . stringify ( lifecyclePolicyDocument ) , repository : repository . name , } , opts ) ; return repository ; } } function getImageName ( pathOrBuild ) { let buildSig ; if ( typeof pathOrBuild === "string" ) { buildSig = pathOrBuild ; } else { buildSig = pathOrBuild . context || "." ; if ( pathOrBuild . dockerfile ) { buildSig += `;dockerfile=${ pathOrBuild . dockerfile }` ; } if ( pathOrBuild . args ) { for ( const arg of Object . keys ( pathOrBuild . args ) ) { buildSig += `;arg[${ arg }]=${ pathOrBuild . args [ arg ] }` ; } } } buildSig += pulumi . getStack ( ) ; return `${ utils . sha1hash ( buildSig ) }-container` ; } internal export function computeImageFromAsset ( pathOrBuild , repositoryUrl , registryId , parent ) { pulumi . log . debug ( `Building container image at '${ JSON . stringify ( pathOrBuild ) }'` , parent ) ; const imageName = getImageName ( pathOrBuild ) ; const uniqueImageName = docker . buildAndPushImage ( imageName , pathOrBuild , repositoryUrl , parent , async ( ) => { if ( ! registryId ) { throw new Error ( "Expected registry ID to be defined during push" ) ; } const credentials = await aws . ecr . getCredentials ( { registryId : registryId } , { parent , async : true } ) ; const decodedCredentials = Buffer . from ( credentials . authorizationToken , "base64" ) . toString ( ) ; const [ username , password ] = decodedCredentials . split ( ":" ) ; if ( ! password || ! username ) { throw new Error ( "Invalid credentials" ) ; } return { registry : credentials . proxyEndpoint , username : username , password : password , } ; } ) ; uniqueImageName . apply ( d => pulumi . log . debug ( `    build complete: ${ imageName } (${ d })` , parent ) ) ; return uniqueImageName ; }