/// <summary> /// Runs the Smart Detector's resolution check flow. /// </summary> /// <param name="request">The alert resolution check request.</param> /// <param name="shouldDetectorTrace">Determines if the detector's traces are emitted.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>A <see cref="Task{TResult}"/>, returning the resolution check response generated by the Smart Detector.</returns> public async Task <ContractsAlertResolutionCheckResponse> CheckResolutionAsync( ContractsAlertResolutionCheckRequest request, bool shouldDetectorTrace, CancellationToken cancellationToken) { return(await this.LoadAndRunSmartDetector( request.OriginalAnalysisRequest.SmartDetectorId, shouldDetectorTrace, request, this.CheckAlertResolutionAsync, cancellationToken)); }
/// <summary> /// Runs the Smart Detector's resolution check flow. /// </summary> /// <param name="request">The alert resolution check request.</param> /// <param name="smartDetector">The Smart Detector to run</param> /// <param name="smartDetectorManifest">The Smart Detector's manifest</param> /// <param name="detectorTracer">The tracer to provider for the Smart Detector</param> /// <param name="cancellationToken">The cancellation token</param> /// <returns>A <see cref="Task{TResult}"/>, returning the resolution check response generated by the Smart Detector.</returns> private async Task <ContractsAlertResolutionCheckResponse> CheckAlertResolutionAsync( ContractsAlertResolutionCheckRequest request, ISmartDetector smartDetector, SmartDetectorManifest smartDetectorManifest, ITracer detectorTracer, CancellationToken cancellationToken) { // Check that the detector supports resolution if (!(smartDetector is IResolvableAlertSmartDetector resolvableAlertSmartDetector)) { throw new ResolutionCheckNotSupportedException($"Smart Detector {smartDetectorManifest.Name} does not support alert resolution of alerts"); } // Create state repository IStateRepository stateRepository = this.stateRepositoryFactory.Create(request.OriginalAnalysisRequest.SmartDetectorId, request.OriginalAnalysisRequest.AlertRuleResourceId); // Load the resolution state from the repository ResolutionState resolutionState = await stateRepository.GetStateAsync <ResolutionState>(GetResolutionStateKey(request.AlertCorrelationHash), cancellationToken); if (resolutionState == null) { throw new ResolutionStateNotFoundException($"Resolution state for Alert with correlation {request.AlertCorrelationHash} was not found"); } // Create the input for the Smart Detector AnalysisRequestParameters analysisRequestParameters = await this.CreateAnalysisRequestParametersAsync( resolutionState.AnalysisRequestTime, request.OriginalAnalysisRequest, smartDetectorManifest, false, cancellationToken); var alertResolutionCheckRequest = new AlertResolutionCheckRequest( analysisRequestParameters, new AlertResolutionCheckRequestParameters(ResourceIdentifier.CreateFromResourceId(request.TargetResource), request.AlertFireTime, resolutionState.AlertPredicates), this.analysisServicesFactory, stateRepository); // Run the Smart Detector this.tracer.TraceInformation($"Started running Smart Detector ID {smartDetectorManifest.Id}, Name {smartDetectorManifest.Name} for resolution check"); try { AlertResolutionCheckResponse alertResolutionCheckResponse = await resolvableAlertSmartDetector.CheckForResolutionAsync(alertResolutionCheckRequest, detectorTracer, cancellationToken); this.tracer.TraceInformation($"Completed running Smart Detector ID {smartDetectorManifest.Id}, Name {smartDetectorManifest.Name} for resolution check"); // If the alert is resolved - delete the state if (alertResolutionCheckResponse.ShouldBeResolved) { await stateRepository.DeleteStateAsync(GetResolutionStateKey(request.AlertCorrelationHash), cancellationToken); } // Convert the result return(new ContractsAlertResolutionCheckResponse { ShouldBeResolved = alertResolutionCheckResponse.ShouldBeResolved, ResolutionParameters = alertResolutionCheckResponse.AlertResolutionParameters?.CreateContractsResolutionParameters() }); } catch (Exception e) { this.tracer.TraceError($"Failed running Smart Detector ID {smartDetectorManifest.Id}, Name {smartDetectorManifest.Name} for resolution check: {e}"); throw new FailedToRunSmartDetectorException($"Calling Smart Detector '{smartDetectorManifest.Name}' for resolution check failed with exception of type {e.GetType()} and message: {e.Message}", e); } }
private void TestInitialize(ResourceType requestResourceType, ResourceType smartDetectorResourceType) { this.testContainer = new UnityContainer(); this.testContainer.RegisterType <ISmartDetectorRunner, SmartDetectorRunner>(); this.testContainer.RegisterInstance(new Mock <ITracer>().Object); ResourceIdentifier resourceId; switch (requestResourceType) { case ResourceType.Subscription: resourceId = new ResourceIdentifier(requestResourceType, "subscriptionId", string.Empty, string.Empty); break; case ResourceType.ResourceGroup: resourceId = new ResourceIdentifier(requestResourceType, "subscriptionId", "resourceGroup", string.Empty); break; default: resourceId = new ResourceIdentifier(requestResourceType, "subscriptionId", "resourceGroup", "resourceName"); break; } this.resourceIds = new List <string> { resourceId.ToResourceId() }; this.analysisRequest = new SmartDetectorAnalysisRequest { ResourceIds = this.resourceIds, Cadence = TimeSpan.FromDays(1), AlertRuleResourceId = "alertRule", SmartDetectorId = "1", DetectorParameters = new Dictionary <string, object> { { "param1", "value1" }, { "param2", 2 }, } }; this.alertResolutionCheckRequest = new ContractsAlertResolutionCheckRequest { OriginalAnalysisRequest = new SmartDetectorAnalysisRequest { ResourceIds = this.resourceIds, Cadence = TimeSpan.FromDays(1), AlertRuleResourceId = "alertRule", SmartDetectorId = "2", DetectorParameters = new Dictionary <string, object> { { "param1", "value1" }, { "param2", 2 }, } }, AlertCorrelationHash = "correlationHash", TargetResource = resourceId.ToResourceId(), AlertFireTime = new DateTime(1985, 7, 3) }; var smartDetectorManifest = new SmartDetectorManifest( "1", "Test Smart Detector", "Test Smart Detector description", Version.Parse("1.0"), "TestSmartDetectorLibrary", "class", new List <ResourceType>() { smartDetectorResourceType }, new List <int> { 60 }, null, null); this.smartDetectorPackage = new SmartDetectorPackage(new Dictionary <string, byte[]> { ["manifest.json"] = Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(smartDetectorManifest)), ["TestSmartDetectorLibrary"] = Array.Empty <byte>(), }); var autoResolveSmartDetectorManifest = new SmartDetectorManifest( "2", "Test Auto Resolve Smart Detector", "Test Auto Resolve Smart Detector description", Version.Parse("1.0"), "TestSmartDetectorLibrary", "class", new List <ResourceType>() { smartDetectorResourceType }, new List <int> { 60 }, null, null); this.autoResolveSmartDetectorPackage = new SmartDetectorPackage(new Dictionary <string, byte[]> { ["manifest.json"] = Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(autoResolveSmartDetectorManifest)), ["TestSmartDetectorLibrary"] = Array.Empty <byte>(), }); var smartDetectorRepositoryMock = new Mock <ISmartDetectorRepository>(); smartDetectorRepositoryMock .Setup(x => x.ReadSmartDetectorPackageAsync("1", It.IsAny <CancellationToken>())) .ReturnsAsync(() => this.smartDetectorPackage); smartDetectorRepositoryMock .Setup(x => x.ReadSmartDetectorPackageAsync("2", It.IsAny <CancellationToken>())) .ReturnsAsync(() => this.autoResolveSmartDetectorPackage); this.testContainer.RegisterInstance(smartDetectorRepositoryMock.Object); this.testContainer.RegisterInstance(new Mock <IInternalAnalysisServicesFactory>().Object); this.smartDetector = new TestSmartDetector { ExpectedResourceType = smartDetectorResourceType }; this.autoResolveSmartDetector = new TestAutoResolveSmartDetector { ExpectedResourceType = smartDetectorResourceType }; var smartDetectorLoaderMock = new Mock <ISmartDetectorLoader>(); smartDetectorLoaderMock .Setup(x => x.LoadSmartDetector(this.smartDetectorPackage)) .Returns(() => this.smartDetector); smartDetectorLoaderMock .Setup(x => x.LoadSmartDetector(this.autoResolveSmartDetectorPackage)) .Returns(() => this.autoResolveSmartDetector); this.testContainer.RegisterInstance(smartDetectorLoaderMock.Object); var azureResourceManagerClientMock = new Mock <IExtendedAzureResourceManagerClient>(); azureResourceManagerClientMock .Setup(x => x.GetAllResourceGroupsInSubscriptionAsync(It.IsAny <string>(), It.IsAny <CancellationToken>())) .ReturnsAsync((string subscriptionId, CancellationToken cancellationToken) => new List <ResourceIdentifier>() { new ResourceIdentifier(ResourceType.ResourceGroup, subscriptionId, "resourceGroupName", string.Empty) }); azureResourceManagerClientMock .Setup(x => x.GetAllResourcesInSubscriptionAsync(It.IsAny <string>(), It.IsAny <IEnumerable <ResourceType> >(), It.IsAny <CancellationToken>())) .ReturnsAsync((string subscriptionId, IEnumerable <ResourceType> resourceTypes, CancellationToken cancellationToken) => new List <ResourceIdentifier>() { new ResourceIdentifier(ResourceType.VirtualMachine, subscriptionId, "resourceGroupName", "resourceName") }); azureResourceManagerClientMock .Setup(x => x.GetAllResourcesInResourceGroupAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <IEnumerable <ResourceType> >(), It.IsAny <CancellationToken>())) .ReturnsAsync((string subscriptionId, string resourceGroupName, IEnumerable <ResourceType> resourceTypes, CancellationToken cancellationToken) => new List <ResourceIdentifier>() { new ResourceIdentifier(ResourceType.VirtualMachine, subscriptionId, resourceGroupName, "resourceName") }); this.testContainer.RegisterInstance(azureResourceManagerClientMock.Object); this.stateRepository = new Dictionary <string, object>(); this.stateRepositoryMock = new Mock <IStateRepository>(); this.stateRepositoryMock .Setup(m => m.StoreStateAsync(It.IsAny <string>(), It.IsAny <object>(), It.IsAny <CancellationToken>())) .Callback <string, object, CancellationToken>((key, value, token) => this.stateRepository[key] = value) .Returns(Task.CompletedTask); this.stateRepositoryMock .Setup(m => m.GetStateAsync <ResolutionState>(It.IsAny <string>(), It.IsAny <CancellationToken>())) .Returns <string, CancellationToken>((key, token) => Task.FromResult((ResolutionState)(this.stateRepository.ContainsKey(key) ? this.stateRepository[key] : null))); this.stateRepositoryMock .Setup(m => m.DeleteStateAsync(It.IsAny <string>(), It.IsAny <CancellationToken>())) .Callback <string, CancellationToken>((key, token) => this.stateRepository.Remove(key)) .Returns(Task.CompletedTask); this.stateRepositoryFactoryMock = new Mock <IStateRepositoryFactory>(); this.stateRepositoryFactoryMock.Setup(m => m.Create(It.IsAny <string>(), It.IsAny <string>())).Returns(this.stateRepositoryMock.Object); this.testContainer.RegisterInstance(this.stateRepositoryFactoryMock.Object); }