Skip to content

Instantly share code, notes, and snippets.

@phobologic
Created August 17, 2018 21:55
Show Gist options
  • Save phobologic/fa1681e3fc2e78ecd8e5cda1004a390e to your computer and use it in GitHub Desktop.
Save phobologic/fa1681e3fc2e78ecd8e5cda1004a390e to your computer and use it in GitHub Desktop.
from awacs.aws import Policy
from awacs.helpers.trust import (
make_service_domain_name,
make_simple_assume_policy,
)
from troposphere import (
codebuild,
ecr,
iam,
)
from troposphere import (
NoValue,
Sub,
)
from stacker.blueprints.base import Blueprint
from stacker_blueprints.policies import (
cloudwatch_logs_write_statements,
)
from .policies import (
ecr_repo_publisher_statements,
ecr_repo_client_statements,
)
def codebuild_assumerole_policy():
return make_simple_assume_policy(make_service_domain_name("codebuild"))
repo_str = (
"${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ProjectName}"
)
DOCKER_BUILD_SPEC = """
version: 0.2
env:
variables:
DOCKER_REPO: "%(repo_string)s"
phases:
pre_build:
commands:
- echo [`date`] Logging in to Amazon ECR
- $(aws ecr get-login --no-include-email --region ${AWS::Region})
- docker pull $DOCKER_REPO:latest || true
build:
commands:
- echo [`date`] Building the Docker image
- docker build --cache-from $DOCKER_REPO:latest -t \
$DOCKER_REPO:$(git rev-parse --short HEAD) \
-t $DOCKER_REPO:latest .
post_build:
commands:
- echo [`date`] Build completed
- echo [`date`] Pushing the Docker image...
- docker push $DOCKER_REPO
""" % {"repo_string": repo_str}
class DockerImageCreator(Blueprint):
VARIABLES = {
"GithubRepo": {
"type": str,
"description": "The short github repo name, ie: modsy/www.",
},
"Environment": {
"type": dict,
"description": "Environment variables to set in the build.",
"default": {},
},
"ComputeType": {
"type": str,
"description": "Compute type to use for codebuild. Default: "
"BUILD_GENERAL1_SMALL",
"default": "BUILD_GENERAL1_SMALL",
},
}
@property
def github_repo(self):
return self.get_variables()["GithubRepo"]
@property
def ecr_repo(self):
return self.github_repo.split("/")[-1]
@property
def environment(self):
env_dict = self.get_variables()["Environment"]
if not env_dict:
return NoValue
env_list = []
# Sort it first to avoid dict sort issues on different machines
sorted_env = sorted(env_dict.items(), key=lambda pair: pair[0])
for k, v in sorted_env:
env_list.append(codebuild.Environment(Name=str(k), Value=str(v)))
return env_list
@property
def compute_type(self):
return self.get_variables()["ComputeType"]
def create_role(self):
t = self.template
self.role = t.add_resource(
iam.Role(
"Role",
AssumeRolePolicyDocument=codebuild_assumerole_policy(),
Path="/",
)
)
self.add_output("RoleName", self.role.Ref())
self.add_output("RoleArn", self.role.GetAtt("Arn"))
self.add_output("RoleId", self.role.GetAtt("RoleId"))
def generate_policy_statements(self):
statements = cloudwatch_logs_write_statements()
repo_arn = self.repository.GetAtt("Arn")
statements.extend(
ecr_repo_publisher_statements(repo_arn)
)
statements.extend(
ecr_repo_client_statements("*")
)
return statements
def generate_policy_document(self):
return Policy(
Statement=self.generate_policy_statements(),
Version="2012-10-17",
)
def create_role_policy(self):
t = self.template
self.role_policy = t.add_resource(
iam.ManagedPolicy(
"ManagedPolicy",
PolicyDocument=self.generate_policy_document(),
Roles=[self.role.Ref()],
)
)
self.add_output("ManagedPolicyArn", self.role_policy.Ref())
def generate_lifecycle_policy(self):
return NoValue
def create_ecr_repo(self):
t = self.template
self.repository = t.add_resource(
ecr.Repository(
"Repository",
RepositoryName=self.ecr_repo,
LifecyclePolicy=self.generate_lifecycle_policy(),
),
)
self.add_output("RepositoryId", self.repository.Ref())
self.add_output("RepositoryArn", self.repository.GetAtt("Arn"))
def create_project(self):
t = self.template
build_spec = Sub(DOCKER_BUILD_SPEC, ProjectName=self.ecr_repo)
self.project = t.add_resource(
codebuild.Project(
"Project",
Name=self.github_repo.replace("/", "-"),
Artifacts=codebuild.Artifacts(
Type="NO_ARTIFACTS",
),
BadgeEnabled=True,
Environment=codebuild.Environment(
ComputeType=self.compute_type,
Image="aws/codebuild/docker:17.09.0",
Type="LINUX_CONTAINER",
EnvironmentVariables=self.environment
),
ServiceRole=self.role.GetAtt("Arn"),
Source=codebuild.Source(
Type="GITHUB",
Location="https://github.com/%s" % self.github_repo,
BuildSpec=build_spec,
),
Triggers=codebuild.ProjectTriggers(
Webhook=True,
),
)
)
self.add_output("ProjectId", self.project.Ref())
self.add_output("ProjectArn", self.project.GetAtt("Arn"))
def create_template(self):
self.create_ecr_repo()
self.create_role()
self.create_role_policy()
self.create_project()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment