From 3acf6c2bf16f0d0dc73bb8e2fafa59fdd9ce47f1 Mon Sep 17 00:00:00 2001 From: Tom Kerkhove Date: Thu, 18 Feb 2021 08:14:51 +0100 Subject: [PATCH] feat: Provide support for scraping Azure Synapse workspace, Apache Spark & SQL pools (#1513) * Add basics Signed-off-by: Tom Kerkhove * Provide documentation & changelog Signed-off-by: Tom Kerkhove * Add discovery groups Signed-off-by: Tom Kerkhove * Add new metrics Signed-off-by: Tom Kerkhove * Implement scrapers Signed-off-by: Tom Kerkhove * Less verbose logs Signed-off-by: Tom Kerkhove * Information logs Signed-off-by: Tom Kerkhove * Cleanup Signed-off-by: Tom Kerkhove * Code cleanup Signed-off-by: Tom Kerkhove * Provide unit tests Signed-off-by: Tom Kerkhove --- .github/PULL_REQUEST_TEMPLATE.md | 3 + changelog/content/experimental/unreleased.md | 12 ++ .../resource-discovery-declaration.yaml | 6 + .../promitor/resource-discovery/runtime.yaml | 6 +- config/promitor/scraper/metrics.yaml | 40 ++++-- config/promitor/scraper/runtime.yaml | 2 +- docs/configuration/v2.x/metrics/index.md | 3 + .../v2.x/metrics/synapse-apache-spark-pool.md | 44 ++++++ .../v2.x/metrics/synapse-sql-pool.md | 44 ++++++ .../v2.x/metrics/synapse-workspace.md | 42 ++++++ docs/configuration/v2.x/resource-discovery.md | 3 + .../Docs/Open-Api.xml | 8 ++ .../Graph/ResourceDiscoveryFactory.cs | 6 + .../Graph/ResourceDiscoveryQuery.cs | 18 +++ .../SqlDatabaseDiscoveryQuery.cs | 6 +- .../Graph/ResourceTypes/SqlDiscoveryQuery.cs | 23 --- .../SqlElasticPoolDiscoveryQuery.cs | 6 +- .../SynapseApacheSparkPoolDiscoveryQuery.cs | 31 ++++ .../SynapseSqlPoolDiscoveryQuery.cs | 31 ++++ .../SynapseWorkspaceDiscoveryQuery.cs | 21 +++ .../Factories/MetricValidatorFactory.cs | 6 + .../SynapseApacheSparkPoolMetricValidator.cs | 30 ++++ .../SynapseSqlPoolMetricValidator.cs | 30 ++++ .../SynapseWorkspaceMetricValidator.cs | 25 ++++ src/Promitor.Core.Contracts/ResourceType.cs | 5 +- .../SqlElasticPoolResourceDefinition.cs | 2 +- ...ynapseApacheSparkPoolResourceDefinition.cs | 32 +++++ .../SynapseSqlPoolResourceDefinition.cs | 32 +++++ .../SynapseWorkspaceResourceDefinition.cs | 25 ++++ .../Serialization/ConfigurationSerializer.cs | 2 +- .../Core/AzureResourceDeserializerFactory.cs | 9 ++ .../v1/Mapping/V1MappingProfile.cs | 6 + .../SynapseApacheSparkPoolResourceV1.cs | 28 ++++ .../ResourceTypes/SynapseSqlPoolResourceV1.cs | 28 ++++ .../SynapseWorkspaceResourceV1.cs | 22 +++ .../SynapseApacheSparkPoolDeserializer.cs | 16 +++ .../Providers/SynapseSqlPoolDeserializer.cs | 16 +++ .../Providers/SynapseWorkspaceDeserializer.cs | 14 ++ .../Factories/MetricScraperFactory.cs | 6 + .../ResourceTypes/AzureMessagingScraper.cs | 2 +- .../SynapseApacheSparkPoolScraper.cs | 35 +++++ .../ResourceTypes/SynapseSqlPoolScraper.cs | 35 +++++ .../ResourceTypes/SynapseWorkspaceScraper.cs | 34 +++++ .../Metrics/v1/MetricsDeclarationBuilder.cs | 58 ++++++++ ...lDatabaseResourceDiscoveryQueryUnitTest.cs | 12 +- .../SqlElasticPoolDiscoveryQueryUnitTest.cs | 52 +++++++ ...seApacheSparkPoolDiscoveryQueryUnitTest.cs | 52 +++++++ .../SynapseSqlPoolDiscoveryQueryUnitTest.cs | 52 +++++++ ...SynapseApacheSparkPoolDeserializerTests.cs | 87 ++++++++++++ .../SynapseSqlPoolDeserializerTests.cs | 87 ++++++++++++ .../SynapseWorkspaceDeserializerTests.cs | 54 +++++++ ...olMetricsDeclarationValidationStepTests.cs | 132 ++++++++++++++++++ ...olMetricsDeclarationValidationStepTests.cs | 132 ++++++++++++++++++ ...ceMetricsDeclarationValidationStepTests.cs | 115 +++++++++++++++ 54 files changed, 1572 insertions(+), 56 deletions(-) create mode 100644 docs/configuration/v2.x/metrics/synapse-apache-spark-pool.md create mode 100644 docs/configuration/v2.x/metrics/synapse-sql-pool.md create mode 100644 docs/configuration/v2.x/metrics/synapse-workspace.md delete mode 100644 src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SqlDiscoveryQuery.cs create mode 100644 src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SynapseApacheSparkPoolDiscoveryQuery.cs create mode 100644 src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SynapseSqlPoolDiscoveryQuery.cs create mode 100644 src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SynapseWorkspaceDiscoveryQuery.cs create mode 100644 src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/SynapseApacheSparkPoolMetricValidator.cs create mode 100644 src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/SynapseSqlPoolMetricValidator.cs create mode 100644 src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/SynapseWorkspaceMetricValidator.cs create mode 100644 src/Promitor.Core.Contracts/ResourceTypes/SynapseApacheSparkPoolResourceDefinition.cs create mode 100644 src/Promitor.Core.Contracts/ResourceTypes/SynapseSqlPoolResourceDefinition.cs create mode 100644 src/Promitor.Core.Contracts/ResourceTypes/SynapseWorkspaceResourceDefinition.cs create mode 100644 src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/ResourceTypes/SynapseApacheSparkPoolResourceV1.cs create mode 100644 src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/ResourceTypes/SynapseSqlPoolResourceV1.cs create mode 100644 src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/ResourceTypes/SynapseWorkspaceResourceV1.cs create mode 100644 src/Promitor.Core.Scraping/Configuration/Serialization/v1/Providers/SynapseApacheSparkPoolDeserializer.cs create mode 100644 src/Promitor.Core.Scraping/Configuration/Serialization/v1/Providers/SynapseSqlPoolDeserializer.cs create mode 100644 src/Promitor.Core.Scraping/Configuration/Serialization/v1/Providers/SynapseWorkspaceDeserializer.cs create mode 100644 src/Promitor.Core.Scraping/ResourceTypes/SynapseApacheSparkPoolScraper.cs create mode 100644 src/Promitor.Core.Scraping/ResourceTypes/SynapseSqlPoolScraper.cs create mode 100644 src/Promitor.Core.Scraping/ResourceTypes/SynapseWorkspaceScraper.cs create mode 100644 src/Promitor.Tests.Unit/Discovery/Query/SqlElasticPoolDiscoveryQueryUnitTest.cs create mode 100644 src/Promitor.Tests.Unit/Discovery/Query/SynapseApacheSparkPoolDiscoveryQueryUnitTest.cs create mode 100644 src/Promitor.Tests.Unit/Discovery/Query/SynapseSqlPoolDiscoveryQueryUnitTest.cs create mode 100644 src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseApacheSparkPoolDeserializerTests.cs create mode 100644 src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseSqlPoolDeserializerTests.cs create mode 100644 src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseWorkspaceDeserializerTests.cs create mode 100644 src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/SynapseApacheSparkPoolMetricsDeclarationValidationStepTests.cs create mode 100644 src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/SynapseSqlPoolMetricsDeclarationValidationStepTests.cs create mode 100644 src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/SynapseWorkspaceMetricsDeclarationValidationStepTests.cs diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index ec853bb22..a701a8a36 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,3 +1,4 @@ + Fixes # + + \ No newline at end of file diff --git a/changelog/content/experimental/unreleased.md b/changelog/content/experimental/unreleased.md index d4e9f0b62..7b9e81073 100644 --- a/changelog/content/experimental/unreleased.md +++ b/changelog/content/experimental/unreleased.md @@ -12,6 +12,12 @@ version: | [#343](https://github.com/tomkerkhove/promitor/issues/343)) - {{% tag added %}} Support for scraping Azure SQL Elastic Pool ([docs](https://promitor.io/configuration/v2.x/metrics/sql-elastic-pool) | [#319](https://github.com/tomkerkhove/promitor/issues/319)) +- {{% tag added %}} Support for scraping Azure Synapse (Apache Spark pool) ([docs](https://promitor.io/configuration/v2.x/metrics/synapse-apache-spark-pool) + | [#1477](https://github.com/tomkerkhove/promitor/issues/1477)) +- {{% tag added %}} Support for scraping Azure Synapse (SQL pool) ([docs](https://promitor.io/configuration/v2.x/metrics/sql-elastic-pool) + | [#1477](https://github.com/tomkerkhove/promitor/issues/1477)) +- {{% tag added %}} Support for scraping Azure Synapse (Workspace) ([docs](https://promitor.io/configuration/v2.x/metrics/sql-elastic-pool) + | [#1477](https://github.com/tomkerkhove/promitor/issues/1477)) - {{% tag added %}} Support Prometheus Operator in Helm chart ([PR #31](https://github.com/promitor/charts/pull/31) | Contributed by [@DaveOHenry](https://github.com/DaveOHenry) 🎉) - {{% tag added %}} Support for affinity in Helm chart ([PR #30](https://github.com/promitor/charts/pull/30) @@ -40,6 +46,12 @@ version: | [#343](https://github.com/tomkerkhove/promitor/issues/343)) - {{% tag added %}} Support for scraping Azure SQL Elastic Pool ([docs](https://promitor.io/configuration/v2.x/metrics/sql-elastic-pool) | [#319](https://github.com/tomkerkhove/promitor/issues/319)) +- {{% tag added %}} Support for scraping Azure Synapse (Apache Spark pool) ([docs](https://promitor.io/configuration/v2.x/metrics/synapse-apache-spark-pool) + | [#1477](https://github.com/tomkerkhove/promitor/issues/1477)) +- {{% tag added %}} Support for scraping Azure Synapse (SQL pool) ([docs](https://promitor.io/configuration/v2.x/metrics/sql-elastic-pool) + | [#1477](https://github.com/tomkerkhove/promitor/issues/1477)) +- {{% tag added %}} Support for scraping Azure Synapse (Workspace) ([docs](https://promitor.io/configuration/v2.x/metrics/sql-elastic-pool) + | [#1477](https://github.com/tomkerkhove/promitor/issues/1477)) - {{% tag added %}} Support for affinity in Helm chart ([PR #30](https://github.com/promitor/charts/pull/30) | Contributed by [@t3mi](https://github.com/t3mi) 🎉) - {{% tag added %}} Support for priority class name in Helm chart ([PR #30](https://github.com/promitor/charts/pull/30) diff --git a/config/promitor/resource-discovery/resource-discovery-declaration.yaml b/config/promitor/resource-discovery/resource-discovery-declaration.yaml index 13ebd3bcc..e245b8aa2 100644 --- a/config/promitor/resource-discovery/resource-discovery-declaration.yaml +++ b/config/promitor/resource-discovery/resource-discovery-declaration.yaml @@ -46,6 +46,12 @@ resourceDiscoveryGroups: type: SqlServer - name: storage-accounts type: StorageAccount +- name: synapse-apache-spark-pools + type: SynapseApacheSparkPool +- name: synapse-sql-pools + type: SynapseSqlPool +- name: synapse-workspaces + type: SynapseWorkspace - name: virtual-machines type: VirtualMachine - name: virtual-machine-scale-sets diff --git a/config/promitor/resource-discovery/runtime.yaml b/config/promitor/resource-discovery/runtime.yaml index fb0e13d94..d6a874782 100644 --- a/config/promitor/resource-discovery/runtime.yaml +++ b/config/promitor/resource-discovery/runtime.yaml @@ -3,9 +3,7 @@ server: telemetry: applicationInsights: instrumentationKey: ABC - isEnabled: true - verbosity: warning + isEnabled: false containerLogs: isEnabled: true - verbosity: trace - defaultVerbosity: trace \ No newline at end of file + defaultVerbosity: information \ No newline at end of file diff --git a/config/promitor/scraper/metrics.yaml b/config/promitor/scraper/metrics.yaml index 4e86ee650..8e141d54d 100644 --- a/config/promitor/scraper/metrics.yaml +++ b/config/promitor/scraper/metrics.yaml @@ -10,17 +10,6 @@ metricDefaults: # Every minute schedule: "0 * * ? * *" metrics: -- name: promitor_demo_frontdoor_backend_health - description: "Average percentage of memory usage on an Azure App Plan" - resourceType: FrontDoor - labels: - app: promitor - azureMetricConfiguration: - metricName: BackendHealthPercentage - aggregation: - type: Average - resources: - - name: promitor-app-plan - name: promitor_demo_appplan_percentage_cpu description: "Average percentage of memory usage on an Azure App Plan" resourceType: AppPlan @@ -248,4 +237,31 @@ metrics: aggregation: type: Average resourceDiscoveryGroups: - - name: sql-elastic-pools \ No newline at end of file + - name: sql-elastic-pools +- name: promitor_demo_synapse_apache_spark_apps_ended + description: "Amount of apps ended running on Apache Spark pool in Azure Synapse" + resourceType: SynapseApacheSparkPool + azureMetricConfiguration: + metricName: BigDataPoolApplicationsEnded + aggregation: + type: Total + resourceDiscoveryGroups: + - name: synapse-apache-spark-pools +- name: promitor_demo_synapse_sql_pool_dwu_limit + description: "Amount of DWUs defined as limit for SQL pool in Azure Synapse" + resourceType: SynapseSqlPool + azureMetricConfiguration: + metricName: DWULimit + aggregation: + type: Maximum + resourceDiscoveryGroups: + - name: synapse-sql-pools +- name: promitor_demo_synapse_workspace_builtin_sql_processed_bytes + description: "Amount of bytes processed in Azure Synapse workspace" + resourceType: SynapseWorkspace + azureMetricConfiguration: + metricName: BuiltinSqlPoolDataProcessedBytes + aggregation: + type: Total + resourceDiscoveryGroups: + - name: synapse-workspaces \ No newline at end of file diff --git a/config/promitor/scraper/runtime.yaml b/config/promitor/scraper/runtime.yaml index ee9013d8d..6e8c858d6 100644 --- a/config/promitor/scraper/runtime.yaml +++ b/config/promitor/scraper/runtime.yaml @@ -19,7 +19,7 @@ metricsConfiguration: telemetry: applicationInsights: instrumentationKey: ABC - isEnabled: true + isEnabled: false verbosity: warning containerLogs: isEnabled: true diff --git a/docs/configuration/v2.x/metrics/index.md b/docs/configuration/v2.x/metrics/index.md index 1fe1a6bd6..e6e637a27 100644 --- a/docs/configuration/v2.x/metrics/index.md +++ b/docs/configuration/v2.x/metrics/index.md @@ -153,6 +153,9 @@ We also provide a simplified way to scrape the following Azure resources: - [Azure Storage (Blob)](blob-storage) - [Azure Storage (Files)](file-storage) - [Azure Storage (Queue)](storage-queue) +- [Azure Synapse (Apache Spark pool)](synapse-apache-spark-pool) +- [Azure Synapse (SQL pool)](synapse-sql-pool) +- [Azure Synapse (Workspace)](synapse-workspace) - [Azure Virtual Machine](virtual-machine) - [Azure Virtual Machine Scale Set (VMSS)](virtual-machine-scale-set) - [Azure Web App](web-app) diff --git a/docs/configuration/v2.x/metrics/synapse-apache-spark-pool.md b/docs/configuration/v2.x/metrics/synapse-apache-spark-pool.md new file mode 100644 index 000000000..9e354ab7a --- /dev/null +++ b/docs/configuration/v2.x/metrics/synapse-apache-spark-pool.md @@ -0,0 +1,44 @@ +--- +layout: default +title: Azure Synapse (Apache Spark pool) Declaration +--- + +## Azure Synapse (Apache Spark pool) + +![Availability Badge](https://img.shields.io/badge/Available%20Starting-v2.1-green.svg)![Resource Discovery Support Badge](https://img.shields.io/badge/Support%20for%20Resource%20Discovery-Yes-green.svg) + +You can scrape an Azure Synapse Apache Spark pool via the `SynapseApacheSparkPool` resource type. + +The following fields need to be provided: + +- `workspaceName` - The name of the Azure Synapse workspace. +- `poolName` - The name of the Apache Spark pool. + +All supported metrics are documented in the official [Azure Monitor documentation](https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-supported#microsoftsynapseworkspacesbigdatapools). + +The following scraper-specific metric labels will be added: + +- `workspace_name` - The name of the Azure Synapse workspace. +- `pool_name` - The name of the Apache Spark pool. + +Example: + +```yaml +- name: promitor_demo_synapse_apache_spark_apps_ended + description: "Amount of apps ended running on Apache Spark pool in Azure Synapse" + resourceType: SynapseApacheSparkPool + azureMetricConfiguration: + metricName: BigDataPoolApplicationsEnded + aggregation: + type: Total + resources: + - workspaceName: promitor-synapse + poolName: sparkpool + resourceDiscoveryGroups: # Optional, requires Promitor Resource Discovery agent (https://promitor.io/concepts/how-it-works#using-resource-discovery) + - name: synapse-apache-spark-pools +``` + + +[← back to metrics declarations](/configuration/v2.x/metrics)
+[← back to introduction](/) + diff --git a/docs/configuration/v2.x/metrics/synapse-sql-pool.md b/docs/configuration/v2.x/metrics/synapse-sql-pool.md new file mode 100644 index 000000000..a3422e33d --- /dev/null +++ b/docs/configuration/v2.x/metrics/synapse-sql-pool.md @@ -0,0 +1,44 @@ +--- +layout: default +title: Azure Synapse (SQL pool) Declaration +--- + +## Azure Synapse (SQL pool) + +![Availability Badge](https://img.shields.io/badge/Available%20Starting-v2.1-green.svg)![Resource Discovery Support Badge](https://img.shields.io/badge/Support%20for%20Resource%20Discovery-Yes-green.svg) + +You can scrape an Azure Synapse SQL pool via the `SynapseSqlPool` resource type. + +The following fields need to be provided: + +- `workspaceName` - The name of the Azure Synapse workspace. +- `poolName` - The name of the SQL pool. + +All supported metrics are documented in the official [Azure Monitor documentation](https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-supported#microsoftsynapseworkspacessqlpools). + +The following scraper-specific metric labels will be added: + +- `workspace_name` - The name of the Azure Synapse workspace. +- `pool_name` - The name of the SQL pool. + +Example: + +```yaml +- name: promitor_demo_synapse_sql_pool_dwu_limit + description: "Amount of DWUs defined as limit for SQL pool in Azure Synapse" + resourceType: SynapseSqlPool + azureMetricConfiguration: + metricName: DWULimit + aggregation: + type: Maximum + resources: + - workspaceName: promitor-synapse + poolName: sqlpool + resourceDiscoveryGroups: # Optional, requires Promitor Resource Discovery agent (https://promitor.io/concepts/how-it-works#using-resource-discovery) + - name: synapse-sql-pools +``` + + +[← back to metrics declarations](/configuration/v2.x/metrics)
+[← back to introduction](/) + diff --git a/docs/configuration/v2.x/metrics/synapse-workspace.md b/docs/configuration/v2.x/metrics/synapse-workspace.md new file mode 100644 index 000000000..0a14255f5 --- /dev/null +++ b/docs/configuration/v2.x/metrics/synapse-workspace.md @@ -0,0 +1,42 @@ +--- +layout: default +title: Azure Synapse (Workspace) Declaration +--- + +## Azure Synapse (Workspace) + +![Availability Badge](https://img.shields.io/badge/Available%20Starting-v2.1-green.svg)![Resource Discovery Support Badge](https://img.shields.io/badge/Support%20for%20Resource%20Discovery-Yes-green.svg) + +You can scrape an Azure Synapse workspace via the `SynapseWorkspace` resource type. + +The following fields need to be provided: + +- `workspaceName` - The name of the Azure Synapse workspace. + +All supported metrics are documented in the official [Azure Monitor documentation](https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-supported#microsoftsynapseworkspaces). + +The following scraper-specific metric labels will be added: + +- `workspace_name` - The name of the Azure Synapse workspace. + +Example: + +```yaml +- name: promitor_demo_synapse_workspace_builtin_sql_processed_bytes + description: "Amount of bytes processed in Azure Synapse workspace" + resourceType: SynapseWorkspace + azureMetricConfiguration: + metricName: BuiltinSqlPoolDataProcessedBytes + aggregation: + type: Total + resources: + - workspaceName: promitor-synapse + resourceGroupName: promitor-sources + resourceDiscoveryGroups: # Optional, requires Promitor Resource Discovery agent (https://promitor.io/concepts/how-it-works#using-resource-discovery) + - name: synapse-apache-spark-pools +``` + + +[← back to metrics declarations](/configuration/v2.x/metrics)
+[← back to introduction](/) + diff --git a/docs/configuration/v2.x/resource-discovery.md b/docs/configuration/v2.x/resource-discovery.md index a58e0969a..2e03dffa4 100644 --- a/docs/configuration/v2.x/resource-discovery.md +++ b/docs/configuration/v2.x/resource-discovery.md @@ -112,6 +112,9 @@ Dynamic resource discovery is supported for the following scrapers: - [Azure SQL Elastic Pool](metrics/sql-elastic-pool) - [Azure SQL Managed Instance](metrics/sql-managed-instance) - [Azure Storage (Account)](metrics/storage-account) +- [Azure Synapse (Apache Spark pool)](metrics/synapse-apache-spark-pool) +- [Azure Synapse (SQL pool)](metrics/synapse-sql-pool) +- [Azure Synapse (Workspace)](metrics/synapse-workspace) - [Azure Virtual Machine](metrics/virtual-machine) - [Azure Virtual Machine Scale Set (VMSS)](metrics/virtual-machine-scale-set) - [Azure Web App](metrics/web-app) diff --git a/src/Promitor.Agents.ResourceDiscovery/Docs/Open-Api.xml b/src/Promitor.Agents.ResourceDiscovery/Docs/Open-Api.xml index 32f001016..b4e28878c 100644 --- a/src/Promitor.Agents.ResourceDiscovery/Docs/Open-Api.xml +++ b/src/Promitor.Agents.ResourceDiscovery/Docs/Open-Api.xml @@ -97,6 +97,14 @@ Response provided by Azure Resource Graph after running a query + + + Gets the name of the parent resource from a resource URI + + Identifier to split on, ie servers/ for Azure SQL DB to get the server name + Uri of the child resource + Name of the parent resource + Initializes a new instance of the class. diff --git a/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceDiscoveryFactory.cs b/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceDiscoveryFactory.cs index cf6de2d11..48e937279 100644 --- a/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceDiscoveryFactory.cs +++ b/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceDiscoveryFactory.cs @@ -60,6 +60,12 @@ public static ResourceDiscoveryQuery UseResourceDiscoveryFor(ResourceType resour return new SqlManagedInstanceDiscoveryQuery(); case ResourceType.StorageAccount: return new StorageAccountDiscoveryQuery(); + case ResourceType.SynapseApacheSparkPool: + return new SynapseApacheSparkPoolDiscoveryQuery(); + case ResourceType.SynapseSqlPool: + return new SynapseSqlPoolDiscoveryQuery(); + case ResourceType.SynapseWorkspace: + return new SynapseWorkspaceDiscoveryQuery(); case ResourceType.VirtualMachine: return new VirtualMachineDiscoveryQuery(); case ResourceType.VirtualMachineScaleSet: diff --git a/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceDiscoveryQuery.cs b/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceDiscoveryQuery.cs index 8f0c3ac61..6a9b0dd4c 100644 --- a/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceDiscoveryQuery.cs +++ b/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceDiscoveryQuery.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using GuardNet; using Newtonsoft.Json.Linq; using Promitor.Agents.ResourceDiscovery.Configuration; @@ -45,6 +46,23 @@ public virtual GraphQueryBuilder DefineQuery(ResourceCriteriaDefinition criteria return graphQueryBuilder; } + + /// + /// Gets the name of the parent resource from a resource URI + /// + /// Identifier to split on, ie servers/ for Azure SQL DB to get the server name + /// Uri of the child resource + /// Name of the parent resource + public virtual string GetParentResourceNameFromResourceUri(string resourceIdentifier, JToken resourceUri) + { + Guard.NotNull(resourceUri, nameof(resourceUri)); + var rawResourceUri = resourceUri.ToString(); + Guard.For(() => string.IsNullOrWhiteSpace(rawResourceUri), nameof(resourceUri)); + + var positionOfServersSection = rawResourceUri.LastIndexOf(resourceIdentifier, StringComparison.InvariantCultureIgnoreCase) + resourceIdentifier.Length; + var sqlResourceDetailsParts = rawResourceUri.Substring(positionOfServersSection).Split("/"); + return sqlResourceDetailsParts.FirstOrDefault(); + } public abstract string[] ResourceTypes { get; } public abstract string[] ProjectedFieldNames { get; } diff --git a/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SqlDatabaseDiscoveryQuery.cs b/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SqlDatabaseDiscoveryQuery.cs index f4199fbf1..9f6201360 100644 --- a/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SqlDatabaseDiscoveryQuery.cs +++ b/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SqlDatabaseDiscoveryQuery.cs @@ -6,8 +6,9 @@ namespace Promitor.Agents.ResourceDiscovery.Graph.ResourceTypes { - public class SqlDatabaseDiscoveryQuery : SqlDiscoveryQuery + public class SqlDatabaseDiscoveryQuery : ResourceDiscoveryQuery { + public const string ServerSectionInResourceUri = "servers/"; public override string[] ResourceTypes => new[] { "microsoft.sql/servers/databases" }; public override string[] ProjectedFieldNames => new[] { "subscriptionId", "resourceGroup", "type", "name", "id" }; @@ -15,8 +16,7 @@ public override AzureResourceDefinition ParseResults(JToken resultRowEntry) { Guard.NotNull(resultRowEntry, nameof(resultRowEntry)); - var serverName = GetServerNameFromResourceUri(resultRowEntry[4]); - + var serverName = GetParentResourceNameFromResourceUri(ServerSectionInResourceUri, resultRowEntry[4]); if (string.IsNullOrWhiteSpace(serverName)) { throw new Exception($"Unable to determine server name from resource URI '{resultRowEntry[4]}'"); diff --git a/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SqlDiscoveryQuery.cs b/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SqlDiscoveryQuery.cs deleted file mode 100644 index c672ee91e..000000000 --- a/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SqlDiscoveryQuery.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Linq; -using GuardNet; -using Newtonsoft.Json.Linq; - -namespace Promitor.Agents.ResourceDiscovery.Graph.ResourceTypes -{ - public abstract class SqlDiscoveryQuery : ResourceDiscoveryQuery - { - private const string ServerSectionInResourceUri = "servers/"; - - public virtual string GetServerNameFromResourceUri(JToken resourceUri) - { - Guard.NotNull(resourceUri, nameof(resourceUri)); - var rawResourceUri = resourceUri.ToString(); - Guard.For(() => string.IsNullOrWhiteSpace(rawResourceUri), nameof(resourceUri)); - - var positionOfServersSection = rawResourceUri.LastIndexOf(ServerSectionInResourceUri, StringComparison.InvariantCultureIgnoreCase) + ServerSectionInResourceUri.Length; - var sqlResourceDetailsParts = rawResourceUri.Substring(positionOfServersSection).Split("/"); - return sqlResourceDetailsParts.FirstOrDefault(); - } - } -} diff --git a/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SqlElasticPoolDiscoveryQuery.cs b/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SqlElasticPoolDiscoveryQuery.cs index e43b402f0..a847337c4 100644 --- a/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SqlElasticPoolDiscoveryQuery.cs +++ b/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SqlElasticPoolDiscoveryQuery.cs @@ -6,8 +6,9 @@ namespace Promitor.Agents.ResourceDiscovery.Graph.ResourceTypes { - public class SqlElasticPoolDiscoveryQuery : SqlDiscoveryQuery + public class SqlElasticPoolDiscoveryQuery : ResourceDiscoveryQuery { + public const string ServerSectionInResourceUri = "servers/"; public override string[] ResourceTypes => new[] { "microsoft.sql/servers/elasticpools" }; public override string[] ProjectedFieldNames => new[] { "subscriptionId", "resourceGroup", "type", "name", "id" }; @@ -15,8 +16,7 @@ public override AzureResourceDefinition ParseResults(JToken resultRowEntry) { Guard.NotNull(resultRowEntry, nameof(resultRowEntry)); - var serverName = GetServerNameFromResourceUri(resultRowEntry[4]); - + var serverName = GetParentResourceNameFromResourceUri(ServerSectionInResourceUri, resultRowEntry[4]); if (string.IsNullOrWhiteSpace(serverName)) { throw new Exception($"Unable to determine server name from resource URI '{resultRowEntry[4]}'"); diff --git a/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SynapseApacheSparkPoolDiscoveryQuery.cs b/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SynapseApacheSparkPoolDiscoveryQuery.cs new file mode 100644 index 000000000..a3c25d517 --- /dev/null +++ b/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SynapseApacheSparkPoolDiscoveryQuery.cs @@ -0,0 +1,31 @@ +using System; +using GuardNet; +using Newtonsoft.Json.Linq; +using Promitor.Core.Contracts; +using Promitor.Core.Contracts.ResourceTypes; + +namespace Promitor.Agents.ResourceDiscovery.Graph.ResourceTypes +{ + public class SynapseApacheSparkPoolDiscoveryQuery : ResourceDiscoveryQuery + { + public const string WorkspaceSectionInResourceUri = "workspaces/"; + public override string[] ResourceTypes => new[] { "microsoft.synapse/workspaces/bigdatapools" }; + public override string[] ProjectedFieldNames => new[] { "subscriptionId", "resourceGroup", "type", "name", "id" }; + + public override AzureResourceDefinition ParseResults(JToken resultRowEntry) + { + Guard.NotNull(resultRowEntry, nameof(resultRowEntry)); + + // Get workspace name + var workspaceName = GetParentResourceNameFromResourceUri(WorkspaceSectionInResourceUri, resultRowEntry[4]); + if (string.IsNullOrWhiteSpace(workspaceName)) + { + throw new Exception($"Unable to determine workspace name from resource URI '{resultRowEntry[4]}'"); + } + + // Create resource definition + var resource = new SynapseApacheSparkPoolResourceDefinition(resultRowEntry[0]?.ToString(), resultRowEntry[1]?.ToString(), workspaceName, resultRowEntry[3]?.ToString()); + return resource; + } + } +} diff --git a/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SynapseSqlPoolDiscoveryQuery.cs b/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SynapseSqlPoolDiscoveryQuery.cs new file mode 100644 index 000000000..e47a49eb4 --- /dev/null +++ b/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SynapseSqlPoolDiscoveryQuery.cs @@ -0,0 +1,31 @@ +using System; +using GuardNet; +using Newtonsoft.Json.Linq; +using Promitor.Core.Contracts; +using Promitor.Core.Contracts.ResourceTypes; + +namespace Promitor.Agents.ResourceDiscovery.Graph.ResourceTypes +{ + public class SynapseSqlPoolDiscoveryQuery : ResourceDiscoveryQuery + { + public const string WorkspaceSectionInResourceUri = "workspaces/"; + public override string[] ResourceTypes => new[] { "microsoft.synapse/workspaces/sqlpools" }; + public override string[] ProjectedFieldNames => new[] { "subscriptionId", "resourceGroup", "type", "name", "id" }; + + public override AzureResourceDefinition ParseResults(JToken resultRowEntry) + { + Guard.NotNull(resultRowEntry, nameof(resultRowEntry)); + + // Get workspace name + var workspaceName = GetParentResourceNameFromResourceUri(WorkspaceSectionInResourceUri, resultRowEntry[4]); + if (string.IsNullOrWhiteSpace(workspaceName)) + { + throw new Exception($"Unable to determine workspace name from resource URI '{resultRowEntry[4]}'"); + } + + // Create resource definition + var resource = new SynapseSqlPoolResourceDefinition(resultRowEntry[0]?.ToString(), resultRowEntry[1]?.ToString(), workspaceName, resultRowEntry[3]?.ToString()); + return resource; + } + } +} diff --git a/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SynapseWorkspaceDiscoveryQuery.cs b/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SynapseWorkspaceDiscoveryQuery.cs new file mode 100644 index 000000000..a7a596eec --- /dev/null +++ b/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/SynapseWorkspaceDiscoveryQuery.cs @@ -0,0 +1,21 @@ +using GuardNet; +using Newtonsoft.Json.Linq; +using Promitor.Core.Contracts; +using Promitor.Core.Contracts.ResourceTypes; + +namespace Promitor.Agents.ResourceDiscovery.Graph.ResourceTypes +{ + public class SynapseWorkspaceDiscoveryQuery : ResourceDiscoveryQuery + { + public override string[] ResourceTypes => new[] { "microsoft.synapse/workspaces" }; + public override string[] ProjectedFieldNames => new[] { "subscriptionId", "resourceGroup", "type", "name" }; + + public override AzureResourceDefinition ParseResults(JToken resultRowEntry) + { + Guard.NotNull(resultRowEntry, nameof(resultRowEntry)); + + var resource = new SynapseWorkspaceResourceDefinition(resultRowEntry[0]?.ToString(), resultRowEntry[1]?.ToString(), resultRowEntry[3]?.ToString()); + return resource; + } + } +} diff --git a/src/Promitor.Agents.Scraper/Validation/Factories/MetricValidatorFactory.cs b/src/Promitor.Agents.Scraper/Validation/Factories/MetricValidatorFactory.cs index 68c5f5756..6c155770b 100644 --- a/src/Promitor.Agents.Scraper/Validation/Factories/MetricValidatorFactory.cs +++ b/src/Promitor.Agents.Scraper/Validation/Factories/MetricValidatorFactory.cs @@ -71,6 +71,12 @@ internal static IMetricValidator GetValidatorFor(ResourceType resourceType) return new StorageAccountMetricValidator(); case ResourceType.StorageQueue: return new StorageQueueMetricValidator(); + case ResourceType.SynapseApacheSparkPool: + return new SynapseApacheSparkPoolMetricValidator(); + case ResourceType.SynapseSqlPool: + return new SynapseSqlPoolMetricValidator(); + case ResourceType.SynapseWorkspace: + return new SynapseWorkspaceMetricValidator(); case ResourceType.VirtualMachineScaleSet: return new VirtualMachineScaleSetMetricValidator(); case ResourceType.VirtualMachine: diff --git a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/SynapseApacheSparkPoolMetricValidator.cs b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/SynapseApacheSparkPoolMetricValidator.cs new file mode 100644 index 000000000..7a5b71e3f --- /dev/null +++ b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/SynapseApacheSparkPoolMetricValidator.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Linq; +using GuardNet; +using Promitor.Core.Scraping.Configuration.Model.Metrics; +using Promitor.Agents.Scraper.Validation.MetricDefinitions.Interfaces; +using Promitor.Core.Contracts.ResourceTypes; + +namespace Promitor.Agents.Scraper.Validation.MetricDefinitions.ResourceTypes +{ + internal class SynapseApacheSparkPoolMetricValidator : IMetricValidator + { + public IEnumerable Validate(MetricDefinition metricDefinition) + { + Guard.NotNull(metricDefinition, nameof(metricDefinition)); + + foreach (var resourceDefinition in metricDefinition.Resources.Cast()) + { + if (string.IsNullOrWhiteSpace(resourceDefinition.WorkspaceName)) + { + yield return "No workspace name is configured"; + } + + if (string.IsNullOrWhiteSpace(resourceDefinition.PoolName)) + { + yield return "No pool name is configured"; + } + } + } + } +} \ No newline at end of file diff --git a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/SynapseSqlPoolMetricValidator.cs b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/SynapseSqlPoolMetricValidator.cs new file mode 100644 index 000000000..0a3cda476 --- /dev/null +++ b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/SynapseSqlPoolMetricValidator.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Linq; +using GuardNet; +using Promitor.Core.Scraping.Configuration.Model.Metrics; +using Promitor.Agents.Scraper.Validation.MetricDefinitions.Interfaces; +using Promitor.Core.Contracts.ResourceTypes; + +namespace Promitor.Agents.Scraper.Validation.MetricDefinitions.ResourceTypes +{ + internal class SynapseSqlPoolMetricValidator : IMetricValidator + { + public IEnumerable Validate(MetricDefinition metricDefinition) + { + Guard.NotNull(metricDefinition, nameof(metricDefinition)); + + foreach (var resourceDefinition in metricDefinition.Resources.Cast()) + { + if (string.IsNullOrWhiteSpace(resourceDefinition.WorkspaceName)) + { + yield return "No workspace name is configured"; + } + + if (string.IsNullOrWhiteSpace(resourceDefinition.PoolName)) + { + yield return "No pool name is configured"; + } + } + } + } +} \ No newline at end of file diff --git a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/SynapseWorkspaceMetricValidator.cs b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/SynapseWorkspaceMetricValidator.cs new file mode 100644 index 000000000..baf2ab19d --- /dev/null +++ b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/SynapseWorkspaceMetricValidator.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using System.Linq; +using GuardNet; +using Promitor.Core.Scraping.Configuration.Model.Metrics; +using Promitor.Agents.Scraper.Validation.MetricDefinitions.Interfaces; +using Promitor.Core.Contracts.ResourceTypes; + +namespace Promitor.Agents.Scraper.Validation.MetricDefinitions.ResourceTypes +{ + internal class SynapseWorkspaceMetricValidator : IMetricValidator + { + public IEnumerable Validate(MetricDefinition metricDefinition) + { + Guard.NotNull(metricDefinition, nameof(metricDefinition)); + + foreach (var resourceDefinition in metricDefinition.Resources.Cast()) + { + if (string.IsNullOrWhiteSpace(resourceDefinition.WorkspaceName)) + { + yield return "No workspace name is configured"; + } + } + } + } +} \ No newline at end of file diff --git a/src/Promitor.Core.Contracts/ResourceType.cs b/src/Promitor.Core.Contracts/ResourceType.cs index d788d86ff..489a84bca 100644 --- a/src/Promitor.Core.Contracts/ResourceType.cs +++ b/src/Promitor.Core.Contracts/ResourceType.cs @@ -35,6 +35,9 @@ public enum ResourceType KubernetesService = 30, AutomationAccount = 31, FrontDoor = 32, - SqlElasticPool = 33 + SqlElasticPool = 33, + SynapseApacheSparkPool = 34, + SynapseSqlPool = 35, + SynapseWorkspace = 36 } } \ No newline at end of file diff --git a/src/Promitor.Core.Contracts/ResourceTypes/SqlElasticPoolResourceDefinition.cs b/src/Promitor.Core.Contracts/ResourceTypes/SqlElasticPoolResourceDefinition.cs index 2f8e695a7..8e4efc641 100644 --- a/src/Promitor.Core.Contracts/ResourceTypes/SqlElasticPoolResourceDefinition.cs +++ b/src/Promitor.Core.Contracts/ResourceTypes/SqlElasticPoolResourceDefinition.cs @@ -1,7 +1,7 @@ namespace Promitor.Core.Contracts.ResourceTypes { /// - /// Represents an Azure Azure SQL Elastic Pool resource. + /// Represents an Azure SQL Elastic Pool resource. /// public class SqlElasticPoolResourceDefinition : AzureResourceDefinition { diff --git a/src/Promitor.Core.Contracts/ResourceTypes/SynapseApacheSparkPoolResourceDefinition.cs b/src/Promitor.Core.Contracts/ResourceTypes/SynapseApacheSparkPoolResourceDefinition.cs new file mode 100644 index 000000000..1caaa42f4 --- /dev/null +++ b/src/Promitor.Core.Contracts/ResourceTypes/SynapseApacheSparkPoolResourceDefinition.cs @@ -0,0 +1,32 @@ +namespace Promitor.Core.Contracts.ResourceTypes +{ + /// + /// Represents a Apache Spark pool in an Azure Synapse workspace. + /// + public class SynapseApacheSparkPoolResourceDefinition : AzureResourceDefinition + { + /// + /// Initializes a new instance of the class. + /// + /// Specify a subscription to scrape that defers from the default subscription. + /// The name of the resource group the server is in. + /// The name of the Azure Synapse workspace. + /// The name of the Apache Spark pool inside the Synapse workspace. + public SynapseApacheSparkPoolResourceDefinition(string subscriptionId, string resourceGroupName, string workspaceName, string poolName) + : base(ResourceType.SynapseApacheSparkPool, subscriptionId, resourceGroupName, poolName, $"{workspaceName}-{poolName}") + { + WorkspaceName = workspaceName; + PoolName = poolName; + } + + /// + /// The name of the Azure Synapse workspace. + /// + public string WorkspaceName { get; } + + /// + /// The name of the Apache Spark pool inside the Synapse workspace. + /// + public string PoolName { get; } + } +} \ No newline at end of file diff --git a/src/Promitor.Core.Contracts/ResourceTypes/SynapseSqlPoolResourceDefinition.cs b/src/Promitor.Core.Contracts/ResourceTypes/SynapseSqlPoolResourceDefinition.cs new file mode 100644 index 000000000..b6aa15030 --- /dev/null +++ b/src/Promitor.Core.Contracts/ResourceTypes/SynapseSqlPoolResourceDefinition.cs @@ -0,0 +1,32 @@ +namespace Promitor.Core.Contracts.ResourceTypes +{ + /// + /// Represents a SQL pool in an Azure Synapse workspace. + /// + public class SynapseSqlPoolResourceDefinition : AzureResourceDefinition + { + /// + /// Initializes a new instance of the class. + /// + /// Specify a subscription to scrape that defers from the default subscription. + /// The name of the resource group the server is in. + /// The name of the Azure Synapse workspace. + /// The name of the SQL pool inside the Synapse workspace. + public SynapseSqlPoolResourceDefinition(string subscriptionId, string resourceGroupName, string workspaceName, string poolName) + : base(ResourceType.SynapseSqlPool, subscriptionId, resourceGroupName, poolName, $"{workspaceName}-{poolName}") + { + WorkspaceName = workspaceName; + PoolName = poolName; + } + + /// + /// The name of the Azure Synapse workspace. + /// + public string WorkspaceName { get; } + + /// + /// The name of the SQL pool inside the Synapse workspace. + /// + public string PoolName { get; } + } +} \ No newline at end of file diff --git a/src/Promitor.Core.Contracts/ResourceTypes/SynapseWorkspaceResourceDefinition.cs b/src/Promitor.Core.Contracts/ResourceTypes/SynapseWorkspaceResourceDefinition.cs new file mode 100644 index 000000000..f771bf07f --- /dev/null +++ b/src/Promitor.Core.Contracts/ResourceTypes/SynapseWorkspaceResourceDefinition.cs @@ -0,0 +1,25 @@ +namespace Promitor.Core.Contracts.ResourceTypes +{ + /// + /// Represents an Azure Synapse workspace. + /// + public class SynapseWorkspaceResourceDefinition : AzureResourceDefinition + { + /// + /// Initializes a new instance of the class. + /// + /// Specify a subscription to scrape that defers from the default subscription. + /// The name of the resource group the server is in. + /// The name of the Azure Synapse workspace. + public SynapseWorkspaceResourceDefinition(string subscriptionId, string resourceGroupName, string workspaceName) + : base(ResourceType.SynapseWorkspace, subscriptionId, resourceGroupName, workspaceName) + { + WorkspaceName = workspaceName; + } + + /// + /// The name of the Azure Synapse workspace. + /// + public string WorkspaceName { get; } + } +} \ No newline at end of file diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/ConfigurationSerializer.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/ConfigurationSerializer.cs index f5e859df4..4abf8ea26 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/ConfigurationSerializer.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/ConfigurationSerializer.cs @@ -53,7 +53,7 @@ private MetricsDeclaration InterpretYamlStream(YamlStream metricsDeclarationYaml var rootNode = (YamlMappingNode)document.RootNode; var specVersion = DetermineDeclarationSpecVersion(rootNode); - _logger.LogInformation("Metrics declaration is using spec version {SpecVersion}", specVersion); + _logger.LogTrace("Metrics declaration is using spec version {SpecVersion}", specVersion); switch (specVersion) { diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureResourceDeserializerFactory.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureResourceDeserializerFactory.cs index cb750f58c..9b6883af3 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureResourceDeserializerFactory.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureResourceDeserializerFactory.cs @@ -111,6 +111,15 @@ public IDeserializer GetDeserializerFor(ResourceType case ResourceType.StorageQueue: var storageQueueLogger = _loggerFactory.CreateLogger(); return new StorageQueueDeserializer(_secretDeserializer, storageQueueLogger); + case ResourceType.SynapseApacheSparkPool: + var synapseApacheSparkPoolLogger = _loggerFactory.CreateLogger(); + return new SynapseApacheSparkPoolDeserializer(synapseApacheSparkPoolLogger); + case ResourceType.SynapseSqlPool: + var synapseSqlPoolLogger = _loggerFactory.CreateLogger(); + return new SynapseSqlPoolDeserializer(synapseSqlPoolLogger); + case ResourceType.SynapseWorkspace: + var synapseWorkspaceLogger = _loggerFactory.CreateLogger(); + return new SynapseWorkspaceDeserializer(synapseWorkspaceLogger); case ResourceType.VirtualMachine: var virtualMachineLogger = _loggerFactory.CreateLogger(); return new VirtualMachineDeserializer(virtualMachineLogger); diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Mapping/V1MappingProfile.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Mapping/V1MappingProfile.cs index b3156bdb2..ff457a431 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Mapping/V1MappingProfile.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Mapping/V1MappingProfile.cs @@ -53,6 +53,9 @@ public V1MappingProfile() CreateMap(); CreateMap(); CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); CreateMap(); CreateMap(); CreateMap(); @@ -93,6 +96,9 @@ public V1MappingProfile() .Include() .Include() .Include() + .Include() + .Include() + .Include() .Include() .Include() .Include(); diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/ResourceTypes/SynapseApacheSparkPoolResourceV1.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/ResourceTypes/SynapseApacheSparkPoolResourceV1.cs new file mode 100644 index 000000000..96453adbd --- /dev/null +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/ResourceTypes/SynapseApacheSparkPoolResourceV1.cs @@ -0,0 +1,28 @@ +namespace Promitor.Core.Scraping.Configuration.Serialization.v1.Model.ResourceTypes +{ + /// + /// Represents an Apache Spark pool in an Azure Synapse workspace. + /// + public class SynapseApacheSparkPoolResourceV1 : AzureResourceDefinitionV1 + { + public SynapseApacheSparkPoolResourceV1() + { + } + + public SynapseApacheSparkPoolResourceV1(string workspaceName, string poolName) + { + WorkspaceName = workspaceName; + PoolName = poolName; + } + + /// + /// The name of the Azure Synapse workspace. + /// + public string WorkspaceName { get; set; } + + /// + /// The name of the Apache Spark pool inside the Synapse workspace. + /// + public string PoolName { get; set; } + } +} \ No newline at end of file diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/ResourceTypes/SynapseSqlPoolResourceV1.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/ResourceTypes/SynapseSqlPoolResourceV1.cs new file mode 100644 index 000000000..24574907d --- /dev/null +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/ResourceTypes/SynapseSqlPoolResourceV1.cs @@ -0,0 +1,28 @@ +namespace Promitor.Core.Scraping.Configuration.Serialization.v1.Model.ResourceTypes +{ + /// + /// Represents an SQL pool in an Azure Synapse workspace. + /// + public class SynapseSqlPoolResourceV1 : AzureResourceDefinitionV1 + { + public SynapseSqlPoolResourceV1() + { + } + + public SynapseSqlPoolResourceV1(string workspaceName, string poolName) + { + WorkspaceName = workspaceName; + PoolName = poolName; + } + + /// + /// The name of the Azure Synapse workspace. + /// + public string WorkspaceName { get; set; } + + /// + /// The name of the SQL pool inside the Synapse workspace. + /// + public string PoolName { get; set; } + } +} \ No newline at end of file diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/ResourceTypes/SynapseWorkspaceResourceV1.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/ResourceTypes/SynapseWorkspaceResourceV1.cs new file mode 100644 index 000000000..175808220 --- /dev/null +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/ResourceTypes/SynapseWorkspaceResourceV1.cs @@ -0,0 +1,22 @@ +namespace Promitor.Core.Scraping.Configuration.Serialization.v1.Model.ResourceTypes +{ + /// + /// Represents an Azure Synapse workspace. + /// + public class SynapseWorkspaceResourceV1 : AzureResourceDefinitionV1 + { + public SynapseWorkspaceResourceV1() + { + } + + public SynapseWorkspaceResourceV1(string workspaceName) + { + WorkspaceName = workspaceName; + } + + /// + /// The name of the Azure Synapse workspace. + /// + public string WorkspaceName { get; set; } + } +} \ No newline at end of file diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Providers/SynapseApacheSparkPoolDeserializer.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Providers/SynapseApacheSparkPoolDeserializer.cs new file mode 100644 index 000000000..deffaf76a --- /dev/null +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Providers/SynapseApacheSparkPoolDeserializer.cs @@ -0,0 +1,16 @@ +using Microsoft.Extensions.Logging; +using Promitor.Core.Scraping.Configuration.Serialization.v1.Model.ResourceTypes; + +namespace Promitor.Core.Scraping.Configuration.Serialization.v1.Providers +{ + public class SynapseApacheSparkPoolDeserializer : ResourceDeserializer + { + public SynapseApacheSparkPoolDeserializer(ILogger logger) : base(logger) + { + Map(resource => resource.WorkspaceName) + .IsRequired(); + Map(resource => resource.PoolName) + .IsRequired(); + } + } +} \ No newline at end of file diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Providers/SynapseSqlPoolDeserializer.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Providers/SynapseSqlPoolDeserializer.cs new file mode 100644 index 000000000..b0c41a9be --- /dev/null +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Providers/SynapseSqlPoolDeserializer.cs @@ -0,0 +1,16 @@ +using Microsoft.Extensions.Logging; +using Promitor.Core.Scraping.Configuration.Serialization.v1.Model.ResourceTypes; + +namespace Promitor.Core.Scraping.Configuration.Serialization.v1.Providers +{ + public class SynapseSqlPoolDeserializer : ResourceDeserializer + { + public SynapseSqlPoolDeserializer(ILogger logger) : base(logger) + { + Map(resource => resource.WorkspaceName) + .IsRequired(); + Map(resource => resource.PoolName) + .IsRequired(); + } + } +} \ No newline at end of file diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Providers/SynapseWorkspaceDeserializer.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Providers/SynapseWorkspaceDeserializer.cs new file mode 100644 index 000000000..45f7c845b --- /dev/null +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Providers/SynapseWorkspaceDeserializer.cs @@ -0,0 +1,14 @@ +using Microsoft.Extensions.Logging; +using Promitor.Core.Scraping.Configuration.Serialization.v1.Model.ResourceTypes; + +namespace Promitor.Core.Scraping.Configuration.Serialization.v1.Providers +{ + public class SynapseWorkspaceDeserializer : ResourceDeserializer + { + public SynapseWorkspaceDeserializer(ILogger logger) : base(logger) + { + Map(resource => resource.WorkspaceName) + .IsRequired(); + } + } +} \ No newline at end of file diff --git a/src/Promitor.Core.Scraping/Factories/MetricScraperFactory.cs b/src/Promitor.Core.Scraping/Factories/MetricScraperFactory.cs index 60111704f..1eec66eca 100644 --- a/src/Promitor.Core.Scraping/Factories/MetricScraperFactory.cs +++ b/src/Promitor.Core.Scraping/Factories/MetricScraperFactory.cs @@ -92,6 +92,12 @@ public IScraper CreateScraper(ResourceType metricDefin return new StorageAccountScraper(scraperConfiguration); case ResourceType.StorageQueue: return new StorageQueueScraper(scraperConfiguration); + case ResourceType.SynapseApacheSparkPool: + return new SynapseApacheSparkPoolScraper(scraperConfiguration); + case ResourceType.SynapseSqlPool: + return new SynapseSqlPoolScraper(scraperConfiguration); + case ResourceType.SynapseWorkspace: + return new SynapseWorkspaceScraper(scraperConfiguration); case ResourceType.VirtualMachine: return new VirtualMachineScraper(scraperConfiguration); case ResourceType.VirtualMachineScaleSet: diff --git a/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs b/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs index c40f0cab5..704d90317 100644 --- a/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs +++ b/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs @@ -47,7 +47,7 @@ protected override string DetermineMetricDimension(TResourceDefinition resourceD return base.DetermineMetricDimension(resourceDefinition, dimension); } - Logger.LogWarning("Using 'EntityName' dimension since no topic was configured."); + Logger.LogTrace("Using 'EntityName' dimension since no topic was configured."); return "EntityName"; } diff --git a/src/Promitor.Core.Scraping/ResourceTypes/SynapseApacheSparkPoolScraper.cs b/src/Promitor.Core.Scraping/ResourceTypes/SynapseApacheSparkPoolScraper.cs new file mode 100644 index 000000000..8c7d0dacf --- /dev/null +++ b/src/Promitor.Core.Scraping/ResourceTypes/SynapseApacheSparkPoolScraper.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using Promitor.Core.Contracts; +using Promitor.Core.Contracts.ResourceTypes; +using Promitor.Core.Scraping.Configuration.Model.Metrics; + +namespace Promitor.Core.Scraping.ResourceTypes +{ + /// + /// Scrapes an Apache Spark pool in an Azure Synapse workspace. + /// + public class SynapseApacheSparkPoolScraper : AzureMonitorScraper + { + private const string ResourceUriTemplate = "subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Synapse/workspaces/{2}/bigDataPools/{3}"; + + public SynapseApacheSparkPoolScraper(ScraperConfiguration scraperConfiguration) + : base(scraperConfiguration) + { + } + + protected override string BuildResourceUri(string subscriptionId, ScrapeDefinition scrapeDefinition, SynapseApacheSparkPoolResourceDefinition resource) + { + return string.Format(ResourceUriTemplate, subscriptionId, scrapeDefinition.ResourceGroupName, resource.WorkspaceName, resource.PoolName); + } + + protected override Dictionary DetermineMetricLabels(SynapseApacheSparkPoolResourceDefinition resourceDefinition) + { + var metricLabels = base.DetermineMetricLabels(resourceDefinition); + + metricLabels.TryAdd("workspace_name", resourceDefinition.WorkspaceName); + metricLabels.TryAdd("pool_name", resourceDefinition.PoolName); + + return metricLabels; + } + } +} \ No newline at end of file diff --git a/src/Promitor.Core.Scraping/ResourceTypes/SynapseSqlPoolScraper.cs b/src/Promitor.Core.Scraping/ResourceTypes/SynapseSqlPoolScraper.cs new file mode 100644 index 000000000..da5424788 --- /dev/null +++ b/src/Promitor.Core.Scraping/ResourceTypes/SynapseSqlPoolScraper.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using Promitor.Core.Contracts; +using Promitor.Core.Contracts.ResourceTypes; +using Promitor.Core.Scraping.Configuration.Model.Metrics; + +namespace Promitor.Core.Scraping.ResourceTypes +{ + /// + /// Scrapes an SQL pool in an Azure Synapse workspace. + /// + public class SynapseSqlPoolScraper : AzureMonitorScraper + { + private const string ResourceUriTemplate = "subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Synapse/workspaces/{2}/sqlPools/{3}"; + + public SynapseSqlPoolScraper(ScraperConfiguration scraperConfiguration) + : base(scraperConfiguration) + { + } + + protected override string BuildResourceUri(string subscriptionId, ScrapeDefinition scrapeDefinition, SynapseSqlPoolResourceDefinition resource) + { + return string.Format(ResourceUriTemplate, subscriptionId, scrapeDefinition.ResourceGroupName, resource.WorkspaceName, resource.PoolName); + } + + protected override Dictionary DetermineMetricLabels(SynapseSqlPoolResourceDefinition resourceDefinition) + { + var metricLabels = base.DetermineMetricLabels(resourceDefinition); + + metricLabels.TryAdd("workspace_name", resourceDefinition.WorkspaceName); + metricLabels.TryAdd("pool_name", resourceDefinition.PoolName); + + return metricLabels; + } + } +} \ No newline at end of file diff --git a/src/Promitor.Core.Scraping/ResourceTypes/SynapseWorkspaceScraper.cs b/src/Promitor.Core.Scraping/ResourceTypes/SynapseWorkspaceScraper.cs new file mode 100644 index 000000000..cca7ac3b7 --- /dev/null +++ b/src/Promitor.Core.Scraping/ResourceTypes/SynapseWorkspaceScraper.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using Promitor.Core.Contracts; +using Promitor.Core.Contracts.ResourceTypes; +using Promitor.Core.Scraping.Configuration.Model.Metrics; + +namespace Promitor.Core.Scraping.ResourceTypes +{ + /// + /// Scrapes an Azure Synapse workspace. + /// + public class SynapseWorkspaceScraper : AzureMonitorScraper + { + private const string ResourceUriTemplate = "subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Synapse/workspaces/{2}"; + + public SynapseWorkspaceScraper(ScraperConfiguration scraperConfiguration) + : base(scraperConfiguration) + { + } + + protected override string BuildResourceUri(string subscriptionId, ScrapeDefinition scrapeDefinition, SynapseWorkspaceResourceDefinition resource) + { + return string.Format(ResourceUriTemplate, subscriptionId, scrapeDefinition.ResourceGroupName, resource.WorkspaceName); + } + + protected override Dictionary DetermineMetricLabels(SynapseWorkspaceResourceDefinition resourceDefinition) + { + var metricLabels = base.DetermineMetricLabels(resourceDefinition); + + metricLabels.TryAdd("workspace_name", resourceDefinition.WorkspaceName); + + return metricLabels; + } + } +} \ No newline at end of file diff --git a/src/Promitor.Tests.Unit/Builders/Metrics/v1/MetricsDeclarationBuilder.cs b/src/Promitor.Tests.Unit/Builders/Metrics/v1/MetricsDeclarationBuilder.cs index cdfa2cdd3..e5fdcde0f 100644 --- a/src/Promitor.Tests.Unit/Builders/Metrics/v1/MetricsDeclarationBuilder.cs +++ b/src/Promitor.Tests.Unit/Builders/Metrics/v1/MetricsDeclarationBuilder.cs @@ -615,6 +615,64 @@ public MetricsDeclarationBuilder WithSqlManagedInstanceMetric( return this; } + public MetricsDeclarationBuilder WithSynapseApacheSparkPoolMetric( + string metricName = "promitor-sql-db", + string azureMetricName = "cpu_percent", + string workspaceName = "promitor-synapse-workspace", + string poolName = "promitor-synapse-apache-spark-pool", + string metricDescription = "Metric description", + string resourceDiscoveryGroupName = "", + bool omitResource = false) + { + var resource = new SynapseApacheSparkPoolResourceV1 + { + WorkspaceName = workspaceName, + PoolName = poolName + }; + + CreateAndAddMetricDefinition(ResourceType.SynapseApacheSparkPool, metricName, metricDescription, resourceDiscoveryGroupName, omitResource, azureMetricName, resource); + + return this; + } + + public MetricsDeclarationBuilder WithSynapseSqlPoolMetric( + string metricName = "promitor-sql-db", + string azureMetricName = "cpu_percent", + string workspaceName = "promitor-synapse-workspace", + string poolName = "promitor-synapse-sql-pool", + string metricDescription = "Metric description", + string resourceDiscoveryGroupName = "", + bool omitResource = false) + { + var resource = new SynapseSqlPoolResourceV1 + { + WorkspaceName = workspaceName, + PoolName = poolName + }; + + CreateAndAddMetricDefinition(ResourceType.SynapseSqlPool, metricName, metricDescription, resourceDiscoveryGroupName, omitResource, azureMetricName, resource); + + return this; + } + + public MetricsDeclarationBuilder WithSynapseWorkspaceMetric( + string metricName = "promitor-sql-db", + string azureMetricName = "cpu_percent", + string workspaceName = "promitor-synapse-workspace", + string metricDescription = "Metric description", + string resourceDiscoveryGroupName = "", + bool omitResource = false) + { + var resource = new SynapseWorkspaceResourceV1 + { + WorkspaceName = workspaceName + }; + + CreateAndAddMetricDefinition(ResourceType.SynapseWorkspace, metricName, metricDescription, resourceDiscoveryGroupName, omitResource, azureMetricName, resource); + + return this; + } + public MetricsDeclarationBuilder WithIoTHubMetric(string metricName = "promitor-iot-hub", string metricDescription = "Description for a metric", string iotHubName = "promitor-iot-hub", diff --git a/src/Promitor.Tests.Unit/Discovery/Query/SqlDatabaseResourceDiscoveryQueryUnitTest.cs b/src/Promitor.Tests.Unit/Discovery/Query/SqlDatabaseResourceDiscoveryQueryUnitTest.cs index 16fcc20f5..001e5ca6f 100644 --- a/src/Promitor.Tests.Unit/Discovery/Query/SqlDatabaseResourceDiscoveryQueryUnitTest.cs +++ b/src/Promitor.Tests.Unit/Discovery/Query/SqlDatabaseResourceDiscoveryQueryUnitTest.cs @@ -12,7 +12,7 @@ public class SqlDatabaseResourceDiscoveryQueryUnitTest private readonly Faker _faker = new Faker(); [Fact] - public void GetServerNameFromResourceUri_ValidResourceUri_GetsServerName() + public void GetParentResourceNameFromResourceUri_ValidResourceUri_GetsServerName() { // Arrange var serverName = _faker.Name.FirstName(); @@ -20,14 +20,14 @@ public void GetServerNameFromResourceUri_ValidResourceUri_GetsServerName() var sqlDatabaseDiscoveryQuery = new SqlDatabaseDiscoveryQuery(); // Act - var foundServerName = sqlDatabaseDiscoveryQuery.GetServerNameFromResourceUri(resourceUri); + var foundServerName = sqlDatabaseDiscoveryQuery.GetParentResourceNameFromResourceUri(SqlDatabaseDiscoveryQuery.ServerSectionInResourceUri, resourceUri); // Assert Assert.Equal(serverName, foundServerName); } [Fact] - public void GetServerNameFromResourceUri_NoResourceUri_ThrowsArgumentException() + public void GetParentResourceNameFromResourceUri_NoResourceUri_ThrowsArgumentException() { // Arrange string resourceUri = null; @@ -35,18 +35,18 @@ public void GetServerNameFromResourceUri_NoResourceUri_ThrowsArgumentException() // Act & Assert // ReSharper disable once ExpressionIsAlwaysNull - Assert.Throws(() => sqlDatabaseDiscoveryQuery.GetServerNameFromResourceUri(resourceUri)); + Assert.Throws(() => sqlDatabaseDiscoveryQuery.GetParentResourceNameFromResourceUri(SqlDatabaseDiscoveryQuery.ServerSectionInResourceUri, resourceUri)); } [Fact] - public void GetServerNameFromResourceUri_EmptyResourceUri_ThrowsArgumentException() + public void GetParentResourceNameFromResourceUri_EmptyResourceUri_ThrowsArgumentException() { // Arrange var resourceUri = string.Empty; var sqlDatabaseDiscoveryQuery = new SqlDatabaseDiscoveryQuery(); // Act & Assert - Assert.Throws(() => sqlDatabaseDiscoveryQuery.GetServerNameFromResourceUri(resourceUri)); + Assert.Throws(() => sqlDatabaseDiscoveryQuery.GetParentResourceNameFromResourceUri(SqlDatabaseDiscoveryQuery.ServerSectionInResourceUri, resourceUri)); } } } diff --git a/src/Promitor.Tests.Unit/Discovery/Query/SqlElasticPoolDiscoveryQueryUnitTest.cs b/src/Promitor.Tests.Unit/Discovery/Query/SqlElasticPoolDiscoveryQueryUnitTest.cs new file mode 100644 index 000000000..8854fdfd2 --- /dev/null +++ b/src/Promitor.Tests.Unit/Discovery/Query/SqlElasticPoolDiscoveryQueryUnitTest.cs @@ -0,0 +1,52 @@ +using System; +using System.ComponentModel; +using Bogus; +using Promitor.Agents.ResourceDiscovery.Graph.ResourceTypes; +using Xunit; + +namespace Promitor.Tests.Unit.Discovery.Query +{ + [Category("Unit")] + public class SqlElasticPoolDiscoveryQueryUnitTest + { + private readonly Faker _faker = new Faker(); + + [Fact] + public void GetParentResourceNameFromResourceUri_ValidResourceUri_GetsServerName() + { + // Arrange + var serverName = _faker.Name.FirstName(); + var resourceUri = $"/subscriptions/0f9d7fea-99e8-4768-8672-06a28514f77e/resourceGroups/promitor/providers/Microsoft.Sql/servers/{serverName}/elasticpools/promitor-pool"; + var elasticPoolDiscoveryQuery = new SqlElasticPoolDiscoveryQuery(); + + // Act + var foundServerName = elasticPoolDiscoveryQuery.GetParentResourceNameFromResourceUri(SqlElasticPoolDiscoveryQuery.ServerSectionInResourceUri, resourceUri); + + // Assert + Assert.Equal(serverName, foundServerName); + } + + [Fact] + public void GetParentResourceNameFromResourceUri_NoResourceUri_ThrowsArgumentException() + { + // Arrange + string resourceUri = null; + var elasticPoolDiscoveryQuery = new SqlElasticPoolDiscoveryQuery(); + + // Act & Assert + // ReSharper disable once ExpressionIsAlwaysNull + Assert.Throws(() => elasticPoolDiscoveryQuery.GetParentResourceNameFromResourceUri(SqlElasticPoolDiscoveryQuery.ServerSectionInResourceUri, resourceUri)); + } + + [Fact] + public void GetParentResourceNameFromResourceUri_EmptyResourceUri_ThrowsArgumentException() + { + // Arrange + var resourceUri = string.Empty; + var elasticPoolDiscoveryQuery = new SqlElasticPoolDiscoveryQuery(); + + // Act & Assert + Assert.Throws(() => elasticPoolDiscoveryQuery.GetParentResourceNameFromResourceUri(SqlElasticPoolDiscoveryQuery.ServerSectionInResourceUri, resourceUri)); + } + } +} diff --git a/src/Promitor.Tests.Unit/Discovery/Query/SynapseApacheSparkPoolDiscoveryQueryUnitTest.cs b/src/Promitor.Tests.Unit/Discovery/Query/SynapseApacheSparkPoolDiscoveryQueryUnitTest.cs new file mode 100644 index 000000000..37531fbab --- /dev/null +++ b/src/Promitor.Tests.Unit/Discovery/Query/SynapseApacheSparkPoolDiscoveryQueryUnitTest.cs @@ -0,0 +1,52 @@ +using System; +using System.ComponentModel; +using Bogus; +using Promitor.Agents.ResourceDiscovery.Graph.ResourceTypes; +using Xunit; + +namespace Promitor.Tests.Unit.Discovery.Query +{ + [Category("Unit")] + public class SynapseApacheSparkPoolDiscoveryQueryUnitTest + { + private readonly Faker _faker = new Faker(); + + [Fact] + public void GetParentResourceNameFromResourceUri_ValidResourceUri_GetsServerName() + { + // Arrange + var workspaceName = _faker.Name.FirstName(); + var resourceUri = $"/subscriptions/0f9d7fea-99e8-4768-8672-06a28514f77e/resourceGroups/promitor-sources/providers/Microsoft.Synapse/workspaces/{workspaceName}/bigDataPools/sparkpool"; + var apacheSparkPoolDiscoveryQuery = new SynapseApacheSparkPoolDiscoveryQuery(); + + // Act + var foundWorkspaceName = apacheSparkPoolDiscoveryQuery.GetParentResourceNameFromResourceUri(SynapseApacheSparkPoolDiscoveryQuery.WorkspaceSectionInResourceUri, resourceUri); + + // Assert + Assert.Equal(workspaceName, foundWorkspaceName); + } + + [Fact] + public void GetParentResourceNameFromResourceUri_NoResourceUri_ThrowsArgumentException() + { + // Arrange + string resourceUri = null; + var apacheSparkPoolDiscoveryQuery = new SynapseApacheSparkPoolDiscoveryQuery(); + + // Act & Assert + // ReSharper disable once ExpressionIsAlwaysNull + Assert.Throws(() => apacheSparkPoolDiscoveryQuery.GetParentResourceNameFromResourceUri(SynapseApacheSparkPoolDiscoveryQuery.WorkspaceSectionInResourceUri, resourceUri)); + } + + [Fact] + public void GetParentResourceNameFromResourceUri_EmptyResourceUri_ThrowsArgumentException() + { + // Arrange + var resourceUri = string.Empty; + var apacheSparkPoolDiscoveryQuery = new SynapseApacheSparkPoolDiscoveryQuery(); + + // Act & Assert + Assert.Throws(() => apacheSparkPoolDiscoveryQuery.GetParentResourceNameFromResourceUri(SynapseApacheSparkPoolDiscoveryQuery.WorkspaceSectionInResourceUri, resourceUri)); + } + } +} diff --git a/src/Promitor.Tests.Unit/Discovery/Query/SynapseSqlPoolDiscoveryQueryUnitTest.cs b/src/Promitor.Tests.Unit/Discovery/Query/SynapseSqlPoolDiscoveryQueryUnitTest.cs new file mode 100644 index 000000000..f6393ab6c --- /dev/null +++ b/src/Promitor.Tests.Unit/Discovery/Query/SynapseSqlPoolDiscoveryQueryUnitTest.cs @@ -0,0 +1,52 @@ +using System; +using System.ComponentModel; +using Bogus; +using Promitor.Agents.ResourceDiscovery.Graph.ResourceTypes; +using Xunit; + +namespace Promitor.Tests.Unit.Discovery.Query +{ + [Category("Unit")] + public class SynapseSqlPoolDiscoveryQueryUnitTest + { + private readonly Faker _faker = new Faker(); + + [Fact] + public void GetParentResourceNameFromResourceUri_ValidResourceUri_GetsServerName() + { + // Arrange + var workspaceName = _faker.Name.FirstName(); + var resourceUri = $"/subscriptions/0f9d7fea-99e8-4768-8672-06a28514f77e/resourceGroups/promitor-sources/providers/Microsoft.Synapse/workspaces/{workspaceName}/sqlPools/sqlpool"; + var sqlPoolDiscoveryQuery = new SynapseSqlPoolDiscoveryQuery(); + + // Act + var foundWorkspaceName = sqlPoolDiscoveryQuery.GetParentResourceNameFromResourceUri(SynapseSqlPoolDiscoveryQuery.WorkspaceSectionInResourceUri, resourceUri); + + // Assert + Assert.Equal(workspaceName, foundWorkspaceName); + } + + [Fact] + public void GetParentResourceNameFromResourceUri_NoResourceUri_ThrowsArgumentException() + { + // Arrange + string resourceUri = null; + var sqlPoolDiscoveryQuery = new SynapseSqlPoolDiscoveryQuery(); + + // Act & Assert + // ReSharper disable once ExpressionIsAlwaysNull + Assert.Throws(() => sqlPoolDiscoveryQuery.GetParentResourceNameFromResourceUri(SynapseSqlPoolDiscoveryQuery.WorkspaceSectionInResourceUri, resourceUri)); + } + + [Fact] + public void GetParentResourceNameFromResourceUri_EmptyResourceUri_ThrowsArgumentException() + { + // Arrange + var resourceUri = string.Empty; + var sqlPoolDiscoveryQuery = new SynapseSqlPoolDiscoveryQuery(); + + // Act & Assert + Assert.Throws(() => sqlPoolDiscoveryQuery.GetParentResourceNameFromResourceUri(SynapseSqlPoolDiscoveryQuery.WorkspaceSectionInResourceUri, resourceUri)); + } + } +} diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseApacheSparkPoolDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseApacheSparkPoolDeserializerTests.cs new file mode 100644 index 000000000..92c2b0d10 --- /dev/null +++ b/src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseApacheSparkPoolDeserializerTests.cs @@ -0,0 +1,87 @@ +using System.ComponentModel; +using Microsoft.Extensions.Logging.Abstractions; +using Promitor.Core.Scraping.Configuration.Serialization; +using Promitor.Core.Scraping.Configuration.Serialization.v1.Model; +using Promitor.Core.Scraping.Configuration.Serialization.v1.Model.ResourceTypes; +using Promitor.Core.Scraping.Configuration.Serialization.v1.Providers; +using Xunit; + +namespace Promitor.Tests.Unit.Serialization.v1.Providers +{ + [Category("Unit")] + public class SynapseApacheSparkPoolDeserializerTests : ResourceDeserializerTest + { + private readonly SynapseApacheSparkPoolDeserializer _deserializer = new SynapseApacheSparkPoolDeserializer(NullLogger.Instance); + + [Fact] + public void Deserialize_PoolNameSupplied_SetsPoolName() + { + const string expectedPoolName = "promitor-synapse-spark-pool"; + YamlAssert.PropertySet( + _deserializer, + $"poolName: {expectedPoolName}", + expectedPoolName, + c => c.PoolName); + } + + [Fact] + public void Deserialize_PoolNameNotSupplied_Null() + { + YamlAssert.PropertyNull( + _deserializer, + "resourceGroupName: promitor-group", + c => c.PoolName); + } + + [Fact] + public void Deserialize_WorkspaceNameSupplied_SetsWorkspace() + { + const string expectedWorkspaceName = "promitor-synapse-workspace"; + YamlAssert.PropertySet( + _deserializer, + $"workspaceName: {expectedWorkspaceName}", + expectedWorkspaceName, + c => c.WorkspaceName); + } + + [Fact] + public void Deserialize_WorkspaceNameNotSupplied_Null() + { + YamlAssert.PropertyNull( + _deserializer, + "resourceGroupName: promitor-group", + c => c.WorkspaceName); + } + + [Fact] + public void Deserialize_PoolNameNotSupplied_ReportsError() + { + // Arrange + var node = YamlUtils.CreateYamlNode("resourceGroupName: promitor-resource-group"); + + // Act / Assert + YamlAssert.ReportsErrorForProperty( + _deserializer, + node, + "poolName"); + } + + [Fact] + public void Deserialize_WorkspaceNameNotSupplied_ReportsError() + { + // Arrange + var node = YamlUtils.CreateYamlNode("resourceGroupName: promitor-resource-group"); + + // Act / Assert + YamlAssert.ReportsErrorForProperty( + _deserializer, + node, + "workspaceName"); + } + + protected override IDeserializer CreateDeserializer() + { + return new SynapseApacheSparkPoolDeserializer(NullLogger.Instance); + } + } +} \ No newline at end of file diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseSqlPoolDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseSqlPoolDeserializerTests.cs new file mode 100644 index 000000000..aeb118b46 --- /dev/null +++ b/src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseSqlPoolDeserializerTests.cs @@ -0,0 +1,87 @@ +using System.ComponentModel; +using Microsoft.Extensions.Logging.Abstractions; +using Promitor.Core.Scraping.Configuration.Serialization; +using Promitor.Core.Scraping.Configuration.Serialization.v1.Model; +using Promitor.Core.Scraping.Configuration.Serialization.v1.Model.ResourceTypes; +using Promitor.Core.Scraping.Configuration.Serialization.v1.Providers; +using Xunit; + +namespace Promitor.Tests.Unit.Serialization.v1.Providers +{ + [Category("Unit")] + public class SynapseSqlPoolDeserializerTests : ResourceDeserializerTest + { + private readonly SynapseSqlPoolDeserializer _deserializer = new SynapseSqlPoolDeserializer(NullLogger.Instance); + + [Fact] + public void Deserialize_PoolNameSupplied_SetsPoolName() + { + const string expectedPoolName = "promitor-synapse-sql-pool"; + YamlAssert.PropertySet( + _deserializer, + $"poolName: {expectedPoolName}", + expectedPoolName, + c => c.PoolName); + } + + [Fact] + public void Deserialize_PoolNameNotSupplied_Null() + { + YamlAssert.PropertyNull( + _deserializer, + "resourceGroupName: promitor-group", + c => c.PoolName); + } + + [Fact] + public void Deserialize_WorkspaceNameSupplied_SetsWorkspace() + { + const string expectedWorkspaceName = "promitor-synapse-workspace"; + YamlAssert.PropertySet( + _deserializer, + $"workspaceName: {expectedWorkspaceName}", + expectedWorkspaceName, + c => c.WorkspaceName); + } + + [Fact] + public void Deserialize_WorkspaceNameNotSupplied_Null() + { + YamlAssert.PropertyNull( + _deserializer, + "resourceGroupName: promitor-group", + c => c.WorkspaceName); + } + + [Fact] + public void Deserialize_PoolNameNotSupplied_ReportsError() + { + // Arrange + var node = YamlUtils.CreateYamlNode("resourceGroupName: promitor-resource-group"); + + // Act / Assert + YamlAssert.ReportsErrorForProperty( + _deserializer, + node, + "poolName"); + } + + [Fact] + public void Deserialize_WorkspaceNameNotSupplied_ReportsError() + { + // Arrange + var node = YamlUtils.CreateYamlNode("resourceGroupName: promitor-resource-group"); + + // Act / Assert + YamlAssert.ReportsErrorForProperty( + _deserializer, + node, + "workspaceName"); + } + + protected override IDeserializer CreateDeserializer() + { + return new SynapseSqlPoolDeserializer(NullLogger.Instance); + } + } +} \ No newline at end of file diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseWorkspaceDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseWorkspaceDeserializerTests.cs new file mode 100644 index 000000000..3ecf9ebde --- /dev/null +++ b/src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseWorkspaceDeserializerTests.cs @@ -0,0 +1,54 @@ +using System.ComponentModel; +using Microsoft.Extensions.Logging.Abstractions; +using Promitor.Core.Scraping.Configuration.Serialization; +using Promitor.Core.Scraping.Configuration.Serialization.v1.Model; +using Promitor.Core.Scraping.Configuration.Serialization.v1.Model.ResourceTypes; +using Promitor.Core.Scraping.Configuration.Serialization.v1.Providers; +using Xunit; + +namespace Promitor.Tests.Unit.Serialization.v1.Providers +{ + [Category("Unit")] + public class SynapseWorkspaceDeserializerTests : ResourceDeserializerTest + { + private readonly SynapseWorkspaceDeserializer _deserializer = new SynapseWorkspaceDeserializer(NullLogger.Instance); + + [Fact] + public void Deserialize_WorkspaceNameSupplied_SetsWorkspace() + { + const string expectedWorkspaceName = "promitor-synapse-workspace"; + YamlAssert.PropertySet( + _deserializer, + $"workspaceName: {expectedWorkspaceName}", + expectedWorkspaceName, + c => c.WorkspaceName); + } + + [Fact] + public void Deserialize_WorkspaceNameNotSupplied_Null() + { + YamlAssert.PropertyNull( + _deserializer, + "resourceGroupName: promitor-group", + c => c.WorkspaceName); + } + + [Fact] + public void Deserialize_WorkspaceNameNotSupplied_ReportsError() + { + // Arrange + var node = YamlUtils.CreateYamlNode("resourceGroupName: promitor-resource-group"); + + // Act / Assert + YamlAssert.ReportsErrorForProperty( + _deserializer, + node, + "workspaceName"); + } + + protected override IDeserializer CreateDeserializer() + { + return new SynapseWorkspaceDeserializer(NullLogger.Instance); + } + } +} \ No newline at end of file diff --git a/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/SynapseApacheSparkPoolMetricsDeclarationValidationStepTests.cs b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/SynapseApacheSparkPoolMetricsDeclarationValidationStepTests.cs new file mode 100644 index 000000000..3dea1d586 --- /dev/null +++ b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/SynapseApacheSparkPoolMetricsDeclarationValidationStepTests.cs @@ -0,0 +1,132 @@ +using System.ComponentModel; +using Microsoft.Extensions.Logging.Abstractions; +using Promitor.Agents.Scraper.Validation.Steps; +using Promitor.Tests.Unit.Builders.Metrics.v1; +using Promitor.Tests.Unit.Stubs; +using Xunit; + +namespace Promitor.Tests.Unit.Validation.Scraper.Metrics.ResourceTypes +{ + [Category("Unit")] + public class SynapseApacheSparkPoolMetricsDeclarationValidationStepTests : MetricsDeclarationValidationStepsTests + { + [Fact] + public void SynapseApacheSparkPoolMetricsDeclaration_DeclarationWithoutAzureMetricName_Fails() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithSynapseApacheSparkPoolMetric(azureMetricName: string.Empty) + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationFailed(validationResult); + } + + [Fact] + public void SynapseApacheSparkPoolMetricsDeclaration_DeclarationWithoutAzureMetricDescription_Succeeds() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithSynapseApacheSparkPoolMetric(metricDescription: string.Empty) + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationIsSuccessful(validationResult); + } + + [Fact] + public void SynapseApacheSparkPoolMetricsDeclaration_DeclarationWithoutWorkspaceName_Fails() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithSynapseApacheSparkPoolMetric(workspaceName: string.Empty) + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationFailed(validationResult); + } + + [Fact] + public void SynapseApacheSparkPoolMetricsDeclaration_DeclarationWithoutPoolName_Fails() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithSynapseApacheSparkPoolMetric(poolName: string.Empty) + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationFailed(validationResult); + } + + [Fact] + public void SynapseApacheSparkPoolMetricsDeclaration_DeclarationWithoutResourceAndResourceDiscoveryGroupInfo_Fails() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithSynapseApacheSparkPoolMetric(omitResource: true) + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationFailed(validationResult); + } + + [Fact] + public void SynapseApacheSparkPoolMetricsDeclaration_DeclarationWithoutResourceButWithResourceDiscoveryGroupInfo_Succeeds() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithSynapseApacheSparkPoolMetric(omitResource:true, resourceDiscoveryGroupName:"sample-collection") + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationIsSuccessful(validationResult); + } + + [Fact] + public void SynapseApacheSparkPoolMetricsDeclaration_ValidDeclaration_Succeeds() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithSynapseApacheSparkPoolMetric() + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationIsSuccessful(validationResult); + } + } +} diff --git a/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/SynapseSqlPoolMetricsDeclarationValidationStepTests.cs b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/SynapseSqlPoolMetricsDeclarationValidationStepTests.cs new file mode 100644 index 000000000..a4da77913 --- /dev/null +++ b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/SynapseSqlPoolMetricsDeclarationValidationStepTests.cs @@ -0,0 +1,132 @@ +using System.ComponentModel; +using Microsoft.Extensions.Logging.Abstractions; +using Promitor.Agents.Scraper.Validation.Steps; +using Promitor.Tests.Unit.Builders.Metrics.v1; +using Promitor.Tests.Unit.Stubs; +using Xunit; + +namespace Promitor.Tests.Unit.Validation.Scraper.Metrics.ResourceTypes +{ + [Category("Unit")] + public class SynapseSqlPoolMetricsDeclarationValidationStepTests : MetricsDeclarationValidationStepsTests + { + [Fact] + public void SynapseSqlPoolMetricsDeclaration_DeclarationWithoutAzureMetricName_Fails() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithSynapseSqlPoolMetric(azureMetricName: string.Empty) + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationFailed(validationResult); + } + + [Fact] + public void SynapseSqlPoolMetricsDeclaration_DeclarationWithoutAzureMetricDescription_Succeeds() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithSynapseSqlPoolMetric(metricDescription: string.Empty) + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationIsSuccessful(validationResult); + } + + [Fact] + public void SynapseSqlPoolMetricsDeclaration_DeclarationWithoutWorkspaceName_Fails() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithSynapseSqlPoolMetric(workspaceName: string.Empty) + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationFailed(validationResult); + } + + [Fact] + public void SynapseSqlPoolMetricsDeclaration_DeclarationWithoutPoolName_Fails() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithSynapseSqlPoolMetric(poolName: string.Empty) + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationFailed(validationResult); + } + + [Fact] + public void SynapseSqlPoolMetricsDeclaration_DeclarationWithoutResourceAndResourceDiscoveryGroupInfo_Fails() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithSynapseSqlPoolMetric(omitResource: true) + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationFailed(validationResult); + } + + [Fact] + public void SynapseSqlPoolMetricsDeclaration_DeclarationWithoutResourceButWithResourceDiscoveryGroupInfo_Succeeds() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithSynapseSqlPoolMetric(omitResource:true, resourceDiscoveryGroupName:"sample-collection") + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationIsSuccessful(validationResult); + } + + [Fact] + public void SynapseSqlPoolMetricsDeclaration_ValidDeclaration_Succeeds() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithSynapseSqlPoolMetric() + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationIsSuccessful(validationResult); + } + } +} diff --git a/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/SynapseWorkspaceMetricsDeclarationValidationStepTests.cs b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/SynapseWorkspaceMetricsDeclarationValidationStepTests.cs new file mode 100644 index 000000000..873e00154 --- /dev/null +++ b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/SynapseWorkspaceMetricsDeclarationValidationStepTests.cs @@ -0,0 +1,115 @@ +using System.ComponentModel; +using Microsoft.Extensions.Logging.Abstractions; +using Promitor.Agents.Scraper.Validation.Steps; +using Promitor.Tests.Unit.Builders.Metrics.v1; +using Promitor.Tests.Unit.Stubs; +using Xunit; + +namespace Promitor.Tests.Unit.Validation.Scraper.Metrics.ResourceTypes +{ + [Category("Unit")] + public class SynapseWorkspaceMetricsDeclarationValidationStepTests : MetricsDeclarationValidationStepsTests + { + [Fact] + public void SynapseWorkspaceMetricsDeclaration_DeclarationWithoutAzureMetricName_Fails() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithSynapseWorkspaceMetric(azureMetricName: string.Empty) + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationFailed(validationResult); + } + + [Fact] + public void SynapseWorkspaceMetricsDeclaration_DeclarationWithoutAzureMetricDescription_Succeeds() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithSynapseWorkspaceMetric(metricDescription: string.Empty) + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationIsSuccessful(validationResult); + } + + [Fact] + public void SynapseWorkspaceMetricsDeclaration_DeclarationWithoutWorkspaceName_Fails() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithSynapseWorkspaceMetric(workspaceName: string.Empty) + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationFailed(validationResult); + } + + [Fact] + public void SynapseWorkspaceMetricsDeclaration_DeclarationWithoutResourceAndResourceDiscoveryGroupInfo_Fails() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithSynapseWorkspaceMetric(omitResource: true) + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationFailed(validationResult); + } + + [Fact] + public void SynapseWorkspaceMetricsDeclaration_DeclarationWithoutResourceButWithResourceDiscoveryGroupInfo_Succeeds() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithSynapseWorkspaceMetric(omitResource:true, resourceDiscoveryGroupName:"sample-collection") + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationIsSuccessful(validationResult); + } + + [Fact] + public void SynapseWorkspaceMetricsDeclaration_ValidDeclaration_Succeeds() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithSynapseWorkspaceMetric() + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationIsSuccessful(validationResult); + } + } +}