* Add support for Microsoft health checks
This commit is contained in:
Hananiel Sarella 2019-04-17 23:09:36 -04:00 коммит произвёл GitHub
Родитель ef8a089078
Коммит 469ce90729
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
24 изменённых файлов: 522 добавлений и 37 удалений

Просмотреть файл

@ -87,9 +87,12 @@ namespace Steeltoe.Management.Endpoint.CloudFoundry
var request = new HttpRequestMessage(HttpMethod.Get, checkPermissionsUri);
AuthenticationHeaderValue auth = new AuthenticationHeaderValue("bearer", token);
request.Headers.Authorization = auth;
SecurityProtocolType prevProtocols = default(SecurityProtocolType);
RemoteCertificateValidationCallback prevValidator = null;
// If certificate validation is disabled, inject a callback to handle properly
HttpClientHelper.ConfigureCertificateValidation(
_options.ValidateCertificates,
out SecurityProtocolType prevProtocols,
out RemoteCertificateValidationCallback prevValidator);
try
{
_logger.LogDebug("GetPermissions({0}, {1})", checkPermissionsUri, token);

Просмотреть файл

@ -17,6 +17,7 @@ using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Steeltoe.Management.Endpoint.Env
{
@ -63,7 +64,7 @@ namespace Steeltoe.Management.Endpoint.Env
{
foreach (var provider in root.Providers)
{
var psd = GetPropertySourceDescriptor(provider, root);
var psd = GetPropertySourceDescriptor(provider);
if (psd != null)
{
results.Add(psd);
@ -74,16 +75,16 @@ namespace Steeltoe.Management.Endpoint.Env
return results;
}
public virtual PropertySourceDescriptor GetPropertySourceDescriptor(IConfigurationProvider provider, IConfigurationRoot root)
public virtual PropertySourceDescriptor GetPropertySourceDescriptor(IConfigurationProvider provider)
{
Dictionary<string, PropertyValueDescriptor> properties = new Dictionary<string, PropertyValueDescriptor>();
var sourceName = GetPropertySourceName(provider);
foreach (var kvp in root.AsEnumerable())
foreach (var key in GetFullKeyNames(provider, null, new HashSet<string>()).OrderBy(p => p))
{
if (provider.TryGet(kvp.Key, out string provValue))
if (provider.TryGet(key, out var value))
{
var sanitized = _sanitizer.Sanitize(kvp);
var sanitized = _sanitizer.Sanitize(new KeyValuePair<string, string>(key, value));
properties.Add(sanitized.Key, new PropertyValueDescriptor(sanitized.Value));
}
}
@ -97,5 +98,26 @@ namespace Steeltoe.Management.Endpoint.Env
? provider.GetType().Name + ": [" + fileProvider.Source.Path + "]"
: provider.GetType().Name;
}
private HashSet<string> GetFullKeyNames(IConfigurationProvider provider, string rootKey, HashSet<string> initialKeys)
{
foreach (var key in provider.GetChildKeys(Enumerable.Empty<string>(), rootKey))
{
string surrogateKey = key;
if (rootKey != null)
{
surrogateKey = rootKey + ":" + key;
}
GetFullKeyNames(provider, surrogateKey, initialKeys);
if (!initialKeys.Any(k => k.StartsWith(surrogateKey)))
{
initialKeys.Add(surrogateKey);
}
}
return initialKeys;
}
}
}

Просмотреть файл

@ -16,6 +16,7 @@ using Steeltoe.Common.HealthChecks;
using System;
using System.Collections.Generic;
using System.Linq;
using HealthCheckResult = Steeltoe.Common.HealthChecks.HealthCheckResult;
namespace Steeltoe.Management.Endpoint.Health
{
@ -46,18 +47,22 @@ namespace Steeltoe.Management.Endpoint.Health
result.Status = h.Status;
}
if (!result.Details.ContainsKey(contributor.Id))
{
result.Details.Add(contributor.Id, h.Details);
}
else
{
// add the contribtor with a -n appended to the id
result.Details.Add(string.Concat(contributor.Id, "-", result.Details.Count(k => k.Key == contributor.Id)), h.Details);
}
string key = GetKey(result, contributor.Id);
result.Details.Add(key, h.Details);
}
return result;
}
protected static string GetKey(HealthCheckResult result, string key)
{
// add the contribtor with a -n appended to the id
if (result.Details.ContainsKey(key))
{
return string.Concat(key, "-", result.Details.Count(k => k.Key == key));
}
return key;
}
}
}

Просмотреть файл

@ -18,6 +18,8 @@ using Steeltoe.Management.Endpoint.Security;
using System;
using System.Collections.Generic;
using System.Linq;
using HealthCheckResult = Steeltoe.Common.HealthChecks.HealthCheckResult;
using HealthStatus = Steeltoe.Common.HealthChecks.HealthStatus;
namespace Steeltoe.Management.Endpoint.Health
{
@ -68,6 +70,7 @@ namespace Steeltoe.Management.Endpoint.Health
protected virtual HealthCheckResult BuildHealth(IHealthAggregator aggregator, IList<IHealthContributor> contributors, ISecurityContext securityContext)
{
var result = _aggregator.Aggregate(contributors);
var showDetails = Options.ShowDetails;
if (showDetails == ShowDetails.Never

Просмотреть файл

@ -34,13 +34,12 @@
<PackageReference Include="Steeltoe.Management.Diagnostics" Version="$(SteeltoeVersion)$(SteeltoeVersionSuffix)" />
<PackageReference Include="Steeltoe.Management.OpenCensusBase" Version="$(SteeltoeVersion)$(SteeltoeVersionSuffix)" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="$(SourceLinkGitHubVersion)" PrivateAssets="All"/>
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="$(ExtensionsVersion)" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="$(HostingExtensionVersion)" />
<PackageReference Include="Newtonsoft.Json" Version="$(JsonNetVersion)" />
<PackageReference Include="Microsoft.DiaSymReader" Version="$(SymReaderVersion)" />
<PackageReference Include="Microsoft.DiaSymReader.PortablePdb" Version="$(SymReaderPortableVersion)" />
<PackageReference Include="OpenCensus" Version="$(OpenCensusVersion)" />

Просмотреть файл

@ -34,7 +34,7 @@ namespace Steeltoe.Management.Endpoint.Health
/// <param name="config">Application configuration (this actuator looks for a settings starting with management:endpoints:health)</param>
public static void AddHealthActuator(this IServiceCollection services, IConfiguration config)
{
services.AddHealthActuator(config, new DefaultHealthAggregator(), GetDefaultHealthContributors());
services.AddHealthActuator(config, new HealthRegistrationsAggregator(), GetDefaultHealthContributors());
}
/// <summary>
@ -45,7 +45,7 @@ namespace Steeltoe.Management.Endpoint.Health
/// <param name="contributors">Contributors to application health</param>
public static void AddHealthActuator(this IServiceCollection services, IConfiguration config, params Type[] contributors)
{
services.AddHealthActuator(config, new DefaultHealthAggregator(), contributors);
services.AddHealthActuator(config, new HealthRegistrationsAggregator(), contributors);
}
/// <summary>
@ -79,8 +79,9 @@ namespace Steeltoe.Management.Endpoint.Health
services.TryAddSingleton<IHealthOptions>(options);
services.RegisterEndpointOptions(options);
AddHealthContributors(services, contributors);
services.TryAddSingleton<IHealthAggregator>(aggregator);
services.TryAddScoped<HealthEndpoint>();
services.TryAddScoped<HealthEndpointCore>();
}
public static void AddHealthContributors(IServiceCollection services, params Type[] contributors)

Просмотреть файл

@ -0,0 +1,93 @@
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Logging;
using Steeltoe.Common.HealthChecks;
using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using HealthCheckResult = Steeltoe.Common.HealthChecks.HealthCheckResult;
using HealthStatus = Steeltoe.Common.HealthChecks.HealthStatus;
using MicrosoftHealthStatus = Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus;
namespace Steeltoe.Management.Endpoint.Health
{
public static class HealthCheckExtensions
{
public static HealthStatus ToHealthStatus(this MicrosoftHealthStatus status)
{
switch (status)
{
case MicrosoftHealthStatus.Healthy: return HealthStatus.UP;
case MicrosoftHealthStatus.Degraded: return HealthStatus.WARNING;
case MicrosoftHealthStatus.Unhealthy: return HealthStatus.DOWN;
default: return HealthStatus.UNKNOWN;
}
}
public static MicrosoftHealthStatus ToHealthStatus(this HealthStatus status)
{
switch (status)
{
case HealthStatus.UP: return MicrosoftHealthStatus.Healthy;
case HealthStatus.WARNING: return MicrosoftHealthStatus.Degraded;
default: return MicrosoftHealthStatus.Unhealthy;
}
}
public static Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult ToHealthCheckResult(this Common.HealthChecks.HealthCheckResult result)
{
return new Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult(result.Status.ToHealthStatus(), result.Description, null, result.Details);
}
public static HealthCheckResult ToHealthCheckResult(this Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult result)
{
return new Common.HealthChecks.HealthCheckResult()
{
Status = result.Status.ToHealthStatus(),
Description = result.Description,
Details = result.Data.ToDictionary(t => t.Key, t => t.Value)
};
}
public static async Task<HealthCheckResult> HealthCheck(this HealthCheckRegistration registration, IServiceProvider provider)
{
var context = new HealthCheckContext { Registration = registration };
var healthCheckResult = new HealthCheckResult();
try
{
var res = await registration.Factory(provider).CheckHealthAsync(context);
healthCheckResult = new HealthCheckResult()
{
Status = res.Status.ToHealthStatus(),
Description = res.Description,
Details = res.Data?.ToDictionary(i => i.Key, i => i.Value)
};
if (res.Exception != null && !string.IsNullOrEmpty(res.Exception.Message))
{
healthCheckResult.Details.Add("error", res.Exception.Message);
}
}
catch (Exception)
{
}
return healthCheckResult;
}
}
}

Просмотреть файл

@ -0,0 +1,93 @@
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Steeltoe.Common.HealthChecks;
using Steeltoe.Management.Endpoint.Security;
using System;
using System.Collections.Generic;
using System.Linq;
using HealthCheckResult = Steeltoe.Common.HealthChecks.HealthCheckResult;
using HealthStatus = Steeltoe.Common.HealthChecks.HealthStatus;
namespace Steeltoe.Management.Endpoint.Health
{
public class HealthEndpointCore : HealthEndpoint
{
private readonly IOptionsMonitor<HealthCheckServiceOptions> _serviceOptions;
private readonly IServiceProvider _provider;
private IHealthAggregator _aggregator;
private IList<IHealthContributor> _contributors;
private ILogger<HealthEndpoint> _logger;
public HealthEndpointCore(IHealthOptions options, IHealthAggregator aggregator, IEnumerable<IHealthContributor> contributors, IOptionsMonitor<HealthCheckServiceOptions> serviceOptions, IServiceProvider provider, ILogger<HealthEndpoint> logger = null)
: base(options, aggregator, contributors, logger)
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
if (contributors == null)
{
throw new ArgumentNullException(nameof(contributors));
}
_aggregator = aggregator ?? throw new ArgumentNullException(nameof(aggregator));
_serviceOptions = serviceOptions ?? throw new ArgumentNullException(nameof(serviceOptions));
_provider = provider ?? throw new ArgumentNullException(nameof(provider));
_contributors = contributors.ToList();
_logger = logger;
}
public new IHealthOptions Options
{
get
{
return options as IHealthOptions;
}
}
public override HealthCheckResult Invoke(ISecurityContext securityContext)
{
return BuildHealth(_aggregator, _contributors, securityContext, _serviceOptions, _provider);
}
protected virtual HealthCheckResult BuildHealth(IHealthAggregator aggregator, IList<IHealthContributor> contributors, ISecurityContext securityContext, IOptionsMonitor<HealthCheckServiceOptions> svcOptions, IServiceProvider provider)
{
var registrationAggregator = _aggregator as IHealthRegistrationsAggregator;
var result = registrationAggregator == null
? _aggregator.Aggregate(contributors)
: registrationAggregator.Aggregate(contributors, svcOptions, provider);
var showDetails = Options.ShowDetails;
if (showDetails == ShowDetails.Never
|| (showDetails == ShowDetails.WhenAuthorized
&& !securityContext.HasClaim(Options.Claim)))
{
result = new HealthCheckResult
{
Status = result.Status,
Description = result.Description
};
}
return result;
}
}
}

Просмотреть файл

@ -42,7 +42,7 @@ namespace Steeltoe.Management.Endpoint.Health
_next = next;
}
public async Task Invoke(HttpContext context, HealthEndpoint endpoint)
public async Task Invoke(HttpContext context, HealthEndpointCore endpoint)
{
_endpoint = endpoint;

Просмотреть файл

@ -0,0 +1,53 @@
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Options;
using Steeltoe.Common.HealthChecks;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using HealthCheckResult = Steeltoe.Common.HealthChecks.HealthCheckResult;
namespace Steeltoe.Management.Endpoint.Health
{
public class HealthRegistrationsAggregator : DefaultHealthAggregator, IHealthRegistrationsAggregator
{
public HealthCheckResult Aggregate(IList<IHealthContributor> contributors, IOptionsMonitor<HealthCheckServiceOptions> healthServiceOptions, IServiceProvider serviceProvider)
{
var result = Aggregate(contributors);
if (healthServiceOptions == null)
{
return result;
}
foreach (var registration in healthServiceOptions.CurrentValue.Registrations)
{
HealthCheckResult h = registration.HealthCheck(serviceProvider).Result;
if (h.Status > result.Status)
{
result.Status = h.Status;
}
var key = GetKey(result, registration.Name);
result.Details.Add(key, h);
}
return result;
}
}
}

Просмотреть файл

@ -0,0 +1,27 @@
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Options;
using Steeltoe.Common.HealthChecks;
using System;
using System.Collections.Generic;
namespace Steeltoe.Management.Endpoint.Health
{
public interface IHealthRegistrationsAggregator : IHealthAggregator
{
Common.HealthChecks.HealthCheckResult Aggregate(IList<IHealthContributor> contributors, IOptionsMonitor<HealthCheckServiceOptions> healthServiceOptions, IServiceProvider serviceProvider);
}
}

Просмотреть файл

@ -26,12 +26,14 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="$(SourceLinkGitHubVersion)" PrivateAssets="All"/>
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="$(SourceLinkGitHubVersion)" PrivateAssets="All" />
<PackageReference Include="Microsoft.AspNetCore.Cors" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.Abstractions" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="2.2.0" />
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="$(SystemDiagnosticsVersion)" />
<PackageReference Include="Steeltoe.Common.Http" Version="$(SteeltoeCommonVersion)" />
<PackageReference Include="StyleCop.Analyzers" Version="$(StyleCopVersion)">

Просмотреть файл

@ -149,7 +149,7 @@ namespace Steeltoe.Management.EndpointOwin.Health
return builder.Use<HealthEndpointOwinMiddleware>(endpoint, mgmtOptions, logger);
}
internal static List<IHealthContributor> GetDefaultHealthContributors()
internal static List<IHealthContributor> GetDefaultHealthContributors()
{
return new List<IHealthContributor>
{

Просмотреть файл

@ -77,25 +77,43 @@ namespace Steeltoe.Management.Endpoint.Env.Test
["management:endpoints:heapdump:enabled"] = "true",
["management:endpoints:heapdump:sensitive"] = "true",
["management:endpoints:cloudfoundry:validatecertificates"] = "true",
["management:endpoints:cloudfoundry:enabled"] = "true"
["management:endpoints:cloudfoundry:enabled"] = "true",
["common"] = "appsettings"
};
var otherAppsettings = new Dictionary<string, string>()
{
["common"] = "otherAppsettings"
};
ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddInMemoryCollection(appsettings);
configurationBuilder.AddInMemoryCollection(otherAppsettings);
var config = configurationBuilder.Build();
var ep = new EnvEndpoint(opts, config, new TestHosting());
var provider = config.Providers.Single();
var desc = ep.GetPropertySourceDescriptor(provider, config);
Assert.Equal("MemoryConfigurationProvider", desc.Name);
var props = desc.Properties;
var appsettingsProvider = config.Providers.ElementAt(0);
var appsettingsDesc = ep.GetPropertySourceDescriptor(appsettingsProvider);
var otherAppsettingsProvider = config.Providers.ElementAt(1);
var otherAppsettingsDesc = ep.GetPropertySourceDescriptor(otherAppsettingsProvider);
Assert.Equal("MemoryConfigurationProvider", appsettingsDesc.Name);
var props = appsettingsDesc.Properties;
Assert.NotNull(props);
Assert.Equal(7, props.Count);
Assert.Equal(8, props.Count);
Assert.Contains("management:endpoints:enabled", props.Keys);
var prop = props["management:endpoints:enabled"];
Assert.NotNull(prop);
Assert.Equal("false", prop.Value);
Assert.Null(prop.Origin);
var otherProps = otherAppsettingsDesc.Properties;
var appsettingsCommonProp = props["common"];
var otherAppsettingCommonProp = otherProps["common"];
Assert.Equal("appsettings", appsettingsCommonProp.Value);
Assert.Equal("otherAppsettings", otherAppsettingCommonProp.Value);
}
[Fact]

