feat(core): add systemd unit collector
This commit is contained in:
1 parent
d43173fe42
commit
8fda3d8211
5 files changed
+106
No files matched your search
@@ -0,0 +1,8 @@
|
||||
using Vantage.Core.Models;
|
||||
|
||||
namespace Vantage.Core.Collectors.Systemd;
|
||||
|
||||
public interface ISystemdProvider
|
||||
{
|
||||
Task<IReadOnlyList<SystemdUnit>> GetServicesAsync(HostConfig host, CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Vantage.Core.Models;
|
||||
|
||||
namespace Vantage.Core.Collectors.Systemd;
|
||||
|
||||
public sealed class MockSystemdProvider : ISystemdProvider
|
||||
{
|
||||
private static readonly SystemdUnit[] Units =
|
||||
{
|
||||
new("docker.service", "loaded", "active", "running", "Docker Application Container Engine"),
|
||||
new("nginx.service", "loaded", "active", "running", "A high performance web server"),
|
||||
new("postgresql.service", "loaded", "active", "running", "PostgreSQL RDBMS"),
|
||||
new("ssh.service", "loaded", "active", "running", "OpenBSD Secure Shell server"),
|
||||
new("prometheus.service", "loaded", "active", "running", "Prometheus monitoring"),
|
||||
new("fail2ban.service", "loaded", "active", "running", "Fail2Ban Service"),
|
||||
new("systemd-journald.service", "loaded", "active", "running", "Journal Service"),
|
||||
new("backup.service", "loaded", "failed", "failed", "Nightly backup job"),
|
||||
new("certbot-renew.service", "loaded", "inactive", "dead", "Certbot renewal")
|
||||
};
|
||||
|
||||
public Task<IReadOnlyList<SystemdUnit>> GetServicesAsync(HostConfig host, CancellationToken cancellationToken) =>
|
||||
Task.FromResult<IReadOnlyList<SystemdUnit>>(Units);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Vantage.Core.Models;
|
||||
using Vantage.Core.Ssh;
|
||||
|
||||
namespace Vantage.Core.Collectors.Systemd;
|
||||
|
||||
public sealed class SshSystemdProvider : ISystemdProvider
|
||||
{
|
||||
public const string Command =
|
||||
"systemctl list-units --type=service --all --no-legend --no-pager --plain";
|
||||
|
||||
private readonly ISshCommandRunner runner;
|
||||
|
||||
public SshSystemdProvider(ISshCommandRunner runner)
|
||||
{
|
||||
this.runner = runner;
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyList<SystemdUnit>> GetServicesAsync(HostConfig host, CancellationToken cancellationToken)
|
||||
{
|
||||
var output = await runner.RunAsync(host, Command, cancellationToken).ConfigureAwait(false);
|
||||
return SystemdUnitParser.Parse(output);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace Vantage.Core.Collectors.Systemd;
|
||||
|
||||
public readonly record struct SystemdUnit(
|
||||
string Unit,
|
||||
string Load,
|
||||
string Active,
|
||||
string Sub,
|
||||
string Description)
|
||||
{
|
||||
public bool IsRunning => Active == "active" && Sub == "running";
|
||||
public bool IsFailed => Active == "failed" || Sub == "failed";
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
namespace Vantage.Core.Collectors.Systemd;
|
||||
|
||||
public static class SystemdUnitParser
|
||||
{
|
||||
public static IReadOnlyList<SystemdUnit> Parse(string listUnitsOutput)
|
||||
{
|
||||
var units = new List<SystemdUnit>();
|
||||
|
||||
foreach (var rawLine in listUnitsOutput.Replace("\r\n", "\n").Split('\n'))
|
||||
{
|
||||
var line = StripLeadingMarker(rawLine).TrimEnd();
|
||||
if (line.Length == 0)
|
||||
continue;
|
||||
if (!line.Contains(".service", StringComparison.Ordinal))
|
||||
continue;
|
||||
|
||||
var fields = line.Split(' ', 5, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
if (fields.Length < 4)
|
||||
continue;
|
||||
|
||||
units.Add(new SystemdUnit(
|
||||
Unit: fields[0],
|
||||
Load: fields[1],
|
||||
Active: fields[2],
|
||||
Sub: fields[3],
|
||||
Description: fields.Length >= 5 ? fields[4] : ""));
|
||||
}
|
||||
|
||||
return units;
|
||||
}
|
||||
|
||||
private static string StripLeadingMarker(string line)
|
||||
{
|
||||
var index = 0;
|
||||
while (index < line.Length && !IsUnitStart(line[index]))
|
||||
index++;
|
||||
return line[index..];
|
||||
}
|
||||
|
||||
private static bool IsUnitStart(char c) => char.IsLetterOrDigit(c) && c < 128;
|
||||
}
|
||||
Reference in new issue
Block a user