diff --git a/CHANGELOG.md b/CHANGELOG.md index ac0af7753..8f3be0538 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file. - add support for IAM to `data-catalog-policy-tag` module - add support for IAM additive to `folder` module, fixes #580 - **incompatible change** the variable for PSA ranges in the `net-vpc` module has changed to support configuring peering routes +- optionally turn off gcplogs driver in COS modules **FAST** diff --git a/examples/cloud-operations/network-dashboard/README.md b/examples/cloud-operations/network-dashboard/README.md index ee3167cc4..2f958375e 100644 --- a/examples/cloud-operations/network-dashboard/README.md +++ b/examples/cloud-operations/network-dashboard/README.md @@ -27,7 +27,6 @@ A dashboard called "quotas-utilization" should be created. The Cloud Function runs every 5 minutes by default so you should start getting some data points after a few minutes. You can change this frequency by modifying the "schedule_cron" variable in variables.tf. -Note that we are using Google defined metrics that are populated only once a day so you might need to wait up to one day for some metrics. Once done testing, you can clean up resources by running `terraform destroy`. @@ -43,4 +42,13 @@ The Cloud Function currently tracks usage, limit and utilization of: - internal forwarding rules for internal L4 load balancers per VPC peering group - internal forwarding rules for internal L7 load balancers per VPC peering group -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. \ No newline at end of file +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. + +## Next steps and ideas +In a future release, we could support: +- Static routes per VPC / per VPC peering group +- Dynamic routes per VPC / 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. \ No newline at end of file diff --git a/examples/cloud-operations/network-dashboard/cloud-function/main.py b/examples/cloud-operations/network-dashboard/cloud-function/main.py index 0b1e3dff2..8875ff8d6 100644 --- a/examples/cloud-operations/network-dashboard/cloud-function/main.py +++ b/examples/cloud-operations/network-dashboard/cloud-function/main.py @@ -17,10 +17,15 @@ import os import time import yaml +from collections import defaultdict from google.api import metric_pb2 as ga_metric -from google.cloud import monitoring_v3 +from google.api_core import protobuf_helpers +from google.cloud import monitoring_v3, asset_v1 +from google.protobuf import field_mask_pb2 from googleapiclient import discovery +# Organization ID containing the projects to be monitored +ORGANIZATION_ID = os.environ.get("ORGANIZATION_ID") # list of projects from which function will get quotas information MONITORED_PROJECTS_LIST = os.environ.get("MONITORED_PROJECTS_LIST").split(",") # project where the metrics and dahsboards will be created @@ -28,25 +33,11 @@ MONITORING_PROJECT_ID = os.environ.get("MONITORING_PROJECT_ID") MONITORING_PROJECT_LINK = f"projects/{MONITORING_PROJECT_ID}" service = discovery.build('compute', 'v1') -# DEFAULT LIMITS: -LIMIT_INSTANCES = os.environ.get("LIMIT_INSTANCES").split(",") -LIMIT_INSTANCES_PPG = os.environ.get("LIMIT_INSTANCES_PPG").split(",") -LIMIT_L4 = os.environ.get("LIMIT_L4").split(",") -LIMIT_L4_PPG = os.environ.get("LIMIT_L4_PPG").split(",") -LIMIT_L7 = os.environ.get("LIMIT_L7").split(",") -LIMIT_L7_PPG = os.environ.get("LIMIT_L7_PPG").split(",") -LIMIT_SUBNETS = os.environ.get("LIMIT_SUBNETS").split(",") -LIMIT_VPC_PEER = os.environ.get("LIMIT_VPC_PEER").split(",") - # Existing GCP metrics per network GCE_INSTANCES_LIMIT_METRIC = "compute.googleapis.com/quota/instances_per_vpc_network/limit" -GCE_INSTANCES_USAGE_METRIC = "compute.googleapis.com/quota/instances_per_vpc_network/usage" L4_FORWARDING_RULES_LIMIT_METRIC = "compute.googleapis.com/quota/internal_lb_forwarding_rules_per_vpc_network/limit" -L4_FORWARDING_RULES_USAGE_METRIC = "compute.googleapis.com/quota/internal_lb_forwarding_rules_per_vpc_network/usage" L7_FORWARDING_RULES_LIMIT_METRIC = "compute.googleapis.com/quota/internal_managed_forwarding_rules_per_vpc_network/limit" -L7_FORWARDING_RULES_USAGE_METRIC = "compute.googleapis.com/quota/internal_managed_forwarding_rules_per_vpc_network/usage" SUBNET_RANGES_LIMIT_METRIC = "compute.googleapis.com/quota/subnet_ranges_per_vpc_network/limit" -SUBNET_RANGES_USAGE_METRIC = "compute.googleapis.com/quota/subnet_ranges_per_vpc_network/usage" def main(event, context): @@ -59,39 +50,200 @@ def main(event, context): Returns: 'Function executed successfully' ''' + metrics_dict, limits_dict = create_metrics() - metrics_dict = create_metrics() + # Asset inventory queries + gce_instance_dict = get_gce_instance_dict() + l4_forwarding_rules_dict = get_l4_forwarding_rules_dict() + l7_forwarding_rules_dict = get_l7_forwarding_rules_dict() + subnet_range_dict = get_subnet_ranges_dict() # Per Network metrics - get_gce_instances_data(metrics_dict) - get_l4_forwarding_rules_data(metrics_dict) - get_vpc_peering_data(metrics_dict) + get_gce_instances_data(metrics_dict, gce_instance_dict, + limits_dict['number_of_instances_limit']) + get_l4_forwarding_rules_data( + metrics_dict, l4_forwarding_rules_dict, + limits_dict['internal_forwarding_rules_l4_limit']) + get_vpc_peering_data(metrics_dict, + limits_dict['number_of_vpc_peerings_limit']) get_pgg_data( metrics_dict["metrics_per_peering_group"]["instance_per_peering_group"], - GCE_INSTANCES_USAGE_METRIC, GCE_INSTANCES_LIMIT_METRIC, - LIMIT_INSTANCES_PPG) + gce_instance_dict, GCE_INSTANCES_LIMIT_METRIC, + limits_dict['number_of_instances_ppg_limit']) get_pgg_data( metrics_dict["metrics_per_peering_group"] - ["l4_forwarding_rules_per_peering_group"], - L4_FORWARDING_RULES_USAGE_METRIC, L4_FORWARDING_RULES_LIMIT_METRIC, - LIMIT_L4_PPG) + ["l4_forwarding_rules_per_peering_group"], l4_forwarding_rules_dict, + L4_FORWARDING_RULES_LIMIT_METRIC, + limits_dict['internal_forwarding_rules_l4_ppg_limit']) get_pgg_data( metrics_dict["metrics_per_peering_group"] - ["l7_forwarding_rules_per_peering_group"], - L7_FORWARDING_RULES_USAGE_METRIC, L7_FORWARDING_RULES_LIMIT_METRIC, - LIMIT_L7_PPG) + ["l7_forwarding_rules_per_peering_group"], l7_forwarding_rules_dict, + L7_FORWARDING_RULES_LIMIT_METRIC, + limits_dict['internal_forwarding_rules_l7_ppg_limit']) get_pgg_data( metrics_dict["metrics_per_peering_group"] - ["subnet_ranges_per_peering_group"], SUBNET_RANGES_USAGE_METRIC, - SUBNET_RANGES_LIMIT_METRIC, LIMIT_SUBNETS) + ["subnet_ranges_per_peering_group"], subnet_range_dict, + SUBNET_RANGES_LIMIT_METRIC, + limits_dict['number_of_subnet_IP_ranges_limit']) return 'Function executed successfully' +def get_l4_forwarding_rules_dict(): + ''' + Calls the Asset Inventory API to get all L4 Forwarding Rules under the GCP organization. + + Parameters: + None + Returns: + forwarding_rules_dict (dictionary of string: int): Keys are the network links and values are the number of Forwarding Rules per network. + ''' + client = asset_v1.AssetServiceClient() + + read_mask = field_mask_pb2.FieldMask() + read_mask.FromJsonString('name,versionedResources') + + forwarding_rules_dict = defaultdict(int) + + response = client.search_all_resources( + request={ + "scope": f"organizations/{ORGANIZATION_ID}", + "asset_types": ["compute.googleapis.com/ForwardingRule"], + "read_mask": read_mask, + }) + for resource in response: + internal = False + network_link = "" + for versioned in resource.versioned_resources: + for field_name, field_value in versioned.resource.items(): + if field_name == "loadBalancingScheme": + internal = (field_value == "INTERNAL") + if field_name == "network": + network_link = field_value + if internal: + if network_link in forwarding_rules_dict: + forwarding_rules_dict[network_link] += 1 + else: + forwarding_rules_dict[network_link] = 1 + + return forwarding_rules_dict + + +def get_l7_forwarding_rules_dict(): + ''' + Calls the Asset Inventory API to get all L7 Forwarding Rules under the GCP organization. + + Parameters: + None + Returns: + forwarding_rules_dict (dictionary of string: int): Keys are the network links and values are the number of Forwarding Rules per network. + ''' + client = asset_v1.AssetServiceClient() + + read_mask = field_mask_pb2.FieldMask() + read_mask.FromJsonString('name,versionedResources') + + forwarding_rules_dict = defaultdict(int) + + response = client.search_all_resources( + request={ + "scope": f"organizations/{ORGANIZATION_ID}", + "asset_types": ["compute.googleapis.com/ForwardingRule"], + "read_mask": read_mask, + }) + for resource in response: + internal = False + network_link = "" + for versioned in resource.versioned_resources: + for field_name, field_value in versioned.resource.items(): + if field_name == "loadBalancingScheme": + internal = (field_value == "INTERNAL_MANAGED") + if field_name == "network": + network_link = field_value + if internal: + if network_link in forwarding_rules_dict: + forwarding_rules_dict[network_link] += 1 + else: + forwarding_rules_dict[network_link] = 1 + + return forwarding_rules_dict + + +def get_gce_instance_dict(): + ''' + Calls the Asset Inventory API to get all GCE instances under the GCP organization. + + Parameters: + None + Returns: + gce_instance_dict (dictionary of string: int): Keys are the network links and values are the number of GCE Instances per network. + ''' + client = asset_v1.AssetServiceClient() + + gce_instance_dict = defaultdict(int) + + response = client.search_all_resources( + request={ + "scope": f"organizations/{ORGANIZATION_ID}", + "asset_types": ["compute.googleapis.com/Instance"], + }) + for resource in response: + for field_name, field_value in resource.additional_attributes.items(): + if field_name == "networkInterfaceNetworks": + for network in field_value: + if network in gce_instance_dict: + gce_instance_dict[network] += 1 + else: + gce_instance_dict[network] = 1 + + return gce_instance_dict + + +def get_subnet_ranges_dict(): + ''' + Calls the Asset Inventory API to get all Subnet ranges under the GCP organization. + + Parameters: + None + Returns: + subnet_range_dict (dictionary of string: int): Keys are the network links and values are the number of subnet ranges per network. + ''' + client = asset_v1.AssetServiceClient() + subnet_range_dict = defaultdict(int) + read_mask = field_mask_pb2.FieldMask() + read_mask.FromJsonString('name,versionedResources') + + response = client.search_all_resources( + request={ + "scope": f"organizations/{ORGANIZATION_ID}", + "asset_types": ["compute.googleapis.com/Subnetwork"], + "read_mask": read_mask, + }) + 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 create_client(): ''' Creates the monitoring API client, that will be used to create, read and update custom metrics. @@ -123,16 +275,41 @@ def create_client(): def create_metrics(): + ''' + Creates all Cloud Monitoring custom metrics based on the metric.yaml file + + Parameters: + None + + Returns: + metrics_dict (dictionary of dictionary of string: string): metrics names and descriptions + limits_dict (dictionary of dictionary of string: int): limits_dict[metric_name]: dict[network_name] = limit_value + ''' + client = monitoring_v3.MetricServiceClient() + existing_metrics = [] + for desc in client.list_metric_descriptors(name=MONITORING_PROJECT_LINK): + existing_metrics.append(desc.type) + limits_dict = {} + with open("metrics.yaml", 'r') as stream: try: metrics_dict = yaml.safe_load(stream) for metric_list in metrics_dict.values(): for metric in metric_list.values(): - for sub_metric in metric.values(): - create_metric(sub_metric["name"], sub_metric["description"]) + 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"]) + # Parse limits (both default values and network specific ones) + if sub_metric_key == "limit": + limits_dict_for_metric = {} + for network_link, limit_value in sub_metric["values"].items(): + limits_dict_for_metric[network_link] = limit_value + limits_dict[sub_metric["name"]] = limits_dict_for_metric - return metrics_dict + return metrics_dict, limits_dict except yaml.YAMLError as exc: print(exc) @@ -150,76 +327,72 @@ def create_metric(metric_name, description): ''' client = monitoring_v3.MetricServiceClient() - metric_link = f"custom.googleapis.com/{metric_name}" - types = [] - for desc in client.list_metric_descriptors(name=MONITORING_PROJECT_LINK): - types.append(desc.type) - - # If the metric doesn't exist yet, then we create it - if metric_link not in types: - descriptor = ga_metric.MetricDescriptor() - descriptor.type = f"custom.googleapis.com/{metric_name}" - descriptor.metric_kind = ga_metric.MetricDescriptor.MetricKind.GAUGE - descriptor.value_type = ga_metric.MetricDescriptor.ValueType.DOUBLE - descriptor.description = description - descriptor = client.create_metric_descriptor(name=MONITORING_PROJECT_LINK, - metric_descriptor=descriptor) - print("Created {}.".format(descriptor.name)) + descriptor = ga_metric.MetricDescriptor() + descriptor.type = f"custom.googleapis.com/{metric_name}" + descriptor.metric_kind = ga_metric.MetricDescriptor.MetricKind.GAUGE + descriptor.value_type = ga_metric.MetricDescriptor.ValueType.DOUBLE + descriptor.description = description + descriptor = client.create_metric_descriptor(name=MONITORING_PROJECT_LINK, + metric_descriptor=descriptor) + print("Created {}.".format(descriptor.name)) -def get_gce_instances_data(metrics_dict): +def get_gce_instances_data(metrics_dict, gce_instance_dict, limit_dict): ''' Gets the data for GCE instances per VPC Network and writes it to the metric defined in instance_metric. Parameters: metrics_dict (dictionary of dictionary of string: string): metrics names and descriptions + gce_instance_dict (dictionary of string: int): Keys are the network links and values are the number of GCE Instances per network. + limit_dict (dictionary of string:int): Dictionary with the network link as key and the limit as value Returns: - None + gce_instance_dict ''' # Existing GCP Monitoring metrics for GCE instances - metric_instances_usage = "compute.googleapis.com/quota/instances_per_vpc_network/usage" metric_instances_limit = "compute.googleapis.com/quota/instances_per_vpc_network/limit" for project in MONITORED_PROJECTS_LIST: network_dict = get_networks(project) - current_quota_usage = get_quota_current_usage(f"projects/{project}", - metric_instances_usage) current_quota_limit = get_quota_current_limit(f"projects/{project}", metric_instances_limit) - - current_quota_usage_view = customize_quota_view(current_quota_usage) current_quota_limit_view = customize_quota_view(current_quota_limit) for net in network_dict: - set_usage_limits(net, current_quota_usage_view, current_quota_limit_view, - LIMIT_INSTANCES) + set_limits(net, current_quota_limit_view, limit_dict) + + network_link = f"https://www.googleapis.com/compute/v1/projects/{project}/global/networks/{net['network_name']}" + + usage = 0 + if network_link in gce_instance_dict: + usage = gce_instance_dict[network_link] + write_data_to_metric( - project, net['usage'], metrics_dict["metrics_per_network"] - ["instance_per_network"]["usage"]["name"], net['network name']) + project, usage, metrics_dict["metrics_per_network"] + ["instance_per_network"]["usage"]["name"], net['network_name']) write_data_to_metric( project, net['limit'], metrics_dict["metrics_per_network"] - ["instance_per_network"]["limit"]["name"], net['network name']) + ["instance_per_network"]["limit"]["name"], net['network_name']) write_data_to_metric( - project, net['usage'] / net['limit'], - metrics_dict["metrics_per_network"]["instance_per_network"] - ["utilization"]["name"], net['network name']) + project, usage / net['limit'], metrics_dict["metrics_per_network"] + ["instance_per_network"]["utilization"]["name"], net['network_name']) print(f"Wrote number of instances to metric for projects/{project}") -def get_vpc_peering_data(metrics_dict): +def get_vpc_peering_data(metrics_dict, limit_dict): ''' Gets the data for VPC peerings (active or not) and writes it to the metric defined (vpc_peering_active_metric and vpc_peering_metric). Parameters: metrics_dict (dictionary of dictionary of string: string): metrics names and descriptions + limit_dict (dictionary of string:int): Dictionary with the network link as key and the limit as value Returns: None ''' for project in MONITORED_PROJECTS_LIST: active_vpc_peerings, vpc_peerings = gather_vpc_peerings_data( - project, LIMIT_VPC_PEER) + project, limit_dict) for peering in active_vpc_peerings: write_data_to_metric( project, peering['active_peerings'], @@ -250,13 +423,13 @@ def get_vpc_peering_data(metrics_dict): print("Wrote number of VPC peerings to custom metric for project:", project) -def gather_vpc_peerings_data(project_id, limit_list): +def gather_vpc_peerings_data(project_id, limit_dict): ''' Gets the data for all VPC peerings (active or not) in project_id and writes it to the metric defined in vpc_peering_active_metric and vpc_peering_metric. Parameters: project_id (string): We will take all VPCs in that project_id and look for all peerings to these VPCs. - limit_list (list of string): Used to get the limit per VPC or the default limit. + limit_dict (dictionary of string:int): Dictionary with the network link as key and the limit as value Returns: active_peerings_dict (dictionary of string: string): Contains project_id, network_name, network_limit for each active VPC peering. peerings_dict (dictionary of string: string): Contains project_id, network_name, network_limit for each VPC peering. @@ -279,96 +452,102 @@ def gather_vpc_peerings_data(project_id, limit_list): peerings_count = 0 active_peerings_count = 0 + network_link = f"https://www.googleapis.com/compute/v1/projects/{project_id}/global/networks/{network['name']}" + network_limit = get_limit_ppg(network_link, limit_dict) + active_d = { 'project_id': project_id, 'network_name': network['name'], 'active_peerings': active_peerings_count, - 'network_limit': get_limit(network['name'], limit_list) + 'network_limit': network_limit } active_peerings_dict.append(active_d) d = { 'project_id': project_id, 'network_name': network['name'], 'peerings': peerings_count, - 'network_limit': get_limit(network['name'], limit_list) + 'network_limit': network_limit } peerings_dict.append(d) return active_peerings_dict, peerings_dict -def get_limit(network_name, limit_list): +def get_limit_ppg(network_link, limit_dict): ''' Checks if this network has a specific limit for a metric, if so, returns that limit, if not, returns the default limit. Parameters: - network_name (string): Name of the VPC network. + network_link (string): VPC network link. limit_list (list of string): Used to get the limit per VPC or the default limit. Returns: - limit (int): Limit for that VPC and that metric. + limit_dict (dictionary of string:int): Dictionary with the network link as key and the limit as value ''' - if network_name in limit_list: - return int(limit_list[limit_list.index(network_name) + 1]) + if network_link in limit_dict: + return limit_dict[network_link] else: - if 'default_value' in limit_list: - return int(limit_list[limit_list.index('default_value') + 1]) + if 'default_value' in limit_dict: + return limit_dict['default_value'] else: + print(f"Error: limit not found for {network_link}") return 0 -def get_l4_forwarding_rules_data(metrics_dict): +def get_l4_forwarding_rules_data(metrics_dict, forwarding_rules_dict, + limit_dict): ''' Gets the data for L4 Internal Forwarding Rules per VPC Network and writes it to the metric defined in forwarding_rules_metric. Parameters: - metrics_dict (dictionary of dictionary of string: string): metrics names and descriptions + metrics_dict (dictionary of dictionary of string: string): metrics names and descriptions. + forwarding_rules_dict (dictionary of string: int): Keys are the network links and values are the number of Forwarding Rules per network. + limit_dict (dictionary of string:int): Dictionary with the network link as key and the limit as value. Returns: None ''' - # Existing GCP Monitoring metrics for L4 Forwarding Rules - l4_forwarding_rules_usage = "compute.googleapis.com/quota/internal_lb_forwarding_rules_per_vpc_network/usage" - l4_forwarding_rules_limit = "compute.googleapis.com/quota/internal_lb_forwarding_rules_per_vpc_network/limit" - for project in MONITORED_PROJECTS_LIST: network_dict = get_networks(project) - current_quota_usage = get_quota_current_usage(f"projects/{project}", - l4_forwarding_rules_usage) - current_quota_limit = get_quota_current_limit(f"projects/{project}", - l4_forwarding_rules_limit) + current_quota_limit = get_quota_current_limit( + f"projects/{project}", L4_FORWARDING_RULES_LIMIT_METRIC) - current_quota_usage_view = customize_quota_view(current_quota_usage) current_quota_limit_view = customize_quota_view(current_quota_limit) for net in network_dict: - set_usage_limits(net, current_quota_usage_view, current_quota_limit_view, - LIMIT_L4) + set_limits(net, current_quota_limit_view, limit_dict) + + network_link = f"https://www.googleapis.com/compute/v1/projects/{project}/global/networks/{net['network_name']}" + + usage = 0 + if network_link in forwarding_rules_dict: + usage = forwarding_rules_dict[network_link] + write_data_to_metric( - project, net['usage'], metrics_dict["metrics_per_network"] + project, usage, metrics_dict["metrics_per_network"] ["l4_forwarding_rules_per_network"]["usage"]["name"], - net['network name']) + net['network_name']) write_data_to_metric( project, net['limit'], metrics_dict["metrics_per_network"] ["l4_forwarding_rules_per_network"]["limit"]["name"], - net['network name']) + net['network_name']) write_data_to_metric( - project, net['usage'] / net['limit'], - metrics_dict["metrics_per_network"]["l4_forwarding_rules_per_network"] - ["utilization"]["name"], net['network name']) + project, usage / net['limit'], metrics_dict["metrics_per_network"] + ["l4_forwarding_rules_per_network"]["utilization"]["name"], + net['network_name']) print( f"Wrote number of L4 forwarding rules to metric for projects/{project}") -def get_pgg_data(metric_dict, usage_metric, limit_metric, limit_ppg): +def get_pgg_data(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: - metric_dict (dictionary of string: string): A dictionary with the metric names and description, that will be used to populate the metrics + metric_dict (dictionary of string: string): Dictionary with the metric names and description, that will be used to populate the metrics usage_metric (string): Name of the existing GCP metric for usage per VPC network. - limit_metric (string): Name of the existing GCP metric for limit per VPC network. - limit_ppg (list of string): List containing the limit per peering group (either VPC specific or default limit). + 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 ''' @@ -382,38 +561,43 @@ def get_pgg_data(metric_dict, usage_metric, limit_metric, limit_ppg): # For each network in this GCP project for network_dict in network_dict_list: - current_quota_usage = get_quota_current_usage(f"projects/{project}", - usage_metric) + network_link = f"https://www.googleapis.com/compute/v1/projects/{project}/global/networks/{network_dict['network_name']}" + current_quota_limit = get_quota_current_limit(f"projects/{project}", limit_metric) - - current_quota_usage_view = customize_quota_view(current_quota_usage) current_quota_limit_view = customize_quota_view(current_quota_limit) + limit = get_limit_network(network_dict, network_link, + current_quota_limit_view, limit_dict) + + usage = 0 + if network_link in usage_dict: + usage = usage_dict[network_link] - usage, limit = get_usage_limit(network_dict, current_quota_usage_view, - current_quota_limit_view, limit_ppg) # 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 in network_dict['peerings']: - peering_project_usage = customize_quota_view( - get_quota_current_usage(f"projects/{peered_network['project_id']}", - usage_metric)) - peering_project_limit = customize_quota_view( - get_quota_current_limit(f"projects/{peered_network['project_id']}", - limit_metric)) + 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] - usage, limit = get_usage_limit(peered_network, peering_project_usage, - peering_project_limit, limit_ppg) + peering_project_limit = customize_quota_view( + get_quota_current_limit( + f"projects/{peered_network_dict['project_id']}", limit_metric)) + + peered_limit = get_limit_network(peered_network_dict, + peered_network_link, + peering_project_limit, limit_dict) # Here we add usage and limit to the peered network dictionary - peered_network["usage"] = usage - peered_network["limit"] = limit + peered_network_dict["usage"] = peered_usage + peered_network_dict["limit"] = peered_limit count_effective_limit(project, network_dict, metric_dict["usage"]["name"], metric_dict["limit"]["name"], - metric_dict["utilization"]["name"], limit_ppg) + metric_dict["utilization"]["name"], limit_dict) print( f"Wrote {metric_dict['usage']['name']} to metric for peering group {network_dict['network_name']} in {project}" ) @@ -421,7 +605,7 @@ def get_pgg_data(metric_dict, usage_metric, limit_metric, limit_ppg): def count_effective_limit(project_id, network_dict, usage_metric_name, limit_metric_name, utilization_metric_name, - limit_ppg): + limit_dict): ''' Calculates the effective limits (using algorithm in the link below) for peering groups and writes data (usage, limit, utilization) to the custom metrics. Source: https://cloud.google.com/vpc/docs/quota#vpc-peering-effective-limit @@ -432,7 +616,7 @@ def count_effective_limit(project_id, network_dict, usage_metric_name, usage_metric_name (string): Name of the custom metric to be populated for usage per VPC peering group. limit_metric_name (string): Name of the custom metric to be populated for limit per VPC peering group. utilization_metric_name (string): Name of the custom metric to be populated for utilization per VPC peering group. - limit_ppg (list of string): List containing the limit per peering group (either VPC specific or default limit). + limit_dict (dictionary of string:int): Dictionary containing the limit per peering group (either VPC specific or default limit). Returns: None ''' @@ -445,16 +629,20 @@ def count_effective_limit(project_id, network_dict, usage_metric_name, for peered_network in network_dict['peerings']: peering_group_usage += peered_network['usage'] + network_link = f"https://www.googleapis.com/compute/v1/projects/{project_id}/global/networks/{network_dict['network_name']}" + # Calculates effective limit: Step 1: max(per network limit, per network_peering_group limit) limit_step1 = max(network_dict['limit'], - get_limit(network_dict['network_name'], limit_ppg)) + get_limit_ppg(network_link, limit_dict)) # Calculates effective limit: Step 2: List of max(per network limit, per network_peering_group limit) for each peered network limit_step2 = [] for peered_network in network_dict['peerings']: + peered_network_link = f"https://www.googleapis.com/compute/v1/projects/{peered_network['project_id']}/global/networks/{peered_network['network_name']}" + limit_step2.append( max(peered_network['limit'], - get_limit(peered_network['network_name'], limit_ppg))) + get_limit_ppg(peered_network_link, limit_dict))) # Calculates effective limit: Step 3: Find minimum from the list created by Step 2 limit_step3 = min(limit_step2) @@ -485,9 +673,39 @@ def get_networks(project_id): network_dict = [] if 'items' in response: for network in response['items']: - NETWORK = network['name'] - ID = network['id'] - d = {'project_id': project_id, 'network name': NETWORK, 'network id': ID} + network_name = network['name'] + network_id = network['id'] + d = { + 'project_id': project_id, + 'network_name': network_name, + 'network_id': network_id + } + network_dict.append(d) + return network_dict + + +# TODO: list all routers (https://cloud.google.com/compute/docs/reference/rest/v1/routers/list) then https://cloud.google.com/compute/docs/reference/rest/v1/routers/getRouterStatus +def get_routes(project_id): + ''' + Returns a dictionary of all dynamic routes in a project. + + Parameters: + 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 = service.routers().list(project=project_id) + response = request.execute() + network_dict = [] + if 'items' in response: + for router in response['items']: + network_name = router['name'] + network_id = router['id'] + d = { + 'project_id': project_id, + 'network name': network_name, + 'network id': network_id + } network_dict.append(d) return network_dict @@ -564,29 +782,6 @@ def get_network_id(project_id, network_name): return network_id -def get_quota_current_usage(project_link, metric_name): - ''' - Retrieves quota usage for a specific metric. - - Parameters: - project_link (string): Project link. - metric_name (string): Name of the metric. - Returns: - results_list (list of string): Current usage. - ''' - client, interval = create_client() - - results = client.list_time_series( - request={ - "name": project_link, - "filter": f'metric.type = "{metric_name}"', - "interval": interval, - "view": monitoring_v3.ListTimeSeriesRequest.TimeSeriesView.FULL - }) - results_list = list(results) - return (results_list) - - def get_quota_current_limit(project_link, metric_name): ''' Retrieves limit for a specific metric. @@ -630,98 +825,64 @@ def customize_quota_view(quota_results): return quotaViewList -def set_usage_limits(network_dict, quota_usage, quota_limit, limit_list): +def set_limits(network_dict, quota_limit, limit_dict): ''' - Updates the network dictionary with quota usage and limit values. + Updates the network dictionary with quota limit values. Parameters: network_dict (dictionary of string: string): Contains network information. - quota_usage (list of dictionaries of string: string): Current quota usage. quota_limit (list of dictionaries of string: string): Current quota limit. - limit_list (list of string): List containing the limit per VPC (either VPC specific or default limit). + limit_dict (dictionary of string:int): Dictionary with the network link as key and the limit as value Returns: None ''' - if quota_usage: - for net in quota_usage: - if net['network_id'] == network_dict[ - 'network id']: # if network ids in GCP quotas and in dictionary (using API) are the same - network_dict['usage'] = net['value'] # set network usage in dictionary - break - else: - network_dict['usage'] = 0 # if network does not appear in GCP quotas - else: - network_dict['usage'] = 0 # if quotas does not appear in GCP quotas + + network_dict['limit'] = None if quota_limit: for net in quota_limit: - if net['network_id'] == network_dict[ - 'network id']: # if network ids in GCP quotas and in dictionary (using API) are the same - network_dict['limit'] = net['value'] # set network limit in dictionary - break - else: - if network_dict[ - 'network name'] in limit_list: # if network limit is in the environmental variables - network_dict['limit'] = int( - limit_list[limit_list.index(network_dict['network name']) + 1]) - else: - network_dict['limit'] = int( - limit_list[limit_list.index('default_value') + - 1]) # set default value - else: # if quotas does not appear in GCP quotas - if network_dict['network name'] in limit_list: - network_dict['limit'] = int( - limit_list[limit_list.index(network_dict['network name']) + - 1]) # ["default", 100, "networkname", 200] + if net['network_id'] == network_dict['network_id']: + network_dict['limit'] = net['value'] + return + + network_link = f"https://www.googleapis.com/compute/v1/projects/{network_dict['project_id']}/global/networks/{network_dict['network_name']}" + + if network_link in limit_dict: + network_dict['limit'] = limit_dict[network_link] + else: + if 'default_value' in limit_dict: + network_dict['limit'] = limit_dict['default_value'] else: - network_dict['limit'] = int(limit_list[limit_list.index('default_value') + - 1]) + print(f"Error: Couldn't find limit for {network_link}") + network_dict['limit'] = 0 -def get_usage_limit(network, quota_usage, quota_limit, limit_list): +def get_limit_network(network_dict, network_link, quota_limit, limit_dict): ''' - Returns usage and limit for a specific network and metric. + 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. - quota_usage (list of dictionaries of string: string): Current quota usage for all networks in that project. + network_link (string): Contains network link quota_limit (list of dictionaries of string: string): Current quota limit for all networks in that project. - limit_list (list of string): List containing the limit per VPC (either VPC specific or default limit). + limit_dict (dictionary of string:int): Dictionary with the network link as key and the limit as value Returns: - usage (int): Current usage for that network. - limit (int): Current usage for that network. + limit (int): Current limit for that network. ''' - usage = 0 - limit = 0 - - if quota_usage: - for net in quota_usage: - if net['network_id'] == network[ - 'network_id']: # if network ids in GCP quotas and in dictionary (using API) are the same - usage = net['value'] # set network usage in dictionary - break - if quota_limit: for net in quota_limit: - if net['network_id'] == network[ - 'network_id']: # if network ids in GCP quotas and in dictionary (using API) are the same - limit = net['value'] # set network limit in dictionary - break - else: - if network[ - 'network_name'] in limit_list: # if network limit is in the environmental variables - limit = int(limit_list[limit_list.index(network['network_name']) + 1]) - else: - limit = int(limit_list[limit_list.index('default_value') + - 1]) # set default value - else: # if quotas does not appear in GCP quotas - if network['network_name'] in limit_list: - limit = int(limit_list[limit_list.index(network['network_name']) + - 1]) # ["default", 100, "networkname", 200] - else: - limit = int(limit_list[limit_list.index('default_value') + 1]) + if net['network_id'] == network_dict['network_id']: + return net['value'] - return usage, limit + 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 def write_data_to_metric(monitored_project_id, value, metric_name, @@ -762,4 +923,10 @@ def write_data_to_metric(monitored_project_id, value, metric_name, }) series.points = [point] - client.create_time_series(name=MONITORING_PROJECT_LINK, time_series=[series]) + # TODO: sometimes this cashes with 'DeadlineExceeded: 504 Deadline expired before operation could complete' error + # Implement exponential backoff retries? + try: + client.create_time_series(name=MONITORING_PROJECT_LINK, + time_series=[series]) + except Exception as e: + print(e) diff --git a/examples/cloud-operations/network-dashboard/cloud-function/metrics.yaml b/examples/cloud-operations/network-dashboard/cloud-function/metrics.yaml index 233dc9be6..a9772b5c1 100644 --- a/examples/cloud-operations/network-dashboard/cloud-function/metrics.yaml +++ b/examples/cloud-operations/network-dashboard/cloud-function/metrics.yaml @@ -22,6 +22,8 @@ metrics_per_network: limit: name: number_of_instances_limit description: Number of instances per VPC network - limit. + values: + default_value: 15000 utilization: name: number_of_instances_utilization description: Number of instances per VPC network - utilization. @@ -32,6 +34,8 @@ metrics_per_network: limit: name: number_of_active_vpc_peerings_limit description: Number of active VPC Peerings per VPC - limit. + values: + default_value: 25 utilization: name: number_of_active_vpc_peerings_utilization description: Number of active VPC Peerings per VPC - utilization. @@ -42,6 +46,9 @@ metrics_per_network: limit: name: number_of_vpc_peerings_limit description: Number of VPC Peerings per VPC - limit. + values: + default_value: 25 + https://www.googleapis.com/compute/v1/projects/net-dash-test-host-prod/global/networks/vpc-prod: 40 utilization: name: number_of_vpc_peerings_utilization description: Number of VPC Peerings per VPC - utilization. @@ -52,6 +59,8 @@ metrics_per_network: limit: name: internal_forwarding_rules_l4_limit description: Number of Internal Forwarding Rules for Internal L4 Load Balancers - limit. + values: + default_value: 75 utilization: name: internal_forwarding_rules_l4_utilization description: Number of Internal Forwarding Rules for Internal L4 Load Balancers - utilization. @@ -62,6 +71,8 @@ metrics_per_network: limit: name: internal_forwarding_rules_l7_limit description: Number of Internal Forwarding Rules for Internal L7 Load Balancers per network - effective limit. + values: + default_value: 75 utilization: name: internal_forwarding_rules_l7_utilization description: Number of Internal Forwarding Rules for Internal L7 Load Balancers per Vnetwork - utilization. @@ -73,6 +84,8 @@ metrics_per_peering_group: limit: 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: 175 utilization: name: internal_forwarding_rules_l4_ppg_utilization description: Number of Internal Forwarding Rules for Internal L4 Load Balancers per VPC peering group - utilization. @@ -83,18 +96,22 @@ metrics_per_peering_group: limit: name: internal_forwarding_rules_l7_ppg_limit description: Number of Internal Forwarding Rules for Internal L7 Load Balancers per VPC peering group - effective limit. + values: + default_value: 175 utilization: name: internal_forwarding_rules_l7_ppg_utilization description: Number of Internal Forwarding Rules for Internal L7 Load Balancers per VPC peering group - utilization. subnet_ranges_per_peering_group: usage: - name: number_of_subnet_IP_ranges_usage + name: number_of_subnet_IP_ranges_ppg_usage description: Number of Subnet Ranges per peering group - usage. limit: - name: number_of_subnet_IP_ranges_limit + name: number_of_subnet_IP_ranges_ppg_limit description: Number of Subnet Ranges per peering group - effective limit. + values: + default_value: 400 utilization: - name: number_of_subnet_IP_ranges_utilization + name: number_of_subnet_IP_ranges_ppg_utilization description: Number of Subnet Ranges per peering group - utilization. instance_per_peering_group: usage: @@ -103,6 +120,8 @@ metrics_per_peering_group: limit: name: number_of_instances_ppg_limit description: Number of instances per peering group - limit. + values: + default_value: 15500 utilization: name: number_of_instances_ppg_utilization description: Number of instances per peering group - utilization. \ No newline at end of file diff --git a/examples/cloud-operations/network-dashboard/cloud-function/requirements.txt b/examples/cloud-operations/network-dashboard/cloud-function/requirements.txt index 0888969cb..8a6a5960b 100644 --- a/examples/cloud-operations/network-dashboard/cloud-function/requirements.txt +++ b/examples/cloud-operations/network-dashboard/cloud-function/requirements.txt @@ -6,4 +6,5 @@ google-cloud-logging==3.0.0 google-cloud-monitoring==2.9.1 oauth2client==4.1.3 google-api-core==2.7.0 -PyYAML==6.0 \ No newline at end of file +PyYAML==6.0 +google-cloud-asset==3.8.1 \ No newline at end of file diff --git a/examples/cloud-operations/network-dashboard/dashboards/quotas-utilization.json b/examples/cloud-operations/network-dashboard/dashboards/quotas-utilization.json index af812061f..794d61234 100644 --- a/examples/cloud-operations/network-dashboard/dashboards/quotas-utilization.json +++ b/examples/cloud-operations/network-dashboard/dashboards/quotas-utilization.json @@ -196,7 +196,7 @@ { "height": 4, "widget": { - "title": "number_of_subnet_IP_ranges_utilization", + "title": "number_of_subnet_IP_ranges_ppg_utilization", "xyChart": { "chartOptions": { "mode": "COLOR" @@ -212,7 +212,7 @@ "alignmentPeriod": "3600s", "perSeriesAligner": "ALIGN_NEXT_OLDER" }, - "filter": "metric.type=\"custom.googleapis.com/number_of_subnet_IP_ranges_utilization\" resource.type=\"global\"", + "filter": "metric.type=\"custom.googleapis.com/number_of_subnet_IP_ranges_ppg_utilization\" resource.type=\"global\"", "secondaryAggregation": { "alignmentPeriod": "3600s", "perSeriesAligner": "ALIGN_MEAN" diff --git a/examples/cloud-operations/network-dashboard/main.tf b/examples/cloud-operations/network-dashboard/main.tf index 152bb3609..8fb7963cd 100644 --- a/examples/cloud-operations/network-dashboard/main.tf +++ b/examples/cloud-operations/network-dashboard/main.tf @@ -17,23 +17,6 @@ locals { project_id_list = toset(var.monitored_projects_list) projects = join(",", local.project_id_list) - - limit_instances = join(",", local.limit_instances_list) - limit_instances_list = tolist(var.limit_instances) - limit_instances_ppg = join(",", local.limit_instances_ppg_list) - limit_instances_ppg_list = tolist(var.limit_instances_ppg) - limit_l4 = join(",", local.limit_l4_list) - limit_l4_list = tolist(var.limit_l4) - limit_l4_ppg = join(",", local.limit_l4_ppg_list) - limit_l4_ppg_list = tolist(var.limit_l4_ppg) - limit_l7 = join(",", local.limit_l7_list) - limit_l7_list = tolist(var.limit_l7) - limit_l7_ppg = join(",", local.limit_l7_ppg_list) - limit_l7_ppg_list = tolist(var.limit_l7_ppg) - limit_subnets = join(",", local.limit_subnets_list) - limit_subnets_list = tolist(var.limit_subnets) - limit_vpc_peer = join(",", local.limit_vpc_peer_list) - limit_vpc_peer_list = tolist(var.limit_vpc_peer) } ################################################ @@ -66,6 +49,7 @@ module "service-account-function" { "${var.organization_id}" = [ "roles/compute.networkViewer", "roles/monitoring.viewer", + "roles/cloudasset.viewer" ] } @@ -129,16 +113,9 @@ module "cloud-function" { } environment_variables = { - LIMIT_INSTANCES = local.limit_instances - LIMIT_INSTANCES_PPG = local.limit_instances_ppg - LIMIT_L4 = local.limit_l4 - LIMIT_L4_PPG = local.limit_l4_ppg - LIMIT_L7 = local.limit_l7 - LIMIT_L7_PPG = local.limit_l7_ppg - LIMIT_SUBNETS = local.limit_subnets - LIMIT_VPC_PEER = local.limit_vpc_peer MONITORED_PROJECTS_LIST = local.projects MONITORING_PROJECT_ID = module.project-monitoring.project_id + ORGANIZATION_ID = var.organization_id } service_account = module.service-account-function.email diff --git a/examples/cloud-operations/network-dashboard/tests/test.tf b/examples/cloud-operations/network-dashboard/tests/test.tf index 8161af65b..791d68b06 100644 --- a/examples/cloud-operations/network-dashboard/tests/test.tf +++ b/examples/cloud-operations/network-dashboard/tests/test.tf @@ -270,7 +270,6 @@ resource "google_compute_instance" "test-vm-hub1" { } # Forwarding Rules - resource "google_compute_forwarding_rule" "forwarding-rule-dev" { count = 10 name = "forwarding-rule-dev${count.index}" diff --git a/examples/cloud-operations/network-dashboard/variables.tf b/examples/cloud-operations/network-dashboard/variables.tf index 7170a513f..7e4237ca8 100644 --- a/examples/cloud-operations/network-dashboard/variables.tf +++ b/examples/cloud-operations/network-dashboard/variables.tf @@ -75,69 +75,4 @@ variable "region" { variable "zone" { description = "Zone used to deploy vms" default = "europe-west1-b" -} - -variable "limit_l4" { - description = "Maximum number of forwarding rules for Internal TCP/UDP Load Balancing per network." - type = list(string) - default = [ - "default_value", "75", - ] -} - -variable "limit_l7" { - description = "Maximum number of forwarding rules for Internal HTTP(S) Load Balancing per network." - type = list(string) - default = [ - "default_value", "75", - ] -} - -variable "limit_subnets" { - description = "Maximum number of subnet IP ranges (primary and secondary) per peering group" - type = list(string) - default = [ - "default_value", "400", - ] -} - -variable "limit_instances" { - description = "Maximum number of instances per network" - type = list(string) - default = [ - "default_value", "15000", - ] -} - -variable "limit_instances_ppg" { - description = "Maximum number of instances per peering group." - type = list(string) - default = [ - "default_value", "15000", - ] -} - -variable "limit_vpc_peer" { - description = "Maximum number of peering VPC peerings per network." - type = list(string) - default = [ - "default_value", "25", - "test-vpc", "40", - ] -} - -variable "limit_l4_ppg" { - description = "Maximum number of forwarding rules for Internal TCP/UDP Load Balancing per network." - type = list(string) - default = [ - "default_value", "175", - ] -} - -variable "limit_l7_ppg" { - description = "Maximum number of forwarding rules for Internal HTTP(S) Load Balancing per network." - type = list(string) - default = [ - "default_value", "175", - ] } \ No newline at end of file diff --git a/examples/serverless/api-gateway/function/package-lock.json b/examples/serverless/api-gateway/function/package-lock.json index 6bf7ab5c1..da027c38b 100644 --- a/examples/serverless/api-gateway/function/package-lock.json +++ b/examples/serverless/api-gateway/function/package-lock.json @@ -896,9 +896,9 @@ } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "node_modules/ms": { "version": "2.0.0", @@ -2125,9 +2125,9 @@ } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "ms": { "version": "2.0.0", diff --git a/fast/stages/02-networking-vpn/vpn-spoke-prod.tf b/fast/stages/02-networking-vpn/vpn-spoke-prod.tf index ff635194c..3001c4ec9 100644 --- a/fast/stages/02-networking-vpn/vpn-spoke-prod.tf +++ b/fast/stages/02-networking-vpn/vpn-spoke-prod.tf @@ -82,7 +82,7 @@ module "landing-to-prod-ew4-vpn" { source = "../../../modules/net-vpn-ha" project_id = module.landing-project.project_id network = module.landing-vpc.self_link - region = "europe-west1" + region = "europe-west4" name = "vpn-to-prod-ew4" router_create = true router_name = "landing-vpn-ew4" @@ -112,7 +112,7 @@ module "prod-to-landing-ew4-vpn" { source = "../../../modules/net-vpn-ha" project_id = module.prod-spoke-project.project_id network = module.prod-spoke-vpc.self_link - region = "europe-west1" + region = "europe-west4" name = "vpn-to-landing-ew4" router_create = true router_name = "prod-spoke-vpn-ew4" diff --git a/modules/bigquery-dataset/README.md b/modules/bigquery-dataset/README.md index 59a692415..139ef9a57 100644 --- a/modules/bigquery-dataset/README.md +++ b/modules/bigquery-dataset/README.md @@ -15,7 +15,7 @@ Access configuration defaults to using the separate `google_bigquery_dataset_acc You can choose to manage the `google_bigquery_dataset` access rules instead via the `dataset_access` variable, but be sure to always have at least one `OWNER` access and to avoid duplicating accesses, or `terraform apply` will fail. -The access variables are split into `access_roles` and `access_identities` variables, so that dynamic values can be passed in for identities (eg a service account email generated by a different module or resource). The `access_views` variable is separate, so as to allow proper type constraints. +The access variables are split into `access` and `access_identities` variables, so that dynamic values can be passed in for identities (eg a service account email generated by a different module or resource). ```hcl module "bigquery-dataset" { @@ -54,8 +54,6 @@ module "bigquery-dataset" { # tftest modules=1 resources=2 ``` -roles/bigquery.dataOwner - ### Dataset options Dataset options are set via the `options` variable. all options must be specified, but a `null` value can be set to options that need to use defaults. @@ -182,7 +180,7 @@ module "bigquery-dataset" { | [id](variables.tf#L69) | Dataset id. | string | ✓ | | | [project_id](variables.tf#L100) | Id of the project where datasets will be created. | string | ✓ | | | [access](variables.tf#L17) | Map of access rules with role and identity type. Keys are arbitrary and must match those in the `access_identities` variable, types are `domain`, `group`, `special_group`, `user`, `view`. | map(object({…})) | | {} | -| [access_identities](variables.tf#L33) | Map of access identities used for basic access roles. View identities have the format 'project_id|dataset_id|table_id'. | map(string) | | {} | +| [access_identities](variables.tf#L33) | Map of access identities used for basic access roles. View identities have the format 'project_id\|dataset_id\|table_id'. | map(string) | | {} | | [dataset_access](variables.tf#L39) | Set access in the dataset resource instead of using separate resources. | bool | | false | | [description](variables.tf#L45) | Optional description. | string | | "Terraform managed." | | [encryption_key](variables.tf#L51) | Self link of the KMS key that will be used to protect destination table. | string | | null | diff --git a/modules/cloud-config-container/coredns/README.md b/modules/cloud-config-container/coredns/README.md index 09cc44916..8099aee5c 100644 --- a/modules/cloud-config-container/coredns/README.md +++ b/modules/cloud-config-container/coredns/README.md @@ -77,8 +77,9 @@ module "cos-coredns" { | [cloud_config](variables.tf#L17) | Cloud config template path. If null default will be used. | string | | null | | [config_variables](variables.tf#L23) | Additional variables used to render the cloud-config and CoreDNS templates. | map(any) | | {} | | [coredns_config](variables.tf#L29) | CoreDNS configuration path, if null default will be used. | string | | null | -| [file_defaults](variables.tf#L35) | Default owner and permissions for files. | object({…}) | | {…} | -| [files](variables.tf#L47) | Map of extra files to create on the instance, path as key. Owner and permissions will use defaults if null. | map(object({…})) | | {} | +| [docker_logging](variables.tf#L35) | Log via the Docker gcplogs driver. Disable if you use the legacy Logging Agent instead. | bool | | true | +| [file_defaults](variables.tf#L41) | Default owner and permissions for files. | object({…}) | | {…} | +| [files](variables.tf#L53) | Map of extra files to create on the instance, path as key. Owner and permissions will use defaults if null. | map(object({…})) | | {} | | [test_instance](variables-instance.tf#L17) | Test/development instance attributes, leave null to skip creation. | object({…}) | | null | | [test_instance_defaults](variables-instance.tf#L30) | Test/development instance defaults used for optional configuration. If image is null, COS stable will be used. | object({…}) | | {…} | diff --git a/modules/cloud-config-container/coredns/cloud-config.yaml b/modules/cloud-config-container/coredns/cloud-config.yaml index 0796fc6b9..1fe9a0043 100644 --- a/modules/cloud-config-container/coredns/cloud-config.yaml +++ b/modules/cloud-config-container/coredns/cloud-config.yaml @@ -58,7 +58,10 @@ write_files: Wants=gcr-online.target docker.socket docker-events-collector.service [Service] ExecStart=/usr/bin/docker run --rm --name=coredns \ - --log-driver=gcplogs --network host \ + %{~ if docker_logging ~} + --log-driver=gcplogs \ + %{~ endif ~} + --network host \ -v /etc/coredns:/etc/coredns \ coredns/coredns -conf /etc/coredns/Corefile ExecStop=/usr/bin/docker stop coredns diff --git a/modules/cloud-config-container/coredns/main.tf b/modules/cloud-config-container/coredns/main.tf index 789168ca4..422882963 100644 --- a/modules/cloud-config-container/coredns/main.tf +++ b/modules/cloud-config-container/coredns/main.tf @@ -16,8 +16,9 @@ locals { cloud_config = templatefile(local.template, merge(var.config_variables, { - corefile = templatefile(local.corefile, var.config_variables) - files = local.files + corefile = templatefile(local.corefile, var.config_variables) + docker_logging = var.docker_logging + files = local.files })) corefile = ( var.coredns_config == null ? "${path.module}/Corefile" : var.coredns_config diff --git a/modules/cloud-config-container/coredns/variables.tf b/modules/cloud-config-container/coredns/variables.tf index c323017fc..bc9be06ef 100644 --- a/modules/cloud-config-container/coredns/variables.tf +++ b/modules/cloud-config-container/coredns/variables.tf @@ -32,6 +32,12 @@ variable "coredns_config" { default = null } +variable "docker_logging" { + description = "Log via the Docker gcplogs driver. Disable if you use the legacy Logging Agent instead." + type = bool + default = true +} + variable "file_defaults" { description = "Default owner and permissions for files." type = object({ diff --git a/modules/cloud-config-container/cos-generic-metadata/README.md b/modules/cloud-config-container/cos-generic-metadata/README.md index 5a01b43ec..fef183862 100644 --- a/modules/cloud-config-container/cos-generic-metadata/README.md +++ b/modules/cloud-config-container/cos-generic-metadata/README.md @@ -64,7 +64,7 @@ module "cos-envoy" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| | [container_image](variables.tf#L42) | Container image. | string | ✓ | | -| [authenticate_gcr](variables.tf#L112) | Setup docker to pull images from private GCR. Requires at least one user since the token is stored in the home of the first user defined. | bool | | false | +| [authenticate_gcr](variables.tf#L118) | Setup docker to pull images from private GCR. Requires at least one user since the token is stored in the home of the first user defined. | bool | | false | | [boot_commands](variables.tf#L17) | List of cloud-init `bootcmd`s. | list(string) | | [] | | [cloud_config](variables.tf#L23) | Cloud config template path. If provided, takes precedence over all other arguments. | string | | null | | [config_variables](variables.tf#L29) | Additional variables used to render the template passed via `cloud_config`. | map(any) | | {} | @@ -72,11 +72,12 @@ module "cos-envoy" { | [container_name](variables.tf#L47) | Name of the container to be run. | string | | "container" | | [container_volumes](variables.tf#L53) | List of volumes. | list(object({…})) | | [] | | [docker_args](variables.tf#L62) | Extra arguments to be passed for docker. | string | | null | -| [file_defaults](variables.tf#L68) | Default owner and permissions for files. | object({…}) | | {…} | -| [files](variables.tf#L80) | Map of extra files to create on the instance, path as key. Owner and permissions will use defaults if null. | map(object({…})) | | {} | -| [gcp_logging](variables.tf#L90) | Should container logs be sent to Google Cloud Logging. | bool | | true | -| [run_commands](variables.tf#L96) | List of cloud-init `runcmd`s. | list(string) | | [] | -| [users](variables.tf#L102) | List of usernames to be created. If provided, first user will be used to run the container. | list(object({…})) | | […] | +| [docker_logging](variables.tf#L68) | Log via the Docker gcplogs driver. Disable if you use the legacy Logging Agent instead. | bool | | true | +| [file_defaults](variables.tf#L74) | Default owner and permissions for files. | object({…}) | | {…} | +| [files](variables.tf#L86) | Map of extra files to create on the instance, path as key. Owner and permissions will use defaults if null. | map(object({…})) | | {} | +| [gcp_logging](variables.tf#L96) | Should container logs be sent to Google Cloud Logging. | bool | | true | +| [run_commands](variables.tf#L102) | List of cloud-init `runcmd`s. | list(string) | | [] | +| [users](variables.tf#L108) | List of usernames to be created. If provided, first user will be used to run the container. | list(object({…})) | | […] | ## Outputs diff --git a/modules/cloud-config-container/cos-generic-metadata/cloud-config.yaml b/modules/cloud-config-container/cos-generic-metadata/cloud-config.yaml index fc75616a5..d516a1ded 100644 --- a/modules/cloud-config-container/cos-generic-metadata/cloud-config.yaml +++ b/modules/cloud-config-container/cos-generic-metadata/cloud-config.yaml @@ -44,26 +44,26 @@ write_files: After=gcr-online.target docker.socket Wants=gcr-online.target docker.socket docker-events-collector.service [Service] -%{ if authenticate_gcr && length(users) > 0 ~} + %{ if authenticate_gcr && length(users) > 0 ~} Environment="HOME=/home/${users[0].username}" ExecStartPre=/usr/bin/docker-credential-gcr configure-docker -%{ endif ~} + %{ endif ~} ExecStart=/usr/bin/docker run --rm --name=${container_name} \ -%{ if length(users) > 0 ~} + %{ if length(users) > 0 ~} --user=${users[0].uid} \ -%{ endif ~} -%{ if gcp_logging == true ~} + %{ endif ~} + %{~ if docker_logging ~} --log-driver=gcplogs \ -%{ endif ~} -%{ if docker_args != null ~} + %{~ endif ~} + %{~ if docker_args != null ~} ${docker_args} \ -%{ endif ~} -%{ for volume in container_volumes ~} + %{~ endif ~} + %{ for volume in container_volumes ~} -v ${volume.host}:${volume.container} \ -%{ endfor ~} + %{ endfor ~} ${container_image} ${container_args} ExecStop=/usr/bin/docker stop ${container_name} -%{ for path, data in files ~} + %{ for path, data in files ~} - path: ${path} owner: ${lookup(data, "owner", "root")} permissions: ${lookup(data, "permissions", "0644")} diff --git a/modules/cloud-config-container/cos-generic-metadata/main.tf b/modules/cloud-config-container/cos-generic-metadata/main.tf index 5019fa097..835183f3d 100644 --- a/modules/cloud-config-container/cos-generic-metadata/main.tf +++ b/modules/cloud-config-container/cos-generic-metadata/main.tf @@ -22,6 +22,7 @@ locals { container_name = var.container_name container_volumes = var.container_volumes docker_args = var.docker_args + docker_logging = var.docker_logging files = local.files gcp_logging = var.gcp_logging run_commands = var.run_commands diff --git a/modules/cloud-config-container/cos-generic-metadata/variables.tf b/modules/cloud-config-container/cos-generic-metadata/variables.tf index e9aa051a0..b84842f57 100644 --- a/modules/cloud-config-container/cos-generic-metadata/variables.tf +++ b/modules/cloud-config-container/cos-generic-metadata/variables.tf @@ -65,6 +65,12 @@ variable "docker_args" { default = null } +variable "docker_logging" { + description = "Log via the Docker gcplogs driver. Disable if you use the legacy Logging Agent instead." + type = bool + default = true +} + variable "file_defaults" { description = "Default owner and permissions for files." type = object({ diff --git a/modules/cloud-config-container/envoy-traffic-director/README.md b/modules/cloud-config-container/envoy-traffic-director/README.md index 4493e9ba7..c18df6e44 100644 --- a/modules/cloud-config-container/envoy-traffic-director/README.md +++ b/modules/cloud-config-container/envoy-traffic-director/README.md @@ -50,8 +50,8 @@ module "vm-cos" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| +| [docker_logging](variables.tf#L23) | Log via the Docker gcplogs driver. Disable if you use the legacy Logging Agent instead. | bool | | true | | [envoy_image](variables.tf#L17) | Envoy Proxy container image to use. | string | | "envoyproxy/envoy:v1.14.1" | -| [gcp_logging](variables.tf#L23) | Should container logs be sent to Google Cloud Logging. | bool | | true | ## Outputs diff --git a/modules/cloud-config-container/envoy-traffic-director/main.tf b/modules/cloud-config-container/envoy-traffic-director/main.tf index cdb805c6b..bc8bd7c3b 100644 --- a/modules/cloud-config-container/envoy-traffic-director/main.tf +++ b/modules/cloud-config-container/envoy-traffic-director/main.tf @@ -44,7 +44,7 @@ module "cos-envoy-td" { } } - gcp_logging = var.gcp_logging + gcp_logging = var.docker_logging run_commands = [ "iptables -t nat -N ENVOY_IN_REDIRECT", diff --git a/modules/cloud-config-container/envoy-traffic-director/variables.tf b/modules/cloud-config-container/envoy-traffic-director/variables.tf index b43b3c5ec..8135a48a1 100644 --- a/modules/cloud-config-container/envoy-traffic-director/variables.tf +++ b/modules/cloud-config-container/envoy-traffic-director/variables.tf @@ -20,8 +20,8 @@ variable "envoy_image" { default = "envoyproxy/envoy:v1.14.1" } -variable "gcp_logging" { - description = "Should container logs be sent to Google Cloud Logging." +variable "docker_logging" { + description = "Log via the Docker gcplogs driver. Disable if you use the legacy Logging Agent instead." type = bool default = true } diff --git a/modules/cloud-config-container/mysql/README.md b/modules/cloud-config-container/mysql/README.md index 4c99d5042..3dc4e7919 100644 --- a/modules/cloud-config-container/mysql/README.md +++ b/modules/cloud-config-container/mysql/README.md @@ -79,13 +79,14 @@ module "cos-mysql" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [mysql_password](variables.tf#L58) | MySQL root password. If an encrypted password is set, use the kms_config variable to specify KMS configuration. | string | ✓ | | +| [mysql_password](variables.tf#L64) | MySQL root password. If an encrypted password is set, use the kms_config variable to specify KMS configuration. | string | ✓ | | | [cloud_config](variables.tf#L17) | Cloud config template path. If null default will be used. | string | | null | | [config_variables](variables.tf#L23) | Additional variables used to render the cloud-config template. | map(any) | | {} | -| [image](variables.tf#L29) | MySQL container image. | string | | "mysql:5.7" | -| [kms_config](variables.tf#L35) | Optional KMS configuration to decrypt passed-in password. Leave null if a plaintext password is used. | object({…}) | | null | -| [mysql_config](variables.tf#L46) | MySQL configuration file content, if null container default will be used. | string | | null | -| [mysql_data_disk](variables.tf#L52) | MySQL data disk name in /dev/disk/by-id/ including the google- prefix. If null the boot disk will be used for data. | string | | null | +| [docker_logging](variables.tf#L29) | Log via the Docker gcplogs driver. Disable if you use the legacy Logging Agent instead. | bool | | true | +| [image](variables.tf#L35) | MySQL container image. | string | | "mysql:5.7" | +| [kms_config](variables.tf#L41) | Optional KMS configuration to decrypt passed-in password. Leave null if a plaintext password is used. | object({…}) | | null | +| [mysql_config](variables.tf#L52) | MySQL configuration file content, if null container default will be used. | string | | null | +| [mysql_data_disk](variables.tf#L58) | MySQL data disk name in /dev/disk/by-id/ including the google- prefix. If null the boot disk will be used for data. | string | | null | | [test_instance](variables-instance.tf#L17) | Test/development instance attributes, leave null to skip creation. | object({…}) | | null | | [test_instance_defaults](variables-instance.tf#L30) | Test/development instance defaults used for optional configuration. If image is null, COS stable will be used. | object({…}) | | {…} | diff --git a/modules/cloud-config-container/mysql/cloud-config.yaml b/modules/cloud-config-container/mysql/cloud-config.yaml index 1c792a744..e3bf831f1 100644 --- a/modules/cloud-config-container/mysql/cloud-config.yaml +++ b/modules/cloud-config-container/mysql/cloud-config.yaml @@ -96,7 +96,9 @@ write_files: ExecStartPre=/bin/chown -R 2000 /run/mysql/secrets /run/mysql/data ExecStart=/usr/bin/docker run --rm --name=mysql \ --user 2000:2000 \ + %{~ if docker_logging ~} --log-driver=gcplogs \ + %{~ endif ~} --network host \ -e MYSQL_ROOT_PASSWORD_FILE=/etc/secrets/mysql-passwd.txt \ -v /run/mysql/secrets:/etc/secrets \ diff --git a/modules/cloud-config-container/mysql/main.tf b/modules/cloud-config-container/mysql/main.tf index 4e44c4693..1dc3908d4 100644 --- a/modules/cloud-config-container/mysql/main.tf +++ b/modules/cloud-config-container/mysql/main.tf @@ -16,6 +16,7 @@ locals { cloud_config = templatefile(local.template, merge(var.config_variables, { + docker_logging = var.docker_logging image = var.image kms_config = var.kms_config mysql_config = var.mysql_config diff --git a/modules/cloud-config-container/mysql/variables.tf b/modules/cloud-config-container/mysql/variables.tf index 52bb3dbbd..d15ecfdd2 100644 --- a/modules/cloud-config-container/mysql/variables.tf +++ b/modules/cloud-config-container/mysql/variables.tf @@ -26,6 +26,12 @@ variable "config_variables" { default = {} } +variable "docker_logging" { + description = "Log via the Docker gcplogs driver. Disable if you use the legacy Logging Agent instead." + type = bool + default = true +} + variable "image" { description = "MySQL container image." type = string diff --git a/modules/cloud-config-container/nginx/README.md b/modules/cloud-config-container/nginx/README.md index c993eb72e..317f6b565 100644 --- a/modules/cloud-config-container/nginx/README.md +++ b/modules/cloud-config-container/nginx/README.md @@ -59,10 +59,11 @@ module "cos-nginx" { |---|---|:---:|:---:|:---:| | [cloud_config](variables.tf#L17) | Cloud config template path. If null default will be used. | string | | null | | [config_variables](variables.tf#L23) | Additional variables used to render the cloud-config and Nginx templates. | map(any) | | {} | -| [file_defaults](variables.tf#L41) | Default owner and permissions for files. | object({…}) | | {…} | -| [files](variables.tf#L53) | Map of extra files to create on the instance, path as key. Owner and permissions will use defaults if null. | map(object({…})) | | {} | -| [image](variables.tf#L29) | Nginx container image. | string | | "nginxdemos/hello:plain-text" | -| [nginx_config](variables.tf#L35) | Nginx configuration path, if null container default will be used. | string | | null | +| [docker_logging](variables.tf#L29) | Log via the Docker gcplogs driver. Disable if you use the legacy Logging Agent instead. | bool | | true | +| [file_defaults](variables.tf#L47) | Default owner and permissions for files. | object({…}) | | {…} | +| [files](variables.tf#L59) | Map of extra files to create on the instance, path as key. Owner and permissions will use defaults if null. | map(object({…})) | | {} | +| [image](variables.tf#L35) | Nginx container image. | string | | "nginxdemos/hello:plain-text" | +| [nginx_config](variables.tf#L41) | Nginx configuration path, if null container default will be used. | string | | null | | [test_instance](variables-instance.tf#L17) | Test/development instance attributes, leave null to skip creation. | object({…}) | | null | | [test_instance_defaults](variables-instance.tf#L30) | Test/development instance defaults used for optional configuration. If image is null, COS stable will be used. | object({…}) | | {…} | diff --git a/modules/cloud-config-container/nginx/cloud-config.yaml b/modules/cloud-config-container/nginx/cloud-config.yaml index d061e0376..f7be84dfb 100644 --- a/modules/cloud-config-container/nginx/cloud-config.yaml +++ b/modules/cloud-config-container/nginx/cloud-config.yaml @@ -53,7 +53,10 @@ write_files: Wants=gcr-online.target docker.socket docker-events-collector.service [Service] ExecStart=/usr/bin/docker run --rm --name=nginx \ - --log-driver=gcplogs --network host \ + %{~ if docker_logging ~} + --log-driver=gcplogs \ + %{~ endif ~} + --network host \ %{~ if etc_mount ~} -v /etc/nginx/conf.d:/etc/nginx/conf.d \ %{~ endif ~} diff --git a/modules/cloud-config-container/nginx/main.tf b/modules/cloud-config-container/nginx/main.tf index a2fce41b8..688545d74 100644 --- a/modules/cloud-config-container/nginx/main.tf +++ b/modules/cloud-config-container/nginx/main.tf @@ -16,6 +16,7 @@ locals { cloud_config = templatefile(local.template, merge(var.config_variables, { + docker_logging = var.docker_logging etc_mount = ( var.nginx_config != null || length([ for name in keys(var.files) : diff --git a/modules/cloud-config-container/nginx/variables.tf b/modules/cloud-config-container/nginx/variables.tf index dec89cc2b..c0ad3f6e5 100644 --- a/modules/cloud-config-container/nginx/variables.tf +++ b/modules/cloud-config-container/nginx/variables.tf @@ -26,6 +26,12 @@ variable "config_variables" { default = {} } +variable "docker_logging" { + description = "Log via the Docker gcplogs driver. Disable if you use the legacy Logging Agent instead." + type = bool + default = true +} + variable "image" { description = "Nginx container image." type = string diff --git a/modules/cloud-config-container/onprem/README.md b/modules/cloud-config-container/onprem/README.md index 222d25b04..5033dcc97 100644 --- a/modules/cloud-config-container/onprem/README.md +++ b/modules/cloud-config-container/onprem/README.md @@ -81,3 +81,4 @@ module "on-prem" { | [test_instance](outputs-instance.tf#L17) | Optional test instance name and address. | | + diff --git a/modules/cloud-config-container/squid/README.md b/modules/cloud-config-container/squid/README.md index 912c52622..7f2f45db7 100644 --- a/modules/cloud-config-container/squid/README.md +++ b/modules/cloud-config-container/squid/README.md @@ -61,15 +61,16 @@ module "cos-squid" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [allow](variables.tf#L57) | List of domains Squid will allow connections to. | list(string) | | [] | -| [clients](variables.tf#L69) | List of CIDR ranges from which Squid will allow connections. | list(string) | | [] | +| [allow](variables.tf#L63) | List of domains Squid will allow connections to. | list(string) | | [] | +| [clients](variables.tf#L75) | List of CIDR ranges from which Squid will allow connections. | list(string) | | [] | | [cloud_config](variables.tf#L17) | Cloud config template path. If null default will be used. | string | | null | | [config_variables](variables.tf#L23) | Additional variables used to render the cloud-config and Squid templates. | map(any) | | {} | -| [default_action](variables.tf#L75) | Default action for domains not matching neither the allow or deny lists. | string | | "deny" | -| [deny](variables.tf#L63) | List of domains Squid will deny connections to. | list(string) | | [] | -| [file_defaults](variables.tf#L35) | Default owner and permissions for files. | object({…}) | | {…} | -| [files](variables.tf#L47) | Map of extra files to create on the instance, path as key. Owner and permissions will use defaults if null. | map(object({…})) | | {} | -| [squid_config](variables.tf#L29) | Squid configuration path, if null default will be used. | string | | null | +| [default_action](variables.tf#L81) | Default action for domains not matching neither the allow or deny lists. | string | | "deny" | +| [deny](variables.tf#L69) | List of domains Squid will deny connections to. | list(string) | | [] | +| [docker_logging](variables.tf#L29) | Log via the Docker gcplogs driver. Disable if you use the legacy Logging Agent instead. | bool | | true | +| [file_defaults](variables.tf#L41) | Default owner and permissions for files. | object({…}) | | {…} | +| [files](variables.tf#L53) | Map of extra files to create on the instance, path as key. Owner and permissions will use defaults if null. | map(object({…})) | | {} | +| [squid_config](variables.tf#L35) | Squid configuration path, if null default will be used. | string | | null | | [test_instance](variables-instance.tf#L17) | Test/development instance attributes, leave null to skip creation. | object({…}) | | null | | [test_instance_defaults](variables-instance.tf#L30) | Test/development instance defaults used for optional configuration. If image is null, COS stable will be used. | object({…}) | | {…} | diff --git a/modules/cloud-config-container/squid/cloud-config.yaml b/modules/cloud-config-container/squid/cloud-config.yaml index b0c4b7fe3..8fef77b35 100644 --- a/modules/cloud-config-container/squid/cloud-config.yaml +++ b/modules/cloud-config-container/squid/cloud-config.yaml @@ -71,7 +71,10 @@ write_files: Environment="HOME=/home/squid" ExecStartPre=/usr/bin/docker-credential-gcr configure-docker ExecStart=/usr/bin/docker run --rm --name=squid \ - --log-driver=gcplogs --network host \ + %{~ if docker_logging ~} + --log-driver=gcplogs \ + %{~ endif ~} + --network host \ -v /etc/squid:/etc/squid \ gcr.io/pso-cft-fabric/squid:0.10 ExecStop=/usr/bin/docker stop squid diff --git a/modules/cloud-config-container/squid/main.tf b/modules/cloud-config-container/squid/main.tf index ad895c178..81538c60b 100644 --- a/modules/cloud-config-container/squid/main.tf +++ b/modules/cloud-config-container/squid/main.tf @@ -16,8 +16,9 @@ locals { cloud_config = templatefile(local.template, merge(local.config_variables, { - squid_config = templatefile(local.squid_config, local.config_variables) - files = local.files + docker_logging = var.docker_logging + squid_config = templatefile(local.squid_config, local.config_variables) + files = local.files })) squid_config = ( var.squid_config == null ? "${path.module}/squid.conf" : var.squid_config diff --git a/modules/cloud-config-container/squid/variables.tf b/modules/cloud-config-container/squid/variables.tf index 5180c6d32..6e65e779d 100644 --- a/modules/cloud-config-container/squid/variables.tf +++ b/modules/cloud-config-container/squid/variables.tf @@ -26,6 +26,12 @@ variable "config_variables" { default = {} } +variable "docker_logging" { + description = "Log via the Docker gcplogs driver. Disable if you use the legacy Logging Agent instead." + type = bool + default = true +} + variable "squid_config" { description = "Squid configuration path, if null default will be used." type = string diff --git a/modules/cloud-function/README.md b/modules/cloud-function/README.md index 46a5b4586..6eac68bf1 100644 --- a/modules/cloud-function/README.md +++ b/modules/cloud-function/README.md @@ -169,7 +169,7 @@ module "cf-http" { | [environment_variables](variables.tf#L46) | Cloud function environment variables. | map(string) | | {} | | [function_config](variables.tf#L52) | Cloud function configuration. | object({…}) | | {…} | | [iam](variables.tf#L70) | IAM bindings for topic in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | -| [ingress_settings](variables.tf#L76) | Control traffic that reaches the cloud function. Allowed values are ALLOW_ALL and ALLOW_INTERNAL_ONLY. | string | | null | +| [ingress_settings](variables.tf#L76) | Control traffic that reaches the cloud function. Allowed values are ALLOW_ALL, ALLOW_INTERNAL_AND_GCLB and ALLOW_INTERNAL_ONLY . | string | | null | | [labels](variables.tf#L82) | Resource labels. | map(string) | | {} | | [prefix](variables.tf#L93) | Optional prefix used for resource names. | string | | null | | [region](variables.tf#L104) | Region used for all resources. | string | | "europe-west1" | diff --git a/modules/cloud-function/main.tf b/modules/cloud-function/main.tf index 3a37a63f1..949cb69b1 100644 --- a/modules/cloud-function/main.tf +++ b/modules/cloud-function/main.tf @@ -103,9 +103,10 @@ resource "google_cloudfunctions_function_iam_binding" "default" { } resource "google_storage_bucket" "bucket" { - count = var.bucket_config == null ? 0 : 1 - project = var.project_id - name = "${local.prefix}${var.bucket_name}" + count = var.bucket_config == null ? 0 : 1 + project = var.project_id + name = "${local.prefix}${var.bucket_name}" + uniform_bucket_level_access = true location = ( var.bucket_config.location == null ? var.region @@ -117,7 +118,17 @@ resource "google_storage_bucket" "bucket" { for_each = var.bucket_config.lifecycle_delete_age == null ? [] : [""] content { action { type = "Delete" } - condition { age = var.bucket_config.lifecycle_delete_age } + condition { + age = var.bucket_config.lifecycle_delete_age + with_state = "ARCHIVED" + } + } + } + + dynamic "versioning" { + for_each = var.bucket_config.lifecycle_delete_age == null ? [] : [""] + content { + enabled = true } } } diff --git a/modules/cloud-function/variables.tf b/modules/cloud-function/variables.tf index 2ac663b13..a613b2f68 100644 --- a/modules/cloud-function/variables.tf +++ b/modules/cloud-function/variables.tf @@ -74,7 +74,7 @@ variable "iam" { } variable "ingress_settings" { - description = "Control traffic that reaches the cloud function. Allowed values are ALLOW_ALL and ALLOW_INTERNAL_ONLY." + description = "Control traffic that reaches the cloud function. Allowed values are ALLOW_ALL, ALLOW_INTERNAL_AND_GCLB and ALLOW_INTERNAL_ONLY ." type = string default = null } diff --git a/tools/tfdoc.py b/tools/tfdoc.py index 68bbe00cc..b4d36fb55 100755 --- a/tools/tfdoc.py +++ b/tools/tfdoc.py @@ -206,7 +206,7 @@ def parse_variables(basepath, exclude_files=None): except (IOError, OSError) as e: raise SystemExit(f'Cannot open variables file {shortname}.') for item in _parse(body): - description = ''.join(item['description']) + description = (''.join(item['description'])).replace('|', '\\|') vtype = '\n'.join(item['type']) default = HEREDOC_RE.sub(r'\1', '\n'.join(item['default'])) required = not item['default']