mirror of
https://github.com/ublue-os/forge.git
synced 2025-07-04 08:45:45 +03:00
feat: add graphical user interface (#34)
This commit is contained in:
parent
c3ed45a21b
commit
4f2130bcce
43 changed files with 2939 additions and 971 deletions
121
anvil/nicegui/pages/ansible.py
Normal file
121
anvil/nicegui/pages/ansible.py
Normal file
|
@ -0,0 +1,121 @@
|
|||
import ansible_runner
|
||||
import re
|
||||
import asyncio
|
||||
import os
|
||||
from nicegui import ui
|
||||
from theme import GuiProgressSpinner
|
||||
from utils import local_file_picker
|
||||
|
||||
ANSIBLE_EXTRA_VARS = None
|
||||
|
||||
|
||||
# Ansible integration
|
||||
@ui.refreshable # https://www.reddit.com/r/nicegui/comments/1bphjk5/comment/kx7l5kj/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button
|
||||
async def load_configuration_file() -> None:
|
||||
global ANSIBLE_EXTRA_VARS
|
||||
result = await local_file_picker(
|
||||
directory="/data", multiple=False, file_name_filter=".yml"
|
||||
)
|
||||
file_path = result[0]
|
||||
with open(file_path, "r") as file:
|
||||
data = file.read()
|
||||
## Give feedback to user
|
||||
ui.notify(f"You chose {file_path}")
|
||||
## Display content
|
||||
ui.code(content=data, language="yaml")
|
||||
## Preserve configuration file path for ansible-playbook --extra-vars
|
||||
ANSIBLE_EXTRA_VARS = f"@{file_path}"
|
||||
|
||||
|
||||
async def run_ansible_playbook(
|
||||
playbook_name: str, gui_log: ui.log, gui_spinner: GuiProgressSpinner
|
||||
) -> None:
|
||||
# Clear log console
|
||||
gui_log.clear()
|
||||
# Enable spinner
|
||||
gui_spinner.enable()
|
||||
# Run ansible playbook
|
||||
project_root = os.environ["ANSIBLE_DIR"]
|
||||
playbook_path = f"{project_root}/playbooks/"
|
||||
extra_vars_file = ANSIBLE_EXTRA_VARS
|
||||
thread, runner = ansible_runner.interface.run_command_async(
|
||||
executable_cmd="ansible-playbook",
|
||||
cmdline_args=[
|
||||
f"{playbook_path}/{playbook_name}",
|
||||
# playbook_path + playbook_name,
|
||||
"--extra-vars",
|
||||
extra_vars_file,
|
||||
],
|
||||
)
|
||||
# Parse and display output from ansible playbook
|
||||
## Remove color characters from response until clear how to display them in a log
|
||||
output_parser = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-9;#]+[mGK]?)")
|
||||
# show log from asynchronous job
|
||||
processed_events = set() # Set to store processed events
|
||||
while runner.rc is None:
|
||||
for event in runner.events:
|
||||
# Make sure log is displayed during playbook run
|
||||
await asyncio.sleep(0.1)
|
||||
# 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
|
||||
def content() -> None:
|
||||
with ui.row().classes("w-full"):
|
||||
with ui.row().classes("w-full"):
|
||||
with ui.card().classes("h-full"):
|
||||
ui.button(
|
||||
text="Load configuration file",
|
||||
on_click=lambda: load_configuration_file.refresh(),
|
||||
icon="folder",
|
||||
)
|
||||
## show configuration file with ui.code
|
||||
load_configuration_file()
|
||||
with ui.row().classes("w-full"):
|
||||
# First Row
|
||||
with ui.card().classes("h-full"):
|
||||
with ui.row().classes("no-wrap"):
|
||||
ui.label("Build").classes("text-h5")
|
||||
gui_build_progress = GuiProgressSpinner()
|
||||
ui.button(
|
||||
text="Clone project",
|
||||
on_click=lambda: run_ansible_playbook(
|
||||
playbook_name="project_clone.yml",
|
||||
gui_log=gui_playbook_log,
|
||||
gui_spinner=gui_build_progress,
|
||||
),
|
||||
)
|
||||
ui.button(
|
||||
text="Build project",
|
||||
on_click=lambda: run_ansible_playbook(
|
||||
"project_build.yml",
|
||||
gui_log=gui_playbook_log,
|
||||
gui_spinner=gui_build_progress,
|
||||
),
|
||||
)
|
||||
# Second Row
|
||||
with ui.card().classes("h-full"):
|
||||
with ui.row().classes("no-wrap"):
|
||||
ui.label("Deploy").classes("text-h6")
|
||||
gui_deploy_progress = GuiProgressSpinner
|
||||
ui.button(
|
||||
"Deploy VM",
|
||||
on_click=lambda: ui.notify("This playbook is not implemented yet"),
|
||||
)
|
||||
|
||||
with ui.row().classes("w-full"):
|
||||
with ui.card().classes("w-full"):
|
||||
ui.label("Playbook Log").classes("text-h6")
|
||||
ui.button("Clear Log", on_click=lambda: gui_playbook_log.clear())
|
||||
|
||||
gui_playbook_log = ui.log().classes("w-full h-full")
|
Loading…
Add table
Add a link
Reference in a new issue