IoT Hub-eszközidentitások tömeges importálása vagy exportálása

Minden IoT Hub rendelkezik egy identitásregisztrációs adatbázissal, amellyel eszközerőforrásokat hozhat létre a szolgáltatásban. Az identitásjegyzék az eszközökhöz kapcsolódó végpontokhoz való hozzáférés vezérlését is lehetővé teszi. Ez a cikk azt ismerteti, hogyan importálhatja és exportálhatja tömegesen az eszközidentitásokat egy identitásjegyzékbe és abból a Microsoft Azure IoT SDK for .NET-hez készült ImportExportDeviceSample mintával. Ha többet szeretne tudni arról, hogyan használhatja ezt a képességet egy IoT Hub másik régióba történő migrálásakor, olvassa el az Azure IoT Hub manuális migrálását Azure Resource Manager-sablonnal.

Feljegyzés

Az IoT Hub nemrég hozzáadott virtuális hálózati támogatást korlátozott számú régióban. Ez a funkció biztosítja az importálási és exportálási műveleteket, és szükségtelenné teszi a kulcsok hitelesítéshez való átadását. A virtuális hálózat támogatása jelenleg csak ezekben a régiókban érhető el: WestUS2, EastUS és SouthCentralUS. A virtuális hálózatok támogatásával és a implementálásra irányuló API-hívásokkal kapcsolatos további információkért lásd : IoT Hub-támogatás a virtuális hálózatokhoz.

Az importálási és exportálási műveletek olyan feladatok kontextusában történnek, amelyek lehetővé teszik tömeges szolgáltatásműveletek végrehajtását egy IoT Hubon.

Az SDK RegistryManager osztálya tartalmazza a Feladat keretrendszert használó ExportDevicesAsync és ImportDevicesAsync metódusokat. Ezek a módszerek lehetővé teszik egy IoT Hub-identitásregisztrációs adatbázis teljes egészének exportálását, importálását és szinkronizálását.

Ez a cikk a RegistryManager osztály és a feladatrendszer használatával ismerteti az eszközök tömeges importálását és exportálását az IoT Hub identitásregisztrációs adatbázisába és azokból. Az Azure IoT Hub Device Provisioning Service használatával érintésmentes, igény szerinti üzembe helyezést is engedélyezhet egy vagy több IoT Hubon. További információkért tekintse meg a kiépítési szolgáltatás dokumentációját.

Feljegyzés

A cikkben szereplő kódrészletek némelyike a Microsoft Azure IoT SDK for .NET-hez biztosított ImportExportDevicesSample szolgáltatásmintából származik. A minta az /iothub/service/samples/how to guides/ImportExportDevicesSample SDK mappájában található, és ahol meg van adva, a kódrészletek az ImportExportDevicesSample.cs adott SDK-minta fájljából származnak. Az ImportExportDevicesSample mintáról és az Azure IoT SDK for.NET tartalmazott egyéb szolgáltatásmintákról a C#-hoz készült Azure IoT Hub szolgáltatásmintákban talál további információt.

Mik azok a feladatok?

Az identitásregisztrációs adatbázis műveletei a feladatrendszert használják a művelet során:

  • A normál futásidejű műveletekhez képest potenciálisan hosszú végrehajtási idővel rendelkezik.

  • Nagy mennyiségű adatot ad vissza a felhasználónak.

A művelet eredményén várakozó vagy blokkoló EGYETLEN API-hívás helyett a művelet aszinkron módon létrehoz egy feladatot az IoT Hub számára. A művelet ezután azonnal visszaad egy JobProperties objektumot .

Az alábbi C#-kódrészlet bemutatja, hogyan hozhat létre exportálási feladatot:

// Call an export job on the IoT hub to retrieve all devices
JobProperties exportJob = await 
  registryManager.ExportDevicesAsync(containerSasUri, false);

Feljegyzés

A RegistryManager osztály C#-kódban való használatához adja hozzá a Microsoft.Azure.Devices NuGet-csomagot a projekthez. A RegistryManager osztály a Microsoft.Azure.Devices névtérben található.

A RegistryManager osztály használatával lekérdezheti a feladat állapotát a visszaadott JobProperties metaadatokkal. A RegistryManager osztály egy példányának létrehozásához használja a CreateFrom Csatlakozás ionString metódust.

RegistryManager registryManager =
  RegistryManager.CreateFromConnectionString("{your IoT Hub connection string}");

Az IoT Hub kapcsolati sztring az Azure Portalon találhatja meg:

  1. Keresse meg az IoT-központot.

  2. Válassza a Megosztott hozzáférési szabályzatok lehetőséget.

  3. Válasszon ki egy szabályzatot, figyelembe véve a szükséges engedélyeket.

  4. Másolja ki a szabályzathoz tartozó kapcsolati sztring.

Az SDK-minta WaitForJobAsync metódusából származó következő C#-kódrészlet azt mutatja be, hogyan kérdezhet le öt másodpercenként, hogy lássa, a feladat befejeződött-e:

// Wait until job is finished
while (true)
{
    job = await registryManager.GetJobAsync(job.JobId);
    if (job.Status == JobStatus.Completed
        || job.Status == JobStatus.Failed
        || job.Status == JobStatus.Cancelled)
    {
        // Job has finished executing
        break;
    }
    Console.WriteLine($"\tJob status is {job.Status}...");

    await Task.Delay(TimeSpan.FromSeconds(5));
}

Feljegyzés

Ha a tárfiók olyan tűzfalkonfigurációkkal rendelkezik, amelyek korlátozzák az IoT Hub kapcsolatát, fontolja meg a Microsoft megbízható, első féltől származó kivételének használatát (a felügyeltszolgáltatás-identitással rendelkező IoT Hubok egyes régióiban érhető el).

Eszközimportálási/exportálási feladatok korlátai

Egyszerre csak egy aktív eszközimportálási vagy -exportálási feladat engedélyezett az összes IoT Hub-szinten. Az IoT Hub a feladatok sebességére vonatkozó korlátozásokkal is rendelkezik. További információ: IoT Hub-kvóták és szabályozás.

Eszközök exportálása

Az ExportDevicesAsync metódussal egy IoT Hub-identitásregisztrációs adatbázis teljes egészét exportálhatja egy Azure Storage-blobtárolóba közös hozzáférésű jogosultságkód (SAS) használatával. Ez a módszer lehetővé teszi az eszközadatok megbízható biztonsági mentését egy ön által felügyelt blobtárolóban.

Az ExportDevicesAsync metódushoz két paraméter szükséges:

  • Blobtároló URI-ját tartalmazó sztring . Ennek az URI-nak tartalmaznia kell egy SAS-jogkivonatot, amely írási hozzáférést biztosít a tárolóhoz. A feladat létrehoz egy blokkblobot ebben a tárolóban a szerializált exportálási eszköz adatainak tárolásához. Az SAS-jogkivonatnak tartalmaznia kell az alábbi engedélyeket:

    SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read 
       | SharedAccessBlobPermissions.Delete
    
  • Logikai érték , amely jelzi, hogy ki szeretné-e zárni a hitelesítési kulcsokat az exportálási adatokból. Ha hamis, a hitelesítési kulcsok szerepelnek az exportálási kimenetben. Ellenkező esetben a kulcsok null értékűként lesznek exportálva.

A következő C#-kódrészlet bemutatja, hogyan kezdeményezhet olyan exportálási feladatot, amely eszközhitelesítési kulcsokat tartalmaz az exportálási adatokban, majd lekérdezi a befejezést:

// Call an export job on the IoT Hub to retrieve all devices
JobProperties exportJob = 
  await registryManager.ExportDevicesAsync(containerSasUri, false);

// Wait until job is finished
while(true)
{
    exportJob = await registryManager.GetJobAsync(exportJob.JobId);
    if (exportJob.Status == JobStatus.Completed || 
        exportJob.Status == JobStatus.Failed ||
        exportJob.Status == JobStatus.Cancelled)
    {
    // Job has finished executing
    break;
    }

    await Task.Delay(TimeSpan.FromSeconds(5));
}

Hasonló kódot az ExportDevicesAsync metódusban talál az SDK-mintából. A feladat a kimenetét a megadott blobtárolóban tárolja blokkblobként, amelynek neve devices.txt. A kimeneti adatok JSON szerializált eszközadatokból állnak, soronként egy eszközzel.

