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.
|
|
|
|
#
|
|
|
|
|
|
|
|
from code import interact
|
|
|
|
from collections import defaultdict
|
|
|
|
from google.protobuf import field_mask_pb2
|
|
|
|
from googleapiclient import errors
|
|
|
|
import http
|
|
|
|
|
|
|
|
|
|
|
|
def get_subnet_ranges_dict(config: dict):
|
|
|
|
'''
|
|
|
|
Calls the Asset Inventory API to get all Subnet ranges under the GCP organization.
|
|
|
|
|
|
|
|
Parameters:
|
|
|
|
config (dict): The dict containing config like clients and limits
|
|
|
|
Returns:
|
|
|
|
subnet_range_dict (dictionary of string: int): Keys are the network links and values are the number of subnet ranges per network.
|
|
|
|
'''
|
|
|
|
|
|
|
|
subnet_range_dict = defaultdict(int)
|
|
|
|
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,
|
2022-10-19 09:59:28 -07:00
|
|
|
"page_size": config["page_size"],
|
2022-04-28 02:48:48 -07:00
|
|
|
})
|
|
|
|
for resource in response:
|
|
|
|
ranges = 0
|
|
|
|
network_link = None
|
|
|
|
|
|
|
|
for versioned in resource.versioned_resources:
|
|
|
|
for field_name, field_value in versioned.resource.items():
|
|
|
|
if field_name == "network":
|
|
|
|
network_link = field_value
|
|
|
|
ranges += 1
|
|
|
|
if field_name == "secondaryIpRanges":
|
|
|
|
for range in field_value:
|
|
|
|
ranges += 1
|
|
|
|
|
|
|
|
if network_link in subnet_range_dict:
|
|
|
|
subnet_range_dict[network_link] += ranges
|
|
|
|
else:
|
|
|
|
subnet_range_dict[network_link] = ranges
|
|
|
|
|
|
|
|
return subnet_range_dict
|
|
|
|
|
|
|
|
|
|
|
|
def get_networks(config, project_id):
|
|
|
|
'''
|
|
|
|
Returns a dictionary of all networks in a project.
|
|
|
|
|
|
|
|
Parameters:
|
|
|
|
config (dict): The dict containing config like clients and limits
|
|
|
|
project_id (string): Project ID for the project containing the networks.
|
|
|
|
Returns:
|
|
|
|
network_dict (dictionary of string: string): Contains the project_id, network_name(s) and network_id(s)
|
|
|
|
'''
|
|
|
|
request = config["clients"]["discovery_client"].networks().list(
|
|
|
|
project=project_id)
|
|
|
|
response = request.execute()
|
|
|
|
network_dict = []
|
|
|
|
if 'items' in response:
|
|
|
|
for network in response['items']:
|
|
|
|
network_name = network['name']
|
|
|
|
network_id = network['id']
|
|
|
|
self_link = network['selfLink']
|
|
|
|
d = {
|
|
|
|
'project_id': project_id,
|
|
|
|
'network_name': network_name,
|
|
|
|
'network_id': network_id,
|
|
|
|
'self_link': self_link
|
|
|
|
}
|
|
|
|
network_dict.append(d)
|
|
|
|
return network_dict
|
|
|
|
|
|
|
|
|
|
|
|
def get_network_id(config, project_id, network_name):
|
|
|
|
'''
|
|
|
|
Returns the network_id for a specific project / network name.
|
|
|
|
|
|
|
|
Parameters:
|
|
|
|
config (dict): The dict containing config like clients and limits
|
|
|
|
project_id (string): Project ID for the project containing the networks.
|
|
|
|
network_name (string): Name of the network
|
|
|
|
Returns:
|
|
|
|
network_id (int): Network ID.
|
|
|
|
'''
|
|
|
|
request = config["clients"]["discovery_client"].networks().list(
|
|
|
|
project=project_id)
|
|
|
|
try:
|
|
|
|
response = request.execute()
|
|
|
|
except errors.HttpError as err:
|
|
|
|
# TODO: log proper warning
|
|
|
|
if err.resp.status == http.HTTPStatus.FORBIDDEN:
|
|
|
|
print(
|
|
|
|
f"Warning: error reading networks for {project_id}. " +
|
|
|
|
f"This can happen if you don't have permissions on the project, for example if the project is in another organization or a Google managed project"
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
print(f"Warning: error reading networks for {project_id}: {err}")
|
|
|
|
return 0
|
|
|
|
|
|
|
|
network_id = 0
|
|
|
|
|
|
|
|
if 'items' in response:
|
|
|
|
for network in response['items']:
|
|
|
|
if network['name'] == network_name:
|
|
|
|
network_id = network['id']
|
|
|
|
break
|
|
|
|
|
|
|
|
if network_id == 0:
|
|
|
|
print(f"Error: network_id not found for {network_name} in {project_id}")
|
|
|
|
|
|
|
|
return network_id
|
|
|
|
|
|
|
|
|
|
|
|
def get_limit_network(network_dict, network_link, quota_limit, limit_dict):
|
|
|
|
'''
|
|
|
|
Returns limit for a specific network and metric, using the GCP quota metrics or the values in the yaml file if not found.
|
|
|
|
|
|
|
|
Parameters:
|
|
|
|
network_dict (dictionary of string: string): Contains network information.
|
|
|
|
network_link (string): Contains network link
|
|
|
|
quota_limit (list of dictionaries of string: string): Current quota limit for all networks in that project.
|
|
|
|
limit_dict (dictionary of string:int): Dictionary with the network link as key and the limit as value
|
|
|
|
Returns:
|
|
|
|
limit (int): Current limit for that network.
|
|
|
|
'''
|
|
|
|
if quota_limit:
|
|
|
|
for net in quota_limit:
|
|
|
|
if net['network_id'] == network_dict['network_id']:
|
|
|
|
return net['value']
|
|
|
|
|
|
|
|
if network_link in limit_dict:
|
|
|
|
return limit_dict[network_link]
|
|
|
|
else:
|
|
|
|
if 'default_value' in limit_dict:
|
|
|
|
return limit_dict['default_value']
|
|
|
|
else:
|
|
|
|
print(f"Error: Couldn't find limit for {network_link}")
|
|
|
|
|
|
|
|
return 0
|