/// <summary>
        /// Enable or disable twin on supervisor
        /// </summary>
        /// <param name="supervisorId"></param>
        /// <param name="twinId"></param>
        /// <param name="secret"></param>
        /// <param name="ct"></param>
        /// <returns></returns>
        private async Task SetSupervisorTwinSecretAsync(string supervisorId,
                                                        string twinId, string secret, CancellationToken ct = default)
        {
            if (string.IsNullOrEmpty(twinId))
            {
                throw new ArgumentNullException(nameof(twinId));
            }
            if (string.IsNullOrEmpty(supervisorId))
            {
                return; // ok, no supervisor
            }
            var deviceId = SupervisorModelEx.ParseDeviceId(supervisorId, out var moduleId);

            if (secret == null)
            {
                // Remove from supervisor - this disconnects the device
                await _iothub.UpdatePropertyAsync(deviceId, moduleId, twinId, null, ct);

                _logger.Information("Twin {twinId} deactivated on {supervisorId}.",
                                    twinId, supervisorId);
            }
            else
            {
                // Update supervisor to start supervising this endpoint
                await _iothub.UpdatePropertyAsync(deviceId, moduleId, twinId, secret, ct);

                _logger.Information("Twin {twinId} activated on {supervisorId}.",
                                    twinId, supervisorId);
            }
        }
        /// <inheritdoc/>
        public async Task <byte[]> GetEndpointCertificateAsync(
            EndpointRegistrationModel registration, CancellationToken ct)
        {
            if (registration == null)
            {
                throw new ArgumentNullException(nameof(registration));
            }
            if (registration.Endpoint == null)
            {
                throw new ArgumentNullException(nameof(registration.Endpoint));
            }
            if (string.IsNullOrEmpty(registration.SupervisorId))
            {
                throw new ArgumentNullException(nameof(registration.SupervisorId));
            }

            var deviceId = SupervisorModelEx.ParseDeviceId(registration.SupervisorId,
                                                           out var moduleId);

            var sw     = Stopwatch.StartNew();
            var result = await _client.CallMethodAsync(deviceId, moduleId,
                                                       "GetEndpointCertificate_V2",
                                                       _serializer.SerializeToString(registration.Endpoint), null, ct);

            _logger.Debug("Calling supervisor {deviceId}/{moduleId} to get certificate." +
                          "Took {elapsed} ms and returned {result}!", deviceId, moduleId,
                          sw.ElapsedMilliseconds, result);
            return(_serializer.Deserialize <byte[]>(result));
        }
