From 04ec4037a9b712c3424ccb1abedc9574b61699e2 Mon Sep 17 00:00:00 2001 From: realaravinth Date: Fri, 24 Jun 2022 20:33:32 +0530 Subject: [PATCH 01/14] feat: init gitpython and infrastructure app --- Makefile | 11 ++++++----- dashboard/settings.py | 8 ++++++++ dashboard/urls.py | 1 + requirements.txt | 3 +++ 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 2af4ca2..e44ab37 100644 --- a/Makefile +++ b/Makefile @@ -33,11 +33,12 @@ help: ## Prints help for targets with comments @cat $(MAKEFILE_LIST) | grep -E '^[a-zA-Z_-]+:.*?## .*$$' | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' lint: ## Run linter - @./venv/bin/black ./dashboard/* - @./venv/bin/black ./accounts/* - @./venv/bin/black ./dash/* - @./venv/bin/black ./support/* - @./venv/bin/black ./billing/* + @./venv/bin/black ./dashboard/ + @./venv/bin/black ./accounts/ + @./venv/bin/black ./dash/ + @./venv/bin/black ./support/ + @./venv/bin/black ./billing/ + @./venv/bin/black ./infrastructure/ migrate: ## Run migrations $(call run_migrations) diff --git a/dashboard/settings.py b/dashboard/settings.py index 831c722..75664d8 100644 --- a/dashboard/settings.py +++ b/dashboard/settings.py @@ -47,6 +47,7 @@ INSTALLED_APPS = [ "oauth2_provider", "payments", "billing", + "infrastructure", ] MIDDLEWARE = [ @@ -177,6 +178,13 @@ HOSTEA = { # ref: https://gitea.hostea.org/Hostea/july-mvp/issues/17 "SUPPORT_REPOSITORY": "support", }, + "INFRA": { + "HOSTEA_REPO": { + "PATH": "/srv/hostea/dashboard/infrastructure", + "REMOTE": "git@localhost:Hostea/enough.git", + "SSH_KEY": "/srv/hostea/deploy", + } + }, } EMAIL_CONFIG = env.email("EMAIL_URL", default="smtp://admin:password@localhost:10025") diff --git a/dashboard/urls.py b/dashboard/urls.py index 12c3a14..13c4378 100644 --- a/dashboard/urls.py +++ b/dashboard/urls.py @@ -23,5 +23,6 @@ urlpatterns = [ path("admin/", admin.site.urls), path("dash/", include("dash.urls")), path("support/", include("support.urls")), + path("infra/", include("infrastructure.urls")), path("", include("accounts.urls")), ] diff --git a/requirements.txt b/requirements.txt index 50a105c..b771c4a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,6 +14,8 @@ django-oauth-toolkit==2.0.0 django-payments==1.0.0 django-phonenumber-field==6.3.0 djangorestframework==3.13.1 +gitdb==4.0.9 +GitPython==3.1.27 greenlet==1.1.2 idna==3.3 isort==5.10.1 @@ -34,6 +36,7 @@ pylint==2.12.2 pynvim==0.4.3 pytz==2022.1 requests==2.27.1 +smmap==5.0.0 sqlparse==0.4.2 stripe==3.4.0 tblib==1.7.0 From ff8a21d9dc7c6b3bb2298e17d020017af3aa6aa4 Mon Sep 17 00:00:00 2001 From: realaravinth Date: Fri, 24 Jun 2022 20:34:11 +0530 Subject: [PATCH 02/14] feat: bootstrap infrastructure app with create_instance delete_instance views --- infrastructure/__init__.py | 0 infrastructure/admin.py | 3 ++ infrastructure/apps.py | 6 +++ infrastructure/migrations/__init__.py | 0 infrastructure/models.py | 3 ++ infrastructure/urls.py | 23 ++++++++++ infrastructure/views.py | 64 +++++++++++++++++++++++++++ 7 files changed, 99 insertions(+) create mode 100644 infrastructure/__init__.py create mode 100644 infrastructure/admin.py create mode 100644 infrastructure/apps.py create mode 100644 infrastructure/migrations/__init__.py create mode 100644 infrastructure/models.py create mode 100644 infrastructure/urls.py create mode 100644 infrastructure/views.py diff --git a/infrastructure/__init__.py b/infrastructure/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/infrastructure/admin.py b/infrastructure/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/infrastructure/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/infrastructure/apps.py b/infrastructure/apps.py new file mode 100644 index 0000000..039f2dd --- /dev/null +++ b/infrastructure/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class InfrastructureConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "infrastructure" diff --git a/infrastructure/migrations/__init__.py b/infrastructure/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/infrastructure/models.py b/infrastructure/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/infrastructure/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/infrastructure/urls.py b/infrastructure/urls.py new file mode 100644 index 0000000..b1cd20a --- /dev/null +++ b/infrastructure/urls.py @@ -0,0 +1,23 @@ +# Copyright © 2022 Aravinth Manivannan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from django.contrib import admin +from django.urls import path, include + +from .views import create_instance, delete_instance + +urlpatterns = [ + path("create//", create_instance, name="infra.create"), + path("rm//", delete_instance, name="infra.rm"), +] diff --git a/infrastructure/views.py b/infrastructure/views.py new file mode 100644 index 0000000..d315f18 --- /dev/null +++ b/infrastructure/views.py @@ -0,0 +1,64 @@ +# Copyright © 2022 Aravinth Manivannan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from django.shortcuts import render, redirect, get_object_or_404 +from django.utils.http import urlencode +from django.contrib.auth import authenticate, login, logout +from django.contrib.auth import get_user_model +from django.contrib.auth.decorators import login_required +from django.http import HttpResponse +from django.views.decorators.csrf import csrf_protect +from django.urls import reverse + +from accounts.decorators import confirm_access +from dash.models import Instance + +from .utils import Infra + + +def default_ctx(title: str, username: str): + """ + Default context for all dashboard pages + """ + return { + "title": title, + "username": username, + "open_instances": "open", + } + + +@login_required +def create_instance(request, instance_name: str): + """ + Dashboard homepage view + """ + instance = get_object_or_404(Instance, name=instance_name, owned_by=request.user) + infra = Infra() + infra.add_vm(instance=instance) + # TODO: push isn't implemented yet + + return HttpResponse() + + +@login_required +@confirm_access +def delete_instance(request, instance_name: str): + """ + Dashboard homepage view + """ + instance = get_object_or_404(Instance, name=instance_name, owned_by=request.user) + infra = Infra() + infra.remove_vm(instance=instance) + # TODO: push isn't implemented yet + return HttpResponse() From 1a234d402f405887e5985ac496afee0255110093 Mon Sep 17 00:00:00 2001 From: realaravinth Date: Fri, 24 Jun 2022 20:35:00 +0530 Subject: [PATCH 03/14] feat: init templates from enough docs[0] [0]: https://enough-community.readthedocs.io/en/latest/services/hostea.html --- .../infrastructure/sh/hostscripts/create.sh | 2 + .../infrastructure/sh/hostscripts/rm.sh | 1 + .../templates/infrastructure/yml/backups.yml | 3 + .../templates/infrastructure/yml/gitea.yml | 83 +++++++++++++++++++ .../infrastructure/yml/provision.yml | 1 + 5 files changed, 90 insertions(+) create mode 100644 infrastructure/templates/infrastructure/sh/hostscripts/create.sh create mode 100644 infrastructure/templates/infrastructure/sh/hostscripts/rm.sh create mode 100644 infrastructure/templates/infrastructure/yml/backups.yml create mode 100644 infrastructure/templates/infrastructure/yml/gitea.yml create mode 100644 infrastructure/templates/infrastructure/yml/provision.yml diff --git a/infrastructure/templates/infrastructure/sh/hostscripts/create.sh b/infrastructure/templates/infrastructure/sh/hostscripts/create.sh new file mode 100644 index 0000000..ad607bc --- /dev/null +++ b/infrastructure/templates/infrastructure/sh/hostscripts/create.sh @@ -0,0 +1,2 @@ +enough --domain d.hostea.org host create {{subdomain}}-host +enough --domain d.hostea.org service create --host {{subdomain}}-host gitea diff --git a/infrastructure/templates/infrastructure/sh/hostscripts/rm.sh b/infrastructure/templates/infrastructure/sh/hostscripts/rm.sh new file mode 100644 index 0000000..0eeb490 --- /dev/null +++ b/infrastructure/templates/infrastructure/sh/hostscripts/rm.sh @@ -0,0 +1 @@ +enough --domain d.hostea.org host delete hostea001-host diff --git a/infrastructure/templates/infrastructure/yml/backups.yml b/infrastructure/templates/infrastructure/yml/backups.yml new file mode 100644 index 0000000..540dc86 --- /dev/null +++ b/infrastructure/templates/infrastructure/yml/backups.yml @@ -0,0 +1,3 @@ +pets: + hosts: + {{ subdomain }}-host: diff --git a/infrastructure/templates/infrastructure/yml/gitea.yml b/infrastructure/templates/infrastructure/yml/gitea.yml new file mode 100644 index 0000000..8a3c99e --- /dev/null +++ b/infrastructure/templates/infrastructure/yml/gitea.yml @@ -0,0 +1,83 @@ +--- +# +####################################### +# +# Public hostname of the Gitea instance +# +# +gitea_host: "gitea.{{ domain }}" +# +####################################### +# +# Mailer from +# +# +gitea_mailer_from: "noreply@enough.community" +# +####################################### +# +# SSH port of the Gitea instance +# +# +gitea_ssh_port: "22" +# +####################################### +# +# Gitea version +# +# +gitea_version: "1.16.8" +# +####################################### +# +# Admin user name +# +gitea_user: root +# +####################################### +# +# Admin user password +# +#gitea_password: etquofEtseudett +# +####################################### +# +# Admin user email +# +gitea_email: contact@enough.community +# +####################################### +# +# Unique hostname of the woodpecker server relative to {{ domain }} +# +woodpecker_hostname: "woodpecker" +# +####################################### +# +# Public hostname of the Woodpecker instance +# +woodpecker_host: "{{ woodpecker_hostname }}.{{ domain }}" +# +####################################### +# +# Gitea users with admin rights on woodpecker +# +woodpecker_admins: "{{ gitea_user }}" +# +####################################### +# +# Woodpecker shared agent secret `openssl rand -hex 32` +# +#woodpecker_agent_secret: c2cd326f7104c2ca93e6d22da0b28d1e33b4aeaa071c08945e0ade576b3192ce +# +####################################### +# +# Woodpecker version +# +woodpecker_version: "v0.15.2" +# +####################################### +# +# Woodpecker max procs +# +woodpecker_max_procs: 1 diff --git a/infrastructure/templates/infrastructure/yml/provision.yml b/infrastructure/templates/infrastructure/yml/provision.yml new file mode 100644 index 0000000..09998e7 --- /dev/null +++ b/infrastructure/templates/infrastructure/yml/provision.yml @@ -0,0 +1 @@ +openstack_flavor: "\{\{ {{ vm_size }} \}\}" From f3324579c9d8f7413f52e65f09eb10afa79f1955 Mon Sep 17 00:00:00 2001 From: realaravinth Date: Fri, 24 Jun 2022 20:35:32 +0530 Subject: [PATCH 04/14] feat: utilities to add and remove VM on the Hostea repo --- infrastructure/tests.py | 76 +++++++++++++++++ infrastructure/utils.py | 181 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 257 insertions(+) create mode 100644 infrastructure/tests.py create mode 100644 infrastructure/utils.py diff --git a/infrastructure/tests.py b/infrastructure/tests.py new file mode 100644 index 0000000..71e3310 --- /dev/null +++ b/infrastructure/tests.py @@ -0,0 +1,76 @@ +# Copyright © 2022 Aravinth Manivannan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from pathlib import Path + +from django.test import TestCase, Client, override_settings +from django.conf import settings + +from dash.models import Instance +from .utils import Infra + +from accounts.tests import register_util, login_util +from dash.tests import create_configurations, create_instance_util + + +class InfraUtilTest(TestCase): + """ + Tests billing system + """ + + def setUp(self): + self.username = "infrautil_user" + register_util(t=self, username=self.username) + create_configurations(t=self) + + @override_settings( + HOSTEA={ + "INFRA": { + "HOSTEA_REPO": { + "PATH": "/tmp/hostea/dashboard/test_path_util/repo/", + "REMOTE": "git@gitea.hostea.org:Hostea/payments.git", + "SSH_KEY": "/src/atm/.ssh/id", + } + } + } + ) + def test_path_utils(self): + infra = Infra() + subdomain = "foo" + base = infra.repo_path + + self.assertEqual( + base.joinpath(f"inventory/host_vars/{subdomain}-host/"), + infra._host_vars_dir(subdomain=subdomain), + ) + + self.assertEqual( + base.joinpath(f"inventory/host_vars/{subdomain}-host/gitea.yml"), + infra._gitea_path(subdomain=subdomain), + ) + + self.assertEqual( + base.joinpath(f"inventory/host_vars/{subdomain}-host/provision.yml"), + infra._provision_path(subdomain=subdomain), + ) + + self.assertEqual( + base.joinpath(f"inventory/{subdomain}-backup.yml"), + infra._backup_path(subdomain=subdomain), + ) + + self.assertEqual( + base.joinpath(f"inventory/hosts-scripts/{subdomain}-host.sh"), + infra._hostscript_path(subdomain=subdomain), + ) diff --git a/infrastructure/utils.py b/infrastructure/utils.py new file mode 100644 index 0000000..11612d6 --- /dev/null +++ b/infrastructure/utils.py @@ -0,0 +1,181 @@ +# Copyright © 2022 Aravinth Manivannan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +import os +import shutil +from pathlib import Path + +from django.template.loader import render_to_string +from django.conf import settings +from git import Repo +from git.exc import InvalidGitRepositoryError + +from dash.models import Instance + + +class Infra: + """ + Utility function to manage infrastructure repository + """ + + def __init__(self): + conf = settings.HOSTEA["INFRA"]["HOSTEA_REPO"] + self.repo_path = Path(conf["PATH"]) + if not self.repo_path.exists(): + os.makedirs(self.repo_path) + + self.ssh_cmd = f"ssh -i {conf['SSH_KEY']}" + try: + self.repo = Repo(path=self.repo_path) + except InvalidGitRepositoryError: + self.repo = Repo.clone_from( + conf["REMOTE"], self.repo_path, env={"GIT_SSH_COMMAND": self.ssh_cmd} + ) + + def _host_vars_dir(self, subdomain: str) -> Path: + """ + utility method: get host_vars directory for a subdomain + """ + return self.repo_path.joinpath(f"inventory/host_vars/{subdomain}-host/") + + def _provision_path(self, subdomain: str) -> Path: + """ + utility method: get provision file pay for a subdomain + """ + + return self._host_vars_dir(subdomain=subdomain).joinpath("provision.yml") + + def _gitea_path(self, subdomain: str) -> Path: + """ + utility method: get gitea file for a subdomain + """ + + return self._host_vars_dir(subdomain=subdomain).joinpath("gitea.yml") + + def _backup_path(self, subdomain: str) -> Path: + """ + utility method: get backup file for a subdomain + """ + + return self.repo_path.joinpath(f"inventory/{subdomain}-backup.yml") + + def _hostscript_path(self, subdomain: str) -> Path: + """ + utility method: hostscript file for a subdomain + """ + return self.repo_path.joinpath(f"inventory/hosts-scripts/{subdomain}-host.sh") + + def write_hostscript(self, subdomain: str, content: str): + """ + Write contents to hostscript. + Hostscript will contain the history of all actions that have been + ordered on a particular VM. So content needs to be appended to it, + rather than overwritten. + """ + hostscript = self._hostscript_path(subdomain) + with open(hostscript, "a", encoding="utf-8") as f: + f.write(content) + f.write("\n") + + def _add_files(self, subdomain: str): + """ + Add all relevant files of a VM + """ + self.repo.index.add(self._host_vars_dir(subdomain=subdomain)) + self.repo.index.add(self._backup_path(subdomain=subdomain)) + self.repo.index.add(self._hostscript_path(subdomain=subdomain)) + + def _commit(self, action: str, subdomain: str): + """ + Commit changes to a VM configuration + """ + + self._add_files(subdomain=subdomain) + self.repo.git.commit( + f"{action} VM {subdomain}", author="bot@dashboard.hostea.org" + ) + + def add_vm(self, instance: Instance): + """ + Add new VM to infrastructure repository + """ + subdomain = instance.name + host_vars_dir = self._host_vars_dir(subdomain) + + if not host_vars_dir.exists(): + os.makedirs(host_vars_dir) + + hostscript_path = self.repo_path.joinpath("inventory/hosts-scripts/") + if not hostscript_path.exists(): + os.makedirs(hostscript_path) + + gitea = self._gitea_path(subdomain) + gitea_template = "./templates/infrastructure/yml/gitea.yml" + shutil.copy(gitea_template, gitea) + + # provision_template = "./templates/infrastructure/yml/provision.yml" + provision = self._provision_path(subdomain) + # TODO: instance config names are different the flavours expected: + # ``` + # openstack_flavor: ‘{{ openstack_flavor_medium }}’ * openstack_flavor: ‘{{ openstack_flavor_large }}’ + # ``` + # check with @dachary about this + with open(provision, "w", encoding="utf-8") as f: + f.write( + render_to_string( + "infrastructure/yml/provision.yml", + context={"vm_size": instance.instance_id.name}, + ) + ) + + # backup = self.repo_path.joinpath(f"inventory/{instance.name}-backup.yml") + backup = self._backup_path(subdomain) + # backup_template = "./templates/infrastructure/yml/provision.yml" + with open(backup, "w", encoding="utf-8") as f: + f.write( + render_to_string( + "infrastructure/yml/backups.yml", context={"subdomain": subdomain} + ) + ) + + # hostscript = self.repo_path.join("inventory/hosts-scripts/{instance.name}-host.sh") + + self.write_hostscript( + subdomain=subdomain, + content=render_to_string( + "infrastructure/sh/create.sh", context={"subdomain": subdomain} + ), + ) + + self._commit(action="add", subdomain=subdomain) + + def remove_vm(self, instance: Instance): + """ + Remove a VM from infrastructure repository + """ + subdomain = instance.name + + host_vars_dir = self._host_vars_dir(subdomain) + shutil.rmtree(host_vars_dir) + + backup = self._backup_path(subdomain) + os.remove(backup) + + self.write_hostscript( + subdomain=subdomain, + content=render_to_string( + "infrastructure/sh/rm.sh", context={"subdomain": subdomain} + ), + ) + self._commit(action="rm", subdomain=subdomain) From 9f55a8ced7f468429a999f134aebac2abd3fcf57 Mon Sep 17 00:00:00 2001 From: realaravinth Date: Fri, 24 Jun 2022 20:38:37 +0530 Subject: [PATCH 05/14] feat: docs: hostea infrastructure config parameters --- dashboard/settings.py | 3 +++ docs/INSTALL.md | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/dashboard/settings.py b/dashboard/settings.py index 75664d8..9df86bd 100644 --- a/dashboard/settings.py +++ b/dashboard/settings.py @@ -180,8 +180,11 @@ HOSTEA = { }, "INFRA": { "HOSTEA_REPO": { + # where to clone the repository "PATH": "/srv/hostea/dashboard/infrastructure", + # Git remote URI of the repository "REMOTE": "git@localhost:Hostea/enough.git", + # SSH key that can push to the Git repository remote mentioned above "SSH_KEY": "/srv/hostea/deploy", } }, diff --git a/docs/INSTALL.md b/docs/INSTALL.md index c58b301..044929e 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -72,3 +72,24 @@ PAYMENT_VARIANTS = { ) } ``` + +## Infrastructure(via [Enough](https://enough.community)) + +```python +HOSTEA = { +# <------snip--------> + "INFRA": { + "HOSTEA_REPO": { + # where to clone the repository + "PATH": "/srv/hostea/dashboard/infrastructure", + # Git remote URI of the repository + "REMOTE": "git@localhost:Hostea/enough.git", + # SSH key that can push to the Git repository remote mentioned above + "SSH_KEY": "/srv/hostea/deploy", + } + }, +``` + +### References: + +https://enough-community.readthedocs.io/en/latest/services/hostea.html From e688528fa3d6a28aabc0c189a4a727025dfc3f65 Mon Sep 17 00:00:00 2001 From: realaravinth Date: Sat, 25 Jun 2022 16:27:26 +0530 Subject: [PATCH 06/14] fix: check payment status on instance level, used to be user level --- billing/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/billing/views.py b/billing/views.py index fa87276..1c2de6f 100644 --- a/billing/views.py +++ b/billing/views.py @@ -68,7 +68,7 @@ def generate_invoice(request, instance_name: str): delta = now - timedelta(seconds=(60 * 60 * 24 * 30)) # one month payment = None - for p in Payment.objects.filter(date__gt=(delta)): + for p in Payment.objects.filter(date__gt=(delta), instance_name=instance_name): if p.status == PaymentStatus.CONFIRMED: return HttpResponse("BAD REQUEST: Already paid", status=400) elif any([p.status == PaymentStatus.INPUT, p.status == PaymentStatus.WAITING]): From ec49caa973176428fc8ff0228982681816cf846f Mon Sep 17 00:00:00 2001 From: realaravinth Date: Sat, 25 Jun 2022 16:27:43 +0530 Subject: [PATCH 07/14] feat: payment status checking util --- billing/tests.py | 10 ++++++++++ billing/utils.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 billing/utils.py diff --git a/billing/tests.py b/billing/tests.py index 90d83fd..d5a2b74 100644 --- a/billing/tests.py +++ b/billing/tests.py @@ -27,8 +27,10 @@ from payments import get_payment_model, RedirectNeeded, PaymentStatus from accounts.tests import register_util, login_util from dash.tests import create_configurations, create_instance_util +from dash.models import Instance from .models import Payment +from .utils import payment_fullfilled class BillingTest(TestCase): @@ -49,6 +51,8 @@ class BillingTest(TestCase): t=self, c=c, instance_name=instance_name, config=self.instance_config[0] ) + instance = Instance.objects.get(name=instance_name) + payment_uri = reverse("billing.invoice.generate", args=(instance_name,)) # generate invoice @@ -78,11 +82,17 @@ class BillingTest(TestCase): resp = c.get(reverse("billing.invoice.pending")) self.assertEqual(str.encode(invoice_uri) in resp.content, True) + self.assertEqual(payment_fullfilled(instance=instance), False) + # simulate payment. There's probably a better way to do this payment = get_payment_model().objects.get(paid_by=self.user) payment.status = PaymentStatus.CONFIRMED payment.save() + self.assertEqual(payment_fullfilled(instance=instance), True) + + # + # check if paid invoice is listed in paid invoice list view resp = c.get(reverse("billing.invoice.paid")) self.assertEqual(str.encode(invoice_uri) in resp.content, True) diff --git a/billing/utils.py b/billing/utils.py new file mode 100644 index 0000000..9693de7 --- /dev/null +++ b/billing/utils.py @@ -0,0 +1,33 @@ +# Copyright © 2022 Aravinth Manivannan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from datetime import datetime, timedelta, timezone +from payments import get_payment_model, RedirectNeeded, PaymentStatus +from django.contrib.auth.models import User +from django.shortcuts import get_object_or_404 + +from dash.models import Instance + + +def payment_fullfilled(instance: Instance) -> bool: + Payment = get_payment_model() + now = datetime.now(tz=timezone.utc) + delta = now - timedelta(seconds=(60 * 60 * 24 * 30)) # one month + + payment = None + for p in Payment.objects.filter(date__gt=(delta), instance_name=instance.name): + if p.status == PaymentStatus.CONFIRMED: + return True + + return False From 80d6664f0d9a5cced121909033c6cb1256452a88 Mon Sep 17 00:00:00 2001 From: realaravinth Date: Sat, 25 Jun 2022 17:57:23 +0530 Subject: [PATCH 08/14] feat: load VM domain from settings --- dashboard/settings.py | 4 +++- docs/INSTALL.md | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/dashboard/settings.py b/dashboard/settings.py index 9df86bd..4f72c1d 100644 --- a/dashboard/settings.py +++ b/dashboard/settings.py @@ -186,7 +186,9 @@ HOSTEA = { "REMOTE": "git@localhost:Hostea/enough.git", # SSH key that can push to the Git repository remote mentioned above "SSH_KEY": "/srv/hostea/deploy", - } + }, + # domain where new VMs will be created + "HOSTEA_DOMAIN": "hostea.org", }, } diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 044929e..dbf6a27 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -86,7 +86,10 @@ HOSTEA = { "REMOTE": "git@localhost:Hostea/enough.git", # SSH key that can push to the Git repository remote mentioned above "SSH_KEY": "/srv/hostea/deploy", - } + }, + # domain where new VMs will be created + "HOSTEA_DOMAIN": "hostea.org" + }, ``` From 94aad8e6ea3f40cd1cc0699dee80db615f1d521c Mon Sep 17 00:00:00 2001 From: realaravinth Date: Sat, 25 Jun 2022 18:00:13 +0530 Subject: [PATCH 09/14] fix: templates: load user credentials and pass dynamic configuration. Also escape curly braces --- .../infrastructure/sh/hostscripts/create.sh | 4 ++-- .../infrastructure/sh/hostscripts/rm.sh | 2 +- .../templates/infrastructure/yml/gitea.yml | 18 +++++++++--------- .../templates/infrastructure/yml/provision.yml | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/infrastructure/templates/infrastructure/sh/hostscripts/create.sh b/infrastructure/templates/infrastructure/sh/hostscripts/create.sh index ad607bc..5511578 100644 --- a/infrastructure/templates/infrastructure/sh/hostscripts/create.sh +++ b/infrastructure/templates/infrastructure/sh/hostscripts/create.sh @@ -1,2 +1,2 @@ -enough --domain d.hostea.org host create {{subdomain}}-host -enough --domain d.hostea.org service create --host {{subdomain}}-host gitea +enough --domain d.{{ hostea_domain }} host create {{subdomain}}-host +enough --domain d.{{ hostea_domain }} service create --host {{subdomain}}-host gitea diff --git a/infrastructure/templates/infrastructure/sh/hostscripts/rm.sh b/infrastructure/templates/infrastructure/sh/hostscripts/rm.sh index 0eeb490..61d1a22 100644 --- a/infrastructure/templates/infrastructure/sh/hostscripts/rm.sh +++ b/infrastructure/templates/infrastructure/sh/hostscripts/rm.sh @@ -1 +1 @@ -enough --domain d.hostea.org host delete hostea001-host +enough --domain d.{{ hostea_domain }} host delete hostea001-host diff --git a/infrastructure/templates/infrastructure/yml/gitea.yml b/infrastructure/templates/infrastructure/yml/gitea.yml index 8a3c99e..fcf7aab 100644 --- a/infrastructure/templates/infrastructure/yml/gitea.yml +++ b/infrastructure/templates/infrastructure/yml/gitea.yml @@ -5,14 +5,14 @@ # Public hostname of the Gitea instance # # -gitea_host: "gitea.{{ domain }}" +gitea_host: "{{ subdomain }}.{{ '{' }}{{ '{' }} domain {{ '}' }}{{ '}' }}" # ####################################### # # Mailer from # # -gitea_mailer_from: "noreply@enough.community" +gitea_mailer_from: "noreply@{{ '{' }}{{ '{' }} domain {{ '}' }}{{ '}' }}" # ####################################### # @@ -38,37 +38,37 @@ gitea_user: root # # Admin user password # -#gitea_password: etquofEtseudett +gitea_password: "{{ gitea_password }}" # ####################################### # # Admin user email # -gitea_email: contact@enough.community +gitea_email: "{{ gitea_email }}" # ####################################### # -# Unique hostname of the woodpecker server relative to {{ domain }} +# Unique hostname of the woodpecker server relative to {{ '{' }}{{ '{' }} domain {{ '}' }}{{ '}' }} # -woodpecker_hostname: "woodpecker" +woodpecker_hostname: "{{ woodpecker_hostname }}" # ####################################### # # Public hostname of the Woodpecker instance # -woodpecker_host: "{{ woodpecker_hostname }}.{{ domain }}" +woodpecker_host: "{{ '{' }}{{ '{' }} woodpecker_hostname {{ '}' }}{{ '}' }}.{{ '{' }}{{ '{' }} domain {{ '}' }}{{ '}' }}" # ####################################### # # Gitea users with admin rights on woodpecker # -woodpecker_admins: "{{ gitea_user }}" +woodpecker_admins: "{{ '{' }}{{ '{' }} gitea_user {{ '}' }}{{ '}' }}" # ####################################### # # Woodpecker shared agent secret `openssl rand -hex 32` # -#woodpecker_agent_secret: c2cd326f7104c2ca93e6d22da0b28d1e33b4aeaa071c08945e0ade576b3192ce +woodpecker_agent_secret: {{ woodpecker_agent_secret }} # ####################################### # diff --git a/infrastructure/templates/infrastructure/yml/provision.yml b/infrastructure/templates/infrastructure/yml/provision.yml index 09998e7..ab67c1e 100644 --- a/infrastructure/templates/infrastructure/yml/provision.yml +++ b/infrastructure/templates/infrastructure/yml/provision.yml @@ -1 +1 @@ -openstack_flavor: "\{\{ {{ vm_size }} \}\}" +openstack_flavor: {{ vm_size }} From 922d0c5f81c020e93aa91d93923156e5d42ed066 Mon Sep 17 00:00:00 2001 From: realaravinth Date: Sat, 25 Jun 2022 18:01:08 +0530 Subject: [PATCH 10/14] fix: don't create additional configuration opts --- dash/tests.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dash/tests.py b/dash/tests.py index e0c20a6..8d02936 100644 --- a/dash/tests.py +++ b/dash/tests.py @@ -26,18 +26,18 @@ from .models import InstanceConfiguration, Instance def create_configurations(t: TestCase): t.instance_config = [ - InstanceConfiguration(name="Personal", rent=5.0, ram=0.5, cpu=1, storage=25), - InstanceConfiguration(name="Enthusiast", rent=10.0, ram=2, cpu=2, storage=50), - InstanceConfiguration( - name="Small Business", rent=20.0, ram=8, cpu=4, storage=64 + InstanceConfiguration.objects.get( + name="s1-2", rent=10, ram=2, cpu=1, storage=10 ), - InstanceConfiguration( - name="Enterprise", rent=100.0, ram=64, cpu=24, storage=1024 + InstanceConfiguration.objects.get( + name="s1-4", rent=20, ram=4, cpu=1, storage=20 + ), + InstanceConfiguration.objects.get( + name="s1-8", rent=40, ram=8, cpu=2, storage=40 ), ] for instance in t.instance_config: - instance.save() print(f"[*][init] Instance {instance.name} is saved") t.assertEqual( InstanceConfiguration.objects.filter(name=instance.name).exists(), True From 9af5361f632d1bbe0e1632f840f24cc52b2798a8 Mon Sep 17 00:00:00 2001 From: realaravinth Date: Sat, 25 Jun 2022 18:01:39 +0530 Subject: [PATCH 11/14] feat: load local settings --- dashboard/settings.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dashboard/settings.py b/dashboard/settings.py index 4f72c1d..3b1823e 100644 --- a/dashboard/settings.py +++ b/dashboard/settings.py @@ -195,3 +195,9 @@ HOSTEA = { EMAIL_CONFIG = env.email("EMAIL_URL", default="smtp://admin:password@localhost:10025") vars().update(EMAIL_CONFIG) + +try: + import dashboard.local_settings + print("Found local_settings") +except ModuleNotFoundError: + pass From beb4b29c49f280f8e0dc3e5e803722fab3d708f4 Mon Sep 17 00:00:00 2001 From: realaravinth Date: Sat, 25 Jun 2022 18:02:03 +0530 Subject: [PATCH 12/14] feat: pass template configuration, map VM sizes, generate secrets return gitea passwd, git pull before writing and push after add/rm --- infrastructure/utils.py | 62 +++++++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/infrastructure/utils.py b/infrastructure/utils.py index 11612d6..69a6ed5 100644 --- a/infrastructure/utils.py +++ b/infrastructure/utils.py @@ -16,6 +16,7 @@ import os import shutil from pathlib import Path +from django.utils.crypto import get_random_string from django.template.loader import render_to_string from django.conf import settings from git import Repo @@ -31,6 +32,7 @@ class Infra: def __init__(self): conf = settings.HOSTEA["INFRA"]["HOSTEA_REPO"] + self.hostea_domain = settings.HOSTEA["INFRA"]["HOSTEA_DOMAIN"] self.repo_path = Path(conf["PATH"]) if not self.repo_path.exists(): os.makedirs(self.repo_path) @@ -92,9 +94,9 @@ class Infra: """ Add all relevant files of a VM """ - self.repo.index.add(self._host_vars_dir(subdomain=subdomain)) - self.repo.index.add(self._backup_path(subdomain=subdomain)) - self.repo.index.add(self._hostscript_path(subdomain=subdomain)) + self.repo.git.add(str(self._host_vars_dir(subdomain=subdomain))) + self.repo.git.add(str(self._backup_path(subdomain=subdomain))) + self.repo.git.add(str(self._hostscript_path(subdomain=subdomain))) def _commit(self, action: str, subdomain: str): """ @@ -103,13 +105,18 @@ class Infra: self._add_files(subdomain=subdomain) self.repo.git.commit( - f"{action} VM {subdomain}", author="bot@dashboard.hostea.org" + message=f"{action} VM {subdomain}", + author="Dashboard Bot ", ) - def add_vm(self, instance: Instance): + def add_vm(self, instance: Instance) -> str: """ Add new VM to infrastructure repository + + The gitea user password is returned """ + self.repo.git.pull() + subdomain = instance.name host_vars_dir = self._host_vars_dir(subdomain) @@ -120,9 +127,26 @@ class Infra: if not hostscript_path.exists(): os.makedirs(hostscript_path) + woodpecker_agent_secret = get_random_string(64) + gitea_password = get_random_string(20) + + ctx = { + "woodpecker_agent_secret": woodpecker_agent_secret, + "woodpecker_hostname": f"{subdomain}-ci", + "woodpecker_admins": f"{instance.owned_by.username}", + "gitea_email": instance.owned_by.email, + "gitea_password": gitea_password, + "subdomain": subdomain, + } + gitea = self._gitea_path(subdomain) - gitea_template = "./templates/infrastructure/yml/gitea.yml" - shutil.copy(gitea_template, gitea) + with open(gitea, "w", encoding="utf-8") as f: + f.write( + render_to_string( + "infrastructure/yml/gitea.yml", + context=ctx, + ) + ) # provision_template = "./templates/infrastructure/yml/provision.yml" provision = self._provision_path(subdomain) @@ -131,11 +155,21 @@ class Infra: # openstack_flavor: ‘{{ openstack_flavor_medium }}’ * openstack_flavor: ‘{{ openstack_flavor_large }}’ # ``` # check with @dachary about this + + size = None + if instance.configuration_id.name == "s1-2": + size = "openstack_flavor_small" + elif instance.configuration_id.name == "s1-4": + size = "openstack_flavor_medium" + elif instance.configuration_id.name == "s1-8": + size = "openstack_flavor_large" + else: + size = instance.configuration_id.name + with open(provision, "w", encoding="utf-8") as f: f.write( render_to_string( - "infrastructure/yml/provision.yml", - context={"vm_size": instance.instance_id.name}, + "infrastructure/yml/provision.yml", context={"vm_size": size} ) ) @@ -154,16 +188,20 @@ class Infra: self.write_hostscript( subdomain=subdomain, content=render_to_string( - "infrastructure/sh/create.sh", context={"subdomain": subdomain} + "infrastructure/sh/hostscripts/create.sh", + context={"subdomain": subdomain, "hostea_domain": self.hostea_domain}, ), ) self._commit(action="add", subdomain=subdomain) + self.repo.git.push() + return gitea_password def remove_vm(self, instance: Instance): """ Remove a VM from infrastructure repository """ + self.repo.git.pull() subdomain = instance.name host_vars_dir = self._host_vars_dir(subdomain) @@ -175,7 +213,9 @@ class Infra: self.write_hostscript( subdomain=subdomain, content=render_to_string( - "infrastructure/sh/rm.sh", context={"subdomain": subdomain} + "infrastructure/sh/hostscripts/create.sh", + context={"subdomain": subdomain, "hostea_domain": self.hostea_domain}, ), ) self._commit(action="rm", subdomain=subdomain) + self.repo.git.push() From 871a05ddd35268ad5c99a43f20cbea6aea810c2d Mon Sep 17 00:00:00 2001 From: realaravinth Date: Sat, 25 Jun 2022 18:03:04 +0530 Subject: [PATCH 13/14] feat: payment check before creation and save gitea passwd in DB --- infrastructure/migrations/0001_initial.py | 37 +++++++++++++++++++ .../0002_instancecreated_gitea_password.py | 18 +++++++++ infrastructure/models.py | 26 ++++++++++++- infrastructure/tests.py | 34 +++++++++++++++-- infrastructure/views.py | 13 ++++++- 5 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 infrastructure/migrations/0001_initial.py create mode 100644 infrastructure/migrations/0002_instancecreated_gitea_password.py diff --git a/infrastructure/migrations/0001_initial.py b/infrastructure/migrations/0001_initial.py new file mode 100644 index 0000000..d7a6dcc --- /dev/null +++ b/infrastructure/migrations/0001_initial.py @@ -0,0 +1,37 @@ +# Generated by Django 4.0.3 on 2022-06-25 10:48 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ("dash", "0006_auto_20220619_0800"), + ] + + operations = [ + migrations.CreateModel( + name="InstanceCreated", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("creted", models.BooleanField(default=False)), + ( + "instance", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, to="dash.instance" + ), + ), + ], + ), + ] diff --git a/infrastructure/migrations/0002_instancecreated_gitea_password.py b/infrastructure/migrations/0002_instancecreated_gitea_password.py new file mode 100644 index 0000000..8a126d2 --- /dev/null +++ b/infrastructure/migrations/0002_instancecreated_gitea_password.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.3 on 2022-06-25 12:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('infrastructure', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='instancecreated', + name='gitea_password', + field=models.CharField(default=None, max_length=32, verbose_name='Name of this configuration'), + ), + ] diff --git a/infrastructure/models.py b/infrastructure/models.py index 71a8362..a74f4ab 100644 --- a/infrastructure/models.py +++ b/infrastructure/models.py @@ -1,3 +1,27 @@ +# Copyright © 2022 Aravinth Manivannan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . from django.db import models -# Create your models here. +from dash.models import Instance + + +class InstanceCreated(models.Model): + instance = models.ForeignKey(Instance, on_delete=models.PROTECT) + gitea_password = models.CharField( + "Name of this configuration", + default=None, + max_length=32, + ) + creted = models.BooleanField(default=False) diff --git a/infrastructure/tests.py b/infrastructure/tests.py index 71e3310..2ddaac4 100644 --- a/infrastructure/tests.py +++ b/infrastructure/tests.py @@ -39,9 +39,10 @@ class InfraUtilTest(TestCase): "INFRA": { "HOSTEA_REPO": { "PATH": "/tmp/hostea/dashboard/test_path_util/repo/", - "REMOTE": "git@gitea.hostea.org:Hostea/payments.git", - "SSH_KEY": "/src/atm/.ssh/id", - } + "REMOTE": "git@git.batsense.net:realaravinth/dummy-hostea-dash-test", + "SSH_KEY": "/src/atm/.ssh/aravinth", + }, + "HOSTEA_DOMAIN": "hostea.org", } } ) @@ -74,3 +75,30 @@ class InfraUtilTest(TestCase): base.joinpath(f"inventory/hosts-scripts/{subdomain}-host.sh"), infra._hostscript_path(subdomain=subdomain), ) + + @override_settings( + HOSTEA={ + "INFRA": { + "HOSTEA_REPO": { + "PATH": "/tmp/hostea/dashboard/test_add_vm/repo/", + "REMOTE": "git@git.batsense.net:realaravinth/dummy-hostea-dash-test", + "SSH_KEY": "/src/atm/.ssh/aravinth", + }, + "HOSTEA_DOMAIN": "hostea.org", + } + } + ) + def test_add_vm(self): + infra = Infra() + c = Client() + login_util(self, c, "accounts.home") + subdomain = "add_vm" + + base = infra.repo_path + + create_instance_util( + t=self, c=c, instance_name=subdomain, config=self.instance_config[0] + ) + + instance = Instance.objects.get(name=subdomain) + woodpecker_agent_secret = infra.add_vm(instance=instance) diff --git a/infrastructure/views.py b/infrastructure/views.py index d315f18..e634e11 100644 --- a/infrastructure/views.py +++ b/infrastructure/views.py @@ -23,8 +23,10 @@ from django.urls import reverse from accounts.decorators import confirm_access from dash.models import Instance +from billing.utils import payment_fullfilled from .utils import Infra +from .models import InstanceCreated def default_ctx(title: str, username: str): @@ -44,9 +46,16 @@ def create_instance(request, instance_name: str): Dashboard homepage view """ instance = get_object_or_404(Instance, name=instance_name, owned_by=request.user) + if not payment_fullfilled(instance=instance): + return redirect(reverse("billing.invoice.generate", args=(instance_name,))) + infra = Infra() - infra.add_vm(instance=instance) - # TODO: push isn't implemented yet + if not InstanceCreated.objects.filter(instance=instance).exists(): + instance = InstanceCreated.objects.create(instance=instance, created=True) + instance.save() + gitea_password = infra.add_vm(instance=instance) + instance.gitea_password = gitea_password + instance.save() return HttpResponse() From 26b7ea3ef23e96d37e3f201215cb523f64190790 Mon Sep 17 00:00:00 2001 From: realaravinth Date: Sat, 25 Jun 2022 18:24:52 +0530 Subject: [PATCH 14/14] fix & rm: create/rm hostscripts, rm HOSTEA_DOMAIN --- dashboard/settings.py | 5 ++--- docs/INSTALL.md | 3 --- .../migrations/0002_instancecreated_gitea_password.py | 10 ++++++---- .../templates/infrastructure/sh/hostscripts/create.sh | 4 ++-- .../templates/infrastructure/sh/hostscripts/rm.sh | 2 +- infrastructure/tests.py | 4 ++-- infrastructure/utils.py | 7 +++---- 7 files changed, 16 insertions(+), 19 deletions(-) diff --git a/dashboard/settings.py b/dashboard/settings.py index 3b1823e..2f5fca9 100644 --- a/dashboard/settings.py +++ b/dashboard/settings.py @@ -186,9 +186,7 @@ HOSTEA = { "REMOTE": "git@localhost:Hostea/enough.git", # SSH key that can push to the Git repository remote mentioned above "SSH_KEY": "/srv/hostea/deploy", - }, - # domain where new VMs will be created - "HOSTEA_DOMAIN": "hostea.org", + } }, } @@ -198,6 +196,7 @@ vars().update(EMAIL_CONFIG) try: import dashboard.local_settings + print("Found local_settings") except ModuleNotFoundError: pass diff --git a/docs/INSTALL.md b/docs/INSTALL.md index dbf6a27..c9d1c7e 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -87,9 +87,6 @@ HOSTEA = { # SSH key that can push to the Git repository remote mentioned above "SSH_KEY": "/srv/hostea/deploy", }, - # domain where new VMs will be created - "HOSTEA_DOMAIN": "hostea.org" - }, ``` diff --git a/infrastructure/migrations/0002_instancecreated_gitea_password.py b/infrastructure/migrations/0002_instancecreated_gitea_password.py index 8a126d2..0777dbd 100644 --- a/infrastructure/migrations/0002_instancecreated_gitea_password.py +++ b/infrastructure/migrations/0002_instancecreated_gitea_password.py @@ -6,13 +6,15 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('infrastructure', '0001_initial'), + ("infrastructure", "0001_initial"), ] operations = [ migrations.AddField( - model_name='instancecreated', - name='gitea_password', - field=models.CharField(default=None, max_length=32, verbose_name='Name of this configuration'), + model_name="instancecreated", + name="gitea_password", + field=models.CharField( + default=None, max_length=32, verbose_name="Name of this configuration" + ), ), ] diff --git a/infrastructure/templates/infrastructure/sh/hostscripts/create.sh b/infrastructure/templates/infrastructure/sh/hostscripts/create.sh index 5511578..4a4f752 100644 --- a/infrastructure/templates/infrastructure/sh/hostscripts/create.sh +++ b/infrastructure/templates/infrastructure/sh/hostscripts/create.sh @@ -1,2 +1,2 @@ -enough --domain d.{{ hostea_domain }} host create {{subdomain}}-host -enough --domain d.{{ hostea_domain }} service create --host {{subdomain}}-host gitea +enough --domain $domain host create {{subdomain}}-host +enough --domain $domain service create --host {{subdomain}}-host gitea diff --git a/infrastructure/templates/infrastructure/sh/hostscripts/rm.sh b/infrastructure/templates/infrastructure/sh/hostscripts/rm.sh index 61d1a22..43a649c 100644 --- a/infrastructure/templates/infrastructure/sh/hostscripts/rm.sh +++ b/infrastructure/templates/infrastructure/sh/hostscripts/rm.sh @@ -1 +1 @@ -enough --domain d.{{ hostea_domain }} host delete hostea001-host +enough --domain $domain host delete hostea001-host diff --git a/infrastructure/tests.py b/infrastructure/tests.py index 2ddaac4..f6cd742 100644 --- a/infrastructure/tests.py +++ b/infrastructure/tests.py @@ -42,7 +42,6 @@ class InfraUtilTest(TestCase): "REMOTE": "git@git.batsense.net:realaravinth/dummy-hostea-dash-test", "SSH_KEY": "/src/atm/.ssh/aravinth", }, - "HOSTEA_DOMAIN": "hostea.org", } } ) @@ -84,7 +83,6 @@ class InfraUtilTest(TestCase): "REMOTE": "git@git.batsense.net:realaravinth/dummy-hostea-dash-test", "SSH_KEY": "/src/atm/.ssh/aravinth", }, - "HOSTEA_DOMAIN": "hostea.org", } } ) @@ -102,3 +100,5 @@ class InfraUtilTest(TestCase): instance = Instance.objects.get(name=subdomain) woodpecker_agent_secret = infra.add_vm(instance=instance) + + # infra.remove_vm(instance=instance) diff --git a/infrastructure/utils.py b/infrastructure/utils.py index 69a6ed5..cd47054 100644 --- a/infrastructure/utils.py +++ b/infrastructure/utils.py @@ -32,7 +32,6 @@ class Infra: def __init__(self): conf = settings.HOSTEA["INFRA"]["HOSTEA_REPO"] - self.hostea_domain = settings.HOSTEA["INFRA"]["HOSTEA_DOMAIN"] self.repo_path = Path(conf["PATH"]) if not self.repo_path.exists(): os.makedirs(self.repo_path) @@ -189,7 +188,7 @@ class Infra: subdomain=subdomain, content=render_to_string( "infrastructure/sh/hostscripts/create.sh", - context={"subdomain": subdomain, "hostea_domain": self.hostea_domain}, + context={"subdomain": subdomain}, ), ) @@ -213,8 +212,8 @@ class Infra: self.write_hostscript( subdomain=subdomain, content=render_to_string( - "infrastructure/sh/hostscripts/create.sh", - context={"subdomain": subdomain, "hostea_domain": self.hostea_domain}, + "infrastructure/sh/hostscripts/rm.sh", + context={"subdomain": subdomain}, ), ) self._commit(action="rm", subdomain=subdomain)