Beispiel #1
0
        public void WhenDeserializingValidManifestThenAllValuesAreSetCorrectly()
        {
            SmartDetectorManifest manifest = DeserializeManifestFromResource(ManifestsResources.AllValues);

            Assert.AreEqual("id", manifest.Id);
            Assert.AreEqual("name", manifest.Name);
            Assert.AreEqual("description", manifest.Description);
            Assert.AreEqual(new Version(1, 0), manifest.Version);
            Assert.AreEqual("TestSmartDetectorLibrary", manifest.AssemblyName);
            Assert.AreEqual("TestSmartDetectorLibrary.TestSmartDetectorWithDependency", manifest.ClassName);

            Assert.AreEqual(1, manifest.SupportedResourceTypes.Count);
            Assert.AreEqual(ResourceType.Subscription, manifest.SupportedResourceTypes[0]);

            Assert.AreEqual(1, manifest.SupportedCadencesInMinutes.Count);
            Assert.AreEqual(60, manifest.SupportedCadencesInMinutes[0]);

            Assert.AreEqual(2, manifest.ImagePaths.Count);
            Assert.AreEqual("someImage", manifest.ImagePaths[0]);
            Assert.AreEqual("anotherImage", manifest.ImagePaths[1]);

            Assert.AreEqual(2, manifest.ParametersDefinitions.Count);
            Assert.AreEqual("param1", manifest.ParametersDefinitions[0].Name);
            Assert.AreEqual(DetectorParameterType.String, manifest.ParametersDefinitions[0].Type);
            Assert.AreEqual("first parameter", manifest.ParametersDefinitions[0].DisplayName);
            Assert.AreEqual("the first parameter for the detector", manifest.ParametersDefinitions[0].Description);
            Assert.AreEqual(true, manifest.ParametersDefinitions[0].IsMandatory);
            Assert.AreEqual("param2", manifest.ParametersDefinitions[1].Name);
            Assert.AreEqual(DetectorParameterType.Integer, manifest.ParametersDefinitions[1].Type);
            Assert.AreEqual("second parameter", manifest.ParametersDefinitions[1].DisplayName);
            Assert.IsNull(manifest.ParametersDefinitions[1].Description);
            Assert.AreEqual(false, manifest.ParametersDefinitions[1].IsMandatory);
        }
        /// <summary>
        /// Loads and runs a specific flow on the requested Smart Detector.
        /// </summary>
        /// <typeparam name="TIn">The flow's primary input type.</typeparam>
        /// <typeparam name="TOut">The flow's output type.</typeparam>
        /// <param name="smartDetectorId">The ID of the Smart Detector to load</param>
        /// <param name="shouldDetectorTrace">Determines if the detector's traces are emitted.</param>
        /// <param name="runnerInput">The flow's input</param>
        /// <param name="flowRunner">A function that runs the Smart Detector Flow.</param>
        /// <param name="cancellationToken">The cancellation token</param>
        /// <returns>A <see cref="Task{TResult}"/>, returning the output returned from <paramref name="flowRunner"/>.</returns>
        private async Task <TOut> LoadAndRunSmartDetector <TIn, TOut>(
            string smartDetectorId,
            bool shouldDetectorTrace,
            TIn runnerInput,
            Func <TIn, ISmartDetector, SmartDetectorManifest, ITracer, CancellationToken, Task <TOut> > flowRunner,
            CancellationToken cancellationToken)
        {
            // Read the Smart Detector's package
            this.tracer.TraceInformation($"Loading Smart Detector package for Smart Detector ID {smartDetectorId}");
            SmartDetectorPackage smartDetectorPackage = await this.smartDetectorRepository.ReadSmartDetectorPackageAsync(smartDetectorId, cancellationToken);

            SmartDetectorManifest smartDetectorManifest = smartDetectorPackage.Manifest;

            this.tracer.TraceInformation($"Read Smart Detector package, ID {smartDetectorManifest.Id}, Version {smartDetectorManifest.Version}");

            // Load the Smart Detector
            ISmartDetector smartDetector = this.smartDetectorLoader.LoadSmartDetector(smartDetectorPackage);

            this.tracer.TraceInformation($"Smart Detector instance loaded successfully, ID {smartDetectorManifest.Id}");

            try
            {
                ITracer detectorTracer = shouldDetectorTrace ? this.tracer : new EmptyTracer();
                return(await flowRunner(runnerInput, smartDetector, smartDetectorManifest, detectorTracer, cancellationToken));
            }
            finally
            {
                if (smartDetector is IDisposable disposableSmartDetector)
                {
                    disposableSmartDetector.Dispose();
                }
            }
        }