Просмотреть файл

@ -62,6 +62,21 @@ namespace Steeltoe.Management.Endpoint.Health.Test
Assert.NotNull(result.Details);
}
[Fact]
public void Aggregate_DuplicateContributor_ReturnsExpectedHealth()
{
List<IHealthContributor> contribs = new List<IHealthContributor>()
{
new UpContributor(),
new UpContributor()
};
var agg = new DefaultHealthAggregator();
var result = agg.Aggregate(contribs);
Assert.NotNull(result);
Assert.Equal(HealthStatus.UP, result.Status);
Assert.Contains("Up-1", result.Details.Keys);
}
[Fact]
public void Aggregate_MultipleContributor_OrderDoesntMatter_ReturnsExpectedHealth()
{

Просмотреть файл

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
using Microsoft.Extensions.Options;
using Steeltoe.Common.HealthChecks;
using Steeltoe.Management.Endpoint.Health.Contributor;
using Steeltoe.Management.Endpoint.Test;

Просмотреть файл

@ -63,7 +63,7 @@ namespace Steeltoe.Management.Endpoint.Env.Test
context.Response.Body.Seek(0, SeekOrigin.Begin);
var reader = new StreamReader(context.Response.Body, Encoding.UTF8);
var json = await reader.ReadLineAsync();
var expected = "{\"activeProfiles\":[\"EnvironmentName\"],\"propertySources\":[{\"properties\":{\"management:endpoints:path\":{\"value\":\"/cloudfoundryapplication\"},\"management:endpoints:enabled\":{\"value\":\"true\"},\"Logging:LogLevel:Steeltoe\":{\"value\":\"Information\"},\"Logging:LogLevel:Pivotal\":{\"value\":\"Information\"},\"Logging:LogLevel:Default\":{\"value\":\"Warning\"},\"Logging:IncludeScopes\":{\"value\":\"false\"}},\"name\":\"MemoryConfigurationProvider\"}]}";
var expected = "{\"activeProfiles\":[\"EnvironmentName\"],\"propertySources\":[{\"properties\":{\"Logging:IncludeScopes\":{\"value\":\"false\"},\"Logging:LogLevel:Default\":{\"value\":\"Warning\"},\"Logging:LogLevel:Pivotal\":{\"value\":\"Information\"},\"Logging:LogLevel:Steeltoe\":{\"value\":\"Information\"},\"management:endpoints:enabled\":{\"value\":\"true\"},\"management:endpoints:path\":{\"value\":\"/cloudfoundryapplication\"}},\"name\":\"MemoryConfigurationProvider\"}]}";
Assert.Equal(expected, json);
}
@ -87,7 +87,7 @@ namespace Steeltoe.Management.Endpoint.Env.Test
var result = await client.GetAsync("http://localhost/cloudfoundryapplication/env");
Assert.Equal(HttpStatusCode.OK, result.StatusCode);
var json = await result.Content.ReadAsStringAsync();
var expected = "{\"activeProfiles\":[\"Production\"],\"propertySources\":[{\"properties\":{\"applicationName\":{\"value\":\"Steeltoe.Management.EndpointCore.Test\"}},\"name\":\"ChainedConfigurationProvider\"},{\"properties\":{\"management:endpoints:path\":{\"value\":\"/cloudfoundryapplication\"},\"management:endpoints:enabled\":{\"value\":\"true\"},\"Logging:LogLevel:Steeltoe\":{\"value\":\"Information\"},\"Logging:LogLevel:Pivotal\":{\"value\":\"Information\"},\"Logging:LogLevel:Default\":{\"value\":\"Warning\"},\"Logging:IncludeScopes\":{\"value\":\"false\"}},\"name\":\"MemoryConfigurationProvider\"}]}";
var expected = "{\"activeProfiles\":[\"Production\"],\"propertySources\":[{\"properties\":{\"applicationName\":{\"value\":\"Steeltoe.Management.EndpointCore.Test\"}},\"name\":\"ChainedConfigurationProvider\"},{\"properties\":{\"Logging:IncludeScopes\":{\"value\":\"false\"},\"Logging:LogLevel:Default\":{\"value\":\"Warning\"},\"Logging:LogLevel:Pivotal\":{\"value\":\"Information\"},\"Logging:LogLevel:Steeltoe\":{\"value\":\"Information\"},\"management:endpoints:enabled\":{\"value\":\"true\"},\"management:endpoints:path\":{\"value\":\"/cloudfoundryapplication\"}},\"name\":\"MemoryConfigurationProvider\"}]}";
Assert.Equal(expected, json);
}

