diff --git a/app/cli/automate.py b/app/cli/automate.py index 93552cd..21e0b00 100644 --- a/app/cli/automate.py +++ b/app/cli/automate.py @@ -12,7 +12,7 @@ from app.terraform.block_bridge_github import BlockBridgeGitHubAutomation from app.terraform.block_external import BlockExternalAutomation from app.terraform.block_ooni import BlockOONIAutomation from app.terraform.block_roskomsvoboda import BlockRoskomsvobodaAutomation -from app.terraform.eotk import EotkAutomation +from app.terraform.eotk.aws import EotkAWSAutomation from app.terraform.alarms.proxy_azure_cdn import AlarmProxyAzureCdnAutomation from app.terraform.alarms.proxy_cloudfront import AlarmProxyCloudfrontAutomation from app.terraform.alarms.proxy_http_status import AlarmProxyHTTPStatusAutomation @@ -41,7 +41,7 @@ jobs = { BridgeGandiAutomation, BridgeHcloudAutomation, BridgeOvhAutomation, - EotkAutomation, + EotkAWSAutomation, ListGithubAutomation, ListGitlabAutomation, ListS3Automation, diff --git a/app/models/onions.py b/app/models/onions.py index faac6c6..cb8f252 100644 --- a/app/models/onions.py +++ b/app/models/onions.py @@ -13,6 +13,7 @@ class Onion(AbstractConfiguration): class Eotk(AbstractResource): group_id = db.Column(db.Integer(), db.ForeignKey("group.id"), nullable=False) instance_id = db.Column(db.String(100), nullable=True) + provider = db.Column(db.String(20), nullable=False) region = db.Column(db.String(20), nullable=False) group = db.relationship("Group", back_populates="eotks") diff --git a/app/portal/__init__.py b/app/portal/__init__.py index 527589f..ac2987a 100644 --- a/app/portal/__init__.py +++ b/app/portal/__init__.py @@ -10,6 +10,7 @@ from app.portal.list import NewMirrorListForm from app.portal.automation import bp as automation from app.portal.bridgeconf import bp as bridgeconf from app.portal.bridge import bp as bridge +from app.portal.eotk import bp as eotk from app.portal.group import bp as group from app.portal.list import bp as list_ from app.portal.origin import bp as origin @@ -20,6 +21,7 @@ portal = Blueprint("portal", __name__, template_folder="templates", static_folde portal.register_blueprint(automation, url_prefix="/automation") portal.register_blueprint(bridgeconf, url_prefix="/bridgeconf") portal.register_blueprint(bridge, url_prefix="/bridge") +portal.register_blueprint(eotk, url_prefix="/eotk") portal.register_blueprint(group, url_prefix="/group") portal.register_blueprint(list_, url_prefix="/list") portal.register_blueprint(origin, url_prefix="/origin") diff --git a/app/portal/eotk.py b/app/portal/eotk.py new file mode 100644 index 0000000..d730c1a --- /dev/null +++ b/app/portal/eotk.py @@ -0,0 +1,16 @@ +from flask import render_template, Blueprint +from sqlalchemy import desc + +from app.models.onions import Eotk + +bp = Blueprint("eotk", __name__) + + +@bp.route("/list") +def eotk_list(): + instances = Eotk.query.filter(Eotk.destroyed == None).order_by(desc(Eotk.added)).all() + return render_template("list.html.j2", + section="eotk", + title="EOTK Instances", + item="eotk", + items=instances) diff --git a/app/portal/templates/base.html.j2 b/app/portal/templates/base.html.j2 index 1d9d65a..c763d4f 100644 --- a/app/portal/templates/base.html.j2 +++ b/app/portal/templates/base.html.j2 @@ -132,8 +132,8 @@ diff --git a/app/portal/templates/list.html.j2 b/app/portal/templates/list.html.j2 index 35e6407..525016f 100644 --- a/app/portal/templates/list.html.j2 +++ b/app/portal/templates/list.html.j2 @@ -1,5 +1,5 @@ {% extends "base.html.j2" %} -{% from "tables.html.j2" import alarms_table, automations_table, bridgeconfs_table, bridges_table, +{% from "tables.html.j2" import alarms_table, automations_table, bridgeconfs_table, bridges_table, eotk_table, groups_table, mirrorlists_table, origins_table, origin_onion_table, onions_table, proxies_table %} {% block content %} diff --git a/app/portal/templates/tables.html.j2 b/app/portal/templates/tables.html.j2 index b808ce2..a5e1f01 100644 --- a/app/portal/templates/tables.html.j2 +++ b/app/portal/templates/tables.html.j2 @@ -55,12 +55,62 @@ {% endmacro %} -{% macro eotk_table(eotks) %} -
Not implemented yet.
+{% macro eotk_table(instances) %} +
+ + + + + + + + + + + + + + {% for instance in instances %} + {% if not instance.destroyed %} + + + + + + + + + + {% endif %} + {% endfor %} + +
GroupProviderRegionInstance IDCreatedAlarmsActions
+ {{ instance.group.group_name }} + {{ instance.provider }}{{ instance.region }} + {{ instance.instance_id }} + + {{ instance.added | format_datetime }} + + {% for alarm in [] %} + + {% if alarm.alarm_state.name == "OK" %} + {{ alarm_ok() }} + {% elif alarm.alarm_state.name == "UNKNOWN" %} + {{ alarm_unknown() }} + {% else %} + {{ alarm_critical() }} + {% endif %} + + {% endfor %} + + Generate Configuration +
+
{% endmacro %} {% macro automations_table(automations) %} -
+
diff --git a/app/terraform/eotk.py b/app/terraform/eotk.py deleted file mode 100644 index e88515a..0000000 --- a/app/terraform/eotk.py +++ /dev/null @@ -1,66 +0,0 @@ -from app import app -from app.models.base import Group -from app.terraform.terraform import TerraformAutomation - - -class EotkAutomation(TerraformAutomation): - short_name = "eotk" - description = "Deploy EOTK instances to AWS" - - template_parameters = [ - "aws_access_key", - "aws_secret_key" - ] - - template = """ - terraform { - required_providers { - aws = { - version = "~> 4.4.0" - } - } - } - - provider "aws" { - access_key = "{{ aws_access_key }}" - secret_key = "{{ aws_secret_key }}" - region = "us-east-2" - } - - provider "aws" { - access_key = "{{ aws_access_key }}" - secret_key = "{{ aws_secret_key }}" - region = "eu-central-1" - alias = "second_region" - } - - {% for group in groups %} - module "eotk_{{ group.id }}" { - providers = { - aws = aws, - aws.second_region = aws.second_region - } - source = "sr2c/eotk/aws" - version = "0.0.5" - namespace = "{{ global_namespace }}" - tenant = "{{ group.group_name }}" - name = "eotk" - label_order = ["namespace", "tenant", "name", "attributes"] - disable_api_termination = true - } - {% endfor %} - """ - - def tf_generate(self): - self.tf_write( - self.template, - groups=Group.query.filter( - Group.eotk == True, - Group.destroyed == None - ).all(), - global_namespace=app.config['GLOBAL_NAMESPACE'], - **{ - k: app.config[k.upper()] - for k in self.template_parameters - } - ) diff --git a/app/terraform/eotk/__init__.py b/app/terraform/eotk/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/terraform/eotk/aws.py b/app/terraform/eotk/aws.py new file mode 100644 index 0000000..4f79384 --- /dev/null +++ b/app/terraform/eotk/aws.py @@ -0,0 +1,110 @@ +import datetime +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.terraform import TerraformAutomation + + +def update_eotk_instance(group_id: int, region: str, instance_id: str): + instance = Eotk.query.filter( + Eotk.group_id == group_id, + Eotk.region == region, + Eotk.provider == "aws", + Eotk.destroyed == None + ).first() + if instance is None: + instance = Eotk() + instance.added = datetime.datetime.utcnow() + instance.group_id = group_id + instance.provider = "aws" + instance.region = region + db.session.add(instance) + instance.updated = datetime.datetime.utcnow() + 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 { + required_providers { + aws = { + version = "~> 4.4.0" + } + } + } + + provider "aws" { + access_key = "{{ aws_access_key }}" + secret_key = "{{ aws_secret_key }}" + region = "us-east-2" + } + + provider "aws" { + access_key = "{{ aws_access_key }}" + secret_key = "{{ aws_secret_key }}" + region = "eu-central-1" + alias = "second_region" + } + + {% for group in groups %} + module "eotk_{{ group.id }}" { + providers = { + aws = aws, + aws.second_region = aws.second_region + } + source = "sr2c/eotk/aws" + version = "0.0.5" + namespace = "{{ global_namespace }}" + tenant = "{{ group.group_name }}" + name = "eotk" + label_order = ["namespace", "tenant", "name", "attributes"] + disable_api_termination = true + } + {% endfor %} + """ + + def tf_generate(self): + self.tf_write( + self.template, + groups=Group.query.filter( + Group.eotk == True, + Group.destroyed == None + ).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: + state = self.tf_show() + for g in state["values"]["root_module"]["child_modules"]: + if g["address"].startswith("module.eotk_"): + group_id = int(g["address"][len("module.eotk_"):]) + for i in g["child_modules"]: + if ".module.instance_" in i["address"]: + instance = int(i["address"][-1]) + region = "us-east-2" if instance == 1 else "eu-central-1" + for s in i["child_modules"]: + if s["address"].endswith(".module.instance"): + for x in s["resources"]: + if x["address"].endswith(".module.instance.aws_instance.default[0]"): + update_eotk_instance(group_id, region, x['values']['id']) + db.session.commit() + + +with app.app_context(): + auto = EotkAWSAutomation() + auto.tf_posthook() diff --git a/migrations/versions/7ecfb305d243_add_eotk_provider.py b/migrations/versions/7ecfb305d243_add_eotk_provider.py new file mode 100644 index 0000000..56e751e --- /dev/null +++ b/migrations/versions/7ecfb305d243_add_eotk_provider.py @@ -0,0 +1,46 @@ +"""add eotk provider + +Revision ID: 7ecfb305d243 +Revises: 7155ba7dec60 +Create Date: 2022-05-13 15:34:59.922410 + +""" +from alembic import op +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision = '7ecfb305d243' +down_revision = '7155ba7dec60' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('eotk_instance', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('added', sa.DateTime(), nullable=False), + sa.Column('updated', sa.DateTime(), nullable=False), + sa.Column('deprecated', sa.DateTime(), nullable=True), + sa.Column('deprecation_reason', sa.String(), nullable=True), + sa.Column('destroyed', sa.DateTime(), nullable=True), + sa.Column('group_id', sa.Integer(), nullable=False), + sa.Column('provider', sa.String(length=20), nullable=False), + sa.Column('region', sa.String(length=20), nullable=False), + sa.Column('instance_id', sa.String(length=255), nullable=True), + sa.ForeignKeyConstraint(['group_id'], ['group.id'], name=op.f('fk_eotk_instance_group_id_group')), + sa.PrimaryKeyConstraint('id', name=op.f('pk_eotk_instance')) + ) + with op.batch_alter_table('eotk', schema=None) as batch_op: + batch_op.add_column(sa.Column('provider', sa.String(length=20), nullable=False)) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('eotk', schema=None) as batch_op: + batch_op.drop_column('provider') + + op.drop_table('eotk_instance') + # ### end Alembic commands ###