Exemple #3
0
        /// <summary>
        /// Publisher demands
        /// </summary>
        /// <param name="endpoint"></param>
        /// <returns></returns>
        private static List <DemandModel> PublisherDemands(EndpointInfoModel endpoint)
        {
            var demands = new List <DemandModel> {
                new DemandModel {
                    Key   = "Type",
                    Value = IdentityType.Publisher
                }
            };

            // Add site as demand if available
            if (!string.IsNullOrEmpty(endpoint.Registration.SiteId))
            {
                demands.Add(new DemandModel {
                    Key   = nameof(endpoint.Registration.SiteId),
                    Value = endpoint.Registration.SiteId
                });
            }
            else if (!string.IsNullOrEmpty(endpoint.Registration.SupervisorId))
            {
                var deviceId = SupervisorModelEx.ParseDeviceId(
                    endpoint.Registration.SupervisorId, out _);
                // Otherwise confine to the supervisor's gateway
                demands.Add(new DemandModel {
                    Key   = "DeviceId",
                    Value = deviceId
                });
            }
            return(demands);
        }
        /// <summary>
        /// helper to invoke service
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="R"></typeparam>
        /// <param name="service"></param>
        /// <param name="registration"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        private async Task <R> CallServiceOnSupervisorAsync <T, R>(string service,
                                                                   EndpointRegistrationModel registration, T request)
        {
            if (registration == null)
            {
                throw new ArgumentNullException(nameof(registration));
            }
            if (registration.Endpoint == null)
            {
                throw new ArgumentNullException(nameof(registration.Endpoint));
            }
            if (string.IsNullOrEmpty(registration.SupervisorId))
            {
                throw new ArgumentNullException(nameof(registration.SupervisorId));
            }
            var sw       = Stopwatch.StartNew();
            var deviceId = SupervisorModelEx.ParseDeviceId(registration.SupervisorId,
                                                           out var moduleId);
            var result = await _client.CallMethodAsync(deviceId, moduleId, service,
                                                       _serializer.SerializeToString(new {
                endpoint = registration.Endpoint,
                request
            }));

            _logger.Debug("Calling supervisor service '{service}' on {deviceId}/{moduleId} " +
                          "took {elapsed} ms and returned {result}!", service, deviceId, moduleId,
                          sw.ElapsedMilliseconds, result);
            return(_serializer.Deserialize <R>(result));
        }
        /// <inheritdoc/>
        public async Task UpdateSupervisorAsync(string supervisorId,
                                                SupervisorUpdateModel request, CancellationToken ct)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }
            if (string.IsNullOrEmpty(supervisorId))
            {
                throw new ArgumentException(nameof(supervisorId));
            }

            // Get existing endpoint and compare to see if we need to patch.
            var deviceId = SupervisorModelEx.ParseDeviceId(supervisorId, out var moduleId);

            while (true)
            {
                try {
                    var twin = await _iothub.GetAsync(deviceId, moduleId, ct);

                    if (twin.Id != deviceId && twin.ModuleId != moduleId)
                    {
                        throw new ArgumentException("Id must be same as twin to patch",
                                                    nameof(supervisorId));
                    }

                    var registration = twin.ToEntityRegistration(true) as SupervisorRegistration;
                    if (registration == null)
                    {
                        throw new ResourceNotFoundException(
                                  $"{supervisorId} is not a supervisor registration.");
                    }

                    // Update registration from update request
                    var patched = registration.ToServiceModel();

                    if (request.SiteId != null)
                    {
                        patched.SiteId = string.IsNullOrEmpty(request.SiteId) ?
                                         null : request.SiteId;
                    }

                    if (request.LogLevel != null)
                    {
                        patched.LogLevel = request.LogLevel == TraceLogLevel.Information ?
                                           null : request.LogLevel;
                    }

                    // Patch
                    await _iothub.PatchAsync(registration.Patch(
                                                 patched.ToSupervisorRegistration()), false, ct);

                    return;
                }
                catch (ResourceOutOfDateException ex) {
                    _logger.Debug(ex, "Retrying updating supervisor...");
                    continue;
                }
            }
        }
        /// <summary>
        /// Get device scope of the supervisor
        /// </summary>
        /// <param name="supervisorId"></param>
        /// <param name="ct"></param>
        /// <returns></returns>
        private async Task <string> GetSupervisorDeviceScopeAsync(string supervisorId,
                                                                  CancellationToken ct = default)
        {
            if (string.IsNullOrEmpty(supervisorId))
            {
                return(null); // No scope
            }
            var edgeDeviceId   = SupervisorModelEx.ParseDeviceId(supervisorId, out _);
            var edgeDeviceTwin = await _iothub.FindAsync(edgeDeviceId, ct : ct);

            return(edgeDeviceTwin?.DeviceScope);
        }
Exemple #7
0
        /// <summary>
        /// Send endpoint alert
        /// </summary>
        /// <param name="endpoint"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        private Task SendEndpointAlertAsync(EndpointInfoModel endpoint, string message)
        {
#if USE_SUPERVISOR_IDENTITY
            var deviceId = SupervisorModelEx.ParseDeviceId(
                endpoint.Registration.SupervisorId, out var moduleId);
#else
            var deviceId = endpoint.Registration.Id;
            var moduleId = (string)null;
#endif
            return(SendAlertAsync(deviceId, moduleId, message,
                                  FlattenToDict(endpoint.Registration)));
        }
        /// <summary>
        /// Helper to invoke service
        /// </summary>
        /// <param name="service"></param>
        /// <param name="supervisorId"></param>
        /// <param name="payload"></param>
        /// <returns></returns>
        private async Task CallServiceOnSupervisor(string service, string supervisorId,
                                                   object payload)
        {
            var sw       = Stopwatch.StartNew();
            var deviceId = SupervisorModelEx.ParseDeviceId(supervisorId,
                                                           out var moduleId);
            var result = await _client.CallMethodAsync(deviceId, moduleId, service,
                                                       JsonConvertEx.SerializeObject(payload));

            _logger.Debug("Calling supervisor service '{service}' on " +
                          "{deviceId}/{moduleId} took {elapsed} ms.", service, deviceId,
                          moduleId, sw.ElapsedMilliseconds);
        }