Просмотреть файл

@ -16,11 +16,13 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Steeltoe.Common.HealthChecks;
using Steeltoe.Management.Endpoint.CloudFoundry;
using Steeltoe.Management.Endpoint.Health.Contributor;
using Steeltoe.Management.Endpoint.Hypermedia;
using Steeltoe.Management.Endpoint.Security;
using Steeltoe.Management.Endpoint.Test;
using System;
using System.Collections.Generic;
@ -159,6 +161,31 @@ namespace Steeltoe.Management.Endpoint.Health.Test
}
}
[Fact]
public async void TestDI()
{
var settings = new Dictionary<string, string>(appSettings);
var builder = new WebHostBuilder()
.UseStartup<Startup>()
.ConfigureAppConfiguration((context, config) => config.AddInMemoryCollection(settings));
builder.ConfigureServices(services =>
{
var foo = services.BuildServiceProvider().GetServices<HealthEndpoint>();
var foo2 = services.BuildServiceProvider().GetServices<HealthEndpointCore>();
var foo3 = services.BuildServiceProvider().GetServices<IEndpoint<HealthCheckResult, ISecurityContext>>();
});
using (var server = new TestServer(builder))
{
var client = server.CreateClient();
var result = await client.GetAsync("http://localhost/cloudfoundryapplication/health");
Assert.Equal(HttpStatusCode.OK, result.StatusCode);
var json = await result.Content.ReadAsStringAsync();
Assert.NotNull(json);
}
}
[Fact]
public async void GetStatusCode_ReturnsExpected()
{
@ -217,6 +244,20 @@ namespace Steeltoe.Management.Endpoint.Health.Test
Assert.NotNull(unknownJson);
Assert.Contains("\"status\":\"UNKNOWN\"", unknownJson);
}
builder = new WebHostBuilder()
.UseStartup<Startup>()
.ConfigureAppConfiguration((context, config) => config.AddInMemoryCollection(new Dictionary<string, string>(appSettings) { ["HealthCheckType"] = "defaultAggregator" }));
using (var server = new TestServer(builder))
{
var client = server.CreateClient();
var unknownResult = await client.GetAsync("http://localhost/cloudfoundryapplication/health");
Assert.Equal(HttpStatusCode.OK, unknownResult.StatusCode);
var unknownJson = await unknownResult.Content.ReadAsStringAsync();
Assert.NotNull(unknownJson);
Assert.Contains("\"status\":\"UP\"", unknownJson);
}
}
[Fact]

