Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Cet article explique comment générer, valider, déboguer et publier des connecteurs Akri personnalisés à l’aide des connecteurs Azure IoT Operations Akri en préversion de l’extension VS Code.
L’extension prend en charge les plateformes suivantes :
- Linux
- Sous-système Microsoft Windows pour Linux (WSL)
- Fenêtres
L’extension vous permet de créer des connecteurs à l’aide des langages de programmation suivants :
- .NET
- Rust
Prerequisites
Environnement de développement :
- Docker
- Visual Studio Code
- Connecteurs Azure IoT Operations Akri (version préliminaire) Extension VS Code
- Kit de développement logiciel (SDK) .NET
- Pour déboguer des connecteurs .NET : l'extension C#
- Pour déboguer des connecteurs Rust - Extension C/C++
- Azure CLI
- CLI ORAS
- Clonez le référentiel Explorer les opérations Azure IoT si vous ne l’avez pas déjà fait.
Configuration docker :
Les images utilisées par l’extension doivent être extraites et étiquetées localement avant d’utiliser l’extension :
docker pull mcr.microsoft.com/azureiotoperations/devx-runtime:0.1.8 docker tag mcr.microsoft.com/azureiotoperations/devx-runtime:0.1.8 devx-runtimeTous les conteneurs que l’extension lance sont configurés pour s’exécuter sur un réseau personnalisé nommé
aio_akri_networkà des fins d’isolation réseau :docker network create aio_akri_networkLe conteneur DevX utilise un volume
akri_devx_docker_volumepersonnalisé pour stocker la configuration du cluster :docker volume rm akri_devx_docker_volume # delete the volume created from any previous release docker volume create akri_devx_docker_volume
Pour déployer et utiliser votre connecteur avec une instance Azure IoT Operations, vous avez également besoin des éléments suivants :
- Une instance d’Azure IoT Operations.
- Accès à un registre de conteneurs, tel qu’Azure Container Registry, pour publier vos images de connecteur.
- Un point de terminaison de registre de conteneurs configuré dans votre instance Opérations Azure IoT pour extraire vos images de connecteur. Pour plus d’informations, consultez Configurer des points de terminaison de Registre.
Créer et valider un connecteur Akri
Dans cet exemple, vous créez un connecteur HTTP/REST à l’aide du langage C#, générez une image Docker, puis exécutez l’application de connecteur à l’aide de l’extension VS Code :
Appuyez
Ctrl+Shift+Ppour ouvrir la palette de commandes et rechercher la commande Azure IoT Operations Akri Connectors: Create a New Akri Connector. Créez un dossier appelémy-connectorset sélectionnez-le, sélectionnez C# comme langue, entrez un nom pour le connecteur telrest_connectorque , puis sélectionnez PollingTelemetryConnector comme type de connecteur.L’extension crée un espace de travail nommé à l’aide du nom du connecteur que vous avez choisi à l’étape précédente. L’espace de travail inclut la structure d’un connecteur de télémétrie de sondage écrit dans le langage C#.
Les étapes suivantes supposent que vous avez créé un projet .NET appelé MyConnector.
Important
L’exemple de code suivant est destiné uniquement à des fins d’illustration et n’est pas destiné à être utilisé en production. Dans un connecteur de production, vous devez implémenter une logique robuste de gestion des erreurs et de nouvelle tentative, et vous assurer que toutes les informations d’identification utilisées pour se connecter à la ressource sont stockées et utilisées en toute sécurité. Un connecteur de qualité de production doit implémenter le contrat décrit dans le document du contrat d’opérateur et de connecteur Akri dans le référentiel des kits SDK.
Pour représenter l’état du thermostat, créez un fichier appelé ThermostatStatus.cs dans le dossier de l’espace MyConnector de travail avec le contenu suivant. Ce fichier modélise la réponse JSON à partir du point de terminaison REST :
using System.Text.Json.Serialization;
namespace MyConnector
{
internal class ThermostatStatus
{
[JsonPropertyName("desiredTemperature")]
public double? DesiredTemperature { get; set; }
[JsonPropertyName("currentTemperature")]
public double? CurrentTemperature { get; set; }
}
}
Pour ajouter un paramètre de configuration de point de données, créez un fichier appelé DataPointConfiguration.cs dans le dossier de l’espace MyConnector de travail avec le contenu suivant. Ce fichier modélise un paramètre de configuration pour un point de données que l’utilisateur spécifie dans l’interface utilisateur de l’expérience des opérations :
using System.Text.Json.Serialization;
namespace MyConnector
{
public class DataPointConfiguration
{
[JsonPropertyName("HttpRequestMethod")]
public string? HttpRequestMethod { get; set; }
}
}
Implémentez la SampleDatasetAsync méthode dans la classe fournie DatasetSampler . La méthode prend un Dataset paramètre. Un Dataset contient les points de données du connecteur à traiter.
Ouvrez le fichier
MyConnector/DatasetSampler.csdans votre espace de travail VS Code.Pour transmettre les données requises pour le traitement des données de point de terminaison, ajoutez un constructeur à la
DatasetSamplerclasse. La classe utilise lesHttpClientetEndpointProfileCredentialspour se connecter et s’authentifier avec le point de terminaison de ressource :private readonly HttpClient _httpClient; private readonly string _assetName; private readonly EndpointCredentials? _credentials; private readonly static JsonSerializerOptions _jsonSerializerOptions = new() { AllowTrailingCommas = true, }; public DatasetSampler(HttpClient httpClient, string assetName, EndpointCredentials? credentials) { _httpClient = httpClient; _assetName = assetName; _credentials = credentials; } public ValueTask DisposeAsync() { _httpClient.Dispose(); return ValueTask.CompletedTask; }Modifiez la
GetSamplingIntervalAsyncméthode pour retourner un intervalle d’échantillonnage de trois secondes :public Task<TimeSpan> GetSamplingIntervalAsync(AssetDataset dataset, CancellationToken cancellationToken = default) { return Task.FromResult(TimeSpan.FromSeconds(3)); }Note
Par souci de simplicité, cet exemple utilise un intervalle d’échantillonnage fixe. Dans un connecteur de production, vous pouvez configurer l’intervalle d’échantillonnage à l’aide des métadonnées du connecteur pour définir une propriété d’intervalle d’échantillonnage qu’un utilisateur peut définir dans l’interface utilisateur de l’expérience des opérations.
Remplacez la méthode existante
SampleDatasetAsyncpar le plan suivant :public async Task<byte[]> SampleDatasetAsync(AssetDataset dataset, CancellationToken cancellationToken = default) { int retryCount = 0; while (true) { try { // TODO: Implement your dataset sampling logic here. } catch (Exception ex) { if (++retryCount >= 3) { throw new InvalidOperationException($"Failed to sample dataset with name {dataset.Name} in asset with name {_assetName}. Error: {ex.Message}", ex); } await Task.Delay(1000, cancellationToken); } } }Dans le bloc
tryde la méthodeSampleDatasetAsync, ajoutez le code suivant pour récupérer chaqueDataPointduDataSetet extraire les chemins de la source de données. Ces chemins font partie des URL utilisées pour extraire les données du point de terminaison REST. Les points de donnéescurrentTemperatureetdesiredTemperatureont été modélisés précédemment dans la classeThermostatStatus. La méthode de requête HTTP est extraite de la configuration du point de données modélisée dans laDataPointConfigurationclasse :AssetDatasetDataPointSchemaElement httpServerDesiredTemperatureDataPoint = dataset.DataPoints!.Where(x => x.Name!.Equals("desiredTemperature"))!.First(); HttpMethod httpServerDesiredTemperatureHttpMethod = HttpMethod.Parse(JsonSerializer.Deserialize<DataPointConfiguration>(httpServerDesiredTemperatureDataPoint.DataPointConfiguration!, _jsonSerializerOptions)!.HttpRequestMethod); string httpServerDesiredTemperatureRequestPath = httpServerDesiredTemperatureDataPoint.DataSource!; AssetDatasetDataPointSchemaElement httpServerCurrentTemperatureDataPoint = dataset.DataPoints!.Where(x => x.Name!.Equals("currentTemperature"))!.First(); HttpMethod httpServerCurrentTemperatureHttpMethod = HttpMethod.Parse(JsonSerializer.Deserialize<DataPointConfiguration>(httpServerCurrentTemperatureDataPoint.DataPointConfiguration!, _jsonSerializerOptions)!.HttpRequestMethod); string httpServerCurrentTemperatureRequestPath = httpServerCurrentTemperatureDataPoint.DataSource!;Note
Par souci de simplicité, cet exemple montre uniquement comment récupérer la méthode HTTP à utiliser à partir de la configuration du point de données. L’exemple n’utilise pas cette valeur lorsqu’il effectue la requête HTTP.
Dans la même méthode, configurez l’authentification à l’aide des informations d’identification fournies si les points de terminaison authentifiés sont en cours d’utilisation :
if (_credentials != null && _credentials.Username != null && _credentials.Password != null) { // Note that this sample uses username + password for authenticating the connection to the asset. In general, // x509 authentication should be used instead (if available) as it is more secure. string httpServerUsername = _credentials.Username; string httpServerPassword = _credentials.Password; var byteArray = Encoding.ASCII.GetBytes($"{httpServerUsername}:{httpServerPassword}"); _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray)); }Ce code extrait les informations d’identification et les ajoute à l’en-tête d’autorisation. L’authentification
DatasetSamplerde base est implémentée avec les informations d’identification de nom d’utilisateur et de mot de passe.Ensuite, ajoutez du code pour effectuer une requête HTTP au point de terminaison, désérialiser la réponse, et extraire les propriétés
CurrentTemperatureetDesiredTemperature, puis les placer dans un objetThermostatStatus.var currentTemperatureHttpResponse = await _httpClient.GetAsync(httpServerCurrentTemperatureRequestPath); var desiredTemperatureHttpResponse = await _httpClient.GetAsync(httpServerDesiredTemperatureRequestPath); if (currentTemperatureHttpResponse.StatusCode == System.Net.HttpStatusCode.Unauthorized || desiredTemperatureHttpResponse.StatusCode == System.Net.HttpStatusCode.Unauthorized) { throw new Exception("Failed to authorize request to HTTP server. Check credentials configured in rest-server-device-definition.yaml."); } currentTemperatureHttpResponse.EnsureSuccessStatusCode(); desiredTemperatureHttpResponse.EnsureSuccessStatusCode(); ThermostatStatus thermostatStatus = new() { CurrentTemperature = (JsonSerializer.Deserialize<ThermostatStatus>(await currentTemperatureHttpResponse.Content.ReadAsStreamAsync(), _jsonSerializerOptions)!).CurrentTemperature, DesiredTemperature = (JsonSerializer.Deserialize<ThermostatStatus>(await desiredTemperatureHttpResponse.Content.ReadAsStreamAsync(), _jsonSerializerOptions)!).DesiredTemperature };Ensuite, sérialisez l’état au format JSON et retournez la réponse au point de terminaison. Dans cet exemple, la charge utile de réponse HTTP correspond déjà au schéma de message attendu. Par conséquent, aucune traduction n’est nécessaire :
// The HTTP response payload matches the expected message schema, so return it as-is return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(thermostatStatus));Conseil / Astuce
Si vous le souhaitez, le connecteur peut inscrire un schéma dans le registre de schémas pour permettre à d’autres opérations Azure IoT de comprendre le format des messages.
Enfin, importez les types nécessaires :
using Azure.Iot.Operations.Connector.Files; using System.Net.Http.Headers; using System.Text; using System.Text.Json;
La version finale du code ressemble à DatasetSampler.
Implémentez la CreateDatasetSampler méthode dans la DatasetSamplerProvider classe. Cette classe crée des DataSetSampler objets à injecter dans l’application en fonction des besoins.
Ouvrez le
MyConnector/DatasetSamplerProvider.csfichier dans votre espace de travail VS Code.Dans la méthode
CreateDatasetSampler, retournez unDatasetSampleravec leendpointCredentialssi le nom du jeu de données estthermostat_status:if (dataset.Name.Equals("thermostat_status")) { if (device.Endpoints != null && device.Endpoints.Inbound != null && device.Endpoints.Inbound.TryGetValue(inboundEndpointName, out var inboundEndpoint)) { var httpClient = new HttpClient() { BaseAddress = new Uri(inboundEndpoint.Address), }; return new DatasetSampler(httpClient, assetName, endpointCredentials); } } throw new InvalidOperationException($"Unrecognized dataset with name {dataset.Name} on asset with name {assetName}");Note
Par souci de simplicité, cet exemple suppose que le nom du jeu de données est toujours
thermostat_status. Dans un connecteur de production, vous pouvez implémenter une logique supplémentaire pour gérer plusieurs jeux de données.
La version finale du code ressemble à DatasetSamplerProvider.
Ensuite, générez le projet pour confirmer qu’il n’y a aucune erreur. Utilisez la commande VS Code Azure IoT Operations Akri Connectors : générez un connecteur Akri et choisissez le mode Mise en production . Cette commande affiche la progression de la compilation dans la console OUTPUT et vous avertit une fois la compilation terminée. Vous pouvez ensuite voir une nouvelle image Docker nommée <connector_name> avec une balise release localement dans Docker Desktop.
Pour tester le nouveau connecteur localement, procédez comme suit :
Créez un point de terminaison local qui joue le rôle de serveur REST pour que le connecteur se connecte. Dans le
explore-iot-operationréférentiel que vous avez cloné précédemment, exécutez les commandes suivantes pour générer un serveur REST local à des fins de test :cd samples/akri-vscode-extension/sample-rest-server docker build -t rest-server:latest .Vous pouvez voir l’image dans Docker Desktop.
Exécutez la commande suivante pour démarrer le serveur REST dans un conteneur local :
docker run -d --rm --network aio_akri_network --name restserver rest-server:latestVous pouvez voir le conteneur s’exécutant dans Docker Desktop. Le serveur REST est accessible à
http://restserver:3000pour les conteneurs s'exécutant suraio_akri_network.Copiez le fichier
rest-server-device-definition.yamlà partir dusamples/akri-vscode-extension/rest-server-custom-resourcesdossier dans votre copie locale duexplore-iot-operationsdépôt vers le dossier Appareils de votre espace de travail connecteur dans VS Code. Cette ressource d’appareil définit une connexion de point de terminaison au serveur REST.Copiez le fichier
rest-server-asset1-definition.yamlà partir dusamples/akri-vscode-extension/rest-server-custom-resourcesdossier dans votre copie locale duexplore-iot-operationsdépôt vers le dossier Assets de votre espace de travail connecteur dans VS Code. Cette ressource publie les informations de température de l’appareil dans lamqtt/machine/asset1/statusrubrique MQTT.Copiez le fichier
rest-server-asset2-definition.yamlà partir dusamples/akri-vscode-extension/rest-server-custom-resourcesdossier dans votre copie locale duexplore-iot-operationsdépôt vers le dossier Assets de votre espace de travail connecteur dans VS Code. Cette ressource publie les informations de température de l’appareil dans le stockage d’état.Pour tester le connecteur avec les ressources de l’appareil et de la ressource, accédez au panneau Exécuter et déboguer dans l’espace de travail VS Code, puis sélectionnez la configuration Exécuter un connecteur Akri . Cette configuration lance un terminal qui exécute les tâches de prélancement pour démarrer le
aio-brokerconteneur et le connecteur REST que vous avez développé dans un autre conteneur appelé<connector_name>_release. Cette opération prend plusieurs minutes. Vous pouvez voir le flux de données de télémétrie du serveur REST vers le répartiteur MQ via le connecteur REST dans la fenêtre de terminal dans VS Code. Les journaux de conteneur sont également visibles dans Docker Desktop.Vous pouvez arrêter l’exécution à tout moment à l’aide du bouton Arrêter dans le panneau de commandes de débogage. Cette commande nettoie et supprime les conteneurs
aio-brokeren cours d’exécution et<connector_name>_release.
Déboguer un connecteur Akri
Pour déboguer un connecteur Akri basé sur .NET, vérifiez que l’extension VS Code C# est installée. Utilisez le même connecteur REST que vous avez créé précédemment :
Pour générer le connecteur en mode Débogage , utilisez la commande VS Code Azure IoT Operations Akri Connectors : générez un connecteur Akri et sélectionnez Mode débogage . Cette commande crée une image Docker locale appelée
<connector_name>avec la balisedebug. Vous pouvez voir l’image dans Docker Desktop.Vous pouvez ajouter un point d’arrêt et l’exécution s’arrête lorsque le point d’arrêt est atteint. Essayez d’ajouter un point d’arrêt au début de la
SampleDatasetAsyncméthode dansDatasetSampler.cs.Pour déboguer le connecteur, accédez au panneau Exécuter et Déboguer dans l’espace de travail VS Code, puis sélectionnez la configuration du connecteur Akri. Cette configuration lance un terminal qui exécute les tâches de prélancement pour démarrer le
aio-brokerconteneur et le connecteur REST que vous avez développé dans un autre conteneur appelé<connector_name>_debug. Cette opération prend plusieurs minutes. Vous pouvez voir le flux de données de télémétrie du serveur REST vers le répartiteur MQ via le connecteur REST dans la fenêtre de terminal dans VS Code. Les journaux de conteneur sont également visibles dans Docker Desktop.Utilisez le bouton Déconnecter dans le panneau de commandes de débogage pour mettre fin à l’exécution.
Note
L’extension AKri VS Code lance le conteneur DevX dans un scénario d’exécution/débogage avec une période d’expiration de trois minutes. Si le conteneur ne termine pas le lancement au cours de la période d’expiration, l’extension met fin au conteneur.
Appliquer des mises à jour de configuration
Vous pouvez mettre à jour dynamiquement les configurations de l’appareil et des ressources dans l’environnement d’exécution local pendant que vous exécutez votre connecteur. Cette fonctionnalité vous permet de vérifier que votre connecteur répond aux modifications de configuration. Utilisez les commandes d’extension VS Code suivantes pour apporter ces modifications :
- Connecteurs Azure IoT Operations Akri : appliquer le YAML de périphérique au cluster
- Connecteurs Azure IoT Operations Akri : appliquer le YAML de ressource au cluster
- Connecteurs Azure IoT Operations Akri : supprimer le fichier YAML du dispositif du cluster
- Connecteurs Azure IoT Operations Akri : supprimer le fichier YAML de ressource du cluster
Capturer l’état du connecteur
Pour capturer l’état actuel du registre de schémas, utilisez la commande d’extension Azure IoT Operations Akri Connector : Capture Connector State VS Code. Cette commande crée un dossier dans le dossier OUTPUT de l’espace de travail avec un nom basé sur l’horodatage actuel. Le dossier créé contient une copie de l’état actuel du registre de schémas, y compris les schémas créés par le connecteur personnalisé.
L’état du registre de schémas est toujours visible dans le Output/ConnectorState dossier. La commande vous permet de capturer l’état du registre de schémas à un moment spécifique.
Publier une image de connecteur
Utilisez les connecteurs Azure IoT Operations Akri : publiez une commande d’image ou de métadonnées du connecteur Akri pour publier des images de connecteur dans un registre ACR (Microsoft Azure Container Registry). La commande utilise les commandes Microsoft Azure CLI et oras. Pour publier dans un registre ACR, vous avez besoin de votre ID d’abonnement Azure et du nom du registre ACR.
Configuration des métadonnées de l'auteur du connecteur
Utilisez l’espace de travail VS Code créé à partir de la commande Créer un connecteur Akri pour créer le connector-metadata.json fichier conforme au schéma JSON pour le schéma Azure IoT Operations Connector Metadata 9.0-preview . Vous pouvez placer ce fichier n’importe où dans l'espace de travail du connecteur. L’extension fournit une fonctionnalité de validation statique à l’aide du connector-metadata.json fichier et affiche des avertissements dans le PROBLEMS panneau si des propriétés requises sont manquantes.
Publier des artéfacts de métadonnées
Utilisez les connecteurs Azure IoT Operations Akri : commande Publier l’image ou les métadonnées du connecteur Akri pour publier des dossiers de métadonnées dans un registre ACR. La commande utilise les commandes Azure CLI et oras. Pour publier dans un registre ACR, vous avez besoin de votre ID d’abonnement Azure et du nom du registre ACR. Actuellement, l’extension s’attend à ce que les fichiers appelés connector-metadata.json et éventuellement additionalConfig.json soient présents dans n’importe quel dossier que vous envoyez.
Problèmes connus
Les mises à jour de configuration résultant des
Delete/Apply Asset/Device YAMLcommandes VS Code ne fonctionnent actuellement pas dans Windows en raison des limitations de l’implémentation CIFS dans le noyau Linux. Tous les événements de modification de fichier dans les dossiers montés sur l’hôte ne sont pas propagés au conteneur par Docker pour Windows.Lorsque vous supprimez une ressource ou un appareil du cluster à l’aide des commandes VS Code, le connecteur .NET lève actuellement l’erreur 404 suivante :
Unhandled exception. Azure.Iot.Operations.Protocol.Retry.RetryExpiredException: Retry expired while attempting the operation. Last known exception is the inner exception. ---> Azure.Iot.Operations.Services.AssetAndDeviceRegistry.Models.AkriServiceErrorException: ApiError: assets.namespaces.deviceregistry.microsoft.com "my-rest-thermostat-asset2" not found: NotFound (ErrorResponse { status: "Failure", message: "assets.namespaces.deviceregistry.microsoft.com \"my-rest-thermostat-asset2\" not found", reason: "NotFound", code: 404 }) at Azure.Iot.Operations.Services.AssetAndDeviceRegistry.AdrServiceClient.<>c__DisplayClass19_0.<<SetNotificationPreferenceForAssetUpdatesAsync>b__0>d.MoveNext() --- End of stack trace from previous location --- at Azure.Iot.Operations.Services.AssetAndDeviceRegistry.AdrServiceClient.RunWithRetryAsync[TResult](Func`1 taskFunc, CancellationToken cancellationToken) --- End of inner exception stack trace --- at Azure.Iot.Operations.Services.AssetAndDeviceRegistry.AdrServiceClient.RunWithRetryAsync[TResult](Func`1 taskFunc, CancellationToken cancellationToken) at Azure.Iot.Operations.Services.AssetAndDeviceRegistry.AdrServiceClient.SetNotificationPreferenceForAssetUpdatesAsync(String deviceName, String inboundEndpointName, String assetName, NotificationPreference notificationPreference, Nullable`1 commandTimeout, CancellationToken cancellationToken) at Azure.Iot.Operations.Connector.AdrClientWrapper.AssetFileChanged(Object sender, AssetFileChangedEventArgs e) at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_1(Object state) at System.Threading.ThreadPoolWorkQueue.Dispatch() at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart()Actuellement, le lancement de l’image DevX en tant que conteneur à partir de WSL sans Docker Desktop installé entraîne le blocage du conteneur pour toujours.