Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…ore.Diagnostics.HealthChecks into ahryshchanka-feature/479
  • Loading branch information
unaizorrilla committed May 18, 2020
2 parents 40f44ce + 9fb7f06 commit aba91fc
Show file tree
Hide file tree
Showing 13 changed files with 340 additions and 1 deletion.
7 changes: 7 additions & 0 deletions AspNetCore.Diagnostics.HealthChecks.sln
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HealthChecks.SendGrid", "sr
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HealthChecks.Prometheus.Metrics", "src\HealthChecks.Prometheus.Metrics\HealthChecks.Prometheus.Metrics.csproj", "{A292F77F-DAC9-4539-A9A1-E4FFA5FADDFD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HealthChecks.ArangoDb", "src\HealthChecks.ArangoDb\HealthChecks.ArangoDb.csproj", "{E58B606C-EDC4-4238-AE66-C547904946FE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -361,6 +363,10 @@ Global
{945ABBC6-5280-4233-8E61-745B6E6B4D8B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{945ABBC6-5280-4233-8E61-745B6E6B4D8B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{945ABBC6-5280-4233-8E61-745B6E6B4D8B}.Release|Any CPU.Build.0 = Release|Any CPU
{E58B606C-EDC4-4238-AE66-C547904946FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E58B606C-EDC4-4238-AE66-C547904946FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E58B606C-EDC4-4238-AE66-C547904946FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E58B606C-EDC4-4238-AE66-C547904946FE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -421,6 +427,7 @@ Global
{C755B50A-61F6-46D2-B5D0-51AE25CAFB70} = {2A3FD988-2BB8-43CF-B3A2-B70E648259D4}
{A292F77F-DAC9-4539-A9A1-E4FFA5FADDFD} = {2A3FD988-2BB8-43CF-B3A2-B70E648259D4}
{945ABBC6-5280-4233-8E61-745B6E6B4D8B} = {2A3FD988-2BB8-43CF-B3A2-B70E648259D4}
{E58B606C-EDC4-4238-AE66-C547904946FE} = {2A3FD988-2BB8-43CF-B3A2-B70E648259D4}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2B8C62A1-11B6-469F-874C-A02443256568}
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ HealthChecks packages include health checks for:
- Hangfire
- SignalR
- Kubernetes
- ArangoDB

> We support netcoreapp 2.2, 3.0 and 3.1. Please use package versions 2.2.X, 3.0.X and 3.1.X to target different versions.
Expand Down Expand Up @@ -115,6 +116,7 @@ Install-Package AspNetCore.HealthChecks.SignalR
Install-Package AspNetCore.HealthChecks.Kubernetes
Install-Package AspNetCore.HealthChecks.Gcp.CloudFirestore
Install-Package AspNetCore.HealthChecks.SendGrid
Install-Package AspNetCore.HealthChecks.ArangoDb
```

Once the package is installed you can add the HealthCheck using the **AddXXX** IServiceCollection extension methods.
Expand Down
2 changes: 2 additions & 0 deletions build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ if ($suffix -eq "") {
exec { & dotnet pack .\src\HealthChecks.Gcp.CloudFirestore\HealthChecks.Gcp.CloudFirestore.csproj -c Release -o .\artifacts --include-symbols --no-build }
exec { & dotnet pack .\src\HealthChecks.IbmMQ\HealthChecks.IbmMQ.csproj -c Release -o .\artifacts --include-symbols --no-build }
exec { & dotnet pack .\src\HealthChecks.SendGrid\HealthChecks.SendGrid.csproj -c Release -o .\artifacts --include-symbols --no-build }
exec { & dotnet pack .\src\HealthChecks.ArangoDb\HealthChecks.ArangoDb.csproj -c Release -o .\artifacts --include-symbols --no-build }
}

else {
Expand Down Expand Up @@ -161,4 +162,5 @@ else {
exec { & dotnet pack .\src\HealthChecks.Gcp.CloudFirestore\HealthChecks.Gcp.CloudFirestore.csproj -c Release -o .\artifacts --include-symbols --no-build --version-suffix=$suffix }
exec { & dotnet pack .\src\HealthChecks.IbmMQ\HealthChecks.IbmMQ.csproj -c Release -o .\artifacts --include-symbols --no-build --version-suffix=$suffix }
exec { & dotnet pack .\src\HealthChecks.SendGrid\HealthChecks.SendGrid.csproj -c Release -o .\artifacts --include-symbols --no-build --version-suffix=$suffix }
exec { & dotnet pack .\src\HealthChecks.ArangoDb\HealthChecks.ArangoDb.csproj -c Release -o .\artifacts --include-symbols --no-build --version-suffix=$suffix }
}
2 changes: 2 additions & 0 deletions build/dependencies.props
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
<IBMMQDotnetClient>9.1.4</IBMMQDotnetClient>
<PomeloEntityFrameworkCoreMySql>3.1.1</PomeloEntityFrameworkCoreMySql>
<SendGrid>9.14.0</SendGrid>
<ArangoDBNetStandard>1.0.0-alpha02</ArangoDBNetStandard>
</PropertyGroup>

<PropertyGroup Label="CLI Tools Versions">
Expand Down Expand Up @@ -134,5 +135,6 @@
<HealthCheckIbmMQ>3.1.1</HealthCheckIbmMQ>
<HealthChecksUIK8sOperator>3.1.0-beta.8</HealthChecksUIK8sOperator>
<HealthCheckSendGrid>3.1.1-preview1</HealthCheckSendGrid>
<HealthCheckArangoDb>3.1.1-preview1</HealthCheckArangoDb>
</PropertyGroup>
</Project>
7 changes: 6 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,9 @@ services:
- MQ_QMGR_NAME=QM.TEST.01
- MQ_APP_PASSWORD=12345678
- MQ_ENABLE_METRICS=true

arangodb:
image: arangodb/arangodb:latest
ports:
- "8529:8529"
environment:
- ARANGO_ROOT_PASSWORD=strongArangoDbPassword
70 changes: 70 additions & 0 deletions src/HealthChecks.ArangoDb/ArangoDbHealthCheck.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using Microsoft.Extensions.Diagnostics.HealthChecks;
using System;
using System.Threading;
using System.Threading.Tasks;
using ArangoDBNetStandard;
using ArangoDBNetStandard.AuthApi;
using ArangoDBNetStandard.Transport.Http;

namespace HealthChecks.ArangoDb
{
public class ArangoDbHealthCheck
: IHealthCheck
{
private readonly ArangoDbOptions _options;
public ArangoDbHealthCheck(ArangoDbOptions options)
{
_options = options ?? throw new ArgumentNullException(nameof(options));
}
public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
{
try
{
using (var transport = await GetTransport(_options))
using (var adb = new ArangoDBClient(transport))
{
var databases = await adb.Database.GetCurrentDatabaseInfoAsync();
return databases.Error
? new HealthCheckResult(context.Registration.FailureStatus, $"HealthCheck failed with status code: {databases.Code}.")
: HealthCheckResult.Healthy();
}
}
catch (Exception ex)
{
return new HealthCheckResult(context.Registration.FailureStatus, ex.Message, ex);
}
}
private static async Task<HttpApiTransport> GetTransport(ArangoDbOptions options)
{
if (!string.IsNullOrWhiteSpace(options.JwtToken))
{
return HttpApiTransport.UsingJwtAuth(new Uri(options.HostUri), options.Database, options.JwtToken);
}

if (options.IsGenerateJwtTokenBasedOnUserNameAndPassword)
{
if (string.IsNullOrWhiteSpace(options.UserName))
{
throw new ArgumentNullException(nameof(options.UserName));
}
if (string.IsNullOrWhiteSpace(options.Password))
{
throw new ArgumentNullException(nameof(options.Password));
}

var transport = HttpApiTransport.UsingNoAuth(new Uri(options.HostUri), options.Database);
var authClient = new AuthApiClient(transport);
var jwtTokenResponse = await authClient.GetJwtTokenAsync(options.UserName, options.Password);
transport.SetJwtToken(jwtTokenResponse.Jwt);
return transport;
}

if (!string.IsNullOrWhiteSpace(options.UserName) && !string.IsNullOrWhiteSpace(options.Password))
{
return HttpApiTransport.UsingBasicAuth(new Uri(options.HostUri), options.Database, options.UserName, options.Password);
}

return HttpApiTransport.UsingNoAuth(new Uri(options.HostUri), options.Database);
}
}
}
12 changes: 12 additions & 0 deletions src/HealthChecks.ArangoDb/ArangoDbOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace HealthChecks.ArangoDb
{
public class ArangoDbOptions
{
public string HostUri { get; set; }
public string Database { get; set; }
public bool IsGenerateJwtTokenBasedOnUserNameAndPassword { get; set; } = false;
public string UserName { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
public string JwtToken { get; set; } = string.Empty;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using Microsoft.Extensions.Diagnostics.HealthChecks;
using System;
using System.Collections.Generic;
using HealthChecks.ArangoDb;

namespace Microsoft.Extensions.DependencyInjection
{
public static class ArangoDbHealthCheckBuilderExtensions
{
private const string NAME = "arangodb";

/// <summary>
/// Add a health check for ArangoDB.
/// </summary>
/// <param name="builder">The <see cref="IHealthChecksBuilder"/>.</param>
/// <param name="connectionOptionsFactory">A factory to build the ArangoDB connection data to use.</param>
/// <param name="name">The health check name. Optional. If <c>null</c> the type name 'arangodb' will be used for the name.</param>
/// <param name="failureStatus">
/// The <see cref="HealthStatus"/> that should be reported when the health check fails. Optional. If <c>null</c> then
/// the default status of <see cref="HealthStatus.Unhealthy"/> will be reported.
/// </param>
/// <param name="tags">A list of tags that can be used to filter sets of health checks. Optional.</param>
/// <param name="timeout">An optional System.TimeSpan representing the timeout of the check.</param>
/// <returns>The <see cref="IHealthChecksBuilder"/>.</returns>
public static IHealthChecksBuilder AddArangoDb(this IHealthChecksBuilder builder,
Func<IServiceProvider, ArangoDbOptions> connectionOptionsFactory,
string name = default,
HealthStatus? failureStatus = default,
IEnumerable<string> tags = default,
TimeSpan? timeout = default)
{
if (connectionOptionsFactory == null)
{
throw new ArgumentNullException(nameof(connectionOptionsFactory));
}

return builder.Add(new HealthCheckRegistration(
name ?? NAME,
sp => new ArangoDbHealthCheck(connectionOptionsFactory(sp)),
failureStatus,
tags,
timeout));
}
}
}
25 changes: 25 additions & 0 deletions src/HealthChecks.ArangoDb/HealthChecks.ArangoDb.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>$(NetStandardTargetVersion)</TargetFramework>
<PackageLicenseUrl>$(PackageLicenseUrl)</PackageLicenseUrl>
<PackageProjectUrl>$(PackageProjectUrl)</PackageProjectUrl>
<Description>HealthChecks.ArangoDb is the health check package for ArangoDb.</Description>
<PackageTags>HealthCheck;Health;ArangoDb</PackageTags>
<Version>$(HealthCheckArangoDb)</Version>
<RepositoryUrl>$(RepositoryUrl)</RepositoryUrl>
<Company>$(Company)</Company>
<Authors>$(Authors)</Authors>
<LangVersion>latest</LangVersion>
<PackageId>AspNetCore.HealthChecks.ArangoDb</PackageId>
<PublishRepositoryUrl>$(PublishRepositoryUrl)</PublishRepositoryUrl>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder)</AllowedOutputExtensionsInPackageBuildOutputFolder>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ArangoDBNetStandard" Version="$(ArangoDBNetStandard)" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="$(MicrosoftExtensionsDiagnosticsHealthChecks)" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="$(MicrosoftSourceLinkGithub)">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>
1 change: 1 addition & 0 deletions test/FunctionalTests/FunctionalTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\HealthChecks.ArangoDb\HealthChecks.ArangoDb.csproj" />
<ProjectReference Include="..\..\src\HealthChecks.Aws.S3\HealthChecks.Aws.S3.csproj" />
<ProjectReference Include="..\..\src\HealthChecks.Consul\HealthChecks.Consul.csproj" />
<ProjectReference Include="..\..\src\HealthChecks.DynamoDb\HealthChecks.DynamoDb.csproj" />
Expand Down
119 changes: 119 additions & 0 deletions test/FunctionalTests/HealthChecks.ArangoDb/ArangoDbHealthCheckTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
using FluentAssertions;
using FunctionalTests.Base;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using System.Net;
using System.Threading.Tasks;
using HealthChecks.ArangoDb;
using Xunit;

namespace FunctionalTests.HealthChecks.ArangoDb
{
[Collection("execution")]
public class arangodb_healthcheck_should
{
[SkipOnAppVeyor]
public async Task be_healthy_if_arangodb_is_available()
{
var webHostBuilder = new WebHostBuilder()
.UseStartup<DefaultStartup>()
.ConfigureServices(services =>
{
services.AddHealthChecks()
.AddArangoDb(_ => new ArangoDbOptions
{
HostUri = "http://localhost:8529/",
Database = "_system",
UserName = "root",
Password = "strongArangoDbPassword"
}, tags: new string[] { "arangodb" });
})
.Configure(app =>
{
app.UseHealthChecks("/health", new HealthCheckOptions
{
Predicate = r => r.Tags.Contains("arangodb")
});
});

var server = new TestServer(webHostBuilder);

var response = await server.CreateRequest($"/health").GetAsync();

response.StatusCode.Should().Be(HttpStatusCode.OK);
}

[SkipOnAppVeyor]
public async Task be_healthy_if_multiple_arango_are_available()
{
var webHostBuilder = new WebHostBuilder()
.UseStartup<DefaultStartup>()
.ConfigureServices(services =>
{
services.AddHealthChecks()
.AddArangoDb(_ => new ArangoDbOptions
{
HostUri = "http://localhost:8529/",
Database = "_system",
UserName = "root",
Password = "strongArangoDbPassword"
}, tags: new string[] { "arango" }, name: "1")
.AddArangoDb(_ =>new ArangoDbOptions
{
HostUri = "http://localhost:8529/",
Database = "_system",
UserName = "root",
Password = "strongArangoDbPassword",
IsGenerateJwtTokenBasedOnUserNameAndPassword = true
}, tags: new string[] { "arango" }, name: "2");
})
.Configure(app =>
{
app.UseHealthChecks("/health", new HealthCheckOptions
{
Predicate = r => r.Tags.Contains("arango")
});
});

var server = new TestServer(webHostBuilder);

var response = await server.CreateRequest($"/health").GetAsync();

response.StatusCode.Should().Be(HttpStatusCode.OK);
}

[Fact]
public async Task be_unhealthy_if_arango_is_not_available()
{
var webHostBuilder = new WebHostBuilder()
.UseStartup<DefaultStartup>()
.ConfigureServices(services =>
{
services.AddHealthChecks()
.AddArangoDb(_ => new ArangoDbOptions
{
HostUri = "http://localhost:8529/",
Database = "_system",
UserName = "root",
Password = "invalid password"
}, tags: new string[] { "arango" });
})
.Configure(app =>
{
app.UseHealthChecks("/health", new HealthCheckOptions
{
Predicate = r => r.Tags.Contains("arango")
});
});

var server = new TestServer(webHostBuilder);

var response = await server.CreateRequest($"/health").GetAsync();

response.StatusCode.Should().Be(HttpStatusCode.ServiceUnavailable);
}
}
}
Loading

0 comments on commit aba91fc

Please sign in to comment.