diff --git a/src/Plugins/AWSS3/StorageAdminService.cs b/src/Plugins/AWSS3/StorageAdminService.cs index 1ca23e3..e2b78d2 100644 --- a/src/Plugins/AWSS3/StorageAdminService.cs +++ b/src/Plugins/AWSS3/StorageAdminService.cs @@ -15,6 +15,7 @@ */ using System; +using System.Collections.Generic; using System.Threading.Tasks; using Amazon.SecurityToken.Model; using Monai.Deploy.Storage.API; @@ -28,6 +29,10 @@ public class StorageAdminService : IStorageAdminService public Task CreateUserAsync(string username, PolicyRequest[] policyRequests) => throw new NotImplementedException(); + public Task> GetConnectionAsync() => throw new NotImplementedException(); + + public Task HasConnectionAsync() => throw new NotImplementedException(); + public Task RemoveUserAsync(string username) => throw new NotImplementedException(); } } diff --git a/src/Plugins/MinIO/HealthCheckBuilder.cs b/src/Plugins/MinIO/HealthCheckBuilder.cs index 9d01b5a..e996dbe 100644 --- a/src/Plugins/MinIO/HealthCheckBuilder.cs +++ b/src/Plugins/MinIO/HealthCheckBuilder.cs @@ -17,6 +17,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; +using Monai.Deploy.Storage.API; namespace Monai.Deploy.Storage.MinIO { @@ -39,6 +40,19 @@ public override IHealthChecksBuilder Configure( failureStatus, tags, timeout)); + + builder.Add(new HealthCheckRegistration( + $"{ConfigurationKeys.StorageServiceName}-admin", + serviceProvider => + { + var logger = serviceProvider.GetRequiredService>(); + var storageAdminService = serviceProvider.GetRequiredService(); + return new MinIoAdminHealthCheck(storageAdminService, logger); + }, + failureStatus, + tags, + timeout)); + return builder; } } diff --git a/src/Plugins/MinIO/MinIoAdminHealthCheck.cs b/src/Plugins/MinIO/MinIoAdminHealthCheck.cs new file mode 100644 index 0000000..06a566d --- /dev/null +++ b/src/Plugins/MinIO/MinIoAdminHealthCheck.cs @@ -0,0 +1,59 @@ +/* + * Copyright 2022 MONAI Consortium + * + * 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 + * + * http://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 System.Collections.ObjectModel; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Microsoft.Extensions.Logging; +using Monai.Deploy.Storage.API; + +namespace Monai.Deploy.Storage.MinIO +{ + internal class MinIoAdminHealthCheck : IHealthCheck + { + private readonly IStorageAdminService _storageAdminService; + private readonly ILogger _logger; + + public MinIoAdminHealthCheck(IStorageAdminService storageAdminService, ILogger logger) + { + _storageAdminService = storageAdminService ?? throw new ArgumentNullException(nameof(storageAdminService)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } + + public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = new()) + { + try + { + var hasConnection = await _storageAdminService.HasConnectionAsync(); + var connectionResult = await _storageAdminService.GetConnectionAsync(); + var joinedResult = string.Join("\n", connectionResult); + + var roDict = new ReadOnlyDictionary(new Dictionary() { { "MinoAdminResult", joinedResult } }); + + if (hasConnection) + { + return HealthCheckResult.Healthy(data: roDict); + } + + return HealthCheckResult.Unhealthy(data: roDict); + } + catch (Exception exception) + { + _logger.HealthCheckError(exception); + return HealthCheckResult.Unhealthy(exception: exception); + } + } + } +} diff --git a/src/Plugins/MinIO/StorageAdminService.cs b/src/Plugins/MinIO/StorageAdminService.cs index ab5550b..0696d7d 100644 --- a/src/Plugins/MinIO/StorageAdminService.cs +++ b/src/Plugins/MinIO/StorageAdminService.cs @@ -168,10 +168,12 @@ private Process CreateProcess(string cmd) public async Task HasConnectionAsync() { - var result = await ExecuteAsync(_get_connections_cmd).ConfigureAwait(false); + var result = await GetConnectionAsync().ConfigureAwait(false); return result.Any(r => r.Equals(_serviceName)); } + public async Task> GetConnectionAsync() => await ExecuteAsync(_get_connections_cmd).ConfigureAwait(false); + public async Task SetConnectionAsync() { if (await HasConnectionAsync().ConfigureAwait(false)) diff --git a/src/Plugins/MinIO/Tests/MinIoAdminHealthCheckTest.cs b/src/Plugins/MinIO/Tests/MinIoAdminHealthCheckTest.cs new file mode 100644 index 0000000..5ab5efb --- /dev/null +++ b/src/Plugins/MinIO/Tests/MinIoAdminHealthCheckTest.cs @@ -0,0 +1,61 @@ +/* + * Copyright 2022 MONAI Consortium + * + * 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 + * + * http://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 Monai.Deploy.Storage.API; +using Moq; +using Xunit; + +namespace Monai.Deploy.Storage.MinIO.Tests +{ + public class MinIoAdminHealthCheckTest + { + private readonly Mock _storageAdminService; + private readonly Mock> _logger; + + public MinIoAdminHealthCheckTest() + { + _storageAdminService = new Mock(); + _logger = new Mock>(); + } + + [Fact] + public async Task CheckHealthAsync_WhenConnectionThrows_ReturnUnhealthy() + { + _storageAdminService.Setup(p => p.HasConnectionAsync()).Throws(new Exception("error")); + + var healthCheck = new MinIoAdminHealthCheck(_storageAdminService.Object, _logger.Object); + var results = await healthCheck.CheckHealthAsync(new HealthCheckContext()).ConfigureAwait(false); + + Assert.Equal(HealthStatus.Unhealthy, results.Status); + Assert.NotNull(results.Exception); + Assert.Equal("error", results.Exception.Message); + } + + [Fact] + public async Task CheckHealthAsync_WhenConnectionSucceeds_ReturnHealthy() + { + _storageAdminService.Setup(p => p.HasConnectionAsync()).ReturnsAsync(true); + _storageAdminService.Setup(p => p.GetConnectionAsync()).ReturnsAsync(new List() { "strings" }); + var healthCheck = new MinIoAdminHealthCheck(_storageAdminService.Object, _logger.Object); + var results = await healthCheck.CheckHealthAsync(new HealthCheckContext()).ConfigureAwait(false); + + Assert.Equal(HealthStatus.Healthy, results.Status); + Assert.Null(results.Exception); + } + } +} diff --git a/src/Storage/API/IStorageAdminService.cs b/src/Storage/API/IStorageAdminService.cs index b9ab702..a8915df 100644 --- a/src/Storage/API/IStorageAdminService.cs +++ b/src/Storage/API/IStorageAdminService.cs @@ -44,5 +44,17 @@ public interface IStorageAdminService /// /// Username Task RemoveUserAsync(string username); + + /// + /// Gets list of alias connections. + /// + /// + Task> GetConnectionAsync(); + + /// + /// If connection contains configured service name. + /// + /// + Task HasConnectionAsync(); } }