diff --git a/blueprints/cloud-operations/network-dashboard/cloud-function/main.py b/blueprints/cloud-operations/network-dashboard/cloud-function/main.py
index 7b36c79ab..ae380c209 100644
--- a/blueprints/cloud-operations/network-dashboard/cloud-function/main.py
+++ b/blueprints/cloud-operations/network-dashboard/cloud-function/main.py
@@ -12,7 +12,7 @@
# 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.
-#
+# CFv2 define whether to use Cloud function 2nd generation or 1st generation
from distutils.command.config import config
import os
@@ -22,16 +22,20 @@ from google.protobuf import field_mask_pb2
from googleapiclient import discovery
from metrics import ilb_fwrules, instances, networks, metrics, limits, peerings, routes, subnets, vpc_firewalls
+CFv2 = False
+if CFv2:
+ import functions_framework
+
def get_monitored_projects_list(config):
'''
- Gets the projects to be monitored from the MONITORED_FOLDERS_LIST environment variable.
+ Gets the projects to be monitored from the MONITORED_FOLDERS_LIST environment variable.
- Parameters:
- config (dict): The dict containing config like clients and limits
- Returns:
- monitored_projects (List of strings): Full list of projects to be monitored
- '''
+ Parameters:
+ config (dict): The dict containing config like clients and limits
+ Returns:
+ monitored_projects (List of strings): Full list of projects to be monitored
+ '''
monitored_projects = config["monitored_projects"]
monitored_folders = [] #os.environ.get("MONITORED_FOLDERS_LIST").split(",")
@@ -68,10 +72,10 @@ def get_monitored_projects_list(config):
def monitoring_interval():
'''
- Creates the monitoring interval of 24 hours
- Returns:
- monitoring_v3.TimeInterval: Monitoring time interval of 24h
- '''
+ Creates the monitoring interval of 24 hours
+ Returns:
+ monitoring_v3.TimeInterval: Monitoring time interval of 24h
+ '''
now = time.time()
seconds = int(now)
nanos = int((now - seconds) * 10**9)
@@ -124,13 +128,13 @@ config = {
def main(event, context):
'''
- Cloud Function Entry point, called by the scheduler.
- Parameters:
- event: Not used for now (Pubsub trigger)
- context: Not used for now (Pubsub trigger)
- Returns:
- 'Function executed successfully'
- '''
+ Cloud Function Entry point, called by the scheduler.
+ Parameters:
+ event: Not used for now (Pubsub trigger)
+ context: Not used for now (Pubsub trigger)
+ Returns:
+ 'Function executed successfully'
+ '''
# Handling empty monitored projects list
if config["monitored_projects"] == ['']:
config["monitored_projects"] = []
@@ -203,5 +207,11 @@ def main(event, context):
return 'Function executed successfully'
-if __name__ == "__main__":
- main(None, None)
+if CFv2:
+
+ @functions_framework.http
+ def main_http(request):
+ main(None, None)
+else:
+ if __name__ == "__main__":
+ main(None, None)
\ No newline at end of file
diff --git a/blueprints/cloud-operations/network-dashboard/cloud-function/requirements.txt b/blueprints/cloud-operations/network-dashboard/cloud-function/requirements.txt
index 8a6a5960b..d56134822 100644
--- a/blueprints/cloud-operations/network-dashboard/cloud-function/requirements.txt
+++ b/blueprints/cloud-operations/network-dashboard/cloud-function/requirements.txt
@@ -7,4 +7,5 @@ google-cloud-monitoring==2.9.1
oauth2client==4.1.3
google-api-core==2.7.0
PyYAML==6.0
-google-cloud-asset==3.8.1
\ No newline at end of file
+google-cloud-asset==3.8.1
+functions-framework==3.*
\ No newline at end of file
diff --git a/blueprints/cloud-operations/network-dashboard/main.tf b/blueprints/cloud-operations/network-dashboard/main.tf
index a381d21d5..932adeaea 100644
--- a/blueprints/cloud-operations/network-dashboard/main.tf
+++ b/blueprints/cloud-operations/network-dashboard/main.tf
@@ -50,6 +50,8 @@ module "service-account-function" {
# Required IAM permissions for this service account are:
# 1) compute.networkViewer on projects to be monitored (I gave it at organization level for now for simplicity)
# 2) monitoring viewer on the projects to be monitored (I gave it at organization level for now for simplicity)
+ # 3) if you dont have permission to create service account and assign permission at organization Level, move these 3 roles to project level.
+
iam_organization_roles = {
"${var.organization_id}" = [
"roles/compute.networkViewer",
@@ -59,17 +61,20 @@ module "service-account-function" {
}
iam_project_roles = {
- "${local.monitoring_project}" = [
- "roles/monitoring.metricWriter"
- ]
+ "${local.monitoring_project}" = compact([
+ "roles/monitoring.metricWriter",
+ var.v2 ? "roles/run.invoker" : ""
+ ])
}
}
################################################
# Cloud Function configuration (& Scheduler) #
+# you can comment out the pub/sub call in case of 2nd generation function
################################################
module "pubsub" {
+
source = "../../../modules/pubsub"
project_id = local.monitoring_project
name = "network-dashboard-pubsub"
@@ -81,6 +86,7 @@ module "pubsub" {
}
resource "google_cloud_scheduler_job" "job" {
+ count = var.v2 ? 0 : 1
project = local.monitoring_project
region = var.region
name = "network-dashboard-scheduler"
@@ -92,9 +98,28 @@ resource "google_cloud_scheduler_job" "job" {
data = base64encode("test")
}
}
+#http trigger for 2nd generation function
+resource "google_cloud_scheduler_job" "job_httptrigger" {
+ count = var.v2 ? 1 : 0
+ project = local.monitoring_project
+ region = var.region
+ name = "network-dashboard-scheduler"
+ schedule = var.schedule_cron
+ time_zone = "UTC"
+
+ http_target {
+ http_method = "POST"
+ uri = module.cloud-function.uri
+
+ oidc_token {
+ service_account_email = module.service-account-function.email
+ }
+ }
+}
module "cloud-function" {
+ v2 = var.v2
source = "../../../modules/cloud-function"
project_id = local.monitoring_project
name = "network-dashboard-cloud-function"
@@ -115,7 +140,8 @@ module "cloud-function" {
entry_point = "main"
runtime = "python39"
instances = 1
- memory = 256
+ memory = 256 # Memory in MB
+
}
environment_variables = {
diff --git a/blueprints/cloud-operations/network-dashboard/variables.tf b/blueprints/cloud-operations/network-dashboard/variables.tf
index 63a61ee99..dbb2921f4 100644
--- a/blueprints/cloud-operations/network-dashboard/variables.tf
+++ b/blueprints/cloud-operations/network-dashboard/variables.tf
@@ -69,4 +69,9 @@ variable "project_monitoring_services" {
variable "region" {
description = "Region used to deploy the cloud functions and scheduler"
default = "europe-west1"
+}
+variable "v2" {
+ description = "Whether to use Cloud Function version 2nd Gen or 1st Gen."
+ type = bool
+ default = false
}
\ No newline at end of file
diff --git a/modules/cloud-function/README.md b/modules/cloud-function/README.md
index ffad5d4cc..b51285b3c 100644
--- a/modules/cloud-function/README.md
+++ b/modules/cloud-function/README.md
@@ -167,7 +167,7 @@ module "cf-http" {
| [bucket_config](variables.tf#L17) | Enable and configure auto-created bucket. Set fields to null to use defaults. | object({…}) | | null |
| [description](variables.tf#L40) | Optional description. | string | | "Terraform managed." |
| [environment_variables](variables.tf#L46) | Cloud function environment variables. | map(string) | | {} |
-| [function_config](variables.tf#L52) | Cloud function configuration. | object({…}) | | {…} |
+| [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, ALLOW_INTERNAL_AND_GCLB and ALLOW_INTERNAL_ONLY . | string | | null |
| [labels](variables.tf#L82) | Resource labels. | map(string) | | {} |
@@ -177,6 +177,7 @@ module "cf-http" {
| [service_account](variables.tf#L122) | Service account email. Unused if service account is auto-created. | string | | null |
| [service_account_create](variables.tf#L128) | Auto-create service account. | bool | | false |
| [trigger_config](variables.tf#L134) | Function trigger configuration. Leave null for HTTP trigger. | object({…}) | | null |
+| [v2](variables.tf#L163) | Whether to use Cloud Function version 2nd Gen or 1st Gen. | bool | | false |
| [vpc_connector](variables.tf#L144) | VPC connector configuration. Set create to 'true' if a new connector needs to be created. | object({…}) | | null |
| [vpc_connector_config](variables.tf#L154) | VPC connector network configuration. Must be provided if new VPC connector is being created. | object({…}) | | null |
@@ -188,9 +189,10 @@ module "cf-http" {
| [bucket_name](outputs.tf#L24) | Bucket name. | |
| [function](outputs.tf#L29) | Cloud function resources. | |
| [function_name](outputs.tf#L34) | Cloud function name. | |
-| [service_account](outputs.tf#L39) | Service account resource. | |
-| [service_account_email](outputs.tf#L44) | Service account email. | |
-| [service_account_iam_email](outputs.tf#L49) | Service account email. | |
-| [vpc_connector](outputs.tf#L57) | VPC connector resource if created. | |
+| [service_account](outputs.tf#L42) | Service account resource. | |
+| [service_account_email](outputs.tf#L47) | Service account email. | |
+| [service_account_iam_email](outputs.tf#L52) | Service account email. | |
+| [uri](outputs.tf#L38) | Cloud function service uri. | |
+| [vpc_connector](outputs.tf#L60) | VPC connector resource if created. | |
diff --git a/modules/cloud-function/main.tf b/modules/cloud-function/main.tf
index 0a26c1205..1ad64f46e 100644
--- a/modules/cloud-function/main.tf
+++ b/modules/cloud-function/main.tf
@@ -24,6 +24,11 @@ locals {
: null
)
)
+ function = (
+ var.v2
+ ? google_cloudfunctions2_function.function[0]
+ : google_cloudfunctions_function.function[0]
+ )
prefix = var.prefix == null ? "" : "${var.prefix}-"
service_account_email = (
var.service_account_create
@@ -55,6 +60,7 @@ resource "google_vpc_access_connector" "connector" {
}
resource "google_cloudfunctions_function" "function" {
+ count = var.v2 ? 0 : 1
project = var.project_id
region = var.region
name = "${local.prefix}${var.name}"
@@ -122,11 +128,74 @@ resource "google_cloudfunctions_function" "function" {
}
+resource "google_cloudfunctions2_function" "function" {
+ count = var.v2 ? 1 : 0
+ provider = google-beta
+ project = var.project_id
+ location = var.region
+ name = "${local.prefix}${var.name}"
+ description = var.description
+ build_config {
+ runtime = var.function_config.runtime
+ entry_point = "${var.function_config.entry_point}_http" # Set the entry point
+ environment_variables = var.environment_variables
+ source {
+ storage_source {
+ bucket = google_storage_bucket.bucket[0].name
+ object = google_storage_bucket_object.bundle.name
+ }
+ }
+ }
+ service_config {
+ max_instance_count = var.function_config.instances
+ min_instance_count = 0
+ available_memory = "${var.function_config.memory}M"
+ timeout_seconds = var.function_config.timeout
+ environment_variables = var.environment_variables
+ ingress_settings = var.ingress_settings
+ all_traffic_on_latest_revision = true
+ service_account_email = local.service_account_email
+ vpc_connector = local.vpc_connector
+ vpc_connector_egress_settings = try(
+ var.vpc_connector.egress_settings, null)
+
+ dynamic "secret_environment_variables" {
+ for_each = { for k, v in var.secrets : k => v if !v.is_volume }
+ iterator = secret
+ content {
+ key = secret.key
+ project_id = secret.value.project_id
+ secret = secret.value.secret
+ version = try(secret.value.versions.0, "latest")
+ }
+ }
+
+ dynamic "secret_volumes" {
+ for_each = { for k, v in var.secrets : k => v if v.is_volume }
+ iterator = secret
+ content {
+ mount_path = secret.key
+ project_id = secret.value.project_id
+ secret = secret.value.secret
+ dynamic "versions" {
+ for_each = secret.value.versions
+ iterator = version
+ content {
+ path = split(":", version)[1]
+ version = split(":", version)[0]
+ }
+ }
+ }
+ }
+ }
+ labels = var.labels
+}
+
resource "google_cloudfunctions_function_iam_binding" "default" {
for_each = var.iam
project = var.project_id
region = var.region
- cloud_function = google_cloudfunctions_function.function.name
+ cloud_function = local.function.name
role = each.key
members = each.value
}
diff --git a/modules/cloud-function/outputs.tf b/modules/cloud-function/outputs.tf
index 1071270e1..a4bbcebb4 100644
--- a/modules/cloud-function/outputs.tf
+++ b/modules/cloud-function/outputs.tf
@@ -28,14 +28,17 @@ output "bucket_name" {
output "function" {
description = "Cloud function resources."
- value = google_cloudfunctions_function.function
+ value = local.function
}
output "function_name" {
description = "Cloud function name."
- value = google_cloudfunctions_function.function.name
+ value = local.function.name
+}
+output "uri" {
+ description = "Cloud function service uri."
+ value = var.v2 ? google_cloudfunctions2_function.function[0].service_config[0].uri : null
}
-
output "service_account" {
description = "Service account resource."
value = try(google_service_account.service_account[0], null)
diff --git a/modules/cloud-function/variables.tf b/modules/cloud-function/variables.tf
index ce8633c8f..8458bff6a 100644
--- a/modules/cloud-function/variables.tf
+++ b/modules/cloud-function/variables.tf
@@ -54,7 +54,7 @@ variable "function_config" {
type = object({
entry_point = string
instances = number
- memory = number
+ memory = number # Memory in MB
runtime = string
timeout = number
})
@@ -160,3 +160,9 @@ variable "vpc_connector_config" {
default = null
}
+variable "v2" {
+ description = "Whether to use Cloud Function version 2nd Gen or 1st Gen."
+ type = bool
+ default = false
+}
+