Failover: Removed newtonsoft. Added retries for send alert email.

This commit is contained in:
Shreyas Zare
2022-12-24 11:41:49 +05:30
parent d83bfc783a
commit 5d04668faa
6 changed files with 189 additions and 316 deletions

View File

@@ -18,11 +18,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using DnsServerCore.ApplicationCommon;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text.Json;
using System.Threading.Tasks;
using TechnitiumLibrary;
using TechnitiumLibrary.Net.Dns;
@@ -64,17 +64,14 @@ namespace Failover
#region private
private void GetAnswers(dynamic jsonAddresses, DnsQuestionRecord question, uint appRecordTtl, string healthCheck, Uri healthCheckUrl, List<DnsResourceRecord> answers)
private void GetAnswers(JsonElement jsonAddresses, DnsQuestionRecord question, uint appRecordTtl, string healthCheck, Uri healthCheckUrl, List<DnsResourceRecord> answers)
{
if (jsonAddresses == null)
return;
switch (question.Type)
{
case DnsResourceRecordType.A:
foreach (dynamic jsonAddress in jsonAddresses)
foreach (JsonElement jsonAddress in jsonAddresses.EnumerateArray())
{
IPAddress address = IPAddress.Parse(jsonAddress.Value);
IPAddress address = IPAddress.Parse(jsonAddress.GetString());
if (address.AddressFamily == AddressFamily.InterNetwork)
{
@@ -94,9 +91,9 @@ namespace Failover
break;
case DnsResourceRecordType.AAAA:
foreach (dynamic jsonAddress in jsonAddresses)
foreach (JsonElement jsonAddress in jsonAddresses.EnumerateArray())
{
IPAddress address = IPAddress.Parse(jsonAddress.Value);
IPAddress address = IPAddress.Parse(jsonAddress.GetString());
if (address.AddressFamily == AddressFamily.InterNetworkV6)
{
@@ -117,14 +114,11 @@ namespace Failover
}
}
private void GetStatusAnswers(dynamic jsonAddresses, FailoverType type, DnsQuestionRecord question, uint appRecordTtl, string healthCheck, Uri healthCheckUrl, List<DnsResourceRecord> answers)
private void GetStatusAnswers(JsonElement jsonAddresses, FailoverType type, DnsQuestionRecord question, uint appRecordTtl, string healthCheck, Uri healthCheckUrl, List<DnsResourceRecord> answers)
{
if (jsonAddresses == null)
return;
foreach (dynamic jsonAddress in jsonAddresses)
foreach (JsonElement jsonAddress in jsonAddresses.EnumerateArray())
{
IPAddress address = IPAddress.Parse(jsonAddress.Value);
IPAddress address = IPAddress.Parse(jsonAddress.GetString());
HealthCheckResponse response = _healthService.QueryStatus(address, healthCheck, healthCheckUrl, false);
string text = "app=failover; addressType=" + type.ToString() + "; address=" + address.ToString() + "; healthCheck=" + healthCheck + (healthCheckUrl is null ? "" : "; healthCheckUrl=" + healthCheckUrl.AbsoluteUri) + "; healthStatus=" + response.Status.ToString() + ";";
@@ -145,7 +139,7 @@ namespace Failover
if (_healthService is null)
_healthService = HealthService.Create(dnsServer);
_healthService.Initialize(JsonConvert.DeserializeObject(config));
_healthService.Initialize(config);
return Task.CompletedTask;
}
@@ -158,17 +152,18 @@ namespace Failover
case DnsResourceRecordType.A:
case DnsResourceRecordType.AAAA:
{
dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData);
using JsonDocument jsonDocument = JsonDocument.Parse(appRecordData);
JsonElement jsonAppRecordData = jsonDocument.RootElement;
string healthCheck = jsonAppRecordData.healthCheck?.Value;
string healthCheck = jsonAppRecordData.GetPropertyValue("healthCheck", null);
Uri healthCheckUrl = null;
if (_healthService.HealthChecks.TryGetValue(healthCheck, out HealthCheck hc) && ((hc.Type == HealthCheckType.Https) || (hc.Type == HealthCheckType.Http)) && (hc.Url is null))
{
//read health check url only for http/https type checks and only when app config does not have an url configured
if ((jsonAppRecordData.healthCheckUrl is not null) && (jsonAppRecordData.healthCheckUrl.Value is not null))
if (jsonAppRecordData.TryGetProperty("healthCheckUrl", out JsonElement jsonHealthCheckUrl) && (jsonHealthCheckUrl.ValueKind != JsonValueKind.Null))
{
healthCheckUrl = new Uri(jsonAppRecordData.healthCheckUrl.Value);
healthCheckUrl = new Uri(jsonHealthCheckUrl.GetString());
}
else
{
@@ -181,19 +176,23 @@ namespace Failover
List<DnsResourceRecord> answers = new List<DnsResourceRecord>();
GetAnswers(jsonAppRecordData.primary, question, appRecordTtl, healthCheck, healthCheckUrl, answers);
if (jsonAppRecordData.TryGetProperty("primary", out JsonElement jsonPrimary))
GetAnswers(jsonPrimary, question, appRecordTtl, healthCheck, healthCheckUrl, answers);
if (answers.Count == 0)
{
GetAnswers(jsonAppRecordData.secondary, question, appRecordTtl, healthCheck, healthCheckUrl, answers);
if (jsonAppRecordData.TryGetProperty("secondary", out JsonElement jsonSecondary))
GetAnswers(jsonSecondary, question, appRecordTtl, healthCheck, healthCheckUrl, answers);
if (answers.Count == 0)
{
if (jsonAppRecordData.serverDown is not null)
if (jsonAppRecordData.TryGetProperty("serverDown", out JsonElement jsonServerDown))
{
if (question.Type == DnsResourceRecordType.A)
{
foreach (dynamic jsonAddress in jsonAppRecordData.serverDown)
foreach (JsonElement jsonAddress in jsonServerDown.EnumerateArray())
{
IPAddress address = IPAddress.Parse(jsonAddress.Value);
IPAddress address = IPAddress.Parse(jsonAddress.GetString());
if (address.AddressFamily == AddressFamily.InterNetwork)
answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.A, question.Class, 30, new DnsARecordData(address)));
@@ -201,9 +200,9 @@ namespace Failover
}
else
{
foreach (dynamic jsonAddress in jsonAppRecordData.serverDown)
foreach (JsonElement jsonAddress in jsonServerDown.EnumerateArray())
{
IPAddress address = IPAddress.Parse(jsonAddress.Value);
IPAddress address = IPAddress.Parse(jsonAddress.GetString());
if (address.AddressFamily == AddressFamily.InterNetworkV6)
answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.AAAA, question.Class, 30, new DnsAAAARecordData(address)));
@@ -224,27 +223,22 @@ namespace Failover
case DnsResourceRecordType.TXT:
{
dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData);
bool allowTxtStatus;
if (jsonAppRecordData.allowTxtStatus == null)
allowTxtStatus = false;
else
allowTxtStatus = jsonAppRecordData.allowTxtStatus.Value;
using JsonDocument jsonDocument = JsonDocument.Parse(appRecordData);
JsonElement jsonAppRecordData = jsonDocument.RootElement;
bool allowTxtStatus = jsonAppRecordData.GetPropertyValue("allowTxtStatus", false);
if (!allowTxtStatus)
return Task.FromResult<DnsDatagram>(null);
string healthCheck = jsonAppRecordData.healthCheck?.Value;
string healthCheck = jsonAppRecordData.GetPropertyValue("healthCheck", null);
Uri healthCheckUrl = null;
if (_healthService.HealthChecks.TryGetValue(healthCheck, out HealthCheck hc) && ((hc.Type == HealthCheckType.Https) || (hc.Type == HealthCheckType.Http)) && (hc.Url is null))
{
//read health check url only for http/https type checks and only when app config does not have an url configured
if ((jsonAppRecordData.healthCheckUrl is not null) && (jsonAppRecordData.healthCheckUrl.Value is not null))
if (jsonAppRecordData.TryGetProperty("healthCheckUrl", out JsonElement jsonHealthCheckUrl) && (jsonHealthCheckUrl.ValueKind != JsonValueKind.Null))
{
healthCheckUrl = new Uri(jsonAppRecordData.healthCheckUrl.Value);
healthCheckUrl = new Uri(jsonHealthCheckUrl.GetString());
}
else
{
@@ -257,8 +251,11 @@ namespace Failover
List<DnsResourceRecord> answers = new List<DnsResourceRecord>();
GetStatusAnswers(jsonAppRecordData.primary, FailoverType.Primary, question, 30, healthCheck, healthCheckUrl, answers);
GetStatusAnswers(jsonAppRecordData.secondary, FailoverType.Secondary, question, 30, healthCheck, healthCheckUrl, answers);
if (jsonAppRecordData.TryGetProperty("primary", out JsonElement jsonPrimary))
GetStatusAnswers(jsonPrimary, FailoverType.Primary, question, 30, healthCheck, healthCheckUrl, answers);
if (jsonAppRecordData.TryGetProperty("secondary", out JsonElement jsonSecondary))
GetStatusAnswers(jsonSecondary, FailoverType.Secondary, question, 30, healthCheck, healthCheckUrl, answers);
return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers));
}

View File

@@ -18,11 +18,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using DnsServerCore.ApplicationCommon;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net;
using System.Text.Json;
using System.Threading.Tasks;
using TechnitiumLibrary;
using TechnitiumLibrary.Net.Dns;
using TechnitiumLibrary.Net.Dns.ResourceRecords;
@@ -119,17 +120,18 @@ namespace Failover
{
DnsQuestionRecord question = request.Question[0];
dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData);
using JsonDocument jsonDocument = JsonDocument.Parse(appRecordData);
JsonElement jsonAppRecordData = jsonDocument.RootElement;
string healthCheck = jsonAppRecordData.healthCheck?.Value;
string healthCheck = jsonAppRecordData.GetPropertyValue("healthCheck", null);
Uri healthCheckUrl = null;
if (_healthService.HealthChecks.TryGetValue(healthCheck, out HealthCheck hc) && ((hc.Type == HealthCheckType.Https) || (hc.Type == HealthCheckType.Http)) && (hc.Url is null))
{
//read health check url only for http/https type checks and only when app config does not have an url configured
if ((jsonAppRecordData.healthCheckUrl is not null) && (jsonAppRecordData.healthCheckUrl.Value is not null))
if (jsonAppRecordData.TryGetProperty("healthCheckUrl", out JsonElement jsonHealthCheckUrl) && (jsonHealthCheckUrl.ValueKind != JsonValueKind.Null))
{
healthCheckUrl = new Uri(jsonAppRecordData.healthCheckUrl.Value);
healthCheckUrl = new Uri(jsonHealthCheckUrl.GetString());
}
else
{
@@ -140,47 +142,50 @@ namespace Failover
}
}
IReadOnlyList<DnsResourceRecord> answers;
IReadOnlyList<DnsResourceRecord> answers = null;
if (question.Type == DnsResourceRecordType.TXT)
{
bool allowTxtStatus;
if (jsonAppRecordData.allowTxtStatus == null)
allowTxtStatus = false;
else
allowTxtStatus = jsonAppRecordData.allowTxtStatus.Value;
bool allowTxtStatus = jsonAppRecordData.GetPropertyValue("allowTxtStatus", false);
if (!allowTxtStatus)
return Task.FromResult<DnsDatagram>(null);
List<DnsResourceRecord> txtAnswers = new List<DnsResourceRecord>();
GetStatusAnswers(jsonAppRecordData.primary.Value, FailoverType.Primary, question, 30, healthCheck, healthCheckUrl, txtAnswers);
if (jsonAppRecordData.TryGetProperty("primary", out JsonElement jsonPrimary))
GetStatusAnswers(jsonPrimary.GetString(), FailoverType.Primary, question, 30, healthCheck, healthCheckUrl, txtAnswers);
foreach (dynamic jsonDomain in jsonAppRecordData.secondary)
GetStatusAnswers(jsonDomain.Value, FailoverType.Secondary, question, 30, healthCheck, healthCheckUrl, txtAnswers);
if (jsonAppRecordData.TryGetProperty("secondary", out JsonElement jsonSecondary))
{
foreach (JsonElement jsonDomain in jsonSecondary.EnumerateArray())
GetStatusAnswers(jsonDomain.GetString(), FailoverType.Secondary, question, 30, healthCheck, healthCheckUrl, txtAnswers);
}
answers = txtAnswers;
}
else
{
answers = GetAnswers(jsonAppRecordData.primary.Value, question, zoneName, appRecordTtl, healthCheck, healthCheckUrl);
if (jsonAppRecordData.TryGetProperty("primary", out JsonElement jsonPrimary))
answers = GetAnswers(jsonPrimary.GetString(), question, zoneName, appRecordTtl, healthCheck, healthCheckUrl);
if (answers is null)
{
foreach (dynamic jsonDomain in jsonAppRecordData.secondary)
if (jsonAppRecordData.TryGetProperty("secondary", out JsonElement jsonSecondary))
{
answers = GetAnswers(jsonDomain.Value, question, zoneName, appRecordTtl, healthCheck, healthCheckUrl);
if (answers is not null)
break;
foreach (JsonElement jsonDomain in jsonSecondary.EnumerateArray())
{
answers = GetAnswers(jsonDomain.GetString(), question, zoneName, appRecordTtl, healthCheck, healthCheckUrl);
if (answers is not null)
break;
}
}
if (answers is null)
{
if ((jsonAppRecordData.serverDown is null) || (jsonAppRecordData.serverDown.Value is null))
if (!jsonAppRecordData.TryGetProperty("serverDown", out JsonElement jsonServerDown) || (jsonServerDown.ValueKind == JsonValueKind.Null))
return Task.FromResult<DnsDatagram>(null);
string serverDown = jsonAppRecordData.serverDown.Value;
string serverDown = jsonServerDown.GetString();
if (question.Name.Equals(zoneName, StringComparison.OrdinalIgnoreCase)) //check for zone apex
answers = new DnsResourceRecord[] { new DnsResourceRecord(question.Name, DnsResourceRecordType.ANAME, DnsClass.IN, 30, new DnsANAMERecordData(serverDown)) }; //use ANAME

View File

@@ -23,8 +23,10 @@ using System.Collections.Generic;
using System.Net;
using System.Net.Mail;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using TechnitiumLibrary;
using TechnitiumLibrary.Net.Dns;
using TechnitiumLibrary.Net.Dns.ResourceRecords;
using TechnitiumLibrary.Net.Mail;
@@ -37,7 +39,7 @@ namespace Failover
readonly HealthService _service;
string _name;
readonly string _name;
bool _enabled;
MailAddress[] _alertTo;
string _smtpServer;
@@ -54,13 +56,15 @@ namespace Failover
#region constructor
public EmailAlert(HealthService service, dynamic jsonEmailAlert)
public EmailAlert(HealthService service, JsonElement jsonEmailAlert)
{
_service = service;
_smtpClient = new SmtpClientEx();
_smtpClient.DnsClient = new DnsClientInternal(_service.DnsServer);
_name = jsonEmailAlert.GetPropertyValue("name", "default");
Reload(jsonEmailAlert);
}
@@ -98,7 +102,24 @@ namespace Failover
{
try
{
await _smtpClient.SendMailAsync(message);
const int MAX_RETRIES = 3;
const int WAIT_INTERVAL = 30000;
for (int retries = 0; retries < MAX_RETRIES; retries++)
{
try
{
await _smtpClient.SendMailAsync(message);
break;
}
catch
{
if (retries == MAX_RETRIES - 1)
throw;
await Task.Delay(WAIT_INTERVAL);
}
}
}
catch (Exception ex)
{
@@ -110,71 +131,33 @@ namespace Failover
#region public
public void Reload(dynamic jsonEmailAlert)
public void Reload(JsonElement jsonEmailAlert)
{
if (jsonEmailAlert.name is null)
_name = "default";
else
_name = jsonEmailAlert.name.Value;
_enabled = jsonEmailAlert.GetPropertyValue("enabled", false);
if (jsonEmailAlert.enabled is null)
_enabled = false;
if (jsonEmailAlert.TryReadArray("alertTo", delegate (string emailAddress) { return new MailAddress(emailAddress); }, out MailAddress[] alertTo))
_alertTo = alertTo;
else
_enabled = jsonEmailAlert.enabled.Value;
if (jsonEmailAlert.alertTo is null)
{
_alertTo = null;
}
else
_smtpServer = jsonEmailAlert.GetPropertyValue("smtpServer", null);
_smtpPort = jsonEmailAlert.GetPropertyValue("smtpPort", 25);
_startTls = jsonEmailAlert.GetPropertyValue("startTls", false);
_smtpOverTls = jsonEmailAlert.GetPropertyValue("smtpOverTls", false);
_username = jsonEmailAlert.GetPropertyValue("username", null);
_password = jsonEmailAlert.GetPropertyValue("password", null);
if (jsonEmailAlert.TryGetProperty("mailFrom", out JsonElement jsonMailFrom))
{
_alertTo = new MailAddress[jsonEmailAlert.alertTo.Count];
for (int i = 0; i < _alertTo.Length; i++)
_alertTo[i] = new MailAddress(jsonEmailAlert.alertTo[i].Value);
if (jsonEmailAlert.TryGetProperty("mailFromName", out JsonElement jsonMailFromName))
_mailFrom = new MailAddress(jsonMailFrom.GetString(), jsonMailFromName.GetString(), Encoding.UTF8);
else
_mailFrom = new MailAddress(jsonMailFrom.GetString());
}
if (jsonEmailAlert.smtpServer is null)
_smtpServer = null;
else
_smtpServer = jsonEmailAlert.smtpServer.Value;
if (jsonEmailAlert.smtpPort is null)
_smtpPort = 25;
else
_smtpPort = Convert.ToInt32(jsonEmailAlert.smtpPort.Value);
if (jsonEmailAlert.startTls is null)
_startTls = false;
else
_startTls = jsonEmailAlert.startTls.Value;
if (jsonEmailAlert.smtpOverTls is null)
_smtpOverTls = false;
else
_smtpOverTls = jsonEmailAlert.smtpOverTls.Value;
if (jsonEmailAlert.username is null)
_username = null;
else
_username = jsonEmailAlert.username.Value;
if (jsonEmailAlert.password is null)
_password = null;
else
_password = jsonEmailAlert.password.Value;
if (jsonEmailAlert.mailFrom is null)
{
_mailFrom = null;
}
else
{
if (jsonEmailAlert.mailFromName is null)
_mailFrom = new MailAddress(jsonEmailAlert.mailFrom.Value);
else
_mailFrom = new MailAddress(jsonEmailAlert.mailFrom.Value, jsonEmailAlert.mailFromName.Value, Encoding.UTF8);
}
//update smtp client settings
_smtpClient.Host = _smtpServer;

View File

@@ -23,6 +23,7 @@ using System.Net;
using System.Net.Http;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text.Json;
using System.Threading.Tasks;
using TechnitiumLibrary;
using TechnitiumLibrary.Net;
@@ -49,7 +50,7 @@ namespace Failover
readonly HealthService _service;
string _name;
readonly string _name;
HealthCheckType _type;
int _interval;
int _retries;
@@ -66,10 +67,12 @@ namespace Failover
#region constructor
public HealthCheck(HealthService service, dynamic jsonHealthCheck)
public HealthCheck(HealthService service, JsonElement jsonHealthCheck)
{
_service = service;
_name = jsonHealthCheck.GetPropertyValue("name", "default");
Reload(jsonHealthCheck);
}
@@ -200,63 +203,25 @@ namespace Failover
#region public
public void Reload(dynamic jsonHealthCheck)
public void Reload(JsonElement jsonHealthCheck)
{
if (jsonHealthCheck.name is null)
_name = "default";
else
_name = jsonHealthCheck.name.Value;
_type = Enum.Parse<HealthCheckType>(jsonHealthCheck.GetPropertyValue("type", "Tcp"), true);
_interval = jsonHealthCheck.GetPropertyValue("interval", 60) * 1000;
_retries = jsonHealthCheck.GetPropertyValue("retries", 3);
_timeout = jsonHealthCheck.GetPropertyValue("timeout", 10) * 1000;
_port = jsonHealthCheck.GetPropertyValue("port", 80);
if (jsonHealthCheck.type == null)
_type = HealthCheckType.Tcp;
if (jsonHealthCheck.TryGetProperty("url", out JsonElement jsonUrl) && (jsonUrl.ValueKind != JsonValueKind.Null))
_url = new Uri(jsonUrl.GetString());
else
_type = Enum.Parse<HealthCheckType>(jsonHealthCheck.type.Value, true);
if (jsonHealthCheck.interval is null)
_interval = 60000;
else
_interval = Convert.ToInt32(jsonHealthCheck.interval.Value) * 1000;
if (jsonHealthCheck.retries is null)
_retries = 3;
else
_retries = Convert.ToInt32(jsonHealthCheck.retries.Value);
if (jsonHealthCheck.timeout is null)
_timeout = 10000;
else
_timeout = Convert.ToInt32(jsonHealthCheck.timeout.Value) * 1000;
if (jsonHealthCheck.port is null)
_port = 80;
else
_port = Convert.ToInt32(jsonHealthCheck.port.Value);
if ((jsonHealthCheck.url is null) || (jsonHealthCheck.url.Value is null))
_url = null;
else
_url = new Uri(jsonHealthCheck.url.Value);
string emailAlertName;
if (jsonHealthCheck.emailAlert is null)
emailAlertName = null;
else
emailAlertName = jsonHealthCheck.emailAlert.Value;
if ((emailAlertName is not null) && _service.EmailAlerts.TryGetValue(emailAlertName, out EmailAlert emailAlert))
if (jsonHealthCheck.TryGetProperty("emailAlert", out JsonElement jsonEmailAlert) && _service.EmailAlerts.TryGetValue(jsonEmailAlert.GetString(), out EmailAlert emailAlert))
_emailAlert = emailAlert;
else
_emailAlert = null;
string webHookName;
if (jsonHealthCheck.webHook is null)
webHookName = null;
else
webHookName = jsonHealthCheck.webHook.Value;
if ((webHookName is not null) && _service.WebHooks.TryGetValue(webHookName, out WebHook webHook))
if (jsonHealthCheck.TryGetProperty("webHook", out JsonElement jsonWebHook) && _service.WebHooks.TryGetValue(jsonWebHook.GetString(), out WebHook webHook))
_webHook = webHook;
else
_webHook = null;

View File

@@ -1,6 +1,6 @@
/*
Technitium DNS Server
Copyright (C) 2021 Shreyas Zare (shreyas@technitium.com)
Copyright (C) 2022 Shreyas Zare (shreyas@technitium.com)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,7 +22,9 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Net;
using System.Text.Json;
using System.Threading;
using TechnitiumLibrary;
using TechnitiumLibrary.Net;
using TechnitiumLibrary.Net.Dns.ResourceRecords;
@@ -178,19 +180,19 @@ namespace Failover
#region public
public void Initialize(dynamic jsonConfig)
public void Initialize(string config)
{
using JsonDocument jsonDocument = JsonDocument.Parse(config);
JsonElement jsonConfig = jsonDocument.RootElement;
//email alerts
{
//add or update email alerts
foreach (dynamic jsonEmailAlert in jsonConfig.emailAlerts)
{
string name;
JsonElement jsonEmailAlerts = jsonConfig.GetProperty("emailAlerts");
if (jsonEmailAlert.name is null)
name = "default";
else
name = jsonEmailAlert.name.Value;
//add or update email alerts
foreach (JsonElement jsonEmailAlert in jsonEmailAlerts.EnumerateArray())
{
string name = jsonEmailAlert.GetPropertyValue("name", "default");
if (_emailAlerts.TryGetValue(name, out EmailAlert existingEmailAlert))
{
@@ -201,7 +203,6 @@ namespace Failover
{
//add
EmailAlert emailAlert = new EmailAlert(this, jsonEmailAlert);
_emailAlerts.TryAdd(emailAlert.Name, emailAlert);
}
}
@@ -211,15 +212,9 @@ namespace Failover
{
bool emailAlertExists = false;
foreach (dynamic jsonEmailAlert in jsonConfig.emailAlerts)
foreach (JsonElement jsonEmailAlert in jsonEmailAlerts.EnumerateArray())
{
string name;
if (jsonEmailAlert.name is null)
name = "default";
else
name = jsonEmailAlert.name.Value;
string name = jsonEmailAlert.GetPropertyValue("name", "default");
if (name == emailAlert.Key)
{
emailAlertExists = true;
@@ -237,15 +232,12 @@ namespace Failover
//web hooks
{
//add or update email alerts
foreach (dynamic jsonWebHook in jsonConfig.webHooks)
{
string name;
JsonElement jsonWebHooks = jsonConfig.GetProperty("webHooks");
if (jsonWebHook.name is null)
name = "default";
else
name = jsonWebHook.name.Value;
//add or update email alerts
foreach (JsonElement jsonWebHook in jsonWebHooks.EnumerateArray())
{
string name = jsonWebHook.GetPropertyValue("name", "default");
if (_webHooks.TryGetValue(name, out WebHook existingWebHook))
{
@@ -256,7 +248,6 @@ namespace Failover
{
//add
WebHook webHook = new WebHook(this, jsonWebHook);
_webHooks.TryAdd(webHook.Name, webHook);
}
}
@@ -266,15 +257,9 @@ namespace Failover
{
bool webHookExists = false;
foreach (dynamic jsonWebHook in jsonConfig.webHooks)
foreach (JsonElement jsonWebHook in jsonWebHooks.EnumerateArray())
{
string name;
if (jsonWebHook.name is null)
name = "default";
else
name = jsonWebHook.name.Value;
string name = jsonWebHook.GetPropertyValue("name", "default");
if (name == webHook.Key)
{
webHookExists = true;
@@ -292,15 +277,12 @@ namespace Failover
//health checks
{
//add or update health checks
foreach (dynamic jsonHealthCheck in jsonConfig.healthChecks)
{
string name;
JsonElement jsonHealthChecks = jsonConfig.GetProperty("healthChecks");
if (jsonHealthCheck.name is null)
name = "default";
else
name = jsonHealthCheck.name.Value;
//add or update health checks
foreach (JsonElement jsonHealthCheck in jsonHealthChecks.EnumerateArray())
{
string name = jsonHealthCheck.GetPropertyValue("name", "default");
if (_healthChecks.TryGetValue(name, out HealthCheck existingHealthCheck))
{
@@ -311,7 +293,6 @@ namespace Failover
{
//add
HealthCheck healthCheck = new HealthCheck(this, jsonHealthCheck);
_healthChecks.TryAdd(healthCheck.Name, healthCheck);
}
}
@@ -321,15 +302,9 @@ namespace Failover
{
bool healthCheckExists = false;
foreach (dynamic jsonHealthCheck in jsonConfig.healthChecks)
foreach (JsonElement jsonHealthCheck in jsonHealthChecks.EnumerateArray())
{
string name;
if (jsonHealthCheck.name is null)
name = "default";
else
name = jsonHealthCheck.name.Value;
string name = jsonHealthCheck.GetPropertyValue("name", "default");
if (name == healthCheck.Key)
{
healthCheckExists = true;
@@ -353,12 +328,12 @@ namespace Failover
//under maintenance networks
_underMaintenance.Clear();
if (jsonConfig.underMaintenance is not null)
if (jsonConfig.TryGetProperty("underMaintenance", out JsonElement jsonUnderMaintenance))
{
foreach (dynamic jsonNetwork in jsonConfig.underMaintenance)
foreach (JsonElement jsonNetwork in jsonUnderMaintenance.EnumerateArray())
{
string network = jsonNetwork.network.Value;
bool enable = jsonNetwork.enable.Value;
string network = jsonNetwork.GetProperty("network").GetString();
bool enable = jsonNetwork.GetProperty("enable").GetBoolean();
_underMaintenance.TryAdd(NetworkAddress.Parse(network), enable);
}

View File

@@ -17,14 +17,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.Json;
using System.Threading.Tasks;
using TechnitiumLibrary;
using TechnitiumLibrary.Net.Dns.ResourceRecords;
using TechnitiumLibrary.Net.Proxy;
@@ -36,7 +37,7 @@ namespace Failover
readonly HealthService _service;
string _name;
readonly string _name;
bool _enabled;
Uri[] _urls;
@@ -47,10 +48,12 @@ namespace Failover
#region constructor
public WebHook(HealthService service, dynamic jsonWebHook)
public WebHook(HealthService service, JsonElement jsonWebHook)
{
_service = service;
_name = jsonWebHook.GetPropertyValue("name", "default");
Reload(jsonWebHook);
}
@@ -176,29 +179,14 @@ namespace Failover
#region public
public void Reload(dynamic jsonWebHook)
public void Reload(JsonElement jsonWebHook)
{
if (jsonWebHook.name is null)
_name = "default";
else
_name = jsonWebHook.name.Value;
_enabled = jsonWebHook.GetPropertyValue("enabled", false);
if (jsonWebHook.enabled is null)
_enabled = false;
if (jsonWebHook.TryReadArray("urls", delegate (string uri) { return new Uri(uri); }, out Uri[] urls))
_urls = urls;
else
_enabled = jsonWebHook.enabled.Value;
if (jsonWebHook.urls is null)
{
_urls = null;
}
else
{
_urls = new Uri[jsonWebHook.urls.Count];
for (int i = 0; i < _urls.Length; i++)
_urls[i] = new Uri(jsonWebHook.urls[i].Value);
}
ConditionalHttpReload();
}
@@ -212,26 +200,17 @@ namespace Failover
{
using (MemoryStream mS = new MemoryStream())
{
JsonTextWriter jsonWriter = new JsonTextWriter(new StreamWriter(mS));
Utf8JsonWriter jsonWriter = new Utf8JsonWriter(mS);
jsonWriter.WriteStartObject();
jsonWriter.WritePropertyName("address");
jsonWriter.WriteValue(address.ToString());
jsonWriter.WritePropertyName("healthCheck");
jsonWriter.WriteValue(healthCheck);
jsonWriter.WritePropertyName("status");
jsonWriter.WriteValue(healthCheckResponse.Status.ToString());
jsonWriter.WriteString("address", address.ToString());
jsonWriter.WriteString("healthCheck", healthCheck);
jsonWriter.WriteString("status", healthCheckResponse.Status.ToString());
if (healthCheckResponse.Status == HealthStatus.Failed)
{
jsonWriter.WritePropertyName("failureReason");
jsonWriter.WriteValue(healthCheckResponse.FailureReason);
}
jsonWriter.WriteString("failureReason", healthCheckResponse.FailureReason);
jsonWriter.WritePropertyName("dateTime");
jsonWriter.WriteValue(healthCheckResponse.DateTime);
jsonWriter.WriteString("dateTime", healthCheckResponse.DateTime);
jsonWriter.WriteEndObject();
jsonWriter.Flush();
@@ -253,23 +232,14 @@ namespace Failover
{
using (MemoryStream mS = new MemoryStream())
{
JsonTextWriter jsonWriter = new JsonTextWriter(new StreamWriter(mS));
Utf8JsonWriter jsonWriter = new Utf8JsonWriter(mS);
jsonWriter.WriteStartObject();
jsonWriter.WritePropertyName("address");
jsonWriter.WriteValue(address.ToString());
jsonWriter.WritePropertyName("healthCheck");
jsonWriter.WriteValue(healthCheck);
jsonWriter.WritePropertyName("status");
jsonWriter.WriteValue("Error");
jsonWriter.WritePropertyName("failureReason");
jsonWriter.WriteValue(ex.ToString());
jsonWriter.WritePropertyName("dateTime");
jsonWriter.WriteValue(DateTime.UtcNow);
jsonWriter.WriteString("address", address.ToString());
jsonWriter.WriteString("healthCheck", healthCheck);
jsonWriter.WriteString("status", "Error");
jsonWriter.WriteString("failureReason", ex.ToString());
jsonWriter.WriteString("dateTime", DateTime.UtcNow);
jsonWriter.WriteEndObject();
jsonWriter.Flush();
@@ -291,29 +261,18 @@ namespace Failover
{
using (MemoryStream mS = new MemoryStream())
{
JsonTextWriter jsonWriter = new JsonTextWriter(new StreamWriter(mS));
Utf8JsonWriter jsonWriter = new Utf8JsonWriter(mS);
jsonWriter.WriteStartObject();
jsonWriter.WritePropertyName("domain");
jsonWriter.WriteValue(domain);
jsonWriter.WritePropertyName("recordType");
jsonWriter.WriteValue(type.ToString());
jsonWriter.WritePropertyName("healthCheck");
jsonWriter.WriteValue(healthCheck);
jsonWriter.WritePropertyName("status");
jsonWriter.WriteValue(healthCheckResponse.Status.ToString());
jsonWriter.WriteString("domain", domain);
jsonWriter.WriteString("recordType", type.ToString());
jsonWriter.WriteString("healthCheck", healthCheck);
jsonWriter.WriteString("status", healthCheckResponse.Status.ToString());
if (healthCheckResponse.Status == HealthStatus.Failed)
{
jsonWriter.WritePropertyName("failureReason");
jsonWriter.WriteValue(healthCheckResponse.FailureReason);
}
jsonWriter.WriteString("failureReason", healthCheckResponse.FailureReason);
jsonWriter.WritePropertyName("dateTime");
jsonWriter.WriteValue(healthCheckResponse.DateTime);
jsonWriter.WriteString("dateTime", healthCheckResponse.DateTime);
jsonWriter.WriteEndObject();
jsonWriter.Flush();
@@ -335,26 +294,15 @@ namespace Failover
{
using (MemoryStream mS = new MemoryStream())
{
JsonTextWriter jsonWriter = new JsonTextWriter(new StreamWriter(mS));
Utf8JsonWriter jsonWriter = new Utf8JsonWriter(mS);
jsonWriter.WriteStartObject();
jsonWriter.WritePropertyName("domain");
jsonWriter.WriteValue(domain);
jsonWriter.WritePropertyName("recordType");
jsonWriter.WriteValue(type.ToString());
jsonWriter.WritePropertyName("healthCheck");
jsonWriter.WriteValue(healthCheck);
jsonWriter.WritePropertyName("status");
jsonWriter.WriteValue("Error");
jsonWriter.WritePropertyName("failureReason");
jsonWriter.WriteValue(ex.ToString());
jsonWriter.WritePropertyName("dateTime");
jsonWriter.WriteValue(DateTime.UtcNow);
jsonWriter.WriteString("domain", domain);
jsonWriter.WriteString("recordType", type.ToString());
jsonWriter.WriteString("healthCheck", healthCheck);
jsonWriter.WriteString("status", "Error");
jsonWriter.WriteString("failureReason", ex.ToString());
jsonWriter.WriteString("dateTime", DateTime.UtcNow);
jsonWriter.WriteEndObject();
jsonWriter.Flush();