Beispiel #3
0
        /// <summary>
        /// Loads a Smart Detector.
        /// This method load the Smart Detector's assembly into the current application domain,
        /// and creates the Smart Detector object using reflection.
        /// </summary>
        /// <param name="smartDetectorPackage">The Smart Detector package.</param>
        /// <returns>The Smart Detector object.</returns>
        /// <exception cref="SmartDetectorLoadException">
        /// Thrown if an error occurred during the Smart Detector load (either due to assembly load
        /// error or failure to create the Smart Detector object).
        /// </exception>
        public ISmartDetector LoadSmartDetector(SmartDetectorPackage smartDetectorPackage)
        {
            SmartDetectorManifest smartDetectorManifest = smartDetectorPackage.Manifest;

            try
            {
                this.tracer.TraceInformation($"Read {smartDetectorPackage.Content.Count} assemblies for Smart Detector ID {smartDetectorManifest.Id}");

                // Add assembly resolver, that uses the Smart Detector's assemblies
                AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
                {
                    this.tracer.TraceInformation($"Resolving assembly {args.Name} for Smart Detector ID {smartDetectorManifest.Id}");

                    // Get the short name of the assembly (AssemblyName.Name)
                    AssemblyName assemblyName = new AssemblyName(args.Name);
                    string       name         = assemblyName.Name;

                    // Try to find the assembly bytes in the Smart Detector's assemblies
                    if (smartDetectorPackage.TryGetAssemblyBytes(name, out byte[] assemblyBytes))
                    {
                        // Load the assembly from its bytes
                        return(Assembly.Load(assemblyBytes));
                    }

                    return(null);
                };

                // Find the main Smart Detector assembly
                if (!smartDetectorPackage.TryGetAssemblyBytes(smartDetectorManifest.AssemblyName, out byte[] smartDetectorMainAssemblyBytes))
        private void AssertMetadata(SmartDetectorManifest smartDetectorManifest, Dictionary <string, string> expectedMetadata)
        {
            var supportedResourceTypes = JArray.Parse(expectedMetadata["supportedResourceTypes"])
                                         .Select(jtoken => (ResourceType)Enum.Parse(typeof(ResourceType), jtoken.ToString(), true))
                                         .ToList();

            var supportedCadencesInMinutes = JArray.Parse(expectedMetadata["supportedCadencesInMinutes"])
                                             .Select(jToken => int.Parse(jToken.ToString()))
                                             .ToList();

            Assert.AreEqual(expectedMetadata["id"], smartDetectorManifest.Id);
            Assert.AreEqual(expectedMetadata["name"], smartDetectorManifest.Name);
            Assert.AreEqual(expectedMetadata["version"], smartDetectorManifest.Version.ToString());
            Assert.AreEqual(expectedMetadata["description"], smartDetectorManifest.Description);
            Assert.AreEqual(expectedMetadata["assemblyName"], smartDetectorManifest.AssemblyName);
            Assert.AreEqual(expectedMetadata["className"], smartDetectorManifest.ClassName);

            Assert.AreEqual(supportedResourceTypes.Count, smartDetectorManifest.SupportedResourceTypes.Count);
            foreach (var supportedResourceType in supportedResourceTypes)
            {
                Assert.IsTrue(smartDetectorManifest.SupportedResourceTypes.Contains(supportedResourceType));
            }

            Assert.AreEqual(supportedCadencesInMinutes.Count, smartDetectorManifest.SupportedCadencesInMinutes.Count);
            foreach (var supportedCadence in supportedCadencesInMinutes)
            {
                Assert.IsTrue(smartDetectorManifest.SupportedCadencesInMinutes.Contains(supportedCadence));
            }
        }
Beispiel #5
0
        /// <summary>
        /// Raises the <see cref="E:System.Windows.Application.Startup" /> event.
        /// </summary>
        /// <param name="e">A <see cref="T:System.Windows.StartupEventArgs" /> that contains the event data.</param>
        protected override void OnStartup(StartupEventArgs e)
        {
            ITracer stringTracer        = new StringTracer(string.Empty);
            ITracer consoleTracer       = new ConsoleTracer(string.Empty);
            var     smartDetectorLoader = new SmartDetectorLoader(consoleTracer);

            // *Temporary*: if package file path wasn't accepted, raise file selection window to allow package file selection.
            // This option should be removed before launching version for customers (bug for tracking: 1177247)
            string smartDetectorPackagePath = e.Args.Length != 1 ?
                                              this.GetSmartDetectorPackagePath() :
                                              Diagnostics.EnsureStringNotNullOrWhiteSpace(() => e.Args[0]);

            SmartDetectorPackage smartDetectorPackage;

            using (var fileStream = new FileStream(smartDetectorPackagePath, FileMode.Open))
            {
                smartDetectorPackage = SmartDetectorPackage.CreateFromStream(fileStream, consoleTracer);
            }

            SmartDetectorManifest smartDetectorManifest = smartDetectorPackage.Manifest;
            ISmartDetector        detector = smartDetectorLoader.LoadSmartDetector(smartDetectorPackage);

            // Authenticate the user to Active Directory
            var authenticationServices = new AuthenticationServices();

            authenticationServices.AuthenticateUser();
            ICredentialsFactory credentialsFactory = new ActiveDirectoryCredentialsFactory(authenticationServices);

            IAzureResourceManagerClient azureResourceManagerClient = new AzureResourceManagerClient(credentialsFactory, consoleTracer);

            // Create analysis service factory
            var queryRunInroProvider = new QueryRunInfoProvider(azureResourceManagerClient);
            var httpClientWrapper    = new HttpClientWrapper();
            IAnalysisServicesFactory analysisServicesFactory = new AnalysisServicesFactory(consoleTracer, httpClientWrapper, credentialsFactory, azureResourceManagerClient, queryRunInroProvider);

            // Create state repository factory
            IStateRepositoryFactory stateRepositoryFactory = new InMemoryStateRepositoryFactory();

            var smartDetectorRunner = new SmartDetectorRunner(detector, analysisServicesFactory, queryRunInroProvider, smartDetectorManifest, stateRepositoryFactory, smartDetectorManifest.Id, stringTracer);

            // Create a Unity container with all the required models and view models registrations
            Container = new UnityContainer();
            Container
            .RegisterInstance(stringTracer)
            .RegisterInstance(new AlertsRepository())
            .RegisterInstance(authenticationServices)
            .RegisterInstance(azureResourceManagerClient)
            .RegisterInstance(detector)
            .RegisterInstance(smartDetectorManifest)
            .RegisterInstance(analysisServicesFactory)
            .RegisterInstance(smartDetectorRunner)
            .RegisterInstance(stateRepositoryFactory);
        }
        private async Task TestLoadSmartDetectorSimple(Type smartDetectorType, string expectedTitle = "test test test")
        {
            SmartDetectorManifest manifest = new SmartDetectorManifest("3", "simple", "description", Version.Parse("1.0"), smartDetectorType.Assembly.GetName().Name, smartDetectorType.FullName, new List <ResourceType>()
            {
                ResourceType.Subscription
            }, new List <int> {
                60
            }, null);
            SmartDetectorPackage package = new SmartDetectorPackage(manifest, this.assemblies["3"]);

            await this.TestLoadSmartDetectorSimple(package, expectedTitle);
        }
        public SmartDetectorConfigurationControlViewModel(
            IExtendedAzureResourceManagerClient azureResourceManagerClient,
            ITracer tracer,
            SmartDetectorManifest smartDetectorManifest,
            IEmulationSmartDetectorRunner smartDetectorRunner,
            UserSettings userSettings)
        {
            this.azureResourceManagerClient = azureResourceManagerClient;
            this.smartDetectorManifest      = smartDetectorManifest;
            this.tracer = tracer;
            this.smartDetectorManifest = smartDetectorManifest;
            this.userSettings          = userSettings;

            this.SmartDetectorRunner     = smartDetectorRunner;
            this.SmartDetectorName       = this.smartDetectorManifest.Name;
            this.ShouldShowStatusControl = false;

            // Create dummy resource identifier for initialization purposes
            this.dummyResourceIdentifier = new ResourceIdentifier(ResourceType.ApplicationInsights, "dummy-subscription-id", "dummy-resource-group-name", "dummy-resource-name");

            // Initialize cadences combo box
            IEnumerable <SmartDetectorCadence> cadences = this.smartDetectorManifest.SupportedCadencesInMinutes
                                                          .Select(cadence => new SmartDetectorCadence(TimeSpan.FromMinutes(cadence)));

            this.Cadences = new ObservableCollection <SmartDetectorCadence>(cadences);

            // Set selected cadence to be the first one. If non, pick 10 minutes cadence as default
            this.SelectedCadence = this.Cadences.Any() ?
                                   this.Cadences.First() :
                                   new SmartDetectorCadence(TimeSpan.FromMinutes(10));

            this.IterativeRunModeEnabled = false;
            this.IterativeStartTime      = DateTime.UtcNow;
            this.IterativeEndTime        = DateTime.UtcNow;

            // In case there is no subscription to select from user settings, skip the entire phase of re-loading resources from user settings
            if (this.userSettings.SelectedSubscription != null)
            {
                this.ShouldSelectResourcesAccordingToUserSettings = true;
            }

            this.SupportedResourceTypes = this.GetSupportedResourceTypes();

            this.ReadResourcesTask = new ObservableTask <List <ResourceIdentifier> >(
                Task.FromResult(new List <ResourceIdentifier>()),
                this.tracer);

            this.ReadSubscriptionsTask = new ObservableTask <ObservableCollection <HierarchicalResource> >(
                this.GetSubscriptionsAsync(),
                this.tracer,
                this.LoadPreviousSelectedSubscription);
        }
Beispiel #8
0
        public void Setup()
        {
            this.smartDetectorRunnerMock        = new Mock <IEmulationSmartDetectorRunner>();
            this.azureResourceManagerClientMock = new Mock <IExtendedAzureResourceManagerClient>();
            this.tracerMock = new Mock <ITracer>();

            this.userSettings = new UserSettings();

            this.smartDetectorManifest = new SmartDetectorManifest(
                "someId",
                "someName",
                "someDisplayName",
                Version.Parse("1.0"),
                "someAssemblyName",
                "someClassName",
                new List <ResourceType> {
                ResourceType.ResourceGroup, ResourceType.VirtualMachine
            },
                new List <int> {
                10, 60, 120
            },
                null,
                null);

            this.azureResourceManagerClientMock
            .Setup(x => x.GetAllSubscriptionsAsync(It.IsAny <CancellationToken>()))
            .ReturnsAsync(() => new List <AzureSubscription>()
            {
                new AzureSubscription("subId1", "subDisplayName1")
            });

            this.azureResourceManagerClientMock
            .Setup(x => x.GetAllResourcesInSubscriptionAsync(It.IsAny <string>(), It.IsAny <IEnumerable <ResourceType> >(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(() => new List <ResourceIdentifier>()
            {
                new ResourceIdentifier(ResourceType.VirtualMachine, "subId1", "someResourceGroup", "someVM")
            });

            this.azureResourceManagerClientMock
            .Setup(x => x.GetAllResourceGroupsInSubscriptionAsync(It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(() => new List <ResourceIdentifier>()
            {
                new ResourceIdentifier(ResourceType.ResourceGroup, "subId1", "someResourceGroup", string.Empty)
            });

            this.smartDetectorConfigurationControlViewModel = new SmartDetectorConfigurationControlViewModel(
                this.azureResourceManagerClientMock.Object,
                this.tracerMock.Object,
                this.smartDetectorManifest,
                this.smartDetectorRunnerMock.Object,
                this.userSettings);
        }
 /// <summary>
 /// Creates a <see cref="SmartDetector"/> from a <see cref="SmartDetectorManifest"/>
 /// </summary>
 /// <param name="manifest">The smart detector manifest</param>
 /// <returns>A <see cref="SmartDetector"/> based on the <see cref="SmartDetectorManifest"/></returns>
 private SmartDetector CreateSmartDetectorFromManifest(SmartDetectorManifest manifest)
 {
     return(new SmartDetector
     {
         Id = manifest.Id,
         Name = manifest.Name,
         Description = manifest.Description,
         SupportedCadences = new List <int>(manifest.SupportedCadencesInMinutes),
         SupportedResourceTypes = manifest.SupportedResourceTypes.Select(resourceType => (ResourceType)resourceType).ToList(),
         Configurations = new List <SmartDetectorConfiguration>(),
         ImagePaths = manifest.ImagePaths?.Select(imagePath => new Uri(imagePath)).ToList()
     });
 }
        /// <summary>
        /// Creates a new instance of the <see cref="AnalysisRequestParameters"/> class, based on <paramref name="request"/>.
        /// </summary>
        /// <param name="requestTime">The original time the analysis request was received from Azure Monitor back-end.</param>
        /// <param name="request">The analysis request received from Azure Monitoring back-end.</param>
        /// <param name="smartDetectorManifest">The Smart Detector's manifest, used for validations of the request.</param>
        /// <param name="shouldValidateResources">A value indicating whether we should validate that the request's resources are supported by the detector.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A <see cref="Task{TResult}"/>, returning the analysis request parameters.</returns>
        private async Task <AnalysisRequestParameters> CreateAnalysisRequestParametersAsync(
            DateTime requestTime,
            SmartDetectorAnalysisRequest request,
            SmartDetectorManifest smartDetectorManifest,
            bool shouldValidateResources,
            CancellationToken cancellationToken)
        {
            // Get the resources on which to run the Smart Detector
            List <ResourceIdentifier> resources = shouldValidateResources
                ? await this.GetResourcesForSmartDetector(request.ResourceIds, smartDetectorManifest, cancellationToken)
                : request.ResourceIds.Select(ResourceIdentifier.CreateFromResourceId).ToList();

            return(new AnalysisRequestParameters(requestTime, resources, request.Cadence, request.AlertRuleResourceId, request.DetectorParameters));
        }
        private async Task TestLoadSmartDetectorSimple(Type smartDetectorType, string expectedTitle = "test test test")
        {
            SmartDetectorManifest manifest = new SmartDetectorManifest("3", "simple", "description", Version.Parse("1.0"), smartDetectorType.Assembly.GetName().Name, smartDetectorType.FullName, new List <ResourceType>()
            {
                ResourceType.Subscription
            }, new List <int> {
                60
            }, null, null);
            Dictionary <string, byte[]> packageContent = this.assemblies["3"];

            packageContent["manifest.json"] = Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(manifest));
            SmartDetectorPackage package = new SmartDetectorPackage(packageContent);

            await this.TestLoadSmartDetectorSimple(package, expectedTitle);
        }
        /// <summary>
        /// Gets a Smart Detector.
        /// </summary>
        /// <param name="detectorId">The detector ID</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The Smart Detector</returns>
        /// <exception cref="SmartDetectorsManagementApiException">This exception is thrown when we failed to retrieve the Smart Detector.</exception>
        public async Task <SmartDetector> GetSmartDetectorAsync(string detectorId, CancellationToken cancellationToken)
        {
            try
            {
                SmartDetectorManifest manifest = await this.smartDetectorRepository.ReadSmartDetectorManifestAsync(detectorId, cancellationToken);

                return(this.CreateSmartDetectorFromManifest(manifest));
            }
            catch (SmartDetectorNotFoundException)
            {
                throw new SmartDetectorsManagementApiException($"Smart Detector {detectorId} was not found", HttpStatusCode.NotFound);
            }
            catch (Exception e)
            {
                throw new SmartDetectorsManagementApiException($"Failed to get Smart Detector {detectorId}", e, HttpStatusCode.InternalServerError);
            }
        }
Beispiel #13
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SmartDetectorRunner"/> class.
 /// </summary>
 /// <param name="smartDetector">The Smart Detector.</param>
 /// <param name="analysisServicesFactory">The analysis services factory.</param>
 /// <param name="smartDetectorManifest">The Smart Detector manifest.</param>
 /// <param name="stateRepositoryFactory">The state repository factory</param>
 /// <param name="azureResourceManagerClient">The Azure Resource Manager client</param>
 /// <param name="logArchive">The log archive.</param>
 public SmartDetectorRunner(
     ISmartDetector smartDetector,
     IInternalAnalysisServicesFactory analysisServicesFactory,
     SmartDetectorManifest smartDetectorManifest,
     IStateRepositoryFactory stateRepositoryFactory,
     IExtendedAzureResourceManagerClient azureResourceManagerClient,
     IPageableLogArchive logArchive)
 {
     this.smartDetector           = smartDetector;
     this.analysisServicesFactory = analysisServicesFactory;
     this.smartDetectorManifest   = smartDetectorManifest;
     this.logArchive             = logArchive;
     this.IsSmartDetectorRunning = false;
     this.Alerts = new ObservableCollection <EmulationAlert>();
     this.stateRepositoryFactory     = stateRepositoryFactory;
     this.azureResourceManagerClient = azureResourceManagerClient;
 }
Beispiel #14
0
        public async Task WhenSelectingSubscriptionForDetectorThatSupportsOnlyResourceGroupsThenTheReadResourcesTaskIsFiredAndFetchingOnlyResourceGroups()
        {
            // Update detector manifest to support only resource groups
            this.smartDetectorManifest = new SmartDetectorManifest(
                "someId",
                "someName",
                "someDescription",
                Version.Parse("1.0"),
                "someAssemblyName",
                "someClassName",
                new List <ResourceType> {
                ResourceType.ResourceGroup
            },
                new List <int> {
                10, 60, 120
            },
                null,
                null);

            this.smartDetectorConfigurationControlViewModel = new SmartDetectorConfigurationControlViewModel(
                this.azureResourceManagerClientMock.Object,
                this.tracerMock.Object,
                this.smartDetectorManifest,
                this.smartDetectorRunnerMock.Object,
                this.userSettings);

            var subscriptionToSelect = new HierarchicalResource(
                new ResourceIdentifier(ResourceType.Subscription, "subId1", string.Empty, string.Empty),
                new List <HierarchicalResource>(),
                "subDisplayName1");

            this.smartDetectorConfigurationControlViewModel.SelectedSubscription = subscriptionToSelect;

            // Wait for resources task
            await Task.Delay(TimeSpan.FromSeconds(1));

            var expectedFirstResourceIdentifier = new ResourceIdentifier(ResourceType.ResourceGroup, "subId1", "someResourceGroup", string.Empty);

            Assert.IsNotNull(this.smartDetectorConfigurationControlViewModel.ReadResourcesTask.Result);
            Assert.AreEqual(1, this.smartDetectorConfigurationControlViewModel.ReadResourcesTask.Result.Count);

            Assert.AreEqual(expectedFirstResourceIdentifier, this.smartDetectorConfigurationControlViewModel.ReadResourcesTask.Result[0]);
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="SmartDetectorRunner"/> class.
 /// </summary>
 /// <param name="smartDetector">The Smart Detector.</param>
 /// <param name="analysisServicesFactory">The analysis services factory.</param>
 /// <param name="queryRunInfoProvider">The query run information provider.</param>
 /// <param name="smartDetectorManifes">The Smart Detector manifest.</param>
 /// <param name="stateRepositoryFactory">The state repository factory</param>
 /// <param name="smartDetectorId">The id of the Smart Detector</param>
 /// <param name="tracer">The tracer.</param>
 public SmartDetectorRunner(
     ISmartDetector smartDetector,
     IAnalysisServicesFactory analysisServicesFactory,
     IQueryRunInfoProvider queryRunInfoProvider,
     SmartDetectorManifest smartDetectorManifes,
     IStateRepositoryFactory stateRepositoryFactory,
     string smartDetectorId,
     ITracer tracer)
 {
     this.smartDetector           = smartDetector;
     this.analysisServicesFactory = analysisServicesFactory;
     this.queryRunInfoProvider    = queryRunInfoProvider;
     this.smartDetectorManifes    = smartDetectorManifes;
     this.Tracer = tracer;
     this.IsSmartDetectorRunning = false;
     this.Alerts = new ObservableCollection <EmulationAlert>();
     this.stateRepositoryFactory = stateRepositoryFactory;
     this.smartDetectorId        = smartDetectorId;
 }
Beispiel #16
0
        public SmartDetectorConfigurationControlViewModel(
            IAzureResourceManagerClient azureResourceManagerClient,
            ITracer tracer,
            SmartDetectorManifest smartDetectorManifest,
            SmartDetectorRunner smartDetectorRunner)
        {
            this.azureResourceManagerClient = azureResourceManagerClient;
            this.smartDetectorManifes       = smartDetectorManifest;
            this.tracer = tracer;

            this.SmartDetectorRunner     = smartDetectorRunner;
            this.SmartDetectorName       = this.smartDetectorManifes.Name;
            this.ShouldShowStatusControl = false;

            // Initialize cadences combo box
            IEnumerable <SmartDetectorCadence> cadences = this.smartDetectorManifes.SupportedCadencesInMinutes
                                                          .Select(cadence => new SmartDetectorCadence(TimeSpan.FromMinutes(cadence)));

            this.Cadences = new ObservableCollection <SmartDetectorCadence>(cadences);

            // Set selected cadence to be the first one. If non, pick 10 minutes cadence as default
            this.SelectedCadence = this.Cadences.Any() ?
                                   this.Cadences.First() :
                                   new SmartDetectorCadence(TimeSpan.FromMinutes(10));

            // Initialize combo boxes read tasks
            this.ReadSubscriptionsTask = new ObservableTask <ObservableCollection <AzureSubscription> >(
                this.GetSubscriptionsAsync());

            this.ReadResourceGroupsTask = new ObservableTask <ObservableCollection <string> >(
                Task.FromResult(new ObservableCollection <string>()));

            this.ReadResourceTypesTask = new ObservableTask <ObservableCollection <string> >(
                Task.FromResult(new ObservableCollection <string>()));

            this.ReadResourcesTask = new ObservableTask <ObservableCollection <ResourceIdentifier> >(
                Task.FromResult(new ObservableCollection <ResourceIdentifier>()));

            this.IterativeRunModeEnabled = false;

            this.StartTimePickerViewModel = new TimePickerControlViewModel("Start time:");
            this.EndTimePickerViewModel   = new TimePickerControlViewModel("End time:");
        }
Beispiel #17
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SmartDetectorRunner"/> class.
 /// </summary>
 /// <param name="smartDetector">The Smart Detector.</param>
 /// <param name="analysisServicesFactory">The analysis services factory.</param>
 /// <param name="queryRunInfoProvider">The query run information provider.</param>
 /// <param name="smartDetectorManifes">The Smart Detector manifest.</param>
 /// <param name="stateRepositoryFactory">The state repository factory</param>
 /// <param name="azureResourceManagerClient">The Azure Resource Manager client</param>
 /// <param name="tracer">The tracer.</param>
 public SmartDetectorRunner(
     ISmartDetector smartDetector,
     IInternalAnalysisServicesFactory analysisServicesFactory,
     IQueryRunInfoProvider queryRunInfoProvider,
     SmartDetectorManifest smartDetectorManifes,
     IStateRepositoryFactory stateRepositoryFactory,
     IExtendedAzureResourceManagerClient azureResourceManagerClient,
     ITracer tracer)
 {
     this.smartDetector           = smartDetector;
     this.analysisServicesFactory = analysisServicesFactory;
     this.queryRunInfoProvider    = queryRunInfoProvider;
     this.smartDetectorManifest   = smartDetectorManifes;
     this.Tracer = tracer;
     this.IsSmartDetectorRunning = false;
     this.Alerts = new ObservableCollection <EmulationAlert>();
     this.stateRepositoryFactory     = stateRepositoryFactory;
     this.azureResourceManagerClient = azureResourceManagerClient;
 }
Beispiel #18
0
        public void WhenDeserializingValidManifestWithNoOptionalPropertiesThenAllValuesAreSetCorrectly()
        {
            SmartDetectorManifest manifest = DeserializeManifestFromResource(ManifestsResources.NoOptionalProperties);

            Assert.AreEqual("id", manifest.Id);
            Assert.AreEqual("name", manifest.Name);
            Assert.AreEqual("description", manifest.Description);
            Assert.AreEqual(new Version(1, 0), manifest.Version);
            Assert.AreEqual("TestSmartDetectorLibrary.dll", manifest.AssemblyName);
            Assert.AreEqual("TestSmartDetectorLibrary.TestSmartDetectorWithDependency", manifest.ClassName);

            Assert.AreEqual(1, manifest.SupportedResourceTypes.Count);
            Assert.AreEqual(ResourceType.Subscription, manifest.SupportedResourceTypes[0]);

            Assert.AreEqual(1, manifest.SupportedCadencesInMinutes.Count);
            Assert.AreEqual(60, manifest.SupportedCadencesInMinutes[0]);

            Assert.AreEqual(0, manifest.ImagePaths.Count);
            Assert.AreEqual(0, manifest.ParametersDefinitions.Count);
        }
        private static void AssertMetadata(SmartDetectorManifest smartDetectorManifest, ICloudBlob smartDetectorBlob)
        {
            IDictionary <string, string> expectedMetadata = smartDetectorBlob.Metadata;
            var supportedResourceTypes = JArray.Parse(expectedMetadata["supportedResourceTypes"])
                                         .Select(jtoken => (ResourceType)Enum.Parse(typeof(ResourceType), jtoken.ToString(), true))
                                         .ToList();

            var supportedCadencesInMinutes = JArray.Parse(expectedMetadata["supportedCadencesInMinutes"])
                                             .Select(jToken => int.Parse(jToken.ToString(), CultureInfo.InvariantCulture))
                                             .ToList();

            var imagePaths = JArray.Parse(expectedMetadata["imagePaths"])
                             .Select(jToken => $"{smartDetectorBlob.Parent.Uri.AbsoluteUri}{jToken.ToString()}")
                             .ToList();

            Assert.AreEqual(expectedMetadata["id"], smartDetectorManifest.Id);
            Assert.AreEqual(expectedMetadata["name"], smartDetectorManifest.Name);
            Assert.AreEqual(expectedMetadata["version"], smartDetectorManifest.Version.ToString());
            Assert.AreEqual(expectedMetadata["description"], smartDetectorManifest.Description);
            Assert.AreEqual(expectedMetadata["assemblyName"], smartDetectorManifest.AssemblyName);
            Assert.AreEqual(expectedMetadata["className"], smartDetectorManifest.ClassName);

            Assert.AreEqual(supportedResourceTypes.Count, smartDetectorManifest.SupportedResourceTypes.Count);
            foreach (var supportedResourceType in supportedResourceTypes)
            {
                Assert.IsTrue(smartDetectorManifest.SupportedResourceTypes.Contains(supportedResourceType));
            }

            Assert.AreEqual(supportedCadencesInMinutes.Count, smartDetectorManifest.SupportedCadencesInMinutes.Count);
            foreach (var supportedCadence in supportedCadencesInMinutes)
            {
                Assert.IsTrue(smartDetectorManifest.SupportedCadencesInMinutes.Contains(supportedCadence));
            }

            Assert.AreEqual(imagePaths.Count, smartDetectorManifest.ImagePaths.Count);
            foreach (var imagePath in imagePaths)
            {
                Assert.IsTrue(smartDetectorManifest.ImagePaths.Contains(imagePath));
            }
        }
Beispiel #20
0
 /// <summary>
 /// Initializes a new instance of the <see cref="IncompatibleResourceTypesException"/> class
 /// with the specified error message.
 /// </summary>
 /// <param name="requestResourceType">The requested resource type</param>
 /// <param name="smartDetectorManifest">The Smart Detector manifest</param>
 public IncompatibleResourceTypesException(ResourceType requestResourceType, SmartDetectorManifest smartDetectorManifest)
     : base($"Resource type {requestResourceType} is not supported by Smart Detector {smartDetectorManifest.Name}")
 {
 }
        /// <summary>
        /// Raises the <see cref="Application.Startup" /> event.
        /// </summary>
        /// <param name="e">A <see cref="StartupEventArgs" /> that contains the event data.</param>
        protected override void OnStartup(StartupEventArgs e)
        {
            // Cleanup previous temp folders (that are at least 2 days old), and create a new temp folder
            FileSystemExtensions.CleanupTempFolders(TempSubFolderName, 48);
            tempFolder = FileSystemExtensions.CreateTempFolder(TempSubFolderName);

            NotificationService notificationService = new NotificationService();
            ITracer             consoleTracer       = new ConsoleTracer(string.Empty);
            var smartDetectorLoader = new SmartDetectorLoader(tempFolder, consoleTracer);

            // *Temporary*: if package file path wasn't accepted, raise file selection window to allow package file selection.
            // This option should be removed before launching version for customers (bug for tracking: 1177247)
            string smartDetectorPackagePath = e.Args.Length != 1 ?
                                              GetSmartDetectorPackagePath() :
                                              Diagnostics.EnsureStringNotNullOrWhiteSpace(() => e.Args[0]);

            SmartDetectorPackage smartDetectorPackage;

            using (var fileStream = new FileStream(smartDetectorPackagePath, FileMode.Open))
            {
                smartDetectorPackage = SmartDetectorPackage.CreateFromStream(fileStream);
            }

            try
            {
                SmartDetectorManifest smartDetectorManifest = smartDetectorPackage.Manifest;
                ISmartDetector        detector = smartDetectorLoader.LoadSmartDetector(smartDetectorPackage);

                // Authenticate the user to Active Directory
                IAuthenticationServices authenticationServices = new AuthenticationServices();
                authenticationServices.AuthenticateUserAsync().Wait();
                ICredentialsFactory credentialsFactory = new ActiveDirectoryCredentialsFactory(authenticationServices);
                IHttpClientWrapper  httpClientWrapper  = new HttpClientWrapper();
                IExtendedAzureResourceManagerClient azureResourceManagerClient = new ExtendedAzureResourceManagerClient(httpClientWrapper, credentialsFactory, consoleTracer);

                // Create analysis service factory
                IInternalAnalysisServicesFactory analysisServicesFactory = new AnalysisServicesFactory(consoleTracer, httpClientWrapper, credentialsFactory, azureResourceManagerClient);

                // Create state repository factory
                IStateRepositoryFactory stateRepositoryFactory = new EmulationStateRepositoryFactory();

                // Load user settings
                var userSettings = UserSettings.LoadUserSettings();

                // Create the detector runner
                IPageableLogArchive           logArchive          = new PageableLogArchive(smartDetectorManifest.Name);
                IEmulationSmartDetectorRunner smartDetectorRunner = new SmartDetectorRunner(
                    detector,
                    analysisServicesFactory,
                    smartDetectorManifest,
                    stateRepositoryFactory,
                    azureResourceManagerClient,
                    logArchive);

                // Create a Unity container with all the required models and view models registrations
                Container = new UnityContainer();
                Container
                .RegisterInstance(notificationService)
                .RegisterInstance <ITracer>(consoleTracer)
                .RegisterInstance(new AlertsRepository())
                .RegisterInstance(authenticationServices)
                .RegisterInstance(azureResourceManagerClient)
                .RegisterInstance(detector)
                .RegisterInstance(smartDetectorManifest)
                .RegisterInstance(analysisServicesFactory)
                .RegisterInstance(logArchive)
                .RegisterInstance(smartDetectorRunner)
                .RegisterInstance(stateRepositoryFactory)
                .RegisterInstance(userSettings);
            }
            catch (Exception exception)
            {
                var message = $"{exception.Message}. {Environment.NewLine}{exception.InnerException?.Message}";
                MessageBox.Show(message);
                System.Diagnostics.Trace.WriteLine(message);
                Environment.Exit(1);
            }
        }
        /// <summary>
        /// Verify that the request resource type is supported by the Smart Detector, and enumerate
        /// the resources that the Smart Detector should run on.
        /// </summary>
        /// <param name="requestResourceIds">The request resource Ids</param>
        /// <param name="smartDetectorManifest">The Smart Detector manifest</param>
        /// <param name="cancellationToken">The cancellation token</param>
        /// <returns>A <see cref="Task{TResult}"/>, returning the resource identifiers that the Smart Detector should run on</returns>
        private async Task <List <ResourceIdentifier> > GetResourcesForSmartDetector(IList <string> requestResourceIds, SmartDetectorManifest smartDetectorManifest, CancellationToken cancellationToken)
        {
            HashSet <ResourceIdentifier> resourcesForSmartDetector = new HashSet <ResourceIdentifier>();

            foreach (string requestResourceId in requestResourceIds)
            {
                ResourceIdentifier requestResource = ResourceIdentifier.CreateFromResourceId(requestResourceId);

                if (smartDetectorManifest.SupportedResourceTypes.Contains(requestResource.ResourceType))
                {
                    // If the Smart Detector directly supports the requested resource type, then that's it
                    resourcesForSmartDetector.Add(requestResource);
                }
                else if (requestResource.ResourceType == ResourceType.Subscription && smartDetectorManifest.SupportedResourceTypes.Contains(ResourceType.ResourceGroup))
                {
                    // If the request is for a subscription, and the Smart Detector supports a resource group type, enumerate all resource groups in the requested subscription
                    IList <ResourceIdentifier> resourceGroups = await this.azureResourceManagerClient.GetAllResourceGroupsInSubscriptionAsync(requestResource.SubscriptionId, cancellationToken);

                    resourcesForSmartDetector.UnionWith(resourceGroups);
                    this.tracer.TraceInformation($"Added {resourceGroups.Count} resource groups found in subscription {requestResource.SubscriptionId}");
                }
                else if (requestResource.ResourceType == ResourceType.Subscription)
                {
                    // If the request is for a subscription, enumerate all the resources in the requested subscription that the Smart Detector supports
                    IList <ResourceIdentifier> resources = await this.azureResourceManagerClient.GetAllResourcesInSubscriptionAsync(requestResource.SubscriptionId, smartDetectorManifest.SupportedResourceTypes, cancellationToken);

                    resourcesForSmartDetector.UnionWith(resources);
                    this.tracer.TraceInformation($"Added {resources.Count} resources found in subscription {requestResource.SubscriptionId}");
                }
                else if (requestResource.ResourceType == ResourceType.ResourceGroup && smartDetectorManifest.SupportedResourceTypes.Any(type => type != ResourceType.Subscription))
                {
                    // If the request is for a resource group, and the Smart Detector supports resource types (other than subscription),
                    // enumerate all the resources in the requested resource group that the Smart Detector supports
                    IList <ResourceIdentifier> resources = await this.azureResourceManagerClient.GetAllResourcesInResourceGroupAsync(requestResource.SubscriptionId, requestResource.ResourceGroupName, smartDetectorManifest.SupportedResourceTypes, cancellationToken);

                    resourcesForSmartDetector.UnionWith(resources);
                    this.tracer.TraceInformation($"Added {resources.Count} resources found in the specified resource group in subscription {requestResource.SubscriptionId}");
                }
                else
                {
                    // The Smart Detector does not support the requested resource type
                    throw new IncompatibleResourceTypesException(requestResource.ResourceType, smartDetectorManifest);
                }
            }

            return(resourcesForSmartDetector.ToList());
        }
        /// <summary>
        /// Loads the Smart Detector, runs it, and returns the generated alert presentations
        /// </summary>
        /// <param name="request">The Smart Detector request</param>
        /// <param name="cancellationToken">The cancellation token</param>
        /// <returns>A <see cref="Task{TResult}"/>, returning the list of Alerts presentations generated by the Smart Detector</returns>
        public async Task <List <ContractsAlert> > RunAsync(SmartDetectorExecutionRequest request, CancellationToken cancellationToken)
        {
            // Read the Smart Detector's package
            this.tracer.TraceInformation($"Loading Smart Detector package for Smart Detector ID {request.SmartDetectorId}");
            SmartDetectorPackage smartDetectorPackage = await this.smartDetectorRepository.ReadSmartDetectorPackageAsync(request.SmartDetectorId, cancellationToken);

            SmartDetectorManifest smartDetectorManifest = smartDetectorPackage.Manifest;

            this.tracer.TraceInformation($"Read Smart Detector package, ID {smartDetectorManifest.Id}, Version {smartDetectorManifest.Version}");

            // Load the Smart Detector
            ISmartDetector smartDetector = this.smartDetectorLoader.LoadSmartDetector(smartDetectorPackage);

            this.tracer.TraceInformation($"Smart Detector instance loaded successfully, ID {smartDetectorManifest.Id}");

            // Get the resources on which to run the Smart Detector
            List <ResourceIdentifier> resources = await this.GetResourcesForSmartDetector(request.ResourceIds, smartDetectorManifest, cancellationToken);

            // Create state repository
            IStateRepository stateRepository = this.stateRepositoryFactory.Create(request.SmartDetectorId);

            // Run the Smart Detector
            this.tracer.TraceInformation($"Started running Smart Detector ID {smartDetectorManifest.Id}, Name {smartDetectorManifest.Name}");
            List <Alert> alerts;

            try
            {
                var analysisRequest = new AnalysisRequest(resources, request.DataEndTime, request.Cadence, request.AlertRuleResourceId, this.analysisServicesFactory, stateRepository);
                alerts = await smartDetector.AnalyzeResourcesAsync(analysisRequest, this.tracer, cancellationToken);

                this.tracer.TraceInformation($"Completed running Smart Detector ID {smartDetectorManifest.Id}, Name {smartDetectorManifest.Name}, returning {alerts.Count} alerts");
            }
            catch (Exception e)
            {
                this.tracer.TraceInformation($"Failed running Smart Detector ID {smartDetectorManifest.Id}, Name {smartDetectorManifest.Name}: {e.Message}");
                throw new SmartDetectorCustomException(e.GetType().ToString(), e.Message, e.StackTrace);
            }

            // Verify that each alert belongs to one of the types declared in the Smart Detector manifest
            foreach (Alert alert in alerts)
            {
                if (!smartDetectorManifest.SupportedResourceTypes.Contains(alert.ResourceIdentifier.ResourceType))
                {
                    throw new UnidentifiedAlertResourceTypeException(alert.ResourceIdentifier);
                }
            }

            // Trace the number of alerts of each type
            foreach (var alertType in alerts.GroupBy(x => x.GetType().Name))
            {
                this.tracer.TraceInformation($"Got {alertType.Count()} Alerts of type '{alertType.Key}'");
                this.tracer.ReportMetric("AlertType", alertType.Count(), new Dictionary <string, string>()
                {
                    { "AlertType", alertType.Key }
                });
            }

            // Create results
            List <ContractsAlert> results = new List <ContractsAlert>();

            foreach (var alert in alerts)
            {
                QueryRunInfo queryRunInfo = await this.queryRunInfoProvider.GetQueryRunInfoAsync(new List <ResourceIdentifier>() { alert.ResourceIdentifier }, cancellationToken);

                results.Add(alert.CreateContractsAlert(request, smartDetectorManifest.Name, queryRunInfo));
            }

            this.tracer.TraceInformation($"Returning {results.Count} results");
            return(results);
        }
        /// <summary>
        /// Runs the Smart Detector's analysis flow.
        /// </summary>
        /// <param name="request">The Smart Detector analysis 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 list of Alerts generated by the Smart Detector.</returns>
        private async Task <List <ContractsAlert> > AnalyzeAsync(
            SmartDetectorAnalysisRequest request,
            ISmartDetector smartDetector,
            SmartDetectorManifest smartDetectorManifest,
            ITracer detectorTracer,
            CancellationToken cancellationToken)
        {
            // Create state repository
            IStateRepository stateRepository = this.stateRepositoryFactory.Create(request.SmartDetectorId, request.AlertRuleResourceId);

            // Create the input for the Smart Detector
            AnalysisRequestParameters analysisRequestParameters = await this.CreateAnalysisRequestParametersAsync(DateTime.UtcNow, request, smartDetectorManifest, true, cancellationToken);

            var analysisRequest = new AnalysisRequest(analysisRequestParameters, this.analysisServicesFactory, stateRepository);

            // Run the Smart Detector
            this.tracer.TraceInformation($"Started running Smart Detector ID {smartDetectorManifest.Id}, Name {smartDetectorManifest.Name}");
            List <Alert> alerts;

            try
            {
                alerts = await smartDetector.AnalyzeResourcesAsync(analysisRequest, detectorTracer, cancellationToken);

                this.tracer.TraceInformation(
                    $"Completed running Smart Detector ID {smartDetectorManifest.Id}, Name {smartDetectorManifest.Name}, returning {alerts.Count} alerts");
            }
            catch (DetectorNotReadyException dnre)
            {
                this.tracer.TraceWarning($"Smart Detector is not ready to run analysis yet, aborting analysis: {dnre.Message}");
                return(new List <ContractsAlert>());
            }
            catch (Exception e)
            {
                this.tracer.TraceError($"Failed running Smart Detector ID {smartDetectorManifest.Id}, Name {smartDetectorManifest.Name}: {e}");
                throw new FailedToRunSmartDetectorException($"Calling Smart Detector '{smartDetectorManifest.Name}' failed with exception of type {e.GetType()} and message: {e.Message}", e);
            }

            // Verify that each alert belongs to one of the types declared in the Smart Detector manifest
            foreach (Alert alert in alerts)
            {
                if (!smartDetectorManifest.SupportedResourceTypes.Contains(alert.ResourceIdentifier.ResourceType))
                {
                    throw new UnidentifiedAlertResourceTypeException(alert.ResourceIdentifier);
                }
            }

            // Trace the number of alerts of each type
            foreach (var alertType in alerts.GroupBy(x => x.GetType().Name))
            {
                this.tracer.TraceInformation($"Got {alertType.Count()} Alerts of type '{alertType.Key}'");
                this.tracer.ReportMetric("AlertType", alertType.Count(), new Dictionary <string, string>()
                {
                    { "AlertType", alertType.Key }
                });
            }

            // Create results
            bool detectorSupportsAlertResolution = smartDetector is IResolvableAlertSmartDetector;
            List <ContractsAlert> results        = new List <ContractsAlert>();

            foreach (var alert in alerts)
            {
                ContractsAlert contractsAlert = alert.CreateContractsAlert(
                    request,
                    smartDetectorManifest.Name,
                    this.analysisServicesFactory.UsedLogAnalysisClient,
                    this.analysisServicesFactory.UsedMetricClient);

                // Handle resolution parameters in the alerts:
                // If the detector supports resolution - save the predicates for the resolution checks
                // If the detector doesn't support resolution - drop the resolution parameters (since they are useless) and error trace
                if (contractsAlert.ResolutionParameters != null)
                {
                    if (detectorSupportsAlertResolution)
                    {
                        this.tracer.TraceInformation($"Alert {contractsAlert.CorrelationHash} has resolution parameters, so saving alert details for later use");
                        await stateRepository.StoreStateAsync(
                            GetResolutionStateKey(contractsAlert.CorrelationHash),
                            new ResolutionState
                        {
                            AnalysisRequestTime = analysisRequestParameters.RequestTime,
                            AlertPredicates     = alert.ExtractPredicates()
                        },
                            cancellationToken);
                    }
                    else
                    {
                        this.tracer.TraceError($"Dropping resolution parameters from alert {contractsAlert.CorrelationHash}");
                        contractsAlert.ResolutionParameters = null;
                    }
                }

                // And add the alert to the results
                results.Add(contractsAlert);
            }

            this.tracer.TraceInformation($"Returning {results.Count} results");
            return(results);
        }
        /// <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);
        }
        private void TestInitialize(ResourceType requestResourceType, ResourceType smartDetectorResourceType)
        {
            this.testContainer = new UnityContainer();

            this.testContainer.RegisterType <ISmartDetectorRunner, SmartDetectorRunner>();

            this.testContainer.RegisterInstance(new Mock <IExtendedTracer>().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.request = new SmartDetectorExecutionRequest
            {
                ResourceIds     = this.resourceIds,
                Cadence         = TimeSpan.FromDays(1),
                SmartDetectorId = "1"
            };

            var smartDetectorManifest = new SmartDetectorManifest("1", "Test Smart Detector", "Test Smart Detector description", Version.Parse("1.0"), "assembly", "class", new List <ResourceType>()
            {
                smartDetectorResourceType
            }, new List <int> {
                60
            }, null);

            this.smartDetectorPackage = new SmartDetectorPackage(smartDetectorManifest, new Dictionary <string, byte[]> {
                ["TestSmartDetectorLibrary"] = Array.Empty <byte>()
            });

            var smartDetectorRepositoryMock = new Mock <ISmartDetectorRepository>();

            smartDetectorRepositoryMock
            .Setup(x => x.ReadSmartDetectorPackageAsync(It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(() => this.smartDetectorPackage);
            this.testContainer.RegisterInstance <ISmartDetectorRepository>(smartDetectorRepositoryMock.Object);

            this.testContainer.RegisterInstance <IInternalAnalysisServicesFactory>(new Mock <IInternalAnalysisServicesFactory>().Object);

            this.smartDetector = new TestSmartDetector {
                ExpectedResourceType = smartDetectorResourceType
            };

            var smartDetectorLoaderMock = new Mock <ISmartDetectorLoader>();

            smartDetectorLoaderMock
            .Setup(x => x.LoadSmartDetector(this.smartDetectorPackage))
            .Returns(this.smartDetector);
            this.testContainer.RegisterInstance <ISmartDetectorLoader>(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 <IExtendedAzureResourceManagerClient>(azureResourceManagerClientMock.Object);

            this.testContainer.RegisterInstance <IQueryRunInfoProvider>(new Mock <IQueryRunInfoProvider>().Object);

            var stateRepositoryMock        = new Mock <IStateRepository>();
            var stateRepositoryFactoryMock = new Mock <IStateRepositoryFactory>();

            stateRepositoryFactoryMock.Setup(m => m.Create(It.IsAny <string>(), It.IsAny <string>())).Returns(stateRepositoryMock.Object);
            this.testContainer.RegisterInstance <IStateRepositoryFactory>(stateRepositoryFactoryMock.Object);
        }
        /// <summary>
        /// Loads a Smart Detector.
        /// This method load the Smart Detector's assembly into the current application domain,
        /// and creates the Smart Detector object using reflection.
        /// </summary>
        /// <param name="smartDetectorPackage">The Smart Detector package.</param>
        /// <returns>The Smart Detector object.</returns>
        /// <exception cref="SmartDetectorLoadException">
        /// Thrown if an error occurred during the Smart Detector load (either due to assembly load
        /// error or failure to create the Smart Detector object).
        /// </exception>
        public ISmartDetector LoadSmartDetector(SmartDetectorPackage smartDetectorPackage)
        {
            SmartDetectorManifest smartDetectorManifest = smartDetectorPackage.Manifest;

            try
            {
                this.tracer.TraceInformation($"Read {smartDetectorPackage.Content.Count} assemblies for Smart Detector ID {smartDetectorManifest.Id}");

                // Write all DLLs to the temp folder
                foreach (var assemblyNameAndBytes in smartDetectorPackage.Content)
                {
                    string fileName = Path.Combine(this.tempFolder, assemblyNameAndBytes.Key);
                    Directory.CreateDirectory(Directory.GetParent(fileName).FullName);
                    File.WriteAllBytes(fileName, assemblyNameAndBytes.Value);
                }

                // Add assembly resolver, that uses the Smart Detector's assemblies
                AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
                {
                    this.tracer.TraceInformation($"Resolving assembly {args.Name} for Smart Detector ID {smartDetectorManifest.Id}");
                    return(this.LoadAssembly(args.Name));
                };

                // Load the main Smart Detector assembly
                Assembly mainSmartDetectorAssembly = this.LoadAssembly(smartDetectorManifest.AssemblyName);
                if (mainSmartDetectorAssembly == null)
                {
                    throw new SmartDetectorLoadException($"Unable to find main Smart Detector assembly: {smartDetectorManifest.AssemblyName}");
                }

                // Get the Smart Detector type from the assembly
                this.tracer.TraceInformation($"Creating Smart Detector for {smartDetectorManifest.Name}, version {smartDetectorManifest.Version}, using type {smartDetectorManifest.ClassName}");
                Type smartDetectorType = mainSmartDetectorAssembly.GetType(smartDetectorManifest.ClassName);
                if (smartDetectorType == null)
                {
                    throw new SmartDetectorLoadException($"Smart Detector type {smartDetectorManifest.ClassName} was not found in the main Smart Detector assembly {smartDetectorManifest.AssemblyName}");
                }

                // Check if the type inherits from ISmartDetector
                if (!typeof(ISmartDetector).IsAssignableFrom(smartDetectorType))
                {
                    throw new SmartDetectorLoadException($"Smart Detector type {smartDetectorType.Name} does not extend ISmartDetector");
                }

                // Check that type is not abstract
                if (smartDetectorType.IsAbstract)
                {
                    throw new SmartDetectorLoadException($"Smart Detector type {smartDetectorType.Name} is abstract - a Smart Detector must be a concrete type");
                }

                // Check that type is not generic
                if (smartDetectorType.IsGenericTypeDefinition)
                {
                    throw new SmartDetectorLoadException($"Smart Detector type {smartDetectorType.Name} is generic - a Smart Detector must be a closed constructed type");
                }

                // Check that type has a parameter-less constructor
                if (smartDetectorType.GetConstructor(Type.EmptyTypes) == null)
                {
                    throw new SmartDetectorLoadException($"Smart Detector type {smartDetectorType.Name} does not have a public, parameter-less constructor");
                }

                // Create the Smart Detector object
                ISmartDetector smartDetector = Activator.CreateInstance(smartDetectorType) as ISmartDetector;
                if (smartDetector == null)
                {
                    throw new SmartDetectorLoadException($"Smart Detector {smartDetectorType.Name} failed to be created - instance is null");
                }

                this.tracer.TraceInformation($"Successfully created Smart Detector of type {smartDetectorType.Name}");
                return(smartDetector);
            }
            catch (Exception e)
            {
                this.tracer.TrackEvent(
                    "FailedToLoadSmartDetector",
                    properties: new Dictionary <string, string>
                {
                    { "smartDetectorId", smartDetectorManifest.Id },
                    { "SmartDetectorName", smartDetectorManifest.Name },
                    { "ExceptionType", e.GetType().Name },
                    { "ExceptionMessage", e.Message },
                });

                throw new SmartDetectorLoadException($"Failed to load Smart Detector {smartDetectorManifest.Name}", e);
            }
        }