mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-07-26 12:38:36 +02:00
cleanup + test on sandbox
This commit is contained in:
parent
a17368be24
commit
e1a37fbc35
4 changed files with 41 additions and 56 deletions
|
@ -1,11 +1,9 @@
|
||||||
from itertools import zip_longest
|
from itertools import zip_longest
|
||||||
import logging
|
import logging
|
||||||
import ipaddress
|
import ipaddress
|
||||||
import requests
|
|
||||||
import re
|
import re
|
||||||
from datetime import date
|
from datetime import date
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from django.conf import settings
|
|
||||||
from django_fsm import FSMField, transition, TransitionNotAllowed # type: ignore
|
from django_fsm import FSMField, transition, TransitionNotAllowed # type: ignore
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
@ -239,7 +237,6 @@ class Domain(TimeStampedModel, DomainHelper):
|
||||||
is called in the validate function on the request/domain page
|
is called in the validate function on the request/domain page
|
||||||
|
|
||||||
throws- RegistryError or InvalidDomainError"""
|
throws- RegistryError or InvalidDomainError"""
|
||||||
return True
|
|
||||||
if not cls.string_could_be_domain(domain):
|
if not cls.string_could_be_domain(domain):
|
||||||
logger.warning("Not a valid domain: %s" % str(domain))
|
logger.warning("Not a valid domain: %s" % str(domain))
|
||||||
# throw invalid domain error so that it can be caught in
|
# throw invalid domain error so that it can be caught in
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
|
|
||||||
{% url 'domain-dns-dnssec' pk=domain.id as url %}
|
{% url 'domain-dns-dnssec' pk=domain.id as url %}
|
||||||
<li><a href="{{ url }}">DNSSEC</a></li>
|
<li><a href="{{ url }}">DNSSEC</a></li>
|
||||||
{% if dns_prototype_flag %}
|
{% if dns_prototype_flag and is_valid_domain_for_prototype %}
|
||||||
<li><a href="{% url 'prototype-domain-dns' pk=domain.id %}">Prototype DNS record creator</a></li>
|
<li><a href="{% url 'prototype-domain-dns' pk=domain.id %}">Prototype DNS record creator</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -7,12 +7,15 @@
|
||||||
|
|
||||||
{% include "includes/form_errors.html" with form=form %}
|
{% include "includes/form_errors.html" with form=form %}
|
||||||
|
|
||||||
<h1>Add a cloudflare DNS record</h1>
|
<h1>Add DNS records</h1>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
This is a prototype that demonstrates adding an 'A' record to igorville.gov.
|
This is a prototype that demonstrates adding an 'A' record to a zone.
|
||||||
Do note that this just adds records, but does not update or delete existing ones.
|
Do note that this just adds records, but does not update or delete existing ones.
|
||||||
<strong>You can only use this on igorville.gov, domainops.gov, and dns.gov.</strong>
|
<strong>
|
||||||
|
On non-production environments, you can only use this on igorville.gov, domainops.gov, and dns.gov.
|
||||||
|
On production environments, you can only use this on igorville.gov.
|
||||||
|
</strong>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<form class="usa-form usa-form--large" method="post" novalidate id="form-container">
|
<form class="usa-form usa-form--large" method="post" novalidate id="form-container">
|
||||||
|
|
|
@ -459,25 +459,29 @@ class DomainDNSView(DomainBaseView):
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
"""Adds custom context."""
|
"""Adds custom context."""
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
|
object = self.get_object()
|
||||||
context["dns_prototype_flag"] = flag_is_active_for_user(self.request.user, "dns_prototype_flag")
|
context["dns_prototype_flag"] = flag_is_active_for_user(self.request.user, "dns_prototype_flag")
|
||||||
|
|
||||||
|
context["is_valid_domain_for_prototype"] = True
|
||||||
|
x = object.name == "igorville.gov"
|
||||||
|
print(f"what is the object? {object.name} and equal? {x}")
|
||||||
|
if settings.IS_PRODUCTION:
|
||||||
|
context["is_valid_domain_for_prototype"] = object.name == "igorville.gov"
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class PrototypeDomainDNSRecordForm(forms.Form):
|
class PrototypeDomainDNSRecordForm(forms.Form):
|
||||||
"""Form for adding DNS records in prototype."""
|
"""Form for adding DNS records in prototype."""
|
||||||
|
|
||||||
name = forms.CharField(
|
name = forms.CharField(label="DNS record name (A record)", required=True, help_text="DNS record name")
|
||||||
label="DNS record name (A record)",
|
|
||||||
required=True,
|
|
||||||
help_text="DNS record name"
|
|
||||||
)
|
|
||||||
|
|
||||||
content = forms.GenericIPAddressField(
|
content = forms.GenericIPAddressField(
|
||||||
label="IPv4 Address",
|
label="IPv4 Address",
|
||||||
required=True,
|
required=True,
|
||||||
protocol="IPv4",
|
protocol="IPv4",
|
||||||
)
|
)
|
||||||
|
|
||||||
ttl = forms.ChoiceField(
|
ttl = forms.ChoiceField(
|
||||||
label="TTL",
|
label="TTL",
|
||||||
choices=[
|
choices=[
|
||||||
|
@ -488,26 +492,28 @@ class PrototypeDomainDNSRecordForm(forms.Form):
|
||||||
(3600, "1 hour"),
|
(3600, "1 hour"),
|
||||||
(7200, "2 hours"),
|
(7200, "2 hours"),
|
||||||
(18000, "5 hours"),
|
(18000, "5 hours"),
|
||||||
(43200, "12 hours"),
|
(43200, "12 hours"),
|
||||||
(86400, "1 day")
|
(86400, "1 day"),
|
||||||
],
|
],
|
||||||
initial=1,
|
initial=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class PrototypeDomainDNSRecordView(DomainFormBaseView):
|
class PrototypeDomainDNSRecordView(DomainFormBaseView):
|
||||||
template_name = "prototype_domain_dns.html"
|
template_name = "prototype_domain_dns.html"
|
||||||
form_class = PrototypeDomainDNSRecordForm
|
form_class = PrototypeDomainDNSRecordForm
|
||||||
|
|
||||||
def has_permission(self):
|
def has_permission(self):
|
||||||
has_permission = super().has_permission()
|
has_permission = super().has_permission()
|
||||||
if not has_permission:
|
if not has_permission:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
flag_enabled = flag_is_active_for_user(self.request.user, "dns_prototype_flag")
|
flag_enabled = flag_is_active_for_user(self.request.user, "dns_prototype_flag")
|
||||||
if not flag_enabled:
|
if not flag_enabled:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return reverse("prototype-domain-dns", kwargs={"pk": self.object.pk})
|
return reverse("prototype-domain-dns", kwargs={"pk": self.object.pk})
|
||||||
|
|
||||||
|
@ -520,22 +526,22 @@ class PrototypeDomainDNSRecordView(DomainFormBaseView):
|
||||||
try:
|
try:
|
||||||
if settings.IS_PRODUCTION and self.object.name != "igorville.gov":
|
if settings.IS_PRODUCTION and self.object.name != "igorville.gov":
|
||||||
raise Exception(f"create dns record was called for domain {self.name}")
|
raise Exception(f"create dns record was called for domain {self.name}")
|
||||||
|
|
||||||
valid_domains = ["igorville.gov", "domainops.gov", "dns.gov"]
|
valid_domains = ["igorville.gov", "domainops.gov", "dns.gov"]
|
||||||
if not settings.IS_PRODUCTION and self.object.name not in valid_domains:
|
if not settings.IS_PRODUCTION and self.object.name not in valid_domains:
|
||||||
raise Exception(
|
raise Exception(
|
||||||
f"Can only create DNS records for: {valid_domains}."
|
f"Can only create DNS records for: {valid_domains}."
|
||||||
" Create one in a test environment if it doesn't already exist."
|
" Create one in a test environment if it doesn't already exist."
|
||||||
)
|
)
|
||||||
|
|
||||||
base_url = "https://api.cloudflare.com/client/v4"
|
base_url = "https://api.cloudflare.com/client/v4"
|
||||||
headers = {
|
headers = {
|
||||||
"X-Auth-Email": settings.SECRET_REGISTRY_SERVICE_EMAIL,
|
"X-Auth-Email": settings.SECRET_REGISTRY_SERVICE_EMAIL,
|
||||||
"X-Auth-Key": settings.SECRET_REGISTRY_TENANT_KEY,
|
"X-Auth-Key": settings.SECRET_REGISTRY_TENANT_KEY,
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json",
|
||||||
}
|
}
|
||||||
params = {"tenant_name": settings.SECRET_REGISTRY_TENANT_NAME}
|
params = {"tenant_name": settings.SECRET_REGISTRY_TENANT_NAME}
|
||||||
|
|
||||||
# 1. Get tenant details
|
# 1. Get tenant details
|
||||||
tenant_response = requests.get(f"{base_url}/user/tenants", headers=headers, params=params)
|
tenant_response = requests.get(f"{base_url}/user/tenants", headers=headers, params=params)
|
||||||
tenant_response_json = tenant_response.json()
|
tenant_response_json = tenant_response.json()
|
||||||
|
@ -557,7 +563,7 @@ class PrototypeDomainDNSRecordView(DomainFormBaseView):
|
||||||
account_response.raise_for_status()
|
account_response.raise_for_status()
|
||||||
|
|
||||||
# See if we already made an account.
|
# See if we already made an account.
|
||||||
# This doesn't need to be a for loop (1 record or 0) but alas, here we are
|
# This maybe doesn't need to be a for loop (1 record or 0) but alas, here we are
|
||||||
account_id = None
|
account_id = None
|
||||||
accounts = account_response_json.get("result", [])
|
accounts = account_response_json.get("result", [])
|
||||||
for account in accounts:
|
for account in accounts:
|
||||||
|
@ -565,17 +571,13 @@ class PrototypeDomainDNSRecordView(DomainFormBaseView):
|
||||||
account_id = account.get("id")
|
account_id = account.get("id")
|
||||||
logger.debug(f"Found it! Account: {account_name} (ID: {account_id})")
|
logger.debug(f"Found it! Account: {account_name} (ID: {account_id})")
|
||||||
break
|
break
|
||||||
|
|
||||||
# If we didn't, create one
|
# If we didn't, create one
|
||||||
if not account_id:
|
if not account_id:
|
||||||
account_response = requests.post(
|
account_response = requests.post(
|
||||||
f"{base_url}/accounts",
|
f"{base_url}/accounts",
|
||||||
headers=headers,
|
headers=headers,
|
||||||
json={
|
json={"name": account_name, "type": "enterprise", "unit": {"id": tenant_id}},
|
||||||
"name": account_name,
|
|
||||||
"type": "enterprise",
|
|
||||||
"unit": {"id": tenant_id}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
account_response_json = account_response.json()
|
account_response_json = account_response.json()
|
||||||
logger.info(f"Created account: {account_response_json}")
|
logger.info(f"Created account: {account_response_json}")
|
||||||
|
@ -587,7 +589,7 @@ class PrototypeDomainDNSRecordView(DomainFormBaseView):
|
||||||
|
|
||||||
# Try to find an existing zone first by searching on the current id
|
# Try to find an existing zone first by searching on the current id
|
||||||
zone_name = self.object.name
|
zone_name = self.object.name
|
||||||
params = {"account.id": account_id, "name": zone_name}
|
params = {"account.id": account_id, "name": zone_name}
|
||||||
zone_response = requests.get(f"{base_url}/zones", headers=headers, params=params)
|
zone_response = requests.get(f"{base_url}/zones", headers=headers, params=params)
|
||||||
zone_response_json = zone_response.json()
|
zone_response_json = zone_response.json()
|
||||||
logger.debug(f"get zone: {zone_response_json}")
|
logger.debug(f"get zone: {zone_response_json}")
|
||||||
|
@ -602,23 +604,19 @@ class PrototypeDomainDNSRecordView(DomainFormBaseView):
|
||||||
zone_id = zone.get("id")
|
zone_id = zone.get("id")
|
||||||
logger.debug(f"Found it! Zone: {zone_name} (ID: {zone_id})")
|
logger.debug(f"Found it! Zone: {zone_name} (ID: {zone_id})")
|
||||||
break
|
break
|
||||||
|
|
||||||
# Create one if it doesn't presently exist
|
# Create one if it doesn't presently exist
|
||||||
if not zone_id:
|
if not zone_id:
|
||||||
zone_response = requests.post(
|
zone_response = requests.post(
|
||||||
f"{base_url}/zones",
|
f"{base_url}/zones",
|
||||||
headers=headers,
|
headers=headers,
|
||||||
json={
|
json={"name": zone_name, "account": {"id": account_id}, "type": "full"},
|
||||||
"name": zone_name,
|
|
||||||
"account": {"id": account_id},
|
|
||||||
"type": "full"
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
zone_response_json = zone_response.json()
|
zone_response_json = zone_response.json()
|
||||||
logger.info(f"Created zone: {zone_response_json}")
|
logger.info(f"Created zone: {zone_response_json}")
|
||||||
|
zone_id = zone_response_json.get("result", {}).get("id")
|
||||||
errors = zone_response_json.get("errors", [])
|
errors = zone_response_json.get("errors", [])
|
||||||
zone_response.raise_for_status()
|
zone_response.raise_for_status()
|
||||||
zone_id = zone_response_json.get("result", {}).get("id")
|
|
||||||
|
|
||||||
# 4. Add or get a zone subscription
|
# 4. Add or get a zone subscription
|
||||||
|
|
||||||
|
@ -628,17 +626,14 @@ class PrototypeDomainDNSRecordView(DomainFormBaseView):
|
||||||
logger.debug(f"get subscription: {subscription_response_json}")
|
logger.debug(f"get subscription: {subscription_response_json}")
|
||||||
|
|
||||||
# Create a subscription if one doesn't exist already.
|
# Create a subscription if one doesn't exist already.
|
||||||
# If it doesn't, we get this error message (code 1207):
|
# If it doesn't, we get this error message (code 1207):
|
||||||
# Add a core subscription first and try again. The zone does not have an active core subscription.
|
# Add a core subscription first and try again. The zone does not have an active core subscription.
|
||||||
# Note that status code and error code are different here.
|
# Note that status code and error code are different here.
|
||||||
if subscription_response.status_code == 404:
|
if subscription_response.status_code == 404:
|
||||||
subscription_response = requests.post(
|
subscription_response = requests.post(
|
||||||
f"{base_url}/zones/{zone_id}/subscription",
|
f"{base_url}/zones/{zone_id}/subscription",
|
||||||
headers=headers,
|
headers=headers,
|
||||||
json={
|
json={"rate_plan": {"id": "PARTNERS_ENT"}, "frequency": "annual"},
|
||||||
"rate_plan": {"id": "PARTNERS_ENT"},
|
|
||||||
"frequency": "annual"
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
subscription_response.raise_for_status()
|
subscription_response.raise_for_status()
|
||||||
subscription_response_json = subscription_response.json()
|
subscription_response_json = subscription_response.json()
|
||||||
|
@ -646,7 +641,6 @@ class PrototypeDomainDNSRecordView(DomainFormBaseView):
|
||||||
else:
|
else:
|
||||||
subscription_response.raise_for_status()
|
subscription_response.raise_for_status()
|
||||||
|
|
||||||
|
|
||||||
# # 5. Create DNS record
|
# # 5. Create DNS record
|
||||||
# # Format the DNS record according to Cloudflare's API requirements
|
# # Format the DNS record according to Cloudflare's API requirements
|
||||||
dns_response = requests.post(
|
dns_response = requests.post(
|
||||||
|
@ -657,29 +651,20 @@ class PrototypeDomainDNSRecordView(DomainFormBaseView):
|
||||||
"name": form.cleaned_data["name"],
|
"name": form.cleaned_data["name"],
|
||||||
"content": form.cleaned_data["content"],
|
"content": form.cleaned_data["content"],
|
||||||
"ttl": int(form.cleaned_data["ttl"]),
|
"ttl": int(form.cleaned_data["ttl"]),
|
||||||
"comment": "Test record (will need clean up)"
|
"comment": "Test record (will need clean up)",
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
dns_response_json = dns_response.json()
|
dns_response_json = dns_response.json()
|
||||||
logger.info(f"Created DNS record: {dns_response_json}")
|
logger.info(f"Created DNS record: {dns_response_json}")
|
||||||
errors = dns_response_json.get("errors", [])
|
errors = dns_response_json.get("errors", [])
|
||||||
dns_response.raise_for_status()
|
dns_response.raise_for_status()
|
||||||
messages.success(
|
messages.success(request, f"DNS A record '{form.cleaned_data['name']}' created successfully.")
|
||||||
request,
|
|
||||||
f"DNS A record '{form.cleaned_data['name']}' created successfully."
|
|
||||||
)
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"Error creating DNS A record for {self.object.name}: {err}")
|
logger.error(f"Error creating DNS A record for {self.object.name}: {err}")
|
||||||
messages.error(
|
messages.error(request, f"An error occurred: {err}")
|
||||||
request,
|
|
||||||
f"An error occurred: {err}"
|
|
||||||
)
|
|
||||||
finally:
|
finally:
|
||||||
if errors:
|
if errors:
|
||||||
messages.error(
|
messages.error(request, f"Request errors: {errors}")
|
||||||
request,
|
|
||||||
f"Request errors: {errors}"
|
|
||||||
)
|
|
||||||
return super().post(request)
|
return super().post(request)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue