summaryrefslogtreecommitdiff
path: root/stacks
diff options
context:
space:
mode:
authorKenny Ballou <kballou@devnulllabs.io>2020-01-28 21:49:30 -0700
committerKenny Ballou <kballou@devnulllabs.io>2020-02-05 17:33:12 -0700
commit0eea4a0abfdbf1225abd148eac0a7f151c1144b3 (patch)
tree7572d62e5a9260c2b755d6c085769f2dcab5e8b0 /stacks
parent1bb882edd5c1745d1a1bd4cc12e30fcbd8f81be9 (diff)
downloadkennyballou.com-0eea4a0abfdbf1225abd148eac0a7f151c1144b3.tar.gz
kennyballou.com-0eea4a0abfdbf1225abd148eac0a7f151c1144b3.tar.xz
code-{build,commit} auto build and deploy blog
Create codecommit and codebuild resources to store and build web/blog content. Add in a lambda function to trigger the builds automatically to futher automate deployment and publishing of content. Signed-off-by: Kenny Ballou <kballou@devnulllabs.io>
Diffstat (limited to 'stacks')
-rw-r--r--stacks/blog.tpl150
-rw-r--r--stacks/codebuild-service-role.json.in49
-rw-r--r--stacks/codecommit-build-policy.json.in33
-rwxr-xr-xstacks/codecommit-build.py76
4 files changed, 308 insertions, 0 deletions
diff --git a/stacks/blog.tpl b/stacks/blog.tpl
index 454540c..3a6cd7f 100644
--- a/stacks/blog.tpl
+++ b/stacks/blog.tpl
@@ -230,6 +230,156 @@
"URIRewriteLambdaFunction", "Arn"]},
"Description": "Lambda Function performing URI rewriting"
}
+ },
+ "BlogContentRepository": {
+ "Type": "AWS::CodeCommit::Repository",
+ "Properties": {
+ "RepositoryDescription": "Blog Content Repository",
+ "RepositoryName": {"Ref": "BlogBucketName"},
+ "Triggers": [
+ {
+ "Name": "Build and Deploy",
+ "Branches": ["master"],
+ "DestinationArn": {"Ref": "CodeCommitEventsSnsTopic"},
+ "Events": ["all"]
+ }
+ ]
+ }
+ },
+ "BlogCodeBuildLogGroup": {
+ "Type": "AWS::Logs::LogGroup",
+ "Properties": {
+ "LogGroupName": {"Fn::Join": ["-", [
+ "/aws/codebuild/CodeBuild",
+ {"Ref": "BlogBucketName"}]]},
+ "RetentionInDays": 14
+ }
+ },
+ "BlogCodeBuild": {
+ "Type": "AWS::CodeBuild::Project",
+ "Properties": {
+ "Name": "BlogCI",
+ "Description": "Blog Build Project",
+ "Artifacts": {
+ "Type": "NO_ARTIFACTS"
+ },
+ "Environment": {
+ "ComputeType": "BUILD_GENERAL1_SMALL",
+ "Image": "kennyballou/debian-pandoc:latest",
+ "Type": "LINUX_CONTAINER"
+ },
+ "LogsConfig": {
+ "CloudWatchLogs": {
+ "GroupName": {"Fn::Join": ["-", [
+ "/aws/codebuild/CodeBuild",
+ {"Ref": "BlogBucketName"}
+ ]]},
+ "Status": "ENABLED"
+ }
+ },
+ "ServiceRole": {"Ref": "CodeBuildIamServiceRole"},
+ "Source": {
+ "Type": "CODECOMMIT",
+ "Location": {"Fn::GetAtt": ["BlogContentRepository",
+ "CloneUrlHttp"]}
+ }
+ }
+ },
+ "CodeCommitEventsSnsTopic": {
+ "Type": "AWS::SNS::Topic",
+ "Properties": {
+ "DisplayName": "CodeCommit Events",
+ "TopicName": "codecommit-events"
+ }
+ },
+ "CodeBuildIamManagedPolicy": {
+ "Type": "AWS::IAM::ManagedPolicy",
+ "Properties": {
+ "Description": "CodeBuild Service Policy",
+ "PolicyDocument": [+ INCLUDE "codebuild-service-role.json.in" +]
+ }
+ },
+ "CodeBuildIamServiceRole": {
+ "Type": "AWS::IAM::Role",
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Principal": {
+ "Service": "codebuild.amazonaws.com"
+ },
+ "Effect": "Allow"
+ }
+ ]
+ },
+ "ManagedPolicyArns": [
+ {"Ref": "CodeBuildIamManagedPolicy"}
+ ]
+ }
+ },
+ "LambdaCodeCommitBuildIamManagedPolicy": {
+ "Type": "AWS::IAM::ManagedPolicy",
+ "Properties": {
+ "Description": "Lambda CodeCommit-Build Execution Policy",
+ "PolicyDocument": [+ INCLUDE "codecommit-build-policy.json.in" +]
+ }
+ },
+ "LambdaCodeCommitBuildIamServiceRole": {
+ "Type": "AWS::IAM::Role",
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Principal": {
+ "Service": "lambda.amazonaws.com"
+ },
+ "Effect": "Allow"
+ }
+ ]
+ },
+ "ManagedPolicyArns": [
+ {"Ref": "LambdaCodeCommitBuildIamManagedPolicy"}
+ ]
+ }
+ },
+ "CodeCommitBuildLambdaPermission": {
+ "Type": "AWS::Lambda::Permission",
+ "Properties": {
+ "FunctionName": {"Fn::GetAtt": [
+ "CodeCommitBuildLambdaFunction", "Arn"]},
+ "Action": "lambda:InvokeFunction",
+ "Principal": "sns.amazonaws.com",
+ "SourceArn": {"Ref": "CodeCommitEventsSnsTopic"}
+ }
+ },
+ "CodeCommitBuildLambdaFunction": {
+ "Type": "AWS::Lambda::Function",
+ "Properties": {
+ "FunctionName": "codecommit-build-bae089e8-3871-4067-9a3d-bac114f08438",
+ "Code": {
+ "ZipFile": [+ INCLUDE "codecommit-build.py.in" +]
+ },
+ "Description": "Start builds on commit events",
+ "Handler": "index.handler",
+ "MemorySize": 128,
+ "Timeout": 3,
+ "Role": {"Fn::GetAtt": [
+ "LambdaCodeCommitBuildIamServiceRole", "Arn"]},
+ "Runtime": "python3.7"
+ }
+ },
+ "CodeCommitBuildSnsSubscription": {
+ "Type": "AWS::SNS::Subscription",
+ "Properties": {
+ "Protocol": "lambda",
+ "Endpoint": {"Fn::GetAtt": [
+ "CodeCommitBuildLambdaFunction", "Arn"]},
+ "TopicArn": {"Ref": "CodeCommitEventsSnsTopic"}
+ }
}
}
}
diff --git a/stacks/codebuild-service-role.json.in b/stacks/codebuild-service-role.json.in
new file mode 100644
index 0000000..abcb514
--- /dev/null
+++ b/stacks/codebuild-service-role.json.in
@@ -0,0 +1,49 @@
+[+ autogen5 template -*- mode: json -*- +]
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Action": [
+ "logs:CreateLogStream",
+ "logs:PutLogEvents"
+ ],
+ "Resource": [
+ {"Fn::Join": [":", [
+ "arn:aws:logs",
+ {"Ref": "AWS::Region"},
+ {"Ref": "AWS::AccountId"},
+ "log-group:/aws/codebuild/CodeBuild*"]]},
+ {"Fn::Join": [":", [
+ "arn:aws:logs",
+ {"Ref": "AWS::Region"},
+ {"Ref": "AWS::AccountId"},
+ "log-group:/aws/codebuild/CodeBuild*",
+ "log-stream:*"]]}
+ ]
+ }, {
+ "Effect": "Allow",
+ "Action": [
+ "codecommit:GitPull"
+ ],
+ "Resource": [
+ {"Fn::Join": [":", [
+ "arn:aws:codecommit",
+ {"Ref": "AWS::Region"},
+ {"Ref": "AWS::AccountId"},
+ "*"]]}
+ ]
+ }, {
+ "Effect": "Allow",
+ "Action": [
+ "s3:PutObject",
+ "s3:Get*",
+ "s3:List"
+ ],
+ "Resource": [
+ {"Fn::GetAtt": ["BlogContentBucket", "Arn"]},
+ {"Fn::Join": ["", [{"Fn::GetAtt": ["BlogContentBucket", "Arn"]}, "/*"]]}
+ ]
+ }
+ ]
+}
diff --git a/stacks/codecommit-build-policy.json.in b/stacks/codecommit-build-policy.json.in
new file mode 100644
index 0000000..634acb2
--- /dev/null
+++ b/stacks/codecommit-build-policy.json.in
@@ -0,0 +1,33 @@
+[+ autogen5 template -*- mode: json -*- +]
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Action": [
+ "logs:CreateLogStream",
+ "logs:PutLogEvents"
+ ],
+ "Resource": [
+ {"Fn::Join": [":", [
+ "arn:aws:logs",
+ {"Ref": "AWS::Region"},
+ {"Ref": "AWS::AccountId"},
+ "log-group:/aws/lambda/codecommit-build-bae089e8-3871-4067-9a3d-bac114f08438:*"
+ ]]}
+ ]
+ }, {
+ "Effect": "Allow",
+ "Action": [
+ "codebuild:StartBuild"
+ ],
+ "Resource": [
+ {"Fn::Join": [":", [
+ "arn:aws:codebuild",
+ {"Ref": "AWS::Region"},
+ {"Ref": "AWS::AccountId"},
+ "project/*"]]}
+ ]
+ }
+ ]
+}
diff --git a/stacks/codecommit-build.py b/stacks/codecommit-build.py
new file mode 100755
index 0000000..9c8d3ce
--- /dev/null
+++ b/stacks/codecommit-build.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+'''
+CodeCommit to CodeBuild Integration
+
+Start CodeBuild jobs based on CodeCommit events.
+'''
+
+
+import json
+import logging
+import boto3
+
+LOG = logging.getLogger()
+LOG.setLevel(logging.INFO)
+
+PROJECT_NAME = 'BlogCI'
+
+
+def get_is_tag(ref):
+ return 'tags' in ref
+
+
+def submit_build(reference, project_name, region):
+ '''Submit codebuild job for reference'''
+ client = boto3.client('codebuild', region_name=region)
+
+ response = client.start_build(
+ projectName=project_name,
+ sourceVersion=reference,
+ )
+ LOG.info(response['build'])
+
+
+def debug_handler(detail):
+ '''Log details and exit'''
+ LOG.warn(detail)
+ return True
+
+
+def reference_change_handler(detail):
+ '''handle reference change events, submitting code build jobs if needed'''
+ references = detail['codecommit']['references']
+ region = detail['awsRegion']
+ for reference in references:
+ is_deleted = reference.get('deleted', False)
+ if is_deleted:
+ continue
+ if 'tags' in reference['ref']:
+ submit_build(reference['ref'], PROJECT_NAME, region)
+ else:
+ submit_build(reference['commit'], PROJECT_NAME, region)
+
+
+EVENT_HANDLERS = {
+ 'TriggerEventTest': False,
+ 'ReferenceChanges': reference_change_handler,
+}
+
+
+def handler(event, _context):
+ '''Main Event Handler'''
+ for message_record in event['Records']:
+ records = json.loads(message_record['Sns']['Message'])
+ for record in records['Records']:
+ name = record['eventName']
+ event_handler = EVENT_HANDLERS.get(name)
+ if event_handler is False:
+ return True
+ elif event_handler is None:
+ event_handler = debug_handler
+ try:
+ event_handler(record)
+ except Exception as ex:
+ LOG.error('Runtime exception occurred: %s', ex)
+
+ return True