diff --git a/e2e/test/iothub/service/RegistryManagerExportDevicesTests.cs b/e2e/test/iothub/service/RegistryManagerExportDevicesTests.cs index 0a82c6b650..1b1b8795be 100644 --- a/e2e/test/iothub/service/RegistryManagerExportDevicesTests.cs +++ b/e2e/test/iothub/service/RegistryManagerExportDevicesTests.cs @@ -54,6 +54,7 @@ public async Task RegistryManager_ExportDevices(StorageAuthenticationType storag // arrange StorageContainer storageContainer = null; + string edgeId = $"{nameof(RegistryManager_ExportDevices)}-Edge-{StorageContainer.GetRandomSuffix(4)}"; string deviceId = $"{nameof(RegistryManager_ExportDevices)}-{StorageContainer.GetRandomSuffix(4)}"; var registryManager = RegistryManager.CreateFromConnectionString(TestConfiguration.IoTHub.ConnectionString); @@ -71,11 +72,21 @@ public async Task RegistryManager_ExportDevices(StorageAuthenticationType storag ? storageContainer.SasUri : storageContainer.Uri; + var edge = await registryManager + .AddDeviceAsync( + new Device(edgeId) + { + Authentication = new AuthenticationMechanism { Type = AuthenticationType.Sas }, + Capabilities = new Shared.DeviceCapabilities { IotEdge = true }, + }) + .ConfigureAwait(false); + await registryManager .AddDeviceAsync( new Device(deviceId) { Authentication = new AuthenticationMechanism { Type = AuthenticationType.Sas }, + Scope = edge.Scope, }) .ConfigureAwait(false); @@ -151,6 +162,7 @@ await registryManager { Logger.Trace($"Found device in export as [{serializedDeivce}]"); foundDeviceInExport = true; + device.DeviceScope.Should().Be(edge.Scope); break; } } @@ -163,6 +175,7 @@ await registryManager storageContainer?.Dispose(); await registryManager.RemoveDeviceAsync(deviceId).ConfigureAwait(false); + await registryManager.RemoveDeviceAsync(edgeId).ConfigureAwait(false); } catch { } } diff --git a/iothub/service/src/Device.cs b/iothub/service/src/Device.cs index 610416e563..b5b3c7ccfd 100644 --- a/iothub/service/src/Device.cs +++ b/iothub/service/src/Device.cs @@ -114,7 +114,7 @@ public Device(string id) /// relationship. /// /// - /// For leaf devices, the value to set a parent edge device can be retrieved from the parent edge device's property. + /// For leaf devices, the value to set a parent edge device can be retrieved from the parent edge device's Scope property. /// /// For more information, see . /// diff --git a/iothub/service/src/ExportImportDevice.cs b/iothub/service/src/ExportImportDevice.cs index 8d8ddb7e42..eacfc12b6d 100644 --- a/iothub/service/src/ExportImportDevice.cs +++ b/iothub/service/src/ExportImportDevice.cs @@ -5,13 +5,14 @@ // --------------------------------------------------------------- using System; +using System.Diagnostics.CodeAnalysis; using Microsoft.Azure.Devices.Shared; using Newtonsoft.Json; namespace Microsoft.Azure.Devices { /// - /// Contains device properties specified during export/import operation + /// Contains device properties specified during export/import job operation. /// public sealed class ExportImportDevice { @@ -21,7 +22,7 @@ public sealed class ExportImportDevice /// /// Property container /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1034:Nested types should not be visible", Justification = "Public property. No behavior changes allowed.")] + [SuppressMessage("Design", "CA1034:Nested types should not be visible", Justification = "Public property. No behavior changes allowed.")] public sealed class PropertyContainer { /// @@ -38,14 +39,14 @@ public sealed class PropertyContainer } /// - /// Create an ExportImportDevice + /// Create an ExportImportDevice. /// public ExportImportDevice() { } /// - /// Create an ExportImportDevice + /// Create an ExportImportDevice. /// /// Device properties /// Identifies the behavior when merging a device to the registry during import actions. @@ -66,13 +67,13 @@ public ExportImportDevice(Device device, ImportMode importmode) } /// - /// Id of the device + /// Id of the device. /// [JsonProperty(PropertyName = "id", Required = Required.Always)] public string Id { get; set; } /// - /// Module Id for the object + /// Module Id for the object. /// [JsonProperty(PropertyName = "moduleId", NullValueHandling = NullValueHandling.Ignore)] public string ModuleId { get; set; } @@ -88,31 +89,31 @@ public string ETag } /// - /// ImportMode of the device + /// Import mode of the device. /// [JsonProperty(PropertyName = "importMode", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] public ImportMode ImportMode { get; set; } /// - /// Status of the device + /// Status of the device. /// [JsonProperty(PropertyName = "status", Required = Required.Always)] public DeviceStatus Status { get; set; } /// - /// StatusReason of the device + /// Status reason of the device. /// [JsonProperty(PropertyName = "statusReason", NullValueHandling = NullValueHandling.Ignore)] public string StatusReason { get; set; } /// - /// AuthenticationMechanism of the device + /// Authentication mechanism of the device. /// [JsonProperty(PropertyName = "authentication")] public AuthenticationMechanism Authentication { get; set; } /// - /// string representing a Twin ETag for the entity, as per RFC7232. + /// String representing a Twin ETag for the entity, as per RFC7232. /// [JsonProperty(PropertyName = "twinETag", NullValueHandling = NullValueHandling.Ignore)] public string TwinETag @@ -128,17 +129,29 @@ public string TwinETag public TwinCollection Tags { get; set; } /// - /// Desired and Reported property bags + /// Desired and reported property bags /// [JsonProperty(PropertyName = "properties", NullValueHandling = NullValueHandling.Ignore)] public PropertyContainer Properties { get; set; } /// - /// Status of Capabilities enabled on the device + /// Status of capabilities enabled on the device /// [JsonProperty(PropertyName = "capabilities", NullValueHandling = NullValueHandling.Ignore)] public DeviceCapabilities Capabilities { get; set; } + /// + /// The scope of the device. For edge devices, this is auto-generated and immutable. For leaf devices, set this to create child/parent + /// relationship. + /// + /// + /// For leaf devices, the value to set a parent edge device can be retrieved from the parent edge device's device scope property. + /// + /// For more information, see . + /// + [JsonProperty(PropertyName = "deviceScope", NullValueHandling = NullValueHandling.Include)] + public string DeviceScope { get; set; } + private static string SanitizeETag(string eTag) { if (!string.IsNullOrWhiteSpace(eTag))