Skip to content

Commit

Permalink
Initial commit; Implements the Basic Routing Policy
Browse files Browse the repository at this point in the history
  • Loading branch information
roosterfish committed Mar 5, 2020
0 parents commit bbd00fa
Show file tree
Hide file tree
Showing 6 changed files with 257 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.aws
4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM python:3.8-alpine
RUN apk update && pip3 install boto3
COPY change.py /change.py
ENTRYPOINT ["python3", "/change.py"]
19 changes: 19 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Copyright (c) 2020 Julian Pelizäus

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
62 changes: 62 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# AWS Route 53 Record Set

This GitHub Actions allows you to manage [AWS Route 53](https://aws.amazon.com/route53/) Record Sets.

The naming is aligned with the official interface: https://docs.aws.amazon.com/cli/latest/reference/route53/change-resource-record-sets.html. There you can find possible variations for every Input this GitHub Action supports.

## Get started

A new AWS Route 53 Record Set can be created with the following workflow syntax:

```yaml
jobs:
aws_route53:
runs-on: ubuntu-latest
steps:
- name: "Create an A record set"
uses: Roosterfish/aws-route53-record-set-action@master
with:
aws_access_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws_route53_hosted_zone_id: ${{ secrets.AWS_ROUTE53_HOSTED_ZONE_ID }}
aws_route53_rr_action: "CREATE"
aws_route53_rr_name: "your-fqdn.example.com"
aws_route53_rr_type: "A"
aws_route53_rr_ttl: "300"
aws_route53_rr_value: "1.2.3.4"
```
# GitHub Action Inputs
The behaviour of this Action can be modified with the following Inputs:
Name | Description | Choices | Required
--- | --- | --- | ---
`aws_access_key_id` | The AWS access key id | | yes
`aws_secret_access_key` | The AWS secret access key | | yes
`aws_route53_hosted_zone_id` | The id of the hosted zone | | yes
`aws_route53_rr_action` | The action that should be taken | `CREATE`, `DELETE`, `UPSERT` | yes
`aws_route53_rr_name` | The name of the record set | | yes
`aws_route53_rr_type` | The type of the record set | `SOA`, `A`, `TXT`, `NS`, `CNAME`, `MX`, `PTR`, `SRV`, `SPF`, `AAAA` | yes
`aws_route53_rr_ttl` | The TTL of the record set | | yes
`aws_route53_rr_value` | The value of the record set | | yes
`aws_route53_rr_comment` | A comment for the record set | | no
`aws_route53_wait` | Wait until the record set is fully settled in | `true`, `false` | no

## Supported Routing Policies

Currently this GitHub Actions supports the following Routing Policies of the AWS Route 53 service:

Name | Extra Variables
--- | ---
Basic | None

## License

The MIT License (MIT)

Copyright (c) 2020 Julian Pelizäus

### Used libraries

https://pypi.org/project/boto3/ licensed under [Apache License 2.0](https://github.com/boto/boto3/blob/develop/LICENSE)
40 changes: 40 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: AWS Route 53 Record Set
author: Julian Pelizäus <jp@adformc.de>
branding:
icon: cloud
color: gray-dark
description: Create Route 53 Record Sets
inputs:
aws_access_key_id:
description: The AWS access key id
required: true
aws_secret_access_key:
description: The AWS secret access key
required: true
aws_route53_hosted_zone_id:
description: The id of the hosted zone
required: true
aws_route53_rr_action:
description: The action that should be taken
required: true
aws_route53_rr_name:
description: The name of the record set
required: true
aws_route53_rr_type:
description: The type of the record set
required: true
aws_route53_rr_ttl:
description: The TTL of the record set
required: true
aws_route53_rr_value:
description: The value of the record set
required: true
aws_route53_rr_comment:
description: A comment used for the resource record
required: false
aws_route53_wait:
description: Wait until the record set is fully settled in
required: false
runs:
using: docker
image: Dockerfile
131 changes: 131 additions & 0 deletions change.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import os
import sys
import json
import boto3

from distutils import util


class AWSRoute53RecordSet:
"""
Primary class for the handling of AWS Route 53 Record Sets.
"""
def __init__(self):
"""
The default constructor.
"""
self.client = None
self.waiter = None
self.rr_skeleton = dict()

def _get_env(self, variable, exit=True):
"""
Try to fetch a variable from the environment.
Per default the method will raise an exception if the variable isn't present.
This behaviour can be switched off via the exit flag.
"""
value = os.environ.get(variable)
if not value and exit:
raise NameError("Cannot find environment variable: " + str(variable))
return value

def _connect(self):
"""
Creates a new client object which wraps the connection to AWS.
"""
if not self.client:
self.client = boto3.client(
"route53",
aws_access_key_id=self._get_env("INPUT_AWS_ACCESS_KEY_ID"),
aws_secret_access_key=self._get_env("INPUT_AWS_SECRET_ACCESS_KEY")
)
self.waiter = self.client.get_waiter("resource_record_sets_changed")

def _set_comment(self):
"""
Appends an additional comment field to the record set.
"""
comment = self._get_env("INPUT_AWS_ROUTE53_RR_COMMENT", False)
if comment:
self.rr_skeleton["Comment"] = comment

def _set_base_changes(self):
"""
Creates the base skeleton required for creating a new record set.
"""
self.rr_skeleton["Changes"] = [{
"Action": self._get_env("INPUT_AWS_ROUTE53_RR_ACTION"),
"ResourceRecordSet": {
"Name": self._get_env("INPUT_AWS_ROUTE53_RR_NAME"),
"Type": self._get_env("INPUT_AWS_ROUTE53_RR_TYPE"),
"TTL": int(self._get_env("INPUT_AWS_ROUTE53_RR_TTL")),
"ResourceRecords": [{
"Value": self._get_env("INPUT_AWS_ROUTE53_RR_VALUE")
}]
}
}]

def _build_record_set(self):
"""
Builds up the skeleton used for modulating the record set.
"""
self._set_comment()
self._set_base_changes()
return self.rr_skeleton

def _change_record_set(self, record_set):
"""
Requests the required change at AWS.
"""
return self.client.change_resource_record_sets(
HostedZoneId=self._get_env("INPUT_AWS_ROUTE53_HOSTED_ZONE_ID"),
ChangeBatch=record_set
)

def _wait(self, request_id):
"""
Waits until the requested operations is finished.
"""
wait = self._get_env("INPUT_AWS_ROUTE53_WAIT", False)
if wait and util.strtobool(wait):
self.waiter.wait(
Id=request_id,
WaiterConfig={
"Delay": 10,
"MaxAttempts": 50
}
)

def _obtain_request_id(self, result):
"""
Grabs and returns the id of the given request.
"""
return result["ChangeInfo"]["Id"]

def _obtain_marshalled_result(self, result):
"""
Grabs and returns the HTTP response of the given request.
"""
return json.dumps(result["ResponseMetadata"], indent=4)

def change(self):
"""
Entrypoint for the management of a record set.
"""
self._connect()
record_set = self._build_record_set()
result = self._change_record_set(record_set)
self._wait(
self._obtain_request_id(result)
)
sys.stdout.write(
self._obtain_marshalled_result(result) + "\n"
)


try:
o = AWSRoute53RecordSet()
o.change()
except Exception as e:
sys.stderr.write(str(e) + "\n")
sys.exit(1)

0 comments on commit bbd00fa

Please sign in to comment.