diff --git a/src/AzureIoTHub.Portal.Client/Pages/EdgeModels/EdgeModule/ModuleDialog.razor b/src/AzureIoTHub.Portal.Client/Pages/EdgeModels/EdgeModule/ModuleDialog.razor index ecd1f1375..2d691ea42 100644 --- a/src/AzureIoTHub.Portal.Client/Pages/EdgeModels/EdgeModule/ModuleDialog.razor +++ b/src/AzureIoTHub.Portal.Client/Pages/EdgeModels/EdgeModule/ModuleDialog.razor @@ -50,7 +50,7 @@ Required="true"/> - The Version should be incremented when updating the component + The Version Number should be incremented when updating the component } @@ -120,7 +120,10 @@ Module.ModuleName = currentModuleName; Module.ImageURI = currentImageUri; Module.ContainerCreateOptions = currentContainerCreateOptions; - Module.Version = currentNumVersion; + + if (Portal.CloudProvider.Equals(CloudProviders.Azure)) { Module.Version = " "; } + else { Module.Version = currentNumVersion; } + Module.EnvironmentVariables = new List(currentEnvironmentVariables.ToArray()); Module.ModuleIdentityTwinSettings = new List(currentModuleIdentityTwinSettings.ToArray()); Module.Commands = new List(currentCommands.ToArray()); diff --git a/src/AzureIoTHub.Portal.Domain/Entities/EdgeDeviceModel.cs b/src/AzureIoTHub.Portal.Domain/Entities/EdgeDeviceModel.cs index 2c9978eaf..14f9c1622 100644 --- a/src/AzureIoTHub.Portal.Domain/Entities/EdgeDeviceModel.cs +++ b/src/AzureIoTHub.Portal.Domain/Entities/EdgeDeviceModel.cs @@ -10,7 +10,7 @@ public class EdgeDeviceModel : EntityBase public string Name { get; set; } = default!; public string? Description { get; set; } - public string? IdProvider { get; set; } + public string? ExternalIdentifier { get; set; } /// /// Labels diff --git a/src/AzureIoTHub.Portal.Infrastructure/Services/AWS/AwsConfigService.cs b/src/AzureIoTHub.Portal.Infrastructure/Services/AWS/AwsConfigService.cs index dbefca0fc..8b3d9ef29 100644 --- a/src/AzureIoTHub.Portal.Infrastructure/Services/AWS/AwsConfigService.cs +++ b/src/AzureIoTHub.Portal.Infrastructure/Services/AWS/AwsConfigService.cs @@ -74,7 +74,7 @@ public async Task RollOutEdgeModelConfiguration(IoTEdgeModel edgeModel) } else { - edgeModel!.IdProvider = createDeploymentResponse.DeploymentId; + edgeModel!.ExternalIdentifier = createDeploymentResponse.DeploymentId; _ = this.mapper.Map(edgeModel, edgeModelEntity); @@ -240,9 +240,45 @@ public Task GetConfigItem(string id) throw new NotImplementedException(); } - public Task DeleteConfiguration(string configId) + public async Task DeleteConfiguration(string modelId) { - throw new NotImplementedException(); + var modules = await GetConfigModuleList(modelId); + foreach (var module in modules) + { + var deletedComponentResponse = await this.greengras.DeleteComponentAsync(new DeleteComponentRequest + { + Arn = $"arn:aws:greengrass:{config.AWSRegion}:{config.AWSAccountId}:components:{module.ModuleName}:versions:{module.Version}" + }); + + if (deletedComponentResponse.HttpStatusCode != HttpStatusCode.NoContent) + { + throw new InternalServerErrorException("The deletion of the component failed due to an error in the Amazon IoT API."); + + } + } + + var cancelDeploymentResponse = await this.greengras.CancelDeploymentAsync(new CancelDeploymentRequest + { + DeploymentId = modelId + }); + if (cancelDeploymentResponse.HttpStatusCode != HttpStatusCode.OK) + { + throw new InternalServerErrorException("The cancellation of the deployment failed due to an error in the Amazon IoT API."); + + } + else + { + var deleteDeploymentResponse = await this.greengras.DeleteDeploymentAsync(new DeleteDeploymentRequest + { + DeploymentId = modelId + }); + + if (deleteDeploymentResponse.HttpStatusCode != HttpStatusCode.NoContent) + { + throw new InternalServerErrorException("The deletion of the deployment failed due to an error in the Amazon IoT API."); + } + } + } public Task GetFailedDeploymentsCount() diff --git a/src/AzureIoTHub.Portal.Infrastructure/Services/EdgeModelService.cs b/src/AzureIoTHub.Portal.Infrastructure/Services/EdgeModelService.cs index dbcec3694..96087e3a9 100644 --- a/src/AzureIoTHub.Portal.Infrastructure/Services/EdgeModelService.cs +++ b/src/AzureIoTHub.Portal.Infrastructure/Services/EdgeModelService.cs @@ -219,7 +219,7 @@ private async Task GetAzureEdgeModel(EdgeDeviceModel edgeModelEnti private async Task GetAwsEdgeModel(EdgeDeviceModel edgeModelEntity) { - var modules = await this.configService.GetConfigModuleList(edgeModelEntity.IdProvider!); + var modules = await this.configService.GetConfigModuleList(edgeModelEntity.ExternalIdentifier!); //TODO : User a mapper //Previously return this.edgeDeviceModelMapper.CreateEdgeDeviceModel(query.Value, modules, routes, commands); var result = new IoTEdgeModel @@ -282,17 +282,24 @@ public async Task DeleteEdgeModel(string edgeModelId) return; } - var config = this.configService.GetIoTEdgeConfigurations().Result.FirstOrDefault(x => x.Id.StartsWith(edgeModelId, StringComparison.Ordinal)); - - if (config != null) + if (this.config.CloudProvider.Equals(CloudProviders.Azure, StringComparison.Ordinal)) { - await this.configService.DeleteConfiguration(config.Id); - } + var config = this.configService.GetIoTEdgeConfigurations().Result.FirstOrDefault(x => x.Id.StartsWith(edgeModelId, StringComparison.Ordinal)); - var existingCommands = this.commandRepository.GetAll().Where(x => x.EdgeDeviceModelId == edgeModelId).ToList(); - foreach (var command in existingCommands) + if (config != null) + { + await this.configService.DeleteConfiguration(config.Id); + } + + var existingCommands = this.commandRepository.GetAll().Where(x => x.EdgeDeviceModelId == edgeModelId).ToList(); + foreach (var command in existingCommands) + { + this.commandRepository.Delete(command.Id); + } + } + else { - this.commandRepository.Delete(command.Id); + await this.configService.DeleteConfiguration(edgeModelEntity.ExternalIdentifier!); } foreach (var labelEntity in edgeModelEntity.Labels) diff --git a/src/AzureIoTHub.Portal.Infrastructure/Startup/AWSServiceCollectionExtension.cs b/src/AzureIoTHub.Portal.Infrastructure/Startup/AWSServiceCollectionExtension.cs index 0db5dbd6b..b2e501114 100644 --- a/src/AzureIoTHub.Portal.Infrastructure/Startup/AWSServiceCollectionExtension.cs +++ b/src/AzureIoTHub.Portal.Infrastructure/Startup/AWSServiceCollectionExtension.cs @@ -29,8 +29,7 @@ public static IServiceCollection AddAWSInfrastructureLayer(this IServiceCollecti .ConfigureAWSClient(configuration).Result .ConfigureAWSServices() .ConfigureAWSDeviceModelImages() - .ConfigureAWSSyncJobs(configuration) - .ConfigureOtherDependencies(); + .ConfigureAWSSyncJobs(configuration); } private static async Task ConfigureAWSClient(this IServiceCollection services, ConfigHandler configuration) { @@ -88,10 +87,5 @@ private static IServiceCollection ConfigureAWSSyncJobs(this IServiceCollection s }); } - private static IServiceCollection ConfigureOtherDependencies(this IServiceCollection services) - { - _ = services.AddSingleton(new PortalSettings()); - return services; - } } } diff --git a/src/AzureIoTHub.Portal.Postgres/Migrations/20230526083144_Change IdProvider to ExternalIdentifier.Designer.cs b/src/AzureIoTHub.Portal.Postgres/Migrations/20230526083144_Change IdProvider to ExternalIdentifier.Designer.cs new file mode 100644 index 000000000..3757b91f6 --- /dev/null +++ b/src/AzureIoTHub.Portal.Postgres/Migrations/20230526083144_Change IdProvider to ExternalIdentifier.Designer.cs @@ -0,0 +1,590 @@ +// +using System; +using AzureIoTHub.Portal.Infrastructure; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace AzureIoTHub.Portal.Postgres.Migrations +{ + [DbContext(typeof(PortalDbContext))] + [Migration("20230526083144_Change IdProvider to ExternalIdentifier")] + partial class ChangeIdProvidertoExternalIdentifier + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.Concentrator", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ClientThumbprint") + .HasColumnType("text"); + + b.Property("DeviceType") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsConnected") + .HasColumnType("boolean"); + + b.Property("IsEnabled") + .HasColumnType("boolean"); + + b.Property("LoraRegion") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("Concentrators"); + }); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.Device", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("DeviceModelId") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsConnected") + .HasColumnType("boolean"); + + b.Property("IsEnabled") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("StatusUpdatedTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("DeviceModelId"); + + b.ToTable("Devices", (string)null); + + b.UseTptMappingStrategy(); + }); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.DeviceModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ABPRelaxMode") + .HasColumnType("boolean"); + + b.Property("AppEUI") + .HasColumnType("text"); + + b.Property("ClassType") + .HasColumnType("integer"); + + b.Property("Deduplication") + .HasColumnType("integer"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Downlink") + .HasColumnType("boolean"); + + b.Property("IsBuiltin") + .HasColumnType("boolean"); + + b.Property("KeepAliveTimeout") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("PreferredWindow") + .HasColumnType("integer"); + + b.Property("RXDelay") + .HasColumnType("integer"); + + b.Property("SensorDecoder") + .HasColumnType("text"); + + b.Property("SupportLoRaFeatures") + .HasColumnType("boolean"); + + b.Property("UseOTAA") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("DeviceModels"); + }); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.DeviceModelCommand", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Confirmed") + .HasColumnType("boolean"); + + b.Property("DeviceModelId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Frame") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsBuiltin") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Port") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("DeviceModelCommands"); + }); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.DeviceModelProperty", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsWritable") + .HasColumnType("boolean"); + + b.Property("ModelId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("integer"); + + b.Property("PropertyType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("DeviceModelProperties"); + }); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.DeviceTag", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Label") + .IsRequired() + .HasColumnType("text"); + + b.Property("Required") + .HasColumnType("boolean"); + + b.Property("Searchable") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("DeviceTags"); + }); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.DeviceTagValue", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("DeviceId") + .HasColumnType("text"); + + b.Property("EdgeDeviceId") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("EdgeDeviceId"); + + b.ToTable("DeviceTagValues"); + }); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.EdgeDevice", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ConnectionState") + .IsRequired() + .HasColumnType("text"); + + b.Property("DeviceModelId") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsEnabled") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("NbDevices") + .HasColumnType("integer"); + + b.Property("NbModules") + .HasColumnType("integer"); + + b.Property("Scope") + .HasColumnType("text"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("DeviceModelId"); + + b.ToTable("EdgeDevices"); + }); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.EdgeDeviceModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("ExternalIdentifier") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("EdgeDeviceModels"); + }); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.EdgeDeviceModelCommand", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("EdgeDeviceModelId") + .IsRequired() + .HasColumnType("text"); + + b.Property("ModuleName") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("EdgeDeviceModelCommands"); + }); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.Label", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Color") + .IsRequired() + .HasColumnType("text"); + + b.Property("DeviceId") + .HasColumnType("text"); + + b.Property("DeviceModelId") + .HasColumnType("text"); + + b.Property("EdgeDeviceId") + .HasColumnType("text"); + + b.Property("EdgeDeviceModelId") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("DeviceModelId"); + + b.HasIndex("EdgeDeviceId"); + + b.HasIndex("EdgeDeviceModelId"); + + b.ToTable("Labels"); + }); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.LoRaDeviceTelemetry", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("EnqueuedTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LorawanDeviceId") + .HasColumnType("text"); + + b.Property("Telemetry") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("LorawanDeviceId"); + + b.ToTable("LoRaDeviceTelemetry"); + }); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.LorawanDevice", b => + { + b.HasBaseType("AzureIoTHub.Portal.Domain.Entities.Device"); + + b.Property("ABPRelaxMode") + .HasColumnType("boolean"); + + b.Property("AlreadyLoggedInOnce") + .HasColumnType("boolean"); + + b.Property("AppEUI") + .HasColumnType("text"); + + b.Property("AppKey") + .HasColumnType("text"); + + b.Property("AppSKey") + .HasColumnType("text"); + + b.Property("ClassType") + .HasColumnType("integer"); + + b.Property("DataRate") + .HasColumnType("text"); + + b.Property("Deduplication") + .HasColumnType("integer"); + + b.Property("DevAddr") + .HasColumnType("text"); + + b.Property("Downlink") + .HasColumnType("boolean"); + + b.Property("FCntDownStart") + .HasColumnType("integer"); + + b.Property("FCntResetCounter") + .HasColumnType("integer"); + + b.Property("FCntUpStart") + .HasColumnType("integer"); + + b.Property("GatewayID") + .HasColumnType("text"); + + b.Property("KeepAliveTimeout") + .HasColumnType("integer"); + + b.Property("NbRep") + .HasColumnType("text"); + + b.Property("NwkSKey") + .HasColumnType("text"); + + b.Property("PreferredWindow") + .HasColumnType("integer"); + + b.Property("RX1DROffset") + .HasColumnType("integer"); + + b.Property("RX2DataRate") + .HasColumnType("integer"); + + b.Property("RXDelay") + .HasColumnType("integer"); + + b.Property("ReportedRX1DROffset") + .HasColumnType("text"); + + b.Property("ReportedRX2DataRate") + .HasColumnType("text"); + + b.Property("ReportedRXDelay") + .HasColumnType("text"); + + b.Property("SensorDecoder") + .HasColumnType("text"); + + b.Property("Supports32BitFCnt") + .HasColumnType("boolean"); + + b.Property("TxPower") + .HasColumnType("text"); + + b.Property("UseOTAA") + .HasColumnType("boolean"); + + b.ToTable("LorawanDevices", (string)null); + }); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.Device", b => + { + b.HasOne("AzureIoTHub.Portal.Domain.Entities.DeviceModel", "DeviceModel") + .WithMany() + .HasForeignKey("DeviceModelId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DeviceModel"); + }); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.DeviceTagValue", b => + { + b.HasOne("AzureIoTHub.Portal.Domain.Entities.Device", null) + .WithMany("Tags") + .HasForeignKey("DeviceId"); + + b.HasOne("AzureIoTHub.Portal.Domain.Entities.EdgeDevice", null) + .WithMany("Tags") + .HasForeignKey("EdgeDeviceId"); + }); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.EdgeDevice", b => + { + b.HasOne("AzureIoTHub.Portal.Domain.Entities.EdgeDeviceModel", "DeviceModel") + .WithMany() + .HasForeignKey("DeviceModelId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DeviceModel"); + }); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.Label", b => + { + b.HasOne("AzureIoTHub.Portal.Domain.Entities.Device", null) + .WithMany("Labels") + .HasForeignKey("DeviceId"); + + b.HasOne("AzureIoTHub.Portal.Domain.Entities.DeviceModel", null) + .WithMany("Labels") + .HasForeignKey("DeviceModelId"); + + b.HasOne("AzureIoTHub.Portal.Domain.Entities.EdgeDevice", null) + .WithMany("Labels") + .HasForeignKey("EdgeDeviceId"); + + b.HasOne("AzureIoTHub.Portal.Domain.Entities.EdgeDeviceModel", null) + .WithMany("Labels") + .HasForeignKey("EdgeDeviceModelId"); + }); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.LoRaDeviceTelemetry", b => + { + b.HasOne("AzureIoTHub.Portal.Domain.Entities.LorawanDevice", null) + .WithMany("Telemetry") + .HasForeignKey("LorawanDeviceId"); + }); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.LorawanDevice", b => + { + b.HasOne("AzureIoTHub.Portal.Domain.Entities.Device", null) + .WithOne() + .HasForeignKey("AzureIoTHub.Portal.Domain.Entities.LorawanDevice", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.Device", b => + { + b.Navigation("Labels"); + + b.Navigation("Tags"); + }); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.DeviceModel", b => + { + b.Navigation("Labels"); + }); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.EdgeDevice", b => + { + b.Navigation("Labels"); + + b.Navigation("Tags"); + }); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.EdgeDeviceModel", b => + { + b.Navigation("Labels"); + }); + + modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.LorawanDevice", b => + { + b.Navigation("Telemetry"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/AzureIoTHub.Portal.Postgres/Migrations/20230526083144_Change IdProvider to ExternalIdentifier.cs b/src/AzureIoTHub.Portal.Postgres/Migrations/20230526083144_Change IdProvider to ExternalIdentifier.cs new file mode 100644 index 000000000..d0bd13170 --- /dev/null +++ b/src/AzureIoTHub.Portal.Postgres/Migrations/20230526083144_Change IdProvider to ExternalIdentifier.cs @@ -0,0 +1,30 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +#nullable disable + +namespace AzureIoTHub.Portal.Postgres.Migrations +{ + using Microsoft.EntityFrameworkCore.Migrations; + + /// + public partial class ChangeIdProvidertoExternalIdentifier : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + _ = migrationBuilder.RenameColumn( + name: "IdProvider", + table: "EdgeDeviceModels", + newName: "ExternalIdentifier"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + _ = migrationBuilder.RenameColumn( + name: "ExternalIdentifier", + table: "EdgeDeviceModels", + newName: "IdProvider"); + } + } +} diff --git a/src/AzureIoTHub.Portal.Postgres/Migrations/PortalDbContextModelSnapshot.cs b/src/AzureIoTHub.Portal.Postgres/Migrations/PortalDbContextModelSnapshot.cs index 05d5edac4..27a95859e 100644 --- a/src/AzureIoTHub.Portal.Postgres/Migrations/PortalDbContextModelSnapshot.cs +++ b/src/AzureIoTHub.Portal.Postgres/Migrations/PortalDbContextModelSnapshot.cs @@ -300,7 +300,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Description") .HasColumnType("text"); - b.Property("IdProvider") + b.Property("ExternalIdentifier") .HasColumnType("text"); b.Property("Name") diff --git a/src/AzureIoTHub.Portal.Shared/Models/v1.0/IoTEdgeModelListItem.cs b/src/AzureIoTHub.Portal.Shared/Models/v1.0/IoTEdgeModelListItem.cs index 5c975bd3e..43c5620be 100644 --- a/src/AzureIoTHub.Portal.Shared/Models/v1.0/IoTEdgeModelListItem.cs +++ b/src/AzureIoTHub.Portal.Shared/Models/v1.0/IoTEdgeModelListItem.cs @@ -31,7 +31,7 @@ public class IoTEdgeModelListItem /// /// The aws deployment ID. /// - public string IdProvider { get; set; } = default!; + public string ExternalIdentifier { get; set; } = default!; /// diff --git a/src/AzureIoTHub.Portal.Shared/Models/v1.0/IoTEdgeModule.cs b/src/AzureIoTHub.Portal.Shared/Models/v1.0/IoTEdgeModule.cs index bcb3080ef..643b710f5 100644 --- a/src/AzureIoTHub.Portal.Shared/Models/v1.0/IoTEdgeModule.cs +++ b/src/AzureIoTHub.Portal.Shared/Models/v1.0/IoTEdgeModule.cs @@ -46,7 +46,7 @@ public class IoTEdgeModule /// public List Commands { get; set; } = new List(); - [Required(ErrorMessage = "The component version is required.")] + [Required(ErrorMessage = "The component version is required.", AllowEmptyStrings = true)] public string Version { get; set; } = default!; } } diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/Services/AWS_Tests/AwsConfigTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/Services/AWS_Tests/AwsConfigTests.cs index 3d30916f7..ce13873fa 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/Services/AWS_Tests/AwsConfigTests.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/Services/AWS_Tests/AwsConfigTests.cs @@ -186,10 +186,64 @@ public async Task GetAllDeploymentComponentsShouldRetreiveImageUriAndEnvironment }); //Arrange - _ = await this.awsConfigService.GetConfigModuleList(edge.IdProvider); + _ = await this.awsConfigService.GetConfigModuleList(edge.ExternalIdentifier); //Assert MockRepository.VerifyAll(); } + + [Test] + public async Task DeleteDeploymentShouldDeleteTheDeploymentVersionAndAllItsComponentsVersions() + { + //Act + var edge = Fixture.Create(); + using var recipeAsMemoryStream = new MemoryStream(Encoding.UTF8.GetBytes(Fixture.Create().ToString())); + + _ = this.mockConfigHandler.Setup(handler => handler.AWSRegion).Returns("eu-west-1"); + _ = this.mockConfigHandler.Setup(handler => handler.AWSAccountId).Returns("00000000"); + + _ = this.mockGreengrasClient.Setup(s3 => s3.GetDeploymentAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new GetDeploymentResponse + { + HttpStatusCode = HttpStatusCode.OK, + Components = new Dictionary + { + {"test", new ComponentDeploymentSpecification()} + + } + }); + + _ = this.mockGreengrasClient.Setup(s3 => s3.GetComponentAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new GetComponentResponse + { + HttpStatusCode = HttpStatusCode.OK, + Recipe = recipeAsMemoryStream, + RecipeOutputFormat = RecipeOutputFormat.JSON + }); + + _ = this.mockGreengrasClient.Setup(s3 => s3.DeleteComponentAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new DeleteComponentResponse + { + HttpStatusCode = HttpStatusCode.NoContent + }); + + _ = this.mockGreengrasClient.Setup(s3 => s3.CancelDeploymentAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new CancelDeploymentResponse + { + HttpStatusCode = HttpStatusCode.OK + }); + + _ = this.mockGreengrasClient.Setup(s3 => s3.DeleteDeploymentAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new DeleteDeploymentResponse + { + HttpStatusCode = HttpStatusCode.NoContent + }); + //Arrange + await this.awsConfigService.DeleteConfiguration(edge.ExternalIdentifier); + + //Assert + MockRepository.VerifyAll(); + + } } } diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Server/Services/EdgeModelServiceTest.cs b/src/AzureIoTHub.Portal.Tests.Unit/Server/Services/EdgeModelServiceTest.cs index e2cd9c466..6857ad796 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Server/Services/EdgeModelServiceTest.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Server/Services/EdgeModelServiceTest.cs @@ -459,6 +459,8 @@ public void UpdateEdgeModelShouldThrowInternalServerErrorExceptionIfDbUpdateExce public async Task DeleteEdgeModelShouldDeleteEdgeModel() { // Arrange + _ = this.mockConfigHandler.Setup(handler => handler.CloudProvider).Returns("Azure"); + var edgeDeviceModel = Fixture.Create(); var edgeDeviceModelEntity = Mapper.Map(edgeDeviceModel); @@ -497,6 +499,35 @@ public async Task DeleteEdgeModelShouldDeleteEdgeModel() MockRepository.VerifyAll(); } + [Test] + public async Task DeleteEdgeModelForAwsShouldDeleteEdgeModel() + { + // Arrange + _ = this.mockConfigHandler.Setup(handler => handler.CloudProvider).Returns("AWS"); + + var edgeDeviceModel = Fixture.Create(); + var edgeDeviceModelEntity = Mapper.Map(edgeDeviceModel); + + _ = this.mockEdgeDeviceModelRepository.Setup(repository => repository.GetByIdAsync(edgeDeviceModelEntity.Id, d => d.Labels)) + .ReturnsAsync(edgeDeviceModelEntity); + + this.mockLabelRepository.Setup(repository => repository.Delete(It.IsAny())) + .Verifiable(); + + _ = this.mockEdgeDeviceModelRepository.Setup(repository => repository.Delete(It.IsAny())); + _ = this.mockUnitOfWork.Setup(work => work.SaveAsync()) + .Returns(Task.CompletedTask); + + _ = this.mockConfigService.Setup(x => x.DeleteConfiguration(It.IsAny())) + .Returns(Task.CompletedTask); + + // Act + await this.edgeDeviceModelService.DeleteEdgeModel(edgeDeviceModel.ModelId); + + // Assert + MockRepository.VerifyAll(); + } + [Test] public async Task DeleteEdgeModel_ModelDoesntExist_NothingIsDone() {