Az alábbi példa a kimeneti adatokat mutatja be:

{"id":"Device1","eTag":"MA==","status":"enabled","authentication":{"symmetricKey":{"primaryKey":"abc=","secondaryKey":"def="}}}
{"id":"Device2","eTag":"MA==","status":"enabled","authentication":{"symmetricKey":{"primaryKey":"abc=","secondaryKey":"def="}}}
{"id":"Device3","eTag":"MA==","status":"disabled","authentication":{"symmetricKey":{"primaryKey":"abc=","secondaryKey":"def="}}}
{"id":"Device4","eTag":"MA==","status":"disabled","authentication":{"symmetricKey":{"primaryKey":"abc=","secondaryKey":"def="}}}
{"id":"Device5","eTag":"MA==","status":"enabled","authentication":{"symmetricKey":{"primaryKey":"abc=","secondaryKey":"def="}}}

Ha egy eszköz ikeradattal rendelkezik, akkor az ikeradatok is exportálva lesznek az eszköz adataival együtt. Az alábbi példa ezt a formátumot mutatja be. A "twinETag" sortól a végéig minden adat ikeradat.

{
   "id":"export-6d84f075-0",
   "eTag":"MQ==",
   "status":"enabled",
   "authentication":null,
   "twinETag":"AAAAAAAAAAI=",
   "tags":{
      "Location":"LivingRoom"
   },
   "properties":{
      "desired":{
         "Thermostat":{
            "Temperature":75.1,
            "Unit":"F"
         },
      },
      "reported":{}
   }
}

Ha kódban kell hozzáférnie ezekhez az adatokhoz, deszerializálhatja ezeket az adatokat az ExportImportDevice osztály használatával. Az SDK-mintában található ReadFromBlobAsync metódusból származó következő C#-kódrészlet bemutatja, hogyan olvashatók be a korábban az ExportImportDevice-ből BlobClient-példányba exportált eszközinformációk:

private static async Task<List<string>> ReadFromBlobAsync(BlobClient blobClient)
{
    // Read the blob file of devices, import each row into a list.
    var contents = new List<string>();

    using Stream blobStream = await blobClient.OpenReadAsync();
    using var streamReader = new StreamReader(blobStream, Encoding.UTF8);
    while (streamReader.Peek() != -1)
    {
        string line = await streamReader.ReadLineAsync();
        contents.Add(line);
    }

    return contents;
}

Eszközök importálása

A RegistryManager osztály ImportDevicesAsync metódusával tömeges importálási és szinkronizálási műveleteket hajthat végre egy IoT Hub-identitásjegyzékben. Az ExportDevicesAsync metódushoz hasonlóan az ImportDevicesAsync metódus is a Feladat keretrendszert használja.

Ügyeljen az ImportDevicesAsync metódus használatára, mert amellett, hogy új eszközöket helyez üzembe az identitásjegyzékben, a meglévő eszközöket is frissítheti és törölheti.

Figyelmeztetés

Az importálási művelet nem vonható vissza. Az identitásjegyzék tömeges módosítása előtt mindig készítsen biztonsági másolatot a meglévő adatokról az ExportDevicesAsync metódussal egy másik blobtárolóba.

Az ImportDevicesAsync metódus két paramétert használ:

  • Egy Azure Storage-blobtároló URI-ját tartalmazó sztring, amely a feladat bemeneteként használható. Ennek az URI-nak tartalmaznia kell egy SAS-jogkivonatot, amely olvasási hozzáférést biztosít a tárolóhoz. Ennek a tárolónak tartalmaznia kell egy devices.txt nevű blobot, amely tartalmazza az identitásjegyzékbe importálandó szerializált eszközadatokat. Az importálási adatoknak ugyanabban a JSON-formátumban kell tartalmazniuk az eszközadatokat, amelyet az ExportImportDevice feladat használ egy devices.txt blob létrehozásakor. Az SAS-jogkivonatnak tartalmaznia kell az alábbi engedélyeket:

    SharedAccessBlobPermissions.Read
    
  • Egy Azure Storage-blobtároló URI-ját tartalmazó sztring, amely a feladat kimeneteként használható. A feladat létrehoz egy blokkblobot ebben a tárolóban a befejezett importálási feladat hibainformációinak tárolásához. Az SAS-jogkivonatnak tartalmaznia kell az alábbi engedélyeket:

    SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read 
       | SharedAccessBlobPermissions.Delete
    

