Skip to content

Commit

Permalink
Migrate to CodeBuild batch. (aws#51)
Browse files Browse the repository at this point in the history
* Add batch build spec.

* Use batch-list.

* Remove invalid characters from identifier.

* Fix syntax warning.

* Upgrade cdk to latest version 1.64.

* Add github_codebuild_batch_stack.py.

* Move build specs.

* Refactor cdk code.

* Use aws-lc AWS account.

* Unify default values of env variable.

* Fix windows docker build issue.

* Add s3 bucket deletion when destroy resource.

* Add new variable github_source_version.

* Upgrade ec2 windows from 2016 to 2019.

* Add git to PATH.

* Revert "Upgrade ec2 windows from 2016 to 2019."

This reverts commit a72c367.

* Add 2019 windows.

* Move cyg and quilt installation to build spec.

* Add docker image build doc.

* Fix identifier name.

* Switch to 2016. CodeBuild does not support 2019.

* Clean up and add more docs.

* Fix typo.

* Modify README.md

* Remove '*'.

* Change privileged-mode to false.

* ARM sanitizer needs privileged-mode.
  • Loading branch information
bryce-shang committed Oct 20, 2020
1 parent 0e225e0 commit ba6cd6e
Show file tree
Hide file tree
Showing 23 changed files with 660 additions and 464 deletions.
65 changes: 60 additions & 5 deletions tests/ci/cdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ To setup or update the CI in your account you will need the following IAM permis
* codebuild:Create*
* codebuild:Update*
* codebuild:Batch*
* codebuild:StartBuild
* codebuild:StopBuild
* codebuild:RetryBuild
* EC2
* ec2:Describe*
* ec2:Create*
Expand Down Expand Up @@ -86,17 +89,15 @@ Below is CI file structure.
├── cdk
│   ├── __init__.py
│   ├── ecr_stack.py
│   ├── github_codebuild_stack.py
│   ├── linux_docker_images_build_stack.py
│   ├── windows_docker_build_ssm_document.yaml
│   └── windows_docker_image_build_stack.py
│   ├── ...
├── cdk.json
├── requirements.txt
├── run-cdk.sh
├── setup.py
└── util
├── __init__.py
└── util.py
└── env_util.py
└── ...
```
* `README.md` — The introductory README for this project.
* `app.py` — The “main” for this sample application.
Expand Down Expand Up @@ -158,3 +159,57 @@ command.
* `cdk deploy` deploy this stack to your default AWS account/region
* `cdk diff` compare deployed stack with current state
* `cdk docs` open CDK documentation

### Useful Docker image build commands

**Notes**:
* below commands replicate steps that are performed in `run-cdk.sh` but use default values set in `cdk/util/metadata.py`.
* Always clean up resources set up for Docker image build.
* `cdk destroy aws-lc-docker-image-build-* --force`

#### Linux Docker image build

```bash
# Launch Linux Docker image CodeBuild resources.
cdk deploy aws-lc-docker-image-build-linux --require-approval never

# Trigger CodeBuild to build Linux Docker Images
aws codebuild start-build-batch --project-name aws-lc-docker-image-build-linux

# Go to AWS console, you can check CodeBuild by clicking "Developer Tools > CodeBuild > Build projects".
```

#### Windows Docker image build
Windows docker image build requires more resources (like EC2 host, S3, SSM and so on) set up because DIND (Docker in Docker) is not supported by Windows.
Below are some commands specific to windows docker image build.

```bash
# Define environment variables needed by Windows docker image build.
export DATE_NOW="$(date +%Y-%m-%d-%H-%M)"
export S3_FOR_WIN_DOCKER_IMG_BUILD="${AWS_LC_S3_BUCKET_PREFIX}-${DATE_NOW}"
export WIN_EC2_TAG_KEY="aws-lc"
export WIN_EC2_TAG_VALUE="aws-lc-windows-docker-image-build-${DATE_NOW}"
export WIN_DOCKER_BUILD_SSM_DOCUMENT="windows-ssm-document-${DATE_NOW}"

# Clean up all Windows docker image build resources.
cdk destroy aws-lc-docker-image-build-windows --force
aws s3 rm "s3://${S3_FOR_WIN_DOCKER_IMG_BUILD}" --recursive
aws s3api delete-bucket --bucket "${S3_FOR_WIN_DOCKER_IMG_BUILD}"

# Deploy Windows docker image build resources.
cdk deploy aws-lc-docker-image-build-windows --require-approval never

# Sleep 10 minutes so Windows EC2 is ready to execute SSM commands.
sleep 600

# Trigger SSM commands to build Windows Docker Images.
instance_id=$(aws ec2 describe-instances \
--filters "Name=tag:${WIN_EC2_TAG_KEY},Values=${WIN_EC2_TAG_VALUE}" | jq -r '.Reservations[0].Instances[0].InstanceId')
aws ssm send-command \
--instance-ids "${instance_id}" \
--document-name "${WIN_DOCKER_BUILD_SSM_DOCUMENT}" \
--output-s3-bucket-name "${S3_FOR_WIN_DOCKER_IMG_BUILD}" \
--output-s3-key-prefix 'ssm-runcommand-logs'

# Go to AWS console, you can check run command by clicking `AWS Systems Manager > Run Command`.
```
165 changes: 12 additions & 153 deletions tests/ci/cdk/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,170 +5,29 @@

from aws_cdk import core

from cdk.github_codebuild_stack import GitHubCodeBuildStack
from cdk.linux_docker_images_build_stack import LinuxDockerImagesBuildStack
from cdk.aws_lc_github_ci_stack import AwsLcGitHubCIStack
from cdk.linux_docker_image_batch_build_stack import LinuxDockerImageBatchBuildStack
from cdk.windows_docker_image_build_stack import WindowsDockerImageBuildStack
from cdk.ecr_stack import EcrStack
from util.util import EnvUtil
from util.metadata import LINUX_X86_ECR_REPO, LINUX_AARCH_ECR_REPO, WINDOWS_ECR_REPO

# Initialize app.
app = core.App()

# Fetch environment variables.
aws_account = EnvUtil.get("CDK_DEPLOY_ACCOUNT", "620771051181")
aws_region = EnvUtil.get("CDK_DEPLOY_REGION", "us-west-2")
env = {"account": aws_account, "region": aws_region}

# Define AWS ECR stacks.
# ECR holds the docker images, which are pre-built to accelerate the code builds/tests of git pull requests.
linux_aarch_ecr_repo = EnvUtil.get("ECR_LINUX_AARCH_REPO_NAME", "aws-lc-test-docker-images-linux-aarch")
linux_x86_ecr_repo = EnvUtil.get("ECR_LINUX_X86_REPO_NAME", "aws-lc-test-docker-images-linux-x86")
windows_ecr_repo = EnvUtil.get("ECR_WINDOWS_REPO_NAME", "aws-lc-test-docker-images-windows")
EcrStack(app, linux_aarch_ecr_repo, env=env)
EcrStack(app, linux_x86_ecr_repo, env=env)
EcrStack(app, windows_ecr_repo, env=env)
EcrStack(app, "aws-lc-ecr-linux-x86", LINUX_X86_ECR_REPO)
EcrStack(app, "aws-lc-ecr-linux-aarch", LINUX_AARCH_ECR_REPO)
EcrStack(app, "aws-lc-ecr-windows", WINDOWS_ECR_REPO)

# Define CodeBuild Batch job for testing code.
LinuxDockerImageBatchBuildStack(app, "aws-lc-docker-image-build-linux")

# Define stacks used to build Docker images.
linux_docker_img_build_stacks = [
{
"id": "aws-lc-test-docker-images-build-linux-aarch",
"repo_name": linux_aarch_ecr_repo,
"env_type": "ARM",
"build_spec": "linux-aarch-docker-img-build.yml"
},
{
"id": "aws-lc-test-docker-images-build-linux-x86",
"repo_name": linux_x86_ecr_repo,
"env_type": "Linux",
"build_spec": "linux-x86-docker-img-build.yml"
}
]
code_build_dir = "./tests/ci/codebuild"
for stack in linux_docker_img_build_stacks:
LinuxDockerImagesBuildStack(app, stack["id"], stack["repo_name"],
"./tests/ci/codebuild/{}".format(stack["build_spec"]), env_type=stack["env_type"],
env=env)
# DIND is not supported on Windows and, therefore, AWS CodeBuild is not used to build Windows Server container images.
# Windows Docker images are created by running commands in Windows EC2 instance.
WindowsDockerImageBuildStack(app, "aws-lc-test-docker-images-build-windows", windows_ecr_repo, env=env)
WindowsDockerImageBuildStack(app, "aws-lc-docker-image-build-windows")

# Define CodeBuild stacks used to run test cases.
is_windows = True
# Define CodeBuild running on Linux aarch.
linux_aarch_test_stacks = [
{
"id": "aws-lc-test-ubuntu-19-10--gcc-9x",
"img": "ubuntu-19.10_gcc-9x_latest",
"spec": "ubuntu-19.10_gcc-9x_aarch64.yml",
},
{
"id": "aws-lc-test-ubuntu-19-10--clang-9x",
"img": "ubuntu-19.10_clang-9x_latest",
"spec": "ubuntu-19.10_clang-9x_aarch64.yml",
},
]
for stack in linux_aarch_test_stacks:
GitHubCodeBuildStack(app, stack["id"], linux_aarch_ecr_repo, stack["img"],
"./tests/ci/codebuild/{}".format(stack["spec"]), env_type="ARM", privileged=True, env=env)
# Define CodeBuild running on Linux x86-64.
linux_x86_test_stacks = [
{
"id": "aws-lc-test-pre-push",
"img": "ubuntu-18.04_gcc-7x_latest",
"spec": "pre-push.yml",
},
{
"id": "aws-lc-test-ubuntu-16-04--gcc-5x--x86",
"img": "ubuntu-16.04_gcc-5x_latest",
"spec": "ubuntu-16.04_gcc-5x_x86.yml",
},
{
"id": "aws-lc-test-ubuntu-18-04--clang-6x--x86-64",
"img": "ubuntu-18.04_clang-6x_latest",
"spec": "ubuntu-18.04_clang-6x_x86-64.yml",
},
{
"id": "aws-lc-test-ubuntu-18-04--gcc-7x--x86-64",
"img": "ubuntu-18.04_gcc-7x_latest",
"spec": "ubuntu-18.04_gcc-7x_x86-64.yml",
},
{
"id": "aws-lc-test-ubuntu-19-10--gcc-9x--x86-64",
"img": "ubuntu-19.10_gcc-9x_latest",
"spec": "ubuntu-19.10_gcc-9x_x86-64.yml",
},
{
"id": "aws-lc-test-ubuntu-19-10--clang-9x--x86-64",
"img": "ubuntu-19.10_clang-9x_latest",
"spec": "ubuntu-19.10_clang-9x_x86-64.yml",
},
{
"id": "aws-lc-test-ubuntu-19-04--gcc-8x--x86-64",
"img": "ubuntu-19.04_gcc-8x_latest",
"spec": "ubuntu-19.04_gcc-8x_x86-64.yml",
},
{
"id": "aws-lc-test-ubuntu-19-04--clang-8x--x86-64",
"img": "ubuntu-19.04_clang-8x_latest",
"spec": "ubuntu-19.04_clang-8x_x86-64.yml",
},
{
"id": "aws-lc-test-centos-7--gcc-4x--x86",
"img": "centos-7_gcc-4x_latest",
"spec": "centos-7_gcc-4x-x86.yml",
},
{
"id": "aws-lc-test-centos-7--gcc-4x--x86-64",
"img": "centos-7_gcc-4x_latest",
"spec": "centos-7_gcc-4x-x86-64.yml",
},
{
"id": "aws-lc-test-amazonlinux-2--gcc-7x--x86-64",
"img": "amazonlinux-2_gcc-7x_latest",
"spec": "amazonlinux-2_gcc-7x-x86-64.yml",
},
{
"id": "aws-lc-test-s2n--integration",
"img": "s2n_integration_clang-9x_latest",
"spec": "s2n_integration.yml",
},
{
"id": "aws-lc-test-fedora-31--gcc-9x",
"img": "fedora-31_gcc-9x_latest",
"spec": "fedora-31_gcc-9x_x86-64.yml",
},
{
"id": "aws-lc-test-fedora-31--clang-9x",
"img": "fedora-31_clang-9x_latest",
"spec": "fedora-31_clang-9x_x86-64.yml",
},
]
for stack in linux_x86_test_stacks:
GitHubCodeBuildStack(app, stack["id"], linux_x86_ecr_repo, stack["img"],
"./tests/ci/codebuild/{}".format(stack["spec"]), privileged=True, env=env)
# Define CodeBuild for sanitizer tests.
linux_sanitizer_test_stacks = [
{
"id": "aws-lc-test-ubuntu-19-10--clang-9x--sanitizer",
"img": "ubuntu-19.10_clang-9x_sanitizer_latest",
"spec": "ubuntu-19.10_clang-9x_aarch64_sanitizer.yml",
"env_type": "ARM",
"repo": linux_aarch_ecr_repo,
},
{
"id": "aws-lc-test-ubuntu-19-10--clang-9x--x86-64--sanitizer",
"img": "ubuntu-19.10_clang-9x_sanitizer_latest",
"spec": "ubuntu-19.10_clang-9x_x86-64_sanitizer.yml",
"env_type": "Linux",
"repo": linux_x86_ecr_repo,
},
]
for stack in linux_sanitizer_test_stacks:
GitHubCodeBuildStack(app, stack["id"], stack["repo"], stack["img"],
"./tests/ci/codebuild/{}".format(stack["spec"]), env_type=stack["env_type"], privileged=True,
env=env)
# Define CodeBuild running on Windows.
GitHubCodeBuildStack(app, "aws-lc-test-windows-msvc2015-x64--vs2015", windows_ecr_repo, "vs2015_latest",
"./tests/ci/codebuild/windows-msvc2015-x64.yml", env_type="Windows", env=env)
# Define CodeBuild Batch job for testing code.
AwsLcGitHubCIStack(app, "aws-lc-ci")

app.synth()
75 changes: 75 additions & 0 deletions tests/ci/cdk/cdk/aws_lc_github_ci_stack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

from aws_cdk import core, aws_codebuild as codebuild, aws_iam as iam
from util.iam_policies import codebuild_batch_policy_in_json
from util.metadata import AWS_ACCOUNT, AWS_REGION, GITHUB_REPO_OWNER, GITHUB_REPO_NAME, LINUX_X86_ECR_REPO, \
LINUX_AARCH_ECR_REPO, WINDOWS_ECR_REPO
from util.yml_loader import YmlLoader


class AwsLcGitHubCIStack(core.Stack):
"""Define a stack used to batch execute AWS-LC tests in GitHub."""

def __init__(self,
scope: core.Construct,
id: str,
**kwargs) -> None:
super().__init__(scope, id, **kwargs)

# Define CodeBuild resource.
git_hub_source = codebuild.Source.git_hub(
owner=GITHUB_REPO_OWNER,
repo=GITHUB_REPO_NAME,
webhook=True,
webhook_filters=[
codebuild.FilterGroup.in_event_of(
codebuild.EventAction.PULL_REQUEST_CREATED,
codebuild.EventAction.PULL_REQUEST_UPDATED,
codebuild.EventAction.PULL_REQUEST_REOPENED)
],
clone_depth=1)

# Define a IAM role for this stack.
codebuild_batch_policy = iam.PolicyDocument.from_json(
codebuild_batch_policy_in_json([id])
)
inline_policies = {"codebuild_batch_policy": codebuild_batch_policy}
role = iam.Role(scope=self,
id="{}-role".format(id),
assumed_by=iam.ServicePrincipal("codebuild.amazonaws.com"),
inline_policies=inline_policies,
managed_policies=[
iam.ManagedPolicy.from_aws_managed_policy_name("AmazonEC2ContainerRegistryReadOnly")
])

# Create build spec.
placeholder_map = {"AWS_ACCOUNT_ID_PLACEHOLDER": AWS_ACCOUNT, "AWS_REGION_PLACEHOLDER": AWS_REGION,
"ECR_REPO_X86_PLACEHOLDER": LINUX_X86_ECR_REPO,
"ECR_REPO_AARCH_PLACEHOLDER": LINUX_AARCH_ECR_REPO,
"ECR_REPO_WINDOWS_PLACEHOLDER": WINDOWS_ECR_REPO}
build_spec_content = YmlLoader.load("./cdk/codebuild/github_build_omnibus.yaml", placeholder_map)

# Define CodeBuild.
project = codebuild.Project(
scope=self,
id=id,
project_name=id,
source=git_hub_source,
role=role,
timeout=core.Duration.minutes(120),
environment=codebuild.BuildEnvironment(compute_type=codebuild.ComputeType.SMALL,
privileged=False,
build_image=codebuild.LinuxBuildImage.STANDARD_4_0),
build_spec=codebuild.BuildSpec.from_object(build_spec_content))

# TODO: add build type BUILD_BATCH when CFN finishes the feature release. See CryptoAlg-575.

# Add 'BuildBatchConfig' property, which is not supported in CDK.
# CDK raw overrides: https://docs.aws.amazon.com/cdk/latest/guide/cfn_layer.html#cfn_layer_raw
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codebuild-project.html#aws-resource-codebuild-project-properties
cfn_build = project.node.default_child
cfn_build.add_override("Properties.BuildBatchConfig", {
"ServiceRole": role.role_arn,
"TimeoutInMins": 120
})
Loading

0 comments on commit ba6cd6e

Please sign in to comment.