diff --git a/controller/__init__.py b/controller/__init__.py
new file mode 100644
index 0000000..b1b6456
--- /dev/null
+++ b/controller/__init__.py
@@ -0,0 +1 @@
+"""The controller app for the drunc_ui project."""
diff --git a/controller/admin.py b/controller/admin.py
new file mode 100644
index 0000000..751c975
--- /dev/null
+++ b/controller/admin.py
@@ -0,0 +1,3 @@
+"""Admin module for the controller app."""
+
+# Register your models here.
diff --git a/controller/apps.py b/controller/apps.py
new file mode 100644
index 0000000..38baaf4
--- /dev/null
+++ b/controller/apps.py
@@ -0,0 +1,10 @@
+"""Apps module for the controller app."""
+
+from django.apps import AppConfig
+
+
+class ControllerConfig(AppConfig):
+ """The app config for the controller app."""
+
+ default_auto_field = "django.db.models.BigAutoField"
+ name = "controller"
diff --git a/controller/migrations/__init__.py b/controller/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/controller/models.py b/controller/models.py
new file mode 100644
index 0000000..1873bc5
--- /dev/null
+++ b/controller/models.py
@@ -0,0 +1,3 @@
+"""Models module for the controller app."""
+
+# Create your models here.
diff --git a/controller/templates/controller/index.html b/controller/templates/controller/index.html
new file mode 100644
index 0000000..69f65f2
--- /dev/null
+++ b/controller/templates/controller/index.html
@@ -0,0 +1,4 @@
+{% extends "main/base.html" %}
+{% block title %}
+ Controller
+{% endblock title %}
diff --git a/controller/urls.py b/controller/urls.py
new file mode 100644
index 0000000..2bf73a5
--- /dev/null
+++ b/controller/urls.py
@@ -0,0 +1,10 @@
+"""Urls module for the controller app."""
+
+from django.urls import path
+
+from . import views
+
+app_name = "controller"
+urlpatterns = [
+ path("", views.index, name="index"),
+]
diff --git a/controller/views.py b/controller/views.py
new file mode 100644
index 0000000..f85e30c
--- /dev/null
+++ b/controller/views.py
@@ -0,0 +1,11 @@
+"""Views module for the controller app."""
+
+from django.contrib.auth.decorators import login_required
+from django.http import HttpRequest, HttpResponse
+from django.shortcuts import render
+
+
+@login_required
+def index(request: HttpRequest) -> HttpResponse:
+ """View that renders the index/home page."""
+ return render(request=request, template_name="controller/index.html")
diff --git a/drunc_ui/settings/settings.py b/drunc_ui/settings/settings.py
index 965e1cd..e36a999 100644
--- a/drunc_ui/settings/settings.py
+++ b/drunc_ui/settings/settings.py
@@ -130,7 +130,7 @@
# Custom settings
-INSTALLED_APPS += ["main", "django_tables2"]
+INSTALLED_APPS += ["main", "process_manager", "controller", "django_tables2"]
MIDDLEWARE.insert(1, "whitenoise.middleware.WhiteNoiseMiddleware")
diff --git a/drunc_ui/urls.py b/drunc_ui/urls.py
index 5772129..40144ff 100644
--- a/drunc_ui/urls.py
+++ b/drunc_ui/urls.py
@@ -21,4 +21,6 @@
urlpatterns = [
path("admin/", admin.site.urls),
path("", include("main.urls")),
+ path("process_manager/", include("process_manager.urls")),
+ path("controller/", include("controller.urls")),
]
diff --git a/main/templates/main/base.html b/main/templates/main/base.html
index 898a813..61173fb 100644
--- a/main/templates/main/base.html
+++ b/main/templates/main/base.html
@@ -18,11 +18,7 @@
-
+ {% include "main/navbar.html" %}
{% block content %}
{% endblock content %}
diff --git a/main/templates/main/index.html b/main/templates/main/index.html
index d75d738..8b2edf0 100644
--- a/main/templates/main/index.html
+++ b/main/templates/main/index.html
@@ -2,51 +2,11 @@
{% block title %}
Home
{% endblock title %}
-{% block extra_css %}
-
-{% endblock extra_css %}
{% block content %}
-
-
-
-
-
- {% if messages %}
- {% for message in messages %}- {{ message }}
{% endfor %}
- {% endif %}
-
-
-
+
Process Manager
+
Controller
{% endblock content %}
diff --git a/main/templates/main/navbar.html b/main/templates/main/navbar.html
new file mode 100644
index 0000000..256741c
--- /dev/null
+++ b/main/templates/main/navbar.html
@@ -0,0 +1,27 @@
+
+
diff --git a/main/urls.py b/main/urls.py
index 70b2f98..33fa5d0 100644
--- a/main/urls.py
+++ b/main/urls.py
@@ -5,16 +5,7 @@
from . import views
app_name = "main"
-
-partial_urlpatterns = [
- path("process_table/", views.process_table, name="process_table"),
-]
-
urlpatterns = [
path("", views.index, name="index"),
path("accounts/", include("django.contrib.auth.urls")),
- path("process_action/", views.process_action, name="process_action"),
- path("logs/
", views.logs, name="logs"),
- path("boot_process/", views.BootProcessView.as_view(), name="boot_process"),
- path("partials/", include(partial_urlpatterns)),
]
diff --git a/main/views.py b/main/views.py
index dce1dc2..d859bf5 100644
--- a/main/views.py
+++ b/main/views.py
@@ -1,218 +1,11 @@
"""Views for the main app."""
-import asyncio
-import uuid
-from enum import Enum
-
-import django_tables2
-from django.conf import settings
-from django.contrib.auth.decorators import login_required, permission_required
-from django.contrib.auth.mixins import PermissionRequiredMixin
-from django.db import transaction
-from django.http import HttpRequest, HttpResponse, HttpResponseRedirect
+from django.contrib.auth.decorators import login_required
+from django.http import HttpRequest, HttpResponse
from django.shortcuts import render
-from django.urls import reverse, reverse_lazy
-from django.views.generic.edit import FormView
-from drunc.process_manager.process_manager_driver import ProcessManagerDriver
-from drunc.utils.shell_utils import DecodedResponse, create_dummy_token_from_uname
-from druncschema.process_manager_pb2 import (
- LogRequest,
- ProcessInstance,
- ProcessInstanceList,
- ProcessQuery,
- ProcessUUID,
-)
-
-from .forms import BootProcessForm
-from .tables import ProcessTable
-
-
-def get_process_manager_driver() -> ProcessManagerDriver:
- """Get a ProcessManagerDriver instance."""
- token = create_dummy_token_from_uname()
- return ProcessManagerDriver(
- settings.PROCESS_MANAGER_URL, token=token, aio_channel=True
- )
-
-
-async def get_session_info() -> ProcessInstanceList:
- """Get info about all sessions from process manager."""
- pmd = get_process_manager_driver()
- query = ProcessQuery(names=[".*"])
- return await pmd.ps(query)
@login_required
def index(request: HttpRequest) -> HttpResponse:
"""View that renders the index/home page."""
- with transaction.atomic():
- # atomic to avoid race condition with kafka consumer
- messages = request.session.load().get("messages", [])
- request.session.pop("messages", [])
- request.session.save()
-
- context = {"messages": messages}
- return render(request=request, context=context, template_name="main/index.html")
-
-
-@login_required
-def process_table(request: HttpRequest) -> HttpResponse:
- """Renders the process table.
-
- This view may be called using either GET or POST methods. GET renders the table with
- no check boxes selected. POST renders the table with checked boxes for any table row
- with a uuid provided in the select key of the request data.
- """
- selected_rows = request.POST.getlist("select", [])
- session_info = asyncio.run(get_session_info())
-
- status_enum_lookup = dict(item[::-1] for item in ProcessInstance.StatusCode.items())
-
- table_data = []
- process_instances = session_info.data.values
- for process_instance in process_instances:
- metadata = process_instance.process_description.metadata
- uuid = process_instance.uuid.uuid
- table_data.append(
- {
- "uuid": uuid,
- "name": metadata.name,
- "user": metadata.user,
- "session": metadata.session,
- "status_code": status_enum_lookup[process_instance.status_code],
- "exit_code": process_instance.return_code,
- "checked": (uuid in selected_rows),
- }
- )
- table = ProcessTable(table_data)
-
- # sort table data based on request parameters
- table_configurator = django_tables2.RequestConfig(request)
- table_configurator.configure(table)
-
- return render(
- request=request,
- context=dict(table=table),
- template_name="main/partials/process_table.html",
- )
-
-
-# an enum for process actions
-class ProcessAction(Enum):
- """Enum for process actions."""
-
- RESTART = "restart"
- KILL = "kill"
- FLUSH = "flush"
-
-
-async def _process_call(uuids: list[str], action: ProcessAction) -> None:
- """Perform an action on a process with a given UUID.
-
- Args:
- uuids: List of UUIDs of the process to be actioned.
- action: Action to be performed {restart,flush,kill}.
- """
- pmd = get_process_manager_driver()
- uuids_ = [ProcessUUID(uuid=u) for u in uuids]
-
- match action:
- case ProcessAction.RESTART:
- for uuid_ in uuids_:
- query = ProcessQuery(uuids=[uuid_])
- await pmd.restart(query)
- case ProcessAction.KILL:
- query = ProcessQuery(uuids=uuids_)
- await pmd.kill(query)
- case ProcessAction.FLUSH:
- query = ProcessQuery(uuids=uuids_)
- await pmd.flush(query)
-
-
-@login_required
-@permission_required("main.can_modify_processes", raise_exception=True)
-def process_action(request: HttpRequest) -> HttpResponse:
- """Perform an action on the selected processes.
-
- Both the action and the selected processes are retrieved from the request.
-
- Args:
- request: Django HttpRequest object.
-
- Returns:
- HttpResponse redirecting to the index page.
- """
- try:
- action = request.POST.get("action", "")
- action_enum = ProcessAction(action.lower())
- except ValueError:
- return HttpResponseRedirect(reverse("main:index"))
-
- if uuids_ := request.POST.getlist("select"):
- asyncio.run(_process_call(uuids_, action_enum))
- return HttpResponseRedirect(reverse("main:index"))
-
-
-async def _get_process_logs(uuid: str) -> list[DecodedResponse]:
- """Retrieve logs for a process from the process manager.
-
- Args:
- uuid: UUID of the process.
-
- Returns:
- The process logs.
- """
- pmd = get_process_manager_driver()
- query = ProcessQuery(uuids=[ProcessUUID(uuid=uuid)])
- request = LogRequest(query=query, how_far=100)
- return [item async for item in pmd.logs(request)]
-
-
-@login_required
-@permission_required("main.can_view_process_logs", raise_exception=True)
-def logs(request: HttpRequest, uuid: uuid.UUID) -> HttpResponse:
- """Display the logs of a process.
-
- Args:
- request: the triggering request.
- uuid: identifier for the process.
-
- Returns:
- The rendered page.
- """
- logs_response = asyncio.run(_get_process_logs(str(uuid)))
- context = dict(log_text="\n".join(val.data.line for val in logs_response))
- return render(request=request, context=context, template_name="main/logs.html")
-
-
-async def _boot_process(user: str, data: dict[str, str | int]) -> None:
- """Boot a process with the given data.
-
- Args:
- user: the user to boot the process as.
- data: the data for the process.
- """
- pmd = get_process_manager_driver()
- async for item in pmd.dummy_boot(user=user, **data):
- pass
-
-
-class BootProcessView(PermissionRequiredMixin, FormView): # type: ignore [type-arg]
- """View for the BootProcess form."""
-
- template_name = "main/boot_process.html"
- form_class = BootProcessForm
- success_url = reverse_lazy("main:index")
- permission_required = "main.can_modify_processes"
-
- def form_valid(self, form: BootProcessForm) -> HttpResponse:
- """Boot a Process when valid form data has been POSTed.
-
- Args:
- form: the form instance that has been validated.
-
- Returns:
- A redirect to the index page.
- """
- asyncio.run(_boot_process("root", form.cleaned_data))
- return super().form_valid(form)
+ return render(request=request, template_name="main/index.html")
diff --git a/process_manager/__init__.py b/process_manager/__init__.py
new file mode 100644
index 0000000..0cb9b3c
--- /dev/null
+++ b/process_manager/__init__.py
@@ -0,0 +1 @@
+"""The process_manager app for the drunc_ui project."""
diff --git a/process_manager/admin.py b/process_manager/admin.py
new file mode 100644
index 0000000..eb1b949
--- /dev/null
+++ b/process_manager/admin.py
@@ -0,0 +1,3 @@
+"""Admin module for the process_manager app."""
+
+# Register your models here.
diff --git a/process_manager/apps.py b/process_manager/apps.py
new file mode 100644
index 0000000..3736c31
--- /dev/null
+++ b/process_manager/apps.py
@@ -0,0 +1,10 @@
+"""Apps module for the process_manager app."""
+
+from django.apps import AppConfig
+
+
+class ProcessManagerConfig(AppConfig):
+ """The app config for the process_manager app."""
+
+ default_auto_field = "django.db.models.BigAutoField"
+ name = "process_manager"
diff --git a/main/forms.py b/process_manager/forms.py
similarity index 85%
rename from main/forms.py
rename to process_manager/forms.py
index b487902..457ad0d 100644
--- a/main/forms.py
+++ b/process_manager/forms.py
@@ -1,4 +1,4 @@
-"""Forms for the main app."""
+"""Forms for the process_manager app."""
from django import forms
diff --git a/process_manager/migrations/__init__.py b/process_manager/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/process_manager/models.py b/process_manager/models.py
new file mode 100644
index 0000000..86b8943
--- /dev/null
+++ b/process_manager/models.py
@@ -0,0 +1,3 @@
+"""Models module for the process_manager app."""
+
+# Create your models here.
diff --git a/main/tables.py b/process_manager/tables.py
similarity index 75%
rename from main/tables.py
rename to process_manager/tables.py
index d57b282..8dd6b60 100644
--- a/main/tables.py
+++ b/process_manager/tables.py
@@ -1,10 +1,10 @@
-"""Tables for the main app."""
+"""Tables for the process_manager app."""
import django_tables2 as tables
restart_column_template = (
"{text}".format(
- href="\"{% url 'main:restart' record.uuid%}\"",
+ href="\"{% url 'process_manager:restart' record.uuid%}\"",
message="You are about to restart process {{record.uuid}}. Are you sure?",
text="RESTART",
)
@@ -12,15 +12,19 @@
kill_column_template = (
"{text}".format(
- href="\"{% url 'main:kill' record.uuid%}\"",
+ href="\"{% url 'process_manager:kill' record.uuid%}\"",
message="You are about to kill process {{record.uuid}}. Are you sure?",
text="KILL",
)
)
-flush_column_template = "FLUSH"
+flush_column_template = (
+ "FLUSH"
+)
-logs_column_template = "LOGS"
+logs_column_template = (
+ "LOGS"
+)
class ProcessTable(tables.Table):
diff --git a/main/templates/main/boot_process.html b/process_manager/templates/process_manager/boot_process.html
similarity index 80%
rename from main/templates/main/boot_process.html
rename to process_manager/templates/process_manager/boot_process.html
index 4eef2b8..3c25c35 100644
--- a/main/templates/main/boot_process.html
+++ b/process_manager/templates/process_manager/boot_process.html
@@ -5,7 +5,7 @@
Boot Process
{% endblock title %}
{% block content %}
-