Feljegyzés

A két paraméter ugyanarra a blobtárolóra mutathat. A különálló paraméterek egyszerűen lehetővé teszik az adatok nagyobb ellenőrzését, mivel a kimeneti tároló további engedélyeket igényel.

Az alábbi C#-kódrészlet bemutatja, hogyan kezdeményezhet importálási feladatot:

JobProperties importJob = 
   await registryManager.ImportDevicesAsync(containerSasUri, containerSasUri);

Ez a módszer az ikereszköz adatainak importálására is használható. Az adatbevitel formátuma megegyezik az ExportDevicesAsync szakaszban látható formátummal. Ily módon újraimportálhatja az exportált adatokat.

Importálási viselkedés

Az ImportDevicesAsync metódussal a következő tömeges műveleteket hajthatja végre az identitásjegyzékben:

  • Új eszközök tömeges regisztrálása
  • Meglévő eszközök tömeges törlése
  • Tömeges állapotváltozások (eszközök engedélyezése vagy letiltása)
  • Új eszközhitelesítési kulcsok tömeges hozzárendelése
  • Eszközhitelesítési kulcsok tömeges automatikus újragenerálása
  • Ikeradatok tömeges frissítése

Az előző műveletek bármilyen kombinációját egyetlen ImportDevicesAsync-híváson belül hajthatja végre. Regisztrálhat például új eszközöket, és egyszerre törölheti vagy frissítheti a meglévő eszközöket. Ha az ExportDevicesAsync metódussal együtt használja, az összes eszközt teljesen áttelepítheti az egyik IoT Hubról a másikra.

Az egyes eszközök importálási szerializálási adataiban használja az opcionális importMode tulajdonságot az eszközönkénti importálási folyamat szabályozásához. Az importMode tulajdonság a következő lehetőségeket kínálja:

  • Létrehozás
  • CreateOrUpdate (alapértelmezett)
  • CreateOrUpdateIfMatchETag
  • Törlés
  • DeleteIfMatchETag
  • Frissítés
  • UpdateIfMatchETag
  • UpdateTwin
  • UpdateTwinIfMatchETag

Az importálási mód egyes beállításairól további információt az ImportMode című témakörben talál .

Importálási feladatok hibaelhárítása

Ha importálási feladattal hoz létre eszközöket, az egy kvótaproblémával meghiúsulhat, ha az közel van az IoT Hub eszközszámkorlátához. Ez a hiba akkor is előfordulhat, ha az eszköz teljes száma még mindig alacsonyabb a kvótakorlátnál. Az IotHubQuotaExceeded (403002) hiba a következő hibaüzenettel jelenik meg: "Az IotHubon lévő eszközök teljes száma túllépte a lefoglalt kvótát."

Ha ezt a hibát kapja, a következő lekérdezéssel visszaadhatja az IoT Hubon regisztrált eszközök teljes számát:

SELECT COUNT() as totalNumberOfDevices FROM devices

Az IoT Hubra regisztrálható eszközök teljes számáról az IoT Hub korlátait ismertető cikkben olvashat.

Ha továbbra is rendelkezésre áll kvóta, megvizsgálhatja az IotHubQuotaExceeded (403002) hibával meghiúsult eszközök feladatkimeneti blobját. Ezután egyenként is hozzáadhatja ezeket az eszközöket az IoT Hubhoz. Használhatja például az AddDeviceAsync vagy az AddDeviceWithTwinAsync metódust. Ne próbálja meg más feladattal hozzáadni az eszközöket, mert ugyanez a hiba fordulhat elő.

Példa eszközök importálása – tömeges eszközkiépítés

Az SDK-mintában található GenerateDevicesAsync metódusból származó következő C#-kódrészlet bemutatja, hogyan hozhat létre több olyan eszközidentitást, amelyek:

  • Adja meg a hitelesítési kulcsokat.
  • Írja be az eszköz adatait egy blokkblobba.
  • Importálja az eszközöket az identitásjegyzékbe.
