Skip to content

Commit

Permalink
Merge pull request #149 from nossas/feature/domains-infra
Browse files Browse the repository at this point in the history
Infraestrutura de domínios (Pt. 1)
  • Loading branch information
igr-santos authored Dec 13, 2023
2 parents 92de42b + f9e7979 commit 7debd34
Show file tree
Hide file tree
Showing 33 changed files with 1,032 additions and 128 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,7 @@ GitHub.sublime-settings
.history

# Tailwind
node_modules/
node_modules/

# Domains
deploy/letsencrypt
6 changes: 5 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,8 @@ COPY --from=node-builder /app ./
RUN python manage.py collectstatic --noinput --clear -i tailwindcss

# Runtime command that executes when "docker run" is called.
CMD ["uwsgi", "--ini", "/app/wsgi.ini"]

# Check traefik + etcd configs to running domains
ENV ENABLE_CHECK_TRAEFIK=True

CMD ["uwsgi", "--ini", "/app/wsgi.ini"]
Empty file added app/contrib/domains/__init__.py
Empty file.
Empty file.
56 changes: 56 additions & 0 deletions app/contrib/domains/route53/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from django.contrib import admin
from django.http.request import HttpRequest

from django.utils.html import format_html


from .models import VPS, HostedZone, RecordSet


class VPSAdmin(admin.ModelAdmin):
list_display = ("name", "static_ip")
# list_filter = ("name", )

admin.site.register(VPS, VPSAdmin)


class RecordSetAdmin(admin.ModelAdmin):
search_fields = ("name", )


admin.site.register(RecordSet, RecordSetAdmin)


class RecordSetInline(admin.TabularInline):
model = RecordSet
extra = 0


class HostedZoneAdmin(admin.ModelAdmin):
list_display = ("name", "vps", "healtcheck")
search_fields = ("name", )
list_filter = ("healtcheck", )
readonly_fields = ("healtcheck", )
inlines = [RecordSetInline, ]

class Media:
css = {
'all': ('css/route53/tags.css',)
}

def has_add_permission(self, request: HttpRequest) -> bool:
return False

def has_change_permission(self, request: HttpRequest, obj=None) -> bool:
return False

def vps(self, obj):
html = "<ul class='tags'>"
for x in obj.related_instances():
html += "<li>" + x.name + "</li>"
html += "</ul>"

return format_html(html)


admin.site.register(HostedZone, HostedZoneAdmin)
14 changes: 14 additions & 0 deletions app/contrib/domains/route53/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from django.apps import AppConfig
from django.db.models.signals import pre_delete, pre_save


class Route53AppConfig(AppConfig):
name = "contrib.domains.route53"

def ready(self):
from . import signals, models

# pre_save.connect(signals.create_or_update_route53, models.HostedZone)

pre_delete.connect(signals.delete_on_route53, models.RecordSet)
pre_delete.connect(signals.delete_on_route53, models.HostedZone)
51 changes: 51 additions & 0 deletions app/contrib/domains/route53/entries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from django.conf import settings


class Manager:
def __init__(self, name=None, fields=None):
import boto3

self.client = boto3.client(
"route53",
aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
# aws_region=settings.AWS_REGION
)

def list_hosted_zones(self):
response = self.client.list_hosted_zones()
hosted_zones = response.get("HostedZones", [])

return list(
map(
lambda x: HostedZone(id=x.get("Id", ""), name=x.get("Name", "")),
hosted_zones,
)
)

def get_hosted_zone(self, id):
return self.client.get_hosted_zone(Id=id)

def list_resource_record_sets(self, id):
return self.client.list_resource_record_sets(HostedZoneId=id)

def test_dns_answer(self, id, record_name, record_type):
return self.client.test_dns_answer(
HostedZoneId=id, RecordName=record_name, RecordType=record_type
)


class HostedZone(object):
id: str
name: str

def __init__(self, id, name):
self.id = id
self.name = name

objects = Manager()

@property
def delegation_set(self):
response = self.objects.client.get_hosted_zone(Id=self.id)
return response.get("DelegationSet")
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import boto3

from django.conf import settings
from django.core.management.base import BaseCommand, CommandError

from contrib.domains.route53.models import HostedZone, RecordSet


class Command(BaseCommand):
help = ""

def handle(self, *args, **options):
for hz in HostedZone.objects.all():
hz.healtcheck = hz.check_ns()
hz.save()

is_ok = HostedZone.objects.filter(healtcheck=True).count()
is_fail = HostedZone.objects.filter(healtcheck=False).count()

self.stdout.write(
self.style.SUCCESS(
f"Successfully to update HostedZone: {is_ok} ok | {is_fail} fail."
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import boto3

from django.conf import settings
from django.core.management.base import BaseCommand, CommandError

from contrib.domains.route53.models import HostedZone, RecordSet
from contrib.domains.route53.utils import get_record_set

# from route53.entries import HostedZone as HostedZoneEntry


class Command(BaseCommand):
help = ""

def get_list_resource_record_sets(self, hosted_zone_id, next_marker=None):
params = {"Marker": next_marker} if next_marker else {}
data = self.route53.list_resource_record_sets(
HostedZoneId=hosted_zone_id, **params
)

yield self.prepare_record_set_list(data["ResourceRecordSets"])

if data["IsTruncated"] == True and "NextMarker" in data.keys():
yield from self.get_list_resource_record_sets(
hosted_zone_id, next_marker=data["NextMarker"]
)

def get_list_hosted_zones(self, next_marker=None):
params = {"Marker": next_marker} if next_marker else {}
data = self.route53.list_hosted_zones(**params)

yield self.prepare_hosted_zone_list(data["HostedZones"])

if data["IsTruncated"] == True:
# Chama função até não existir mais páginas
yield from self.get_list_hosted_zones(next_marker=data["NextMarker"])

def prepare_record_set_list(self, records=[]):
return list(map(get_record_set, records))

def prepare_hosted_zone_list(self, hosted_zones=[]):
return list(
map(
lambda x: dict(id=x.get("Id", ""), name=x.get("Name", "")),
hosted_zones,
)
)

def handle(self, *args, **options):
self.count = 0

self.route53 = boto3.client(
"route53",
aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
# aws_region=settings.AWS_REGION
)

# First called
hosted_zones_next = self.get_list_hosted_zones()
for hosted_zones in hosted_zones_next:
for hosted_zone in hosted_zones:
obj, created = HostedZone.objects.get_or_create(**hosted_zone)

records_next = self.get_list_resource_record_sets(obj.id)
for records in records_next:
for record in records:
obj, created = RecordSet.objects.get_or_create(
hosted_zone_id=hosted_zone["id"], **record
)

if created:
self.count += 1

self.stdout.write(
self.style.SUCCESS(
f"Successfully to create HostedZone: {self.count} objects."
)
)
21 changes: 21 additions & 0 deletions app/contrib/domains/route53/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 4.2.6 on 2023-10-31 19:12

from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
]

operations = [
migrations.CreateModel(
name='HostedZone',
fields=[
('id', models.CharField(max_length=50, primary_key=True, serialize=False)),
('name', models.CharField(max_length=100)),
],
),
]
21 changes: 21 additions & 0 deletions app/contrib/domains/route53/migrations/0002_vps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 4.2.6 on 2023-11-01 15:26

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('route53', '0001_initial'),
]

operations = [
migrations.CreateModel(
name='VPS',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=40)),
('static_ip', models.GenericIPAddressField(unique=True)),
],
),
]
24 changes: 24 additions & 0 deletions app/contrib/domains/route53/migrations/0003_recordset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 4.2.6 on 2023-11-06 20:42

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('route53', '0002_vps'),
]

operations = [
migrations.CreateModel(
name='RecordSet',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
('record_type', models.CharField(choices=[('SOA', 'Soa'), ('A', 'A'), ('TXT', 'Txt'), ('NS', 'Ns'), ('CNAME', 'Cname'), ('MX', 'Mx'), ('NAPTR', 'Naptr'), ('PTR', 'Ptr'), ('SRV', 'Srv'), ('SPF', 'Spf'), ('AAAA', 'Aaaa'), ('CAA', 'Caa'), ('DS', 'Ds')], max_length=5)),
('resource', models.JSONField(blank=True, null=True)),
('hosted_zone', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='route53.hostedzone')),
],
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.2.6 on 2023-11-06 22:12

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('route53', '0003_recordset'),
]

operations = [
migrations.AddField(
model_name='hostedzone',
name='healtcheck',
field=models.BooleanField(default=False),
),
]
17 changes: 17 additions & 0 deletions app/contrib/domains/route53/migrations/0005_alter_vps_options.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.2.6 on 2023-11-30 14:45

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('route53', '0004_hostedzone_healtcheck'),
]

operations = [
migrations.AlterModelOptions(
name='vps',
options={'verbose_name': 'Instância', 'verbose_name_plural': 'Instâncias'},
),
]
Empty file.
Loading

0 comments on commit 7debd34

Please sign in to comment.