diff --git a/AspNetCore.Diagnostics.HealthChecks.sln b/AspNetCore.Diagnostics.HealthChecks.sln
index ced291fa9a..aa729bff82 100644
--- a/AspNetCore.Diagnostics.HealthChecks.sln
+++ b/AspNetCore.Diagnostics.HealthChecks.sln
@@ -108,6 +108,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HealthChecks.UI.Branding",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HealthChecks.Azure.IoTHub", "src\HealthChecks.Azure.IoTHub\HealthChecks.Azure.IoTHub.csproj", "{252BB504-B7CB-4581-8CD8-D7398CAA16F5}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HealthChecks.IbmMQ", "src\HealthChecks.IbmMQ\HealthChecks.IbmMQ.csproj", "{E780FB0C-19B8-432B-A749-B9959F2CCA4A}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -282,6 +284,10 @@ Global
{252BB504-B7CB-4581-8CD8-D7398CAA16F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{252BB504-B7CB-4581-8CD8-D7398CAA16F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{252BB504-B7CB-4581-8CD8-D7398CAA16F5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E780FB0C-19B8-432B-A749-B9959F2CCA4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E780FB0C-19B8-432B-A749-B9959F2CCA4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E780FB0C-19B8-432B-A749-B9959F2CCA4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E780FB0C-19B8-432B-A749-B9959F2CCA4A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -329,6 +335,7 @@ Global
{18F9E412-646D-4751-9751-30AA7A0233DF} = {2A3FD988-2BB8-43CF-B3A2-B70E648259D4}
{B526834E-9392-4749-BAB2-7DF579F8F418} = {092533AB-7505-4EDC-8932-D40BF575D0D2}
{252BB504-B7CB-4581-8CD8-D7398CAA16F5} = {2A3FD988-2BB8-43CF-B3A2-B70E648259D4}
+ {E780FB0C-19B8-432B-A749-B9959F2CCA4A} = {2A3FD988-2BB8-43CF-B3A2-B70E648259D4}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2B8C62A1-11B6-469F-874C-A02443256568}
diff --git a/build.ps1 b/build.ps1
index 8fddf81439..6885736a7d 100644
--- a/build.ps1
+++ b/build.ps1
@@ -140,4 +140,5 @@ else {
exec { & dotnet pack .\src\HealthChecks.Kubernetes\HealthChecks.Kubernetes.csproj -c Release -o .\artifacts --include-symbols --no-build --version-suffix=$suffix }
exec { & dotnet pack .\src\HealthChecks.SignalR\HealthChecks.SignalR.csproj -c Release -o .\artifacts --include-symbols --no-build --version-suffix=$suffix }
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 }
}
diff --git a/build/dependencies.props b/build/dependencies.props
index 104dc74a81..1782226ebe 100644
--- a/build/dependencies.props
+++ b/build/dependencies.props
@@ -115,5 +115,6 @@
3.0.0
3.0.0
3.0.0
+ 3.0.0
diff --git a/docker-compose.yml b/docker-compose.yml
index 04ebdca7a2..60b4fa9c8d 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -128,4 +128,15 @@ services:
image: consul:latest
ports:
- "8500:8500"
- - "8600:8600"
\ No newline at end of file
+ - "8600:8600"
+ ibmmq:
+ image: ibmcom/mq
+ ports:
+ - "1414:1414"
+ - "9157:9157"
+ environment:
+ - LICENSE=accept
+ - MQ_QMGR_NAME=QM.TEST.01
+ - MQ_APP_PASSWORD=12345678
+ - MQ_ENABLE_METRICS=true
+
\ No newline at end of file
diff --git a/src/HealthChecks.IbmMQ/DependencyInjection/IbmMQHealthCheckBuilderExtensions.cs b/src/HealthChecks.IbmMQ/DependencyInjection/IbmMQHealthCheckBuilderExtensions.cs
new file mode 100644
index 0000000000..6bc269f2a3
--- /dev/null
+++ b/src/HealthChecks.IbmMQ/DependencyInjection/IbmMQHealthCheckBuilderExtensions.cs
@@ -0,0 +1,81 @@
+using HealthChecks.IbmMQ;
+using IBM.WMQ;
+using Microsoft.Extensions.Diagnostics.HealthChecks;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+
+namespace Microsoft.Extensions.DependencyInjection
+{
+ public static class IbmMQHealthCheckBuilderExtensions
+ {
+ const string NAME = "ibmmq";
+
+ ///
+ /// Add a health check for IbmMQ services using connection properties.
+ ///
+ /// The .
+ /// The name of the queue manager to use.
+ /// The list of properties that will be used for connection.
+ /// The health check name. Optional. If null the type name 'ibmmq' will be used for the name.
+ ///
+ /// The that should be reported when the health check fails. Optional. If null then
+ /// the default status of will be reported.
+ ///
+ /// A list of tags that can be used to filter sets of health checks. Optional.
+ /// An optional System.TimeSpan representing the timeout of the check.
+ /// The .
+ public static IHealthChecksBuilder AddIbmMQ(this IHealthChecksBuilder builder, string queueManager, Hashtable connectionProperties, string name = default, HealthStatus? failureStatus = default, IEnumerable tags = default, TimeSpan? timeout = default)
+ {
+ return builder.Add(new HealthCheckRegistration(
+ name ?? NAME,
+ new IbmMQHealthCheck(queueManager, connectionProperties),
+ failureStatus,
+ tags,
+ timeout));
+ }
+
+ ///
+ /// Add a health check for IbmMQ services using a managed connection.
+ ///
+ /// The .
+ /// The name of the queue manager to use.
+ /// The name of the channel.
+ /// The connection information in the following format HOSTNAME(PORT).
+ /// The user name. Optional.
+ /// The password. Optional
+ /// The health check name. Optional. If null the type name 'ibmmq' will be used for the name.
+ ///
+ /// The that should be reported when the health check fails. Optional. If null then
+ /// the default status of will be reported.
+ ///
+ /// A list of tags that can be used to filter sets of health checks. Optional.
+ /// An optional System.TimeSpan representing the timeout of the check.
+ /// The .
+ public static IHealthChecksBuilder AddIbmMQManagedConnection(this IHealthChecksBuilder builder, string queueManager, string channel, string connectionInfo, string userName = null, string password = null, string name = default, HealthStatus? failureStatus = default, IEnumerable tags = default, TimeSpan? timeout = default)
+ {
+ return builder.Add(new HealthCheckRegistration(
+ name ?? NAME,
+ new IbmMQHealthCheck(queueManager, BuildProperties(channel, connectionInfo, userName, password)),
+ failureStatus,
+ tags,
+ timeout));
+ }
+ private static Hashtable BuildProperties(string channel, string connectionInfo, string userName = null, string password = null)
+ {
+ Hashtable properties = new Hashtable {
+ {MQC.CHANNEL_PROPERTY, channel},
+ {MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED},
+ {MQC.CONNECTION_NAME_PROPERTY, connectionInfo}
+ };
+
+ if (!string.IsNullOrEmpty(userName))
+ properties.Add(MQC.USER_ID_PROPERTY, userName);
+ if (!string.IsNullOrEmpty(password))
+ properties.Add(MQC.PASSWORD_PROPERTY, password);
+
+ return properties;
+ }
+ }
+}
diff --git a/src/HealthChecks.IbmMQ/HealthChecks.IbmMQ.csproj b/src/HealthChecks.IbmMQ/HealthChecks.IbmMQ.csproj
new file mode 100644
index 0000000000..8ea53eebc1
--- /dev/null
+++ b/src/HealthChecks.IbmMQ/HealthChecks.IbmMQ.csproj
@@ -0,0 +1,24 @@
+
+
+
+ $(NetStandardTargetVersion)
+ $(PackageLicenseUrl)
+ $(PackageProjectUrl)
+ HealthCheck;IbmMQ
+ HealthChecks.IbmMQ is the health check package for IbmMQ.
+ $(HealthCheckIbmMQ)
+ $(RepositoryUrl)
+ $(Company)
+ $(Authors)
+ latest
+ AspNetCore.HealthChecks.IbmMQ
+ $(PublishRepositoryUrl)
+ $(AllowedOutputExtensionsInPackageBuildOutputFolder)
+
+
+
+
+
+
+
+
diff --git a/src/HealthChecks.IbmMQ/IbmMQHealthCheck.cs b/src/HealthChecks.IbmMQ/IbmMQHealthCheck.cs
new file mode 100644
index 0000000000..1b99acb9f2
--- /dev/null
+++ b/src/HealthChecks.IbmMQ/IbmMQHealthCheck.cs
@@ -0,0 +1,38 @@
+using IBM.WMQ;
+using Microsoft.Extensions.Diagnostics.HealthChecks;
+using System;
+using System.Collections;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace HealthChecks.IbmMQ
+{
+ public class IbmMQHealthCheck : IHealthCheck
+ {
+ private readonly Hashtable _connectionProperties;
+ private readonly string _queueManager;
+
+ public IbmMQHealthCheck(string queueManager, Hashtable connectionProperties)
+ {
+ _queueManager = queueManager;
+ _connectionProperties = connectionProperties;
+ }
+
+ public Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ using (var connection = new MQQueueManager(_queueManager, _connectionProperties))
+ {
+ return Task.FromResult(
+ HealthCheckResult.Healthy());
+ }
+ }
+ catch (Exception ex)
+ {
+ return Task.FromResult(
+ new HealthCheckResult(context.Registration.FailureStatus, exception: ex));
+ }
+ }
+ }
+}
diff --git a/src/HealthChecks.IbmMQ/README.md b/src/HealthChecks.IbmMQ/README.md
new file mode 100644
index 0000000000..4208f330fb
--- /dev/null
+++ b/src/HealthChecks.IbmMQ/README.md
@@ -0,0 +1,41 @@
+# IbmMQ Health Check
+
+This health check verifies the ability to communicate with a IbmMQ 9.0.+ server
+
+## Example Usage
+
+With all of the following examples, you can additionally add the following parameters:
+
+- `name`: The health check name. Default if not specified is `ibmmq`.
+- `failureStatus`: The `HealthStatus` that should be reported when the health check fails. Default is `HealthStatus.Unhealthy`.
+- `tags`: A list of tags that can be used to filter sets of health checks.
+- `timeout`: A `System.TimeSpan` representing the timeout of the check.
+
+### Basic
+
+Use the extension method where you provide the queue manager name and the connection properties.
+
+```cs
+public void ConfigureServices(IServiceCollection services)
+{
+ Hashtable connectionProperties = new Hashtable {
+ {MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_BINDINGS},
+ };
+ services
+ .AddHealthChecks()
+ .AddIbmMQ("QM.TEST.01", connectionProperties);
+}
+```
+
+### Using Managed Client Connection
+
+For `MQC.TRANSPORT_MQSERIES_MANAGED` connection you can use the following conveniece extension method where you need to specified the channel and the host(port) information. User and password are optional parameters.
+
+```cs
+public void ConfigureServices(IServiceCollection services)
+{
+ services
+ .AddHealthChecks()
+ .AddIbmMQManagedConnection("QM.TEST.01", "DEV.APP.SVRCONN", "localhost(1417)", userName: "app", password: "xxx");
+}
+```
diff --git a/test/FunctionalTests/FunctionalTests.csproj b/test/FunctionalTests/FunctionalTests.csproj
index bea5c07a3f..7c88d6a75d 100644
--- a/test/FunctionalTests/FunctionalTests.csproj
+++ b/test/FunctionalTests/FunctionalTests.csproj
@@ -22,6 +22,7 @@
+
diff --git a/test/FunctionalTests/HealthChecks.IbmMQ/IbmMQHealthChecksTests.cs b/test/FunctionalTests/HealthChecks.IbmMQ/IbmMQHealthChecksTests.cs
new file mode 100644
index 0000000000..98a5f6d2af
--- /dev/null
+++ b/test/FunctionalTests/HealthChecks.IbmMQ/IbmMQHealthChecksTests.cs
@@ -0,0 +1,170 @@
+using FluentAssertions;
+using FunctionalTests.Base;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.TestHost;
+using System;
+using System.Net;
+using System.Threading.Tasks;
+using Xunit;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.AspNetCore.Diagnostics.HealthChecks;
+using System.Collections;
+using IBM.WMQ;
+
+namespace FunctionalTests.HealthChecks.IbmMQ
+{
+
+ [Collection("execution")]
+ public class ibmmq_healthcheck_should
+ {
+ private readonly ExecutionFixture _fixture;
+
+ // Define the name of the queue manager to use (applies to all connections)
+ const string qManager = "QM.TEST.01";
+
+ // Define the name of your host connection (applies to client connections only)
+ const string hostName = "localhost(1414)";
+
+ const string wrongHostName = "localhost(1417)";
+
+ // Define the name of the channel to use (applies to client connections only)
+ const string channel = "DEV.APP.SVRCONN";
+
+ // Define the user name.
+ const string user = "app";
+
+ // Define the password.
+ const string password = "12345678";
+
+ public ibmmq_healthcheck_should(ExecutionFixture fixture)
+ {
+ _fixture = fixture ?? throw new ArgumentNullException(nameof(fixture));
+ }
+
+
+ [SkipOnAppVeyor]
+ public async Task be_healthy_if_ibmmq_is_available()
+ {
+ Hashtable properties = new Hashtable();
+ properties.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED);
+ properties.Add(MQC.CHANNEL_PROPERTY, channel);
+ properties.Add(MQC.CONNECTION_NAME_PROPERTY, hostName);
+ properties.Add(MQC.USER_ID_PROPERTY, user);
+ properties.Add(MQC.PASSWORD_PROPERTY, password);
+
+ var webHostBuilder = new WebHostBuilder()
+ .UseStartup()
+ .ConfigureServices(services =>
+ {
+ services.AddHealthChecks().
+ AddIbmMQ(qManager, properties , tags: new string[] { "ibmmq" });
+ })
+ .Configure(app =>
+ {
+ app.UseHealthChecks("/health", new HealthCheckOptions()
+ {
+ Predicate = r => r.Tags.Contains("ibmmq")
+ });
+ });
+
+ var server = new TestServer(webHostBuilder);
+
+ var response = await server.CreateRequest("/health")
+ .GetAsync();
+
+ response.StatusCode
+ .Should().Be(HttpStatusCode.OK);
+ }
+
+ [SkipOnAppVeyor]
+ public async Task be_unhealthy_if_ibmmq_is_unavailable()
+ {
+ Hashtable properties = new Hashtable();
+ properties.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED);
+ properties.Add(MQC.CHANNEL_PROPERTY, channel);
+ properties.Add(MQC.CONNECTION_NAME_PROPERTY, wrongHostName);
+ properties.Add(MQC.USER_ID_PROPERTY, user);
+ properties.Add(MQC.PASSWORD_PROPERTY, password);
+
+ var webHostBuilder = new WebHostBuilder()
+ .UseStartup()
+ .ConfigureServices(services =>
+ {
+ services.AddHealthChecks()
+ .AddIbmMQ(qManager, properties, tags: new string[] { "ibmmq" });
+ })
+ .Configure(app =>
+ {
+ app.UseHealthChecks("/health", new HealthCheckOptions()
+ {
+ Predicate = r => r.Tags.Contains("ibmmq")
+ });
+ });
+
+ var server = new TestServer(webHostBuilder);
+
+ var response = await server.CreateRequest("/health")
+ .GetAsync();
+
+ response.StatusCode
+ .Should().Be(HttpStatusCode.ServiceUnavailable);
+ }
+
+ [SkipOnAppVeyor]
+ public async Task be_unhealthy_if_ibmmq_managed_is_unavailable()
+ {
+
+ var webHostBuilder = new WebHostBuilder()
+ .UseStartup()
+ .ConfigureServices(services =>
+ {
+ services.AddHealthChecks()
+ .AddIbmMQManagedConnection(qManager, channel, wrongHostName, user, password, tags: new string[] { "ibmmq" });
+ })
+ .Configure(app =>
+ {
+ app.UseHealthChecks("/health", new HealthCheckOptions()
+ {
+ Predicate = r => r.Tags.Contains("ibmmq")
+ });
+ });
+
+ var server = new TestServer(webHostBuilder);
+
+ var response = await server.CreateRequest("/health")
+ .GetAsync();
+
+ response.StatusCode
+ .Should().Be(HttpStatusCode.ServiceUnavailable);
+ }
+
+ [SkipOnAppVeyor]
+ public async Task be_healthy_if_ibmmq_managed_is_available()
+ {
+
+ var webHostBuilder = new WebHostBuilder()
+ .UseStartup()
+ .ConfigureServices(services =>
+ {
+ services.AddHealthChecks().
+ AddIbmMQManagedConnection(qManager, channel, hostName, user, password, tags: new string[] { "ibmmq" });
+ })
+ .Configure(app =>
+ {
+ app.UseHealthChecks("/health", new HealthCheckOptions()
+ {
+ Predicate = r => r.Tags.Contains("ibmmq")
+ });
+ });
+
+ var server = new TestServer(webHostBuilder);
+
+ var response = await server.CreateRequest("/health")
+ .GetAsync();
+
+ response.StatusCode
+ .Should().Be(HttpStatusCode.OK);
+ }
+ }
+}