private async Task GenerateDevicesAsync(RegistryManager registryManager, int numToAdd)
{
    var stopwatch = Stopwatch.StartNew();

    Console.WriteLine($"Creating {numToAdd} devices for the source IoT hub.");
    int interimProgressCount = 0;
    int displayProgressCount = 1000;
    int totalProgressCount = 0;

    // generate reference for list of new devices we're going to add, will write list to this blob
    BlobClient generateDevicesBlob = _blobContainerClient.GetBlobClient(_generateDevicesBlobName);

    // define serializedDevices as a generic list<string>
    var serializedDevices = new List<string>(numToAdd);

    for (int i = 1; i <= numToAdd; i++)
    {
        // Create device name with this format: Hub_00000000 + a new guid.
        // This should be large enough to display the largest number (1 million).
        string deviceName = $"Hub_{i:D8}_{Guid.NewGuid()}";
        Debug.Print($"Adding device '{deviceName}'");

        // Create a new ExportImportDevice.
        var deviceToAdd = new ExportImportDevice
        {
            Id = deviceName,
            Status = DeviceStatus.Enabled,
            Authentication = new AuthenticationMechanism
            {
                SymmetricKey = new SymmetricKey
                {
                    PrimaryKey = GenerateKey(32),
                    SecondaryKey = GenerateKey(32),
                }
            },
            // This indicates that the entry should be added as a new device.
            ImportMode = ImportMode.Create,
        };

        // Add device to the list as a serialized object.
        serializedDevices.Add(JsonConvert.SerializeObject(deviceToAdd));

        // Not real progress as you write the new devices, but will at least show *some* progress.
        interimProgressCount++;
        totalProgressCount++;
        if (interimProgressCount >= displayProgressCount)
        {
            Console.WriteLine($"Added {totalProgressCount}/{numToAdd} devices.");
            interimProgressCount = 0;
        }
    }

    // Now have a list of devices to be added, each one has been serialized.
    // Write the list to the blob.
    var sb = new StringBuilder();
    serializedDevices.ForEach(serializedDevice => sb.AppendLine(serializedDevice));

    // Write list of serialized objects to the blob.
    using Stream stream = await generateDevicesBlob.OpenWriteAsync(overwrite: true);
    byte[] bytes = Encoding.UTF8.GetBytes(sb.ToString());
    for (int i = 0; i < bytes.Length; i += BlobWriteBytes)
    {
        int length = Math.Min(bytes.Length - i, BlobWriteBytes);
        await stream.WriteAsync(bytes.AsMemory(i, length));
    }
    await stream.FlushAsync();

    Console.WriteLine("Running a registry manager job to add the devices.");

    // Should now have a file with all the new devices in it as serialized objects in blob storage.
    // generatedListBlob has the list of devices to be added as serialized objects.
    // Call import using the blob to add the new devices.
    // Log information related to the job is written to the same container.
    // This normally takes 1 minute per 100 devices (according to the docs).

    // First, initiate an import job.
    // This reads in the rows from the text file and writes them to IoT Devices.
    // If you want to add devices from a file, you can create a file and use this to import it.
    //   They have to be in the exact right format.
    try
    {
        // The first URI is the container to import from; the file defaults to devices.txt, but may be specified.
        // The second URI points to the container to write errors to as a blob.
        // This lets you import the devices from any file name. Since we wrote the new
        // devices to [devicesToAdd], need to read the list from there as well.
        var importGeneratedDevicesJob = JobProperties.CreateForImportJob(
            _containerUri,
            _containerUri,
            _generateDevicesBlobName);
        importGeneratedDevicesJob = await registryManager.ImportDevicesAsync(importGeneratedDevicesJob);
        await WaitForJobAsync(registryManager, importGeneratedDevicesJob);
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Adding devices failed due to {ex.Message}");
    }

    stopwatch.Stop();
    Console.WriteLine($"GenerateDevices, time elapsed = {stopwatch.Elapsed}.");
}

Példa az eszközök importálására – tömeges törlés

Az alábbi C#-kódrészlet az SDK-mintában található DeleteFromHubAsync metódusból mutatja be, hogyan törölheti az összes eszközt egy IoT Hubról:

