import datetime from typing import Iterable, Optional, Any, List from app import app from app.extensions import db from app.models.bridges import BridgeConf, Bridge from app.models.base import Group from app.terraform.terraform import TerraformAutomation class BridgeAutomation(TerraformAutomation): 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. """ def create_missing(self) -> None: bridgeconfs: Iterable[BridgeConf] = BridgeConf.query.filter( BridgeConf.provider == self.provider, BridgeConf.destroyed.is_(None) ).all() for bridgeconf in bridgeconfs: active_bridges = Bridge.query.filter( Bridge.conf_id == bridgeconf.id, Bridge.deprecated.is_(None) ).all() if len(active_bridges) < bridgeconf.number: for i in range(bridgeconf.number - len(active_bridges)): bridge = Bridge() bridge.conf_id = bridgeconf.id bridge.added = datetime.datetime.utcnow() bridge.updated = datetime.datetime.utcnow() db.session.add(bridge) elif len(active_bridges) > bridgeconf.number: active_bridge_count = len(active_bridges) for bridge in active_bridges: bridge.deprecate(reason="redundant") active_bridge_count -= 1 if active_bridge_count == bridgeconf.number: break db.session.commit() def destroy_expired(self) -> None: cutoff = datetime.datetime.utcnow() - datetime.timedelta(days=0) bridges = [b for b in Bridge.query.filter( Bridge.destroyed.is_(None), Bridge.deprecated < cutoff ).all() if b.conf.provider == self.provider] for bridge in bridges: bridge.destroy() db.session.commit() def tf_prehook(self) -> Optional[Any]: self.create_missing() self.destroy_expired() return None def tf_generate(self) -> None: self.tf_write( self.template, groups=Group.query.all(), bridgeconfs=BridgeConf.query.filter( BridgeConf.destroyed.is_(None), BridgeConf.provider == self.provider ).all(), global_namespace=app.config['GLOBAL_NAMESPACE'], **{ k: app.config[k.upper()] for k in self.template_parameters } ) def tf_posthook(self, *, prehook_result: Any = None) -> None: outputs = self.tf_output() for output in outputs: if output.startswith('bridge_hashed_fingerprint_'): parts = outputs[output]['value'].split(" ") if len(parts) < 2: continue bridge = Bridge.query.filter(Bridge.id == output[len('bridge_hashed_fingerprint_'):]).first() bridge.nickname = parts[0] bridge.hashed_fingerprint = parts[1] bridge.terraform_updated = datetime.datetime.utcnow() if output.startswith('bridge_bridgeline_'): parts = outputs[output]['value'].split(" ") if len(parts) < 4: continue bridge = Bridge.query.filter(Bridge.id == output[len('bridge_bridgeline_'):]).first() del(parts[3]) bridge.bridgeline = " ".join(parts) bridge.terraform_updated = datetime.datetime.utcnow() db.session.commit()