Exemple #9
0
        /// <summary>
        /// Helper to invoke service
        /// </summary>
        /// <param name="service"></param>
        /// <param name="supervisorId"></param>
        /// <param name="payload"></param>
        /// <param name="ct"></param>
        /// <returns></returns>
        private async Task CallServiceOnSupervisorAsync(string service, string supervisorId,
                                                        object payload, CancellationToken ct)
        {
            var sw       = Stopwatch.StartNew();
            var deviceId = SupervisorModelEx.ParseDeviceId(supervisorId,
                                                           out var moduleId);
            var result = await _client.CallMethodAsync(deviceId, moduleId, service,
                                                       _serializer.SerializeToString(payload), null, ct);

            _logger.Debug("Calling supervisor service '{service}' on " +
                          "{deviceId}/{moduleId} took {elapsed} ms.", service, deviceId,
                          moduleId, sw.ElapsedMilliseconds);
        }
Exemple #10
0
        /// <summary>
        /// Send application alert
        /// </summary>
        /// <param name="application"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        private Task SendApplicationAlertAsync(ApplicationInfoModel application,
                                               string message)
        {
#if !USE_APPLICATION_IDENTITY
            var deviceId = SupervisorModelEx.ParseDeviceId(
                application.SupervisorId, out var moduleId);
#else
            var deviceId = application.ApplicationId;
            var moduleId = (string)null;
#endif
            return(SendAlertAsync(deviceId, moduleId, message,
                                  FlattenToDict(application)));
        }
        /// <inheritdoc/>
        public async Task ResetSupervisorAsync(string supervisorId)
        {
            if (string.IsNullOrEmpty(supervisorId))
            {
                throw new ArgumentNullException(nameof(supervisorId));
            }
            var sw       = Stopwatch.StartNew();
            var deviceId = SupervisorModelEx.ParseDeviceId(supervisorId,
                                                           out var moduleId);
            var result = await _client.CallMethodAsync(deviceId, moduleId,
                                                       "Reset_V2", null);

            _logger.Debug("Reset supervisor {deviceId}/{moduleId} took " +
                          "{elapsed} ms.", deviceId, moduleId, sw.ElapsedMilliseconds);
        }
        /// <summary>
        /// helper to invoke service
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="supervisorId"></param>
        /// <param name="service"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        private async Task CallServiceOnSupervisor <T>(string supervisorId,
                                                       string service, T request)
        {
            if (string.IsNullOrEmpty(supervisorId))
            {
                throw new ArgumentNullException(nameof(supervisorId));
            }
            var sw       = Stopwatch.StartNew();
            var deviceId = SupervisorModelEx.ParseDeviceId(supervisorId,
                                                           out var moduleId);
            var result = await _client.CallMethodAsync(deviceId, moduleId, service,
                                                       JsonConvertEx.SerializeObject(request));

            _logger.Debug("Calling supervisor service '{service}' on " +
                          "{deviceId}/{moduleId} took {elapsed} ms.", service,
                          deviceId, moduleId, sw.ElapsedMilliseconds);
        }
        /// <inheritdoc/>
        public async Task <SupervisorStatusModel> GetSupervisorStatusAsync(
            string supervisorId, CancellationToken ct)
        {
            if (string.IsNullOrEmpty(supervisorId))
            {
                throw new ArgumentNullException(nameof(supervisorId));
            }
            var sw       = Stopwatch.StartNew();
            var deviceId = SupervisorModelEx.ParseDeviceId(supervisorId,
                                                           out var moduleId);
            var result = await _client.CallMethodAsync(deviceId, moduleId,
                                                       "GetStatus_V2", null, null, ct);

            _logger.Debug("Get {deviceId}/{moduleId} status took " +
                          "{elapsed} ms.", deviceId, moduleId, sw.ElapsedMilliseconds);
            return(JsonConvertEx.DeserializeObject <SupervisorStatusModel>(
                       result));
        }
