tfstate: very basic terraform state backend in flask
This commit is contained in:
parent
29870639b8
commit
affa0f0149
4 changed files with 88 additions and 0 deletions
|
@ -6,6 +6,7 @@ from app.extensions import db
|
||||||
from app.extensions import migrate
|
from app.extensions import migrate
|
||||||
from app.extensions import bootstrap
|
from app.extensions import bootstrap
|
||||||
from app.portal import portal
|
from app.portal import portal
|
||||||
|
from app.tfstate import tfstate
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.config.from_file("../config.yaml", load=yaml.safe_load)
|
app.config.from_file("../config.yaml", load=yaml.safe_load)
|
||||||
|
@ -14,6 +15,7 @@ migrate.init_app(app, db, render_as_batch=True)
|
||||||
bootstrap.init_app(app)
|
bootstrap.init_app(app)
|
||||||
|
|
||||||
app.register_blueprint(portal, url_prefix="/portal")
|
app.register_blueprint(portal, url_prefix="/portal")
|
||||||
|
app.register_blueprint(tfstate, url_prefix="/tfstate")
|
||||||
|
|
||||||
|
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
|
|
7
app/models/tfstate.py
Normal file
7
app/models/tfstate.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
from app.extensions import db
|
||||||
|
|
||||||
|
|
||||||
|
class TerraformState(db.Model):
|
||||||
|
key = db.Column(db.String, primary_key=True)
|
||||||
|
state = db.Column(db.String)
|
||||||
|
lock = db.Column(db.String)
|
51
app/tfstate.py
Normal file
51
app/tfstate.py
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
from flask import Blueprint, request, Response
|
||||||
|
|
||||||
|
from app.extensions import db
|
||||||
|
from app.models.tfstate import TerraformState
|
||||||
|
|
||||||
|
tfstate = Blueprint("tfstate", __name__)
|
||||||
|
|
||||||
|
|
||||||
|
@tfstate.route("/<key>", methods=['GET'])
|
||||||
|
def handle_get(key):
|
||||||
|
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("/<key>", methods=['POST', 'DELETE', 'UNLOCK'])
|
||||||
|
def handle_update(key):
|
||||||
|
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):
|
||||||
|
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("/<key>", methods=['LOCK'])
|
||||||
|
def handle_lock(key):
|
||||||
|
state = TerraformState.query.filter(TerraformState.key == key).with_for_update().first()
|
||||||
|
if state is None:
|
||||||
|
state = TerraformState(key=key)
|
||||||
|
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
|
28
migrations/versions/665e340dbe09_add_terraform_state.py
Normal file
28
migrations/versions/665e340dbe09_add_terraform_state.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
"""add terraform state
|
||||||
|
|
||||||
|
Revision ID: 665e340dbe09
|
||||||
|
Revises: c644bb20d0e3
|
||||||
|
Create Date: 2022-08-29 17:10:05.447985
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '665e340dbe09'
|
||||||
|
down_revision = 'c644bb20d0e3'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.create_table('terraform_state',
|
||||||
|
sa.Column('key', sa.String(), nullable=False),
|
||||||
|
sa.Column('state', sa.String(), nullable=True),
|
||||||
|
sa.Column('lock', sa.String(), nullable=True),
|
||||||
|
sa.PrimaryKeyConstraint('key', name=op.f('pk_terraform_state'))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.drop_table('terraform_state')
|
Loading…
Add table
Add a link
Reference in a new issue