const { CfnOutput } = require('aws-cdk-lib')
const { Construct } = require('constructs')
const {
Instance,
InstanceType,
InstanceClass,
InstanceSize,
GenericLinuxImage,
Vpc,
SecurityGroup,
Peer,
Port,
UserData
} = require('aws-cdk-lib/aws-ec2')
const { HostedZone, ARecord, RecordTarget } = require('aws-cdk-lib/aws-route53')
const { Role, ServicePrincipal, Policy, PolicyStatement, Effect } = require('aws-cdk-lib/aws-iam')
const {
getInstallNodeJs,
getInstallNpm,
getInstallDocker
} = require('./user-data-commands')
const { CaddyService } = require('./caddy.service')
const { DeploymentToolsService } = require('./deployment-tools.service')
const { AwsProfile } = require('./aws-profile')
const { SupportedRegions } = require('../../config')
/**
* Platform template definition
* @namespace ContainerServer
* @typedef {Object} ContainerServerProps
* @property {PlatformConfig} platformConfig - platform config
* @property {Bucket} platformConfigBucket - aws bucket
*/
const InstanceImages = {
UBUNTU: 'ami-092cce4a19b438926'
}
/**
* @class
*/
class ContainerServer extends Construct {
/**
* EC2 Instance that docker containers are served on
*
* @param {object} scope - scope
* @param {string} id - id
* @param {ContainerServerProps} props - ContainerServerProps
*/
constructor(scope, id, props) {
super(scope, id)
const hostedZone = HostedZone.fromLookup(this, 'HostedZone', { domainName: props.platformConfig.domain })
const vpc = Vpc.fromLookup(this, 'VPC', {
isDefault: true
})
const securityGroup = new SecurityGroup(this, 'SecurityGroup', {
vpc,
allowAllOutbound: true
})
securityGroup.addIngressRule(
Peer.anyIpv4(),
Port.tcp(22),
'allow SSH access from anywhere'
)
securityGroup.addIngressRule(
Peer.anyIpv4(),
Port.tcp(80),
'allow HTTP traffic from anywhere'
)
securityGroup.addIngressRule(
Peer.anyIpv4(),
Port.tcp(443),
'allow HTTPS traffic from anywhere'
)
const role = new Role(this, 'role', {
assumedBy: new ServicePrincipal('ec2.amazonaws.com')
})
role.attachInlinePolicy(new Policy(this, 'policy', {
statements: [
new PolicyStatement({
effect: Effect.ALLOW,
actions: [
'route53:ListResourceRecordSets',
'route53:GetChange',
'route53:ChangeResourceRecordSets'
],
resources: [
`arn:aws:route53:::hostedzone/${hostedZone.hostedZoneId}`,
'arn:aws:route53:::change/*'
]
}),
new PolicyStatement({
effect: Effect.ALLOW,
actions: [
'route53:ListHostedZonesByName',
'route53:ListHostedZones'
],
resources: ['*']
})
]
}))
const userData = UserData.forLinux()
userData.addCommands(
'sudo apt update -y',
...getInstallNodeJs(),
...getInstallNpm(),
...getInstallDocker(),
'sudo apt-get install awscli --yes',
...AwsProfile.writeFile(role.roleArn, SupportedRegions.North),
...CaddyService.install(),
...DeploymentToolsService.install()
)
userData.addS3DownloadCommand({
bucket: props.platformConfigBucket,
bucketKey: 'platform-config.json',
localFile: '/home/ubuntu/platform-config.json'
})
userData.addCommands(
'sudo systemctl daemon-reload',
...CaddyService.enable(),
...DeploymentToolsService.enable(),
...CaddyService.start(),
...DeploymentToolsService.start()
)
const ec2Instance = new Instance(this, 'Ec2Instance', {
vpc,
securityGroup,
userData,
role,
instanceType: InstanceType.of(
InstanceClass.T3,
InstanceSize.MICRO
),
machineImage: new GenericLinuxImage({
[SupportedRegions.North]: InstanceImages.UBUNTU
}),
keyName: props.platformConfig.awsKeyPairName
})
props.platformConfigBucket.grantRead(ec2Instance, '*')
// const hostedZone = !!props.createNewHostedZone
// ? new PublicHostedZone(this, 'HostedZone', { zoneName: props.domain })
// : HostedZone.fromLookup(this, 'HostedZone', { domainName: props.domain });
// eslint-disable-next-line no-new
new ARecord(this, 'WildcardRecord', {
zone: hostedZone,
recordName: `*.${props.platformConfig.activeEnvironment}.${props.platformConfig.domain}`,
target: RecordTarget.fromIpAddresses(ec2Instance.instancePublicIp)
})
// eslint-disable-next-line no-new
new CfnOutput(this, 'Intance Ip', {
value: ec2Instance.instancePublicIp,
description: 'Public ip of the ec2 instance',
exportName: 'instanceIp'
})
}
}
module.exports = {
ContainerServer
}