Skip to content

Commit

Permalink
Added a Terraform HCL pipeline to deploy CloudFront with S3 backend (#28
Browse files Browse the repository at this point in the history
)

Add Cloudfront distro from React app and Jest test.
  • Loading branch information
cabeaulac authored Feb 14, 2024
1 parent 3a508dd commit 7e78b94
Show file tree
Hide file tree
Showing 43 changed files with 877 additions and 104 deletions.
8 changes: 5 additions & 3 deletions .github/workflows/weekly_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ on:
pull_request:
branches:
- '*'
env:
LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }}
CACHE_TYPE: gha

jobs:
test:
Expand All @@ -19,7 +22,7 @@ jobs:
concurrency: 1
strategy:
matrix:
test_name: [ awscdk, awscdktf ]
test_name: [ awscdk, awscdktf, cloudfront-tf ]
steps:
# Checkout code
- name: Checkout code
Expand All @@ -32,12 +35,11 @@ jobs:
# Start Localstack
- name: Test
env:
LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }}
CI_TEST_NAME: ${{ matrix.test_name }}
run: |
# Unset stale org secret
printenv
unset LOCALSTACK_API_KEY
echo "Starting Localstack and running tests"
make run-ci-test
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,11 @@ output.txt

.terraform*
terraform.tfstate*
*.auto.tfvars
*.tfplan
errored.tfstate
nonenv.makefile
terraform_output.json

!devops-tooling/accounts/non-demo.json
!devops-tooling/accounts/localstack.json
Expand Down
19 changes: 15 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ Features deploying a VPC, Private Application Load Balancer (ALB), and Lambda.

![ALB Solution](./docs/img/solution-diags-priv-alb.drawio.png "ALB Solution")

## Cloudfront S3 Static Website Solution with Jest Test

Features deploying a Cloudfront distribution, S3 bucket, and a React web app.
Checkout the test [here](./auto_tests/jest/cloudfront.test.ts).
The Terraform pipeline is [here](./iac/terraform/hcl/react-ui/main.tf).

![Cloudfront Solution](./docs/img/solution-diags-cloudfront-jest.drawio.png "Cloudfront Solution")

## Private Jumphost on Private VPC Subnet Solution

Features using private jumphost in private VPC for secure access to protected resources.
Expand All @@ -42,7 +50,6 @@ To deploy your infrastructure, follow the steps below.

### Prerequisites


