/// <summary> /// Deactivate /// </summary> /// <param name="registration"></param> /// <param name="context"></param> /// <param name="ct"></param> /// <returns></returns> private async Task DeactivateAsync(EndpointRegistration registration, RegistryOperationContextModel context, CancellationToken ct = default) { var endpoint = registration.ToServiceModel(); // Deactivate twin in twin settings - do no matter what await ClearSupervisorTwinSecretAsync(registration.DeviceId, registration.SupervisorId, ct); // Call down to supervisor to ensure deactivation is complete - do no matter what await Try.Async(() => _activator.DeactivateEndpointAsync(endpoint.Registration)); try { // Mark as deactivated if (registration.Activated ?? false) { var patch = endpoint.ToEndpointRegistration( _serializer, registration.IsDisabled); // Mark as deactivated patch.Activated = false; await _iothub.PatchAsync(registration.Patch(patch, _serializer), true); } await _broker.NotifyAllAsync(l => l.OnEndpointDeactivatedAsync(context, endpoint)); } catch (Exception ex) { _logger.Error(ex, "Failed to deactivate twin"); throw; } }
public void EntityValidator_should_raise_validation_exception_if_endpoint_entity_token_is_short() { var endpoint = new EndpointRegistration { Address = "address", Group = "group", MonitorType = "http", Name = "name", Password = "******" }; Assert.Throws <ValidationException>(() => endpoint.ValidateModel()); }
/// <summary> /// Try to activate endpoint on any supervisor in site /// </summary> /// <param name="endpoint"></param> /// <param name="additional"></param> /// <param name="context"></param> /// <param name="ct"></param> /// <returns></returns> private async Task <bool> ActivateAsync(EndpointRegistration endpoint, IEnumerable <string> additional, RegistryOperationContextModel context, CancellationToken ct) { // Get site of this endpoint var site = endpoint.SiteId; if (string.IsNullOrEmpty(site)) { // Use discovery id gateway part if no site found site = DiscovererModelEx.ParseDeviceId(endpoint.DiscovererId, out _); if (string.IsNullOrEmpty(site)) { // Try supervisor id gateway part site = DiscovererModelEx.ParseDeviceId(endpoint.SupervisorId, out _); } } // Get all supervisors in site endpoint.SiteId = site; var supervisorsInSite = await _supervisors.QueryAllSupervisorsAsync( new SupervisorQueryModel { SiteId = site }); var candidateSupervisors = supervisorsInSite.Select(s => s.Id) .ToList().Shuffle(); // Add all supervisors that managed this endpoint before. // TODO: Consider removing as it is a source of bugs if (additional != null) { candidateSupervisors.AddRange(additional); } // Remove previously failing one candidateSupervisors.Remove(endpoint.SupervisorId); // Loop through all randomly and try to take one that works. foreach (var supervisorId in candidateSupervisors) { endpoint.SupervisorId = supervisorId; endpoint.Activated = false; try { await ActivateAsync(endpoint, context, ct); _logger.Information("Activate twin on supervisor {supervisorId}!", supervisorId); // Done - endpoint was also patched thus has new supervisor id return(true); } catch (Exception ex) { _logger.Debug(ex, "Failed to activate twin on supervisor {supervisorId} " + "- trying next...", supervisorId); } } // Failed return(false); }
public static void AuthorizeRegistration(this HttpRequestContext context, EndpointRegistration model, Endpoint modifiable, params SecurityRole[] roles) { if (modifiable?.Password == null || modifiable.Password == model?.Password?.ToSha256Hash()) { return; } Authorize(context, modifiable.Identity.Id, roles); }
/// <summary> /// Apply activation filter /// </summary> /// <param name="filter"></param> /// <param name="registration"></param> /// <param name="context"></param> /// <param name="ct"></param> /// <returns></returns> private async Task <string> ApplyActivationFilterAsync( EndpointActivationFilterModel filter, EndpointRegistration registration, RegistryOperationContextModel context, CancellationToken ct = default) { if (filter == null || registration == null) { return(null); } // TODO: Get trust list entry and validate endpoint.Certificate var mode = registration.SecurityMode ?? SecurityMode.None; if (!mode.MatchesFilter(filter.SecurityMode ?? SecurityMode.Best)) { return(null); } var policy = registration.SecurityPolicy; if (filter.SecurityPolicies != null) { if (!filter.SecurityPolicies.Any(p => p.EqualsIgnoreCase(registration.SecurityPolicy))) { return(null); } } try { // Ensure device scope for the registration before getting the secret. // Changing device's scope regenerates the secret. await EnsureDeviceScopeForRegistrationAsync(registration, ct); // Get endpoint twin secret var secret = await _iothub.GetPrimaryKeyAsync(registration.DeviceId, null, ct); var endpoint = registration.ToServiceModel(); // Try activate endpoint - if possible... await _activator.ActivateEndpointAsync(endpoint.Registration, secret, ct); // Mark in supervisor await SetSupervisorTwinSecretAsync(registration.SupervisorId, registration.DeviceId, secret, ct); registration.Activated = true; await _broker.NotifyAllAsync( l => l.OnEndpointActivatedAsync(context, endpoint)); return(secret); } catch (Exception ex) { _logger.Information(ex, "Failed activating {eeviceId} based off " + "filter. Manual activation required.", registration.DeviceId); return(null); } }
public IHttpActionResult PostRegisterEndpoint([FromBody] EndpointRegistration endpoint) { endpoint.ValidateModel(); try { var id = _endpointRegistry.RegisterOrUpdate(endpoint.MonitorType, endpoint.Address, endpoint.Group, endpoint.Name, endpoint.Tags); return(Created(new Uri(Request.RequestUri, $"/api/endpoints/{id}"), id)); } catch (UnsupportedMonitorException e) { return(BadRequest(e.Message)); } }
/// <summary> /// Ensure device scope for registration /// </summary> /// <param name="registration"></param> /// <param name="ct"></param> /// <returns></returns> private async Task EnsureDeviceScopeForRegistrationAsync( EndpointRegistration registration, CancellationToken ct = default) { // Ensure device scope is set to the owning edge gateway before activation var edgeScope = await GetSupervisorDeviceScopeAsync(registration.SupervisorId, ct); var deviceTwin = await _iothub.GetAsync(registration.DeviceId, ct : ct); if (!string.IsNullOrEmpty(edgeScope) && deviceTwin.DeviceScope != edgeScope) { deviceTwin.DeviceScope = edgeScope; await _iothub.CreateOrUpdateAsync(deviceTwin, true, ct : ct); } }
public IHttpActionResult PostRegisterEndpoint([FromBody] EndpointRegistration endpoint) { endpoint.ValidateModel(); try { var existed = _endpointRegistry.GetByNaturalKey(endpoint.MonitorType, endpoint.Address); RequestContext.AuthorizeRegistration(endpoint, existed, SecurityRole.Admin); var id = _endpointRegistry.RegisterOrUpdate(endpoint.MonitorType, endpoint.Address, endpoint.Group, endpoint.Name, endpoint.Tags, endpoint.Password); return(Created(new Uri(Request.RequestUri, $"/api/endpoints/{id}"), id)); } catch (UnsupportedMonitorException e) { return(BadRequest(e.Message)); } }
public async Task TestActivateDeactivateEndpoint20Times() { using (var harness = new TwinModuleFixture()) { await harness.RunTestAsync(async (device, module, services) => { // Setup var supervisorId = SupervisorModelEx.CreateSupervisorId(device, module); var activation = services.Resolve<IActivationServices<EndpointRegistrationModel>>(); var hub = services.Resolve<IIoTHubTwinServices>(); var twin = EndpointRegistration.Patch(null, EndpointRegistration.FromServiceModel(new EndpointInfoModel { Registration = new EndpointRegistrationModel { Endpoint = new EndpointModel { Url = "opc.tcp://test" }, SupervisorId = supervisorId }, ApplicationId = "ua326029342304923" })); await hub.CreateOrUpdateAsync(twin); var registry = services.Resolve<IEndpointRegistry>(); var endpoints = await registry.ListAllEndpointsAsync(); var ep1 = endpoints.FirstOrDefault(); Assert.NotNull(ep1); for (var i = 0; i < 20; i++) { // Act await registry.ActivateEndpointAsync(ep1.Registration.Id); await registry.DeactivateEndpointAsync(ep1.Registration.Id); } var diagnostics = services.Resolve<ISupervisorDiagnostics>(); endpoints = await registry.ListAllEndpointsAsync(); var ep3 = endpoints.FirstOrDefault(); var status = await diagnostics.GetSupervisorStatusAsync(supervisorId); // Assert Assert.Equal(device, status.DeviceId); Assert.Equal(module, status.ModuleId); Assert.Null(status.SiteId); Assert.Empty(status.Endpoints); Assert.Equal(EndpointActivationState.Deactivated, ep3.ActivationState); Assert.Null(ep3.EndpointState); }); } }
/// <summary> /// Activate /// </summary> /// <param name="registration"></param> /// <param name="context"></param> /// <param name="ct"></param> /// <returns></returns> private async Task ActivateAsync(EndpointRegistration registration, RegistryOperationContextModel context, CancellationToken ct = default) { // Ensure device scope for the registration before getting the secret. // Changing device's scope regenerates the secret. await EnsureDeviceScopeForRegistrationAsync(registration, ct); // Update supervisor settings var secret = await _iothub.GetPrimaryKeyAsync(registration.DeviceId, null, ct); var endpoint = registration.ToServiceModel(); try { // Call down to supervisor to activate - this can fail await _activator.ActivateEndpointAsync(endpoint.Registration, secret, ct); // Update supervisor desired properties await SetSupervisorTwinSecretAsync(registration.SupervisorId, registration.DeviceId, secret, ct); if (!(registration.Activated ?? false)) { // Update twin activation status in twin settings var patch = endpoint.ToEndpointRegistration(_serializer, registration.IsDisabled); patch.Activated = true; // Mark registration as activated await _iothub.PatchAsync(registration.Patch(patch, _serializer), true, ct); } await _broker.NotifyAllAsync(l => l.OnEndpointActivatedAsync(context, endpoint)); } catch (Exception ex) { // Undo activation await Try.Async(() => _activator.DeactivateEndpointAsync( endpoint.Registration)); await Try.Async(() => ClearSupervisorTwinSecretAsync( registration.DeviceId, registration.SupervisorId)); _logger.Error(ex, "Failed to activate twin"); throw; } }
public async Task TestActivateDeactivate20Endpoints5TimesMultiThreaded() { using (var harness = new TwinModuleFixture()) { await harness.RunTestAsync(async (device, module, services) => { // Setup var supervisorId = SupervisorModelEx.CreateSupervisorId(device, module); var activation = services.Resolve<IActivationServices<EndpointRegistrationModel>>(); var hub = services.Resolve<IIoTHubTwinServices>(); for (var i = 0; i < 20; i++) { var twin = EndpointRegistration.Patch(null, EndpointRegistration.FromServiceModel(new EndpointInfoModel { Registration = new EndpointRegistrationModel { Endpoint = new EndpointModel { Url = "opc.tcp://test" }, SupervisorId = supervisorId }, ApplicationId = "uas" + i })); await hub.CreateOrUpdateAsync(twin); } var registry = services.Resolve<IEndpointRegistry>(); var endpoints = await registry.ListAllEndpointsAsync(); for (var i = 0; i < 5; i++) { await Task.WhenAll(endpoints.Select(ep => registry.ActivateEndpointAsync(ep.Registration.Id))); await Task.WhenAll(endpoints.Select(ep => registry.DeactivateEndpointAsync(ep.Registration.Id))); } var diagnostics = services.Resolve<ISupervisorDiagnostics>(); endpoints = await registry.ListAllEndpointsAsync(); var status = await diagnostics.GetSupervisorStatusAsync(supervisorId); // Assert Assert.Equal(device, status.DeviceId); Assert.Equal(module, status.ModuleId); Assert.Null(status.SiteId); Assert.Empty(status.Endpoints); Assert.True(endpoints.All(ep => ep.ActivationState == EndpointActivationState.Deactivated)); Assert.True(endpoints.All(ep => ep.EndpointState == null)); }); } }
/// <summary> /// Activate /// </summary> /// <param name="endpoint"></param> /// <returns></returns> public EndpointRegistrationModel RegisterAndActivateTwinId(EndpointRegistrationModel endpoint) { var twin = EndpointRegistration.Patch(null, EndpointRegistration.FromServiceModel( new EndpointInfoModel { Registration = endpoint, ApplicationId = "uas" + Guid.NewGuid().ToString() })); var result = _hub.CreateOrUpdateAsync(twin).Result; var registry = HubContainer.Resolve <IEndpointRegistry>(); var endpoints = registry.ListAllEndpointsAsync().Result; var ep1 = endpoints.FirstOrDefault(); if (ep1.ActivationState == EndpointActivationState.Deactivated) { // Activate registry.ActivateEndpointAsync(ep1.Registration.Id).Wait(); } return(ep1.Registration); }
/// <summary> /// Helper to create fixtures /// </summary> /// <param name="site"></param> /// <param name="super"></param> /// <param name="existing"></param> /// <param name="found"></param> /// <param name="registry"></param> /// <param name="countDevices"></param> /// <param name="fixup"></param> /// <param name="disable"></param> private static void CreateFixtures(out string site, out string super, out List <ApplicationRegistrationModel> existing, out List <DiscoveryEventModel> found, out IoTHubServices registry, int countDevices = -1, Func <ApplicationRegistrationModel, ApplicationRegistrationModel> fixup = null, bool disable = false) { var fix = new Fixture(); // Create template applications and endpoints fix.Customizations.Add(new TypeRelay(typeof(JToken), typeof(JObject))); var sitex = site = fix.Create <string>(); var module = fix.Create <string>(); var device = fix.Create <string>(); var superx = super = SupervisorModelEx.CreateSupervisorId(device, module); var supervisor = ( SupervisorRegistration.Patch(null, SupervisorRegistration.FromServiceModel(new SupervisorModel { SiteId = site, Id = superx })), new DeviceModel { Id = device, ModuleId = module }); var template = fix .Build <ApplicationRegistrationModel>() .Without(x => x.Application) .Do(c => c.Application = fix .Build <ApplicationInfoModel>() .Without(x => x.NotSeenSince) .With(x => x.SiteId, sitex) .With(x => x.SupervisorId, superx) .Create()) .Without(x => x.Endpoints) .Do(c => c.Endpoints = fix .Build <EndpointRegistrationModel>() .With(x => x.SiteId, sitex) .With(x => x.SupervisorId, superx) .CreateMany(5) .ToList()) .CreateMany(5) .ToList(); template.ForEach(a => a.Application.ApplicationId = ApplicationInfoModelEx.CreateApplicationId(a.Application) ); // Create discovery results from template var i = 0; var now = DateTime.UtcNow; found = template .SelectMany(a => a.Endpoints.Select( e => new DiscoveryEventModel { Application = a.Application, Registration = e, Index = i++, TimeStamp = now })) .ToList(); // Clone and fixup existing applications as per test case existing = template .Select(e => e.Clone()) .Select(fixup ?? (a => a)) .ToList(); // and fill registry with them... var appdevices = existing .Select(a => ApplicationRegistration.FromServiceModel(a.Application, disable)) .Select(a => ApplicationRegistration.Patch(null, a)) .Select(d => (d, new DeviceModel { Id = d.Id })); var epdevices = existing .SelectMany(a => a.Endpoints .Select(e => EndpointRegistration.FromServiceModel( new EndpointInfoModel { ApplicationId = a.Application.ApplicationId, Registration = e }, disable))) .Select(e => EndpointRegistration.Patch(null, e)) .Select(d => (d, new DeviceModel { Id = d.Id })); appdevices = appdevices.Concat(epdevices); if (countDevices != -1) { appdevices = appdevices.Take(countDevices); } registry = new IoTHubServices(appdevices.Concat(supervisor.YieldReturn())); }