public void Equals_Second_Null_Returns_False() { var options1 = new HealthCheckConfig(); var equals = options1.Equals(null); Assert.False(equals); }
public healthcheck() { var logManager = DependencyInjectionHelper.ResolveService <ILogManager>(); var config = new HealthCheckConfig { MongoDbConnectionString = ConfigurationManager.ConnectionStrings["analytics"].ConnectionString, }; _healthCheckService = new BasicHealthCheckService(logManager, config); }
public healthcheck() { var logManager = DependencyInjectionHelper.ResolveService <ILogManager>(); var nomisApiService = DependencyInjectionHelper.ResolveService <INomisApiService>(); var config = new HealthCheckConfig { MongoDbConnectionString = ConfigurationManager.ConnectionStrings["analytics"].ConnectionString, RedisDbConnectionString = ConfigurationManager.ConnectionStrings["redis.sessions"]?.ConnectionString, IdamHealthCheckUrl = ConfigurationManager.AppSettings["HMPPS.Authentication.HealthCheckEndpoint"].ValueOrEmpty() }; _extendedHealthCheckService = new ExtendedHealthCheckService(logManager, config, nomisApiService); _basicHealthCheckService = new BasicHealthCheckService(logManager, config); }
public static IHealthChecksBuilder ConfigureHealthChecks(this IServiceCollection services, IConfiguration configuration) { _config = configuration.GetSection("HealthCheckConfig").Get <HealthCheckConfig>(); MemoryCheck.Threshold = _config.MemoryCheckConfig.MemoryUsageThresholdMb; var context = services .AddHealthChecks(); if (_config.MemoryCheckConfig.Enabled) { context = context.AddCheck <MemoryCheck>(nameof(MemoryCheck)); } return(context); }
public void Equals_Same_Value_Returns_True() { var options1 = new HealthCheckConfig { Active = new ActiveHealthCheckConfig { Enabled = true, Interval = TimeSpan.FromSeconds(2), Timeout = TimeSpan.FromSeconds(1), Policy = "Any5xxResponse", Path = "/a", }, Passive = new PassiveHealthCheckConfig { Enabled = true, Policy = "Passive", ReactivationPeriod = TimeSpan.FromSeconds(5), } }; var options2 = new HealthCheckConfig { Active = new ActiveHealthCheckConfig { Enabled = true, Interval = TimeSpan.FromSeconds(2), Timeout = TimeSpan.FromSeconds(1), Policy = "any5xxResponse", Path = "/a", }, Passive = new PassiveHealthCheckConfig { Enabled = true, Policy = "passive", ReactivationPeriod = TimeSpan.FromSeconds(5), } }; var equals = options1.Equals(options2); Assert.True(equals); Assert.Equal(options1.GetHashCode(), options2.GetHashCode()); }
public void Equals_Different_Value_Returns_False() { var options1 = new HealthCheckConfig { Active = new ActiveHealthCheckConfig { Enabled = true, Interval = TimeSpan.FromSeconds(2), Timeout = TimeSpan.FromSeconds(1), Policy = "Any5xxResponse", Path = "/a", }, Passive = new PassiveHealthCheckConfig { Enabled = true, Policy = "Passive", ReactivationPeriod = TimeSpan.FromSeconds(5), } }; var options2 = new HealthCheckConfig { Active = new ActiveHealthCheckConfig { Enabled = true, Interval = TimeSpan.FromSeconds(2), Timeout = TimeSpan.FromSeconds(1), Policy = "Different", Path = "/a", }, Passive = new PassiveHealthCheckConfig { Enabled = true, Policy = "Passive", ReactivationPeriod = TimeSpan.FromSeconds(5), } }; var equals = options1.Equals(options2); Assert.False(equals); }
public void GetAvailableDestinations_HealthChecksDisabled_ReturnAll(HealthCheckConfig config) { var cluster = new ClusterConfig() { ClusterId = "cluster1", HealthCheck = config }; var allDestinations = new[] { new DestinationState("d1") { Health = { Active = DestinationHealth.Healthy } }, new DestinationState("d2") { Health = { Active = DestinationHealth.Unhealthy, Passive = DestinationHealth.Healthy } }, new DestinationState("d3") { Health = { Passive = DestinationHealth.Healthy } }, new DestinationState("d4"), new DestinationState("d5") { Health = { Active = DestinationHealth.Healthy, Passive = DestinationHealth.Unhealthy } }, new DestinationState("d6") { Health = { Active = DestinationHealth.Unhealthy, Passive = DestinationHealth.Unhealthy } } }; var policy = new HealthyAndUnknownDestinationsPolicy(); var availableDestinations = policy.GetAvailalableDestinations(cluster, allDestinations); Assert.Equal(6, availableDestinations.Count); Assert.Same(allDestinations[0], availableDestinations[0]); Assert.Same(allDestinations[1], availableDestinations[1]); Assert.Same(allDestinations[2], availableDestinations[2]); Assert.Same(allDestinations[3], availableDestinations[3]); Assert.Same(allDestinations[4], availableDestinations[4]); Assert.Same(allDestinations[5], availableDestinations[5]); }
public async Task PassiveHealthChecksEnabled_MultipleDestinationFailures_ProxyReturnsServiceUnavailable() { var destinationReached = false; var test = new TestEnvironment( context => { destinationReached = true; throw new InvalidOperationException(); }, proxyBuilder => proxyBuilder.Services.AddSingleton <IForwarderHttpClientFactory>(new MockHttpClientFactory((_, _) => throw new IOException())), proxyApp => { }, configTransformer: (c, r) => { c = c with { HealthCheck = new HealthCheckConfig { Passive = new PassiveHealthCheckConfig { Enabled = true } } }; return(c, r); }); await test.Invoke(async uri => { using var client = new HttpClient(); for (var i = 0; i < 42; i++) { using var response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, uri)); Assert.Equal(i < 10 ? HttpStatusCode.BadGateway : HttpStatusCode.ServiceUnavailable, response.StatusCode); } }); Assert.False(destinationReached); }
public ValueTask <ClusterConfig> ConfigureClusterAsync(ClusterConfig cluster, CancellationToken cancel) { // How to use custom metadata to configure clusters if (cluster.Metadata?.TryGetValue("CustomHealth", out var customHealth) ?? false && string.Equals(customHealth, "true", StringComparison.OrdinalIgnoreCase)) { cluster = cluster with { HealthCheck = new HealthCheckConfig { Active = new ActiveHealthCheckConfig { Enabled = true, Policy = HealthCheckConstants.ActivePolicy.ConsecutiveFailures, }, Passive = cluster.HealthCheck?.Passive, } }; } // Or wrap the meatadata in config sugar var config = new ConfigurationBuilder().AddInMemoryCollection(cluster.Metadata).Build(); if (config.GetValue <bool>("CustomHealth")) { cluster = cluster with { HealthCheck = new HealthCheckConfig { Active = new ActiveHealthCheckConfig { Enabled = true, Policy = HealthCheckConstants.ActivePolicy.ConsecutiveFailures, }, Passive = cluster.HealthCheck?.Passive, } }; } return(new ValueTask <ClusterConfig>(cluster)); }
void CopyOrReset(HealthCheckConfig oldConfig, HealthCheckConfig newConfig, UpdateHealthCheckRequest delta) { var hcType = typeof(HealthCheckConfig); var upType = typeof(UpdateHealthCheckRequest); var bFlags = BindingFlags.Public | BindingFlags.Instance; foreach (var hcProp in hcType.GetProperties(bFlags)) { var oldValue = hcProp.GetValue(oldConfig); var newValue = hcProp.GetValue(newConfig); // Cheap way to compare values, even for complex objects var oldValueJson = JsonSerializer.Serialize(oldValue); var newValueJson = JsonSerializer.Serialize(newValue); if (oldValueJson != newValueJson) { var upProp = upType.GetProperty(hcProp.Name, bFlags); if (upProp == null) { _logger.LogWarning($"Detected Health Check config change for property [{hcProp.Name}]" + " but value CANNOT be updated on existing Health Check"); } else { if (newValueJson == null && ResettableHealthCheckElements.Contains(hcProp.Name)) { if (delta.ResetElements == null) { delta.ResetElements = new List <string>(); } delta.ResetElements.Add(hcProp.Name); } else { upProp.SetValue(delta, newValue); } } } } }
public void convert_HealthCheckConfig_to_json() { var hcc = new HealthCheckConfig { AlarmIdentifier = new AlarmIdentifier { Name = "AlarmId", Region = CloudWatchRegion.ApNortheast1, }, ChildHealthChecks = new List <string> { "Child1", "Child2", }, Disabled = true, EnableSNI = true, FailureThreshold = 99, FullyQualifiedDomainName = "FQDN1", HealthThreshold = 88, InsufficientDataHealthStatus = InsufficientDataHealthStatus.LastKnownStatus, Inverted = true, IPAddress = "1.2.3.4", MeasureLatency = true, Port = 7654, Regions = new List <string> { "reg1", "reg2", "reg3", }, RequestInterval = 55, ResourcePath = "ResPath1", SearchString = "Search1", Type = HealthCheckType.CLOUDWATCH_METRIC, }; var json = JsonSerializer.Serialize(hcc, SerOptions); var orig = JsonSerializer.Deserialize <HealthCheckConfig>(json, SerOptions); orig.Should().BeEquivalentTo(hcc); }
public void Equals_Different_Value_Returns_False() { var config1 = new ClusterConfig { ClusterId = "cluster1", Destinations = new Dictionary <string, DestinationConfig>(StringComparer.OrdinalIgnoreCase) { { "destinationA", new DestinationConfig { Address = "https://localhost:10000/destA", Health = "https://localhost:20000/destA", Metadata = new Dictionary <string, string> { { "destA-K1", "destA-V1" }, { "destA-K2", "destA-V2" } } } }, { "destinationB", new DestinationConfig { Address = "https://localhost:10000/destB", Health = "https://localhost:20000/destB", Metadata = new Dictionary <string, string> { { "destB-K1", "destB-V1" }, { "destB-K2", "destB-V2" } } } } }, HealthCheck = new HealthCheckConfig { Passive = new PassiveHealthCheckConfig { Enabled = true, Policy = "FailureRate", ReactivationPeriod = TimeSpan.FromMinutes(5) }, Active = new ActiveHealthCheckConfig { Enabled = true, Interval = TimeSpan.FromSeconds(4), Timeout = TimeSpan.FromSeconds(6), Policy = "Any5xxResponse", Path = "healthCheckPath" } }, LoadBalancingPolicy = LoadBalancingPolicies.Random, SessionAffinity = new SessionAffinityConfig { Enabled = true, FailurePolicy = "Return503Error", Policy = "Cookie", AffinityKeyName = "Key1", Cookie = new SessionAffinityCookieConfig { Domain = "localhost", Expiration = TimeSpan.FromHours(3), HttpOnly = true, IsEssential = true, MaxAge = TimeSpan.FromDays(1), Path = "mypath", SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Strict, SecurePolicy = Microsoft.AspNetCore.Http.CookieSecurePolicy.SameAsRequest } }, HttpClient = new HttpClientConfig { SslProtocols = SslProtocols.Tls11 | SslProtocols.Tls12, MaxConnectionsPerServer = 10, DangerousAcceptAnyServerCertificate = true, ActivityContextHeaders = ActivityContextHeaders.CorrelationContext, }, HttpRequest = new ForwarderRequestConfig { Timeout = TimeSpan.FromSeconds(60), Version = Version.Parse("1.0"), #if NET VersionPolicy = HttpVersionPolicy.RequestVersionExact, #endif }, Metadata = new Dictionary <string, string> { { "cluster1-K1", "cluster1-V1" }, { "cluster1-K2", "cluster1-V2" } } }; Assert.False(config1.Equals(config1 with { ClusterId = "different" })); Assert.False(config1.Equals(config1 with { Destinations = new Dictionary <string, DestinationConfig>() })); Assert.False(config1.Equals(config1 with { HealthCheck = new HealthCheckConfig() })); Assert.False(config1.Equals(config1 with { LoadBalancingPolicy = "different" })); Assert.False(config1.Equals(config1 with { SessionAffinity = new SessionAffinityConfig { Enabled = true, FailurePolicy = "Return503Error", Policy = "Cookie", AffinityKeyName = "Key1", Cookie = new SessionAffinityCookieConfig { Domain = "localhost", Expiration = TimeSpan.FromHours(3), HttpOnly = true, IsEssential = true, MaxAge = TimeSpan.FromDays(1), Path = "newpath", SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Strict, SecurePolicy = Microsoft.AspNetCore.Http.CookieSecurePolicy.SameAsRequest } } })); Assert.False(config1.Equals(config1 with { HttpClient = new HttpClientConfig { SslProtocols = SslProtocols.Tls12, MaxConnectionsPerServer = 10, DangerousAcceptAnyServerCertificate = true, ActivityContextHeaders = ActivityContextHeaders.CorrelationContext, } })); Assert.False(config1.Equals(config1 with { HttpRequest = new ForwarderRequestConfig() { } })); Assert.False(config1.Equals(config1 with { Metadata = null })); }
public IRequest Marshall(CreateHealthCheckRequest createHealthCheckRequest) { IRequest request = new DefaultRequest(createHealthCheckRequest, "AmazonRoute53"); request.HttpMethod = "POST"; string uriResourcePath = "/2012-12-12/healthcheck"; if (uriResourcePath.Contains("?")) { string queryString = uriResourcePath.Substring(uriResourcePath.IndexOf("?") + 1); uriResourcePath = uriResourcePath.Substring(0, uriResourcePath.IndexOf("?")); foreach (string s in queryString.Split('&', ';')) { string[] nameValuePair = s.Split('='); if (nameValuePair.Length == 2 && nameValuePair[1].Length > 0) { request.Parameters.Add(nameValuePair[0], nameValuePair[1]); } else { request.Parameters.Add(nameValuePair[0], null); } } } request.ResourcePath = uriResourcePath; StringWriter stringWriter = new StringWriter(); XmlTextWriter xmlWriter = new XmlTextWriter(stringWriter); xmlWriter.Namespaces = true; xmlWriter.WriteStartElement("CreateHealthCheckRequest", "https://route53.amazonaws.com/doc/2012-12-12/"); if (createHealthCheckRequest.IsSetCallerReference()) { xmlWriter.WriteElementString("CallerReference", "https://route53.amazonaws.com/doc/2012-12-12/", createHealthCheckRequest.CallerReference.ToString()); } if (createHealthCheckRequest != null) { HealthCheckConfig healthCheckConfigHealthCheckConfig = createHealthCheckRequest.HealthCheckConfig; if (healthCheckConfigHealthCheckConfig != null) { xmlWriter.WriteStartElement("HealthCheckConfig", "https://route53.amazonaws.com/doc/2012-12-12/"); if (healthCheckConfigHealthCheckConfig.IsSetIPAddress()) { xmlWriter.WriteElementString("IPAddress", "https://route53.amazonaws.com/doc/2012-12-12/", healthCheckConfigHealthCheckConfig.IPAddress.ToString()); } if (healthCheckConfigHealthCheckConfig.IsSetPort()) { xmlWriter.WriteElementString("Port", "https://route53.amazonaws.com/doc/2012-12-12/", healthCheckConfigHealthCheckConfig.Port.ToString()); } if (healthCheckConfigHealthCheckConfig.IsSetType()) { xmlWriter.WriteElementString("Type", "https://route53.amazonaws.com/doc/2012-12-12/", healthCheckConfigHealthCheckConfig.Type.ToString()); } if (healthCheckConfigHealthCheckConfig.IsSetResourcePath()) { xmlWriter.WriteElementString("ResourcePath", "https://route53.amazonaws.com/doc/2012-12-12/", healthCheckConfigHealthCheckConfig.ResourcePath.ToString()); } if (healthCheckConfigHealthCheckConfig.IsSetFullyQualifiedDomainName()) { xmlWriter.WriteElementString("FullyQualifiedDomainName", "https://route53.amazonaws.com/doc/2012-12-12/", healthCheckConfigHealthCheckConfig.FullyQualifiedDomainName.ToString()); } xmlWriter.WriteEndElement(); } } xmlWriter.WriteEndElement(); try { request.Content = System.Text.Encoding.UTF8.GetBytes(stringWriter.ToString()); request.Headers.Add("Content-Type", "application/xml"); } catch (EncoderFallbackException e) { throw new AmazonServiceException("Unable to marshall request to XML", e); } return(request); }
public BasicHealthCheckService(ILogManager logManager, HealthCheckConfig config) : base(logManager) { _config = config; }
/// Inline form: /// <hc-type> ';' <threshold> ';' <ip-addr> ';' <port> ';' <fqdn> ';' <res-path> ';' <search> Task <HealthCheckConfig> ParseInlineHealthCheck(string specTag) { var specParts = specTag.Split(";", 7); if (specParts.Length < 2) { throw new Exception("invalid INLINE R53 Health Check spec"); } _logger.LogInformation($"Defining R53 Health Check per resolved INLINE spec: {specTag}"); var hcTypeStr = specParts[0]; var hcType = HealthCheckType.FindValue(hcTypeStr); if (hcType == null) { throw new Exception("unknown Health Check type"); } if (!HealthCheckInlineAllowedTypes.Contains(hcType)) { throw new Exception("Health Check type is unsupported for INLINE spec"); } var config = new HealthCheckConfig { Type = hcType, // RequestInterval = 30, // InsufficientDataHealthStatus = InsufficientDataHealthStatus.LastKnownStatus, }; uint numVal; if (specParts.Length > 1 && !string.IsNullOrWhiteSpace(specParts[1])) { if (!uint.TryParse(specParts[1], out numVal)) { throw new Exception("invalid threshold value"); } config.FailureThreshold = (int)numVal; } if (specParts.Length > 2 && !string.IsNullOrWhiteSpace(specParts[2])) { config.IPAddress = specParts[2].Trim(); } if (specParts.Length > 3 && !string.IsNullOrWhiteSpace(specParts[3])) { if (!uint.TryParse(specParts[3], out numVal)) { throw new Exception("invalid port value"); } config.Port = (int)numVal; } if (specParts.Length > 4 && !string.IsNullOrWhiteSpace(specParts[4])) { config.FullyQualifiedDomainName = specParts[4].Trim(); } if (specParts.Length > 5 && !string.IsNullOrWhiteSpace(specParts[5])) { config.ResourcePath = specParts[5]; } if (specParts.Length > 6 && !string.IsNullOrWhiteSpace(specParts[6])) { config.SearchString = specParts[6]; } return(Task.FromResult(config)); }
public async Task PassiveHealthChecksEnabled_IncompleteClientRequests_ProxyHealthIsUnaffected() { var destinationReached = false; var shouldThrow = true; var requestStartedTcs = new TaskCompletionSource <byte>(TaskCreationOptions.RunContinuationsAsynchronously); var proxySendAsync = async(HttpRequestMessage request, CancellationToken ct) => { requestStartedTcs.SetResult(0); if (shouldThrow) { await Task.Delay(-1, ct); throw new OperationCanceledException(ct); } else { return(new HttpResponseMessage((HttpStatusCode)418) { Content = new StringContent("Hello world") }); } }; var test = new TestEnvironment( context => { destinationReached = true; throw new InvalidOperationException(); }, proxyBuilder => proxyBuilder.Services.AddSingleton <IForwarderHttpClientFactory>(new MockHttpClientFactory(proxySendAsync)), proxyApp => { }, configTransformer: (c, r) => { c = c with { HealthCheck = new HealthCheckConfig { Passive = new PassiveHealthCheckConfig { Enabled = true } } }; return(c, r); }); await test.Invoke(async uri => { using var client = new HttpClient(); for (var i = 0; i < 42; i++) { using var cts = new CancellationTokenSource(); _ = requestStartedTcs.Task.ContinueWith(_ => cts.Cancel()); try { await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, uri), cts.Token); Assert.True(false); } catch { } requestStartedTcs = new TaskCompletionSource <byte>(TaskCreationOptions.RunContinuationsAsynchronously); } shouldThrow = false; using var response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, uri)); Assert.Equal(418, (int)response.StatusCode); Assert.Equal("Hello world", await response.Content.ReadAsStringAsync()); }); Assert.False(destinationReached); }
public IRequest Marshall(CreateHealthCheckRequest createHealthCheckRequest) { IRequest request = new DefaultRequest(createHealthCheckRequest, "AmazonRoute53"); request.HttpMethod = "POST"; string uriResourcePath = "/2013-04-01/healthcheck"; if (uriResourcePath.Contains("?")) { int queryIndex = uriResourcePath.IndexOf("?", StringComparison.OrdinalIgnoreCase); string queryString = uriResourcePath.Substring(queryIndex + 1); uriResourcePath = uriResourcePath.Substring(0, queryIndex); foreach (string s in queryString.Split('&', ';')) { string[] nameValuePair = s.Split('='); if (nameValuePair.Length == 2 && nameValuePair[1].Length > 0) { request.Parameters.Add(nameValuePair[0], nameValuePair[1]); } else { request.Parameters.Add(nameValuePair[0], null); } } } request.ResourcePath = uriResourcePath; StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter, new XmlWriterSettings() { Encoding = System.Text.Encoding.UTF8, OmitXmlDeclaration = true })) { xmlWriter.WriteStartElement("CreateHealthCheckRequest", "https://route53.amazonaws.com/doc/2013-04-01/"); if (createHealthCheckRequest.IsSetCallerReference()) { xmlWriter.WriteElementString("CallerReference", "https://route53.amazonaws.com/doc/2013-04-01/", createHealthCheckRequest.CallerReference.ToString(CultureInfo.InvariantCulture)); } if (createHealthCheckRequest != null) { HealthCheckConfig healthCheckConfigHealthCheckConfig = createHealthCheckRequest.HealthCheckConfig; if (healthCheckConfigHealthCheckConfig != null) { xmlWriter.WriteStartElement("HealthCheckConfig", "https://route53.amazonaws.com/doc/2013-04-01/"); if (healthCheckConfigHealthCheckConfig.IsSetIPAddress()) { xmlWriter.WriteElementString("IPAddress", "https://route53.amazonaws.com/doc/2013-04-01/", healthCheckConfigHealthCheckConfig.IPAddress.ToString(CultureInfo.InvariantCulture)); } if (healthCheckConfigHealthCheckConfig.IsSetPort()) { xmlWriter.WriteElementString("Port", "https://route53.amazonaws.com/doc/2013-04-01/", healthCheckConfigHealthCheckConfig.Port.ToString(CultureInfo.InvariantCulture)); } if (healthCheckConfigHealthCheckConfig.IsSetType()) { xmlWriter.WriteElementString("Type", "https://route53.amazonaws.com/doc/2013-04-01/", healthCheckConfigHealthCheckConfig.Type.ToString(CultureInfo.InvariantCulture)); } if (healthCheckConfigHealthCheckConfig.IsSetResourcePath()) { xmlWriter.WriteElementString("ResourcePath", "https://route53.amazonaws.com/doc/2013-04-01/", healthCheckConfigHealthCheckConfig.ResourcePath.ToString(CultureInfo.InvariantCulture)); } if (healthCheckConfigHealthCheckConfig.IsSetFullyQualifiedDomainName()) { xmlWriter.WriteElementString("FullyQualifiedDomainName", "https://route53.amazonaws.com/doc/2013-04-01/", healthCheckConfigHealthCheckConfig.FullyQualifiedDomainName.ToString(CultureInfo.InvariantCulture)); } if (healthCheckConfigHealthCheckConfig.IsSetSearchString()) { xmlWriter.WriteElementString("SearchString", "https://route53.amazonaws.com/doc/2013-04-01/", healthCheckConfigHealthCheckConfig.SearchString.ToString(CultureInfo.InvariantCulture)); } xmlWriter.WriteEndElement(); } } xmlWriter.WriteEndElement(); } try { string content = stringWriter.ToString(); request.Content = System.Text.Encoding.UTF8.GetBytes(content); request.Headers["Content-Type"] = "application/xml"; } catch (EncoderFallbackException e) { throw new AmazonServiceException("Unable to marshall request to XML", e); } return(request); }
public ExtendedHealthCheckService(ILogManager logManager, HealthCheckConfig config, INomisApiService nomisApiService) : base(logManager) { _nomisApiService = nomisApiService; _config = config; }