1. [Install unzip](https://www.tecmint.com/install-zip-and-unzip-in-linux/)

2. [Install LATEST AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
Expand All @@ -68,11 +75,14 @@ nvm install 18
npm install --global cdktf-cli@^0.18.0
```

9. Install `make`, `gcc`, `g++`, etc. For MacOS, run `brew install make gcc openssl readline sqlite3 xz` and for Ubuntu machines run `apt install build-essential libbz2-dev libssl-dev libreadline-dev libffi-dev zlib1g-dev libsqlite3-dev liblzma-dev`.
9. Install `make`, `gcc`, `g++`, etc. For MacOS, run `brew install make gcc openssl readline sqlite3 xz` and for Ubuntu
machines
run `apt install build-essential libbz2-dev libssl-dev libreadline-dev libffi-dev zlib1g-dev libsqlite3-dev liblzma-dev`.

10. Install `zlib1g-dev`. For MacOS, run `xcode-select --install` and for Ubuntu machines run `apt install zlib1g-dev`.

11. [Install Pyenv](https://github.com/pyenv/pyenv#installation). Make sure the [prerequisites](https://github.com/pyenv/pyenv/wiki/Common-build-problems#prerequisites) are also there.
11. [Install Pyenv](https://github.com/pyenv/pyenv#installation). Make sure
the [prerequisites](https://github.com/pyenv/pyenv/wiki/Common-build-problems#prerequisites) are also there.

### Steps

Expand Down Expand Up @@ -153,7 +163,8 @@ export CI_TEST_NAME=awscdk make run-ci-test
export CI_TEST_NAME=awscdktf make run-ci-test
```
***Note: If you run the above tests with Rosetta turned on, and still want to go with `arm64`, you need to export `export OVERRIDE_LOCAL_ARCH=arm64`.***
***Note: If you run the above tests with Rosetta turned on, and still want to go with `arm64`, you need to
export `export OVERRIDE_LOCAL_ARCH=arm64`.***
# Hot Reloading!
Expand Down
22 changes: 22 additions & 0 deletions auto_tests/jest/cloudfront.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as path from 'path'
import {loadAndExtractCloudfrontDomain} from './helpers'

const filePath = path.resolve(__dirname, '../../iac/terraform/hcl/react-ui/terraform_output.json')

// Example usage
const cloudfrontDomain = loadAndExtractCloudfrontDomain(filePath)
const CLOUDFRONT_URL = `https://${cloudfrontDomain}`

test('CloudFront distribution test', async () => {

try {
await page.goto(CLOUDFRONT_URL, {waitUntil: 'networkidle2'})

// Assuming your default React content has a specific string
const content = await page.content()
expect(content).toContain('Web site created using create-react-app')
} catch (error: any) {
console.error('Error during test:', error.message)
throw error
}
})
17 changes: 17 additions & 0 deletions auto_tests/jest/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import fs from "fs"
import TerraformOutput from "./types"

export const loadAndExtractCloudfrontDomain = (filePath: string): string | null => {
try {
const fileContent = fs.readFileSync(filePath, 'utf-8')
const terraformOutput: TerraformOutput = JSON.parse(fileContent)
// Extract cloudfront_domain_name.value
const cloudfrontDomainValue = terraformOutput?.cloudfront_domain_name?.value

return cloudfrontDomainValue || null
} catch (error: any) {
console.error('Error loading or parsing JSON file:', error.message)
return null
}
}

7 changes: 7 additions & 0 deletions auto_tests/jest/jest-puppeteer.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/** @type {import('jest-environment-puppeteer').JestPuppeteerConfig} */
module.exports = {
// Don't use a sandbox in CI, to avoid issues with permissions
launch: {
args: ['--no-sandbox', '--disable-setuid-sandbox'],
},
}
6 changes: 6 additions & 0 deletions auto_tests/jest/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
preset: 'ts-jest',
"globalSetup": "jest-environment-puppeteer/setup",
"globalTeardown": "jest-environment-puppeteer/teardown",
"testEnvironment": "jest-environment-puppeteer"
}
17 changes: 17 additions & 0 deletions auto_tests/jest/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "jest-tests",
"version": "0.1.0",
"devDependencies": {
"@types/jest": "^29.5.12",
"axios": "^1.6.7",
"jest": "^29.7.0",
"jest-puppeteer": "^10.0.0",
"puppeteer": "^22.0.0",
"ts-jest": "^29.1.2",
"typescript": "^5.3.3"
},
"dependencies": {
"@types/jest-environment-puppeteer": "^5.0.6",
"jest-environment-puppeteer": "^10.0.0"
}
}
14 changes: 14 additions & 0 deletions auto_tests/jest/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"isolatedModules": true,
"jsx": "react"
}
}

9 changes: 9 additions & 0 deletions auto_tests/jest/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
interface TerraformOutput {
cloudfront_domain_name: {
sensitive: boolean;
type: string;
value: string;
};
}

export default TerraformOutput
17 changes: 9 additions & 8 deletions devops-tooling/ci/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,9 @@ RUN apt-get update
RUN apt-get install -fy --fix-missing docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

ARG AWS_VERSION=2.15.12
RUN /bin/bash -c 'if [ "${USE_AWS}" = "yes" ] ; then \
set -ex && \
ARCHITECTURE=`uname -m` && \
if [ "ARCHITECTURE" = "x86_64" ]; then \
RUN /bin/bash -c ' set -ex && \
ARCH=$(uname -m | sed "s/amd64/x86_64/") && \
if [ "$ARCH" = "x86_64" ]; then \
echo "aws x86_64" && \
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64-${AWS_VERSION}.zip" -o "awscliv2.zip" && \
curl "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/ubuntu_64bit/session-manager-plugin.deb" -o "session-manager-plugin.deb" && \
Expand All @@ -52,7 +51,7 @@ RUN /bin/bash -c 'if [ "${USE_AWS}" = "yes" ] ; then \
unzip -q "awscliv2.zip" && ./aws/install && rm awscliv2.zip && \
dpkg -i session-manager-plugin.deb && rm ./session-manager-plugin.deb; \
apt install -fy --fix-missing --no-install-recommends amazon-ecr-credential-helper; \
fi'
'

# if bitwarden is enabled so will node
ARG NODE_VERSION=20
Expand All @@ -77,7 +76,6 @@ RUN /bin/bash -c 'if [ "${USE_CDK}" = "yes" ] ; then \
npm -g i aws-cdk-local@latest aws-cdk@latest; \
fi'

ARG TERRAFORM_VERSION

# terraform is installed
RUN /bin/bash -c 'set -ex; \
Expand All @@ -89,18 +87,21 @@ RUN /bin/bash -c 'set -ex; \
COPY devops-tooling/ci/setup.sh /tmp/setup.sh
RUN chmod +x /tmp/setup.sh && /tmp/setup.sh

# copy awssdk
# copy test scripts
COPY devops-tooling/ci/awscdk.sh /usr/local/bin/awscdk
RUN chmod +x /usr/local/bin/awscdk