private async Task DeleteFromHubAsync(RegistryManager registryManager, bool includeConfigurations)
{
    var stopwatch = Stopwatch.StartNew();

    Console.WriteLine("Deleting all devices from an IoT hub.");

    Console.WriteLine("Exporting a list of devices from IoT hub to blob storage.");

    // Read from storage, which contains serialized objects.
    // Write each line to the serializedDevices list.
    BlobClient devicesBlobClient = _blobContainerClient.GetBlobClient(_destHubDevicesImportBlobName);

    Console.WriteLine("Reading the list of devices in from blob storage.");
    List<string> serializedDevices = await ReadFromBlobAsync(devicesBlobClient);

    // Step 1: Update each device's ImportMode to be Delete
    Console.WriteLine("Updating ImportMode to be 'Delete' for each device and writing back to the blob.");
    var sb = new StringBuilder();
    serializedDevices.ForEach(serializedEntity =>
    {
        // Deserialize back to an ExportImportDevice and change import mode.
        ExportImportDevice device = JsonConvert.DeserializeObject<ExportImportDevice>(serializedEntity);
        device.ImportMode = ImportMode.Delete;

        // Reserialize the object now that we've updated the property.
        sb.AppendLine(JsonConvert.SerializeObject(device));
    });

    // Step 2: Write the list in memory to the blob.
    BlobClient deleteDevicesBlobClient = _blobContainerClient.GetBlobClient(_hubDevicesCleanupBlobName);
    await WriteToBlobAsync(deleteDevicesBlobClient, sb.ToString());

    // Step 3: Call import using the same blob to delete all devices.
    Console.WriteLine("Running a registry manager job to delete the devices from the IoT hub.");
    var importJob = JobProperties.CreateForImportJob(
        _containerUri,
        _containerUri,
        _hubDevicesCleanupBlobName);
    importJob = await registryManager.ImportDevicesAsync(importJob);
    await WaitForJobAsync(registryManager, importJob);

    // Step 4: delete configurations
    if (includeConfigurations)
    {
        BlobClient configsBlobClient = _blobContainerClient.GetBlobClient(_srcHubConfigsExportBlobName);
        List<string> serializedConfigs = await ReadFromBlobAsync(configsBlobClient);
        foreach (string serializedConfig in serializedConfigs)
        {
            try
            {
                Configuration config = JsonConvert.DeserializeObject<Configuration>(serializedConfig);
                await registryManager.RemoveConfigurationAsync(config.Id);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Failed to deserialize or remove a config.\n\t{serializedConfig}\n\n{ex.Message}");
            }
        }
    }

    stopwatch.Stop();
    Console.WriteLine($"Deleted IoT hub devices and configs: time elapsed = {stopwatch.Elapsed}");
}

A tároló SAS URI-jának lekérése

Az alábbi kódminta bemutatja, hogyan hozhat létre SAS URI-t olvasási, írási és törlési engedélyekkel egy blobtárolóhoz:

static string GetContainerSasUri(CloudBlobContainer container)
{
  // Set the expiry time and permissions for the container.
  // In this case no start time is specified, so the
  // shared access signature becomes valid immediately.
  var sasConstraints = new SharedAccessBlobPolicy();
  sasConstraints.SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24);
  sasConstraints.Permissions = 
    SharedAccessBlobPermissions.Write | 
    SharedAccessBlobPermissions.Read | 
    SharedAccessBlobPermissions.Delete;

  // Generate the shared access signature on the container,
  // setting the constraints directly on the signature.
  string sasContainerToken = container.GetSharedAccessSignature(sasConstraints);

  // Return the URI string for the container,
  // including the SAS token.
  return container.Uri + sasContainerToken;
}

Következő lépések

Ebben a cikkben megtanulta, hogyan hajthat végre tömeges műveleteket az identitásjegyzéken egy IoT Hubon. Ezen műveletek közül sok, többek között az eszközök egyik központból a másikba való áthelyezését a Hogyan lehet manuálisan migrálni egy Azure IoT Hubot Azure Resource Manager-sablonnal? című szakasz IoT Hubra regisztrált eszközök kezelése című szakaszában találja.