majuna/app/terraform/bridge/__init__.py

119 lines
4.2 KiB
Python
Raw Normal View History

import os
import sys
from datetime import datetime, timedelta, timezone
from typing import Any, List, Optional, Sequence, Tuple
2023-02-26 12:52:08 +00:00
from sqlalchemy import Row, select
2022-03-10 14:26:22 +00:00
from app import app
from app.extensions import db
from app.models import AbstractResource
2023-02-26 12:52:08 +00:00
from app.models.bridges import Bridge, BridgeConf
from app.models.cloud import CloudAccount, CloudProvider
from app.terraform.terraform import TerraformAutomation
2022-03-10 14:26:22 +00:00
BridgeResourceRow = Row[Tuple[AbstractResource, BridgeConf, CloudAccount]]
2023-02-26 12:52:08 +00:00
def active_bridges_by_provider(provider: CloudProvider) -> Sequence[BridgeResourceRow]:
2024-12-06 18:15:47 +00:00
stmt = (
select(Bridge, BridgeConf, CloudAccount)
.join_from(Bridge, BridgeConf)
.join_from(Bridge, CloudAccount)
.where(
CloudAccount.provider == provider,
Bridge.destroyed.is_(None),
)
2023-02-26 12:52:08 +00:00
)
bridges: Sequence[BridgeResourceRow] = db.session.execute(stmt).all()
2023-02-26 12:52:08 +00:00
return bridges
2024-12-06 18:15:47 +00:00
def recently_destroyed_bridges_by_provider(
provider: CloudProvider,
) -> Sequence[BridgeResourceRow]:
cutoff = datetime.now(tz=timezone.utc) - timedelta(hours=72)
2024-12-06 18:15:47 +00:00
stmt = (
select(Bridge, BridgeConf, CloudAccount)
.join_from(Bridge, BridgeConf)
.join_from(Bridge, CloudAccount)
.where(
CloudAccount.provider == provider,
Bridge.destroyed.is_not(None),
Bridge.destroyed >= cutoff,
)
2023-02-26 12:52:08 +00:00
)
bridges: Sequence[BridgeResourceRow] = db.session.execute(stmt).all()
2023-02-26 12:52:08 +00:00
return bridges
2022-03-10 14:26:22 +00:00
class BridgeAutomation(TerraformAutomation):
2022-05-16 11:44:03 +01:00
template: str
"""
Terraform configuration template using Jinja 2.
"""
template_parameters: List[str]
"""
List of parameters to be read from the application configuration for use
in the templating of the Terraform configuration.
"""
max_bridges = sys.maxsize
2022-03-10 14:26:22 +00:00
# TODO: Only enable providers that have details configured
enabled = True
2022-03-10 14:26:22 +00:00
def tf_prehook(self) -> Optional[Any]: # pylint: disable=useless-return
2022-05-16 11:44:03 +01:00
return None
2022-05-16 11:44:03 +01:00
def tf_generate(self) -> None:
self.tf_write(
2022-03-10 14:26:22 +00:00
self.template,
2023-02-26 12:52:08 +00:00
active_resources=active_bridges_by_provider(self.provider),
destroyed_resources=recently_destroyed_bridges_by_provider(self.provider),
2024-12-06 18:15:47 +00:00
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}"
}}""",
2024-12-06 18:15:47 +00:00
**{k: app.config[k.upper()] for k in self.template_parameters},
2022-03-10 14:26:22 +00:00
)
def tf_posthook(self, *, prehook_result: Any = None) -> None:
outputs = self.tf_output()
2022-03-10 14:26:22 +00:00
for output in outputs:
2024-12-06 18:15:47 +00:00
if output.startswith("bridge_hashed_fingerprint_"):
parts = outputs[output]["value"].split(" ")
2022-03-10 14:26:22 +00:00
if len(parts) < 2:
continue
2024-12-06 18:15:47 +00:00
bridge = Bridge.query.filter(
Bridge.id == output[len("bridge_hashed_fingerprint_") :]
).first()
2022-03-10 14:26:22 +00:00
bridge.nickname = parts[0]
bridge.hashed_fingerprint = parts[1]
bridge.terraform_updated = datetime.now(tz=timezone.utc)
2024-12-06 18:15:47 +00:00
if output.startswith("bridge_bridgeline_"):
parts = outputs[output]["value"].split(" ")
2022-03-10 14:26:22 +00:00
if len(parts) < 4:
continue
2024-12-06 18:15:47 +00:00
bridge = Bridge.query.filter(
Bridge.id == output[len("bridge_bridgeline_") :]
).first()
del parts[3]
2022-03-10 14:26:22 +00:00
bridge.bridgeline = " ".join(parts)
bridge.terraform_updated = datetime.now(tz=timezone.utc)
2022-03-10 14:26:22 +00:00
db.session.commit()
@classmethod
def active_bridges_count(self) -> int:
active_bridges = Bridge.query.filter(
Bridge.provider == self.provider,
Bridge.destroyed.is_(None),
).all()
return len(active_bridges)