Mengimpor dan mengekspor identitas perangkat IoT Hub secara massal

Setiap hub IoT memiliki registri identitas yang dapat Anda gunakan untuk membuat sumber daya perangkat dalam layanan. Registri identitas juga mengaktifkan Anda mengontrol akses ke titik akhir yang menghadap perangkat. Artikel ini menjelaskan cara mengimpor dan mengekspor identitas perangkat secara massal ke dan dari registri identitas, menggunakan sampel ImportExportDeviceSample yang disertakan dengan Microsoft Azure IoT SDK untuk .NET. Untuk informasi selengkapnya tentang cara menggunakan kemampuan ini saat memigrasikan hub IoT ke wilayah lain, lihat Cara memigrasikan hub Azure IoT secara manual menggunakan templat Azure Resource Manager.

Catatan

IoT Hub baru-baru ini menambahkan dukungan jaringan virtual di sejumlah wilayah terbatas. Fitur ini mengamankan operasi impor dan ekspor dan menghilangkan kebutuhan meneruskan kunci untuk autentikasi. Saat ini, dukungan jaringan virtual hanya tersedia di wilayah ini: WestUS2, EastUS, dan SouthCentralUS. Untuk mempelajari selengkapnya tentang dukungan jaringan virtual dan panggilan API untuk mengimplementasikannya, lihat Dukungan Azure IoT Hub untuk jaringan virtual.

Operasi impor dan ekspor berlangsung dalam konteks pekerjaan yang memungkinkan Anda menjalankan operasi layanan massal terhadap hub IoT.

Kelas RegistryManager di SDK mencakup metode ExportDevicesAsync dan ImportDevicesAsync yang menggunakan kerangka kerja Pekerjaan . Metode ini mengaktifkan Anda untuk mengekspor, mengimpor, dan menyinkronkan keseluruhan registri identitas hub IoT.

Artikel ini membahas penggunaan kelas RegistryManager dan sistem Pekerjaan untuk melakukan impor massal dan ekspor perangkat ke dan dari registri identitas hub IoT. Anda juga dapat menggunakan Azure IoT Hub Device Provisioning Service untuk mengaktifkan provisi nol sentuhan tepat waktu ke satu atau beberapa hub IoT. Untuk mempelajari lebih lanjut, lihat dokumentasi layanan provisi.

Catatan

Beberapa cuplikan kode dalam artikel ini disertakan dari sampel layanan ImportExportDevicesSample yang disediakan dengan Microsoft Azure IoT SDK untuk .NET. Sampel terletak di /iothub/service/samples/how to guides/ImportExportDevicesSample folder SDK dan, jika ditentukan, cuplikan kode disertakan dari file untuk sampel SDK tersebut ImportExportDevicesSample.cs . Untuk informasi selengkapnya tentang sampel ImportExportDevicesSample dan sampel layanan lainnya yang disertakan dalam for.NET Azure IoT SDK, lihat Sampel layanan hub Azure IoT untuk C#.

Apa itu pekerjaan?

Operasi registri identitas menggunakan sistem pekerjaan saat operasi:

  • BErpotensi memiliki waktu eksekusi yang lama dibandingkan dengan operasi run-time standar.

  • Memberikan sejumlah besar data kepada pengguna.

Alih-alih satu panggilan API menunggu atau memblokir hasil operasi, operasi secara asinkron membuat pekerjaan untuk hub IoT tersebut. Operasi kemudian segera mengembalikan objek JobProperties.

Cuplikan kode C# berikut menunjukkan cara membuat pekerjaan ekspor:

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

Catatan

Untuk menggunakan kelas RegistryManager di kode C# Anda, tambahkan paket NuGet Microsoft.Azure.Devices ke proyek Anda. Kelas RegistryManager berada di ruang nama Microsoft.Azure.Devices.

Anda dapat menggunakan kelas RegistryManager untuk mengkueri status Pekerjaan menggunakan metadata JobProperties yang dihasilkan. Untuk membuat instans kelas RegistryManager, gunakan metode CreateFromConnectionString.

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

Untuk menemukan string koneksi untuk hub IoT Anda, di portal Microsoft Azure:

  1. Buka hub IoT Anda.

  2. Pilih Kebijakan akses bersama.

  3. Pilih kebijakan, dengan mempertimbangkan izin yang Anda butuhkan.

  4. Salin string koneksi untuk kebijakan tersebut.

Cuplikan kode C# berikut, dari metode WaitForJobAsync dalam sampel SDK, menunjukkan cara melakukan polling setiap lima detik untuk melihat apakah pekerjaan telah selesai dieksekusi:

// 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));
}

Catatan

