public PSManagedIdentity(ManagedIdentity identity)
 {
     this.IdentityType           = identity?.Type?.ToString();
     this.PrincipalId            = identity?.PrincipalId;
     this.TenantId               = identity?.TenantId.ToString();
     this.UserAssignedIdentities = identity?.UserAssignedIdentities;
 }
        private async Task <JobProperties> CreateAndWaitForJobAsync(
            StorageAuthenticationType storageAuthenticationType,
            string devicesFileName,
            string configsFileName,
            RegistryManager registryManager,
            Uri containerUri,
            ManagedIdentity identity)
        {
            int           tryCount          = 0;
            JobProperties importJobResponse = null;

            JobProperties jobProperties = JobProperties.CreateForImportJob(
                containerUri.ToString(),
                containerUri.ToString(),
                devicesFileName,
                storageAuthenticationType,
                identity);

            jobProperties.ConfigurationsBlobName = configsFileName;
            jobProperties.IncludeConfigurations  = true;

            while (tryCount < MaxIterationWait)
            {
                try
                {
                    importJobResponse = await registryManager.ImportDevicesAsync(jobProperties).ConfigureAwait(false);

                    if (!string.IsNullOrWhiteSpace(importJobResponse.FailureReason))
                    {
                        Logger.Trace($"Job failed due to {importJobResponse.FailureReason}");
                    }
                    break;
                }
                // Concurrent jobs can be rejected, so implement a retry mechanism to handle conflicts with other tests
                catch (JobQuotaExceededException) when(++tryCount < MaxIterationWait)
                {
                    Logger.Trace($"JobQuotaExceededException... waiting.");
                    await Task.Delay(s_waitDuration).ConfigureAwait(false);

                    continue;
                }
            }

            // wait for job to complete
            for (int i = 0; i < MaxIterationWait; ++i)
            {
                await Task.Delay(1000).ConfigureAwait(false);

                importJobResponse = await registryManager.GetJobAsync(importJobResponse?.JobId).ConfigureAwait(false);

                Logger.Trace($"Job {importJobResponse.JobId} is {importJobResponse.Status} with progress {importJobResponse.Progress}%");
                if (!s_incompleteJobs.Contains(importJobResponse.Status))
                {
                    break;
                }
            }

            return(importJobResponse);
        }
 internal WebPubSubData(ResourceIdentifier id, string name, ResourceType type, SystemData systemData, IDictionary <string, string> tags, AzureLocation location, WebPubSubSku sku, ManagedIdentity identity, ProvisioningState?provisioningState, string externalIP, string hostName, int?publicPort, int?serverPort, string version, IReadOnlyList <PrivateEndpointConnectionData> privateEndpointConnections, IReadOnlyList <SharedPrivateLinkData> sharedPrivateLinkResources, WebPubSubTlsSettings tls, string hostNamePrefix, LiveTraceConfiguration liveTraceConfiguration, ResourceLogConfiguration resourceLogConfiguration, WebPubSubNetworkAcls networkAcls, string publicNetworkAccess, bool?disableLocalAuth, bool?disableAadAuth) : base(id, name, type, systemData, tags, location)
 {
     Sku                        = sku;
     Identity                   = identity;
     ProvisioningState          = provisioningState;
     ExternalIP                 = externalIP;
     HostName                   = hostName;
     PublicPort                 = publicPort;
     ServerPort                 = serverPort;
     Version                    = version;
     PrivateEndpointConnections = privateEndpointConnections;
     SharedPrivateLinkResources = sharedPrivateLinkResources;
     Tls                        = tls;
     HostNamePrefix             = hostNamePrefix;
     LiveTraceConfiguration     = liveTraceConfiguration;
     ResourceLogConfiguration   = resourceLogConfiguration;
     NetworkAcls                = networkAcls;
     PublicNetworkAccess        = publicNetworkAccess;
     DisableLocalAuth           = disableLocalAuth;
     DisableAadAuth             = disableAadAuth;
 }
 internal GrafanaResourceData(ResourceIdentifier id, string name, ResourceType resourceType, SystemData systemData, IDictionary <string, string> tags, AzureLocation location, ResourceSku sku, GrafanaResourceProperties properties, ManagedIdentity identity) : base(id, name, resourceType, systemData, tags, location)
 {
     Sku        = sku;
     Properties = properties;
     Identity   = identity;
 }
        public async Task RegistryManager_ImportDevices(StorageAuthenticationType storageAuthenticationType, bool isUserAssignedMsi)
        {
            // arrange

            const string idPrefix = nameof(RegistryManager_ImportDevices);

            string deviceId = $"{idPrefix}-device-{StorageContainer.GetRandomSuffix(4)}";
            string configId = $"{idPrefix}-config-{StorageContainer.GetRandomSuffix(4)}".ToLower(); // Configuration Id characters must be all lower-case.

            Logger.Trace($"Using Ids {deviceId} and {configId}.");

            string devicesFileName = $"{idPrefix}-devices-{StorageContainer.GetRandomSuffix(4)}.txt";
            string configsFileName = $"{idPrefix}-configs-{StorageContainer.GetRandomSuffix(4)}.txt";

            using RegistryManager registryManager = RegistryManager.CreateFromConnectionString(TestConfiguration.IoTHub.ConnectionString);

            try
            {
                string containerName = StorageContainer.BuildContainerName(nameof(RegistryManager_ImportDevices));
                using StorageContainer storageContainer = await StorageContainer.GetInstanceAsync(containerName).ConfigureAwait(false);

                Logger.Trace($"Using devices container {storageContainer.Uri}");

                Uri containerUri = storageAuthenticationType == StorageAuthenticationType.KeyBased
                    ? storageContainer.SasUri
                    : storageContainer.Uri;

                using Stream devicesStream = ImportExportHelpers.BuildImportStream(
                          new List <ExportImportDevice>
                {
                    new ExportImportDevice(
                        new Device(deviceId)
                    {
                        Authentication = new AuthenticationMechanism { Type = AuthenticationType.Sas }
                    },
                        ImportMode.Create),
                });
                await UploadFileAndConfirmAsync(storageContainer, devicesStream, devicesFileName).ConfigureAwait(false);

                using Stream configsStream = ImportExportHelpers.BuildImportStream(
                          new List <ImportConfiguration>
                {
                    new ImportConfiguration(configId)
                    {
                        ImportMode      = ConfigurationImportMode.CreateOrUpdateIfMatchETag,
                        Priority        = 3,
                        Labels          = { { "labelName", "labelValue" } },
                        TargetCondition = "*",
                        Content         =
                        {
                            DeviceContent = { { "properties.desired.x", 5L } },
                        },
                        Metrics =
                        {
                            Queries = { { "successfullyConfigured", "select deviceId from devices where properties.reported.x = 5" } }
                        },
                    },
                });
                await UploadFileAndConfirmAsync(storageContainer, configsStream, configsFileName).ConfigureAwait(false);

                ManagedIdentity identity = isUserAssignedMsi
                    ? new ManagedIdentity
                {
                    UserAssignedIdentity = TestConfiguration.IoTHub.UserAssignedMsiResourceId
                }
                    : null;

                // act

                JobProperties importJobResponse = await CreateAndWaitForJobAsync(
                    storageAuthenticationType,
                    devicesFileName,
                    configsFileName,
                    registryManager,
                    containerUri,
                    identity)
                                                  .ConfigureAwait(false);

                // assert

                importJobResponse.Status.Should().Be(JobStatus.Completed, "Otherwise import failed");
                importJobResponse.FailureReason.Should().BeNullOrEmpty("Otherwise import failed");

                // should not throw due to 404, but device may not immediately appear in registry
                Device        device = null;
                Configuration config = null;
                for (int i = 0; i < MaxIterationWait; ++i)
                {
                    await Task.Delay(s_waitDuration).ConfigureAwait(false);

                    try
                    {
                        device = await registryManager.GetDeviceAsync(deviceId).ConfigureAwait(false);

                        config = await registryManager.GetConfigurationAsync(configId).ConfigureAwait(false);

                        break;
                    }
                    catch (Exception ex)
                    {
                        Logger.Trace($"Could not find device/config on iteration {i} due to [{ex.Message}]");
                    }
                }
                if (device == null)
                {
                    Assert.Fail($"Device {deviceId} not found in registry manager");
                }
                if (config == null)
                {
                    Assert.Fail($"Config {configId} not found in registry manager");
                }
            }
            finally
            {
                try
                {
                    await registryManager.RemoveDeviceAsync(deviceId).ConfigureAwait(false);

                    await registryManager.RemoveConfigurationAsync(configId).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    Logger.Trace($"Failed to clean up device/config due to {ex}");
                }
            }
        }