Просмотреть файл

@ -14,7 +14,10 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Options;
using Steeltoe.Common.HealthChecks;
using Steeltoe.Management.Endpoint.Health.Contributor;
using Steeltoe.Management.Endpoint.Test;
using System;
using System.Collections.Generic;
@ -44,6 +47,36 @@ namespace Steeltoe.Management.Endpoint.Health.Test
Assert.Contains(nameof(aggregator), ex3.Message);
}
[Fact]
public void AddHealthActuator_AddsCorrectServicesWithDefaultHealthAggregator()
{
ServiceCollection services = new ServiceCollection();
var appSettings = new Dictionary<string, string>()
{
["management:endpoints:enabled"] = "false",
["management:endpoints:path"] = "/cloudfoundryapplication",
["management:endpoints:health:enabled"] = "true"
};
ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddInMemoryCollection(appSettings);
var config = configurationBuilder.Build();
services.AddHealthActuator(config, new DefaultHealthAggregator(), typeof(DiskSpaceContributor));
services.Configure<HealthCheckServiceOptions>(config);
var serviceProvider = services.BuildServiceProvider();
var options = serviceProvider.GetService<IHealthOptions>();
Assert.NotNull(options);
var ep = serviceProvider.GetService<HealthEndpointCore>();
Assert.NotNull(ep);
var agg = serviceProvider.GetService<IHealthAggregator>();
Assert.NotNull(agg);
var contribs = serviceProvider.GetServices<IHealthContributor>();
Assert.NotNull(contribs);
var contribsList = contribs.ToList();
Assert.Single(contribsList);
}
[Fact]
public void AddHealthActuator_AddsCorrectServices()
{
@ -60,10 +93,11 @@ namespace Steeltoe.Management.Endpoint.Health.Test
services.AddHealthActuator(config);
services.Configure<HealthCheckServiceOptions>(config);
var serviceProvider = services.BuildServiceProvider();
var options = serviceProvider.GetService<IHealthOptions>();
Assert.NotNull(options);
var ep = serviceProvider.GetService<HealthEndpoint>();
var ep = serviceProvider.GetService<HealthEndpointCore>();
Assert.NotNull(ep);
var agg = serviceProvider.GetService<IHealthAggregator>();
Assert.NotNull(agg);
@ -84,5 +118,10 @@ namespace Steeltoe.Management.Endpoint.Health.Test
var contribsList = contribs.ToList();
Assert.Single(contribsList);
}
private int IOptionsMonitor<T>()
{
throw new NotImplementedException();
}
}
}