Jika akun penyimpanan Anda memiliki konfigurasi firewall yang membatasi konektivitas IoT Hub, pertimbangkan untuk menggunakan pengecualian pihak pertama tepercaya Microsoft (tersedia di wilayah tertentu untuk hub IoT dengan identitas layanan terkelola).

Batas pekerjaan impor/ekspor perangkat

Hanya satu pekerjaan impor atau ekspor perangkat aktif yang diizinkan pada satu waktu untuk semua tingkat IoT Hub. IoT Hub juga memiliki batasan untuk tingkat operasi pekerjaan. Untuk mempelajari lebih lanjut, lihat Kuota dan pembatasan IoT Hub.

Mengekspor perangkat

Gunakan metode ExportDevicesAsync untuk mengekspor keseluruhan registri identitas hub IoT ke kontainer blob Microsoft Azure Storage menggunakan tanda tangan akses bersama (SAS). Metode ini mengaktifkan Anda membuat cadangan informasi perangkat yang andal dalam kontainer blob yang Anda kontrol.

Metode ExportDevicesAsync memerlukan dua parameter:

  • String yang berisi URI dari kontainer blob. URI ini harus berisi token SAS yang memberikan akses tulis ke kontainer. Pekerjaan membuat blob blok dalam kontainer ini untuk menyimpan data perangkat ekspor berseri. Token SAS harus menyertakan izin ini:

    SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read 
       | SharedAccessBlobPermissions.Delete
    
  • Boolean yang menunjukkan apakah Anda ingin mengecualikan kunci autentikasi dari data ekspor Anda. Jika tidak, kunci autentikasi disertakan dalam output ekspor. Jika sebaliknya, kunci diekspor sebagai null.

Cuplikan kode C# berikut menunjukkan cara memulai pekerjaan ekspor yang menyertakan kunci autentikasi perangkat dalam data ekspor dan kemudian polling untuk penyelesaian:

// 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));
}

Anda dapat menemukan kode serupa dalam metode ExportDevicesAsync dari sampel SDK. Pekerjaan menyimpan outputnya dalam kontainer blob yang disediakan sebagai blob blok dengan nama devices.txt. Data output terdiri dari data perangkat berseri JSON, dengan satu perangkat per baris.

Contoh berikut menunjukkan data output:

{"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="}}}

Jika perangkat memiliki data kembar, maka data kembar juga diekspor bersama dengan data perangkat. Contoh berikut memperlihatkan format ini. Semua data dari baris "twinETag" hingga akhir adalah data kembar.

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

Jika Anda memerlukan akses ke data ini dalam kode, Anda dapat mendeserialisasi data ini menggunakan kelas ExportImportDevice . Cuplikan kode C# berikut, dari metode ReadFromBlobAsync dalam sampel SDK, menunjukkan cara membaca informasi perangkat yang sebelumnya diekspor dari ExportImportDevice ke dalam instans BlobClient :

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;
}

Mengimpor perangkat

Metode ImportDevicesAsync di kelas RegistryManager mengaktifkan Anda melakukan operasi impor dan sinkronisasi massal dalam registri identitas hub IoT. Seperti metode ExportDevicesAsync, metode ImportDevicesAsync menggunakan kerangka kerja Pekerjaan.

Berhati-hatilah menggunakan metode ImportDevicesAsync karena selain provisi perangkat baru di registri identitas Anda, ia juga dapat memperbarui dan menghapus perangkat yang ada.

Peringatan

Operasi impor tak bisa dibatalkan. Selalu cadangkan data Anda yang ada menggunakan metode ExportDevicesAsync ke kontainer blob lain sebelum Anda membuat perubahan massal pada registri identitas Anda.

Metode ExportDevicesAsync memerlukan dua parameter:

  • String yang berisi URI kontainer blob Azure Storage untuk digunakan sebagai input ke pekerjaan. URI ini harus berisi token SAS yang memberikan akses baca ke kontainer. Kontainer ini harus berisi blob dengan nama devices.txt berisi data perangkat berseri untuk diimpor ke registri identitas Anda. Data impor harus berisi informasi perangkat dalam format JSON yang sama dengan yang digunakan oleh pekerjaan ExportImportDevice saat membuat blob devices.txt. Token SAS harus menyertakan izin ini:

    SharedAccessBlobPermissions.Read
    
  • String yang berisi URI kontainer blob Azure Storage untuk digunakan sebagai output dari pekerjaan. Pekerjaan membuat blob blok dalam kontainer ini untuk menyimpan informasi kesalahan apa pun dari pekerjaan impor yang telah selesai. Token SAS harus menyertakan izin ini:

    SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read 
       | SharedAccessBlobPermissions.Delete
    

Catatan

