2022-04-28 02:48:48 -07:00
|
|
|
#
|
|
|
|
# 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.
|
|
|
|
#
|
|
|
|
|
2022-10-10 13:06:57 -07:00
|
|
|
import re
|
2022-10-10 06:53:14 -07:00
|
|
|
import time
|
|
|
|
|
2022-04-28 02:48:48 -07:00
|
|
|
from collections import defaultdict
|
2022-10-10 13:06:57 -07:00
|
|
|
from google.protobuf import field_mask_pb2
|
2022-04-28 02:48:48 -07:00
|
|
|
from . import metrics, networks, limits, peerings, routers
|
|
|
|
|
|
|
|
|
|
|
|
def get_routes_for_router(config, project_id, router_region, router_name):
|
|
|
|
'''
|
|
|
|
Returns the same of dynamic routes learned by a specific Cloud Router instance
|
|
|
|
|
|
|
|
Parameters:
|
|
|
|
config (dict): The dict containing config like clients and limits
|
|
|
|
project_id (string): Project ID for the project containing the Cloud Router.
|
|
|
|
router_region (string): GCP region for the Cloud Router.
|
|
|
|
router_name (string): Cloud Router name.
|
|
|
|
Returns:
|
|
|
|
sum_routes (int): Number of dynamic routes learned by the Cloud Router.
|
|
|
|
'''
|
|
|
|
request = config["clients"]["discovery_client"].routers().getRouterStatus(
|
|
|
|
project=project_id, region=router_region, router=router_name)
|
|
|
|
response = request.execute()
|
|
|
|
|
|
|
|
sum_routes = 0
|
|
|
|
|
|
|
|
if 'result' in response:
|
|
|
|
if 'bgpPeerStatus' in response['result']:
|
|
|
|
for peer in response['result']['bgpPeerStatus']:
|
|
|
|
sum_routes += peer['numLearnedRoutes']
|
|
|
|
|
|
|
|
return sum_routes
|
|
|
|
|
|
|
|
|
|
|
|
def get_routes_for_network(config, network_link, project_id, routers_dict):
|
|
|
|
'''
|
|
|
|
Returns a the number of dynamic routes for a given network
|
|
|
|
|
|
|
|
Parameters:
|
|
|
|
config (dict): The dict containing config like clients and limits
|
|
|
|
network_link (string): Network self link.
|
|
|
|
project_id (string): Project ID containing the network.
|
|
|
|
routers_dict (dictionary of string: list of string): Dictionary with key as network link and value as list of router links.
|
|
|
|
Returns:
|
|
|
|
sum_routes (int): Number of routes in that network.
|
|
|
|
'''
|
|
|
|
sum_routes = 0
|
|
|
|
|
|
|
|
if network_link in routers_dict:
|
|
|
|
for router_link in routers_dict[network_link]:
|
|
|
|
# Router link is using the following format:
|
|
|
|
# 'https://www.googleapis.com/compute/v1/projects/PROJECT_ID/regions/REGION/routers/ROUTER_NAME'
|
|
|
|
start = router_link.find("/regions/") + len("/regions/")
|
|
|
|
end = router_link.find("/routers/")
|
|
|
|
router_region = router_link[start:end]
|
|
|
|
router_name = router_link.split('/routers/')[1]
|
|
|
|
routes = get_routes_for_router(config, project_id, router_region,
|
|
|
|
router_name)
|
|
|
|
|
|
|
|
sum_routes += routes
|
|
|
|
|
|
|
|
return sum_routes
|
|
|
|
|
|
|
|
|
|
|
|
def get_dynamic_routes(config, metrics_dict, limits_dict):
|
|
|
|
'''
|
|
|
|
Writes all dynamic routes per VPC to custom metrics.
|
|
|
|
|
|
|
|
Parameters:
|
|
|
|
config (dict): The dict containing config like clients and limits
|
|
|
|
metrics_dict (dictionary of dictionary of string: string): metrics names and descriptions.
|
|
|
|
limits_dict (dictionary of string: int): key is network link (or 'default_value') and value is the limit for that network
|
|
|
|
Returns:
|
|
|
|
dynamic_routes_dict (dictionary of string: int): key is network link and value is the number of dynamic routes for that network
|
|
|
|
'''
|
|
|
|
routers_dict = routers.get_routers(config)
|
|
|
|
dynamic_routes_dict = defaultdict(int)
|
|
|
|
|
2022-10-10 06:53:14 -07:00
|
|
|
timestamp = time.time()
|
|
|
|
for project in config["monitored_projects"]:
|
|
|
|
network_dict = networks.get_networks(config, project)
|
2022-04-28 02:48:48 -07:00
|
|
|
|
2022-10-10 06:53:14 -07:00
|
|
|
for net in network_dict:
|
|
|
|
sum_routes = get_routes_for_network(config, net['self_link'], project,
|
|
|
|
routers_dict)
|
|
|
|
dynamic_routes_dict[net['self_link']] = sum_routes
|
2022-04-28 02:48:48 -07:00
|
|
|
|
2022-10-10 06:53:14 -07:00
|
|
|
if net['self_link'] in limits_dict:
|
|
|
|
limit = limits_dict[net['self_link']]
|
2022-04-28 02:48:48 -07:00
|
|
|
else:
|
|
|
|
if 'default_value' in limits_dict:
|
|
|
|
limit = limits_dict['default_value']
|
|
|
|
else:
|
|
|
|
print("Error: couldn't find limit for dynamic routes.")
|
|
|
|
break
|
|
|
|
|
|
|
|
utilization = sum_routes / limit
|
2022-10-10 06:53:14 -07:00
|
|
|
metric_labels = {'project': project, 'network_name': net['network_name']}
|
|
|
|
metrics.append_data_to_series_buffer(
|
|
|
|
config, metrics_dict["metrics_per_network"]
|
|
|
|
["dynamic_routes_per_network"]["usage"]["name"], sum_routes,
|
|
|
|
metric_labels, timestamp=timestamp)
|
|
|
|
metrics.append_data_to_series_buffer(
|
|
|
|
config, metrics_dict["metrics_per_network"]
|
|
|
|
["dynamic_routes_per_network"]["limit"]["name"], limit, metric_labels,
|
|
|
|
timestamp=timestamp)
|
|
|
|
metrics.append_data_to_series_buffer(
|
|
|
|
config, metrics_dict["metrics_per_network"]
|
|
|
|
["dynamic_routes_per_network"]["utilization"]["name"], utilization,
|
|
|
|
metric_labels, timestamp=timestamp)
|
|
|
|
|
|
|
|
print("Buffered metrics for dynamic routes for VPCs in project", project)
|
2022-04-28 02:48:48 -07:00
|
|
|
|
|
|
|
return dynamic_routes_dict
|
|
|
|
|
|
|
|
|
|
|
|
def get_dynamic_routes_ppg(config, metric_dict, usage_dict, limit_dict):
|
|
|
|
'''
|
|
|
|
This function gets the usage, limit and utilization for the dynamic routes per VPC peering group.
|
|
|
|
|
|
|
|
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
|
|
|
|
usage_dict (dictionnary of string:int): Dictionary with the network link as key and the number of resources as value
|
|
|
|
limit_dict (dictionary of string:int): Dictionary with the network link as key and the limit as value
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
'''
|
|
|
|
for project in config["monitored_projects"]:
|
|
|
|
network_dict_list = peerings.gather_peering_data(config, project)
|
|
|
|
|
|
|
|
for network_dict in network_dict_list:
|
|
|
|
network_link = f"https://www.googleapis.com/compute/v1/projects/{project}/global/networks/{network_dict['network_name']}"
|
|
|
|
|
|
|
|
limit = limits.get_ppg(network_link, limit_dict)
|
|
|
|
|
|
|
|
usage = 0
|
|
|
|
if network_link in usage_dict:
|
|
|
|
usage = usage_dict[network_link]
|
|
|
|
|
|
|
|
# Here we add usage and limit to the network dictionary
|
|
|
|
network_dict["usage"] = usage
|
|
|
|
network_dict["limit"] = limit
|
|
|
|
|
|
|
|
# For every peered network, get usage and limits
|
|
|
|
for peered_network_dict in network_dict['peerings']:
|
|
|
|
peered_network_link = f"https://www.googleapis.com/compute/v1/projects/{peered_network_dict['project_id']}/global/networks/{peered_network_dict['network_name']}"
|
|
|
|
peered_usage = 0
|
|
|
|
if peered_network_link in usage_dict:
|
|
|
|
peered_usage = usage_dict[peered_network_link]
|
|
|
|
|
|
|
|
peered_limit = limits.get_ppg(peered_network_link, limit_dict)
|
|
|
|
|
|
|
|
# Here we add usage and limit to the peered network dictionary
|
|
|
|
peered_network_dict["usage"] = peered_usage
|
|
|
|
peered_network_dict["limit"] = peered_limit
|
|
|
|
|
|
|
|
limits.count_effective_limit(config, project, network_dict,
|
|
|
|
metric_dict["usage"]["name"],
|
|
|
|
metric_dict["limit"]["name"],
|
|
|
|
metric_dict["utilization"]["name"],
|
|
|
|
limit_dict)
|
|
|
|
print(
|
|
|
|
f"Wrote {metric_dict['usage']['name']} for peering group {network_dict['network_name']} in {project}"
|
|
|
|
)
|
2022-10-10 13:06:57 -07:00
|
|
|
|
|
|
|
|
|
|
|
def get_static_routes_vpc(config, metrics_dict, project_quotas_dict):
|
|
|
|
'''
|
|
|
|
LOREM
|
|
|
|
|
|
|
|
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
|
|
|
|
usage_dict (dictionnary of string:int): Dictionary with the network link as key and the number of resources as value
|
|
|
|
project_quotas_dict (dictionary of string:int): Dictionary with the network link as key and the limit as value.
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
'''
|
|
|
|
routes_per_vpc_dict = defaultdict()
|
|
|
|
usage_dict = defaultdict()
|
|
|
|
|
|
|
|
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/Route"],
|
|
|
|
"read_mask": read_mask,
|
|
|
|
})
|
|
|
|
|
|
|
|
timestamp = time.time()
|
|
|
|
for resource in response:
|
|
|
|
for versioned in resource.versioned_resources:
|
|
|
|
static_route = dict()
|
|
|
|
for field_name, field_value in versioned.resource.items():
|
|
|
|
static_route[field_name] = field_value
|
|
|
|
static_route["project_id"] = re.search("\/([^\/]*)(\/[^\/]*){3}$",
|
|
|
|
static_route["network"]).group(1)
|
|
|
|
static_route["network_name"] = re.search("\/([^\/]*)$",
|
|
|
|
static_route["network"]).group(1)
|
|
|
|
|
|
|
|
#exclude default vpc and peering routes
|
|
|
|
if "nextHopPeering" not in static_route and "nextHopNetwork" not in static_route:
|
|
|
|
if static_route["project_id"] not in routes_per_vpc_dict:
|
|
|
|
routes_per_vpc_dict[static_route["project_id"]] = dict()
|
|
|
|
if static_route["network_name"] not in routes_per_vpc_dict[
|
|
|
|
static_route["project_id"]]:
|
|
|
|
routes_per_vpc_dict[static_route["project_id"]][
|
|
|
|
static_route["network_name"]] = dict()
|
|
|
|
|
|
|
|
if static_route["destRange"] not in routes_per_vpc_dict[
|
|
|
|
static_route["project_id"]][static_route["network_name"]]:
|
|
|
|
routes_per_vpc_dict[static_route["project_id"]][
|
|
|
|
static_route["network_name"]][static_route["destRange"]] = {}
|
|
|
|
if "usage" not in routes_per_vpc_dict[static_route["project_id"]][
|
|
|
|
static_route["network_name"]]:
|
|
|
|
routes_per_vpc_dict[static_route["project_id"]][
|
|
|
|
static_route["network_name"]]["usage"] = 0
|
|
|
|
routes_per_vpc_dict[static_route["project_id"]][
|
|
|
|
static_route["network_name"]]["usage"] = routes_per_vpc_dict[
|
|
|
|
static_route["project_id"]][
|
|
|
|
static_route["network_name"]]["usage"] + 1
|
|
|
|
|
|
|
|
for project_id in routes_per_vpc_dict:
|
|
|
|
current_quota_limit = project_quotas_dict[project_id]['global']["routes"][
|
|
|
|
"limit"]
|
|
|
|
if current_quota_limit is None:
|
|
|
|
print(
|
|
|
|
f"Could not determine static routes metric for projects/{project_id} due to missing quotas"
|
|
|
|
)
|
|
|
|
continue
|
|
|
|
for network_name in routes_per_vpc_dict[project_id]:
|
|
|
|
metric_labels = {"project": project_id, "network_name": network_name}
|
|
|
|
metrics.append_data_to_series_buffer(
|
|
|
|
config, metrics_dict["metrics_per_network"]
|
|
|
|
["static_routes_per_network"]["usage"]["name"],
|
|
|
|
routes_per_vpc_dict[project_id][network_name]["usage"], metric_labels,
|
|
|
|
timestamp=timestamp)
|
|
|
|
|
|
|
|
# limit and utilization are calculted by project
|
|
|
|
metric_labels = {"project": project_id}
|
|
|
|
metrics.append_data_to_series_buffer(
|
|
|
|
config, metrics_dict["metrics_per_network"]["static_routes_per_network"]
|
|
|
|
["limit"]["name"], current_quota_limit, metric_labels,
|
|
|
|
timestamp=timestamp)
|
|
|
|
metrics.append_data_to_series_buffer(
|
|
|
|
config, metrics_dict["metrics_per_network"]["static_routes_per_network"]
|
|
|
|
["utilization"]["name"],
|
|
|
|
routes_per_vpc_dict[project_id][network_name]["usage"] /
|
|
|
|
current_quota_limit, metric_labels, timestamp=timestamp)
|
|
|
|
|
|
|
|
return
|