示例#6
0
        internal static ManagedGrafanaData DeserializeManagedGrafanaData(JsonElement element)
        {
            Optional <ResourceSku> sku = default;
            Optional <ManagedGrafanaProperties> properties = default;
            Optional <ManagedIdentity>          identity   = default;
            IDictionary <string, string>        tags       = default;
            AzureLocation      location   = default;
            ResourceIdentifier id         = default;
            string             name       = default;
            ResourceType       type       = default;
            SystemData         systemData = default;

            foreach (var property in element.EnumerateObject())
            {
                if (property.NameEquals("sku"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        property.ThrowNonNullablePropertyIsNull();
                        continue;
                    }
                    sku = ResourceSku.DeserializeResourceSku(property.Value);
                    continue;
                }
                if (property.NameEquals("properties"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        property.ThrowNonNullablePropertyIsNull();
                        continue;
                    }
                    properties = ManagedGrafanaProperties.DeserializeManagedGrafanaProperties(property.Value);
                    continue;
                }
                if (property.NameEquals("identity"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        property.ThrowNonNullablePropertyIsNull();
                        continue;
                    }
                    identity = ManagedIdentity.DeserializeManagedIdentity(property.Value);
                    continue;
                }
                if (property.NameEquals("tags"))
                {
                    Dictionary <string, string> dictionary = new Dictionary <string, string>();
                    foreach (var property0 in property.Value.EnumerateObject())
                    {
                        dictionary.Add(property0.Name, property0.Value.GetString());
                    }
                    tags = dictionary;
                    continue;
                }
                if (property.NameEquals("location"))
                {
                    location = property.Value.GetString();
                    continue;
                }
                if (property.NameEquals("id"))
                {
                    id = new ResourceIdentifier(property.Value.GetString());
                    continue;
                }
                if (property.NameEquals("name"))
                {
                    name = property.Value.GetString();
                    continue;
                }
                if (property.NameEquals("type"))
                {
                    type = property.Value.GetString();
                    continue;
                }
                if (property.NameEquals("systemData"))
                {
                    systemData = JsonSerializer.Deserialize <SystemData>(property.Value.ToString());
                    continue;
                }
            }
            return(new ManagedGrafanaData(id, name, type, systemData, tags, location, sku.Value, properties.Value, identity.Value));
        }
        public async Task RegistryManager_ImportDevices(StorageAuthenticationType storageAuthenticationType, bool isUserAssignedMsi)
        {
            // arrange

            StorageContainer storageContainer = null;
            string           deviceId         = $"{nameof(RegistryManager_ImportDevices)}-{StorageContainer.GetRandomSuffix(4)}";
            var registryManager = RegistryManager.CreateFromConnectionString(Configuration.IoTHub.ConnectionString);

            Logger.Trace($"Using deviceId {deviceId}");

            try
            {
                string containerName = StorageContainer.BuildContainerName(nameof(RegistryManager_ImportDevices));
                storageContainer = await StorageContainer
                                   .GetInstanceAsync(containerName)
                                   .ConfigureAwait(false);

                Logger.Trace($"Using container {storageContainer.Uri}");

                Uri containerUri = storageAuthenticationType == StorageAuthenticationType.KeyBased
                    ? storageContainer.SasUri
                    : storageContainer.Uri;

                Stream devicesFile = ImportExportDevicesHelpers.BuildDevicesStream(
                    new List <ExportImportDevice>
                {
                    new ExportImportDevice(
                        new Device(deviceId)
                    {
                        Authentication = new AuthenticationMechanism {
                            Type = AuthenticationType.Sas
                        }
                    },
                        ImportMode.Create),
                });
                await UploadFileAndConfirmAsync(storageContainer, devicesFile).ConfigureAwait(false);

                // act

                JobProperties importJobResponse = null;
                int           tryCount          = 0;
                while (true)
                {
                    try
                    {
                        ManagedIdentity identity = null;
                        if (isUserAssignedMsi)
                        {
                            string userAssignedMsiResourceId = Configuration.IoTHub.UserAssignedMsiResourceId;
                            identity = new ManagedIdentity
                            {
                                userAssignedIdentity = userAssignedMsiResourceId
                            };
                        }

                        importJobResponse = await registryManager
                                            .ImportDevicesAsync(
                            JobProperties.CreateForImportJob(
                                containerUri.ToString(),
                                containerUri.ToString(),
                                null,
                                storageAuthenticationType))
                                            .ConfigureAwait(false);

                        break;
                    }
                    // Concurrent jobs can be rejected, so implement a retry mechanism to handle conflicts with other tests
                    catch (JobQuotaExceededException) when(++tryCount < MaxIterationWait)
                    {
                        Logger.Trace($"JobQuotaExceededException... waiting.");
                        await Task.Delay(s_waitDuration).ConfigureAwait(false);

                        continue;
                    }
                }

                // wait for job to complete
                for (int i = 0; i < MaxIterationWait; ++i)
                {
                    await Task.Delay(1000).ConfigureAwait(false);

                    importJobResponse = await registryManager.GetJobAsync(importJobResponse.JobId).ConfigureAwait(false);

                    Logger.Trace($"Job {importJobResponse.JobId} is {importJobResponse.Status} with progress {importJobResponse.Progress}%");
                    if (!s_incompleteJobs.Contains(importJobResponse.Status))
                    {
                        break;
                    }
                }

                // assert

                importJobResponse.Status.Should().Be(JobStatus.Completed, "Otherwise import failed");
                importJobResponse.FailureReason.Should().BeNullOrEmpty("Otherwise import failed");

                // should not throw due to 404, but device may not immediately appear in registry
                Device device = null;
                for (int i = 0; i < MaxIterationWait; ++i)
                {
                    await Task.Delay(s_waitDuration).ConfigureAwait(false);

                    try
                    {
                        device = await registryManager.GetDeviceAsync(deviceId).ConfigureAwait(false);

                        break;
                    }
                    catch (Exception ex)
                    {
                        Logger.Trace($"Could not find device on iteration {i} due to [{ex.Message}]");
                    }
                }
                if (device == null)
                {
                    Assert.Fail($"Device {deviceId} not found in registry manager");
                }
            }
            finally
            {
                try
                {
                    storageContainer?.Dispose();

                    await registryManager.RemoveDeviceAsync(deviceId).ConfigureAwait(false);
                }
                catch { }
            }
        }
        internal static WebPubSubData DeserializeWebPubSubData(JsonElement element)
        {
            Optional <WebPubSubSku>      sku               = default;
            Optional <ManagedIdentity>   identity          = default;
            Optional <SystemData>        systemData        = default;
            IDictionary <string, string> tags              = default;
            Location                     location          = default;
            ResourceIdentifier           id                = default;
            string                       name              = default;
            ResourceType                 type              = default;
            Optional <ProvisioningState> provisioningState = default;
            Optional <string>            externalIP        = default;
            Optional <string>            hostName          = default;
            Optional <int>               publicPort        = default;
            Optional <int>               serverPort        = default;
            Optional <string>            version           = default;
            Optional <IReadOnlyList <PrivateEndpointConnectionData> > privateEndpointConnections = default;
            Optional <IReadOnlyList <SharedPrivateLinkData> >         sharedPrivateLinkResources = default;
            Optional <WebPubSubTlsSettings> tls = default;
            Optional <string> hostNamePrefix    = default;
            Optional <LiveTraceConfiguration>   liveTraceConfiguration   = default;
            Optional <ResourceLogConfiguration> resourceLogConfiguration = default;
            Optional <WebPubSubNetworkAcls>     networkACLs = default;
            Optional <string> publicNetworkAccess           = default;
            Optional <bool>   disableLocalAuth = default;
            Optional <bool>   disableAadAuth   = default;

            foreach (var property in element.EnumerateObject())
            {
                if (property.NameEquals("sku"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        property.ThrowNonNullablePropertyIsNull();
                        continue;
                    }
                    sku = WebPubSubSku.DeserializeWebPubSubSku(property.Value);
                    continue;
                }
                if (property.NameEquals("identity"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        property.ThrowNonNullablePropertyIsNull();
                        continue;
                    }
                    identity = ManagedIdentity.DeserializeManagedIdentity(property.Value);
                    continue;
                }
                if (property.NameEquals("systemData"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        property.ThrowNonNullablePropertyIsNull();
                        continue;
                    }
                    systemData = JsonSerializer.Deserialize <SystemData>(property.Value.ToString());
                    continue;
                }
                if (property.NameEquals("tags"))
                {
                    Dictionary <string, string> dictionary = new Dictionary <string, string>();
                    foreach (var property0 in property.Value.EnumerateObject())
                    {
                        dictionary.Add(property0.Name, property0.Value.GetString());
                    }
                    tags = dictionary;
                    continue;
                }
                if (property.NameEquals("location"))
                {
                    location = property.Value.GetString();
                    continue;
                }
                if (property.NameEquals("id"))
                {
                    id = new ResourceIdentifier(property.Value.GetString());
                    continue;
                }
                if (property.NameEquals("name"))
                {
                    name = property.Value.GetString();
                    continue;
                }
                if (property.NameEquals("type"))
                {
                    type = property.Value.GetString();
                    continue;
                }
                if (property.NameEquals("properties"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        property.ThrowNonNullablePropertyIsNull();
                        continue;
                    }
                    foreach (var property0 in property.Value.EnumerateObject())
                    {
                        if (property0.NameEquals("provisioningState"))
                        {
                            if (property0.Value.ValueKind == JsonValueKind.Null)
                            {
                                property0.ThrowNonNullablePropertyIsNull();
                                continue;
                            }
                            provisioningState = new ProvisioningState(property0.Value.GetString());
                            continue;
                        }
                        if (property0.NameEquals("externalIP"))
                        {
                            externalIP = property0.Value.GetString();
                            continue;
                        }
                        if (property0.NameEquals("hostName"))
                        {
                            hostName = property0.Value.GetString();
                            continue;
                        }
                        if (property0.NameEquals("publicPort"))
                        {
                            if (property0.Value.ValueKind == JsonValueKind.Null)
                            {
                                property0.ThrowNonNullablePropertyIsNull();
                                continue;
                            }
                            publicPort = property0.Value.GetInt32();
                            continue;
                        }
                        if (property0.NameEquals("serverPort"))
                        {
                            if (property0.Value.ValueKind == JsonValueKind.Null)
                            {
                                property0.ThrowNonNullablePropertyIsNull();
                                continue;
                            }
                            serverPort = property0.Value.GetInt32();
                            continue;
                        }
                        if (property0.NameEquals("version"))
                        {
                            version = property0.Value.GetString();
                            continue;
                        }
                        if (property0.NameEquals("privateEndpointConnections"))
                        {
                            if (property0.Value.ValueKind == JsonValueKind.Null)
                            {
                                property0.ThrowNonNullablePropertyIsNull();
                                continue;
                            }
                            List <PrivateEndpointConnectionData> array = new List <PrivateEndpointConnectionData>();
                            foreach (var item in property0.Value.EnumerateArray())
                            {
                                array.Add(PrivateEndpointConnectionData.DeserializePrivateEndpointConnectionData(item));
                            }
                            privateEndpointConnections = array;
                            continue;
                        }
                        if (property0.NameEquals("sharedPrivateLinkResources"))
                        {
                            if (property0.Value.ValueKind == JsonValueKind.Null)
                            {
                                property0.ThrowNonNullablePropertyIsNull();
                                continue;
                            }
                            List <SharedPrivateLinkData> array = new List <SharedPrivateLinkData>();
                            foreach (var item in property0.Value.EnumerateArray())
                            {
                                array.Add(SharedPrivateLinkData.DeserializeSharedPrivateLinkData(item));
                            }
                            sharedPrivateLinkResources = array;
                            continue;
                        }
                        if (property0.NameEquals("tls"))
                        {
                            if (property0.Value.ValueKind == JsonValueKind.Null)
                            {
                                property0.ThrowNonNullablePropertyIsNull();
                                continue;
                            }
                            tls = WebPubSubTlsSettings.DeserializeWebPubSubTlsSettings(property0.Value);
                            continue;
                        }
                        if (property0.NameEquals("hostNamePrefix"))
                        {
                            hostNamePrefix = property0.Value.GetString();
                            continue;
                        }
                        if (property0.NameEquals("liveTraceConfiguration"))
                        {
                            if (property0.Value.ValueKind == JsonValueKind.Null)
                            {
                                property0.ThrowNonNullablePropertyIsNull();
                                continue;
                            }
                            liveTraceConfiguration = LiveTraceConfiguration.DeserializeLiveTraceConfiguration(property0.Value);
                            continue;
                        }
                        if (property0.NameEquals("resourceLogConfiguration"))
                        {
                            if (property0.Value.ValueKind == JsonValueKind.Null)
                            {
                                property0.ThrowNonNullablePropertyIsNull();
                                continue;
                            }
                            resourceLogConfiguration = ResourceLogConfiguration.DeserializeResourceLogConfiguration(property0.Value);
                            continue;
                        }
                        if (property0.NameEquals("networkACLs"))
                        {
                            if (property0.Value.ValueKind == JsonValueKind.Null)
                            {
                                property0.ThrowNonNullablePropertyIsNull();
                                continue;
                            }
                            networkACLs = WebPubSubNetworkAcls.DeserializeWebPubSubNetworkAcls(property0.Value);
                            continue;
                        }
                        if (property0.NameEquals("publicNetworkAccess"))
                        {
                            publicNetworkAccess = property0.Value.GetString();
                            continue;
                        }
                        if (property0.NameEquals("disableLocalAuth"))
                        {
                            if (property0.Value.ValueKind == JsonValueKind.Null)
                            {
                                property0.ThrowNonNullablePropertyIsNull();
                                continue;
                            }
                            disableLocalAuth = property0.Value.GetBoolean();
                            continue;
                        }
                        if (property0.NameEquals("disableAadAuth"))
                        {
                            if (property0.Value.ValueKind == JsonValueKind.Null)
                            {
                                property0.ThrowNonNullablePropertyIsNull();
                                continue;
                            }
                            disableAadAuth = property0.Value.GetBoolean();
                            continue;
                        }
                    }
                    continue;
                }
            }
            return(new WebPubSubData(id, name, type, tags, location, sku.Value, identity.Value, systemData, Optional.ToNullable(provisioningState), externalIP.Value, hostName.Value, Optional.ToNullable(publicPort), Optional.ToNullable(serverPort), version.Value, Optional.ToList(privateEndpointConnections), Optional.ToList(sharedPrivateLinkResources), tls.Value, hostNamePrefix.Value, liveTraceConfiguration.Value, resourceLogConfiguration.Value, networkACLs.Value, publicNetworkAccess.Value, Optional.ToNullable(disableLocalAuth), Optional.ToNullable(disableAadAuth)));
        }