Dua parameter dapat menunjuk ke kontainer blob yang sama. Parameter terpisah hanya mengaktifkan lebih banyak kontrol atas data Anda karena kontainer output memerlukan izin tambahan.

Cuplikan kode C# berikut ini memperlihatkan cara memulai pekerjaan impor:

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

Metode ini juga dapat digunakan untuk mengimpor data untuk perangkat kembar. Format untuk input data sama dengan format yang diperlihatkan di bagian ExportDevicesAsync. Dengan cara ini, Anda dapat mengimpor kembali data yang diekspor.

Perilaku impor

Anda dapat menggunakan metode ImportDevicesAsync untuk melakukan operasi massal berikut di registri identitas Anda:

  • Pendaftaran massal perangkat baru
  • Penghapusan massal perangkat yang ada
  • Perubahan status massal (aktifkan atau nonaktifkan perangkat)
  • Penetapan massal kunci autentikasi perangkat baru
  • Regenerasi otomatis massal kunci autentikasi perangkat
  • Pembaruan data kembar secara massal

Anda dapat melakukan kombinasi operasi tadi dalam satu panggilan ImportDevicesAsync. Misalnya, Anda dapat mendaftarkan perangkat baru dan menghapus atau memperbarui perangkat yang ada secara bersamaan. Ketika digunakan bersama dengan metode ExportDevicesAsync, Anda dapat sepenuhnya memigrasikan semua perangkat Anda dari satu hub IoT ke hub IoT lainnya.

Gunakan properti importMode opsional dalam data serialisasi impor untuk setiap perangkat untuk mengontrol proses impor per perangkat. Properti importMode memiliki opsi berikut:

  • Buat
  • CreateOrUpdate (default)
  • CreateOrUpdateIfMatchETag
  • Hapus
  • DeleteIfMatchETag
  • Pembaruan
  • UpdateIfMatchETag
  • UpdateTwin
  • UpdateTwinIfMatchETag

Untuk detail tentang masing-masing opsi mode impor ini, lihat ImportMode

Memecahkan masalah pekerjaan impor

Menggunakan pekerjaan impor untuk membuat perangkat mungkin gagal dengan masalah kuota saat mendekati batas jumlah perangkat hub IoT. Kegagalan ini dapat terjadi bahkan jika jumlah total perangkat masih lebih rendah dari batas kuota. Kesalahan IotHubQuotaExceeded (403002) dikembalikan dengan pesan kesalahan berikut: "Jumlah total perangkat di IotHub melebihi kuota yang dialokasikan.”

Jika muncul kesalahan ini, Anda dapat menggunakan kueri berikut untuk mengembalikan jumlah total perangkat yang terdaftar di hub IoT Anda:

SELECT COUNT() as totalNumberOfDevices FROM devices

Untuk informasi tentang jumlah total perangkat yang dapat didaftarkan ke hub IoT, lihat Batas IoT Hub.

Jika masih ada kuota yang tersedia, Anda dapat memeriksa blob output pekerjaan untuk perangkat yang gagal dengan kesalahan IotHubQuotaExceeded (403002). Anda kemudian dapat mencoba menambahkan perangkat ini satu per satu ke hub IoT. Misalnya, Anda dapat menggunakan metode AddDeviceAsync atau AddDeviceWithTwinAsync. Jangan mencoba menambahkan perangkat menggunakan pekerjaan lain karena Anda mungkin mengalami kesalahan yang sama.

Contoh impor perangkat – provisi perangkat massal

Cuplikan kode C# berikut, dari metode GenerateDevicesAsync dalam sampel SDK, menggambarkan cara menghasilkan beberapa identitas perangkat yang:

  • Menyertakan kunci autentikasi.
  • Menulis informasi perangkat itu ke blob blok.
  • Mengimpor perangkat ke dalam registri identitas.
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}.");
}

Contoh impor perangkat – penghapusan massal

Cuplikan kode C# berikut, dari metode DeleteFromHubAsync dalam sampel SDK, menunjukkan kepada Anda cara menghapus semua perangkat dari hub IoT:

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}");
}

Mendapatkan kontainer SAS URI

Sampel kode berikut menunjukkan kepada Anda cara membuat SAS URI dengan izin baca, tulis, dan hapus untuk kontainer blob:

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;
}

Langkah berikutnya

Dalam artikel ini, Anda belajar cara melakukan operasi massal terhadap registri identitas di hub IoT. Banyak dari operasi ini, termasuk cara memindahkan perangkat dari satu hub ke hub lainnya, digunakan di bagian Kelola perangkat yang terdaftar ke hub IoT di Cara memigrasikan hub Azure IoT secara manual menggunakan templat Azure Resource Manager.