import json from flask import Blueprint, Response, request from flask.typing import ResponseReturnValue from app.extensions import db from app.models.tfstate import TerraformState tfstate = Blueprint("tfstate", __name__) @tfstate.route("/", methods=["GET"]) def handle_get(key: str) -> ResponseReturnValue: state = TerraformState.query.filter(TerraformState.key == key).first() if state is None or state.state is None: return "Not Found", 404 return Response(state.state, content_type="application/json") @tfstate.route("/", methods=["POST", "DELETE", "UNLOCK"]) def handle_update(key: str) -> ResponseReturnValue: state = TerraformState.query.filter(TerraformState.key == key).first() if not state: if request.method in ["DELETE", "UNLOCK"]: return "OK", 200 state = TerraformState(key=key) if state.lock and not ( request.method == "UNLOCK" and request.args.get("ID") is None ): # force-unlock seems to not give an ID to verify so accept no ID being present if json.loads(state.lock)["ID"] != request.args.get("ID"): return Response(state.lock, status=409, content_type="application/json") if request.method == "POST": state.state = json.dumps(request.json) elif request.method == "DELETE": db.session.delete(state) elif request.method == "UNLOCK": state.lock = None db.session.commit() return "OK", 200 @tfstate.route("/", methods=["LOCK"]) def handle_lock(key: str) -> ResponseReturnValue: state = ( TerraformState.query.filter(TerraformState.key == key).with_for_update().first() ) if state is None: state = TerraformState(key=key, state="") db.session.add(state) if state.lock is not None: lock = state.lock db.session.rollback() return Response(lock, status=423, content_type="application/json") state.lock = json.dumps(request.json) db.session.commit() return "OK", 200