Просмотреть файл

@ -0,0 +1,38 @@
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using Microsoft.Extensions.Options;
using Steeltoe.Common.HealthChecks;
using Steeltoe.Management.Endpoint.Health.Contributor;
using Steeltoe.Management.Endpoint.Test;
using System;
using System.Collections.Generic;
using Xunit;
namespace Steeltoe.Management.Endpoint.Health.Test
{
public class HealthEndpointTest : BaseTest
{
[Fact]
public void Constructor_ThrowsOptionsNull()
{
Assert.Throws<ArgumentNullException>(() => new HealthEndpointCore(null, null, null, null, null));
Assert.Throws<ArgumentNullException>(() => new HealthEndpointCore(new HealthEndpointOptions(), null, null, null, null));
Assert.Throws<ArgumentNullException>(() => new HealthEndpointCore(new HealthEndpointOptions(), new HealthRegistrationsAggregator(), null, null, null));
Assert.Throws<ArgumentNullException>(() => new HealthEndpointCore(new HealthEndpointOptions(), new HealthRegistrationsAggregator(), new List<IHealthContributor>(), null, null));
var svcOptions = default(IOptionsMonitor<Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckServiceOptions>);
Assert.Throws<ArgumentNullException>(() => new HealthEndpointCore(new HealthEndpointOptions(), new HealthRegistrationsAggregator(), new List<IHealthContributor>(), svcOptions, null));
}
}
}

