diff --git a/blueprints/cloud-operations/network-dashboard/README.md b/blueprints/cloud-operations/network-dashboard/README.md index b300089b2..254c80557 100644 --- a/blueprints/cloud-operations/network-dashboard/README.md +++ b/blueprints/cloud-operations/network-dashboard/README.md @@ -9,7 +9,7 @@ Here is an example of dashboard you can get with this solution: Here you see utilization (usage compared to the limit) for a specific metric (number of instances per VPC) for multiple VPCs and projects. -3 metrics are created: Usage, limit and utilization. You can follow each of these and create alerting policies if a threshold is reached. +Three metric descriptors are created for each monitored resource: usage, limit and utilization. You can follow each of these and create alerting policies if a threshold is reached. ## Usage @@ -45,6 +45,7 @@ The Cloud Function currently tracks usage, limit and utilization of: - Dynamic routes per VPC - Dynamic routes per VPC peering group - IP utilization per subnet (% of IP addresses used in a subnet) +- VPC firewall rules per project (VPC drill down is available for usage) It writes this values to custom metrics in Cloud Monitoring and creates a dashboard to visualize the current utilization of these metrics in Cloud Monitoring. diff --git a/blueprints/cloud-operations/network-dashboard/cloud-function/main.py b/blueprints/cloud-operations/network-dashboard/cloud-function/main.py index 439b17c80..7b36c79ab 100644 --- a/blueprints/cloud-operations/network-dashboard/cloud-function/main.py +++ b/blueprints/cloud-operations/network-dashboard/cloud-function/main.py @@ -89,18 +89,15 @@ def monitoring_interval(): config = { # Organization ID containing the projects to be monitored - "organization": #os.environ.get("ORGANIZATION_ID"), - '34855741773', + "organization": + os.environ.get("ORGANIZATION_ID"), # list of projects from which function will get quotas information - "monitored_projects": #os.environ.get("MONITORED_PROJECTS_LIST").split(","), - [ - "mnoseda-prod-net-landing-0", "mnoseda-prod-net-spoke-0", - "mnoseda-dev-net-spoke-0" - ], - "monitoring_project": #os.environ.get('MONITORING_PROJECT_ID'), - "monitoring-tlc", - "monitoring_project_link": #f"projects/{os.environ.get('MONITORING_PROJECT_ID')}", - f"projects/monitoring-tlc", + "monitored_projects": + os.environ.get("MONITORED_PROJECTS_LIST").split(","), + "monitoring_project": + os.environ.get('MONITORING_PROJECT_ID'), + "monitoring_project_link": + f"projects/{os.environ.get('MONITORING_PROJECT_ID')}", "monitoring_interval": monitoring_interval(), "limit_names": { diff --git a/blueprints/cloud-operations/network-dashboard/cloud-function/metrics/metrics.py b/blueprints/cloud-operations/network-dashboard/cloud-function/metrics/metrics.py index f6d8ac01b..3bbca2e39 100644 --- a/blueprints/cloud-operations/network-dashboard/cloud-function/metrics/metrics.py +++ b/blueprints/cloud-operations/network-dashboard/cloud-function/metrics/metrics.py @@ -106,10 +106,10 @@ def write_data_to_metric(config, monitored_project_id, value, metric_name, series = monitoring_v3.TimeSeries() series.metric.type = f"custom.googleapis.com/{metric_name}" series.resource.type = "global" + series.metric.labels["project"] = monitored_project_id if network_name != None: series.metric.labels["network_name"] = network_name - series.metric.labels["project"] = monitored_project_id - if subnet_id: + if subnet_id != None: series.metric.labels["subnet_id"] = subnet_id now = time.time() diff --git a/blueprints/cloud-operations/network-dashboard/dashboards/quotas-utilization.json b/blueprints/cloud-operations/network-dashboard/dashboards/quotas-utilization.json index 6db2499a2..8a70b38ed 100644 --- a/blueprints/cloud-operations/network-dashboard/dashboards/quotas-utilization.json +++ b/blueprints/cloud-operations/network-dashboard/dashboards/quotas-utilization.json @@ -1,4 +1,5 @@ { + "category": "CUSTOM", "displayName": "quotas_utilization", "mosaicLayout": { "columns": 12, @@ -17,14 +18,17 @@ "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { + "apiSource": "DEFAULT_CLOUD", "timeSeriesFilter": { "aggregation": { "alignmentPeriod": "3600s", + "crossSeriesReducer": "REDUCE_NONE", "perSeriesAligner": "ALIGN_NEXT_OLDER" }, "filter": "metric.type=\"custom.googleapis.com/internal_forwarding_rules_l4_utilization\" resource.type=\"global\"", "secondaryAggregation": { "alignmentPeriod": "1800s", + "crossSeriesReducer": "REDUCE_NONE", "perSeriesAligner": "ALIGN_MEAN" } } @@ -38,7 +42,9 @@ } } }, - "width": 6 + "width": 6, + "xPos": 0, + "yPos": 0 }, { "height": 4, @@ -54,14 +60,17 @@ "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { + "apiSource": "DEFAULT_CLOUD", "timeSeriesFilter": { "aggregation": { "alignmentPeriod": "3600s", + "crossSeriesReducer": "REDUCE_NONE", "perSeriesAligner": "ALIGN_NEXT_OLDER" }, "filter": "metric.type=\"custom.googleapis.com/internal_forwarding_rules_l7_utilization\" resource.type=\"global\"", "secondaryAggregation": { "alignmentPeriod": "60s", + "crossSeriesReducer": "REDUCE_NONE", "perSeriesAligner": "ALIGN_MEAN" } } @@ -76,6 +85,7 @@ } }, "width": 6, + "xPos": 0, "yPos": 12 }, { @@ -92,14 +102,17 @@ "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { + "apiSource": "DEFAULT_CLOUD", "timeSeriesFilter": { "aggregation": { "alignmentPeriod": "3600s", + "crossSeriesReducer": "REDUCE_NONE", "perSeriesAligner": "ALIGN_NEXT_OLDER" }, "filter": "metric.type=\"custom.googleapis.com/number_of_instances_utilization\" resource.type=\"global\"", "secondaryAggregation": { "alignmentPeriod": "60s", + "crossSeriesReducer": "REDUCE_NONE", "perSeriesAligner": "ALIGN_MEAN" } } @@ -114,6 +127,7 @@ } }, "width": 6, + "xPos": 0, "yPos": 8 }, { @@ -130,14 +144,17 @@ "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { + "apiSource": "DEFAULT_CLOUD", "timeSeriesFilter": { "aggregation": { "alignmentPeriod": "3600s", + "crossSeriesReducer": "REDUCE_NONE", "perSeriesAligner": "ALIGN_NEXT_OLDER" }, "filter": "metric.type=\"custom.googleapis.com/number_of_vpc_peerings_utilization\" resource.type=\"global\"", "secondaryAggregation": { "alignmentPeriod": "60s", + "crossSeriesReducer": "REDUCE_NONE", "perSeriesAligner": "ALIGN_MEAN" } } @@ -169,14 +186,17 @@ "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { + "apiSource": "DEFAULT_CLOUD", "timeSeriesFilter": { "aggregation": { "alignmentPeriod": "3600s", + "crossSeriesReducer": "REDUCE_NONE", "perSeriesAligner": "ALIGN_NEXT_OLDER" }, "filter": "metric.type=\"custom.googleapis.com/number_of_active_vpc_peerings_utilization\" resource.type=\"global\"", "secondaryAggregation": { "alignmentPeriod": "60s", + "crossSeriesReducer": "REDUCE_NONE", "perSeriesAligner": "ALIGN_INTERPOLATE" } } @@ -191,6 +211,7 @@ } }, "width": 6, + "xPos": 0, "yPos": 4 }, { @@ -207,14 +228,17 @@ "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { + "apiSource": "DEFAULT_CLOUD", "timeSeriesFilter": { "aggregation": { "alignmentPeriod": "3600s", + "crossSeriesReducer": "REDUCE_NONE", "perSeriesAligner": "ALIGN_NEXT_OLDER" }, "filter": "metric.type=\"custom.googleapis.com/number_of_subnet_IP_ranges_ppg_utilization\" resource.type=\"global\"", "secondaryAggregation": { "alignmentPeriod": "3600s", + "crossSeriesReducer": "REDUCE_NONE", "perSeriesAligner": "ALIGN_MEAN" } } @@ -229,6 +253,7 @@ } }, "width": 6, + "xPos": 0, "yPos": 16 }, { @@ -245,14 +270,17 @@ "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { + "apiSource": "DEFAULT_CLOUD", "timeSeriesFilter": { "aggregation": { "alignmentPeriod": "3600s", + "crossSeriesReducer": "REDUCE_NONE", "perSeriesAligner": "ALIGN_NEXT_OLDER" }, "filter": "metric.type=\"custom.googleapis.com/internal_forwarding_rules_l4_ppg_utilization\" resource.type=\"global\"", "secondaryAggregation": { "alignmentPeriod": "3600s", + "crossSeriesReducer": "REDUCE_NONE", "perSeriesAligner": "ALIGN_MEAN" } } @@ -267,7 +295,8 @@ } }, "width": 6, - "xPos": 6 + "xPos": 6, + "yPos": 0 }, { "height": 4, @@ -283,14 +312,17 @@ "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { + "apiSource": "DEFAULT_CLOUD", "timeSeriesFilter": { "aggregation": { "alignmentPeriod": "3600s", + "crossSeriesReducer": "REDUCE_NONE", "perSeriesAligner": "ALIGN_NEXT_OLDER" }, "filter": "metric.type=\"custom.googleapis.com/internal_forwarding_rules_l7_ppg_utilization\" resource.type=\"global\"", "secondaryAggregation": { "alignmentPeriod": "60s", + "crossSeriesReducer": "REDUCE_NONE", "perSeriesAligner": "ALIGN_MEAN" } } @@ -322,9 +354,11 @@ "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { + "apiSource": "DEFAULT_CLOUD", "timeSeriesFilter": { "aggregation": { "alignmentPeriod": "3600s", + "crossSeriesReducer": "REDUCE_NONE", "perSeriesAligner": "ALIGN_NEXT_OLDER" }, "filter": "metric.type=\"custom.googleapis.com/number_of_instances_ppg_utilization\" resource.type=\"global\"" @@ -357,9 +391,11 @@ "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { + "apiSource": "DEFAULT_CLOUD", "timeSeriesFilter": { "aggregation": { "alignmentPeriod": "60s", + "crossSeriesReducer": "REDUCE_NONE", "perSeriesAligner": "ALIGN_MEAN" }, "filter": "metric.type=\"custom.googleapis.com/dynamic_routes_per_network_utilization\" resource.type=\"global\"" @@ -375,50 +411,53 @@ } }, "width": 6, - "yPos": 20 - }, - { - "height": 4, - "widget": { - "title": "ip_addresses_per_subnet_utilization", - "xyChart": { - "chartOptions": { - "mode": "COLOR" - }, - "dataSets": [ - { - "minAlignmentPeriod": "60s", - "plotType": "LINE", - "targetAxis": "Y1", - "timeSeriesQuery": { - "timeSeriesFilter": { - "aggregation": { - "alignmentPeriod": "60s", - "perSeriesAligner": "ALIGN_MEAN" - }, - "filter": "metric.type=\"custom.googleapis.com/ip_addresses_per_subnet_utilization\" resource.type=\"global\"", - "secondaryAggregation": { - "alignmentPeriod": "60s" - } - } - } - } - ], - "timeshiftDuration": "0s", - "yAxis": { - "label": "y1Axis", - "scale": "LINEAR" - } - } - }, - "width": 6, "xPos": 6, "yPos": 16 }, { "height": 4, "widget": { - "title": "dynamic_routes_ppg_utilization", + "title": "firewalls_per_project_usage", + "xyChart": { + "chartOptions": { + "mode": "COLOR" + }, + "dataSets": [ + { + "minAlignmentPeriod": "60s", + "plotType": "STACKED_BAR", + "targetAxis": "Y1", + "timeSeriesQuery": { + "apiSource": "DEFAULT_CLOUD", + "timeSeriesFilter": { + "aggregation": { + "alignmentPeriod": "60s", + "crossSeriesReducer": "REDUCE_SUM", + "groupByFields": [ + "metric.label.\"project\"" + ], + "perSeriesAligner": "ALIGN_MEAN" + }, + "filter": "metric.type=\"custom.googleapis.com/firewalls_per_project_usage\" resource.type=\"global\"" + } + } + } + ], + "timeshiftDuration": "0s", + "yAxis": { + "label": "y1Axis", + "scale": "LINEAR" + } + } + }, + "width": 6, + "xPos": 0, + "yPos": 20 + }, + { + "height": 4, + "widget": { + "title": "firewalls_per_project_utilization", "xyChart": { "chartOptions": { "mode": "COLOR" @@ -429,15 +468,14 @@ "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { + "apiSource": "DEFAULT_CLOUD", "timeSeriesFilter": { "aggregation": { "alignmentPeriod": "60s", - "perSeriesAligner": "ALIGN_MEAN" + "crossSeriesReducer": "REDUCE_MAX", + "perSeriesAligner": "ALIGN_MAX" }, - "filter": "metric.type=\"custom.googleapis.com/dynamic_routes_per_peering_group_utilization\" resource.type=\"global\"", - "secondaryAggregation": { - "alignmentPeriod": "60s" - } + "filter": "metric.type=\"custom.googleapis.com/firewalls_per_project_utilization\" resource.type=\"global\"" } } } @@ -454,6 +492,5 @@ "yPos": 20 } ] - }, - "name": "projects/347834224817/dashboards/1bdcd06a-030d-4977-bf4b-f32231aa3b77" + } } \ No newline at end of file