Created
August 17, 2018 21:55
-
-
Save phobologic/fa1681e3fc2e78ecd8e5cda1004a390e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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