Last active
August 21, 2019 04:38
-
-
Save rarous/50bd9f5eb11321070eadc3e6d12dc187 to your computer and use it in GitHub Desktop.
Pulumi definition of Datomic Ions Resources and API Gateway integration
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as ions from "./ions"; | |
const cloud = new ions.DatomicCloud("test-ions", { | |
enableBastion: true, | |
applicationName: "test", | |
systemName: "datomic-test", | |
environmentMap: "{:env :test}", | |
keyName: "test-key" | |
}); | |
// here you have to create Datomic Ions Lambda function `:test`, push & deploy it. | |
// after that you can add incrementally: | |
const api = new ions.Api("test-ions", { | |
stageName: "v1", | |
datomicCompute: cloud.compute, | |
routes: [ | |
{ httpMethod: "GET", path: "/", lambdaName: "test" } | |
] | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as pulumi from "@pulumi/pulumi"; | |
import * as aws from "@pulumi/aws"; | |
import * as awsx from "@pulumi/awsx"; | |
export class DatomicCloud extends pulumi.ComponentResource { | |
readonly storage: aws.cloudformation.Stack; | |
readonly compute: aws.cloudformation.Stack; | |
constructor( | |
name: string, | |
args: DatomicCloudArgs, | |
opts?: pulumi.ResourceOptions | |
) { | |
super("topmonks:ions:DatomicCloud", name, {}, opts); | |
this.storage = new aws.cloudformation.Stack(`${name}-storage`, { | |
name: args.systemName, | |
capabilities: ["CAPABILITY_NAMED_IAM"], | |
templateUrl: | |
"https://s3.amazonaws.com/datomic-cloud-1/cft/480-8772/datomic-storage-480-8772.json", | |
parameters: { | |
Restart: "false", | |
Subnet0CidrBlock: "10.213.0.0/20", | |
Subnet1CidrBlock: "10.213.16.0/20", | |
Subnet2CidrBlock: "10.213.32.0/20", | |
VpcCidrBlock: "10.213.0.0/16" | |
} | |
}); | |
this.compute = new aws.cloudformation.Stack( | |
`${name}-compute`, | |
{ | |
name: `${args.systemName}-compute`, | |
capabilities: ["CAPABILITY_NAMED_IAM"], | |
templateUrl: | |
"https://s3.amazonaws.com/datomic-cloud-1/cft/480-8772/datomic-solo-compute-480-8772.json", | |
parameters: { | |
EnableBastion: args.enableBastion ? "Yes" : "No", | |
KeyName: args.keyName, | |
SystemName: args.systemName, | |
ApplicationName: args.applicationName, | |
EnvironmentMap: args.environmentMap, | |
PreloadDb: "" | |
} | |
}, | |
{ dependsOn: [this.storage] } | |
); | |
if (args.enableBastion) { | |
new aws.ec2.SecurityGroupRule(`${name}-bastion-ssh-access`, { | |
description: "SSH access to bastion", | |
securityGroupId: this.compute.outputs.apply(o => o.BastionSecurityGroup), | |
protocol: "TCP", | |
cidrBlocks: ["0.0.0.0/0"], | |
ipv6CidrBlocks: ["::/0"], | |
fromPort: 22, | |
toPort: 22, | |
type: "ingress" | |
}); | |
} | |
} | |
} | |
export class Api extends pulumi.ComponentResource { | |
readonly gateway: awsx.apigateway.API; | |
constructor(name: string, args: ApiArgs, opts?: pulumi.ResourceOptions) { | |
super("topmonks:ions:Api", name, {}, opts); | |
this.gateway = new awsx.apigateway.API(name, { | |
stageName: "v1", | |
routes: createRoutes(name, args.datomicCompute, args.routes) | |
}); | |
const anySchemaModel = new aws.apigateway.Model(name, { | |
name: "AnySchema", | |
contentType: "application/json", | |
restApi: this.gateway.restAPI, | |
schema: JSON.stringify({ | |
type: "object", | |
title: "Any Schema" | |
}) | |
}); | |
createLambdaMethodExecutions( | |
name, | |
this.gateway, | |
anySchemaModel, | |
args.routes | |
); | |
} | |
} | |
export class LambdaMethodExecution extends pulumi.ComponentResource { | |
constructor( | |
name: string, | |
args: LambdaMethodExecutionArgs, | |
opts?: pulumi.ResourceOptions | |
) { | |
super("topmonks:ions:LambdaMethodExecution", name, {}, opts); | |
const methodResource = getMethodResource(args.gateway, args.path); | |
const methodResponse = defineMethodResponse( | |
this, | |
name, | |
args.gateway, | |
args.httpMethod, | |
args.responseModel, | |
methodResource | |
); | |
defineIntegrationResponse( | |
this, | |
name, | |
args.gateway, | |
methodResource, | |
methodResponse | |
); | |
} | |
} | |
function createLambdaMethodExecutions( | |
name: string, | |
gateway: awsx.apigateway.API, | |
anySchemaModel: aws.apigateway.Model, | |
routes: ApiRoute[] | |
) { | |
return routes.map( | |
({ httpMethod, path, responseModel }) => | |
new LambdaMethodExecution(`${name}/${httpMethod}/${path}`, { | |
gateway, | |
path, | |
httpMethod, | |
responseModel: responseModel || anySchemaModel | |
}) | |
); | |
} | |
function createRoutes( | |
name: string, | |
datomicCompute: aws.cloudformation.Stack, | |
routes: ApiRoute[] | |
): awsx.apigateway.Route[] { | |
return routes.map(({ httpMethod, path, lambdaName }) => ({ | |
method: httpMethod, | |
path, | |
eventHandler: getLambda( | |
`${name}/${httpMethod}/${path}`, | |
datomicCompute, | |
lambdaName | |
) | |
})); | |
} | |
function getLambda( | |
name: string, | |
ionsComputeStack: aws.cloudformation.Stack, | |
ionsLambdaName: string | |
): aws.lambda.Function { | |
return aws.lambda.Function.get( | |
name, | |
ionsComputeStack.outputs.apply( | |
x => `${x.CodeDeployDeploymentGroup}-${ionsLambdaName}` | |
) | |
); | |
} | |
function getMethodResource( | |
gateway: awsx.apigateway.API, | |
path: string | |
): pulumi.Output<aws.apigateway.GetResourceResult> { | |
return gateway.restAPI.executionArn.apply(x => | |
gateway.deployment.executionArn.apply(_ => | |
aws.apigateway.getResource({ | |
path, | |
restApiId: <string>x.split(":").pop() | |
}) | |
) | |
); | |
} | |
function defineMethodResponse( | |
parent: LambdaMethodExecution, | |
name: string, | |
gateway: awsx.apigateway.API, | |
httpMethod: string, | |
responseModel: aws.apigateway.Model, | |
methodResource: pulumi.Output<aws.apigateway.GetResourceResult> | |
): aws.apigateway.MethodResponse { | |
return new aws.apigateway.MethodResponse( | |
name, | |
{ | |
restApi: gateway.restAPI, | |
resourceId: methodResource.id, | |
httpMethod: httpMethod, | |
statusCode: "200", | |
responseParameters: { | |
"method.response.header.Access-Control-Allow-Headers": true, | |
"method.response.header.Access-Control-Allow-Methods": true, | |
"method.response.header.Access-Control-Allow-Origin": true | |
}, | |
responseModels: { "application/json": responseModel.name } | |
}, | |
{ parent } | |
); | |
} | |
function defineIntegrationResponse( | |
parent: LambdaMethodExecution, | |
name: string, | |
gateway: awsx.apigateway.API, | |
methodResource: pulumi.Output<aws.apigateway.GetResourceResult>, | |
methodResponse: aws.apigateway.MethodResponse | |
): aws.apigateway.IntegrationResponse { | |
return new aws.apigateway.IntegrationResponse( | |
name, | |
{ | |
restApi: gateway.restAPI, | |
resourceId: methodResource.apply(x => x.id), | |
httpMethod: methodResponse.httpMethod, | |
statusCode: methodResponse.statusCode, | |
responseParameters: { | |
"method.response.header.Access-Control-Allow-Headers": | |
"'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'", | |
"method.response.header.Access-Control-Allow-Methods": | |
"'GET,OPTIONS,POST,PUT'", | |
"method.response.header.Access-Control-Allow-Origin": "'*'" | |
} | |
}, | |
{ parent } | |
); | |
} | |
export interface LambdaMethodExecutionArgs { | |
gateway: awsx.apigateway.API; | |
httpMethod: awsx.apigateway.Method; | |
path: string; | |
responseModel: aws.apigateway.Model; | |
} | |
export interface ApiRoute { | |
httpMethod: awsx.apigateway.Method; | |
path: string; | |
lambdaName: string; | |
responseModel?: aws.apigateway.Model; | |
} | |
export interface ApiArgs { | |
stageName: string; | |
datomicCompute: aws.cloudformation.Stack; | |
routes: ApiRoute[]; | |
} | |
export interface DatomicCloudArgs { | |
systemName: string; | |
applicationName: string; | |
environmentMap: string; | |
enableBastion: boolean; | |
keyName: string; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment