127 lines
4.4 KiB
Python
127 lines
4.4 KiB
Python
import os
|
|
from datetime import datetime, timezone
|
|
from typing import Any
|
|
|
|
from app import app
|
|
from app.extensions import db
|
|
from app.models.base import Group
|
|
from app.models.onions import Eotk
|
|
from app.terraform import DeterministicZip
|
|
from app.terraform.eotk import eotk_configuration
|
|
from app.terraform.terraform import TerraformAutomation
|
|
|
|
|
|
def update_eotk_instance(group_id: int, region: str, instance_id: str) -> None:
|
|
instance = Eotk.query.filter(
|
|
Eotk.group_id == group_id,
|
|
Eotk.region == region,
|
|
Eotk.provider == "aws",
|
|
Eotk.destroyed.is_(None),
|
|
).first()
|
|
if instance is None:
|
|
instance = Eotk()
|
|
instance.added = datetime.now(tz=timezone.utc)
|
|
instance.group_id = group_id
|
|
instance.provider = "aws"
|
|
instance.region = region
|
|
db.session.add(instance)
|
|
instance.updated = datetime.now(tz=timezone.utc)
|
|
instance.instance_id = instance_id
|
|
|
|
|
|
class EotkAWSAutomation(TerraformAutomation):
|
|
short_name = "eotk_aws"
|
|
description = "Deploy EOTK instances to AWS"
|
|
|
|
template_parameters = ["aws_access_key", "aws_secret_key"]
|
|
|
|
template = """
|
|
terraform {
|
|
{{ backend_config }}
|
|
required_providers {
|
|
aws = {
|
|
version = "~> 4.4.0"
|
|
}
|
|
}
|
|
}
|
|
|
|
provider "aws" {
|
|
access_key = "{{ aws_access_key }}"
|
|
secret_key = "{{ aws_secret_key }}"
|
|
region = "us-east-2"
|
|
}
|
|
|
|
{% for group in groups %}
|
|
module "eotk_{{ group.id }}" {
|
|
source = "{{ terraform_modules_path }}/terraform-aws-bc-eotk"
|
|
namespace = "{{ global_namespace }}"
|
|
tenant = "{{ group.group_name }}"
|
|
name = "eotk"
|
|
label_order = ["namespace", "tenant", "name", "attributes"]
|
|
tags = {
|
|
"Application" = "EOTK"
|
|
}
|
|
configuration_bundle = "{{ group.id }}.zip"
|
|
}
|
|
|
|
output "eotk_instances_{{ group.id }}" {
|
|
value = module.eotk_{{ group.id }}.instances
|
|
}
|
|
{% endfor %}
|
|
"""
|
|
|
|
def tf_generate(self) -> None:
|
|
if not self.working_dir:
|
|
raise RuntimeError("No working directory specified.")
|
|
self.tf_write(
|
|
self.template,
|
|
groups=Group.query.filter(
|
|
Group.eotk.is_(True), Group.destroyed.is_(None)
|
|
).all(),
|
|
global_namespace=app.config["GLOBAL_NAMESPACE"],
|
|
terraform_modules_path=os.path.join(
|
|
*list(os.path.split(app.root_path))[:-1], "terraform-modules"
|
|
),
|
|
backend_config=f"""backend "http" {{
|
|
lock_address = "{app.config['TFSTATE_BACKEND']}/{self.short_name}"
|
|
unlock_address = "{app.config['TFSTATE_BACKEND']}/{self.short_name}"
|
|
address = "{app.config['TFSTATE_BACKEND']}/{self.short_name}"
|
|
}}""",
|
|
**{k: app.config[k.upper()] for k in self.template_parameters},
|
|
)
|
|
for group in (
|
|
Group.query.filter(Group.eotk.is_(True), Group.destroyed.is_(None))
|
|
.order_by(Group.id)
|
|
.all()
|
|
):
|
|
with DeterministicZip(
|
|
os.path.join(self.working_dir, f"{group.id}.zip")
|
|
) as dzip:
|
|
dzip.add_file("sites.conf", eotk_configuration(group).encode("utf-8"))
|
|
for onion in sorted(group.onions, key=lambda o: o.onion_name):
|
|
dzip.add_file(
|
|
f"{onion.onion_name}.v3pub.key", onion.onion_public_key
|
|
)
|
|
dzip.add_file(
|
|
f"{onion.onion_name}.v3sec.key", onion.onion_private_key
|
|
)
|
|
dzip.add_file(
|
|
f"{onion.onion_name[:20]}-v3.cert", onion.tls_public_key
|
|
)
|
|
dzip.add_file(
|
|
f"{onion.onion_name[:20]}-v3.pem", onion.tls_private_key
|
|
)
|
|
|
|
def tf_posthook(self, *, prehook_result: Any = None) -> None:
|
|
for e in Eotk.query.all():
|
|
db.session.delete(e)
|
|
outputs = self.tf_output()
|
|
for output in outputs:
|
|
if output.startswith("eotk_instances_"):
|
|
try:
|
|
group_id = int(output[len("eotk_instance_") + 1 :])
|
|
for az in outputs[output]["value"]:
|
|
update_eotk_instance(group_id, az, outputs[output]["value"][az])
|
|
except ValueError:
|
|
pass
|
|
db.session.commit()
|