diff --git a/src/AzureIoTHub.Portal.Infrastructure/Jobs/AWS/SyncThingTypesJob.cs b/src/AzureIoTHub.Portal.Infrastructure/Jobs/AWS/SyncThingTypesJob.cs index 0069afc2b..6f728761d 100644 --- a/src/AzureIoTHub.Portal.Infrastructure/Jobs/AWS/SyncThingTypesJob.cs +++ b/src/AzureIoTHub.Portal.Infrastructure/Jobs/AWS/SyncThingTypesJob.cs @@ -1,77 +1,124 @@ -// 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.Jobs.AWS -{ - using System.Threading.Tasks; - using Amazon.IoT; - using Amazon.IoT.Model; - using AutoMapper; - using AzureIoTHub.Portal.Application.Managers; +// 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.Jobs.AWS +{ + using System.Threading.Tasks; + using Amazon.IoT; + using Amazon.IoT.Model; + using AutoMapper; + using AzureIoTHub.Portal.Application.Managers; using AzureIoTHub.Portal.Domain; using AzureIoTHub.Portal.Domain.Entities; using AzureIoTHub.Portal.Domain.Repositories; - using Microsoft.Extensions.Logging; - using Quartz; - - [DisallowConcurrentExecution] - public class SyncThingTypesJob : IJob + using Microsoft.Extensions.Logging; + using Quartz; + + [DisallowConcurrentExecution] + public class SyncThingTypesJob : IJob { - private readonly ILogger logger; - private readonly IMapper mapper; - private readonly IUnitOfWork unitOfWork; - private readonly IDeviceModelRepository deviceModelRepository; - private readonly IAmazonIoT amazonIoTClient; - private readonly IDeviceModelImageManager deviceModelImageManager; - - public SyncThingTypesJob( - ILogger logger, - IMapper mapper, + private readonly ILogger logger; + private readonly IMapper mapper; + private readonly IUnitOfWork unitOfWork; + private readonly IDeviceModelRepository deviceModelRepository; + private readonly IAmazonIoT amazonIoTClient; + private readonly IDeviceModelImageManager deviceModelImageManager; + + public SyncThingTypesJob( + ILogger logger, + IMapper mapper, IUnitOfWork unitOfWork, - IDeviceModelRepository deviceModelRepository, + IDeviceModelRepository deviceModelRepository, IAmazonIoT amazonIoTClient, - IDeviceModelImageManager awsImageManager) - { - this.deviceModelImageManager = awsImageManager; - this.mapper = mapper; + IDeviceModelImageManager awsImageManager) + { + this.deviceModelImageManager = awsImageManager; + this.mapper = mapper; this.unitOfWork = unitOfWork; - this.deviceModelRepository = deviceModelRepository; - this.amazonIoTClient = amazonIoTClient; - this.logger = logger; - } - - - public async Task Execute(IJobExecutionContext context) - { - try - { - this.logger.LogInformation("Start of sync Thing Types job"); - - await SyncThingTypesAsDeviceModels(); - - this.logger.LogInformation("End of sync Thing Types job"); - } - catch (Exception e) - { - this.logger.LogError(e, "Sync Thing Types job has failed"); - } - } - - private async Task SyncThingTypesAsDeviceModels() - { + this.deviceModelRepository = deviceModelRepository; + this.amazonIoTClient = amazonIoTClient; + this.logger = logger; + } + + + public async Task Execute(IJobExecutionContext context) + { + try + { + this.logger.LogInformation("Start of sync Thing Types job"); + + await SyncThingTypesAsDeviceModels(); + + this.logger.LogInformation("End of sync Thing Types job"); + } + catch (Exception e) + { + this.logger.LogError(e, "Sync Thing Types job has failed"); + } + } + + private async Task SyncThingTypesAsDeviceModels() + { var thingTypes = await GetAllThingTypes(); foreach (var thingType in thingTypes) { - await CreateOrUpdateDeviceModel(thingType); - } - - //Delete in Database AWS deleted thing types - await DeleteThingTypes(thingTypes); - } - - private async Task> GetAllThingTypes() + var isEdge = await IsEdgeThingType(thingType); + + // Cannot know if the thing type was created for an iotEdge or not, so skipping... + if (!isEdge.HasValue) + { + continue; + } + + if (isEdge == true) + { + // TODO: Implement CreateOrUpdateEdgeModel here. + } + else + { + await CreateOrUpdateDeviceModel(thingType); + } + } + + // Delete in Database AWS deleted thing types + await DeleteThingTypes(thingTypes); + } + + private async Task IsEdgeThingType(DescribeThingTypeResponse thingType) + { + var response = await this.amazonIoTClient.ListTagsForResourceAsync(new ListTagsForResourceRequest + { + ResourceArn = thingType.ThingTypeArn + }); + + do + { + if (response == null || !response.Tags.Any()) + { + return null; + } + + var iotEdgeTag = response.Tags.Where(c => c.Key.Equals("iotEdge", StringComparison.OrdinalIgnoreCase)); + + if (!iotEdgeTag.Any()) + { + response = await this.amazonIoTClient.ListTagsForResourceAsync(new ListTagsForResourceRequest + { + ResourceArn = thingType.ThingTypeArn, + NextToken = response.NextToken + }); + + continue; + } + + return bool.TryParse(iotEdgeTag.Single().Value, out var result) ? result : null; + + } while (true); + } + + private async Task> GetAllThingTypes() { var thingTypes = new List(); @@ -88,9 +135,9 @@ private async Task> GetAllThingTypes() foreach (var thingType in response.ThingTypes) { - var requestDescribeThingType = new DescribeThingTypeRequest - { - ThingTypeName = thingType.ThingTypeName, + var requestDescribeThingType = new DescribeThingTypeRequest + { + ThingTypeName = thingType.ThingTypeName, }; thingTypes.Add(await this.amazonIoTClient.DescribeThingTypeAsync(requestDescribeThingType)); @@ -98,37 +145,37 @@ private async Task> GetAllThingTypes() nextToken = response.NextToken; } - while (!string.IsNullOrEmpty(nextToken)); - - return thingTypes; - } - - private async Task CreateOrUpdateDeviceModel(DescribeThingTypeResponse thingType) + while (!string.IsNullOrEmpty(nextToken)); + + return thingTypes; + } + + private async Task CreateOrUpdateDeviceModel(DescribeThingTypeResponse thingType) { if (thingType.ThingTypeMetadata.Deprecated) { return; } - + var deviceModel = this.mapper.Map(thingType); - var existingDeviceModel = await this.deviceModelRepository.GetByIdAsync(deviceModel.Id); - - if (existingDeviceModel == null) - { - await this.deviceModelRepository.InsertAsync(deviceModel); - _ = await this.deviceModelImageManager.SetDefaultImageToModel(deviceModel.Id); - } - else - { - _ = this.mapper.Map(deviceModel, existingDeviceModel); - this.deviceModelRepository.Update(existingDeviceModel); - } - await this.unitOfWork.SaveAsync(); - - } - - private async Task DeleteThingTypes(List thingTypes) + var existingDeviceModel = await this.deviceModelRepository.GetByIdAsync(deviceModel.Id); + + if (existingDeviceModel == null) + { + await this.deviceModelRepository.InsertAsync(deviceModel); + _ = await this.deviceModelImageManager.SetDefaultImageToModel(deviceModel.Id); + } + else + { + _ = this.mapper.Map(deviceModel, existingDeviceModel); + this.deviceModelRepository.Update(existingDeviceModel); + } + + await this.unitOfWork.SaveAsync(); + } + + private async Task DeleteThingTypes(List thingTypes) { // Get all device models that are not in AWS anymore or that are deprecated var deviceModelsToDelete = (await this.deviceModelRepository.GetAllAsync()) @@ -140,10 +187,10 @@ private async Task DeleteThingTypes(List thingTypes) { await this.deviceModelImageManager.DeleteDeviceModelImageAsync(deviceModel.Id); this.deviceModelRepository.Delete(deviceModel.Id); - }); - - await this.unitOfWork.SaveAsync(); - } - - } -} + }); + + await this.unitOfWork.SaveAsync(); + } + + } +} diff --git a/src/AzureIoTHub.Portal.Infrastructure/Services/AwsExternalDeviceService.cs b/src/AzureIoTHub.Portal.Infrastructure/Services/AwsExternalDeviceService.cs index 3a2e21322..343f70ea6 100644 --- a/src/AzureIoTHub.Portal.Infrastructure/Services/AwsExternalDeviceService.cs +++ b/src/AzureIoTHub.Portal.Infrastructure/Services/AwsExternalDeviceService.cs @@ -37,6 +37,12 @@ public async Task CreateDeviceModel(ExternalDeviceModelD var createThingTypeRequest = this.mapper.Map(thingType); + createThingTypeRequest.Tags.Add(new Tag + { + Key = "iotEdge", + Value = "False" + }); + var response = await this.amazonIoTClient.CreateThingTypeAsync(createThingTypeRequest); deviceModel.Id = response.ThingTypeId; diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/Jobs/AWS/SyncThingTypesJobTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/Jobs/AWS/SyncThingTypesJobTests.cs index 835897b89..72ce13cfc 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/Jobs/AWS/SyncThingTypesJobTests.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/Jobs/AWS/SyncThingTypesJobTests.cs @@ -88,6 +88,7 @@ public async Task Execute_SyncNewAndExistingAndDepprecatedThingTypes_DeviceModel var existingThingType = new DescribeThingTypeResponse { + ThingTypeArn = Fixture.Create(), ThingTypeId = existingDeviceModelName, ThingTypeName = existingDeviceModelName, ThingTypeMetadata = new ThingTypeMetadata() @@ -95,6 +96,7 @@ public async Task Execute_SyncNewAndExistingAndDepprecatedThingTypes_DeviceModel var newThingType = new DescribeThingTypeResponse { + ThingTypeArn = Fixture.Create(), ThingTypeId = newDeviceModelName, ThingTypeName = newDeviceModelName, ThingTypeMetadata = new ThingTypeMetadata() @@ -102,6 +104,7 @@ public async Task Execute_SyncNewAndExistingAndDepprecatedThingTypes_DeviceModel var depcrecatedThingType = new DescribeThingTypeResponse { + ThingTypeArn = Fixture.Create(), ThingTypeId = depcrecatedDeviceModelName, ThingTypeName = depcrecatedDeviceModelName, ThingTypeMetadata = new ThingTypeMetadata @@ -117,6 +120,20 @@ public async Task Execute_SyncNewAndExistingAndDepprecatedThingTypes_DeviceModel _ = this.iaAmazon.Setup(client => client.DescribeThingTypeAsync(It.Is(c => c.ThingTypeName == depcrecatedThingType.ThingTypeName), It.IsAny())) .ReturnsAsync(depcrecatedThingType); + _ = this.iaAmazon.Setup(client => client.ListTagsForResourceAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new ListTagsForResourceResponse + { + NextToken = Fixture.Create(), + Tags = new List + { + new Tag + { + Key = "iotEdge", + Value = "False" + } + } + }); + var existingDeviceModel = new DeviceModel { Id = existingDeviceModelName,