Просмотреть файл

@ -15,6 +15,7 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Steeltoe.Management.Endpoint.Health.Contributor;
using System;
using System.Collections.Generic;
@ -42,6 +43,9 @@ namespace Steeltoe.Management.Endpoint.Health.Test
case "unknown":
services.AddHealthActuator(Configuration, new Type[] { typeof(UnknownContributor) });
break;
case "defaultAggregator":
services.AddHealthActuator(Configuration, new DefaultHealthAggregator(), new Type[] { typeof(DiskSpaceContributor) });
break;
default:
services.AddHealthActuator(Configuration);
break;

Просмотреть файл

@ -0,0 +1,28 @@
// Copyright 2017 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using Microsoft.Extensions.Diagnostics.HealthChecks;
using System.Threading;
using System.Threading.Tasks;
namespace Steeltoe.Management.Endpoint.Health.Test
{
internal class TestHealthCheck : IHealthCheck
{
public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default(CancellationToken))
{
throw new System.NotImplementedException();
}
}
}

Просмотреть файл

@ -51,7 +51,7 @@ namespace Steeltoe.Management.EndpointOwin.Env.Test
var json = await middle.InvokeAndReadResponse(context);
// assert
var expected = "{\"activeProfiles\":[\"EnvironmentName\"],\"propertySources\":[{\"properties\":{\"management:endpoints:path\":{\"value\":\"/cloudfoundryapplication\"},\"management:endpoints:enabled\":{\"value\":\"true\"},\"Logging:LogLevel:Steeltoe\":{\"value\":\"Information\"},\"Logging:LogLevel:Pivotal\":{\"value\":\"Information\"},\"Logging:LogLevel:Default\":{\"value\":\"Warning\"},\"Logging:IncludeScopes\":{\"value\":\"false\"}},\"name\":\"MemoryConfigurationProvider\"}]}";
var expected = "{\"activeProfiles\":[\"EnvironmentName\"],\"propertySources\":[{\"properties\":{\"Logging:IncludeScopes\":{\"value\":\"false\"},\"Logging:LogLevel:Default\":{\"value\":\"Warning\"},\"Logging:LogLevel:Pivotal\":{\"value\":\"Information\"},\"Logging:LogLevel:Steeltoe\":{\"value\":\"Information\"},\"management:endpoints:enabled\":{\"value\":\"true\"},\"management:endpoints:path\":{\"value\":\"/cloudfoundryapplication\"}},\"name\":\"MemoryConfigurationProvider\"}]}";
Assert.Equal(expected, json);
}
@ -66,8 +66,8 @@ namespace Steeltoe.Management.EndpointOwin.Env.Test
var json = await result.Content.ReadAsStringAsync();
// REVIEW: ChainedConfigurationProvider with Application Name isn't coming back
// "{\"activeProfiles\":[\"Production\"],\"propertySources\":[{\"properties\":{\"applicationName\":{\"value\":\"Steeltoe.Management.EndpointOwin.Test\"}},\"name\":\"ChainedConfigurationProvider\"},{\"properties\":{\"management:endpoints:sensitive\":{\"value\":\"false\"},\"management:endpoints:path\":{\"value\":\"/cloudfoundryapplication\"},\"management:endpoints:enabled\":{\"value\":\"true\"},\"Logging:LogLevel:Steeltoe\":{\"value\":\"Information\"},\"Logging:LogLevel:Pivotal\":{\"value\":\"Information\"},\"Logging:LogLevel:Default\":{\"value\":\"Warning\"},\"Logging:IncludeScopes\":{\"value\":\"false\"}},\"name\":\"MemoryConfigurationProvider\"}]}";
var expected = "{\"activeProfiles\":[\"Production\"],\"propertySources\":[{\"properties\":{\"management:endpoints:path\":{\"value\":\"/cloudfoundryapplication\"},\"management:endpoints:enabled\":{\"value\":\"true\"},\"Logging:LogLevel:Steeltoe\":{\"value\":\"Information\"},\"Logging:LogLevel:Pivotal\":{\"value\":\"Information\"},\"Logging:LogLevel:Default\":{\"value\":\"Warning\"},\"Logging:IncludeScopes\":{\"value\":\"false\"}},\"name\":\"MemoryConfigurationProvider\"}]}";
// "{\"activeProfiles\":[\"Production\"],\"propertySources\":[{\"properties\":{\"applicationName\":{\"value\":\"Steeltoe.Management.EndpointOwin.Test\"}},\"name\":\"ChainedConfigurationProvider\"},{\"properties\":{\"Logging:IncludeScopes\":{\"value\":\"false\"},\"Logging:LogLevel:Default\":{\"value\":\"Warning\"},\"Logging:LogLevel:Pivotal\":{\"value\":\"Information\"},\"Logging:LogLevel:Steeltoe\":{\"value\":\"Information\"},\"management:endpoints:enabled\":{\"value\":\"true\"},\"management:endpoints:path\":{\"value\":\"/cloudfoundryapplication\"}},\"name\":\"MemoryConfigurationProvider\"}]}";
var expected = "{\"activeProfiles\":[\"Production\"],\"propertySources\":[{\"properties\":{\"Logging:IncludeScopes\":{\"value\":\"false\"},\"Logging:LogLevel:Default\":{\"value\":\"Warning\"},\"Logging:LogLevel:Pivotal\":{\"value\":\"Information\"},\"Logging:LogLevel:Steeltoe\":{\"value\":\"Information\"},\"management:endpoints:enabled\":{\"value\":\"true\"},\"management:endpoints:path\":{\"value\":\"/cloudfoundryapplication\"}},\"name\":\"MemoryConfigurationProvider\"}]}";
Assert.Equal(expected, json);
}
}

Просмотреть файл

@ -2,7 +2,7 @@
"$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
"settings": {
"documentationRules": {
"copyrightText": "Copyright {copyrightYear} the original author or authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.",
"copyrightText": "Copyright {copyrightYear} the original author or authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\nhttps://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.",
"xmlHeader": false,
"variables": {
"copyrightYear": "2017"