From bd9e43cf2c95e3700b11dd549f52cadc4bdb379b Mon Sep 17 00:00:00 2001
From: ssgueye2 <127868584+ssgueye2@users.noreply.github.com>
Date: Fri, 26 May 2023 14:28:33 +0200
Subject: [PATCH] Update and delete green grass deployment (#2113)
* retrieve json attribute from Recipe
* Update creation Deployment method + Get Deployment method
* FIX Existing Failed Tests
* Update method done (But not tested)
* Fix Failed Tests + All tests for the update and the Get Deployment Done
* retrieve json attribute from Recipe
* Update creation Deployment method + Get Deployment method
* retrieve json attribute from Recipe
* Update creation Deployment method + Get Deployment method
* Change IdProvider to ExternalIdentifier + Delete Deployment (DONE)
---
.../EdgeModels/CreateEdgeModelsPage.razor | 20 +-
.../EdgeModels/EdgeModelDetailPage.razor | 181 +++--
.../EdgeModels/EdgeModule/ModuleDialog.razor | 22 +-
.../ConfigHandler.cs | 1 +
.../Entities/EdgeDeviceModel.cs | 1 +
.../ConfigHandlerBase.cs | 1 +
.../DevelopmentConfigHandler.cs | 1 +
.../ProductionAWSConfigHandler.cs | 2 +
.../ProductionAzureConfigHandler.cs | 2 +
.../Services/AWS/AwsConfigService.cs | 225 +++++-
.../Services/EdgeModelService.cs | 50 +-
.../Startup/AWSServiceCollectionExtension.cs | 8 +-
...525074805_Add Aws DeploymentId.Designer.cs | 590 ++++++++++++++
.../20230525074805_Add Aws DeploymentId.cs | 30 +
...Provider to ExternalIdentifier.Designer.cs | 590 ++++++++++++++
...Change IdProvider to ExternalIdentifier.cs | 30 +
.../PortalDbContextModelSnapshot.cs | 745 +++++++++---------
.../Models/v1.0/IoTEdgeModelListItem.cs | 6 +
.../Models/v1.0/IoTEdgeModule.cs | 3 +
.../EdgeModels/EdgeModelDetailPageTest.cs | 22 +-
.../Services/AWS_Tests/AwsConfigTests.cs | 116 +++
.../Server/Services/EdgeModelServiceTest.cs | 117 +++
22 files changed, 2257 insertions(+), 506 deletions(-)
create mode 100644 src/AzureIoTHub.Portal.Postgres/Migrations/20230525074805_Add Aws DeploymentId.Designer.cs
create mode 100644 src/AzureIoTHub.Portal.Postgres/Migrations/20230525074805_Add Aws DeploymentId.cs
create mode 100644 src/AzureIoTHub.Portal.Postgres/Migrations/20230526083144_Change IdProvider to ExternalIdentifier.Designer.cs
create mode 100644 src/AzureIoTHub.Portal.Postgres/Migrations/20230526083144_Change IdProvider to ExternalIdentifier.cs
diff --git a/src/AzureIoTHub.Portal.Client/Pages/EdgeModels/CreateEdgeModelsPage.razor b/src/AzureIoTHub.Portal.Client/Pages/EdgeModels/CreateEdgeModelsPage.razor
index e436c0c23..7226764f4 100644
--- a/src/AzureIoTHub.Portal.Client/Pages/EdgeModels/CreateEdgeModelsPage.razor
+++ b/src/AzureIoTHub.Portal.Client/Pages/EdgeModels/CreateEdgeModelsPage.razor
@@ -196,17 +196,17 @@
-
-
-
- Labels
-
-
-
-
-
-
}
+
+
+
+ Labels
+
+
+
+
+
+
diff --git a/src/AzureIoTHub.Portal.Client/Pages/EdgeModels/EdgeModelDetailPage.razor b/src/AzureIoTHub.Portal.Client/Pages/EdgeModels/EdgeModelDetailPage.razor
index 1d199a89d..d5538a896 100644
--- a/src/AzureIoTHub.Portal.Client/Pages/EdgeModels/EdgeModelDetailPage.razor
+++ b/src/AzureIoTHub.Portal.Client/Pages/EdgeModels/EdgeModelDetailPage.razor
@@ -7,12 +7,15 @@
@using AzureIoTHub.Portal.Shared.Models.v10
@using AzureIoTHub.Portal.Client.Validators
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
+@using AzureIoTHub.Portal.Shared.Constants
+
@attribute [Authorize]
@inject NavigationManager NavigationManager
@inject IEdgeModelClientService EdgeModelService
@inject ISnackbar Snackbar
@inject IDialogService DialogService
+@inject PortalSettings Portal
@@ -69,44 +72,46 @@
-
-
-
-
- System Modules
-
-
-
-
-
-
-
-
-
-
- Module name
- Image URI
- Detail
-
-
-
-
-
-
-
-
-
-
- Detail
-
-
-
-
-
-
-
-
-
+ @if (Portal.CloudProvider.Equals(CloudProviders.Azure))
+ {
+
+
+
+ System Modules
+
+
+
+
+
+
+
+
+
+
+ Module name
+ Image URI
+ Detail
+
+
+
+
+
+
+
+
+
+
+ Detail
+
+
+
+
+
+
+
+
+ }
+
@@ -149,55 +154,57 @@
-
-
-
-
- Routes
-
-
-
-
-
-
-
-
-
-
-
- Name
- Value
- Priority
- Time To Live (Secs)
- Delete
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Add new route
-
-
-
-
-
-
-
-
+ @if (Portal.CloudProvider.Equals(CloudProviders.Azure))
+ {
+
+
+
+ Routes
+
+
+
+
+
+
+
+
+
+
+
+ Name
+ Value
+ Priority
+ Time To Live (Secs)
+ Delete
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Add new route
+
+
+
+
+
+
+
+ }
+
diff --git a/src/AzureIoTHub.Portal.Client/Pages/EdgeModels/EdgeModule/ModuleDialog.razor b/src/AzureIoTHub.Portal.Client/Pages/EdgeModels/EdgeModule/ModuleDialog.razor
index d807c792f..2d691ea42 100644
--- a/src/AzureIoTHub.Portal.Client/Pages/EdgeModels/EdgeModule/ModuleDialog.razor
+++ b/src/AzureIoTHub.Portal.Client/Pages/EdgeModels/EdgeModule/ModuleDialog.razor
@@ -39,7 +39,21 @@
How to configure container create options for IoT Edge modules
}
-
+ else
+ {
+
+
+
+
+ The Version Number should be incremented when updating the component
+
+ }
+
@@ -77,6 +91,7 @@
private string currentModuleName = default!;
private string currentImageUri = default!;
private string currentContainerCreateOptions = default!;
+ private string currentNumVersion = "1.0.0";
private List currentEnvironmentVariables = new();
private List currentModuleIdentityTwinSettings = new();
@@ -92,6 +107,7 @@
currentModuleName = Module.ModuleName;
currentImageUri = Module.ImageURI;
currentContainerCreateOptions = Module.ContainerCreateOptions;
+ currentNumVersion = Module.Version;
currentEnvironmentVariables = new List(Module.EnvironmentVariables.ToArray());
currentModuleIdentityTwinSettings = new List(Module.ModuleIdentityTwinSettings.ToArray());
currentCommands = new List(Module.Commands.ToArray());
@@ -104,6 +120,10 @@
Module.ModuleName = currentModuleName;
Module.ImageURI = currentImageUri;
Module.ContainerCreateOptions = currentContainerCreateOptions;
+
+ 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/ConfigHandler.cs b/src/AzureIoTHub.Portal.Domain/ConfigHandler.cs
index c38f5d5b3..97724719b 100644
--- a/src/AzureIoTHub.Portal.Domain/ConfigHandler.cs
+++ b/src/AzureIoTHub.Portal.Domain/ConfigHandler.cs
@@ -80,5 +80,6 @@ public abstract class ConfigHandler
public abstract string AWSRegion { get; }
public abstract string AWSS3StorageConnectionString { get; }
public abstract string AWSBucketName { get; }
+ public abstract string AWSAccountId { get; }
}
}
diff --git a/src/AzureIoTHub.Portal.Domain/Entities/EdgeDeviceModel.cs b/src/AzureIoTHub.Portal.Domain/Entities/EdgeDeviceModel.cs
index 12b29c723..14f9c1622 100644
--- a/src/AzureIoTHub.Portal.Domain/Entities/EdgeDeviceModel.cs
+++ b/src/AzureIoTHub.Portal.Domain/Entities/EdgeDeviceModel.cs
@@ -10,6 +10,7 @@ public class EdgeDeviceModel : EntityBase
public string Name { get; set; } = default!;
public string? Description { get; set; }
+ public string? ExternalIdentifier { get; set; }
///
/// Labels
diff --git a/src/AzureIoTHub.Portal.Infrastructure/ConfigHandlerBase.cs b/src/AzureIoTHub.Portal.Infrastructure/ConfigHandlerBase.cs
index f5b8f3454..a87743b92 100644
--- a/src/AzureIoTHub.Portal.Infrastructure/ConfigHandlerBase.cs
+++ b/src/AzureIoTHub.Portal.Infrastructure/ConfigHandlerBase.cs
@@ -57,6 +57,7 @@ internal abstract class ConfigHandlerBase : ConfigHandler
internal const string AWSRegionKey = "AWS:Region";
internal const string AWSS3StorageConnectionStringKey = "AWS:S3Storage:ConnectionString";
internal const string AWSBucketNameKey = "AWS:BucketName";
+ internal const string AWSAccountIdKey = "AWS:AccountId";
}
}
diff --git a/src/AzureIoTHub.Portal.Infrastructure/DevelopmentConfigHandler.cs b/src/AzureIoTHub.Portal.Infrastructure/DevelopmentConfigHandler.cs
index 1581123d9..0360bff0c 100644
--- a/src/AzureIoTHub.Portal.Infrastructure/DevelopmentConfigHandler.cs
+++ b/src/AzureIoTHub.Portal.Infrastructure/DevelopmentConfigHandler.cs
@@ -89,5 +89,6 @@ internal DevelopmentConfigHandler(IConfiguration config)
public override string AWSRegion => this.config[AWSRegionKey]!;
public override string AWSS3StorageConnectionString => this.config[AWSS3StorageConnectionStringKey]!;
public override string AWSBucketName => this.config[AWSBucketNameKey]!;
+ public override string AWSAccountId => this.config[AWSAccountIdKey]!;
}
}
diff --git a/src/AzureIoTHub.Portal.Infrastructure/ProductionAWSConfigHandler.cs b/src/AzureIoTHub.Portal.Infrastructure/ProductionAWSConfigHandler.cs
index 7e378a9c6..02966e67e 100644
--- a/src/AzureIoTHub.Portal.Infrastructure/ProductionAWSConfigHandler.cs
+++ b/src/AzureIoTHub.Portal.Infrastructure/ProductionAWSConfigHandler.cs
@@ -89,5 +89,7 @@ internal ProductionAWSConfigHandler(IConfiguration config)
public override string AWSRegion => this.config[AWSRegionKey]!;
public override string AWSS3StorageConnectionString => this.config[AWSS3StorageConnectionStringKey]!;
public override string AWSBucketName => this.config[AWSBucketNameKey]!;
+ public override string AWSAccountId => this.config[AWSAccountIdKey]!;
+
}
}
diff --git a/src/AzureIoTHub.Portal.Infrastructure/ProductionAzureConfigHandler.cs b/src/AzureIoTHub.Portal.Infrastructure/ProductionAzureConfigHandler.cs
index 8aba668b6..052d7670a 100644
--- a/src/AzureIoTHub.Portal.Infrastructure/ProductionAzureConfigHandler.cs
+++ b/src/AzureIoTHub.Portal.Infrastructure/ProductionAzureConfigHandler.cs
@@ -92,5 +92,7 @@ internal ProductionAzureConfigHandler(IConfiguration config)
public override string AWSS3StorageConnectionString => throw new NotImplementedException();
public override string AWSBucketName => throw new NotImplementedException();
+ public override string AWSAccountId => throw new NotImplementedException();
+
}
}
diff --git a/src/AzureIoTHub.Portal.Infrastructure/Services/AWS/AwsConfigService.cs b/src/AzureIoTHub.Portal.Infrastructure/Services/AWS/AwsConfigService.cs
index cefd2231d..8b3d9ef29 100644
--- a/src/AzureIoTHub.Portal.Infrastructure/Services/AWS/AwsConfigService.cs
+++ b/src/AzureIoTHub.Portal.Infrastructure/Services/AWS/AwsConfigService.cs
@@ -11,8 +11,11 @@ namespace AzureIoTHub.Portal.Infrastructure.Services.AWS
using Amazon.GreengrassV2.Model;
using Amazon.IoT;
using Amazon.IoT.Model;
+ using AutoMapper;
using AzureIoTHub.Portal.Application.Services;
+ using AzureIoTHub.Portal.Domain;
using AzureIoTHub.Portal.Domain.Exceptions;
+ using AzureIoTHub.Portal.Domain.Repositories;
using AzureIoTHub.Portal.Models.v10;
using AzureIoTHub.Portal.Shared.Models.v10;
using Newtonsoft.Json.Linq;
@@ -23,16 +26,30 @@ public class AwsConfigService : IConfigService
private readonly IAmazonGreengrassV2 greengras;
private readonly IAmazonIoT iotClient;
+ private readonly IUnitOfWork unitOfWork;
+ private readonly IEdgeDeviceModelRepository edgeModelRepository;
+ private readonly ConfigHandler config;
+ private readonly IMapper mapper;
+
public AwsConfigService(
IAmazonGreengrassV2 greengras,
- IAmazonIoT iotClient)
+ IAmazonIoT iot,
+ IMapper mapper,
+ IUnitOfWork unitOfWork,
+ IEdgeDeviceModelRepository edgeModelRepository,
+ ConfigHandler config)
{
this.greengras = greengras;
- this.iotClient = iotClient;
+ this.iotClient = iot;
+ this.mapper = mapper;
+ this.unitOfWork = unitOfWork;
+ this.edgeModelRepository = edgeModelRepository;
+ this.config = config;
}
public async Task RollOutEdgeModelConfiguration(IoTEdgeModel edgeModel)
{
+
var createDeploymentRequest = new CreateDeploymentRequest
{
DeploymentName = edgeModel?.Name,
@@ -47,6 +64,25 @@ public async Task RollOutEdgeModelConfiguration(IoTEdgeModel edgeModel)
throw new InternalServerErrorException("The deployment creation failed due to an error in the Amazon IoT API.");
}
+ else
+ {
+ var edgeModelEntity = await this.edgeModelRepository.GetByIdAsync(edgeModel?.ModelId!);
+ if (edgeModelEntity == null)
+ {
+ throw new Domain.Exceptions.ResourceNotFoundException($"The edge model with id {edgeModel?.ModelId} not found");
+
+ }
+ else
+ {
+ edgeModel!.ExternalIdentifier = createDeploymentResponse.DeploymentId;
+
+ _ = this.mapper.Map(edgeModel, edgeModelEntity);
+
+ this.edgeModelRepository.Update(edgeModelEntity);
+ await this.unitOfWork.SaveAsync();
+ }
+
+ }
}
private async Task GetThingGroupArn(IoTEdgeModel edgeModel)
@@ -118,12 +154,12 @@ private async Task> CreateG
InlineRecipe = recipeStream
};
var response = await greengras.CreateComponentVersionAsync(componentVersion);
- if (response.HttpStatusCode != System.Net.HttpStatusCode.Created)
+ if (response.HttpStatusCode != HttpStatusCode.Created)
{
throw new InternalServerErrorException("The component creation failed due to an error in the Amazon IoT API.");
}
- listcomponentName.Add(component.ModuleName, new ComponentDeploymentSpecification { ComponentVersion = "1.0.0" });
+ listcomponentName.Add(component.ModuleName, new ComponentDeploymentSpecification { ComponentVersion = component.Version });
}
return listcomponentName;
@@ -141,7 +177,7 @@ private static JObject JsonCreateComponent(IoTEdgeModule component)
var recipeJson =new JObject(
new JProperty("RecipeFormatVersion", "2020-01-25"),
new JProperty("ComponentName", component.ModuleName),
- new JProperty("ComponentVersion", "1.0.0"),
+ new JProperty("ComponentVersion", component.Version),
new JProperty("ComponentPublisher", "IotHub"),
new JProperty("ComponentDependencies",
new JObject(
@@ -204,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()
@@ -214,10 +286,143 @@ public Task GetFailedDeploymentsCount()
throw new NotImplementedException();
}
- public Task> GetConfigModuleList(string modelId)
+ public async Task> GetConfigModuleList(string modelId)
{
- // To be implemented with the update method in EdgeModelService
- throw new NotImplementedException();
+
+ var moduleList = new List();
+
+ var getDeployement = new GetDeploymentRequest
+ {
+ DeploymentId = modelId,
+ };
+ try
+ {
+ var response = await this.greengras.GetDeploymentAsync(getDeployement);
+
+ foreach (var compoenent in response.Components)
+ {
+ var responseComponent = await this.greengras.GetComponentAsync(new GetComponentRequest
+ {
+ Arn = $"arn:aws:greengrass:{config.AWSRegion}:{config.AWSAccountId}:components:{compoenent.Key}:versions:{compoenent.Value.ComponentVersion}",
+ RecipeOutputFormat = RecipeOutputFormat.JSON
+ });
+
+ // Read the Recipe which is in JSON Format
+ using var reader = new StreamReader(responseComponent.Recipe);
+ var recipeJsonString = reader.ReadToEnd();
+
+ // Extract the imageUri from the 'Run' JSON object
+ var uriImage = retreiveImageUri("Lifecycle", "Run", recipeJsonString);
+ // Extract the environment Variables from the 'Environment' JSON object
+ var env = retreiveEnvVariableAttr("Lifecycle", "Environment", recipeJsonString);
+
+ var iotEdgeModule = new IoTEdgeModule
+ {
+ ModuleName = compoenent.Key,
+ ImageURI = uriImage,
+ EnvironmentVariables = env,
+ Version = compoenent.Value.ComponentVersion
+ };
+
+ moduleList.Add(iotEdgeModule);
+
+ }
+ return moduleList;
+ }
+ catch (Amazon.IoT.Model.ResourceNotFoundException)
+ {
+ throw new InternalServerErrorException("The deployment is not found");
+
+ }
+ }
+
+ private static string retreiveImageUri(string parent, string child, string recipeJsonString)
+ {
+ var uriImage = "";
+ // Parse the string as a JSON object
+ var recipeJsonObject = JObject.Parse(recipeJsonString);
+
+ // Extract the "Manifests" array
+ var jArray = recipeJsonObject["Manifests"] as JArray;
+ var manifests = jArray;
+
+ if (manifests != null && manifests.Count > 0)
+ {
+ // Get the first manifest in the array
+ var firstManifest = manifests[0] as JObject;
+
+ // Extract the "Lifecycle" object
+ var jObject = firstManifest?[parent] as JObject;
+ var lifecycle = jObject;
+
+ if (lifecycle != null)
+ {
+ // Extract the value of "Run"
+ var runValue = lifecycle[child]?.ToString();
+
+ // Search the index of the 1st whitespace
+ var firstSpaceIndex = runValue.IndexOf(' ');
+
+ if (firstSpaceIndex != -1)
+ {
+ // // Search the index of the 2nd whitespace
+ var secondSpaceIndex = runValue.IndexOf(' ', firstSpaceIndex + 1);
+
+ if (secondSpaceIndex != -1)
+ {
+ // Extract the URI iamge
+ uriImage = runValue[(secondSpaceIndex + 1)..];
+ }
+
+ }
+ }
+ }
+
+ return uriImage;
+ }
+
+ private static List retreiveEnvVariableAttr(string parent, string child, string recipeJsonString)
+ {
+
+ // Parse the string as a JSON object
+ var recipeJsonObject = JObject.Parse(recipeJsonString);
+
+ var environmentVariables = new List();
+
+ // Extract the "Manifests" array
+ var jArray = recipeJsonObject["Manifests"] as JArray;
+ var manifests = jArray;
+
+ if (manifests != null && manifests.Count > 0)
+ {
+ // Get the first manifest in the array
+ var firstManifest = manifests[0] as JObject;
+
+ // Extract the "Lifecycle" object
+ var jObject = firstManifest?[parent] as JObject;
+ var lifecycle = jObject;
+
+ if (lifecycle != null)
+ {
+ // Extract the value of "Environment"
+ var env = lifecycle?[child] as JObject;
+
+ // Convert Environment JSON Object as a dictionnary
+ var keyValuePairs = env!.ToObject>();
+
+ foreach (var kvp in keyValuePairs!)
+ {
+ var iotEnvVariable = new IoTEdgeModuleEnvironmentVariable
+ {
+ Name = kvp.Key,
+ Value = kvp.Value
+ };
+
+ environmentVariables.Add(iotEnvVariable);
+ }
+ }
+ }
+ return environmentVariables;
}
public Task> GetModelSystemModule(string modelId)
diff --git a/src/AzureIoTHub.Portal.Infrastructure/Services/EdgeModelService.cs b/src/AzureIoTHub.Portal.Infrastructure/Services/EdgeModelService.cs
index 83fe5de22..96087e3a9 100644
--- a/src/AzureIoTHub.Portal.Infrastructure/Services/EdgeModelService.cs
+++ b/src/AzureIoTHub.Portal.Infrastructure/Services/EdgeModelService.cs
@@ -117,11 +117,14 @@ public async Task CreateEdgeModel(IoTEdgeModel edgeModel)
_ = await this.deviceModelImageManager.SetDefaultImageToModel(edgeModel?.ModelId);
+
if (this.config.CloudProvider.Equals(CloudProviders.Azure, StringComparison.Ordinal))
{
await SaveModuleCommands(edgeModel);
}
+
await this.configService.RollOutEdgeModelConfiguration(edgeModel);
+
}
///
@@ -171,20 +174,20 @@ public async Task GetEdgeModel(string modelId)
}
if (config.CloudProvider.Equals(CloudProviders.Azure, StringComparison.OrdinalIgnoreCase))
{
- return await GetAzureEdgeModel(modelId, edgeModelEntity);
+ return await GetAzureEdgeModel(edgeModelEntity);
}
else
{
- return await GetAwsEdgeModel(modelId, edgeModelEntity);
+ return await GetAwsEdgeModel(edgeModelEntity);
}
}
- private async Task GetAzureEdgeModel(string modelId, EdgeDeviceModel edgeModelEntity)
+ private async Task GetAzureEdgeModel(EdgeDeviceModel edgeModelEntity)
{
- var modules = await this.configService.GetConfigModuleList(modelId);
- var sysModules = await this.configService.GetModelSystemModule(modelId);
- var routes = await this.configService.GetConfigRouteList(modelId);
- var commands = this.commandRepository.GetAll().Where(x => x.EdgeDeviceModelId == modelId).ToList();
+ var modules = await this.configService.GetConfigModuleList(edgeModelEntity.Id);
+ var sysModules = await this.configService.GetModelSystemModule(edgeModelEntity.Id);
+ var routes = await this.configService.GetConfigRouteList(edgeModelEntity.Id);
+ var commands = this.commandRepository.GetAll().Where(x => x.EdgeDeviceModelId == edgeModelEntity.Id).ToList();
//TODO : User a mapper
//Previously return this.edgeDeviceModelMapper.CreateEdgeDeviceModel(query.Value, modules, routes, commands);
@@ -214,9 +217,9 @@ private async Task GetAzureEdgeModel(string modelId, EdgeDeviceMod
return result;
}
- private async Task GetAwsEdgeModel(string modelId, EdgeDeviceModel edgeModelEntity)
+ private async Task GetAwsEdgeModel(EdgeDeviceModel edgeModelEntity)
{
- var modules = await this.configService.GetConfigModuleList(modelId);
+ 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
@@ -257,7 +260,11 @@ public async Task UpdateEdgeModel(IoTEdgeModel edgeModel)
await this.unitOfWork.SaveAsync();
- await SaveModuleCommands(edgeModel);
+ if (this.config.CloudProvider.Equals(CloudProviders.Azure, StringComparison.Ordinal))
+ {
+ await SaveModuleCommands(edgeModel);
+ }
+
await this.configService.RollOutEdgeModelConfiguration(edgeModel);
}
@@ -275,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/20230525074805_Add Aws DeploymentId.Designer.cs b/src/AzureIoTHub.Portal.Postgres/Migrations/20230525074805_Add Aws DeploymentId.Designer.cs
new file mode 100644
index 000000000..64895a388
--- /dev/null
+++ b/src/AzureIoTHub.Portal.Postgres/Migrations/20230525074805_Add Aws DeploymentId.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("20230525074805_Add Aws DeploymentId")]
+ partial class AddAwsDeploymentId
+ {
+ ///
+ 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("IdProvider")
+ .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/20230525074805_Add Aws DeploymentId.cs b/src/AzureIoTHub.Portal.Postgres/Migrations/20230525074805_Add Aws DeploymentId.cs
new file mode 100644
index 000000000..c7b3d7174
--- /dev/null
+++ b/src/AzureIoTHub.Portal.Postgres/Migrations/20230525074805_Add Aws DeploymentId.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 AddAwsDeploymentId : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ _ = migrationBuilder.AddColumn(
+ name: "IdProvider",
+ table: "EdgeDeviceModels",
+ type: "text",
+ nullable: true);
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ _ = migrationBuilder.DropColumn(
+ name: "IdProvider",
+ table: "EdgeDeviceModels");
+ }
+ }
+}
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 2a1d1045c..27a95859e 100644
--- a/src/AzureIoTHub.Portal.Postgres/Migrations/PortalDbContextModelSnapshot.cs
+++ b/src/AzureIoTHub.Portal.Postgres/Migrations/PortalDbContextModelSnapshot.cs
@@ -1,4 +1,4 @@
-//
+//
using System;
using AzureIoTHub.Portal.Infrastructure;
using Microsoft.EntityFrameworkCore;
@@ -23,561 +23,564 @@ protected override void BuildModel(ModelBuilder modelBuilder)
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.Concentrator", b =>
- {
- b.Property("Id")
- .HasColumnType("text");
+ {
+ b.Property("Id")
+ .HasColumnType("text");
- b.Property("ClientThumbprint")
- .HasColumnType("text");
+ b.Property("ClientThumbprint")
+ .HasColumnType("text");
- b.Property