Exemple #14
0
        public async Task TestListSupervisors()
        {
            using (var harness = new TwinModuleFixture()) {
                await harness.RunTestAsync(async (device, module, services) => {
                    // Setup
                    var registry = services.Resolve <ISupervisorRegistry>();

                    // Act
                    var supervisors = await registry.ListAllSupervisorsAsync();

                    // Assert
                    Assert.Single(supervisors);
                    Assert.True(supervisors.Single().Connected.Value);
                    Assert.True(supervisors.Single().OutOfSync.Value);
                    Assert.Equal(device, SupervisorModelEx.ParseDeviceId(supervisors.Single().Id, out var moduleId));
                    Assert.Equal(module, moduleId);
                });
            }
        }
        /// <inheritdoc/>
        public async Task <SupervisorModel> GetSupervisorAsync(string id,
                                                               bool onlyServerState, CancellationToken ct)
        {
            if (string.IsNullOrEmpty(id))
            {
                throw new ArgumentException(nameof(id));
            }
            var deviceId = SupervisorModelEx.ParseDeviceId(id, out var moduleId);
            var device   = await _iothub.GetAsync(deviceId, moduleId, ct);

            var registration = device.ToRegistration(onlyServerState)
                               as SupervisorRegistration;

            if (registration == null)
            {
                throw new ResourceNotFoundException(
                          $"{id} is not a supervisor registration.");
            }
            return(registration.ToServiceModel());
        }
        /// <inheritdoc/>
        public async Task <(string, EndpointModel)> FindPublisherEndpoint(
            string endpointId, CancellationToken ct)
        {
            // Get the endpoint and the endpoints supervisor
            var device = await _iothub.GetAsync(endpointId, null, ct);

            var registration = device.ToEndpointRegistration(false);

            var endpoint     = registration.ToServiceModel();
            var supervisorId = endpoint?.Registration?.SupervisorId;

            if (string.IsNullOrEmpty(supervisorId))
            {
                // No supervisor set for the retrieved endpoint
                throw new ResourceInvalidStateException(
                          $"Endpoint {endpointId} has no supervisor");
            }

            // Get iotedge device
            var deviceId = SupervisorModelEx.ParseDeviceId(supervisorId, out _);

            // Query for the publisher in the same edge device
            var query = "SELECT * FROM devices.modules WHERE " +
                        $"properties.reported.{TwinProperty.Type} = '{IdentityType.Publisher}' " +
                        $"AND deviceId = '{deviceId}'";
            var devices = await _iothub.QueryAllDeviceTwinsAsync(query, ct);

            device = devices.SingleOrDefault();
            if (device == null)
            {
                throw new ResourceNotFoundException(
                          $"No publisher found for {endpointId} in {deviceId}");
            }
            var publisherId = PublisherModelEx.CreatePublisherId(
                device.Id, device.ModuleId);

            return(publisherId, endpoint.Registration.Endpoint);
        }
