Merge branch 'GoogleCloudPlatform:master' into updates-quota-monitoring-function
This commit is contained in:
commit
9a67546cb9
|
@ -3,7 +3,7 @@
|
|||
This repository provides an end-to-end solution to gather some GCP Networking quotas and limits (that cannot be seen in the GCP console today) and display them in a dashboard.
|
||||
The goal is to allow for better visibility of these limits, facilitating capacity planning and avoiding hitting these limits.
|
||||
|
||||
Here is an blueprint of dashboard you can get with this solution:
|
||||
Here is an example of dashboard you can get with this solution:
|
||||
|
||||
<img src="metric.png" width="640px">
|
||||
|
||||
|
@ -15,10 +15,11 @@ Here you see utilization (usage compared to the limit) for a specific metric (nu
|
|||
|
||||
Clone this repository, then go through the following steps to create resources:
|
||||
- Create a terraform.tfvars file with the following content:
|
||||
- organization_id = "[YOUR-ORG-ID]"
|
||||
- billing_account = "[YOUR-BILLING-ACCOUNT]"
|
||||
- organization_id = "<YOUR-ORG-ID>"
|
||||
- billing_account = "<YOUR-BILLING-ACCOUNT>"
|
||||
- monitoring_project_id = "project-0" # Monitoring project where the dashboard will be created and the solution deployed
|
||||
- monitored_projects_list = ["project-1", "project2"] # Projects to be monitored by the solution
|
||||
- monitored_folders_list = ["folder_id"] # Folders to be monitored by the solution
|
||||
- `terraform init`
|
||||
- `terraform apply`
|
||||
|
||||
|
@ -43,18 +44,17 @@ The Cloud Function currently tracks usage, limit and utilization of:
|
|||
- internal forwarding rules for internal L7 load balancers per VPC peering group
|
||||
- Dynamic routes per VPC
|
||||
- Dynamic routes per VPC peering group
|
||||
- IP utilization per subnet (% of IP addresses used in a subnet)
|
||||
|
||||
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.
|
||||
|
||||
Note that metrics are created in the cloud-function/metrics.yaml file.
|
||||
|
||||
You can also edit default limits for a specific network in that file. See the blueprint for `vpc_peering_per_network`.
|
||||
You can also edit default limits for a specific network in that file. See the example for `vpc_peering_per_network`.
|
||||
|
||||
## Next steps and ideas
|
||||
In a future release, we could support:
|
||||
- Static routes per VPC / per VPC peering group
|
||||
- Dynamic routes per VPC peering group
|
||||
- Google managed VPCs that are peered with PSA (such as Cloud SQL or Memorystore)
|
||||
- Subnet IP ranges utilization
|
||||
|
||||
If you are interested in this and/or would like to contribute, please contact legranda@google.com.
|
||||
If you are interested in this and/or would like to contribute, please contact legranda@google.com.
|
|
@ -14,23 +14,63 @@
|
|||
# limitations under the License.
|
||||
#
|
||||
|
||||
from code import interact
|
||||
from distutils.command.config import config
|
||||
import os
|
||||
from pickletools import int4
|
||||
import time
|
||||
from google.cloud import monitoring_v3, asset_v1
|
||||
from google.protobuf import field_mask_pb2
|
||||
from googleapiclient import discovery
|
||||
from metrics import ilb_fwrules, instances, networks, metrics, limits, peerings, routes
|
||||
from metrics import ilb_fwrules, instances, networks, metrics, limits, peerings, routes, subnets
|
||||
|
||||
|
||||
def get_monitored_projects_list(config):
|
||||
'''
|
||||
Gets the projects to be monitored from the MONITORED_FOLDERS_LIST environment variable.
|
||||
|
||||
Parameters:
|
||||
config (dict): The dict containing config like clients and limits
|
||||
Returns:
|
||||
monitored_projects (List of strings): Full list of projects to be monitored
|
||||
'''
|
||||
monitored_projects = config["monitored_projects"]
|
||||
monitored_folders = os.environ.get("MONITORED_FOLDERS_LIST").split(",")
|
||||
|
||||
# Handling empty monitored folders list
|
||||
if monitored_folders == ['']:
|
||||
monitored_folders = []
|
||||
|
||||
# Gets all projects under each monitored folder (and even in sub folders)
|
||||
for folder in monitored_folders:
|
||||
read_mask = field_mask_pb2.FieldMask()
|
||||
read_mask.FromJsonString('name,versionedResources')
|
||||
|
||||
response = config["clients"]["asset_client"].search_all_resources(
|
||||
request={
|
||||
"scope": f"folders/{folder}",
|
||||
"asset_types": ["cloudresourcemanager.googleapis.com/Project"],
|
||||
"read_mask": read_mask
|
||||
})
|
||||
|
||||
for resource in response:
|
||||
for versioned in resource.versioned_resources:
|
||||
for field_name, field_value in versioned.resource.items():
|
||||
if field_name == "projectId":
|
||||
project_id = field_value
|
||||
# Avoid duplicate
|
||||
if project_id not in monitored_projects:
|
||||
monitored_projects.append(project_id)
|
||||
|
||||
print("List of projects to be monitored:")
|
||||
print(monitored_projects)
|
||||
|
||||
return monitored_projects
|
||||
|
||||
|
||||
def monitoring_interval():
|
||||
'''
|
||||
Creates the monitoring interval of 24 hours
|
||||
|
||||
Returns:
|
||||
monitoring_v3.TimeInterval: Moinitoring time interval of 24h
|
||||
monitoring_v3.TimeInterval: Monitoring time interval of 24h
|
||||
'''
|
||||
now = time.time()
|
||||
seconds = int(now)
|
||||
|
@ -78,20 +118,25 @@ config = {
|
|||
"discovery_client": discovery.build('compute', 'v1'),
|
||||
"asset_client": asset_v1.AssetServiceClient(),
|
||||
"monitoring_client": monitoring_v3.MetricServiceClient()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def main(event, context):
|
||||
'''
|
||||
Cloud Function Entry point, called by the scheduler.
|
||||
|
||||
Parameters:
|
||||
event: Not used for now (Pubsub trigger)
|
||||
context: Not used for now (Pubsub trigger)
|
||||
Returns:
|
||||
'Function executed successfully'
|
||||
'''
|
||||
# Handling empty monitored projects list
|
||||
if config["monitored_projects"] == ['']:
|
||||
config["monitored_projects"] = []
|
||||
|
||||
# Gets projects and folders to be monitored
|
||||
config["monitored_projects"] = get_monitored_projects_list(config)
|
||||
|
||||
# Keep the monitoring interval up2date during each run
|
||||
config["monitoring_interval"] = monitoring_interval()
|
||||
|
@ -99,6 +144,9 @@ def main(event, context):
|
|||
metrics_dict, limits_dict = metrics.create_metrics(
|
||||
config["monitoring_project_link"])
|
||||
|
||||
# IP utilization subnet level metrics
|
||||
subnets.get_subnets(config, metrics_dict)
|
||||
|
||||
# Asset inventory queries
|
||||
gce_instance_dict = instances.get_gce_instance_dict(config)
|
||||
l4_forwarding_rules_dict = ilb_fwrules.get_forwarding_rules_dict(config, "L4")
|
||||
|
@ -143,7 +191,7 @@ def main(event, context):
|
|||
routes.get_dynamic_routes_ppg(
|
||||
config, metrics_dict["metrics_per_peering_group"]
|
||||
["dynamic_routes_per_peering_group"], dynamic_routes_dict,
|
||||
limits_dict['number_of_subnet_IP_ranges_ppg_limit'])
|
||||
limits_dict['dynamic_routes_per_peering_group_limit'])
|
||||
|
||||
return 'Function executed successfully'
|
||||
|
||||
|
|
|
@ -14,6 +14,17 @@
|
|||
# limitations under the License.
|
||||
#
|
||||
---
|
||||
metrics_per_subnet:
|
||||
ip_usage_per_subnet:
|
||||
usage:
|
||||
name: number_of_ip_used
|
||||
description: Number of used IP addresses in the subnet.
|
||||
utilization:
|
||||
name: ip_addresses_per_subnet_utilization
|
||||
description: Percentage of IP used in the subnet.
|
||||
limit:
|
||||
name: number_of_max_ip
|
||||
description: Number of available IP addresses in the subnet.
|
||||
metrics_per_network:
|
||||
instance_per_network:
|
||||
usage:
|
||||
|
@ -60,7 +71,7 @@ metrics_per_network:
|
|||
name: internal_forwarding_rules_l4_limit
|
||||
description: Number of Internal Forwarding Rules for Internal L4 Load Balancers - limit.
|
||||
values:
|
||||
default_value: 300
|
||||
default_value: 500
|
||||
utilization:
|
||||
name: internal_forwarding_rules_l4_utilization
|
||||
description: Number of Internal Forwarding Rules for Internal L4 Load Balancers - utilization.
|
||||
|
@ -97,7 +108,7 @@ metrics_per_peering_group:
|
|||
name: internal_forwarding_rules_l4_ppg_limit
|
||||
description: Number of Internal Forwarding Rules for Internal L4 Load Balancers per VPC peering group - effective limit.
|
||||
values:
|
||||
default_value: 300
|
||||
default_value: 500
|
||||
utilization:
|
||||
name: internal_forwarding_rules_l4_ppg_utilization
|
||||
description: Number of Internal Forwarding Rules for Internal L4 Load Balancers per VPC peering group - utilization.
|
||||
|
@ -148,4 +159,4 @@ metrics_per_peering_group:
|
|||
default_value: 300
|
||||
utilization:
|
||||
name: dynamic_routes_per_peering_group_utilization
|
||||
description: Number of Dynamic routes per peering group - utilization.
|
||||
description: Number of Dynamic routes per peering group - utilization.
|
|
@ -24,7 +24,6 @@ from . import peerings, limits, networks
|
|||
def create_metrics(monitoring_project):
|
||||
'''
|
||||
Creates all Cloud Monitoring custom metrics based on the metric.yaml file
|
||||
|
||||
Parameters:
|
||||
monitoring_project (string): the project where the metrics are written to
|
||||
Returns:
|
||||
|
@ -42,15 +41,16 @@ def create_metrics(monitoring_project):
|
|||
metrics_dict = yaml.safe_load(stream)
|
||||
|
||||
for metric_list in metrics_dict.values():
|
||||
for metric in metric_list.values():
|
||||
for metric_name, metric in metric_list.items():
|
||||
for sub_metric_key, sub_metric in metric.items():
|
||||
metric_link = f"custom.googleapis.com/{sub_metric['name']}"
|
||||
# If the metric doesn't exist yet, then we create it
|
||||
if metric_link not in existing_metrics:
|
||||
create_metric(sub_metric["name"], sub_metric["description"],
|
||||
monitoring_project)
|
||||
# Parse limits (both default values and network specific ones)
|
||||
if sub_metric_key == "limit":
|
||||
# Parse limits for network and peering group metrics
|
||||
# Subnet level metrics have a different limit: the subnet IP range size
|
||||
if sub_metric_key == "limit" and metric_name != "ip_usage_per_subnet":
|
||||
limits_dict_for_metric = {}
|
||||
for network_link, limit_value in sub_metric["values"].items():
|
||||
limits_dict_for_metric[network_link] = limit_value
|
||||
|
@ -64,7 +64,6 @@ def create_metrics(monitoring_project):
|
|||
def create_metric(metric_name, description, monitoring_project):
|
||||
'''
|
||||
Creates a Cloud Monitoring metric based on the parameter given if the metric is not already existing
|
||||
|
||||
Parameters:
|
||||
metric_name (string): Name of the metric to be created
|
||||
description (string): Description of the metric to be created
|
||||
|
@ -85,16 +84,16 @@ def create_metric(metric_name, description, monitoring_project):
|
|||
|
||||
|
||||
def write_data_to_metric(config, monitored_project_id, value, metric_name,
|
||||
network_name):
|
||||
network_name, subnet_id=None):
|
||||
'''
|
||||
Writes data to Cloud Monitoring custom metrics.
|
||||
|
||||
Parameters:
|
||||
config (dict): The dict containing config like clients and limits
|
||||
monitored_project_id: ID of the project where the resource lives (will be added as a label)
|
||||
value (int): Value for the data point of the metric.
|
||||
metric_name (string): Name of the metric
|
||||
network_name (string): Name of the network (will be added as a label)
|
||||
subnet_id (string): Identifier of the Subnet (region/name of the subnet)
|
||||
Returns:
|
||||
usage (int): Current usage for that network.
|
||||
limit (int): Current usage for that network.
|
||||
|
@ -106,6 +105,8 @@ def write_data_to_metric(config, monitored_project_id, value, metric_name,
|
|||
series.resource.type = "global"
|
||||
series.metric.labels["network_name"] = network_name
|
||||
series.metric.labels["project"] = monitored_project_id
|
||||
if subnet_id:
|
||||
series.metric.labels["subnet_id"] = subnet_id
|
||||
|
||||
now = time.time()
|
||||
seconds = int(now)
|
||||
|
@ -129,13 +130,13 @@ def write_data_to_metric(config, monitored_project_id, value, metric_name,
|
|||
client.create_time_series(name=config["monitoring_project_link"],
|
||||
time_series=[series])
|
||||
except Exception as e:
|
||||
print("Error while writing data point for metric", metric_name)
|
||||
print(e)
|
||||
|
||||
|
||||
def get_pgg_data(config, metric_dict, usage_dict, limit_metric, limit_dict):
|
||||
'''
|
||||
This function gets the usage, limit and utilization per VPC peering group for a specific metric for all projects to be monitored.
|
||||
|
||||
Parameters:
|
||||
config (dict): The dict containing config like clients and limits
|
||||
metric_dict (dictionary of string: string): Dictionary with the metric names and description, that will be used to populate the metrics
|
||||
|
@ -221,7 +222,6 @@ def get_pgg_data(config, metric_dict, usage_dict, limit_metric, limit_dict):
|
|||
def customize_quota_view(quota_results):
|
||||
'''
|
||||
Customize the quota output for an easier parsable output.
|
||||
|
||||
Parameters:
|
||||
quota_results (string): Input from get_quota_current_usage or get_quota_current_limit. Contains the Current usage or limit for all networks in that project.
|
||||
Returns:
|
||||
|
@ -235,4 +235,4 @@ def customize_quota_view(quota_results):
|
|||
for val in result.points:
|
||||
quotaViewJson.update({'value': val.value.int64_value})
|
||||
quotaViewList.append(quotaViewJson)
|
||||
return quotaViewList
|
||||
return quotaViewList
|
|
@ -0,0 +1,253 @@
|
|||
#
|
||||
# Copyright 2022 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
from . import metrics
|
||||
from google.protobuf import field_mask_pb2
|
||||
from google.protobuf.json_format import MessageToDict
|
||||
import ipaddress
|
||||
|
||||
|
||||
def get_all_subnets(config):
|
||||
'''
|
||||
Returns a dictionary with subnet level informations (such as IP utilization)
|
||||
|
||||
Parameters:
|
||||
config (dict): The dict containing config like clients and limits
|
||||
Returns:
|
||||
subnet_dict (dictionary of String: dictionary): Key is the project_id, value is a nested dictionary with subnet_region/subnet_name as the key.
|
||||
'''
|
||||
subnet_dict = {}
|
||||
read_mask = field_mask_pb2.FieldMask()
|
||||
read_mask.FromJsonString('name,versionedResources')
|
||||
|
||||
response = config["clients"]["asset_client"].search_all_resources(
|
||||
request={
|
||||
"scope": f"organizations/{config['organization']}",
|
||||
"asset_types": ['compute.googleapis.com/Subnetwork'],
|
||||
"read_mask": read_mask,
|
||||
})
|
||||
|
||||
for asset in response:
|
||||
for versioned in asset.versioned_resources:
|
||||
subnet_name = ""
|
||||
network_name = ""
|
||||
project_id = ""
|
||||
ip_cidr_range = ""
|
||||
subnet_region = ""
|
||||
|
||||
for field_name, field_value in versioned.resource.items():
|
||||
if field_name == 'name':
|
||||
subnet_name = field_value
|
||||
elif field_name == 'network':
|
||||
# Network self link format:
|
||||
# "https://www.googleapis.com/compute/v1/projects/<PROJECT_ID>/global/networks/<NETWORK_NAME>"
|
||||
project_id = field_value.split('/')[6]
|
||||
network_name = field_value.split('/')[-1]
|
||||
elif field_name == 'ipCidrRange':
|
||||
ip_cidr_range = field_value
|
||||
elif field_name == 'region':
|
||||
subnet_region = field_value.split('/')[-1]
|
||||
|
||||
net = ipaddress.ip_network(ip_cidr_range)
|
||||
# Note that 4 IP addresses are reserved by GCP in all subnets
|
||||
# Source: https://cloud.google.com/vpc/docs/subnets#reserved_ip_addresses_in_every_subnet
|
||||
total_ip_addresses = int(net.num_addresses) - 4
|
||||
|
||||
if project_id not in subnet_dict:
|
||||
subnet_dict[project_id] = {}
|
||||
subnet_dict[project_id][f"{subnet_region}/{subnet_name}"] = {
|
||||
'name': subnet_name,
|
||||
'region': subnet_region,
|
||||
'ip_cidr_range': ip_cidr_range,
|
||||
'total_ip_addresses': total_ip_addresses,
|
||||
'used_ip_addresses': 0,
|
||||
'network_name': network_name
|
||||
}
|
||||
|
||||
return subnet_dict
|
||||
|
||||
|
||||
def compute_subnet_utilization(config, all_subnets_dict):
|
||||
'''
|
||||
Counts resources (VMs, ILBs, reserved IPs) using private IPs in the different subnets.
|
||||
Parameters:
|
||||
config (dict): Dict containing config like clients and limits
|
||||
all_subnets_dict (dict): Dict containing the information for each subnets in the GCP organization
|
||||
|
||||
Returns:
|
||||
None
|
||||
'''
|
||||
read_mask = field_mask_pb2.FieldMask()
|
||||
read_mask.FromJsonString('name,versionedResources')
|
||||
response_vm = config["clients"]["asset_client"].search_all_resources(
|
||||
request={
|
||||
"scope": f"organizations/{config['organization']}",
|
||||
"asset_types": ["compute.googleapis.com/Instance"],
|
||||
"read_mask": read_mask,
|
||||
})
|
||||
|
||||
# Counting IP addresses for GCE instances (VMs)
|
||||
for asset in response_vm:
|
||||
for versioned in asset.versioned_resources:
|
||||
for field_name, field_value in versioned.resource.items():
|
||||
if field_name == 'networkInterfaces':
|
||||
response_dict = MessageToDict(list(field_value._pb)[0])
|
||||
# Subnet self link:
|
||||
# https://www.googleapis.com/compute/v1/projects/<project_id>/regions/<subnet_region>/subnetworks/<subnet_name>
|
||||
subnet_region = response_dict['subnetwork'].split('/')[-3]
|
||||
subnet_name = response_dict['subnetwork'].split('/')[-1]
|
||||
# Network self link:
|
||||
# https://www.googleapis.com/compute/v1/projects/<project_id>/global/networks/<network_name>
|
||||
project_id = response_dict['network'].split('/')[6]
|
||||
network_name = response_dict['network'].split('/')[-1]
|
||||
|
||||
all_subnets_dict[project_id][f"{subnet_region}/{subnet_name}"][
|
||||
'used_ip_addresses'] += 1
|
||||
|
||||
response_ilb = config["clients"]["asset_client"].search_all_resources(
|
||||
request={
|
||||
"scope": f"organizations/{config['organization']}",
|
||||
"asset_types": ["compute.googleapis.com/ForwardingRule"],
|
||||
"read_mask": read_mask,
|
||||
})
|
||||
|
||||
# Counting IP addresses for GCE Internal Load Balancers
|
||||
for asset in response_ilb:
|
||||
internal = False
|
||||
psc = False
|
||||
project_id = ''
|
||||
subnet_name = ''
|
||||
subnet_region = ''
|
||||
address = ''
|
||||
for versioned in asset.versioned_resources:
|
||||
for field_name, field_value in versioned.resource.items():
|
||||
if 'loadBalancingScheme' in field_name and field_value == 'INTERNAL':
|
||||
internal = True
|
||||
# We want to count only accepted PSC endpoint Forwarding Rule
|
||||
# If the PSC endpoint Forwarding Rule is pending, we will count it in the reserved IP addresses
|
||||
elif field_name == 'pscConnectionStatus' and field_value == 'ACCEPTED':
|
||||
psc = True
|
||||
elif field_name == 'IPAddress':
|
||||
address = field_value
|
||||
elif field_name == 'network':
|
||||
project_id = field_value.split('/')[6]
|
||||
elif 'subnetwork' in field_name:
|
||||
subnet_name = field_value.split('/')[-1]
|
||||
subnet_region = field_value.split('/')[-3]
|
||||
|
||||
if internal:
|
||||
all_subnets_dict[project_id][f"{subnet_region}/{subnet_name}"][
|
||||
'used_ip_addresses'] += 1
|
||||
elif psc:
|
||||
# PSC endpoint asset doesn't contain the subnet information in Asset Inventory
|
||||
# We need to find the correct subnet with IP address matching
|
||||
ip_address = ipaddress.ip_address(address)
|
||||
for subnet_key, subnet_dict in all_subnets_dict[project_id].items():
|
||||
if ip_address in ipaddress.ip_network(subnet_dict['ip_cidr_range']):
|
||||
all_subnets_dict[project_id][subnet_key]['used_ip_addresses'] += 1
|
||||
|
||||
response_reserved_ips = config["clients"][
|
||||
"asset_client"].search_all_resources(
|
||||
request={
|
||||
"scope": f"organizations/{config['organization']}",
|
||||
"asset_types": ["compute.googleapis.com/Address"],
|
||||
"read_mask": read_mask,
|
||||
})
|
||||
|
||||
# Counting IP addresses for GCE Reserved IPs (ex: PSC, Cloud DNS Inbound policies, reserved GCE IPs)
|
||||
for asset in response_reserved_ips:
|
||||
purpose = ""
|
||||
status = ""
|
||||
project_id = ""
|
||||
network_name = ""
|
||||
subnet_name = ""
|
||||
subnet_region = ""
|
||||
address = ""
|
||||
prefixLength = ""
|
||||
for versioned in asset.versioned_resources:
|
||||
for field_name, field_value in versioned.resource.items():
|
||||
if field_name == 'purpose':
|
||||
purpose = field_value
|
||||
elif field_name == 'region':
|
||||
subnet_region = field_value.split('/')[-1]
|
||||
elif field_name == 'status':
|
||||
status = field_value
|
||||
elif field_name == 'address':
|
||||
address = field_value
|
||||
elif field_name == 'network':
|
||||
network_name = field_value.split('/')[-1]
|
||||
project_id = field_value.split('/')[6]
|
||||
elif field_name == 'subnetwork':
|
||||
subnet_name = field_value.split('/')[-1]
|
||||
project_id = field_value.split('/')[6]
|
||||
elif field_name == 'prefixLength':
|
||||
prefixLength = field_value
|
||||
|
||||
# Rserved IP addresses for GCE instances or PSC Forwarding Rule PENDING state
|
||||
if purpose == "GCE_ENDPOINT" and status == "RESERVED":
|
||||
all_subnets_dict[project_id][f"{subnet_region}/{subnet_name}"][
|
||||
'used_ip_addresses'] += 1
|
||||
# Cloud DNS inbound policy
|
||||
elif purpose == "DNS_RESOLVER":
|
||||
all_subnets_dict[project_id][f"{subnet_region}/{subnet_name}"][
|
||||
'used_ip_addresses'] += 1
|
||||
# PSA Range for Cloud SQL, MemoryStore, etc.
|
||||
elif purpose == "VPC_PEERING":
|
||||
# TODO: PSA range to be handled later
|
||||
# print("PSA range to be handled later:", address, prefixLength, network_name)
|
||||
continue
|
||||
|
||||
|
||||
def get_subnets(config, metrics_dict):
|
||||
'''
|
||||
Writes all subnet metrics to custom metrics.
|
||||
|
||||
Parameters:
|
||||
config (dict): The dict containing config like clients and limits
|
||||
Returns:
|
||||
None
|
||||
'''
|
||||
|
||||
all_subnets_dict = get_all_subnets(config)
|
||||
# Updates all_subnets_dict with the IP utilization info
|
||||
compute_subnet_utilization(config, all_subnets_dict)
|
||||
|
||||
for project_id in config["monitored_projects"]:
|
||||
if project_id not in all_subnets_dict:
|
||||
continue
|
||||
for subnet_dict in all_subnets_dict[project_id].values():
|
||||
ip_utilization = 0
|
||||
if subnet_dict['used_ip_addresses'] > 0:
|
||||
ip_utilization = subnet_dict['used_ip_addresses'] / subnet_dict[
|
||||
'total_ip_addresses']
|
||||
|
||||
# Building unique identifier with subnet region/name
|
||||
subnet_id = f"{subnet_dict['region']}/{subnet_dict['name']}"
|
||||
metrics.write_data_to_metric(
|
||||
config, project_id, subnet_dict['used_ip_addresses'],
|
||||
metrics_dict["metrics_per_subnet"]["ip_usage_per_subnet"]["usage"]
|
||||
["name"], subnet_dict['network_name'], subnet_id)
|
||||
metrics.write_data_to_metric(
|
||||
config, project_id, subnet_dict['total_ip_addresses'],
|
||||
metrics_dict["metrics_per_subnet"]["ip_usage_per_subnet"]["limit"]
|
||||
["name"], subnet_dict['network_name'], subnet_id)
|
||||
metrics.write_data_to_metric(
|
||||
config, project_id, ip_utilization, metrics_dict["metrics_per_subnet"]
|
||||
["ip_usage_per_subnet"]["utilization"]["name"],
|
||||
subnet_dict['network_name'], subnet_id)
|
||||
|
||||
print("Wrote metrics for subnet ip utilization for VPCs in project",
|
||||
project_id)
|
|
@ -4,383 +4,456 @@
|
|||
"columns": 12,
|
||||
"tiles": [
|
||||
{
|
||||
"width": 6,
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "internal_forwarding_rules_l4_utilization",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
},
|
||||
"dataSets": [
|
||||
{
|
||||
"minAlignmentPeriod": "3600s",
|
||||
"plotType": "LINE",
|
||||
"targetAxis": "Y1",
|
||||
"timeSeriesQuery": {
|
||||
"timeSeriesFilter": {
|
||||
"filter": "metric.type=\"custom.googleapis.com/internal_forwarding_rules_l4_utilization\" resource.type=\"global\"",
|
||||
"aggregation": {
|
||||
"alignmentPeriod": "3600s",
|
||||
"perSeriesAligner": "ALIGN_NEXT_OLDER"
|
||||
},
|
||||
"filter": "metric.type=\"custom.googleapis.com/internal_forwarding_rules_l4_utilization\" resource.type=\"global\"",
|
||||
"secondaryAggregation": {
|
||||
"alignmentPeriod": "1800s",
|
||||
"perSeriesAligner": "ALIGN_MEAN"
|
||||
}
|
||||
}
|
||||
},
|
||||
"plotType": "LINE",
|
||||
"minAlignmentPeriod": "3600s",
|
||||
"targetAxis": "Y1"
|
||||
}
|
||||
}
|
||||
],
|
||||
"timeshiftDuration": "0s",
|
||||
"yAxis": {
|
||||
"label": "y1Axis",
|
||||
"scale": "LINEAR"
|
||||
},
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": 6
|
||||
},
|
||||
{
|
||||
"yPos": 12,
|
||||
"width": 6,
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "internal_forwarding_rules_l7_utilization",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
},
|
||||
"dataSets": [
|
||||
{
|
||||
"minAlignmentPeriod": "3600s",
|
||||
"plotType": "LINE",
|
||||
"targetAxis": "Y1",
|
||||
"timeSeriesQuery": {
|
||||
"timeSeriesFilter": {
|
||||
"filter": "metric.type=\"custom.googleapis.com/internal_forwarding_rules_l7_utilization\" resource.type=\"global\"",
|
||||
"aggregation": {
|
||||
"alignmentPeriod": "3600s",
|
||||
"perSeriesAligner": "ALIGN_NEXT_OLDER"
|
||||
},
|
||||
"filter": "metric.type=\"custom.googleapis.com/internal_forwarding_rules_l7_utilization\" resource.type=\"global\"",
|
||||
"secondaryAggregation": {
|
||||
"alignmentPeriod": "60s",
|
||||
"perSeriesAligner": "ALIGN_MEAN"
|
||||
}
|
||||
}
|
||||
},
|
||||
"plotType": "LINE",
|
||||
"minAlignmentPeriod": "3600s",
|
||||
"targetAxis": "Y1"
|
||||
}
|
||||
}
|
||||
],
|
||||
"timeshiftDuration": "0s",
|
||||
"yAxis": {
|
||||
"label": "y1Axis",
|
||||
"scale": "LINEAR"
|
||||
},
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"yPos": 12
|
||||
},
|
||||
{
|
||||
"yPos": 8,
|
||||
"width": 6,
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "number_of_instances_utilization",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
},
|
||||
"dataSets": [
|
||||
{
|
||||
"minAlignmentPeriod": "3600s",
|
||||
"plotType": "LINE",
|
||||
"targetAxis": "Y1",
|
||||
"timeSeriesQuery": {
|
||||
"timeSeriesFilter": {
|
||||
"filter": "metric.type=\"custom.googleapis.com/number_of_instances_utilization\" resource.type=\"global\"",
|
||||
"aggregation": {
|
||||
"alignmentPeriod": "3600s",
|
||||
"perSeriesAligner": "ALIGN_NEXT_OLDER"
|
||||
},
|
||||
"filter": "metric.type=\"custom.googleapis.com/number_of_instances_utilization\" resource.type=\"global\"",
|
||||
"secondaryAggregation": {
|
||||
"alignmentPeriod": "60s",
|
||||
"perSeriesAligner": "ALIGN_MEAN"
|
||||
}
|
||||
}
|
||||
},
|
||||
"plotType": "LINE",
|
||||
"minAlignmentPeriod": "3600s",
|
||||
"targetAxis": "Y1"
|
||||
}
|
||||
}
|
||||
],
|
||||
"timeshiftDuration": "0s",
|
||||
"yAxis": {
|
||||
"label": "y1Axis",
|
||||
"scale": "LINEAR"
|
||||
},
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"yPos": 8
|
||||
},
|
||||
{
|
||||
"xPos": 6,
|
||||
"yPos": 4,
|
||||
"width": 6,
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "number_of_vpc_peerings_utilization",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
},
|
||||
"dataSets": [
|
||||
{
|
||||
"minAlignmentPeriod": "3600s",
|
||||
"plotType": "LINE",
|
||||
"targetAxis": "Y1",
|
||||
"timeSeriesQuery": {
|
||||
"timeSeriesFilter": {
|
||||
"filter": "metric.type=\"custom.googleapis.com/number_of_vpc_peerings_utilization\" resource.type=\"global\"",
|
||||
"aggregation": {
|
||||
"alignmentPeriod": "3600s",
|
||||
"perSeriesAligner": "ALIGN_NEXT_OLDER"
|
||||
},
|
||||
"filter": "metric.type=\"custom.googleapis.com/number_of_vpc_peerings_utilization\" resource.type=\"global\"",
|
||||
"secondaryAggregation": {
|
||||
"alignmentPeriod": "60s",
|
||||
"perSeriesAligner": "ALIGN_MEAN"
|
||||
}
|
||||
}
|
||||
},
|
||||
"plotType": "LINE",
|
||||
"minAlignmentPeriod": "3600s",
|
||||
"targetAxis": "Y1"
|
||||
}
|
||||
}
|
||||
],
|
||||
"timeshiftDuration": "0s",
|
||||
"yAxis": {
|
||||
"label": "y1Axis",
|
||||
"scale": "LINEAR"
|
||||
},
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"xPos": 6,
|
||||
"yPos": 4
|
||||
},
|
||||
{
|
||||
"yPos": 4,
|
||||
"width": 6,
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "number_of_active_vpc_peerings_utilization",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
},
|
||||
"dataSets": [
|
||||
{
|
||||
"minAlignmentPeriod": "3600s",
|
||||
"plotType": "LINE",
|
||||
"targetAxis": "Y1",
|
||||
"timeSeriesQuery": {
|
||||
"timeSeriesFilter": {
|
||||
"filter": "metric.type=\"custom.googleapis.com/number_of_active_vpc_peerings_utilization\" resource.type=\"global\"",
|
||||
"aggregation": {
|
||||
"alignmentPeriod": "3600s",
|
||||
"perSeriesAligner": "ALIGN_NEXT_OLDER"
|
||||
},
|
||||
"filter": "metric.type=\"custom.googleapis.com/number_of_active_vpc_peerings_utilization\" resource.type=\"global\"",
|
||||
"secondaryAggregation": {
|
||||
"alignmentPeriod": "60s",
|
||||
"perSeriesAligner": "ALIGN_INTERPOLATE"
|
||||
}
|
||||
}
|
||||
},
|
||||
"plotType": "LINE",
|
||||
"minAlignmentPeriod": "3600s",
|
||||
"targetAxis": "Y1"
|
||||
}
|
||||
}
|
||||
],
|
||||
"timeshiftDuration": "0s",
|
||||
"yAxis": {
|
||||
"label": "y1Axis",
|
||||
"scale": "LINEAR"
|
||||
},
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"yPos": 4
|
||||
},
|
||||
{
|
||||
"yPos": 16,
|
||||
"width": 6,
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "subnet_IP_ranges_ppg_utilization",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
},
|
||||
"dataSets": [
|
||||
{
|
||||
"minAlignmentPeriod": "3600s",
|
||||
"plotType": "LINE",
|
||||
"targetAxis": "Y1",
|
||||
"timeSeriesQuery": {
|
||||
"timeSeriesFilter": {
|
||||
"filter": "metric.type=\"custom.googleapis.com/number_of_subnet_IP_ranges_ppg_utilization\" resource.type=\"global\"",
|
||||
"aggregation": {
|
||||
"alignmentPeriod": "3600s",
|
||||
"perSeriesAligner": "ALIGN_NEXT_OLDER"
|
||||
},
|
||||
"filter": "metric.type=\"custom.googleapis.com/number_of_subnet_IP_ranges_ppg_utilization\" resource.type=\"global\"",
|
||||
"secondaryAggregation": {
|
||||
"alignmentPeriod": "3600s",
|
||||
"perSeriesAligner": "ALIGN_MEAN"
|
||||
}
|
||||
}
|
||||
},
|
||||
"plotType": "LINE",
|
||||
"minAlignmentPeriod": "3600s",
|
||||
"targetAxis": "Y1"
|
||||
}
|
||||
}
|
||||
],
|
||||
"timeshiftDuration": "0s",
|
||||
"yAxis": {
|
||||
"label": "y1Axis",
|
||||
"scale": "LINEAR"
|
||||
},
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"yPos": 16
|
||||
},
|
||||
{
|
||||
"xPos": 6,
|
||||
"width": 6,
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "internal_forwarding_rules_l4_ppg_utilization",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
},
|
||||
"dataSets": [
|
||||
{
|
||||
"minAlignmentPeriod": "3600s",
|
||||
"plotType": "LINE",
|
||||
"targetAxis": "Y1",
|
||||
"timeSeriesQuery": {
|
||||
"timeSeriesFilter": {
|
||||
"filter": "metric.type=\"custom.googleapis.com/internal_forwarding_rules_l4_ppg_utilization\" resource.type=\"global\"",
|
||||
"aggregation": {
|
||||
"alignmentPeriod": "3600s",
|
||||
"perSeriesAligner": "ALIGN_NEXT_OLDER"
|
||||
},
|
||||
"filter": "metric.type=\"custom.googleapis.com/internal_forwarding_rules_l4_ppg_utilization\" resource.type=\"global\"",
|
||||
"secondaryAggregation": {
|
||||
"alignmentPeriod": "3600s",
|
||||
"perSeriesAligner": "ALIGN_MEAN"
|
||||
}
|
||||
}
|
||||
},
|
||||
"plotType": "LINE",
|
||||
"minAlignmentPeriod": "3600s",
|
||||
"targetAxis": "Y1"
|
||||
}
|
||||
}
|
||||
],
|
||||
"timeshiftDuration": "0s",
|
||||
"yAxis": {
|
||||
"label": "y1Axis",
|
||||
"scale": "LINEAR"
|
||||
},
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"xPos": 6
|
||||
},
|
||||
{
|
||||
"xPos": 6,
|
||||
"yPos": 12,
|
||||
"width": 6,
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "internal_forwarding_rules_l7_ppg_utilization",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
},
|
||||
"dataSets": [
|
||||
{
|
||||
"minAlignmentPeriod": "3600s",
|
||||
"plotType": "LINE",
|
||||
"targetAxis": "Y1",
|
||||
"timeSeriesQuery": {
|
||||
"timeSeriesFilter": {
|
||||
"filter": "metric.type=\"custom.googleapis.com/internal_forwarding_rules_l7_ppg_utilization\" resource.type=\"global\"",
|
||||
"aggregation": {
|
||||
"alignmentPeriod": "3600s",
|
||||
"perSeriesAligner": "ALIGN_NEXT_OLDER"
|
||||
},
|
||||
"filter": "metric.type=\"custom.googleapis.com/internal_forwarding_rules_l7_ppg_utilization\" resource.type=\"global\"",
|
||||
"secondaryAggregation": {
|
||||
"alignmentPeriod": "60s",
|
||||
"perSeriesAligner": "ALIGN_MEAN"
|
||||
}
|
||||
}
|
||||
},
|
||||
"plotType": "LINE",
|
||||
"minAlignmentPeriod": "3600s",
|
||||
"targetAxis": "Y1"
|
||||
}
|
||||
}
|
||||
],
|
||||
"timeshiftDuration": "0s",
|
||||
"yAxis": {
|
||||
"label": "y1Axis",
|
||||
"scale": "LINEAR"
|
||||
},
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"xPos": 6,
|
||||
"yPos": 12
|
||||
},
|
||||
{
|
||||
"xPos": 6,
|
||||
"yPos": 8,
|
||||
"width": 6,
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "number_of_instances_ppg_utilization",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
},
|
||||
"dataSets": [
|
||||
{
|
||||
"minAlignmentPeriod": "3600s",
|
||||
"plotType": "LINE",
|
||||
"targetAxis": "Y1",
|
||||
"timeSeriesQuery": {
|
||||
"timeSeriesFilter": {
|
||||
"filter": "metric.type=\"custom.googleapis.com/number_of_instances_ppg_utilization\" resource.type=\"global\"",
|
||||
"aggregation": {
|
||||
"alignmentPeriod": "3600s",
|
||||
"perSeriesAligner": "ALIGN_NEXT_OLDER"
|
||||
}
|
||||
},
|
||||
"filter": "metric.type=\"custom.googleapis.com/number_of_instances_ppg_utilization\" resource.type=\"global\""
|
||||
}
|
||||
},
|
||||
"plotType": "LINE",
|
||||
"minAlignmentPeriod": "3600s",
|
||||
"targetAxis": "Y1"
|
||||
}
|
||||
}
|
||||
],
|
||||
"timeshiftDuration": "0s",
|
||||
"yAxis": {
|
||||
"label": "y1Axis",
|
||||
"scale": "LINEAR"
|
||||
},
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"xPos": 6,
|
||||
"yPos": 8
|
||||
},
|
||||
{
|
||||
"xPos": 6,
|
||||
"yPos": 16,
|
||||
"width": 6,
|
||||
"height": 4,
|
||||
"widget": {
|
||||
"title": "dynamic_routes_per_network_utilization",
|
||||
"xyChart": {
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
},
|
||||
"dataSets": [
|
||||
{
|
||||
"minAlignmentPeriod": "60s",
|
||||
"plotType": "LINE",
|
||||
"targetAxis": "Y1",
|
||||
"timeSeriesQuery": {
|
||||
"timeSeriesFilter": {
|
||||
"filter": "metric.type=\"custom.googleapis.com/dynamic_routes_per_network_utilization\" resource.type=\"global\"",
|
||||
"aggregation": {
|
||||
"alignmentPeriod": "60s",
|
||||
"perSeriesAligner": "ALIGN_MEAN"
|
||||
},
|
||||
"secondaryAggregation": {
|
||||
"alignmentPeriod": "60s"
|
||||
}
|
||||
"filter": "metric.type=\"custom.googleapis.com/dynamic_routes_per_network_utilization\" resource.type=\"global\""
|
||||
}
|
||||
},
|
||||
"plotType": "LINE",
|
||||
"minAlignmentPeriod": "60s",
|
||||
"targetAxis": "Y1"
|
||||
}
|
||||
}
|
||||
],
|
||||
"timeshiftDuration": "0s",
|
||||
"yAxis": {
|
||||
"label": "y1Axis",
|
||||
"scale": "LINEAR"
|
||||
},
|
||||
"chartOptions": {
|
||||
"mode": "COLOR"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"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",
|
||||
"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/dynamic_routes_per_peering_group_utilization\" resource.type=\"global\"",
|
||||
"secondaryAggregation": {
|
||||
"alignmentPeriod": "60s"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"timeshiftDuration": "0s",
|
||||
"yAxis": {
|
||||
"label": "y1Axis",
|
||||
"scale": "LINEAR"
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": 6,
|
||||
"xPos": 6,
|
||||
"yPos": 20
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"name": "projects/347834224817/dashboards/1bdcd06a-030d-4977-bf4b-f32231aa3b77"
|
||||
}
|
|
@ -15,8 +15,11 @@
|
|||
*/
|
||||
|
||||
locals {
|
||||
project_id_list = toset(var.monitored_projects_list)
|
||||
projects = join(",", local.project_id_list)
|
||||
project_ids = toset(var.monitored_projects_list)
|
||||
projects = join(",", local.project_ids)
|
||||
|
||||
folder_ids = toset(var.monitored_folders_list)
|
||||
folders = join(",", local.folder_ids)
|
||||
monitoring_project = var.monitoring_project_id == "" ? module.project-monitoring[0].project_id : var.monitoring_project_id
|
||||
}
|
||||
|
||||
|
@ -90,6 +93,7 @@ resource "google_cloud_scheduler_job" "job" {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
module "cloud-function" {
|
||||
source = "../../../modules/cloud-function"
|
||||
project_id = local.monitoring_project
|
||||
|
@ -116,11 +120,13 @@ module "cloud-function" {
|
|||
|
||||
environment_variables = {
|
||||
MONITORED_PROJECTS_LIST = local.projects
|
||||
MONITORED_FOLDERS_LIST = local.folders
|
||||
MONITORING_PROJECT_ID = local.monitoring_project
|
||||
ORGANIZATION_ID = var.organization_id
|
||||
}
|
||||
|
||||
service_account = module.service-account-function.email
|
||||
service_account = module.service-account-function.email
|
||||
ingress_settings = "ALLOW_INTERNAL_ONLY"
|
||||
|
||||
trigger_config = {
|
||||
event = "google.pubsub.topic.publish"
|
||||
|
|
|
@ -32,15 +32,20 @@ variable "prefix" {
|
|||
default = ""
|
||||
}
|
||||
|
||||
# TODO: support folder instead of a list of projects?
|
||||
variable "monitored_projects_list" {
|
||||
type = list(string)
|
||||
description = "ID of the projects to be monitored (where limits and quotas data will be pulled)"
|
||||
}
|
||||
|
||||
variable "monitored_folders_list" {
|
||||
type = list(string)
|
||||
description = "ID of the projects to be monitored (where limits and quotas data will be pulled)"
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "schedule_cron" {
|
||||
description = "Cron format schedule to run the Cloud Function. Default is every 5 minutes."
|
||||
default = "*/5 * * * *"
|
||||
default = "*/10 * * * *"
|
||||
}
|
||||
|
||||
variable "project_monitoring_services" {
|
||||
|
|
Loading…
Reference in New Issue