Dashboard improvements

This commit is contained in:
Brett Williams
2022-10-08 17:55:24 -07:00
parent 7b33f06405
commit e12171a6d2

View File

@@ -1,28 +1,24 @@
#!/usr/bin/env python
import datetime
import json
import os.path
import socket
import time
import threading
import time
import traceback
import psutil
import requests
import click
from rich import box
from rich.console import Console
from rich.layout import Layout
from rich.live import Live
from rich.panel import Panel
from rich.table import Column
from rich.table import Table
from rich.text import Text
from rich.layout import Layout
from rich.panel import Panel
from rich.tree import Tree
import zordon_server
from zordon_server import RenderStatus
from zordon_server import string_to_status
from zordon_server import RenderStatus, string_to_status
"""
The RenderDashboard is designed to be run on a remote machine or on the local server
@@ -36,6 +32,8 @@ status_colors = {RenderStatus.ERROR: "red", RenderStatus.CANCELLED: 'orange1', R
categories = [RenderStatus.RUNNING, RenderStatus.ERROR, RenderStatus.NOT_STARTED, RenderStatus.SCHEDULED,
RenderStatus.COMPLETED, RenderStatus.CANCELLED]
renderer_colors = {'ffmpeg': '[magenta]', 'Blender': '[orange1]', 'aerender':'[purple'}
local_hostname = socket.gethostname()
@@ -46,15 +44,19 @@ def status_string_to_color(status_string):
def sorted_jobs(all_jobs):
# sorted_jobs = []
# if all_jobs:
# for status_category in categories:
# found_jobs = [x for x in all_jobs if x['status'] == status_category.value]
# if found_jobs:
# sorted_found_jobs = sorted(found_jobs, key=lambda d: datetime.datetime.fromisoformat(d['date_created']), reverse=True)
# sorted_jobs.extend(sorted_found_jobs)
sorted_jobs = sorted(all_jobs, key=lambda d: datetime.datetime.fromisoformat(d['date_created']), reverse=True)
return sorted_jobs
sort_by_date = True
if not sort_by_date:
sorted_job_list = []
if all_jobs:
for status_category in categories:
found_jobs = [x for x in all_jobs if x['status'] == status_category.value]
if found_jobs:
sorted_found_jobs = sorted(found_jobs, key=lambda d: datetime.datetime.fromisoformat(d['date_created']), reverse=True)
sorted_job_list.extend(sorted_found_jobs)
else:
sorted_job_list = sorted(all_jobs, key=lambda d: datetime.datetime.fromisoformat(d['date_created']), reverse=True)
return sorted_job_list
def create_node_tree(all_server_data) -> Tree:
@@ -69,29 +71,30 @@ def create_node_tree(all_server_data) -> Tree:
node_tree = Tree(node_tree_text)
stats_text = f"CPU: {server_data['status']['cpu_percent']}% | RAM: {server_data['status']['memory_percent']}% | " \
f"Cores: {server_data['status']['cpu_count']} | {server_data['status']['platform'].split('-')[0]}"
stats_text = f"CPU: [yellow]{server_data['status']['cpu_percent']}% [default]| RAM: " \
f"[yellow]{server_data['status']['memory_percent']}% [default]| Cores: " \
f"[yellow]{server_data['status']['cpu_count']} [default]| " \
f"{server_data['status']['platform'].split('-')[0]}"
node_tree.add(Tree(stats_text))
running_jobs = [job for job in server_data['jobs'] if job['status'] == 'running']
not_started = [job for job in server_data['jobs'] if job['status'] == 'not_started']
scheduled = [job for job in server_data['jobs'] if job['status'] == 'scheduled']
jobs_to_display = running_jobs + not_started + scheduled
jobs_tree = Tree(f"Running: [green]{len(running_jobs)} [default]| Queued: [cyan]{len(not_started)}"
f"[default] | Scheduled: [cyan]{len(scheduled)}")
if running_jobs or not_started or scheduled:
for job in running_jobs:
filename = os.path.basename(job['render']['input']).split('.')[0]
jobs_tree.add(f"[bold]{filename} ({job['id']}) - {status_string_to_color(job['status'])}{(float(job['render']['percent_complete']) * 100):.1f}%")
for job in not_started:
filename = os.path.basename(job['render']['input']).split('.')[0]
for job in jobs_to_display:
renderer = f"{renderer_colors[job['renderer']]}{job['renderer']}[default]"
filename = os.path.basename(job['render']['input']).split('.')[0]
if job['status'] == 'running':
jobs_tree.add(f"[bold]{renderer} {filename} ({job['id']}) - {status_string_to_color(job['status'])}{(float(job['render']['percent_complete']) * 100):.1f}%")
else:
jobs_tree.add(f"{filename} ({job['id']}) - {status_string_to_color(job['status'])}{job['status'].title()}")
for job in scheduled:
filename = os.path.basename(job['render']['input']).split('.')[0]
jobs_tree.add(f"{filename} ({job['id']}) - {status_string_to_color(job['status'])}{job['status'].title()}")
else:
if not jobs_to_display:
jobs_tree.add("[italic]No running jobs")
node_tree.add(jobs_tree)
@@ -102,13 +105,13 @@ def create_node_tree(all_server_data) -> Tree:
def create_jobs_table(all_server_data) -> Table:
table = Table("ID", "Project", "Output", "Renderer", Column(header="Priority", justify="center"),
Column(header="Status", justify="center"), Column(header="Time Elapsed", justify="right"),
Column(header="# Frames", justify="right"), "Node", show_lines=True,
Column(header="# Frames", justify="right"), "Client", show_lines=True,
box=box.HEAVY_HEAD)
all_jobs = []
for server_name, server_data in all_server_data['servers'].items():
for job in server_data['jobs']:
job['node'] = server_name
#todo: clean this up
all_jobs.append(job)
all_jobs = sorted_jobs(all_jobs)
@@ -117,7 +120,10 @@ def create_jobs_table(all_server_data) -> Table:
job_status = string_to_status(job['status'])
job_color = '[{}]'.format(status_colors[job_status])
job_text = f"{job_color}" + job_status.value
job_text = f"{job_color}" + job_status.value.title()
if job_status == RenderStatus.ERROR and job['render']['errors']:
job_text = job_text + "\n" + "\n".join(job['render']['errors'])
elapsed_time = job['render'].get('time_elapsed', 'unknown')
@@ -136,8 +142,9 @@ def create_jobs_table(all_server_data) -> Table:
# Priority
priority_color = ["red", "yellow", "cyan"][(job['priority'] - 1)]
node_title = ("[yellow]" if job['node'] == local_hostname else "[magenta]") + job['node']
renderer_colors = {'ffmpeg': '[magenta]', 'Blender': '[orange1]'}
client_name = job['client'] or 'unknown'
client_colors = {'unknown': '[red]', local_hostname: '[yellow]'}
client_title = client_colors.get(client_name, '[magenta]') + client_name
table.add_row(
job['id'],
@@ -148,7 +155,7 @@ def create_jobs_table(all_server_data) -> Table:
job_text,
elapsed_time,
str(max(int(job['render']['total_frames']), 1)),
node_title
client_title
)
return table
@@ -179,7 +186,6 @@ class RenderDashboard:
return req.json()
except Exception as e:
pass
# print(f"Exception fetching server data: {e}")
return None
def get_jobs(self):
@@ -216,20 +222,20 @@ def my_callback(inp):
if __name__ == '__main__':
server_ip = input("Enter server IP or None for local: ") or local_hostname
get_server_ip = input("Enter server IP or None for local: ") or local_hostname
client = RenderDashboard(server_ip, "8080")
client = RenderDashboard(get_server_ip, "8080")
if not client.connect():
if server_ip == local_hostname:
if client.server_ip == local_hostname:
start_server = input("Local server not running. Start server? (y/n) ")
if start_server and start_server[0].lower() == "y":
# Startup the local server
zordon_server.start_server(background_thread=True)
zordon_server.RenderServer.start(background_thread=True)
test = client.connect()
print(f"connected? {test}")
else:
print(f"\nUnable to connect to server: {server_ip}")
print(f"\nUnable to connect to server: {client.server_ip}")
print("\nVerify IP address is correct and server is running")
exit(1)
@@ -256,8 +262,8 @@ if __name__ == '__main__':
# Server connection header
header_text = Text(f"Connected to server: ")
header_text.append(f"{server_ip} ", style="green")
if server_ip == local_hostname:
header_text.append(f"{client.server_ip} ", style="green")
if client.server_ip == local_hostname:
header_text.append("(This Computer)", style="yellow")
else:
header_text.append("(Remote)", style="magenta")