sysview-py 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sysview_py/__init__.py +0 -0
- sysview_py/db.py +122 -0
- sysview_py/flock.py +13 -0
- sysview_py/main.py +27 -0
- sysview_py/report.py +185 -0
- sysview_py/static/simple.css +779 -0
- sysview_py/static/sysview.css +38 -0
- sysview_py/sysview.py +114 -0
- sysview_py/templates/footer.html +5 -0
- sysview_py/templates/header.html +26 -0
- sysview_py/templates/host.html +19 -0
- sysview_py/templates/index.html +22 -0
- sysview_py/templates/index.html.table +22 -0
- sysview_py/templates/service.html +6 -0
- sysview_py/templates/services.html +22 -0
- sysview_py-0.1.0.dist-info/METADATA +10 -0
- sysview_py-0.1.0.dist-info/RECORD +19 -0
- sysview_py-0.1.0.dist-info/WHEEL +4 -0
- sysview_py-0.1.0.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
.OK {
|
|
2
|
+
color: black;
|
|
3
|
+
background-color: green;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.WARNING {
|
|
7
|
+
color: black;
|
|
8
|
+
background-color: gold;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.CRITICAL {
|
|
12
|
+
color: black;
|
|
13
|
+
background-color: crimson;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.UNKNOWN {
|
|
17
|
+
color: black;
|
|
18
|
+
background-color: purple;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.active {
|
|
22
|
+
background-color: dimgrey;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
:root {
|
|
26
|
+
width: 100%;
|
|
27
|
+
color-scheme: dark;
|
|
28
|
+
--bg: #212121;
|
|
29
|
+
--accent-bg: #2b2b2b;
|
|
30
|
+
--text: #dcdcdc;
|
|
31
|
+
--text-light: #ababab;
|
|
32
|
+
--accent: #ffb300;
|
|
33
|
+
--accent-hover: #ffe099;
|
|
34
|
+
--accent-text: var(--bg);
|
|
35
|
+
--code: #f06292;
|
|
36
|
+
--preformatted: #ccc;
|
|
37
|
+
--disabled: #111;
|
|
38
|
+
}
|
sysview_py/sysview.py
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import shutil
|
|
2
|
+
import sys
|
|
3
|
+
from jinja2 import Environment, PackageLoader, select_autoescape
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from .db import SysviewDB
|
|
6
|
+
from .report import Report, Host
|
|
7
|
+
|
|
8
|
+
DEFAULT_DB_PATH = Path.home() / ".sysview.db"
|
|
9
|
+
DEFAULT_HTML_PATH = Path.home() / "sysview"
|
|
10
|
+
STATIC_FILES_PATH = Path(__file__).parent / "static"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Sysview:
|
|
15
|
+
status_sort_order = ("UNKNOWN", "CRITICAL", "WARNING", "OK")
|
|
16
|
+
def __init__(self, db=DEFAULT_DB_PATH, hosts=[], reports=[], html_root=DEFAULT_HTML_PATH):
|
|
17
|
+
self.db = db
|
|
18
|
+
self.hosts = hosts
|
|
19
|
+
self.reports = reports
|
|
20
|
+
self.html_root = html_root
|
|
21
|
+
self.html_hosts = html_root / "hosts"
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def all_services(self):
|
|
25
|
+
items = []
|
|
26
|
+
sorted_items = []
|
|
27
|
+
for host in self.hosts:
|
|
28
|
+
items += host.all_items
|
|
29
|
+
items.sort(key=lambda item: item.status_code, reverse=True)
|
|
30
|
+
return items
|
|
31
|
+
|
|
32
|
+
def setup_db(self, db_path):
|
|
33
|
+
self.db = SysviewDB(path=db_path)
|
|
34
|
+
self.db.connect()
|
|
35
|
+
|
|
36
|
+
def process_reports(self, raw_reports):
|
|
37
|
+
for raw_report in raw_reports:
|
|
38
|
+
report = Report(raw_report)
|
|
39
|
+
report.parse()
|
|
40
|
+
self.db.add(report)
|
|
41
|
+
|
|
42
|
+
def read_hosts(self):
|
|
43
|
+
self.hosts = [
|
|
44
|
+
Host(name=host[0], report_types=host[1]) for host in self.db.get_hosts()
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
def update_html(self):
|
|
48
|
+
shutil.rmtree(self.html_root)
|
|
49
|
+
self.html_root.mkdir(parents=True)
|
|
50
|
+
self.html_hosts.mkdir(parents=True)
|
|
51
|
+
shutil.copytree(STATIC_FILES_PATH, self.html_root / STATIC_FILES_PATH.name)
|
|
52
|
+
env = Environment(
|
|
53
|
+
loader=PackageLoader("sysview_py"),
|
|
54
|
+
autoescape=select_autoescape()
|
|
55
|
+
)
|
|
56
|
+
html = env.get_template("index.html").render(hosts=self.hosts, title="Hosts", active="Hosts", path="")
|
|
57
|
+
html_path = self.html_root / "index.html"
|
|
58
|
+
with open(html_path, 'w') as f:
|
|
59
|
+
f.write(html)
|
|
60
|
+
for host in self.hosts:
|
|
61
|
+
html = env.get_template("host.html").render(host=host, title=host.name, active="Hosts", path="../../")
|
|
62
|
+
host_dir = self.html_hosts / host.name
|
|
63
|
+
host_dir.mkdir()
|
|
64
|
+
html_path = host_dir / "host.html"
|
|
65
|
+
with open(html_path, 'w') as f:
|
|
66
|
+
f.write(html)
|
|
67
|
+
for item in host.all_items:
|
|
68
|
+
html = env.get_template("service.html").render(item=item, title=host.name, active="Services", path="../../")
|
|
69
|
+
html_path = host_dir / f"{item.report_type}_{item.id}.html"
|
|
70
|
+
with open(html_path, 'w') as f:
|
|
71
|
+
f.write(html)
|
|
72
|
+
html = env.get_template("services.html").render(services=self.all_services, title="Services", active="Services", path="")
|
|
73
|
+
html_path = self.html_root / f"services.html"
|
|
74
|
+
with open(html_path, 'w') as f:
|
|
75
|
+
f.write(html)
|
|
76
|
+
|
|
77
|
+
def get_latest_reports(self):
|
|
78
|
+
for host in self.hosts:
|
|
79
|
+
host.reports = []
|
|
80
|
+
raw_reports = self.db.get_latest_reports(hostname=host.name)
|
|
81
|
+
for report_id, raw_report in raw_reports:
|
|
82
|
+
report = Report(raw_report, report_id=report_id)
|
|
83
|
+
report.parse()
|
|
84
|
+
host.reports.append(report)
|
|
85
|
+
host.reports.sort(key=lambda report: report.status_code, reverse=True)
|
|
86
|
+
self.hosts.sort(key=lambda host: host.status_code, reverse=True)
|
|
87
|
+
|
|
88
|
+
@staticmethod
|
|
89
|
+
def read_raw_reports_from_stdin():
|
|
90
|
+
raw_reports = []
|
|
91
|
+
raw_report = ""
|
|
92
|
+
buffer = ""
|
|
93
|
+
identified_fields = 0
|
|
94
|
+
header_fields = ("Hostname:", "Date:", "Type:")
|
|
95
|
+
for raw_line in sys.stdin:
|
|
96
|
+
line = raw_line.rstrip()
|
|
97
|
+
buffer += f"{line}\n"
|
|
98
|
+
possible_header = False
|
|
99
|
+
for field in header_fields:
|
|
100
|
+
if line.startswith(field):
|
|
101
|
+
identified_fields += 1
|
|
102
|
+
possible_header = True
|
|
103
|
+
break
|
|
104
|
+
if identified_fields > 0 and not possible_header:
|
|
105
|
+
identified_fields = 0
|
|
106
|
+
if identified_fields == 3:
|
|
107
|
+
if raw_report:
|
|
108
|
+
raw_reports.append(raw_report)
|
|
109
|
+
raw_report = buffer
|
|
110
|
+
elif identified_fields == 0:
|
|
111
|
+
raw_report += f"{line}\n"
|
|
112
|
+
buffer = ""
|
|
113
|
+
raw_reports.append(raw_report)
|
|
114
|
+
return raw_reports
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>sysview::{{ title }}</title>
|
|
7
|
+
<link rel="stylesheet" href="{{ path }}static/simple.css">
|
|
8
|
+
<link rel="stylesheet" href="{{ path }}static/sysview.css">
|
|
9
|
+
</head>
|
|
10
|
+
<body><header>
|
|
11
|
+
<nav>
|
|
12
|
+
{% if active == 'Hosts' %}
|
|
13
|
+
<a class="current" href="{{ path }}index.html">Hosts</a>
|
|
14
|
+
{% else %}
|
|
15
|
+
<a href="{{ path }}index.html">Hosts</a>
|
|
16
|
+
{% endif %}
|
|
17
|
+
|
|
18
|
+
{% if active == 'Services' %}
|
|
19
|
+
<a class="current" href="{{ path }}services.html">Services</a>
|
|
20
|
+
{% else %}
|
|
21
|
+
<a href="{{ path }}services.html">Services</a>
|
|
22
|
+
{% endif %}
|
|
23
|
+
</nav>
|
|
24
|
+
<h1>{{ title }}</h1>
|
|
25
|
+
</header>
|
|
26
|
+
<main>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{% include 'header.html' %}
|
|
2
|
+
<table>
|
|
3
|
+
<tr>
|
|
4
|
+
<th>Command</th>
|
|
5
|
+
<th>Output</th>
|
|
6
|
+
<th>Last updated</th>
|
|
7
|
+
<th>Status</th>
|
|
8
|
+
</tr>
|
|
9
|
+
{% for item in host.all_items %}
|
|
10
|
+
|
|
11
|
+
<tr>
|
|
12
|
+
<td><a href="{{ item.report_type }}_{{ item.id }}.html">{{ item.command }}</a></td>
|
|
13
|
+
<td>{{ item.status_text }}</td>
|
|
14
|
+
<td>{{ item.date }}</td>
|
|
15
|
+
<td class="{{ item.status }}"></td>
|
|
16
|
+
</tr>
|
|
17
|
+
{% endfor %}
|
|
18
|
+
</table>
|
|
19
|
+
{% include 'footer.html' %}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
{% include 'header.html' %}
|
|
3
|
+
<table>
|
|
4
|
+
<thead><tr>
|
|
5
|
+
<th>Hostname</th>
|
|
6
|
+
<th>Report types</th>
|
|
7
|
+
<th>Last updated</th>
|
|
8
|
+
<th>Status</th>
|
|
9
|
+
</tr></thead>
|
|
10
|
+
<tbody>
|
|
11
|
+
{% for host in hosts %}
|
|
12
|
+
<tr>
|
|
13
|
+
<td><a href="hosts/{{ host.name }}/host.html">{{ host.name }}</a></td>
|
|
14
|
+
<td>{{ host.report_types }}</td>
|
|
15
|
+
<td>{{ host.last_updated }}</td>
|
|
16
|
+
<td class="{{ host.status }}"></td>
|
|
17
|
+
</tr>
|
|
18
|
+
{% endfor %}
|
|
19
|
+
</tbody>
|
|
20
|
+
</table>
|
|
21
|
+
{% include 'footer.html' %}
|
|
22
|
+
</html>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
{% include 'header.html' %}
|
|
3
|
+
<table>
|
|
4
|
+
<thead><tr>
|
|
5
|
+
<th>Hostname</th>
|
|
6
|
+
<th>Report types</th>
|
|
7
|
+
<th>Last updated</th>
|
|
8
|
+
<th>Status</th>
|
|
9
|
+
</tr></thead>
|
|
10
|
+
<tbody>
|
|
11
|
+
{% for host in hosts %}
|
|
12
|
+
<tr>
|
|
13
|
+
<td><a href="hosts/{{ host.name }}/host.html">{{ host.name }}</a></td>
|
|
14
|
+
<td>{{ host.report_types }}</td>
|
|
15
|
+
<td>{{ host.last_updated }}</td>
|
|
16
|
+
<td class="{{ host.status }}"></td>
|
|
17
|
+
</tr>
|
|
18
|
+
{% endfor %}
|
|
19
|
+
</tbody>
|
|
20
|
+
</table>
|
|
21
|
+
{% include 'footer.html' %}
|
|
22
|
+
</html>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
{% include 'header.html' %}
|
|
3
|
+
<table>
|
|
4
|
+
<tr>
|
|
5
|
+
<th>Hostname</th>
|
|
6
|
+
<th>Command</th>
|
|
7
|
+
<th>Output</th>
|
|
8
|
+
<th>Last updated</th>
|
|
9
|
+
<th>Status</th>
|
|
10
|
+
</tr>
|
|
11
|
+
{% for item in services %}
|
|
12
|
+
<tr>
|
|
13
|
+
<td>{{ item.host }}</td>
|
|
14
|
+
<td><a href="hosts/{{ item.host }}/{{ item.report_type}}_{{ item.id }}.html">{{ item.command }}</a></td>
|
|
15
|
+
<td>{{ item.status_text }}</td>
|
|
16
|
+
<td>{{ item.date }}</td>
|
|
17
|
+
<td class="{{ item.status }}"></td>
|
|
18
|
+
</tr>
|
|
19
|
+
{% endfor %}
|
|
20
|
+
</table>
|
|
21
|
+
{% include 'footer.html' %}
|
|
22
|
+
</html>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: sysview-py
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Add your description here
|
|
5
|
+
Author: Michael Wilson
|
|
6
|
+
Author-email: Michael Wilson <mw@1wilson.org>
|
|
7
|
+
Requires-Dist: jinja2>=3.1.6
|
|
8
|
+
Requires-Python: >=3.12
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
sysview_py/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
sysview_py/db.py,sha256=kSkFvD00T68J9YO3Xn6mG1Zc09tqBBKzDgwl8x-CWSQ,4074
|
|
3
|
+
sysview_py/flock.py,sha256=HJnZAMQUPJ6GCjmqyZ8_ST3-a-4xOHCnSAkdM8e6dEo,270
|
|
4
|
+
sysview_py/main.py,sha256=yZQ0VqNItjV3BPS1VAi02DGPoj7r_bXePT2UGGJWLYg,632
|
|
5
|
+
sysview_py/report.py,sha256=nYVDK5qmrpEFmGETfR9-9LqeER-0u5sa6fUrIj-51bY,5856
|
|
6
|
+
sysview_py/static/simple.css,sha256=EN01zNTQvZIZ2n9HNZaV03DD_ie6RUHbEOS6772tRyo,14086
|
|
7
|
+
sysview_py/static/sysview.css,sha256=vWntFiGQrpHBhcZRLg2DX-5lpp73RQmkmj-9NFIMtmI,529
|
|
8
|
+
sysview_py/sysview.py,sha256=LorkHeKDB8OnJYcwn9pdAAKRduCLqD94NkYk_YUEdGM,4348
|
|
9
|
+
sysview_py/templates/footer.html,sha256=DMkYmN0wZRByL_j3LBUEJHSo9U8ncTJQVKvClwuh5AE,66
|
|
10
|
+
sysview_py/templates/header.html,sha256=R_gJhk5ZCw1oFa0cAfXYjvIhiEFTcvRn_88bvZp9QP0,734
|
|
11
|
+
sysview_py/templates/host.html,sha256=SivuflShsO8KHRxDGgQt3hFpk_SCHcURhuc-n2jk9IU,444
|
|
12
|
+
sysview_py/templates/index.html,sha256=NiBPIUluBL-51wJfvde_8uNmSzq0acbAGa1_YReuImA,493
|
|
13
|
+
sysview_py/templates/index.html.table,sha256=NiBPIUluBL-51wJfvde_8uNmSzq0acbAGa1_YReuImA,493
|
|
14
|
+
sysview_py/templates/service.html,sha256=xYNYMJqtotcnWarhXTnit930XDRuesU03k7MEPZFkEM,143
|
|
15
|
+
sysview_py/templates/services.html,sha256=nD8Tllo15LcOh8lvpuc0EOQdsdO44RHjjA0CWmPuJK8,526
|
|
16
|
+
sysview_py-0.1.0.dist-info/WHEEL,sha256=o6xtdofIa8Zz80kUveEHMWeAWtEyZSzYS1bbyKDCgzA,80
|
|
17
|
+
sysview_py-0.1.0.dist-info/entry_points.txt,sha256=CEzvzrPEAijVzJWShPvvtnnSc4WouncYwajUDaSSsR8,53
|
|
18
|
+
sysview_py-0.1.0.dist-info/METADATA,sha256=ecMZthWKWN1SrFhDl4ihJ3ohMYWFf4Sv8fmiCzpP_Z4,252
|
|
19
|
+
sysview_py-0.1.0.dist-info/RECORD,,
|