Adding type annotations and fixing up formatting.
[kiosk.git] / health_renderer.py
1 #!/usr/bin/env python3
2
3 import os
4 import time
5 from typing import Dict, List
6
7 import constants
8 import file_writer
9 import renderer
10 import utils
11
12
13 class periodic_health_renderer(renderer.debuggable_abstaining_renderer):
14     def __init__(self, name_to_timeout_dict: Dict[str, int]) -> None:
15         super(periodic_health_renderer, self).__init__(name_to_timeout_dict, False)
16
17     def debug_prefix(self) -> str:
18         return "health"
19
20     def periodic_render(self, key: str) -> bool:
21         with file_writer.file_writer("periodic-health_6_300.html") as f:
22             timestamps = "/timestamps/"
23             days = constants.seconds_per_day
24             hours = constants.seconds_per_hour
25             mins = constants.seconds_per_minute
26             minutes = mins
27             limits = {
28                 timestamps + "last_http_probe_wannabe_house": mins * 10,
29                 timestamps + "last_http_probe_meerkat_cabin": mins * 10,
30                 timestamps + "last_http_probe_dns_house": mins * 10,
31                 timestamps + "last_http_probe_rpi_cabin": mins * 10,
32                 timestamps + "last_http_probe_rpi_house": mins * 10,
33                 timestamps + "last_http_probe_therm_house": mins * 10,
34                 timestamps + "last_rsnapshot_hourly": hours * 24,
35                 timestamps + "last_rsnapshot_daily": days * 3,
36                 timestamps + "last_rsnapshot_weekly": days * 14,
37                 timestamps + "last_rsnapshot_monthly": days * 70,
38                 timestamps + "last_zfssnapshot_hourly": hours * 5,
39                 timestamps + "last_zfssnapshot_daily": hours * 36,
40                 timestamps + "last_zfssnapshot_weekly": days * 9,
41                 timestamps + "last_zfssnapshot_monthly": days * 70,
42                 timestamps + "last_zfssnapshot_cleanup": hours * 24,
43                 timestamps + "last_zfs_scrub": days * 9,
44                 timestamps + "last_backup_zfs_scrub": days * 9,
45                 timestamps + "last_cabin_zfs_scrub": days * 9,
46                 timestamps + "last_zfsxfer_backup.house": hours * 36,
47                 timestamps + "last_zfsxfer_ski.dyn.guru.org": days * 7,
48                 timestamps + "last_photos_sync": hours * 8,
49                 timestamps + "last_disk_selftest_short": days * 14,
50                 timestamps + "last_disk_selftest_long": days * 31,
51                 timestamps + "last_backup_disk_selftest_short": days * 14,
52                 timestamps + "last_backup_disk_selftest_long": days * 31,
53                 timestamps + "last_cabin_disk_selftest_short": days * 14,
54                 timestamps + "last_cabin_disk_selftest_long": days * 31,
55                 timestamps + "last_cabin_rpi_ping": mins * 10,
56                 timestamps + "last_healthy_wifi": mins * 10,
57                 timestamps + "last_healthy_network": mins * 10,
58                 timestamps + "last_scott_sync": days * 2,
59             }
60             self.write_header(f)
61
62             now = time.time()
63             n = 0
64             for x in sorted(limits):
65                 ts = os.stat(x).st_mtime
66                 age = now - ts
67                 self.debug_print("%s -- age is %ds, limit is %ds" % (x, age, limits[x]))
68                 if age < limits[x]:
69                     f.write(
70                         '<TD BGCOLOR="#007010" HEIGHT=100 WIDTH=33% STYLE="text-size:60%; vertical-align: middle;">\n'
71                     )
72                 else:
73                     f.write(
74                         '<TD BGCOLOR="#990000" HEIGHT=100 WIDTH=33% CLASS="invalid" STYLE="text-size:60%; vertical-align:middle;">\n'
75                     )
76                 f.write("  <CENTER><FONT SIZE=-2>\n")
77
78                 name = x.replace(timestamps, "")
79                 name = name.replace("last_", "")
80                 name = name.replace("_", "&nbsp;")
81                 ts = utils.describe_duration_briefly(age)
82
83                 self.debug_print(f"{name} is {ts} old.")
84                 f.write(f"{name}<BR>\n<B>{ts}</B> old.\n")
85                 f.write("</FONT></CENTER>\n</TD>\n\n")
86                 n += 1
87                 if n % 3 == 0:
88                     f.write("</TR>\n<TR>\n<!-- ------------------- -->\n")
89             self.write_footer(f)
90         return True
91
92     def write_header(self, f: file_writer.file_writer) -> None:
93         f.write(
94             """
95 <HTML>
96 <HEAD>
97 <STYLE>
98 @-webkit-keyframes invalid {
99   from { background-color: #ff6400; }
100   to { background-color: #ff0000; }
101   padding-right: 25px;
102   padding-left: 25px;
103 }
104 @-moz-keyframes invalid {
105   from { background-color: #ff6400; }
106   to { background-color: #ff0000; }
107   padding-right: 25px;
108   padding-left: 25px;
109 }
110 @-o-keyframes invalid {
111   from { background-color: #ff6400; }
112   to { background-color: #ff0000; }
113   padding-right: 25px;
114   padding-left: 25px;
115 }
116 @keyframes invalid {
117   from { background-color: #ff6400; }
118   to { background-color: #ff0000; }
119   padding-right: 25px;
120   padding-left: 25px;
121 }
122 .invalid {
123   -webkit-animation: invalid 1s infinite; /* Safari 4+ */
124   -moz-animation:    invalid 1s infinite; /* Fx 5+ */
125   -o-animation:      invalid 1s infinite; /* Opera 12+ */
126   animation:         invalid 1s infinite; /* IE 10+ */
127 }
128 </STYLE>
129 <meta http-equiv="cache-control" content="max-age=0" />
130 <meta http-equiv="cache-control" content="no-cache" />
131 <meta http-equiv="expires" content="0" />
132 <meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
133 <meta http-equiv="pragma" content="no-cache" />
134 </HEAD>
135 <BODY>
136 <H1>Periodic Cronjob Health Report</H1>
137 <HR>
138 <CENTER>
139 <TABLE BORDER=0 WIDTH=99% style="font-size:16pt">
140 <TR>
141 """
142         )
143
144     def write_footer(self, f: file_writer.file_writer) -> None:
145         f.write(
146             """
147 </TR>
148 </TABLE>
149 </BODY>
150 </HTML>"""
151         )
152
153
154 # test = periodic_health_renderer({"Test", 123})
155 # test.periodic_render("Test")