示例#9
0
 public PSManagedIdentity(ManagedIdentity identity)
 {
     this.IdentityType = identity?.Type?.ToString();
     this.PrincipalId  = identity?.PrincipalId;
     this.TenantId     = identity?.TenantId;
 }
        private async Task <JobProperties> CreateAndWaitForJobAsync(
            StorageAuthenticationType storageAuthenticationType,
            bool isUserAssignedMsi,
            string devicesFileName,
            string configsFileName,
            RegistryManager registryManager,
            Uri containerUri)
        {
            int tryCount = 0;

            ManagedIdentity identity = isUserAssignedMsi
                ? new ManagedIdentity
            {
                UserAssignedIdentity = TestConfiguration.IoTHub.UserAssignedMsiResourceId
            }
                : null;

            JobProperties exportJobResponse = JobProperties.CreateForExportJob(
                containerUri.ToString(),
                true,
                devicesFileName,
                storageAuthenticationType,
                identity);

            exportJobResponse.IncludeConfigurations  = true;
            exportJobResponse.ConfigurationsBlobName = configsFileName;

            while (tryCount < MaxIterationWait)
            {
                try
                {
                    exportJobResponse = await registryManager.ExportDevicesAsync(exportJobResponse).ConfigureAwait(false);

                    break;
                }
                // Concurrent jobs can be rejected, so implement a retry mechanism to handle conflicts with other tests
                catch (JobQuotaExceededException) when(++tryCount < MaxIterationWait)
                {
                    Logger.Trace($"JobQuotaExceededException... waiting.");
                    await Task.Delay(s_waitDuration).ConfigureAwait(false);

                    continue;
                }
            }

            for (int i = 0; i < MaxIterationWait; ++i)
            {
                await Task.Delay(s_waitDuration).ConfigureAwait(false);

                exportJobResponse = await registryManager.GetJobAsync(exportJobResponse.JobId).ConfigureAwait(false);

                Logger.Trace($"Job {exportJobResponse.JobId} is {exportJobResponse.Status} with progress {exportJobResponse.Progress}%");
                if (!s_incompleteJobs.Contains(exportJobResponse.Status))
                {
                    break;
                }
            }

            exportJobResponse.Status.Should().Be(JobStatus.Completed, "Otherwise import failed");
            exportJobResponse.FailureReason.Should().BeNullOrEmpty("Otherwise import failed");

            return(exportJobResponse);
        }
        public async Task RegistryManager_ExportDevices(StorageAuthenticationType storageAuthenticationType, bool isUserAssignedMsi)
        {
            // arrange

            StorageContainer storageContainer = null;
            string           deviceId         = $"{nameof(RegistryManager_ExportDevices)}-{StorageContainer.GetRandomSuffix(4)}";
            var registryManager = RegistryManager.CreateFromConnectionString(Configuration.IoTHub.ConnectionString);

            Logger.Trace($"Using deviceId {deviceId}");

            try
            {
                string containerName = StorageContainer.BuildContainerName(nameof(RegistryManager_ExportDevices));
                storageContainer = await StorageContainer
                                   .GetInstanceAsync(containerName)
                                   .ConfigureAwait(false);

                Logger.Trace($"Using container {storageContainer.Uri}");

                Uri containerUri = storageAuthenticationType == StorageAuthenticationType.KeyBased
                    ? storageContainer.SasUri
                    : storageContainer.Uri;

                await registryManager
                .AddDeviceAsync(
                    new Device(deviceId)
                {
                    Authentication = new AuthenticationMechanism {
                        Type = AuthenticationType.Sas
                    },
                })
                .ConfigureAwait(false);

                // act

                JobProperties exportJobResponse = null;
                int           tryCount          = 0;
                while (true)
                {
                    try
                    {
                        ManagedIdentity identity = null;
                        if (isUserAssignedMsi)
                        {
                            string userAssignedMsiResourceId = Configuration.IoTHub.UserAssignedMsiResourceId;
                            identity = new ManagedIdentity
                            {
                                userAssignedIdentity = userAssignedMsiResourceId
                            };
                        }

                        exportJobResponse = await registryManager
                                            .ExportDevicesAsync(
                            JobProperties.CreateForExportJob(
                                containerUri.ToString(),
                                true,
                                null,
                                storageAuthenticationType,
                                identity))
                                            .ConfigureAwait(false);

                        break;
                    }
                    // Concurrent jobs can be rejected, so implement a retry mechanism to handle conflicts with other tests
                    catch (JobQuotaExceededException) when(++tryCount < MaxIterationWait)
                    {
                        Logger.Trace($"JobQuotaExceededException... waiting.");
                        await Task.Delay(_waitDuration).ConfigureAwait(false);

                        continue;
                    }
                }

                // wait for job to complete
                for (int i = 0; i < MaxIterationWait; ++i)
                {
                    await Task.Delay(_waitDuration).ConfigureAwait(false);

                    exportJobResponse = await registryManager.GetJobAsync(exportJobResponse.JobId).ConfigureAwait(false);

                    Logger.Trace($"Job {exportJobResponse.JobId} is {exportJobResponse.Status} with progress {exportJobResponse.Progress}%");
                    if (!s_incompleteJobs.Contains(exportJobResponse.Status))
                    {
                        break;
                    }
                }

                // assert

                exportJobResponse.Status.Should().Be(JobStatus.Completed, "Otherwise import failed");
                exportJobResponse.FailureReason.Should().BeNullOrEmpty("Otherwise import failed");

                string content = await DownloadFileAsync(storageContainer).ConfigureAwait(false);

                string[] serializedDevices = content.Split(s_newlines, StringSplitOptions.RemoveEmptyEntries);

                bool foundDeviceInExport = false;
                foreach (string serializedDeivce in serializedDevices)
                {
                    // The first line may be a comment to the user, so skip any lines that don't start with a json object initial character: curly brace
                    if (serializedDeivce[0] != '{')
                    {
                        continue;
                    }

                    ExportImportDevice device = JsonConvert.DeserializeObject <ExportImportDevice>(serializedDeivce);
                    if (StringComparer.Ordinal.Equals(device.Id, deviceId))
                    {
                        Logger.Trace($"Found device in export as [{serializedDeivce}]");
                        foundDeviceInExport = true;
                        break;
                    }
                }
                foundDeviceInExport.Should().BeTrue("Expected device did not appear in the export");
            }
            finally
            {
                try
                {
                    storageContainer?.Dispose();

                    await registryManager.RemoveDeviceAsync(deviceId).ConfigureAwait(false);
                }
                catch { }
            }
        }