Microsoft health checks (#60)
* Add support for Microsoft health checks
This commit is contained in:
Родитель
ef8a089078
Коммит
469ce90729
|
@ -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"
|
||||
|
|
Загрузка…
Ссылка в новой задаче