feat: notify user on instance creation
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/pr/woodpecker Pipeline failed Details

pull/14/head
Aravinth Manivannan 2022-06-30 01:10:55 +05:30
parent 53ec0a3982
commit f00746a36d
Signed by: realaravinth
GPG Key ID: AD9F0F08E855ED88
5 changed files with 137 additions and 8 deletions

View File

@ -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"
),
),
],
),
]

View File

@ -12,11 +12,30 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
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,
)

View File

@ -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
)

View File

@ -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<no-reply@exampl.org>", # 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

View File

@ -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