Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
loganpowell committed Oct 26, 2023
1 parent 1c4a7b6 commit 3fc1abc
Show file tree
Hide file tree
Showing 8 changed files with 969 additions and 955 deletions.
215 changes: 215 additions & 0 deletions examples/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
import { modulate, config, Provider, Terraform } from '../src/config'
import { AWS05200 as AWS } from '../registry/index'

import { rout53_zone, acm_cert, route53_record, acm_validation } from './route53'

// ,e,
// /~~~8e 888-~88e "
// 88b 888 888b 888
// e88~-888 888 8888 888
// C888 888 888 888P 888
// "88_-888 888-_88" 888
// 888
const api_domain = ({ subdomain = 'api', apex = 'chopshop-test.net', cert_arn }): AWS => ({
resource: {
apigatewayv2_domain_name: {
domain_name: `${subdomain}.${apex}`,
/**
* Block type "domain_name_configuration" is represented by a list
* of objects, so it must be indexed using a numeric key, like
* .domain_name_configuration[0]
*/
// @ts-ignore
domain_name_configuration: [
{
certificate_arn: cert_arn,
endpoint_type: 'REGIONAL',
security_policy: 'TLS_1_2',
target_domain_name: '-->',
hosted_zone_id: '-->',
},
],
tags: {
Name: `${subdomain}.${apex}`,
BroughtToYouBy: '@-0/micro',
},
},
},
})

const api_gateway = ({ name }): AWS => ({
resource: {
apigatewayv2_api: {
name,
description: `api for ${name}`,
disable_execute_api_endpoint: false,
protocol_type: 'HTTP',
cors_configuration: {
allow_headers: [
'content-type',
'x-amz-date',
'authorization',
'x-api-key',
'x-amz-security-token',
'x-amz-user-agent',
],
allow_methods: ['*'],
allow_origins: ['*'],
max_age: 300,
},
api_endpoint: '-->',
execution_arn: '-->',
id: '-->',
},
},
})

const api_stage = ({ api_id, name = '$default' }): AWS => ({
resource: {
apigatewayv2_stage: {
api_id,
name,
auto_deploy: true,
description: `stage ${name} API`,
},
},
})

const api_lambda_integration = ({ api_id, lambda_invoke_arn }): AWS => ({
resource: {
// @ts-ignore: 🐛 [3]
apigatewayv2_integration: {
api_id,
integration_uri: lambda_invoke_arn,
integration_type: 'AWS_PROXY',
integration_method: 'POST',
connection_type: 'INTERNET',
payload_format_version: '2.0',
timeout_milliseconds: 29000, // 30 sec max for HTTP, 29 for WebSockets
id: '-->',
},
},
})

const api_route = ({ api_id, route_key = 'ANY /', integration_id }): AWS => ({
resource: {
// @ts-ignore: 🐛 [2]
apigatewayv2_route: {
api_id,
route_key,
target: `integrations/${integration_id}`,
id: '-->',

//authorization_scopes: 'TODO',
//authorization_type: 'TODO',
//authorizer_id: 'TODO'
},
},
})

interface Subdomains {
[key: string]: {
[key: string]: {
invoke_arn: string
}
}
}
// 888 888 /~~88b
// 888-~88e-~88e e88~-_ e88~\888 888 888 888 e88~~8e | 888
// 888 888 888 d888 i d888 888 888 888 888 d888 88b ` d88P
// 888 888 888 8888 | 8888 888 888 888 888 8888__888 d88P
// 888 888 888 Y888 ' Y888 888 888 888 888 Y888 , d88P
// 888 888 888 "88_-~ "88_/888 "88_-888 888 "88___/ d88P___

