file-folder-helper/ADO2025/PI5/Helper-2025-04-04.cs
2025-04-10 09:16:01 -07:00

236 lines
12 KiB
C#

using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Logging;
namespace File_Folder_Helper.ADO2025.PI5;
internal static partial class Helper20250404 {
internal record KafkaProducerSaslOptions(
[property: JsonPropertyName("mechanism")] string Mechanism
);
internal record MonitorList(
[property: JsonPropertyName("id")] int Id,
[property: JsonPropertyName("name")] string Name,
[property: JsonPropertyName("description")] string Description,
[property: JsonPropertyName("pathName")] string PathName,
[property: JsonPropertyName("parent")] int? Parent,
[property: JsonPropertyName("childrenIDs")] IReadOnlyList<int> ChildrenIDs,
[property: JsonPropertyName("url")] string Url,
[property: JsonPropertyName("method")] string Method,
[property: JsonPropertyName("hostname")] object Hostname,
[property: JsonPropertyName("port")] object Port,
[property: JsonPropertyName("maxretries")] int MaxRetries,
[property: JsonPropertyName("weight")] int Weight,
[property: JsonPropertyName("active")] bool Active,
[property: JsonPropertyName("forceInactive")] bool ForceInactive,
[property: JsonPropertyName("type")] string Type,
[property: JsonPropertyName("timeout")] int Timeout,
[property: JsonPropertyName("interval")] int Interval,
[property: JsonPropertyName("retryInterval")] int RetryInterval,
[property: JsonPropertyName("resendInterval")] int ResendInterval,
[property: JsonPropertyName("keyword")] object Keyword,
[property: JsonPropertyName("invertKeyword")] bool InvertKeyword,
[property: JsonPropertyName("expiryNotification")] bool ExpiryNotification,
[property: JsonPropertyName("ignoreTls")] bool IgnoreTls,
[property: JsonPropertyName("upsideDown")] bool UpsideDown,
[property: JsonPropertyName("packetSize")] int PacketSize,
[property: JsonPropertyName("maxredirects")] int MaxRedirects,
[property: JsonPropertyName("accepted_statuscodes")] IReadOnlyList<string> AcceptedStatusCodes,
[property: JsonPropertyName("dns_resolve_type")] string DnsResolveType,
[property: JsonPropertyName("dns_resolve_server")] string DnsResolveServer,
[property: JsonPropertyName("dns_last_result")] object DnsLastResult,
[property: JsonPropertyName("docker_container")] string DockerContainer,
[property: JsonPropertyName("docker_host")] object DockerHost,
[property: JsonPropertyName("proxyId")] object ProxyId,
[property: JsonPropertyName("notificationIDList")] NotificationIDList NotificationIDList,
[property: JsonPropertyName("tags")] IReadOnlyList<object> Tags,
[property: JsonPropertyName("maintenance")] bool Maintenance,
[property: JsonPropertyName("mqttTopic")] string MqttTopic,
[property: JsonPropertyName("mqttSuccessMessage")] string MqttSuccessMessage,
[property: JsonPropertyName("databaseQuery")] object DatabaseQuery,
[property: JsonPropertyName("authMethod")] string AuthMethod,
[property: JsonPropertyName("grpcUrl")] object GrpcUrl,
[property: JsonPropertyName("grpcProtobuf")] object GrpcProtobuf,
[property: JsonPropertyName("grpcMethod")] object GrpcMethod,
[property: JsonPropertyName("grpcServiceName")] object GrpcServiceName,
[property: JsonPropertyName("grpcEnableTls")] bool GrpcEnableTls,
[property: JsonPropertyName("radiusCalledStationId")] object RadiusCalledStationId,
[property: JsonPropertyName("radiusCallingStationId")] object RadiusCallingStationId,
[property: JsonPropertyName("game")] object Game,
[property: JsonPropertyName("gamedigGivenPortOnly")] bool GameDigGivenPortOnly,
[property: JsonPropertyName("httpBodyEncoding")] string HttpBodyEncoding,
[property: JsonPropertyName("jsonPath")] object JsonPath,
[property: JsonPropertyName("expectedValue")] object ExpectedValue,
[property: JsonPropertyName("kafkaProducerTopic")] object KafkaProducerTopic,
[property: JsonPropertyName("kafkaProducerBrokers")] IReadOnlyList<object> KafkaProducerBrokers,
[property: JsonPropertyName("kafkaProducerSsl")] bool KafkaProducerSsl,
[property: JsonPropertyName("kafkaProducerAllowAutoTopicCreation")] bool KafkaProducerAllowAutoTopicCreation,
[property: JsonPropertyName("kafkaProducerMessage")] object KafkaProducerMessage,
[property: JsonPropertyName("screenshot")] object Screenshot,
[property: JsonPropertyName("headers")] object Headers,
[property: JsonPropertyName("body")] object Body,
[property: JsonPropertyName("grpcBody")] object GrpcBody,
[property: JsonPropertyName("grpcMetadata")] object GrpcMetadata,
[property: JsonPropertyName("basic_auth_user")] string BasicAuthUser,
[property: JsonPropertyName("basic_auth_pass")] string BasicAuthPass,
[property: JsonPropertyName("oauth_client_id")] object OauthClientId,
[property: JsonPropertyName("oauth_client_secret")] object OauthClientSecret,
[property: JsonPropertyName("oauth_token_url")] object OauthTokenUrl,
[property: JsonPropertyName("oauth_scopes")] object OauthScopes,
[property: JsonPropertyName("oauth_auth_method")] string OauthAuthMethod,
[property: JsonPropertyName("pushToken")] string PushToken,
[property: JsonPropertyName("databaseConnectionString")] string DatabaseConnectionString,
[property: JsonPropertyName("radiusUsername")] object RadiusUsername,
[property: JsonPropertyName("radiusPassword")] object RadiusPassword,
[property: JsonPropertyName("radiusSecret")] object RadiusSecret,
[property: JsonPropertyName("mqttUsername")] string MqttUsername,
[property: JsonPropertyName("mqttPassword")] string MqttPassword,
[property: JsonPropertyName("authWorkstation")] object AuthWorkstation,
[property: JsonPropertyName("authDomain")] object AuthDomain,
[property: JsonPropertyName("tlsCa")] object TlsCa,
[property: JsonPropertyName("tlsCert")] object TlsCert,
[property: JsonPropertyName("tlsKey")] object TlsKey,
[property: JsonPropertyName("kafkaProducerSaslOptions")] KafkaProducerSaslOptions KafkaProducerSaslOptions,
[property: JsonPropertyName("includeSensitiveData")] bool IncludeSensitiveData
);
internal record NotificationIDList(
[property: JsonPropertyName("4")] bool _4
);
internal record NotificationList(
[property: JsonPropertyName("id")] int Id,
[property: JsonPropertyName("name")] string Name,
[property: JsonPropertyName("active")] bool Active,
[property: JsonPropertyName("userId")] int UserId,
[property: JsonPropertyName("isDefault")] bool IsDefault,
[property: JsonPropertyName("config")] string Config
);
internal record Kuma(
[property: JsonPropertyName("version")] string Version,
[property: JsonPropertyName("notificationList")] IReadOnlyList<NotificationList> NotificationList,
[property: JsonPropertyName("monitorList")] IReadOnlyList<MonitorList> MonitorList
);
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(Kuma))]
private partial class KumaCommonSourceGenerationContext : JsonSerializerContext {
}
internal static void KumaToGatus(ILogger<Worker> logger, List<string> args) {
string url = args[4];
string fileName = args[3];
string searchPattern = args[2];
ParseMetrics(logger, fileName, url);
string sourceDirectory = Path.GetFullPath(args[0]);
string[] files = Directory.GetFiles(sourceDirectory, searchPattern, SearchOption.AllDirectories);
if (files.Length == 0)
logger.LogWarning("<{files}>(s)", files.Length);
else
KumaToGatus(files);
}
private static void ParseMetrics(ILogger<Worker> logger, string fileName, string url) {
FileStream fileStream = new(fileName, FileMode.Truncate);
HttpClient httpClient = new();
Task<Stream> streamTask = httpClient.GetStreamAsync(url);
streamTask.Wait();
Task task = streamTask.Result.CopyToAsync(fileStream);
task.Wait();
ParseMetrics(logger, fileStream);
fileStream.Dispose();
streamTask.Dispose();
httpClient.Dispose();
}
private static void ParseMetrics(ILogger<Worker> _, FileStream __) {
// Task<List<IMetric>> metrics = PrometheusMetricsParser.ParseAsync(fileStream);
// metrics.Wait();
// foreach (IMetric metric in metrics.Result) {
// if (metric is not Gauge gauge)
// continue;
// foreach (GaugeMeasurement gaugeMeasurement in gauge.Measurements) {
// if (string.IsNullOrEmpty(metric.Name))
// continue;
// foreach (KeyValuePair<string, string> keyValuePair in gaugeMeasurement.Labels) {
// logger.LogInformation("name:{name}; timestamp:{timestamp}; value:{value}; key-name:{key-name}; key-value:{key-value}",
// metric.Name,
// gaugeMeasurement.Timestamp,
// gaugeMeasurement.Value,
// keyValuePair.Key,
// keyValuePair.Value);
// }
// }
// }
}
private static void KumaToGatus(string[] files) {
Kuma? kuma;
string json;
string checkFile;
foreach (string file in files) {
checkFile = file.ToLower().Replace('_', '-');
if (checkFile != file)
File.Move(file, checkFile);
json = File.ReadAllText(checkFile);
kuma = JsonSerializer.Deserialize(json, KumaCommonSourceGenerationContext.Default.Kuma);
if (kuma is null)
continue;
WriteGatus(checkFile, kuma);
}
}
private static void WriteGatus(string file, Kuma kuma) {
List<string> results = [
string.Empty,
$"# set GATUS_CONFIG_PATH=./{Path.GetFileName(file)}.yaml",
string.Empty,
"endpoints:"
];
string[] segments;
foreach (MonitorList monitorList in kuma.MonitorList) {
if (monitorList.Type is not "http" and not "postgres")
continue;
results.Add($" - name: {monitorList.Name}");
results.Add($" group: {monitorList.PathName.Split(' ')[0]}");
results.Add($" enabled: {monitorList.Active.ToString().ToLower()}");
results.Add($" interval: {monitorList.Interval}s");
if (monitorList.Type == "http") {
results.Add($" method: {monitorList.Method}");
results.Add($" url: \"{monitorList.Url}\"");
if (monitorList.AuthMethod == "basic") {
results.Add($" # user: \"{monitorList.BasicAuthUser}\"");
results.Add($" # password: \"{monitorList.BasicAuthPass}\"");
}
results.Add(" conditions:");
results.Add(" - \"[STATUS] < 300\"");
if (monitorList.Url.Contains("https"))
results.Add(" - \"[CERTIFICATE_EXPIRATION] > 48h\"");
results.Add($" - \"[RESPONSE_TIME] < {monitorList.Timeout}\"");
} else if (monitorList.Type == "postgres") {
segments = monitorList.DatabaseConnectionString.Split('@');
if (segments.Length != 2)
continue;
results.Add($" # connectionString: \"{monitorList.DatabaseConnectionString}\"");
results.Add($" url: \"tcp://{segments[1].Split('/')[0]}\"");
results.Add(" conditions:");
results.Add(" - \"[CONNECTED] == true\"");
} else
throw new NotImplementedException();
results.Add(" alerts:");
results.Add(" - type: email");
results.Add(" description: \"healthcheck failed\"");
results.Add(" send-on-resolved: true");
results.Add(" - type: gotify");
results.Add(" description: \"healthcheck failed\"");
results.Add(" send-on-resolved: true");
results.Add(string.Empty);
}
File.WriteAllText($"{file}.yaml", string.Join(Environment.NewLine, results));
}
}