Exemple #17
0
        /// <summary>
        /// Remove supervisor twin secret from all supervisors managing the endpoint.
        /// </summary>
        /// <param name="twinId"></param>
        /// <param name="supervisorId"></param>
        /// <param name="ct"></param>
        /// <returns></returns>
        private async Task <IEnumerable <string> > ClearSupervisorTwinSecretAsync(
            string twinId, string supervisorId = null, CancellationToken ct = default)
        {
            if (string.IsNullOrEmpty(twinId))
            {
                throw new ArgumentNullException(nameof(twinId));
            }
            // Cleanup and remove endpoint from all supervisors
            var supervisors = await _supervisors.QueryAllSupervisorsAsync(
                new SupervisorQueryModel { EndpointId = twinId });

            var items = supervisors.Select(s => s.Id);

            if (!string.IsNullOrEmpty(supervisorId))
            {
                items.Append(supervisorId);
            }
            var results = items.Distinct().ToList();

            foreach (var supervisor in results)
            {
                try {
                    var deviceId = SupervisorModelEx.ParseDeviceId(supervisor, out var moduleId);
                    // Remove from supervisor - this disconnects the device
                    await _iothub.UpdatePropertyAsync(deviceId, moduleId, twinId, null, ct);

                    _logger.Information("Twin {twinId} deactivated on {supervisorId}.",
                                        twinId, supervisor);
                }
                catch (Exception ex) {
                    _logger.Error(ex, "Twin {twinId} failed to deactivate on {supervisorId}.",
                                  twinId, supervisor);
                }
            }
            return(results);
        }
        /// <inheritdoc/>
        public async Task UpdatePublisherAsync(string publisherId,
                                               PublisherUpdateModel request, CancellationToken ct)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }
            if (string.IsNullOrEmpty(publisherId))
            {
                throw new ArgumentException(nameof(publisherId));
            }

            // Get existing endpoint and compare to see if we need to patch.
            var deviceId = SupervisorModelEx.ParseDeviceId(publisherId, out var moduleId);

            while (true)
            {
                try {
                    var twin = await _iothub.GetAsync(deviceId, moduleId, ct);

                    if (twin.Id != deviceId && twin.ModuleId != moduleId)
                    {
                        throw new ArgumentException("Id must be same as twin to patch",
                                                    nameof(publisherId));
                    }

                    var registration = twin.ToEntityRegistration(true) as PublisherRegistration;
                    if (registration == null)
                    {
                        throw new ResourceNotFoundException(
                                  $"{publisherId} is not a publisher registration.");
                    }
                    // Update registration from update request
                    var patched = registration.ToServiceModel();
                    if (request.SiteId != null)
                    {
                        patched.SiteId = string.IsNullOrEmpty(request.SiteId) ?
                                         null : request.SiteId;
                    }

                    if (request.LogLevel != null)
                    {
                        patched.LogLevel = request.LogLevel == TraceLogLevel.Information ?
                                           null : request.LogLevel;
                    }

                    if (request.Configuration != null)
                    {
                        if (patched.Configuration == null)
                        {
                            patched.Configuration = new PublisherConfigModel();
                        }
                        if (request.Configuration.JobOrchestratorUrl != null)
                        {
                            patched.Configuration.JobOrchestratorUrl =
                                string.IsNullOrEmpty(
                                    request.Configuration.JobOrchestratorUrl.Trim()) ?
                                null : request.Configuration.JobOrchestratorUrl;
                        }
                        if (request.Configuration.HeartbeatInterval != null)
                        {
                            patched.Configuration.HeartbeatInterval =
                                request.Configuration.HeartbeatInterval.Value.Ticks == 0 ?
                                null : request.Configuration.HeartbeatInterval;
                        }
                        if (request.Configuration.JobCheckInterval != null)
                        {
                            patched.Configuration.JobCheckInterval =
                                request.Configuration.JobCheckInterval.Value.Ticks == 0 ?
                                null : request.Configuration.JobCheckInterval;
                        }
                        if (request.Configuration.MaxWorkers != null)
                        {
                            patched.Configuration.MaxWorkers =
                                request.Configuration.MaxWorkers <= 0 ?
                                null : request.Configuration.MaxWorkers;
                        }
                        if (request.Configuration.Capabilities != null)
                        {
                            patched.Configuration.Capabilities =
                                request.Configuration.Capabilities.Count == 0 ?
                                null : request.Configuration.Capabilities;
                        }
                    }
                    // Patch
                    twin = await _iothub.PatchAsync(registration.Patch(
                                                        patched.ToPublisherRegistration(), _serializer), false, ct);

                    // Send update to through broker
                    registration = twin.ToEntityRegistration(true) as PublisherRegistration;
                    await _broker.NotifyAllAsync(l => l.OnPublisherUpdatedAsync(null,
                                                                                registration.ToServiceModel()));

                    return;
                }
                catch (ResourceOutOfDateException ex) {
                    _logger.Debug(ex, "Retrying updating supervisor...");
                    continue;
                }
            }
        }
        /// <inheritdoc/>
        public async Task UpdateSupervisorAsync(string supervisorId,
                                                SupervisorUpdateModel request, CancellationToken ct)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }
            if (string.IsNullOrEmpty(supervisorId))
            {
                throw new ArgumentException(nameof(supervisorId));
            }

            // Get existing endpoint and compare to see if we need to patch.
            var deviceId = SupervisorModelEx.ParseDeviceId(supervisorId, out var moduleId);

            while (true)
            {
                try {
                    var twin = await _iothub.GetAsync(deviceId, moduleId, ct);

                    if (twin.Id != deviceId && twin.ModuleId != moduleId)
                    {
                        throw new ArgumentException("Id must be same as twin to patch",
                                                    nameof(supervisorId));
                    }

                    var registration = twin.ToRegistration(true) as SupervisorRegistration;
                    if (registration == null)
                    {
                        throw new ResourceNotFoundException(
                                  $"{supervisorId} is not a supervisor registration.");
                    }

                    // Update registration from update request
                    var patched = registration.ToServiceModel();
                    if (request.Discovery != null)
                    {
                        patched.Discovery = (DiscoveryMode)request.Discovery;
                    }

                    if (request.SiteId != null)
                    {
                        patched.SiteId = string.IsNullOrEmpty(request.SiteId) ?
                                         null : request.SiteId;
                    }

                    if (request.LogLevel != null)
                    {
                        patched.LogLevel = request.LogLevel == SupervisorLogLevel.Information ?
                                           null : request.LogLevel;
                    }

                    if (request.DiscoveryConfig != null)
                    {
                        if (patched.DiscoveryConfig == null)
                        {
                            patched.DiscoveryConfig = new DiscoveryConfigModel();
                        }
                        if (request.DiscoveryConfig.AddressRangesToScan != null)
                        {
                            patched.DiscoveryConfig.AddressRangesToScan =
                                string.IsNullOrEmpty(
                                    request.DiscoveryConfig.AddressRangesToScan.Trim()) ?
                                null : request.DiscoveryConfig.AddressRangesToScan;
                        }
                        if (request.DiscoveryConfig.PortRangesToScan != null)
                        {
                            patched.DiscoveryConfig.PortRangesToScan =
                                string.IsNullOrEmpty(
                                    request.DiscoveryConfig.PortRangesToScan.Trim()) ?
                                null : request.DiscoveryConfig.PortRangesToScan;
                        }
                        if (request.DiscoveryConfig.IdleTimeBetweenScans != null)
                        {
                            patched.DiscoveryConfig.IdleTimeBetweenScans =
                                request.DiscoveryConfig.IdleTimeBetweenScans;
                        }
                        if (request.DiscoveryConfig.MaxNetworkProbes != null)
                        {
                            patched.DiscoveryConfig.MaxNetworkProbes =
                                request.DiscoveryConfig.MaxNetworkProbes <= 0 ?
                                null : request.DiscoveryConfig.MaxNetworkProbes;
                        }
                        if (request.DiscoveryConfig.NetworkProbeTimeout != null)
                        {
                            patched.DiscoveryConfig.NetworkProbeTimeout =
                                request.DiscoveryConfig.NetworkProbeTimeout.Value.Ticks == 0 ?
                                null : request.DiscoveryConfig.NetworkProbeTimeout;
                        }
                        if (request.DiscoveryConfig.MaxPortProbes != null)
                        {
                            patched.DiscoveryConfig.MaxPortProbes =
                                request.DiscoveryConfig.MaxPortProbes <= 0 ?
                                null : request.DiscoveryConfig.MaxPortProbes;
                        }
                        if (request.DiscoveryConfig.MinPortProbesPercent != null)
                        {
                            patched.DiscoveryConfig.MinPortProbesPercent =
                                request.DiscoveryConfig.MinPortProbesPercent <= 0 ||
                                request.DiscoveryConfig.MinPortProbesPercent > 100 ?
                                null : request.DiscoveryConfig.MinPortProbesPercent;
                        }
                        if (request.DiscoveryConfig.PortProbeTimeout != null)
                        {
                            patched.DiscoveryConfig.PortProbeTimeout =
                                request.DiscoveryConfig.PortProbeTimeout.Value.Ticks == 0 ?
                                null : request.DiscoveryConfig.PortProbeTimeout;
                        }
                        if (request.DiscoveryConfig.ActivationFilter != null)
                        {
                            patched.DiscoveryConfig.ActivationFilter =
                                request.DiscoveryConfig.ActivationFilter.SecurityMode == null &&
                                request.DiscoveryConfig.ActivationFilter.SecurityPolicies == null &&
                                request.DiscoveryConfig.ActivationFilter.TrustLists == null ?
                                null : request.DiscoveryConfig.ActivationFilter;
                        }
                    }
                    // Patch
                    await _iothub.PatchAsync(registration.Patch(
                                                 patched.ToSupervisorRegistration()), false, ct);

                    return;
                }
                catch (ResourceOutOfDateException ex) {
                    _logger.Debug(ex, "Retrying updating supervisor...");
                    continue;
                }
            }
        }