Skip to content

Commit

Permalink
#1929 Configuration logic by provider
Browse files Browse the repository at this point in the history
- Add CloudProvider dependencies to the Server Startup
- Add CloudProvider dependencies to the Infrastructure Startup
- Azure first in the switch to unify
  • Loading branch information
delager committed Apr 3, 2023
1 parent 34899e1 commit 0d350f9
Show file tree
Hide file tree
Showing 5 changed files with 323 additions and 241 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ public static ConfigHandler Create(IHostEnvironment env, IConfiguration config)
{
return config[ConfigHandlerBase.CloudProviderKey] switch
{
CloudProviders.AWS => new ProductionAWSConfigHandler(config),
CloudProviders.Azure => new ProductionAzureConfigHandler(config),
CloudProviders.AWS => new ProductionAWSConfigHandler(config),
_ => throw new InvalidCloudProviderException(ErrorTitles.InvalidCloudProviderIncorrect),
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// 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.Startup
{
using AzureIoTHub.Portal.Infrastructure.ServicesHealthCheck;
using Microsoft.Extensions.DependencyInjection;

public static class AWSServiceCollectionExtension
{
public static IServiceCollection AddAWSInfrastructureLayer(this IServiceCollection services)
{
return services.ConfigureHealthCheck();
}
private static IServiceCollection ConfigureHealthCheck(this IServiceCollection services)
{
_ = services.AddHealthChecks()
.AddDbContextCheck<PortalDbContext>()
.AddCheck<DatabaseHealthCheck>("databaseHealthCheck");

return services;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
// 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.Startup
{
using System.Net;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using AzureIoTHub.Portal.Application.Managers;
using AzureIoTHub.Portal.Application.Mappers;
using AzureIoTHub.Portal.Application.Providers;
using AzureIoTHub.Portal.Application.Services;
using AzureIoTHub.Portal.Application.Wrappers;
using AzureIoTHub.Portal.Domain;
using AzureIoTHub.Portal.Domain.Options;
using AzureIoTHub.Portal.Domain.Repositories;
using AzureIoTHub.Portal.Infrastructure.Extensions;
using AzureIoTHub.Portal.Infrastructure.Jobs;
using AzureIoTHub.Portal.Infrastructure.Managers;
using AzureIoTHub.Portal.Infrastructure.Mappers;
using AzureIoTHub.Portal.Infrastructure.Providers;
using AzureIoTHub.Portal.Infrastructure.Repositories;
using AzureIoTHub.Portal.Infrastructure.Services;
using AzureIoTHub.Portal.Infrastructure.ServicesHealthCheck;
using AzureIoTHub.Portal.Infrastructure.Wrappers;
using AzureIoTHub.Portal.Models.v10;
using AzureIoTHub.Portal.Models.v10.LoRaWAN;
using Microsoft.Azure.Devices;
using Microsoft.Azure.Devices.Provisioning.Service;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Polly;
using Polly.Extensions.Http;
using Quartz;

public static class AzureServiceCollectionExtension
{
public static IServiceCollection AddAzureInfrastructureLayer(this IServiceCollection services, ConfigHandler configuration)
{
return services.ConfigureRepositories()
.ConfigureImageBlobStorage(configuration)
.AddLoRaWanSupport(configuration)
.ConfigureDeviceRegstryDependencies(configuration)
.ConfigureServices()
.ConfigureMappers()
.ConfigureHealthCheck()
.ConfigureMetricsJobs(configuration)
.ConfigureSyncJobs(configuration);
}

private static IServiceCollection AddLoRaWanSupport(this IServiceCollection services, ConfigHandler configuration)
{
_ = services.Configure<LoRaWANOptions>(opts =>
{
opts.Enabled = configuration.IsLoRaEnabled;
opts.KeyManagementApiVersion = configuration.LoRaKeyManagementApiVersion;
opts.KeyManagementCode = configuration.LoRaKeyManagementCode;
opts.KeyManagementUrl = configuration.LoRaKeyManagementUrl;
});

if (!configuration.IsLoRaEnabled)
{
return services;
}

var transientHttpErrorPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(c => c.StatusCode == HttpStatusCode.NotFound)
.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(100));

_ = services.AddHttpClient("RestClient")
.AddPolicyHandler(transientHttpErrorPolicy);

_ = services.AddHttpClient<ILoRaWanManagementService, LoRaWanManagementService>((sp, client) =>
{
var opts = sp.GetService<IOptions<LoRaWANOptions>>()?.Value;

client.BaseAddress = new Uri(opts?.KeyManagementUrl!);
client.DefaultRequestHeaders.Add("x-functions-key", opts?.KeyManagementCode);
client.DefaultRequestHeaders.Add("api-version", opts?.KeyManagementApiVersion ?? "2022-03-04");
})
.AddPolicyHandler(transientHttpErrorPolicy);

return services;
}

private static IServiceCollection ConfigureDeviceRegstryDependencies(this IServiceCollection services, ConfigHandler configuration)
{
_ = services.AddTransient<IProvisioningServiceClient, ProvisioningServiceClientWrapper>();
_ = services.AddTransient<IDeviceRegistryProvider, AzureDeviceRegistryProvider>();

_ = services.AddScoped(_ => RegistryManager.CreateFromConnectionString(configuration.IoTHubConnectionString));
_ = services.AddScoped(_ => ServiceClient.CreateFromConnectionString(configuration.IoTHubConnectionString));
_ = services.AddScoped(_ => ProvisioningServiceClient.CreateFromConnectionString(configuration.DPSConnectionString));

return services;
}

private static IServiceCollection ConfigureRepositories(this IServiceCollection services)
{
return services.AddScoped<IDeviceModelPropertiesRepository, DeviceModelPropertiesRepository>()
.AddScoped<IDeviceTagRepository, DeviceTagRepository>()
.AddScoped<IEdgeDeviceModelRepository, EdgeDeviceModelRepository>()
.AddScoped<IEdgeDeviceModelCommandRepository, EdgeDeviceModelCommandRepository>()
.AddScoped<IDeviceModelRepository, DeviceModelRepository>()
.AddScoped<IDeviceRepository, DeviceRepository>()
.AddScoped<IEdgeDeviceRepository, EdgeDeviceRepository>()
.AddScoped<ILorawanDeviceRepository, LorawanDeviceRepository>()
.AddScoped<IDeviceTagValueRepository, DeviceTagValueRepository>()
.AddScoped<IDeviceModelCommandRepository, DeviceModelCommandRepository>()
.AddScoped<IConcentratorRepository, ConcentratorRepository>()
.AddScoped<ILoRaDeviceTelemetryRepository, LoRaDeviceTelemetryRepository>()
.AddScoped<ILabelRepository, LabelRepository>();
}

private static IServiceCollection ConfigureMappers(this IServiceCollection services)
{
_ = services.AddTransient<IDeviceModelImageManager, DeviceModelImageManager>();
_ = services.AddTransient<IConcentratorTwinMapper, ConcentratorTwinMapper>();
_ = services.AddTransient<IDeviceModelCommandMapper, DeviceModelCommandMapper>();

return services.AddTransient<IDeviceTwinMapper<DeviceListItem, DeviceDetails>, DeviceTwinMapper>()
.AddTransient<IDeviceTwinMapper<DeviceListItem, LoRaDeviceDetails>, LoRaDeviceTwinMapper>()
.AddTransient<IDeviceModelMapper<DeviceModelDto, DeviceModelDto>, DeviceModelMapper>()
.AddTransient<IDeviceModelMapper<DeviceModelDto, LoRaDeviceModelDto>, LoRaDeviceModelMapper>()
.AddTransient<IEdgeDeviceMapper, EdgeDeviceMapper>();
}

private static IServiceCollection ConfigureServices(this IServiceCollection services)
{
return services.AddTransient<ILoRaWanManagementService, LoRaWanManagementService>();
}

private static IServiceCollection ConfigureHealthCheck(this IServiceCollection services)
{
_ = services.AddHealthChecks()
.AddDbContextCheck<PortalDbContext>()
.AddCheck<IoTHubHealthCheck>("iothubHealth")
.AddCheck<StorageAccountHealthCheck>("storageAccountHealth")
.AddCheck<TableStorageHealthCheck>("tableStorageHealth")
.AddCheck<ProvisioningServiceClientHealthCheck>("dpsHealth")
.AddCheck<LoRaManagementKeyFacadeHealthCheck>("loraManagementFacadeHealth")
.AddCheck<DatabaseHealthCheck>("databaseHealthCheck");

return services;
}

private static IServiceCollection ConfigureImageBlobStorage(this IServiceCollection services, ConfigHandler configuration)
{
return services.AddTransient(_ => new BlobServiceClient(configuration.StorageAccountConnectionString))
.Configure<DeviceModelImageOptions>((opts) =>
{
var serviceClient = new BlobServiceClient(configuration.StorageAccountConnectionString);
var container = serviceClient.GetBlobContainerClient(opts.ImageContainerName);

_ = container.SetAccessPolicy(PublicAccessType.Blob);
_ = container.CreateIfNotExists();

opts.BaseUri = container.Uri;
});
}

private static IServiceCollection ConfigureMetricsJobs(this IServiceCollection services, ConfigHandler configuration)
{
return services.AddQuartz(q =>
{
q.AddMetricsService<DeviceMetricExporterJob, DeviceMetricLoaderJob>(configuration);
q.AddMetricsService<EdgeDeviceMetricExporterJob, EdgeDeviceMetricLoaderJob>(configuration);
q.AddMetricsService<ConcentratorMetricExporterJob, ConcentratorMetricLoaderJob>(configuration);
});
}

private static IServiceCollection ConfigureSyncJobs(this IServiceCollection services, ConfigHandler configuration)
{
return services.AddQuartz(q =>
{
_ = q.AddJob<SyncDevicesJob>(j => j.WithIdentity(nameof(SyncDevicesJob)))
.AddTrigger(t => t
.WithIdentity($"{nameof(SyncDevicesJob)}")
.ForJob(nameof(SyncDevicesJob))
.WithSimpleSchedule(s => s
.WithIntervalInMinutes(configuration.SyncDatabaseJobRefreshIntervalInMinutes)
.RepeatForever()));

_ = q.AddJob<SyncConcentratorsJob>(j => j.WithIdentity(nameof(SyncConcentratorsJob)))
.AddTrigger(t => t
.WithIdentity($"{nameof(SyncConcentratorsJob)}")
.ForJob(nameof(SyncConcentratorsJob))
.WithSimpleSchedule(s => s
.WithIntervalInMinutes(configuration.SyncDatabaseJobRefreshIntervalInMinutes)
.RepeatForever()));

_ = q.AddJob<SyncEdgeDeviceJob>(j => j.WithIdentity(nameof(SyncEdgeDeviceJob)))
.AddTrigger(t => t
.WithIdentity($"{nameof(SyncEdgeDeviceJob)}")
.ForJob(nameof(SyncEdgeDeviceJob))
.WithSimpleSchedule(s => s
.WithIntervalInMinutes(configuration.SyncDatabaseJobRefreshIntervalInMinutes)
.RepeatForever()));

_ = q.AddJob<SyncGatewayIDJob>(j => j.WithIdentity(nameof(SyncGatewayIDJob)))
.AddTrigger(t => t
.WithIdentity($"{nameof(SyncGatewayIDJob)}")
.ForJob(nameof(SyncGatewayIDJob))
.WithSimpleSchedule(s => s
.WithIntervalInMinutes(configuration.SyncDatabaseJobRefreshIntervalInMinutes)
.RepeatForever()));

if (configuration.IsLoRaEnabled)
{
_ = q.AddJob<SyncLoRaDeviceTelemetryJob>(j => j.WithIdentity(nameof(SyncLoRaDeviceTelemetryJob)))
.AddTrigger(t => t
.WithIdentity($"{nameof(SyncLoRaDeviceTelemetryJob)}")
.ForJob(nameof(SyncLoRaDeviceTelemetryJob))
.StartAt(DateTimeOffset.Now.AddMinutes(1)));
}
});
}
}
}
Loading

0 comments on commit 0d350f9

Please sign in to comment.