Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update cloudflare record #123

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ Contributors
6. [luisbarrueco](https://github.com/luisbarrueco)
7. [Tungsteno74](https://github.com/Tungsteno74)
8. [Harold Bradley III](https://haroldbradleyiii.com/)
9. [Angus Dippenaar](https://github.com/SN9NV)
2 changes: 1 addition & 1 deletion sewer/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ def __init__(
self.ACME_DIRECTORY_URL = ACME_DIRECTORY_URL
self.LOG_LEVEL = LOG_LEVEL.upper()

self.logger = logging.getLogger()
self.logger = logging.getLogger("sewer")
handler = logging.StreamHandler()
formatter = logging.Formatter("%(message)s")
handler.setFormatter(formatter)
Expand Down
98 changes: 84 additions & 14 deletions sewer/dns_providers/cloudflare.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@
from . import common


def _check_cloudflare_error(response, code):
if response.status_code == 400:
res_json = response.json()
for error in res_json["errors"]:
if error["code"] == code:
return True
return False


class CloudFlareDns(common.BaseDns):
"""
"""
Expand All @@ -27,13 +36,17 @@ def __init__(
self.CLOUDFLARE_API_BASE_URL = CLOUDFLARE_API_BASE_URL + "/"
else:
self.CLOUDFLARE_API_BASE_URL = CLOUDFLARE_API_BASE_URL

self.headers = {
"X-Auth-Email": self.CLOUDFLARE_EMAIL,
"X-Auth-Key": self.CLOUDFLARE_API_KEY,
}
super(CloudFlareDns, self).__init__()

def find_dns_zone(self, domain_name):
self.logger.debug("find_dns_zone")
url = urllib.parse.urljoin(self.CLOUDFLARE_API_BASE_URL, "zones?status=active")
headers = {"X-Auth-Email": self.CLOUDFLARE_EMAIL, "X-Auth-Key": self.CLOUDFLARE_API_KEY}
find_dns_zone_response = requests.get(url, headers=headers, timeout=self.HTTP_TIMEOUT)
find_dns_zone_response = requests.get(url, headers=self.headers, timeout=self.HTTP_TIMEOUT)
self.logger.debug(
"find_dns_zone_response. status_code={0}".format(find_dns_zone_response.status_code)
)
Expand All @@ -60,6 +73,60 @@ def find_dns_zone(self, domain_name):

self.logger.debug("find_dns_zone_success")

def _domain_id(self, domain_name, record_type):
url = urllib.parse.urljoin(
self.CLOUDFLARE_API_BASE_URL,
"zones/{0}/dns_records?type={2}&name={1}".format(
self.CLOUDFLARE_DNS_ZONE_ID, domain_name, record_type
),
)

domain_ids = requests.get(url, headers=self.headers, timeout=self.HTTP_TIMEOUT)
if domain_ids.status_code != 200:
raise ValueError(
"Error getting ID for domain: domain_name={domain_name} status_code={status_code} response={response}".format(
domain_name=domain_name,
status_code=domain_ids.status_code,
response=self.log_response(domain_ids),
)
)

for res in domain_ids.json()["result"]:
return res["id"]

raise ValueError(
"Error getting ID for domain none returned: domain_name={domain_name} status_code={status_code} response={response}".format(
domain_name=domain_name,
status_code=domain_ids.status_code,
response=self.log_response(domain_ids),
)
)

def _update_dns_record(self, domain_name, url, body):
self.logger.info("update_dns_record")
domain_id = self._domain_id(domain_name, "TXT")
url = urllib.parse.urljoin(url + "/", domain_id)
update_cloudflare_dns_record_response = requests.put(
url, headers=self.headers, json=body, timeout=self.HTTP_TIMEOUT
)
self.logger.debug(
"update_cloudflare_dns_record_response. status_code={0}. response={1}".format(
update_cloudflare_dns_record_response.status_code,
self.log_response(update_cloudflare_dns_record_response),
)
)
if update_cloudflare_dns_record_response.status_code != 200:
if _check_cloudflare_error(update_cloudflare_dns_record_response, 81058):
self.logger.info("A record with those settings already exists. Ignoring")
else:
raise ValueError(
"Error updating cloudflare dns record: status_code={status_code} response={response}".format(
status_code=update_cloudflare_dns_record_response.status_code,
response=self.log_response(update_cloudflare_dns_record_response),
)
)
self.logger.info("create_dns_record_end")

def create_dns_record(self, domain_name, domain_dns_value):
self.logger.info("create_dns_record")
# if we have been given a wildcard name, strip wildcard
Expand All @@ -70,14 +137,13 @@ def create_dns_record(self, domain_name, domain_dns_value):
self.CLOUDFLARE_API_BASE_URL,
"zones/{0}/dns_records".format(self.CLOUDFLARE_DNS_ZONE_ID),
)
headers = {"X-Auth-Email": self.CLOUDFLARE_EMAIL, "X-Auth-Key": self.CLOUDFLARE_API_KEY}
body = {
"type": "TXT",
"name": "_acme-challenge" + "." + domain_name + ".",
"name": "_acme-challenge.{0}".format(domain_name),
"content": "{0}".format(domain_dns_value),
}
create_cloudflare_dns_record_response = requests.post(
url, headers=headers, json=body, timeout=self.HTTP_TIMEOUT
url, headers=self.headers, json=body, timeout=self.HTTP_TIMEOUT
)
self.logger.debug(
"create_cloudflare_dns_record_response. status_code={0}. response={1}".format(
Expand All @@ -88,12 +154,18 @@ def create_dns_record(self, domain_name, domain_dns_value):
if create_cloudflare_dns_record_response.status_code != 200:
# raise error so that we do not continue to make calls to ACME
# server
raise ValueError(
"Error creating cloudflare dns record: status_code={status_code} response={response}".format(
status_code=create_cloudflare_dns_record_response.status_code,
response=self.log_response(create_cloudflare_dns_record_response),

# Check for "The record already exists" error. Code 81057
if _check_cloudflare_error(create_cloudflare_dns_record_response, 81057):
self.logger.info("Record exists, attempting to update record")
self._update_dns_record(body["name"], url, body)
else:
raise ValueError(
"Error creating cloudflare dns record: status_code={status_code} response={response}".format(
status_code=create_cloudflare_dns_record_response.status_code,
response=self.log_response(create_cloudflare_dns_record_response),
)
)
)
self.logger.info("create_dns_record_end")

def delete_dns_record(self, domain_name, domain_dns_value):
Expand All @@ -109,7 +181,6 @@ def json(self):
return {}

delete_dns_record_response = MockResponse()
headers = {"X-Auth-Email": self.CLOUDFLARE_EMAIL, "X-Auth-Key": self.CLOUDFLARE_API_KEY}

dns_name = "_acme-challenge" + "." + domain_name
list_dns_payload = {"type": "TXT", "name": dns_name}
Expand All @@ -119,7 +190,7 @@ def json(self):
)

list_dns_response = requests.get(
list_dns_url, params=list_dns_payload, headers=headers, timeout=self.HTTP_TIMEOUT
list_dns_url, params=list_dns_payload, headers=self.headers, timeout=self.HTTP_TIMEOUT
)

for i in range(0, len(list_dns_response.json()["result"])):
Expand All @@ -128,9 +199,8 @@ def json(self):
self.CLOUDFLARE_API_BASE_URL,
"zones/{0}/dns_records/{1}".format(self.CLOUDFLARE_DNS_ZONE_ID, dns_record_id),
)
headers = {"X-Auth-Email": self.CLOUDFLARE_EMAIL, "X-Auth-Key": self.CLOUDFLARE_API_KEY}
delete_dns_record_response = requests.delete(
url, headers=headers, timeout=self.HTTP_TIMEOUT
url, headers=self.headers, timeout=self.HTTP_TIMEOUT
)
self.logger.debug(
"delete_dns_record_response. status_code={0}. response={1}".format(
Expand Down