wip - refactoring and implementing 'real-time' log output

This commit is contained in:
Stephan Lüscher 2024-05-08 18:56:31 +00:00
parent dd001f4fe5
commit 50395caec7
No known key found for this signature in database
GPG key ID: 445779060FF3D3CF
3 changed files with 51 additions and 45 deletions

View file

@ -1,9 +1,9 @@
import ansible_runner import ansible_runner
import re import re
import asyncio import asyncio
import time
from nicegui import ui from nicegui import ui
from utils import get_project_root, local_file_picker, progress_spinner from theme import GuiProgressSpinner
from utils import get_project_root, local_file_picker
ANSIBLE_EXTRA_VARS = None ANSIBLE_EXTRA_VARS = None
@ -25,14 +25,12 @@ async def load_configuration_file() -> None:
ANSIBLE_EXTRA_VARS = f'"@{file_path}"' ANSIBLE_EXTRA_VARS = f'"@{file_path}"'
async def run_ansible_playbook( async def run_ansible_playbook(playbook_name: str, gui_log: ui.log, gui_spinner: GuiProgressSpinner) -> None:
playbook_name: str, # Clear log console
ngui_log: ui.log, gui_log.clear()
ngui_spinner: progress_spinner, # Enable spinner
) -> None: gui_spinner.enable()
ngui_spinner.enable_progress() # Run ansible playbook
# make sure spinner is displayed
await asyncio.sleep(1)
project_root = str(get_project_root()) project_root = str(get_project_root())
playbook_path = project_root + "/ansible/playbooks/" playbook_path = project_root + "/ansible/playbooks/"
inventory_path = project_root + "/ansible/inventory.yml" inventory_path = project_root + "/ansible/inventory.yml"
@ -47,16 +45,26 @@ async def run_ansible_playbook(
extra_vars_file, extra_vars_file,
], ],
) )
# clear log # Parse and display output from ansible playbook
ngui_log.clear() ## Remove color characters from response until clear how to display them in a log
# regex to remove color characters from response until clear how to display them in a log output_parser = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-9;#]+[mGK]?)")
ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-9;#]+[mGK]?)")
# show log from asynchronous job # show log from asynchronous job
processed_events = set() # Set to store processed events
while runner.rc is None: while runner.rc is None:
for event in runner.events: for event in runner.events:
ansible_log = format(ansi_escape.sub("", event["stdout"])) # Make sure log is displayed during playbook run
ngui_log.push(ansible_log) await asyncio.sleep(0.1)
ngui_spinner.disable_progress() # Check if event has been processed already
event_key = (event['uuid'], event['counter'])
if event_key not in processed_events:
# Add event to processed set
processed_events.add(event_key)
# Process event
ansible_log = format(output_parser.sub("", event["stdout"]))
# Push log to ui
gui_log.push(ansible_log)
# Disable spinner
gui_spinner.disable()
# Page content # Page content
@ -76,28 +84,28 @@ def content() -> None:
with ui.card().classes("h-full"): with ui.card().classes("h-full"):
with ui.row().classes("no-wrap"): with ui.row().classes("no-wrap"):
ui.label("Build").classes("text-h5") ui.label("Build").classes("text-h5")
build_progress = progress_spinner() gui_build_progress = GuiProgressSpinner()
ui.button( ui.button(
text="Clone project", text="Clone project",
on_click=lambda: run_ansible_playbook( on_click=lambda: run_ansible_playbook(
playbook_name="project_clone.yml", playbook_name="project_clone.yml",
ngui_log=playbook_log, gui_log=playbook_log,
ngui_spinner=build_progress, gui_spinner=gui_build_progress,
), ),
) )
ui.button( ui.button(
text="Build project", text="Build project",
on_click=lambda: run_ansible_playbook( on_click=lambda: run_ansible_playbook(
"project_build.yml", "project_build.yml",
ngui_log=playbook_log, gui_log=playbook_log,
ngui_spinner=build_progress, gui_spinner=gui_build_progress,
), ),
) )
# Second Row # Second Row
with ui.card().classes("h-full"): with ui.card().classes("h-full"):
with ui.row().classes("no-wrap"): with ui.row().classes("no-wrap"):
ui.label("Deploy").classes("text-h6") ui.label("Deploy").classes("text-h6")
deploy_progress = progress_spinner() gui_deploy_progress = GuiProgressSpinner
ui.button( ui.button(
"Deploy VM", "Deploy VM",
on_click=lambda: ui.notify("This playbook is not implemented yet"), on_click=lambda: ui.notify("This playbook is not implemented yet"),

View file

@ -1,10 +1,28 @@
from contextlib import contextmanager from contextlib import contextmanager
from menu import menu from menu import menu
from nicegui import ui from nicegui import ui
class GuiProgressSpinner(ui.spinner):
def __init__(
self,
*,
type: str = "dots",
size: str = "lg",
color: str | None = "red",
thickness: float = 5
) -> None:
super().__init__(type, size=size, color=color, thickness=thickness)
with self, ui.spinner():
self.visible = False
def enable(self) -> None:
self.set_visibility(True)
def disable(self) -> None:
self.set_visibility(False)
@contextmanager @contextmanager
def frame(navigation_title: str, enable_right_drawer: bool = False): def frame(navigation_title: str, enable_right_drawer: bool = False):
"""Custom page frame to share the same styling and behavior across all pages""" """Custom page frame to share the same styling and behavior across all pages"""

View file

@ -116,25 +116,5 @@ class local_file_picker(ui.dialog):
self.submit([r["path"] for r in rows]) self.submit([r["path"] for r in rows])
class progress_spinner(ui.spinner):
def __init__(
self,
*,
type: str = "dots",
size: str = "lg",
color: str | None = "red",
thickness: float = 5,
) -> None:
super().__init__(type, size=size, color=color, thickness=thickness)
with self, ui.spinner():
self.visible = False
def enable_progress(self) -> None:
self.set_visibility(True)
def disable_progress(self) -> None:
self.set_visibility(False)
def get_project_root() -> Path: def get_project_root() -> Path:
return Path(__file__).parent.parent return Path(__file__).parent.parent