diff --git a/infrastructure/migrations/0006_job.py b/infrastructure/migrations/0006_job.py
new file mode 100644
index 0000000..4561f62
--- /dev/null
+++ b/infrastructure/migrations/0006_job.py
@@ -0,0 +1,36 @@
+# Generated by Django 4.0.3 on 2022-06-29 18:30
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("dash", "0006_auto_20220619_0800"),
+ ("infrastructure", "0005_remove_instancecreated_gitea_password"),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name="Job",
+ fields=[
+ (
+ "id",
+ models.BigAutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("job_type", models.CharField(max_length=10, verbose_name="Job Type")),
+ (
+ "instance",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE, to="dash.instance"
+ ),
+ ),
+ ],
+ ),
+ ]
diff --git a/infrastructure/models.py b/infrastructure/models.py
index 1e0673d..c71b26c 100644
--- a/infrastructure/models.py
+++ b/infrastructure/models.py
@@ -12,11 +12,30 @@
#
# 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
+from enum import Enum, unique
+from django.db import models
from dash.models import Instance
+@unique
+class JobType(Enum):
+ PING = "ping"
+
+ def __str__(self):
+ return self.name
+
+
class InstanceCreated(models.Model):
instance = models.ForeignKey(Instance, on_delete=models.PROTECT)
created = models.BooleanField(default=False)
+
+
+class Job(models.Model):
+ instance = models.ForeignKey(Instance, on_delete=models.CASCADE)
+
+ job_type = models.CharField(
+ "Job Type",
+ max_length=10,
+ null=False,
+ )
diff --git a/infrastructure/tests.py b/infrastructure/tests.py
index cb52910..cb59015 100644
--- a/infrastructure/tests.py
+++ b/infrastructure/tests.py
@@ -15,11 +15,11 @@
import shutil
import time
import os
-import requests
from io import StringIO
-from urllib.parse import urlparse, urlunparse
+from urllib.parse import urlunparse
from pathlib import Path
+import requests
from django.test import TestCase, Client, override_settings
from django.conf import settings
from django.core.management import call_command
@@ -31,8 +31,8 @@ from accounts.tests import register_util, login_util
from dash.tests import create_configurations, create_instance_util
from infrastructure.management.commands.vm import translate_sizes
-from .utils import Infra
-from .models import InstanceCreated
+from .utils import Infra, Worker
+from .models import InstanceCreated, Job, JobType
def custom_config(test_name: str):
@@ -187,3 +187,26 @@ class InfraUtilTest(TestCase):
# run delete VM command to crudely check idempotency
call_command("vm", "delete", subdomain)
+
+ def test_worker(self):
+ subdomain = "gitea" # yes, gitea.hostea.org exists. will use it till I
+ # figure out how to use requests_mock within django
+ c = Client()
+ login_util(self, c, "accounts.home")
+ create_instance_util(
+ t=self, c=c, instance_name=subdomain, config=self.instance_config[0]
+ )
+
+ instance = Instance.objects.get(name=subdomain)
+ job = Job.objects.create(instance=instance, job_type=JobType.PING)
+ gitea_uri = Infra.get_gitea_uri(instance=instance)
+ print(f"mocking {gitea_uri}")
+
+ w = Worker(job=job)
+ w.start()
+ time.sleep(5)
+ self.assertEqual(w.is_alive(), False)
+ w.join()
+ self.assertEqual(
+ Job.objects.filter(instance=instance, job_type=JobType.PING).exists(), True
+ )
diff --git a/infrastructure/utils.py b/infrastructure/utils.py
index 68ef92d..b66f741 100644
--- a/infrastructure/utils.py
+++ b/infrastructure/utils.py
@@ -15,17 +15,65 @@
import os
import shutil
import yaml
+import requests
from pathlib import Path
+from threading import Thread, Event
+from time import sleep
from django.utils.crypto import get_random_string
from django.template.loader import render_to_string
+from django.core.mail import send_mail
from django.conf import settings
from git import Repo, Commit
from git.exc import InvalidGitRepositoryError
from dash.models import Instance
-from .models import InstanceCreated
+from infrastructure.models import InstanceCreated, JobType, Job
+
+
+class Worker(Thread):
+ def __init__(self, job: Job):
+ self.job = job
+ super().__init__()
+
+ ######### self.daemon = True
+
+ def run(self):
+ gitea_uri = Infra.get_gitea_uri(instance=self.job.instance)
+ woodpecker = Infra.get_woodpecker_hostname(instance=self.job.instance)
+ while True:
+ try:
+ print(f"[ping] Trying to reach {gitea_uri}")
+ resp = requests.get(gitea_uri)
+ print(resp.status_code)
+ if resp.status_code == 200:
+ break
+ except Exception:
+ return False
+ sleep(10)
+
+ print("sending email")
+ job = self.job
+ self.job = None
+ email = job.instance.owned_by.email
+ send_mail(
+ subject="[Hostea] Your Hostea instance is now online!",
+ message=f"""
+Hello,
+
+The deployment job has run to completion and your Hostea instance is now online!
+Credentials to admin account was sent in an earlier email, please contact
+support if didn't receive it.
+
+Gitea: {gitea_uri}
+Woodpecker CI: {woodpecker}
+""",
+ from_email="No reply Hostea", # TODO read from settings.py
+ recipient_list=[email],
+ )
+ job.delete()
+ print("job deleted")
def create_vm_if_not_exists(instance: Instance) -> (str, Commit):
@@ -35,13 +83,15 @@ def create_vm_if_not_exists(instance: Instance) -> (str, Commit):
infra = Infra()
if not InstanceCreated.objects.filter(instance=instance).exists():
(gitea_password, commit) = infra.add_vm(instance=instance)
- instance = InstanceCreated.objects.create(instance=instance, created=True)
- instance.save()
+ InstanceCreated.objects.create(instance=instance, created=True)
+ job = Job.objects.create(instance=instance, job_type=str(JobType.PING))
+ Worker(job=job).start()
return (gitea_password, commit)
else:
if str.strip(infra.get_flavor(instance=instance)) != str.strip(
infra.translate_size(instance=instance)
):
+ # Worker.init_global()
return infra.add_vm(instance=instance)
return None
diff --git a/requirements.txt b/requirements.txt
index 896b2a5..ccdcb32 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -37,6 +37,7 @@ pynvim==0.4.3
pytz==2022.1
PyYAML==6.0
requests==2.27.1
+six==1.16.0
smmap==5.0.0
sqlparse==0.4.2
stripe==3.4.0