Skip to content

Commit 77627c5

Browse files
committed
Add Windows OS lifecycle checks and reporting
1 parent f4676f5 commit 77627c5

File tree

4 files changed

+349
-5
lines changed

4 files changed

+349
-5
lines changed

Protest/Front/issues.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class Issues extends List {
1616
"Memory usage" : "url(mono/ram.svg)",
1717
"Disk space" : "url(mono/hdd.svg)",
1818
"Disk I/O" : "url(mono/ssd.svg)",
19+
"Operating system" : "url(mono/os.svg)",
1920
"Printer component" : "url(mono/printer.svg)",
2021
};
2122

Protest/Tasks/Issues.cs

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ internal static class Issues {
2525
private const int DISK_SPACE_THRESHOLD = 85;
2626
private const int DISK_IO_THRESHOLD = 75;
2727

28-
public enum SeverityLevel {
28+
public enum SeverityLevel : byte {
2929
info = 1,
3030
warning = 2,
3131
error = 3,
@@ -228,6 +228,10 @@ public static void ScanDevice(Database.Entry device) {
228228
issues.Add(issue.Value);
229229
}
230230

231+
if (CheckWindowsLifecycle(device, out Issue? lifecycleIssue) && lifecycleIssue.HasValue) {
232+
issues.Add(lifecycleIssue.Value);
233+
}
234+
231235
if (osAttribute?.value.Contains("windows", StringComparison.OrdinalIgnoreCase) == true) {
232236
string ipString = null;
233237
if (device.attributes.TryGetValue("ip", out Database.Attribute ip) && !String.IsNullOrEmpty(ip?.value)) {
@@ -288,7 +292,7 @@ public static void CheckIpAddresses(out Dictionary<string, Database.Entry> ipAdd
288292
name = nameAttribute?.value ?? String.Empty,
289293
identifier = ips[i],
290294
category = "Database",
291-
source = "Internal check",
295+
source = "Internal",
292296
file = device.Value.filename,
293297
isUser = false,
294298
});
@@ -324,7 +328,7 @@ public static void CheckMacAddresses() {
324328
name = nameAttribute?.value ?? String.Empty,
325329
identifier = macs[i].Length == 12 ? Regex.Replace(macs[i], @"(\w{2})(?=\w)", "$1:") : macs[i],
326330
category = "Database",
327-
source = "Internal check",
331+
source = "Internal",
328332
file = device.Value.filename,
329333
isUser = false,
330334
});
@@ -942,7 +946,7 @@ public static bool CheckPasswordStrength(Database.Entry entry, bool isUser, out
942946
name = nameAttribute?.value ?? String.Empty,
943947
identifier = target,
944948
category = "Password",
945-
source = "Internal check",
949+
source = "Internal",
946950
file = entry.filename,
947951
isUser = isUser,
948952
};
@@ -954,6 +958,62 @@ public static bool CheckPasswordStrength(Database.Entry entry, bool isUser, out
954958
return false;
955959
}
956960

961+
public static bool CheckWindowsLifecycle(Database.Entry device, out Issue? issue) {
962+
issue = null;
963+
964+
if (device is null) {
965+
return false;
966+
}
967+
968+
device.attributes.TryGetValue("operating system", out Database.Attribute osAttribute);
969+
device.attributes.TryGetValue("os version", out Database.Attribute osVersionAttribute);
970+
971+
if (!WindowsLifecycle.TryAssess(osAttribute?.value, osVersionAttribute?.value, out WindowsLifecycle.Assessment assessment)) {
972+
return false;
973+
}
974+
975+
if (assessment.state != WindowsLifecycle.SupportState.expiringSoon
976+
&& assessment.state != WindowsLifecycle.SupportState.outOfSupport) {
977+
return false;
978+
}
979+
980+
device.attributes.TryGetValue("name", out Database.Attribute nameAttribute);
981+
982+
string osName = assessment.productName.Contains(assessment.release, StringComparison.OrdinalIgnoreCase)
983+
? assessment.productName
984+
: $"{assessment.productName} {assessment.release}";
985+
986+
string message = assessment.state == WindowsLifecycle.SupportState.outOfSupport
987+
? $"{osName} ({assessment.version}) has reached EOS"
988+
: $"{osName} ({assessment.version}) reaches EOS on {assessment.endOfSupport:yyyy-MM-dd} ({assessment.daysLeft} days left)";
989+
990+
string ipString = string.Empty;
991+
if (device.attributes.TryGetValue("ip", out Database.Attribute ip) && !String.IsNullOrEmpty(ip?.value)) {
992+
ipString = ip.value.Split(';').Select(o => o.Trim()).ToArray()[0];
993+
}
994+
995+
Issues.SeverityLevel severity;
996+
if (assessment.state == WindowsLifecycle.SupportState.outOfSupport) {
997+
severity = SeverityLevel.critical;
998+
}
999+
else {
1000+
severity = assessment.daysLeft < 90 ? SeverityLevel.error : SeverityLevel.warning;
1001+
}
1002+
1003+
issue = new Issue {
1004+
severity = severity,
1005+
message = message,
1006+
name = nameAttribute?.value ?? String.Empty,
1007+
identifier = ipString,
1008+
category = "Operating system",
1009+
source = "Internal",
1010+
file = device.filename,
1011+
isUser = false
1012+
};
1013+
1014+
return true;
1015+
}
1016+
9571017
public static bool CheckDiskSpace(string file, string target, double percent, string diskCaption, out Issue? issue) {
9581018
string message = $"{Math.Round(percent, 1)}% free space on disk {Data.EscapeJsonText(diskCaption)}:";
9591019

Protest/Tools/LiveStats.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ public static async void DeviceStats(HttpListenerContext ctx) {
132132

133133
Lock mutex = new Lock();
134134

135+
if (Issues.CheckWindowsLifecycle(entry, out Issues.Issue? windowsLifecycleIssue) && windowsLifecycleIssue.HasValue) {
136+
WsWriteText(ws, windowsLifecycleIssue.Value.ToLiveStatsJsonBytes(), mutex);
137+
}
138+
135139
string firstAlive = null;
136140
PingReply firstReply = null;
137141
if (pingArray.Length > 0) {
@@ -599,4 +603,4 @@ private static void SnmpQuerySwitch(WebSocket ws, Lock mutex, IPAddress ipAddres
599603
WsWriteText(ws, payload, mutex);
600604
}
601605

602-
}
606+
}

0 commit comments

Comments
 (0)