/**
* subdomains module
*
* @param apex - apex domain name
* @param subdomains - array of subdomains
* - name - name of the subdomain
* - lambda_integration - lambda integration object
* - lambda_invoke_arn - arn of the lambda function to integrate
* - routes - array of routes
* - route object
* - route_key - route key
* - integration_id - id of the integration to use
* @param my - self reference for referencing other resources
*
*/
export const subdomains = (
{
apex = 'chopshop-test.net',
subdomainRoutes = {
test: {
'ANY /': {
invoke_arn: 'lambda_invoke_arn goes here 📌',
},
},
},
}: {
apex: string
subdomainRoutes: Subdomains
},
my: { [key: string]: AWS }
) => ({
zone: rout53_zone({ apex }), // 📌 outside module scope?
...Object.entries(subdomainRoutes).reduce(
(a, [sd, routes]) => ({
...a,
[`cert_${sd}`]: acm_cert({ apex, subdomain: sd }),
[`domain_${sd}`]: api_domain({
subdomain: sd,
apex,
cert_arn:
my?.[`validation_${sd}`]?.resource?.acm_certificate_validation?.certificate_arn,
}),
[`record_${sd}`]: route53_record({
route53_zone_id: my?.zone?.data?.route53_zone?.zone_id,
name: sd,
api_domain_name:
my?.[`domain_${sd}`]?.resource?.apigatewayv2_domain_name
?.domain_name_configuration[0]?.target_domain_name,
api_hosted_zone_id:
my?.[`domain_${sd}`]?.resource?.apigatewayv2_domain_name
?.domain_name_configuration[0]?.hosted_zone_id,
}),
[`record_valid_${sd}`]: route53_record({
route53_zone_id: my?.zone?.data?.route53_zone?.zone_id,
records: [
my?.[`cert_${sd}`]?.resource?.acm_certificate?.domain_validation_options[0]
?.resource_record_value,
],
name: my?.[`cert_${sd}`]?.resource?.acm_certificate?.domain_validation_options[0]
?.resource_record_name,
type: my?.[`cert_${sd}`]?.resource?.acm_certificate?.domain_validation_options[0]
?.resource_record_type,
}),
[`validation_${sd}`]: acm_validation({
cert_arn: my?.[`cert_${sd}`]?.resource?.acm_certificate?.arn,
fqdns: [my?.[`record_valid_${sd}`]?.resource?.route53_record?.fqdn],
}), // TODO
[`gateway_${sd}`]: api_gateway({ name: sd }),
[`stage_${sd}`]: api_stage({
api_id: my?.[`gateway_${sd}`]?.resource?.apigatewayv2_api?.id,
}),
...Object.entries(routes).reduce(
(acc, [route, { invoke_arn }]) => ({
...acc,
[`integration_${sd}_${route.split(' ')[0]}`]: api_lambda_integration({
api_id: my?.[`gateway_${sd}`]?.resource?.apigatewayv2_api?.id,
lambda_invoke_arn: invoke_arn,
}),
[`route_${sd}_${route.split(' ')[0]}`]: api_route({
api_id: my?.[`gateway_${sd}`]?.resource?.apigatewayv2_api?.id,
route_key: route,
integration_id:
my?.[`integration_${sd}_${route.split(' ')[0]}`]?.resource
?.apigatewayv2_integration?.id,
}),
}),
{}
),
}),
{}
),
})
120 changes: 120 additions & 0 deletions examples/example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { modulate, config, Provider, Terraform } from '../src/config'
import { AWS05200 as AWS } from '../registry/index'
import { lambda } from './lambda'
import { subdomains } from './api'

const provider: Provider = {
aws: {
region: 'us-east-2',
profile: 'chopshop',
},
}

const terraform: Terraform = {
required_providers: {
aws: {
source: 'hashicorp/aws',
version: '5.20.0',
},
},
}

/**
*
* my?.zone?.data?.route53_zone?.zone_id
*/

const module = modulate({ ms1: lambda })

const [mod_lambda, out_lambda] = module({ name: 'throwaway-test-123' })

const functionInvokeArn = out_lambda?.lambda?.resource?.lambda_function?.invoke_arn

const moduleAPI = modulate({ subdomains })

const [mod_api, out_api] = moduleAPI({
apex: 'chopshop-test.net',
subdomainRoutes: {
test1: {
'ANY /': {
invoke_arn: functionInvokeArn,
},
},
},
})

// ,e, 888 888
// e88~~\ e88~-_ 888-~88e-~88e 888-~88e " 888 e88~~8e e88~\888
// d888 d888 i 888 888 888 888 888b 888 888 d888 88b d888 888
// 8888 8888 | 888 888 888 888 8888 888 888 8888__888 8888 888
// Y888 Y888 ' 888 888 888 888 888P 888 888 Y888 , Y888 888
// "88__/ "88_-~ 888 888 888 888-_88" 888 888 "88___/ "88_/888
// 888

JSON.stringify(out_api, null, 4) //
JSON.stringify(mod_api, null, 4) //

const compiler = config(provider, terraform, 'main.tf.json')
const compiled = compiler(mod_lambda, mod_api)

JSON.stringify(compiled, null, 4) //?

/**
* References:
* [1]: https://dev.to/madflanderz/how-to-get-parts-of-an-typescript-interface-3mko
* [2]: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_route#argument-reference
* [3]: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_integration#response_parameters
* [4]: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function#lambda-file-systems
*/

// ~~~888~~~ ,88~-_ 888~-_ ,88~-_
// 888 d888 \ 888 \ d888 \
// 888 88888 | 888 | 88888 |
// 888 88888 | 888 | 88888 |
// 888 Y888 / 888 / Y888 /
// 888 `88_-~ 888_-~ `88_-~

// - add ability to add tags at the module level
// - missing tick_groups - (top three) in route53_record
// - EFSAccessPoint - missing `file_system_arn` (not in docs)
// - resource: { lambda_function: { file_system_config
// - topic: sns_topic(name), // 📌 outside module scope?
// - apigatewayv2_route 🐛 [2] `request_parameter_key` and `required` bug in docs (nested under section without heading)
// - apigatewayv2_integration: 🐛 [3] `status_code` and `mappings` bug in docs (nested under section without heading)

/**
* Outline of microservice module:
* - s3
* - bucket
* - sns
* - upstream topic (subscribed to by lambda)
* - downstream topic (published to by lambda)
* - lambda
* - environment variables
* - S3_BUCKET_NAME (for functions that need to read/write to s3)
* - SNS_TOPIC_ARN (downstream topic to publish to sns)
* - sns subscription (upstream topic)
* - filter policy
* - elastic file system (optional)
* - access point
* - mount target
* - api gateway (optional)
* - domain
* - subdomain
* - routes
* - methods
* - required iam permissions
* - lambda
* - s3
* - read/write
* - sns
* - publish
* - subscribe
* - cloudwatch
* - logs
* - metrics
* - sns
* - lambda (via AllowExecutionFromSNS)
* - api gateway (optional)
* - lambda (via AllowExecutionFromAPIGateway)
*/
Loading

0 comments on commit 3fc1abc

Please sign in to comment.