diff --git a/README.md b/README.md index 3405cfc..62ca4b6 100644 --- a/README.md +++ b/README.md @@ -33,13 +33,17 @@ IoT library, which contains common services for Azure IotHub, DeviceProvisioning - [Method](#method-1) - [Module Retrieval](#module-retrieval) - [Usage Example](#usage-example-3) -- [CLI](#cli) - - [Installation](#installation) + - [IConfigurationContentProvider](#iconfigurationcontentprovider) + - [Features](#features-4) + - [Methods](#methods-2) + - [Configuration Content Retrieval from File](#configuration-content-retrieval-from-file) + - [Configuration Content Retrieval from Stream](#configuration-content-retrieval-from-stream) + - [Usage Example](#usage-example-4) - [Update](#update) - [Usage](#usage) - [Option --help](#option---help) - [Atc.Azure.IoTEdge](#atcazureiotedge) - - [Features](#features-4) + - [Features](#features-5) - [Extensions](#extensions) - [Factories](#factories) - [Wrappers](#wrappers) @@ -83,6 +87,7 @@ The `IIoTHubService` is designed to facilitate communication with Azure IoT Hub, ### Methods #### Device Management + - `CreateDevice(string deviceId, bool edgeEnabled, CancellationToken cancellationToken)`: Create a new device with the option to enable as an edge device. - `DeleteDevice(string deviceId, CancellationToken cancellationToken)`: Delete a device from the IoT Hub. - `GetDevice(string deviceId, CancellationToken cancellationToken)`: Retrieve a specific device using its device ID. @@ -95,6 +100,7 @@ The `IIoTHubService` is designed to facilitate communication with Azure IoT Hub, - `GetDeviceTwins(bool onlyIncludeEdgeDevices)`: Retrieve all device twins, with an option to filter for only edge devices. #### Module Management + - `GetModuleTwin(string deviceId, string moduleId, CancellationToken cancellationToken)`: Retrieve a specific module twin. - `UpdateDesiredProperties(string deviceId, string moduleId, TwinCollection twinCollection, CancellationToken cancellationToken)`: Update desired properties on a module twin. - `RemoveModuleFromDevice(string deviceId, string moduleId, CancellationToken cancellationToken)`: Remove a module from an IoT device. @@ -145,6 +151,7 @@ The `IIoTHubModuleService` is tailored for direct interactions with IoT devices ### Method #### Direct Method Invocation + - `CallMethod(string deviceId, string moduleId, MethodParameterModel parameters, CancellationToken cancellationToken)`: This method sends a direct command to a specified module on a device. The `MethodParameterModel` allows for detailed specification of the command, and the operation returns a `MethodResultModel` that includes the status of the call and any resultant data in JSON format. ### Usage Example @@ -183,6 +190,7 @@ The `IDeviceProvisioningService` is designed to manage device enrollments within ### Methods #### Individual Enrollment Management + - `GetIndividualEnrollment(string registrationId, CancellationToken cancellationToken)`: Retrieves a specific enrollment using the registration ID. - `GetIndividualEnrollments(CancellationToken cancellationToken)`: Fetches all registered individual enrollments. - `CreateIndividualTpmEnrollment(string endorsementKey, string registrationId, string deviceId, Dictionary? tags, Dictionary? desiredProperties, CancellationToken cancellationToken)`: Creates or updates a TPM enrollment with specified parameters. @@ -253,6 +261,7 @@ The `IDeviceTwinModuleExtractor` is designed to aid in extracting module informa ### Method #### Module Retrieval + - `GetModuleFromEdgeAgentTwin(Twin twin, string moduleId)`: Extracts a module from the Edge Agent twin using the module identifier. This method is essential for operations needing detailed information about individual modules managed by the Edge Agent. ### Usage Example @@ -276,6 +285,44 @@ else } ``` +## IConfigurationContentProvider + +The `IConfigurationContentProvider` is designed to assist in retrieving configuration content from deployment manifests in Azure IoT solutions. This interface provides methods for obtaining configuration content from both file and stream sources, ensuring flexibility and reliability in handling deployment manifests. + +### Features + +- **Configuration Content Retrieval**: Extract configuration content from deployment manifests, facilitating efficient deployment and management of IoT modules. + +### Methods + +#### Configuration Content Retrieval from File + +- `GetConfigurationContent(FileInfo deploymentManifestFileInfo, CancellationToken cancellationToken)`: Retrieves configuration content from a deployment manifest file. + +#### Configuration Content Retrieval from Stream + +- `GetConfigurationContent(Stream deploymentManifestFileStream, CancellationToken cancellationToken)`: Retrieves configuration content from a deployment manifest stream. + +### Usage Example + +Below is an example demonstrating how to use the `ConfigurationContentProvider` to retrieve configuration content from a deployment manifest file: + +```csharp +var configurationContentProvider = serviceProvider.GetRequiredService(); +var deploymentManifestFile = new FileInfo("path/to/deploymentManifest.json"); +var cancellationToken = new CancellationToken(); + +var (configurationContent, errorMessage) = await configurationContentProvider.GetConfigurationContent(deploymentManifestFile, cancellationToken); + +if (configurationContent != null) +{ + Console.WriteLine("Configuration content retrieved successfully."); +} +else +{ + Console.WriteLine($"Failed to retrieve configuration content: {errorMessage}"); +} + # CLI [![NuGet Version](https://img.shields.io/nuget/v/atc-azure-iot.svg?logo=nuget&style=for-the-badge)](https://www.nuget.org/packages/atc-azure-iot) diff --git a/src/Atc.Azure.IoT/Extensions/ServiceCollectionExtensions.cs b/src/Atc.Azure.IoT/Extensions/ServiceCollectionExtensions.cs index f8d788a..4681e39 100644 --- a/src/Atc.Azure.IoT/Extensions/ServiceCollectionExtensions.cs +++ b/src/Atc.Azure.IoT/Extensions/ServiceCollectionExtensions.cs @@ -56,6 +56,8 @@ public static IServiceCollection ConfigureDeviceProvisioningServices( throw new InvalidOperationException($"Required service '{nameof(DeviceProvisioningServiceOptions)}' is not registered"); } + services.TryAddSingleton(); + services.AddSingleton(s => new DeviceProvisioningService( s.GetRequiredService(), deviceProvisioningServiceOptions)); diff --git a/src/Atc.Azure.IoT/GlobalUsings.cs b/src/Atc.Azure.IoT/GlobalUsings.cs index 2b2fa2b..32d56c7 100644 --- a/src/Atc.Azure.IoT/GlobalUsings.cs +++ b/src/Atc.Azure.IoT/GlobalUsings.cs @@ -8,6 +8,7 @@ global using Atc.Azure.IoT.Extractors; global using Atc.Azure.IoT.Models; global using Atc.Azure.IoT.Options; +global using Atc.Azure.IoT.Providers; global using Atc.Azure.IoT.Serialization.JsonConverters; global using Atc.Azure.IoT.Services.DeviceProvisioning; global using Atc.Azure.IoT.Services.IoTHub; diff --git a/src/Atc.Azure.IoT/Providers/ConfigurationContentProvider.cs b/src/Atc.Azure.IoT/Providers/ConfigurationContentProvider.cs new file mode 100644 index 0000000..95c2f5b --- /dev/null +++ b/src/Atc.Azure.IoT/Providers/ConfigurationContentProvider.cs @@ -0,0 +1,71 @@ +namespace Atc.Azure.IoT.Providers; + +public sealed class ConfigurationContentProvider : IConfigurationContentProvider +{ + public async Task<(ConfigurationContent? ConfigurationContent, string? ErrorMessage)> GetConfigurationContent( + FileInfo deploymentManifestFileInfo, + CancellationToken cancellationToken) + { + if (!deploymentManifestFileInfo.Exists) + { + return (null, "Deployment Manifest file does not exist."); + } + + try + { + await using var fileStream = deploymentManifestFileInfo.OpenRead(); + return await GetConfigurationContent(fileStream, cancellationToken); + } + catch (Exception ex) + { + return (null, $"Error reading Deployment Manifest file: {ex.Message}"); + } + } + + public async Task<(ConfigurationContent? ConfigurationContent, string? ErrorMessage)> GetConfigurationContent( + Stream deploymentManifestFileStream, + CancellationToken cancellationToken) + { + var templateContent = await GetTemplateContent(deploymentManifestFileStream, cancellationToken); + if (templateContent is null) + { + return (null, "Deployment Manifest was not in proper format."); + } + + var configurationContent = GetConfigurationContentFromManifest(templateContent!); + if (configurationContent is null) + { + return (null, "Could not get ConfigurationContent from Deployment Manifest."); + } + + return (configurationContent, null); + } + + private static async Task GetTemplateContent( + Stream deploymentManifestFileStream, + CancellationToken cancellationToken) + { + using var reader = new StreamReader(deploymentManifestFileStream); + var content = await reader.ReadToEndAsync(cancellationToken); + + return content.IsFormatJson() + ? content + : null; + } + + /// + /// Gets the ConfigurationContent from the deployment manifest + /// + /// The deployment manifest + /// The deployment manifest as a + /// + /// We utilize Newtonsoft.Json here, because System.Text.Json does not work! + /// When de-serializing the edgeAgent - properties.desired, instead of "object-array", the serializer returns: + /// ValueKind = Object : " instead of { + /// and " instead of } (for the end). + /// + private static ConfigurationContent? GetConfigurationContentFromManifest( + string deploymentManifest) + => Newtonsoft.Json.JsonConvert.DeserializeObject( + deploymentManifest); +} \ No newline at end of file diff --git a/src/Atc.Azure.IoT/Providers/IConfigurationContentProvider.cs b/src/Atc.Azure.IoT/Providers/IConfigurationContentProvider.cs new file mode 100644 index 0000000..1f0c5a5 --- /dev/null +++ b/src/Atc.Azure.IoT/Providers/IConfigurationContentProvider.cs @@ -0,0 +1,12 @@ +namespace Atc.Azure.IoT.Providers; + +public interface IConfigurationContentProvider +{ + Task<(ConfigurationContent? ConfigurationContent, string? ErrorMessage)> GetConfigurationContent( + FileInfo deploymentManifestFileInfo, + CancellationToken cancellationToken); + + Task<(ConfigurationContent? ConfigurationContent, string? ErrorMessage)> GetConfigurationContent( + Stream deploymentManifestFileStream, + CancellationToken cancellationToken); +} \ No newline at end of file