COPY devops-tooling/ci/awscdktf.sh /usr/local/bin/awscdktf
RUN chmod +x /usr/local/bin/awscdktf
COPY devops-tooling/ci/cloudfront-tf.sh /usr/local/bin/cloudfront-tf
RUN chmod +x /usr/local/bin/cloudfront-tf

# copy bootstrap script
COPY devops-tooling/ci/bootstrap.sh /usr/local/bin/bootstrap
RUN chmod +x /usr/local/bin/bootstrap

COPY devops-tooling/requirements.txt /tmp/requirements.txt

#CMD exec /bin/bash -c "trap : TERM INT; sleep infinity & wait"

ENTRYPOINT ["/bin/bash"]
CMD ["bootstrap"]
34 changes: 34 additions & 0 deletions devops-tooling/ci/cloudfront-tf.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/bin/bash

# Exit immediately if a command exits with a non-zero status
set -e

# Setup NVM and Node.js
. /usr/local/nvm/nvm.sh use 20

# Create AWS config/credentials
make setup-aws

echo "ARCHITECTURE is '$(uname -m)'"
echo "AWS Version is $(aws --version)"

export AWS_PROFILE=localstack
export AWS_CONFIG_FILE=/root/.aws/config
export AWS_SHARED_CREDENTIALS_FILE=/root/.aws/credentials

# The endpoint is not getting picked up from the profile in the config file.
export AWS_ENDPOINT_URL="http://localhost.localstack.cloud:4566"

# Setup Terraform stacks
make local-tf-create-iac-bucket
make local-tf-cfs3-init
make local-tf-cfs3-plan
make local-tf-cfs3-apply
make local-tf-cfs3-output
# Test Terraform stacks
make --silent local-tf-cfs3-test

curl -X POST \
-H "Content-Type: application/json" \
-d '{"action": "kill"}' \
http://localhost.localstack.cloud:4566/_localstack/health
39 changes: 39 additions & 0 deletions devops-tooling/ci/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,45 @@ apt-get update && apt-get install -y \
gnupg2 \
jq

# Install puppeteer dependencies
apt-get install -y \
ca-certificates \
fonts-liberation \
libasound2 \
libatk-bridge2.0-0 \
libatk1.0-0 \
libc6 \
libcairo2 \
libcups2 \
libdbus-1-3 \
libexpat1 \
libfontconfig1 \
libgbm1 \
libgcc1 \
libglib2.0-0 \
libgtk-3-0 \
libnspr4 \
libnss3 \
libpango-1.0-0 \
libpangocairo-1.0-0 \
libstdc++6 \
libx11-6 \
libx11-xcb1 \
libxcb1 \
libxcomposite1 \
libxcursor1 \
libxdamage1 \
libxext6 \
libxfixes3 \
libxi6 \
libxrandr2 \
libxrender1 \
libxss1 \
libxtst6 \
lsb-release \
wget \
xdg-utils


# Setup NVM and Node.js
. /usr/local/nvm/nvm.sh use 20
Expand Down
6 changes: 6 additions & 0 deletions devops-tooling/docker-compose.ci_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ services:
build:
context: ..
dockerfile: devops-tooling/ci/Dockerfile
cache_to:
- type=${CACHE_TYPE},mode=max
cache_from:
- type=${CACHE_TYPE}

environment:
- MAPPING_DIR_NAME=${MAPPING_DIR_NAME}
- CI_TEST_NAME=${CI_TEST_NAME}
Expand All @@ -18,6 +23,7 @@ services:
- ../makefile:${MAPPING_DIR_NAME}/makefile
- ../run-lambdas.sh:${MAPPING_DIR_NAME}/run-lambdas.sh
- ../src:${MAPPING_DIR_NAME}/src
- ../ui:${MAPPING_DIR_NAME}/ui
depends_on:
- localhost.localstack.cloud
network_mode: "service:localhost.localstack.cloud"
1 change: 1 addition & 0 deletions devops-tooling/docker-compose.localstack.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ services:
- DEBUG=1 # turn debug output on
- ENFORCE_IAM=${ENFORCE_IAM-1} # Enable IAM policy evaluation and enforcement
- EXTRA_CORS_ALLOWED_ORIGINS=*
- PERSISTENCE=0 # Disable persistence
- LAMBDA_RUNTIME_ENVIRONMENT_TIMEOUT=90
- LOCALSTACK_AUTH_TOKEN=${LOCALSTACK_AUTH_TOKEN-}
- DOCKER_HOST=unix:///var/run/docker.sock
Expand Down
Loading

0 comments on commit 7e78b94

Please sign in to comment.