/// <summary> /// Executes PackageSmartSignal task. /// </summary> /// <returns>True if the task successfully executed; otherwise, False.</returns> public override bool Execute() { try { SmartSignalPackage package = SmartSignalPackage.CreateFromFolder(this.PackagePath); package.SaveToFile(Path.Combine(this.PackagePath, this.PackageName)); } catch (InvalidSmartSignalPackageException exception) { Log.LogError(exception.Message); return(false); } catch (IOException ioe) { Log.LogError($"Failed to create Smart Signal Package - failed creating the package file: {ioe.Message}"); return(false); } catch (SecurityException securityException) { Log.LogError($"Failed to create Smart Signal Package - failed creating the package file: {securityException.Message}"); return(false); } return(true); }
private async Task TestLoadSignalSimple(Type signalType, string expectedTitle = "test test test") { ISmartSignalLoader loader = new SmartSignalLoader(this.tracerMock.Object); SmartSignalManifest manifest = new SmartSignalManifest("3", "simple", "description", Version.Parse("1.0"), signalType.Assembly.GetName().Name, signalType.FullName, new List <ResourceType>() { ResourceType.Subscription }, new List <int> { 60 }); SmartSignalPackage package = new SmartSignalPackage(manifest, this.assemblies["3"]); ISmartSignal signal = loader.LoadSignal(package); Assert.IsNotNull(signal, "Signal is NULL"); var resource = new ResourceIdentifier(ResourceType.VirtualMachine, "someSubscription", "someGroup", "someVM"); var analysisRequest = new AnalysisRequest( new List <ResourceIdentifier> { resource }, DateTime.UtcNow.AddDays(-1), TimeSpan.FromDays(1), new Mock <IAnalysisServicesFactory>().Object); SmartSignalResult signalResult = await signal.AnalyzeResourcesAsync(analysisRequest, this.tracerMock.Object, default(CancellationToken)); Assert.AreEqual(1, signalResult.ResultItems.Count, "Incorrect number of result items returned"); Assert.AreEqual(expectedTitle, signalResult.ResultItems.Single().Title, "Result item title is wrong"); Assert.AreEqual(resource, signalResult.ResultItems.Single().ResourceIdentifier, "Result item resource identifier is wrong"); }
/// <summary> /// Loads a Smart Signal. /// This method load the signal's assembly into the current application domain, /// and creates the signal object using reflection. /// </summary> /// <param name="signalPackage">The signal package.</param> /// <returns>The Smart Signal object.</returns> /// <exception cref="SmartSignalLoadException"> /// Thrown if an error occurred during the signal load (either due to assembly load /// error or failure to create the signal object). /// </exception> public ISmartSignal LoadSignal(SmartSignalPackage signalPackage) { SmartSignalManifest signalManifest = signalPackage.Manifest; IReadOnlyDictionary <string, byte[]> signalAssemblies = signalPackage.Content; try { this.tracer.TraceInformation($"Read {signalAssemblies.Count} assemblies for signal ID {signalManifest.Id}"); // Add assembly resolver, that uses the signal's assemblies AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { this.tracer.TraceInformation($"Resolving assembly {args.Name} for signal ID {signalManifest.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 signal's assemblies if (signalAssemblies.TryGetValue(name, out byte[] assemblyBytes)) { // Load the assembly from its bytes return(Assembly.Load(assemblyBytes)); } return(null); }; // Find the main signal assembly if (!signalAssemblies.TryGetValue(signalManifest.AssemblyName, out byte[] signalMainAssemblyBytes))
/// <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 signalLoader = new SmartSignalLoader(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 signalPackagePath = e.Args.Length != 1 ? this.GetSignalPackagePath() : Diagnostics.EnsureStringNotNullOrWhiteSpace(() => e.Args[0]); SmartSignalPackage signalPackage; using (var fileStream = new FileStream(signalPackagePath, FileMode.Open)) { signalPackage = SmartSignalPackage.CreateFromStream(fileStream, consoleTracer); } SmartSignalManifest signalManifest = signalPackage.Manifest; ISmartSignal signal = signalLoader.LoadSignal(signalPackage); // 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); var signalRunner = new SmartSignalRunner(signal, analysisServicesFactory, queryRunInroProvider, signalManifest, stringTracer); // Create a Unity container with all the required models and view models registrations Container = new UnityContainer(); Container .RegisterInstance(stringTracer) .RegisterInstance(new SignalsResultsRepository()) .RegisterInstance(authenticationServices) .RegisterInstance(azureResourceManagerClient) .RegisterInstance(signal) .RegisterInstance(signalManifest) .RegisterInstance(analysisServicesFactory) .RegisterInstance(signalRunner); }
/// <summary> /// Reads a smart signal's package from the repository /// </summary> /// <param name="signalId">The signal's ID</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>A <see cref="Task{TResult}"/> returning the signal package</returns> public async Task <SmartSignalPackage> ReadSignalPackageAsync(string signalId, CancellationToken cancellationToken) { this.tracer.TraceInformation($"Getting smart signal {signalId} package"); try { CloudBlob latestVersionSignalBlob = await this.GetLatestSignalBlobVersionAsync(signalId, cancellationToken); this.tracer.TraceInformation($"Last version signal BLOB is {latestVersionSignalBlob.Name}"); using (var blobMemoryStream = new MemoryStream()) { // Download the blob to a stream and generate the signal package from it await latestVersionSignalBlob.DownloadToStreamAsync(blobMemoryStream, cancellationToken); return(SmartSignalPackage.CreateFromStream(blobMemoryStream, this.tracer)); } } catch (StorageException e) { throw new SmartSignalRepositoryException("Failed to get signal package from storage", e); } }
private async Task TestLoadSignalFromDll(string signalId, string expectedTitle) { ISmartSignalLoader loader = new SmartSignalLoader(this.tracerMock.Object); SmartSignalPackage package = new SmartSignalPackage(this.manifests[signalId], this.assemblies[signalId]); ISmartSignal signal = loader.LoadSignal(package); Assert.IsNotNull(signal, "Signal is NULL"); var resource = new ResourceIdentifier(ResourceType.VirtualMachine, "someSubscription", "someGroup", "someVM"); var analysisRequest = new AnalysisRequest( new List <ResourceIdentifier> { resource }, DateTime.UtcNow.AddDays(-1), TimeSpan.FromDays(1), new Mock <IAnalysisServicesFactory>().Object); SmartSignalResult signalResult = await signal.AnalyzeResourcesAsync(analysisRequest, this.tracerMock.Object, default(CancellationToken)); Assert.AreEqual(1, signalResult.ResultItems.Count, "Incorrect number of result items returned"); Assert.AreEqual(expectedTitle, signalResult.ResultItems.Single().Title, "Result item title is wrong"); Assert.AreEqual(resource, signalResult.ResultItems.Single().ResourceIdentifier, "Result item resource identifier is wrong"); }
/// <summary> /// Loads the signal, runs it, and returns the generated result presentations /// </summary> /// <param name="request">The signal request</param> /// <param name="cancellationToken">The cancellation token</param> /// <returns>A <see cref="Task{TResult}"/>, returning the list of Smart Signal result item presentations generated by the signal</returns> public async Task <List <SmartSignalResultItemPresentation> > RunAsync(SmartSignalRequest request, CancellationToken cancellationToken) { // Read the signal's package this.tracer.TraceInformation($"Loading signal package for signal ID {request.SignalId}"); SmartSignalPackage signalPackage = await this.smartSignalRepository.ReadSignalPackageAsync(request.SignalId, cancellationToken); SmartSignalManifest signalManifest = signalPackage.Manifest; this.tracer.TraceInformation($"Read signal package, ID {signalManifest.Id}, Version {signalManifest.Version}"); // Load the signal ISmartSignal signal = this.smartSignalLoader.LoadSignal(signalPackage); this.tracer.TraceInformation($"Signal instance loaded successfully, ID {signalManifest.Id}"); // Get the resources on which to run the signal List <ResourceIdentifier> resources = await this.GetResourcesForSignal(request.ResourceIds, signalManifest, cancellationToken); // Run the signal this.tracer.TraceInformation($"Started running signal ID {signalManifest.Id}, Name {signalManifest.Name}"); SmartSignalResult signalResult; try { var analysisRequest = new AnalysisRequest(resources, request.LastExecutionTime, request.Cadence, this.analysisServicesFactory); signalResult = await signal.AnalyzeResourcesAsync(analysisRequest, this.tracer, cancellationToken); this.tracer.TraceInformation($"Completed running signal ID {signalManifest.Id}, Name {signalManifest.Name}, returning {signalResult.ResultItems.Count} result items"); } catch (Exception e) { this.tracer.TraceInformation($"Failed running signal ID {signalManifest.Id}, Name {signalManifest.Name}: {e.Message}"); throw new SmartSignalCustomException(e.GetType().ToString(), e.Message, e.StackTrace); } // Verify that each result item belongs to one of the types declared in the signal manifest foreach (SmartSignalResultItem resultItem in signalResult.ResultItems) { if (!signalManifest.SupportedResourceTypes.Contains(resultItem.ResourceIdentifier.ResourceType)) { throw new UnidentifiedResultItemResourceTypeException(resultItem.ResourceIdentifier); } } // Trace the number of result items of each type foreach (var resultItemType in signalResult.ResultItems.GroupBy(x => x.GetType().Name)) { this.tracer.TraceInformation($"Got {resultItemType.Count()} Smart Signal result items of type '{resultItemType.Key}'"); this.tracer.ReportMetric("SignalResultItemType", resultItemType.Count(), new Dictionary <string, string>() { { "ResultItemType", resultItemType.Key } }); } // Create results List <SmartSignalResultItemPresentation> results = new List <SmartSignalResultItemPresentation>(); foreach (var resultItem in signalResult.ResultItems) { SmartSignalResultItemQueryRunInfo queryRunInfo = await this.queryRunInfoProvider.GetQueryRunInfoAsync(new List <ResourceIdentifier>() { resultItem.ResourceIdentifier }, cancellationToken); results.Add(SmartSignalResultItemPresentation.CreateFromResultItem(request, signalManifest.Name, resultItem, queryRunInfo)); } this.tracer.TraceInformation($"Returning {results.Count} results"); return(results); }
private void TestInitialize(ResourceType requestResourceType, ResourceType signalResourceType) { this.tracerMock = new Mock <ITracer>(); 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 SmartSignalRequest(this.resourceIds, "1", DateTime.UtcNow.AddDays(-1), TimeSpan.FromDays(1), new SmartSignalSettings()); var smartSignalManifest = new SmartSignalManifest("1", "Test signal", "Test signal description", Version.Parse("1.0"), "assembly", "class", new List <ResourceType>() { signalResourceType }, new List <int> { 60 }); this.smartSignalPackage = new SmartSignalPackage(smartSignalManifest, new Dictionary <string, byte[]> { ["TestSignalLibrary"] = new byte[0] }); this.smartSignalsRepositoryMock = new Mock <ISmartSignalRepository>(); this.smartSignalsRepositoryMock .Setup(x => x.ReadSignalPackageAsync(It.IsAny <string>(), It.IsAny <CancellationToken>())) .ReturnsAsync(() => this.smartSignalPackage); this.analysisServicesFactoryMock = new Mock <IAnalysisServicesFactory>(); this.signal = new TestSignal { ExpectedResourceType = signalResourceType }; this.smartSignalLoaderMock = new Mock <ISmartSignalLoader>(); this.smartSignalLoaderMock .Setup(x => x.LoadSignal(this.smartSignalPackage)) .Returns(this.signal); this.azureResourceManagerClientMock = new Mock <IAzureResourceManagerClient>(); this.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) }); this.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") }); this.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.queryRunInfoProviderMock = new Mock <IQueryRunInfoProvider>(); }