diff --git a/src/AzureIoTHub.Portal.Application/Mappers/AWS/AWSDeviceThingProfile.cs b/src/AzureIoTHub.Portal.Application/Mappers/AWS/AWSDeviceThingProfile.cs index eac1e2186..f44127b6b 100644 --- a/src/AzureIoTHub.Portal.Application/Mappers/AWS/AWSDeviceThingProfile.cs +++ b/src/AzureIoTHub.Portal.Application/Mappers/AWS/AWSDeviceThingProfile.cs @@ -57,6 +57,16 @@ public AWSDeviceThingProfile() Name = att.Key, Value = att.Value }))); + + _ = CreateMap() + .ForMember(dest => dest.ThingName, opts => opts.MapFrom(src => src.DeviceName)) + .ForPath(dest => dest.AttributePayload.Attributes, opts => opts.MapFrom(src => src.Tags)) + .ReverseMap(); + + _ = CreateMap() + .ForMember(dest => dest.ThingName, opts => opts.MapFrom(src => src.DeviceName)) + .ForPath(dest => dest.AttributePayload.Attributes, opts => opts.MapFrom(src => src.Tags)) + .ReverseMap(); } private static MemoryStream EmptyPayload() diff --git a/src/AzureIoTHub.Portal.Application/Mappers/EdgeDeviceProfile.cs b/src/AzureIoTHub.Portal.Application/Mappers/EdgeDeviceProfile.cs index 329ff82ef..b1a29c421 100644 --- a/src/AzureIoTHub.Portal.Application/Mappers/EdgeDeviceProfile.cs +++ b/src/AzureIoTHub.Portal.Application/Mappers/EdgeDeviceProfile.cs @@ -18,6 +18,8 @@ public class EdgeDeviceProfile : Profile { public EdgeDeviceProfile() { + _ = CreateMap(); + _ = CreateMap() .ForMember(dest => dest.Id, opts => opts.MapFrom(src => src.DeviceId)) .ForMember(dest => dest.Name, opts => opts.MapFrom(src => src.Tags["deviceName"])) diff --git a/src/AzureIoTHub.Portal.Infrastructure/Factories/ITableClientFactory.cs b/src/AzureIoTHub.Portal.Infrastructure/Factories/ITableClientFactory.cs deleted file mode 100644 index 21343593b..000000000 --- a/src/AzureIoTHub.Portal.Infrastructure/Factories/ITableClientFactory.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) CGI France. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace AzureIoTHub.Portal.Infrastructure.Factories -{ - using Azure.Data.Tables; - - public interface ITableClientFactory - { - TableClient GetDeviceCommands(); - - TableClient GetDeviceTemplates(); - - TableClient GetEdgeDeviceTemplates(); - - TableClient GetDeviceTemplateProperties(); - - TableClient GetDeviceTagSettings(); - - TableClient GetTemplatesHealthCheck(); - - TableClient GetEdgeModuleCommands(); - } -} diff --git a/src/AzureIoTHub.Portal.Infrastructure/Factories/TableClientFactory.cs b/src/AzureIoTHub.Portal.Infrastructure/Factories/TableClientFactory.cs deleted file mode 100644 index 39d9e87dc..000000000 --- a/src/AzureIoTHub.Portal.Infrastructure/Factories/TableClientFactory.cs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) CGI France. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace AzureIoTHub.Portal.Infrastructure.Factories -{ - using Azure.Data.Tables; - - public class TableClientFactory : ITableClientFactory - { - private readonly string connectionString; - - internal const string DeviceCommandTableName = "DeviceCommands"; - internal const string DeviceTemplateTableName = "DeviceTemplates"; - internal const string EdgeDeviceTemplateTableName = "EdgeDeviceTemplates"; - internal const string DeviceTagSettingTableName = "DeviceTagSettings"; - internal const string DeviceTemplatePropertiesTableName = "DeviceTemplateProperties"; - internal const string EdgeModuleCommandsTableName = "EdgeModuleCommands"; - - public TableClientFactory(string connectionString) - { - this.connectionString = connectionString; - } - - public TableClient GetDeviceCommands() - { - return CreateClient(DeviceCommandTableName); - } - - public TableClient GetDeviceTemplates() - { - return CreateClient(DeviceTemplateTableName); - } - - public TableClient GetEdgeDeviceTemplates() - { - return CreateClient(EdgeDeviceTemplateTableName); - } - - public TableClient GetDeviceTagSettings() - { - return CreateClient(DeviceTagSettingTableName); - } - - private TableClient CreateClient(string tableName) - { - var tableClient = new TableClient(this.connectionString, tableName); - _ = tableClient.CreateIfNotExists(); - - return tableClient; - } - - public TableClient GetDeviceTemplateProperties() - { - return CreateClient(DeviceTemplatePropertiesTableName); - } - - public TableClient GetTemplatesHealthCheck() - { - return CreateClient("tableHealthCheck"); - } - - public TableClient GetEdgeModuleCommands() - { - return CreateClient(EdgeModuleCommandsTableName); - } - } -} diff --git a/src/AzureIoTHub.Portal.Infrastructure/Seeds/DeviceModelCommandSeeder.cs b/src/AzureIoTHub.Portal.Infrastructure/Seeds/DeviceModelCommandSeeder.cs deleted file mode 100644 index 3a32f6575..000000000 --- a/src/AzureIoTHub.Portal.Infrastructure/Seeds/DeviceModelCommandSeeder.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) CGI France. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace AzureIoTHub.Portal.Infrastructure.Seeds -{ - using System.Globalization; - using Azure.Data.Tables; - using Domain; - using Domain.Entities; - using Factories; - using Microsoft.EntityFrameworkCore; - - internal static class DeviceModelCommandSeeder - { - public static async Task MigrateDeviceModelCommands(this PortalDbContext ctx, ConfigHandler config) - { - var table = new TableClientFactory(config.AzureStorageAccountConnectionString) - .GetDeviceCommands(); - - var set = ctx.Set(); - - foreach (var item in table.Query().ToArray()) - { - if (await set.AnyAsync(c => c.Id == item.RowKey)) - continue; - -#pragma warning disable CS8629 // Nullable value type may be null. - _ = await set.AddAsync(new DeviceModelCommand - { - Id = item.RowKey, - Frame = item[nameof(DeviceModelCommand.Frame)].ToString()!, - Port = int.Parse(item[nameof(DeviceModelCommand.Port)].ToString()!, CultureInfo.InvariantCulture), - IsBuiltin = bool.Parse(item[nameof(DeviceModelCommand.IsBuiltin)]?.ToString() ?? "false"), - Confirmed = bool.Parse(item[nameof(DeviceModelCommand.Confirmed)]?.ToString() ?? "false"), - DeviceModelId = item.PartitionKey - }); -#pragma warning restore CS8629 // Nullable value type may be null. - - if (config is ProductionAzureConfigHandler) - { - _ = await table.DeleteEntityAsync(item.PartitionKey, item.RowKey); - } - } - } - } -} diff --git a/src/AzureIoTHub.Portal.Infrastructure/Seeds/DeviceModelPropertySeeder.cs b/src/AzureIoTHub.Portal.Infrastructure/Seeds/DeviceModelPropertySeeder.cs deleted file mode 100644 index 14a566197..000000000 --- a/src/AzureIoTHub.Portal.Infrastructure/Seeds/DeviceModelPropertySeeder.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) CGI France. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace AzureIoTHub.Portal.Infrastructure.Seeds -{ - using Azure.Data.Tables; - using AzureIoTHub.Portal.Domain; - using AzureIoTHub.Portal.Domain.Entities; - using AzureIoTHub.Portal.Models; - using AzureIoTHub.Portal.Infrastructure.Factories; - - internal static class DeviceModelPropertySeeder - { - public static async Task MigrateDeviceModelProperties(this PortalDbContext ctx, ConfigHandler config) - { - var table = new TableClientFactory(config.AzureStorageAccountConnectionString) - .GetDeviceTemplateProperties(); - - var set = ctx.Set(); - - foreach (var item in table.Query() - .Where(item => set.Any(c => c.Id == item.RowKey)) - .ToArray()) - { - -#pragma warning disable CS8629 // Nullable value type may be null. - _ = await set.AddAsync(new DeviceModelProperty - { - Id = item.RowKey, - ModelId = item.PartitionKey, - Name = item.GetString(nameof(DeviceModelProperty.Name)), - DisplayName = item.GetString(nameof(DeviceModelProperty.DisplayName)), - PropertyType = Enum.Parse(item.GetString(nameof(DeviceModelProperty.PropertyType))), - Order = item.GetInt32(nameof(DeviceModelProperty.Order)) ?? 0, - IsWritable = item.GetBoolean(nameof(DeviceModelProperty.IsWritable)).Value - }); -#pragma warning restore CS8629 // Nullable value type may be null. - - if (config is ProductionAzureConfigHandler) - { - _ = await table.DeleteEntityAsync(item.PartitionKey, item.RowKey); - } - } - } - } -} diff --git a/src/AzureIoTHub.Portal.Infrastructure/Seeds/DeviceModelSeeder.cs b/src/AzureIoTHub.Portal.Infrastructure/Seeds/DeviceModelSeeder.cs deleted file mode 100644 index 505e35d8f..000000000 --- a/src/AzureIoTHub.Portal.Infrastructure/Seeds/DeviceModelSeeder.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) CGI France. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace AzureIoTHub.Portal.Infrastructure.Seeds -{ - using Azure.Data.Tables; - using Domain; - using Domain.Entities; - using Factories; - using Microsoft.EntityFrameworkCore; - using Models.v10.LoRaWAN; - - internal static class DeviceModelSeeder - { - public static async Task MigrateDeviceModels(this PortalDbContext ctx, ConfigHandler config) - { - var table = new TableClientFactory(config.AzureStorageAccountConnectionString) - .GetDeviceTemplates(); - - var set = ctx.Set(); - - foreach (var item in table.Query().ToArray()) - { - if (await set.AnyAsync(c => c.Id == item.RowKey)) - continue; - -#pragma warning disable CS8629 // Nullable value type may be null. - _ = await set.AddAsync(new DeviceModel - { - Id = item.RowKey, - Name = item[nameof(DeviceModel.Name)]?.ToString()!, - Description = item[nameof(DeviceModel.Description)]?.ToString(), - IsBuiltin = bool.Parse(item[nameof(DeviceModel.IsBuiltin)]?.ToString() ?? "false"), - SupportLoRaFeatures = bool.Parse(item[nameof(DeviceModel.SupportLoRaFeatures)]?.ToString() ?? "false"), - ABPRelaxMode = bool.TryParse(item[nameof(DeviceModel.ABPRelaxMode)]?.ToString(), out var abpRelaxMode) ? abpRelaxMode : null, - Deduplication = Enum.TryParse(item[nameof(DeviceModel.Deduplication)]?.ToString(), out var deduplication) ? deduplication : null, - Downlink = bool.TryParse(item[nameof(DeviceModel.Downlink)]?.ToString(), out var downLink) ? downLink : null, - KeepAliveTimeout = int.TryParse(item[nameof(DeviceModel.KeepAliveTimeout)]?.ToString(), out var keepAliveTimeout) ? keepAliveTimeout : null, - PreferredWindow = int.TryParse(item[nameof(DeviceModel.PreferredWindow)]?.ToString(), out var preferredWindow) ? preferredWindow : null, - RXDelay = int.TryParse(item[nameof(DeviceModel.PreferredWindow)]?.ToString(), out var rxDelay) ? rxDelay : null, - UseOTAA = bool.TryParse(item[nameof(DeviceModel.UseOTAA)]?.ToString(), out var useOTAA) ? useOTAA : null, - AppEUI = item[nameof(DeviceModel.AppEUI)]?.ToString(), - SensorDecoder = item[nameof(DeviceModel.SensorDecoder)]?.ToString() - }); -#pragma warning restore CS8629 // Nullable value type may be null. - - if (config is ProductionAzureConfigHandler) - { - _ = await table.DeleteEntityAsync(item.PartitionKey, item.RowKey); - } - } - } - } -} diff --git a/src/AzureIoTHub.Portal.Infrastructure/Seeds/DeviceTagSeeder.cs b/src/AzureIoTHub.Portal.Infrastructure/Seeds/DeviceTagSeeder.cs deleted file mode 100644 index 1e2ddfecd..000000000 --- a/src/AzureIoTHub.Portal.Infrastructure/Seeds/DeviceTagSeeder.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) CGI France. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace AzureIoTHub.Portal.Infrastructure.Seeds -{ - using Azure.Data.Tables; - using Domain; - using Domain.Entities; - using Factories; - using Microsoft.EntityFrameworkCore; - - internal static class DeviceTagSeeder - { - public static async Task MigrateDeviceTags(this PortalDbContext ctx, ConfigHandler config) - { - var table = new TableClientFactory(config.AzureStorageAccountConnectionString) - .GetDeviceTagSettings(); - - var set = ctx.Set(); - - foreach (var item in table.Query().ToArray()) - { - if (await set.AnyAsync(c => c.Id == item.RowKey)) - continue; - -#pragma warning disable CS8629 // Nullable value type may be null. - _ = await set.AddAsync(new DeviceTag - { - Id = item.RowKey, - Label = item[nameof(DeviceTag.Label)].ToString()!, - Required = bool.Parse(item[nameof(DeviceTag.Required)].ToString() ?? "false"), - Searchable = bool.Parse(item[nameof(DeviceTag.Searchable)].ToString() ?? "false") - }); -#pragma warning restore CS8629 // Nullable value type may be null. - - if (config is ProductionAzureConfigHandler) - { - _ = await table.DeleteEntityAsync(item.PartitionKey, item.RowKey); - } - } - } - } -} diff --git a/src/AzureIoTHub.Portal.Infrastructure/Seeds/EdgeDeviceModelCommandSeeder.cs b/src/AzureIoTHub.Portal.Infrastructure/Seeds/EdgeDeviceModelCommandSeeder.cs deleted file mode 100644 index a1fe1e381..000000000 --- a/src/AzureIoTHub.Portal.Infrastructure/Seeds/EdgeDeviceModelCommandSeeder.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) CGI France. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace AzureIoTHub.Portal.Infrastructure.Seeds -{ - using Azure.Data.Tables; - using Domain; - using Domain.Entities; - using Factories; - using Microsoft.EntityFrameworkCore; - - internal static class EdgeDeviceModelCommandSeeder - { - public static async Task MigrateEdgeDeviceModelCommands(this PortalDbContext ctx, ConfigHandler config) - { - var table = new TableClientFactory(config.AzureStorageAccountConnectionString) - .GetEdgeModuleCommands(); - - var set = ctx.Set(); - - foreach (var item in table.Query().ToArray()) - { - if (await set.AnyAsync(c => c.Id == item.RowKey)) - continue; - -#pragma warning disable CS8629 // Nullable value type may be null. - _ = await set.AddAsync(new EdgeDeviceModelCommand - { - Id = Guid.NewGuid().ToString(), - ModuleName = item.RowKey.Split("-")[0].ToString(), - Name = item[nameof(EdgeDeviceModelCommand.Name)].ToString()!, - EdgeDeviceModelId = item.PartitionKey - }); -#pragma warning restore CS8629 // Nullable value type may be null. - - if (config is ProductionAzureConfigHandler) - { - _ = await table.DeleteEntityAsync(item.PartitionKey, item.RowKey); - } - } - } - } -} diff --git a/src/AzureIoTHub.Portal.Infrastructure/Seeds/EdgeDeviceModelSeeder.cs b/src/AzureIoTHub.Portal.Infrastructure/Seeds/EdgeDeviceModelSeeder.cs deleted file mode 100644 index bcc43bc4c..000000000 --- a/src/AzureIoTHub.Portal.Infrastructure/Seeds/EdgeDeviceModelSeeder.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) CGI France. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace AzureIoTHub.Portal.Infrastructure.Seeds -{ - using Azure.Data.Tables; - using Domain; - using Domain.Entities; - using Factories; - using Microsoft.EntityFrameworkCore; - - internal static class EdgeDeviceModelSeeder - { - public static async Task MigrateEdgeDeviceModels(this PortalDbContext ctx, ConfigHandler config) - { - var table = new TableClientFactory(config.AzureStorageAccountConnectionString) - .GetEdgeDeviceTemplates(); - - var set = ctx.Set(); - - foreach (var item in table.Query().ToArray()) - { - if (await set.AnyAsync(c => c.Id == item.RowKey)) - continue; - -#pragma warning disable CS8629 // Nullable value type may be null. - _ = await set.AddAsync(new EdgeDeviceModel - { - Id = item.RowKey, - Name = item[nameof(EdgeDeviceModel.Name)].ToString()!, - Description = item[nameof(EdgeDeviceModel.Description)]?.ToString() - }); -#pragma warning restore CS8629 // Nullable value type may be null. - - if (config is ProductionAzureConfigHandler) - { - _ = await table.DeleteEntityAsync(item.PartitionKey, item.RowKey); - } - } - } - } -} diff --git a/src/AzureIoTHub.Portal.Infrastructure/Services/AWS/AWSEdgeDevicesService.cs b/src/AzureIoTHub.Portal.Infrastructure/Services/AWS/AWSEdgeDevicesService.cs index e0a55dea9..723bf01a9 100644 --- a/src/AzureIoTHub.Portal.Infrastructure/Services/AWS/AWSEdgeDevicesService.cs +++ b/src/AzureIoTHub.Portal.Infrastructure/Services/AWS/AWSEdgeDevicesService.cs @@ -29,6 +29,7 @@ public class AWSEdgeDevicesService : EdgeDevicesServiceBase, IEdgeDevicesService private readonly IEdgeDeviceModelRepository deviceModelRepository; private readonly IConfigService configService; private readonly ConfigHandler configHandler; + private readonly IMapper mapper; public AWSEdgeDevicesService( ConfigHandler configHandler, @@ -55,6 +56,8 @@ public AWSEdgeDevicesService( this.unitOfWork = unitOfWork; this.edgeDeviceRepository = edgeDeviceRepository; + + this.mapper = mapper; } /// @@ -73,15 +76,13 @@ public async Task CreateEdgeDevice(IoTEdgeDevice edgeDevice) throw new InvalidOperationException($"Edge model '{edgeDevice.ModelId}' doesn't exist!"); } - var response = await this.awsExternalDevicesService.CreateDevice(new CreateThingRequest - { - ThingName = edgeDevice.DeviceName, - ThingTypeName = model.Name - }); + var createThingRequest = this.mapper.Map(edgeDevice); + createThingRequest.ThingTypeName = model.Name; + var response = await this.awsExternalDevicesService.CreateDevice(createThingRequest); edgeDevice.DeviceId = response.ThingId; - var result = await base.CreateEdgeDeviceInDatabase(edgeDevice); + var result = await base.CreateEdgeDeviceInDatabase(edgeDevice); await this.unitOfWork.SaveAsync(); return result; @@ -97,7 +98,8 @@ public async Task UpdateEdgeDevice(IoTEdgeDevice edgeDevice) { ArgumentNullException.ThrowIfNull(edgeDevice, nameof(edgeDevice)); - _ = await this.awsExternalDevicesService.GetDevice(edgeDevice.DeviceName); + var updateThingRequest = this.mapper.Map(edgeDevice); + _ = await this.awsExternalDevicesService.UpdateDevice(updateThingRequest); var result = await UpdateEdgeDeviceInDatabase(edgeDevice); diff --git a/src/AzureIoTHub.Portal.Infrastructure/ServicesHealthCheck/TableStorageHealthCheck.cs b/src/AzureIoTHub.Portal.Infrastructure/ServicesHealthCheck/TableStorageHealthCheck.cs deleted file mode 100644 index 4bd81653b..000000000 --- a/src/AzureIoTHub.Portal.Infrastructure/ServicesHealthCheck/TableStorageHealthCheck.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) CGI France. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace AzureIoTHub.Portal.Infrastructure.ServicesHealthCheck -{ - using System; - using System.Threading; - using System.Threading.Tasks; - using Azure.Data.Tables; - using AzureIoTHub.Portal.Infrastructure.Factories; - using Microsoft.Extensions.Diagnostics.HealthChecks; - - public class TableStorageHealthCheck : IHealthCheck - { - private readonly ITableClientFactory tableClientFactory; - - public TableStorageHealthCheck(ITableClientFactory tableClientFactory) - { - this.tableClientFactory = tableClientFactory; - } - - public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default) - { - const string partitionKey = "0"; - const string rowKey = "1"; - - try - { - var tableClient = this.tableClientFactory.GetTemplatesHealthCheck(); - - _ = await tableClient.CreateIfNotExistsAsync(cancellationToken: cancellationToken); - var entity = new TableEntity(partitionKey, rowKey) - { - {"key","value" } - }; - - _ = await tableClient.AddEntityAsync(entity, cancellationToken: cancellationToken); - _ = await tableClient.DeleteEntityAsync(partitionKey, rowKey, cancellationToken: cancellationToken); - _ = await tableClient.DeleteAsync(cancellationToken: cancellationToken); - - return HealthCheckResult.Healthy(); - } - catch (Exception ex) - { - return new HealthCheckResult(context.Registration.FailureStatus, exception: ex); - } - } - - } -} diff --git a/src/AzureIoTHub.Portal.Infrastructure/Startup/AzureServiceCollectionExtension.cs b/src/AzureIoTHub.Portal.Infrastructure/Startup/AzureServiceCollectionExtension.cs index e8753cf18..a16885d19 100644 --- a/src/AzureIoTHub.Portal.Infrastructure/Startup/AzureServiceCollectionExtension.cs +++ b/src/AzureIoTHub.Portal.Infrastructure/Startup/AzureServiceCollectionExtension.cs @@ -119,7 +119,6 @@ private static IServiceCollection ConfigureHealthCheck(this IServiceCollection s _ = services.AddHealthChecks() .AddCheck("iothubHealth") .AddCheck("storageAccountHealth") - .AddCheck("tableStorageHealth") .AddCheck("dpsHealth") .AddCheck("loraManagementFacadeHealth"); diff --git a/src/AzureIoTHub.Portal.Server/Startup.cs b/src/AzureIoTHub.Portal.Server/Startup.cs index 800e03e18..2dfbb3775 100644 --- a/src/AzureIoTHub.Portal.Server/Startup.cs +++ b/src/AzureIoTHub.Portal.Server/Startup.cs @@ -22,7 +22,6 @@ namespace AzureIoTHub.Portal.Server using Hellang.Middleware.ProblemDetails.Mvc; using Identity; using Infrastructure; - using Infrastructure.Seeds; using Managers; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; @@ -35,7 +34,6 @@ namespace AzureIoTHub.Portal.Server using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; - using Microsoft.Extensions.Logging; using Microsoft.Extensions.Primitives; using Microsoft.OpenApi.Models; using MudBlazor.Services; @@ -314,6 +312,7 @@ private static void ConfigureServicesAzure(IServiceCollection services) _ = services.AddTransient(); _ = services.AddTransient(); _ = services.AddTransient(); + _ = services.AddTransient(); _ = services.AddTransient(); _ = services.AddTransient(); _ = services.AddTransient(typeof(IDeviceModelService<,>), typeof(DeviceModelService<,>)); @@ -465,8 +464,6 @@ private static async Task ConfigureAzureAsync(IApplicationBuilder app) await deviceModelImageManager?.InitializeDefaultImageBlob()!; await deviceModelImageManager?.SyncImagesCacheControl()!; - - await EnsureDatabaseCreatedAndUpToDate(app)!; } private static async Task ConfigureAwsAsync(IApplicationBuilder app) { @@ -495,39 +492,5 @@ private Task HandleApiFallback(HttpContext context) context.Response.StatusCode = StatusCodes.Status404NotFound; return Task.CompletedTask; } - - private static async Task EnsureDatabaseCreatedAndUpToDate(IApplicationBuilder app) - { - using var scope = app.ApplicationServices.CreateScope(); - using var context = scope.ServiceProvider.GetRequiredService(); - var config = scope.ServiceProvider.GetRequiredService(); - - try - { - await context - .MigrateDeviceModelProperties(config); - - await context - .MigrateDeviceTags(config); - - await context - .MigrateDeviceModelCommands(config); - - await context - .MigrateDeviceModels(config); - - await context - .MigrateEdgeDeviceModels(config); - - await context - .MigrateEdgeDeviceModelCommands(config); - - _ = await context.SaveChangesAsync(); - } - catch (InvalidOperationException e) - { - scope.ServiceProvider.GetRequiredService().LogError(e, "Failed to seed the database."); - } - } } } diff --git a/src/AzureIoTHub.Portal.Tests.Unit/AzureIoTHub.Portal.Tests.Unit.csproj b/src/AzureIoTHub.Portal.Tests.Unit/AzureIoTHub.Portal.Tests.Unit.csproj index 47277554a..b5da11c6e 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/AzureIoTHub.Portal.Tests.Unit.csproj +++ b/src/AzureIoTHub.Portal.Tests.Unit/AzureIoTHub.Portal.Tests.Unit.csproj @@ -45,7 +45,6 @@ - diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/Factories/TableClientFactoryTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/Factories/TableClientFactoryTests.cs deleted file mode 100644 index ad14cc852..000000000 --- a/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/Factories/TableClientFactoryTests.cs +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright (c) CGI France. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace AzureIoTHub.Portal.Tests.Unit.Infrastructure.Factories -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Net; - using Azure.Data.Tables; - using AzureIoTHub.Portal.Infrastructure.Factories; - using Docker.DotNet; - using Docker.DotNet.Models; - using NUnit.Framework; - - [TestFixture] - public class TableClientFactoryTests - { - private const string ContainerName = "azurite"; - private const string ImageName = "mcr.microsoft.com/azure-storage/azurite"; - private const string ImageTag = "latest"; - private static readonly string TestContainerName = ContainerName + "AzureIoTHub"; - - private string containerId; - - [TestCase(nameof(TableClientFactory.GetDeviceCommands), TableClientFactory.DeviceCommandTableName)] - [TestCase(nameof(TableClientFactory.GetDeviceTagSettings), TableClientFactory.DeviceTagSettingTableName)] - [TestCase(nameof(TableClientFactory.GetEdgeDeviceTemplates), TableClientFactory.EdgeDeviceTemplateTableName)] - [TestCase(nameof(TableClientFactory.GetEdgeModuleCommands), TableClientFactory.EdgeModuleCommandsTableName)] - [TestCase(nameof(TableClientFactory.GetDeviceTemplateProperties), TableClientFactory.DeviceTemplatePropertiesTableName)] - [TestCase(nameof(TableClientFactory.GetDeviceTemplates), TableClientFactory.DeviceTemplateTableName)] - public void GetTableShoudReturnExpectedTableClient(string methodName, string tableName) - { - // Arrange - var connectionString = "UseDevelopmentStorage=true"; - var tableClientFactory = new TableClientFactory(connectionString); - - // Act - var result = tableClientFactory - .GetType() - .GetMethod(methodName) - .Invoke(tableClientFactory, Array.Empty()) as TableClient; - // Assert - Assert.AreEqual(tableName, result.Name); - } - - [OneTimeSetUp] - protected void SetUp() - { - IList containers = new List(); - var dockerConnection = Environment.OSVersion.Platform.ToString().Contains("Win", StringComparison.Ordinal) ? - "npipe://./pipe/docker_engine" : - "unix:///var/run/docker.sock"; - Console.WriteLine("Starting container"); - using var conf = new DockerClientConfiguration(new Uri(dockerConnection)); // localhost - using var client = conf.CreateClient(); - - try - { - - Console.WriteLine("On Premise execution detected"); - Console.WriteLine("Starting container..."); - containers = client.Containers.ListContainersAsync(new ContainersListParameters() { All = true }).GetAwaiter().GetResult(); - Console.WriteLine("listing container..."); - - // Download image only if not found - try - { - _ = client.Images.InspectImageAsync(ImageName).GetAwaiter().GetResult(); - } - catch (DockerImageNotFoundException) - { - client.Images.CreateImageAsync(new ImagesCreateParameters() { FromImage = ImageName, Tag = ImageTag }, new AuthConfig(), new Progress()).GetAwaiter().GetResult(); - } - - // Create the container - var config = new Config() - { - Hostname = "localhost" - }; - - // Configure the ports to expose - var hostConfig = new HostConfig() - { - PortBindings = new Dictionary> - { - { - $"10000/tcp", new List { new PortBinding { HostIP = "127.0.0.1", HostPort = "10000" } } - }, - { - $"10001/tcp", new List { new PortBinding { HostIP = "127.0.0.1", HostPort = "10001" } } - }, - { - $"10002/tcp", new List { new PortBinding { HostIP = "127.0.0.1", HostPort = "10002" } } - } - } - }; - - Console.WriteLine("Creating container..."); - - // Create the container - var response = client.Containers.CreateContainerAsync(new CreateContainerParameters(config) - { - Image = ImageName + ":" + ImageTag, - Name = TestContainerName, - Tty = false, - HostConfig = hostConfig - }).GetAwaiter().GetResult(); - - this.containerId = response.ID; - - Console.WriteLine("Starting container..."); - - var started = client.Containers.StartContainerAsync(this.containerId, new ContainerStartParameters()).GetAwaiter().GetResult(); - if (!started) - { - Assert.False(true, "Cannot start the docker container"); - } - - Console.WriteLine("Finish booting sequence container..."); - } - catch (DockerApiException e) when (e.StatusCode == HttpStatusCode.Conflict) - { - var container = containers.FirstOrDefault(c => c.Names.Contains("/" + TestContainerName)); - if (container is { } c && c.State.Equals("exited", StringComparison.OrdinalIgnoreCase)) - { - Console.WriteLine("Starting existing container."); - _ = client.Containers.StartContainerAsync(container.ID, new ContainerStartParameters()).GetAwaiter().GetResult(); - } - else - { - Console.WriteLine("Docker container is already running."); - } - } - catch (Exception ex) - { - Console.WriteLine(ex); - throw; - } - } - - [OneTimeTearDown] - protected void TearDown() - { - if (!string.IsNullOrEmpty(this.containerId)) - { - // we are running locally - var dockerConnection = System.Environment.OSVersion.Platform.ToString().Contains("Win", StringComparison.Ordinal) ? - "npipe://./pipe/docker_engine" : - "unix:///var/run/docker.sock"; - using var conf = new DockerClientConfiguration(new Uri(dockerConnection)); // localhost - using var client = conf.CreateClient(); - client.Containers.RemoveContainerAsync(this.containerId, new ContainerRemoveParameters() - { - Force = true - }).GetAwaiter().GetResult(); - } - } - } -} diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/Mappers/DeviceTwinMapperTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/Mappers/DeviceTwinMapperTests.cs index c8894caf9..13564c736 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/Mappers/DeviceTwinMapperTests.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/Mappers/DeviceTwinMapperTests.cs @@ -8,7 +8,6 @@ namespace AzureIoTHub.Portal.Tests.Unit.Infrastructure.Mappers using AzureIoTHub.Portal.Application.Helpers; using AzureIoTHub.Portal.Application.Managers; using AzureIoTHub.Portal.Crosscutting.Extensions; - using AzureIoTHub.Portal.Infrastructure.Factories; using AzureIoTHub.Portal.Infrastructure.Mappers; using Microsoft.Azure.Devices.Shared; using Models.v10; @@ -21,7 +20,6 @@ public class DeviceTwinMapperTests private MockRepository mockRepository; private Mock mockDeviceModelImageManager; - private Mock mockTableClientFactory; [SetUp] public void SetUp() @@ -29,7 +27,6 @@ public void SetUp() this.mockRepository = new MockRepository(MockBehavior.Strict); this.mockDeviceModelImageManager = this.mockRepository.Create(); - this.mockTableClientFactory = this.mockRepository.Create(); } private DeviceTwinMapper CreateDeviceTwinMapper() diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/ServicesHealthCheck/TableStorageHealthCheckTest.cs b/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/ServicesHealthCheck/TableStorageHealthCheckTest.cs deleted file mode 100644 index 0f211b5ac..000000000 --- a/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/ServicesHealthCheck/TableStorageHealthCheckTest.cs +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) CGI France. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace AzureIoTHub.Portal.Tests.Unit.Infrastructure.ServicesHealthCheck -{ - using System; - using System.Collections.Generic; - using System.Threading; - using System.Threading.Tasks; - using Azure; - using Azure.Data.Tables; - using Azure.Data.Tables.Models; - using AzureIoTHub.Portal.Infrastructure.Factories; - using AzureIoTHub.Portal.Infrastructure.ServicesHealthCheck; - using Microsoft.Extensions.Diagnostics.HealthChecks; - using Moq; - using NUnit.Framework; - - [TestFixture] - public class TableStorageHealthCheckTest - { - private MockRepository mockRepository; - private Mock mockTableClientFactory; - - [SetUp] - public void SetUp() - { - this.mockRepository = new MockRepository(MockBehavior.Strict); - - this.mockTableClientFactory = this.mockRepository.Create(); - } - - private TableStorageHealthCheck CreateHealthService() - { - return new TableStorageHealthCheck(this.mockTableClientFactory.Object); - } - - [Test] - public async Task CheckHealthAsyncStateUnderReturnHealthy() - { - // Arrange - var healthService = CreateHealthService(); - - var healthCheckContext = new HealthCheckContext(); - var token = new CancellationToken(); - - var mockTable = this.mockRepository.Create(); - - var responseCreateIfNotExist = this.mockRepository.Create>(); - var responseAddentity = this.mockRepository.Create(); - - _ = this.mockTableClientFactory - .Setup(c => c.GetTemplatesHealthCheck()) - .Returns(mockTable.Object); - - _ = mockTable - .Setup(c => c.CreateIfNotExistsAsync(It.IsAny())) - .ReturnsAsync(responseCreateIfNotExist.Object); - - _ = mockTable - .Setup(c => c.AddEntityAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(responseAddentity.Object); - - _ = mockTable - .Setup(c => c.DeleteEntityAsync( - It.Is(_ => true), - It.IsAny(), - It.IsAny(), - It.IsAny())) - .ReturnsAsync(responseAddentity.Object); - - _ = mockTable - .Setup(c => c.DeleteAsync(It.IsAny())) - .ReturnsAsync(responseAddentity.Object); - - // Act - var result = await healthService.CheckHealthAsync(healthCheckContext, token); - - // Assert - Assert.IsNotNull(result); - Assert.AreEqual(HealthStatus.Healthy, result.Status); - } - - [Test] - public async Task CheckHealthAsyncStateUnderReturnUnhealthy() - { - // Arrange - var healthService = CreateHealthService(); - - var healthRegistration = new HealthCheckRegistration(Guid.NewGuid().ToString(), healthService, HealthStatus.Unhealthy, new List()); - var healthCheckContext = new HealthCheckContext() - { - Registration = healthRegistration - }; - var token = new CancellationToken(); - - var mockTable = this.mockRepository.Create(); - - var mockResponse = this.mockRepository.Create(); - - _ = this.mockTableClientFactory - .Setup(c => c.GetTemplatesHealthCheck()) - .Returns(mockTable.Object); - - _ = mockTable - .Setup(c => c.CreateIfNotExistsAsync(It.IsAny())) - .Throws(new Exception()); - - _ = mockTable - .Setup(c => c.AddEntityAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(mockResponse.Object); - - _ = mockTable - .Setup(c => c.DeleteEntityAsync( - It.Is(_ => true), - It.IsAny(), - It.IsAny(), - It.IsAny())) - .ReturnsAsync(mockResponse.Object); - - _ = mockTable - .Setup(c => c.DeleteAsync(It.IsAny())) - .ReturnsAsync(mockResponse.Object); - - // Act - var result = await healthService.CheckHealthAsync(healthCheckContext, token); - - // Assert - Assert.IsNotNull(result); - Assert.AreEqual(HealthStatus.Unhealthy, result.Status); - } - } -}