added support 2nd generation cloud function (#872)
* added support 2nd generation cloud function * changed function_version to a simple boolean v2 removed memory_2ndGen * will use the var.v2 to add the invoker role * removed the list uisng compact and formated the code * formated the code and added conditional feature * formated the code * added formating * resolved the merge conflict * Update readme * Create local function object * added secret_volumes and secret_environment_variables for CF V2 Co-authored-by: Julio Castillo <jccb@google.com>
This commit is contained in:
parent
d885372f4e
commit
a12da693a3
|
@ -12,7 +12,7 @@
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
# CFv2 define whether to use Cloud function 2nd generation or 1st generation
|
||||||
|
|
||||||
from distutils.command.config import config
|
from distutils.command.config import config
|
||||||
import os
|
import os
|
||||||
|
@ -22,16 +22,20 @@ from google.protobuf import field_mask_pb2
|
||||||
from googleapiclient import discovery
|
from googleapiclient import discovery
|
||||||
from metrics import ilb_fwrules, instances, networks, metrics, limits, peerings, routes, subnets, vpc_firewalls
|
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):
|
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:
|
Parameters:
|
||||||
config (dict): The dict containing config like clients and limits
|
config (dict): The dict containing config like clients and limits
|
||||||
Returns:
|
Returns:
|
||||||
monitored_projects (List of strings): Full list of projects to be monitored
|
monitored_projects (List of strings): Full list of projects to be monitored
|
||||||
'''
|
'''
|
||||||
monitored_projects = config["monitored_projects"]
|
monitored_projects = config["monitored_projects"]
|
||||||
monitored_folders = [] #os.environ.get("MONITORED_FOLDERS_LIST").split(",")
|
monitored_folders = [] #os.environ.get("MONITORED_FOLDERS_LIST").split(",")
|
||||||
|
|
||||||
|
@ -68,10 +72,10 @@ def get_monitored_projects_list(config):
|
||||||
|
|
||||||
def monitoring_interval():
|
def monitoring_interval():
|
||||||
'''
|
'''
|
||||||
Creates the monitoring interval of 24 hours
|
Creates the monitoring interval of 24 hours
|
||||||
Returns:
|
Returns:
|
||||||
monitoring_v3.TimeInterval: Monitoring time interval of 24h
|
monitoring_v3.TimeInterval: Monitoring time interval of 24h
|
||||||
'''
|
'''
|
||||||
now = time.time()
|
now = time.time()
|
||||||
seconds = int(now)
|
seconds = int(now)
|
||||||
nanos = int((now - seconds) * 10**9)
|
nanos = int((now - seconds) * 10**9)
|
||||||
|
@ -124,13 +128,13 @@ config = {
|
||||||
|
|
||||||
def main(event, context):
|
def main(event, context):
|
||||||
'''
|
'''
|
||||||
Cloud Function Entry point, called by the scheduler.
|
Cloud Function Entry point, called by the scheduler.
|
||||||
Parameters:
|
Parameters:
|
||||||
event: Not used for now (Pubsub trigger)
|
event: Not used for now (Pubsub trigger)
|
||||||
context: Not used for now (Pubsub trigger)
|
context: Not used for now (Pubsub trigger)
|
||||||
Returns:
|
Returns:
|
||||||
'Function executed successfully'
|
'Function executed successfully'
|
||||||
'''
|
'''
|
||||||
# Handling empty monitored projects list
|
# Handling empty monitored projects list
|
||||||
if config["monitored_projects"] == ['']:
|
if config["monitored_projects"] == ['']:
|
||||||
config["monitored_projects"] = []
|
config["monitored_projects"] = []
|
||||||
|
@ -203,5 +207,11 @@ def main(event, context):
|
||||||
return 'Function executed successfully'
|
return 'Function executed successfully'
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if CFv2:
|
||||||
main(None, None)
|
|
||||||
|
@functions_framework.http
|
||||||
|
def main_http(request):
|
||||||
|
main(None, None)
|
||||||
|
else:
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main(None, None)
|
|
@ -7,4 +7,5 @@ google-cloud-monitoring==2.9.1
|
||||||
oauth2client==4.1.3
|
oauth2client==4.1.3
|
||||||
google-api-core==2.7.0
|
google-api-core==2.7.0
|
||||||
PyYAML==6.0
|
PyYAML==6.0
|
||||||
google-cloud-asset==3.8.1
|
google-cloud-asset==3.8.1
|
||||||
|
functions-framework==3.*
|
|
@ -50,6 +50,8 @@ module "service-account-function" {
|
||||||
# Required IAM permissions for this service account are:
|
# 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)
|
# 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)
|
# 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 = {
|
iam_organization_roles = {
|
||||||
"${var.organization_id}" = [
|
"${var.organization_id}" = [
|
||||||
"roles/compute.networkViewer",
|
"roles/compute.networkViewer",
|
||||||
|
@ -59,17 +61,20 @@ module "service-account-function" {
|
||||||
}
|
}
|
||||||
|
|
||||||
iam_project_roles = {
|
iam_project_roles = {
|
||||||
"${local.monitoring_project}" = [
|
"${local.monitoring_project}" = compact([
|
||||||
"roles/monitoring.metricWriter"
|
"roles/monitoring.metricWriter",
|
||||||
]
|
var.v2 ? "roles/run.invoker" : ""
|
||||||
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
################################################
|
################################################
|
||||||
# Cloud Function configuration (& Scheduler) #
|
# Cloud Function configuration (& Scheduler) #
|
||||||
|
# you can comment out the pub/sub call in case of 2nd generation function
|
||||||
################################################
|
################################################
|
||||||
|
|
||||||
module "pubsub" {
|
module "pubsub" {
|
||||||
|
|
||||||
source = "../../../modules/pubsub"
|
source = "../../../modules/pubsub"
|
||||||
project_id = local.monitoring_project
|
project_id = local.monitoring_project
|
||||||
name = "network-dashboard-pubsub"
|
name = "network-dashboard-pubsub"
|
||||||
|
@ -81,6 +86,7 @@ module "pubsub" {
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "google_cloud_scheduler_job" "job" {
|
resource "google_cloud_scheduler_job" "job" {
|
||||||
|
count = var.v2 ? 0 : 1
|
||||||
project = local.monitoring_project
|
project = local.monitoring_project
|
||||||
region = var.region
|
region = var.region
|
||||||
name = "network-dashboard-scheduler"
|
name = "network-dashboard-scheduler"
|
||||||
|
@ -92,9 +98,28 @@ resource "google_cloud_scheduler_job" "job" {
|
||||||
data = base64encode("test")
|
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" {
|
module "cloud-function" {
|
||||||
|
v2 = var.v2
|
||||||
source = "../../../modules/cloud-function"
|
source = "../../../modules/cloud-function"
|
||||||
project_id = local.monitoring_project
|
project_id = local.monitoring_project
|
||||||
name = "network-dashboard-cloud-function"
|
name = "network-dashboard-cloud-function"
|
||||||
|
@ -115,7 +140,8 @@ module "cloud-function" {
|
||||||
entry_point = "main"
|
entry_point = "main"
|
||||||
runtime = "python39"
|
runtime = "python39"
|
||||||
instances = 1
|
instances = 1
|
||||||
memory = 256
|
memory = 256 # Memory in MB
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
environment_variables = {
|
environment_variables = {
|
||||||
|
|
|
@ -69,4 +69,9 @@ variable "project_monitoring_services" {
|
||||||
variable "region" {
|
variable "region" {
|
||||||
description = "Region used to deploy the cloud functions and scheduler"
|
description = "Region used to deploy the cloud functions and scheduler"
|
||||||
default = "europe-west1"
|
default = "europe-west1"
|
||||||
|
}
|
||||||
|
variable "v2" {
|
||||||
|
description = "Whether to use Cloud Function version 2nd Gen or 1st Gen."
|
||||||
|
type = bool
|
||||||
|
default = false
|
||||||
}
|
}
|
|
@ -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. | <code title="object({ location = string lifecycle_delete_age = number })">object({…})</code> | | <code>null</code> |
|
| [bucket_config](variables.tf#L17) | Enable and configure auto-created bucket. Set fields to null to use defaults. | <code title="object({ location = string lifecycle_delete_age = number })">object({…})</code> | | <code>null</code> |
|
||||||
| [description](variables.tf#L40) | Optional description. | <code>string</code> | | <code>"Terraform managed."</code> |
|
| [description](variables.tf#L40) | Optional description. | <code>string</code> | | <code>"Terraform managed."</code> |
|
||||||
| [environment_variables](variables.tf#L46) | Cloud function environment variables. | <code>map(string)</code> | | <code>{}</code> |
|
| [environment_variables](variables.tf#L46) | Cloud function environment variables. | <code>map(string)</code> | | <code>{}</code> |
|
||||||
| [function_config](variables.tf#L52) | Cloud function configuration. | <code title="object({ entry_point = string instances = number memory = number runtime = string timeout = number })">object({…})</code> | | <code title="{ entry_point = "main" instances = 1 memory = 256 runtime = "python37" timeout = 180 }">{…}</code> |
|
| [function_config](variables.tf#L52) | Cloud function configuration. | <code title="object({ entry_point = string instances = number memory = number # Memory in MB runtime = string timeout = number })">object({…})</code> | | <code title="{ entry_point = "main" instances = 1 memory = 256 runtime = "python37" timeout = 180 }">{…}</code> |
|
||||||
| [iam](variables.tf#L70) | IAM bindings for topic in {ROLE => [MEMBERS]} format. | <code>map(list(string))</code> | | <code>{}</code> |
|
| [iam](variables.tf#L70) | IAM bindings for topic in {ROLE => [MEMBERS]} format. | <code>map(list(string))</code> | | <code>{}</code> |
|
||||||
| [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 . | <code>string</code> | | <code>null</code> |
|
| [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 . | <code>string</code> | | <code>null</code> |
|
||||||
| [labels](variables.tf#L82) | Resource labels. | <code>map(string)</code> | | <code>{}</code> |
|
| [labels](variables.tf#L82) | Resource labels. | <code>map(string)</code> | | <code>{}</code> |
|
||||||
|
@ -177,6 +177,7 @@ module "cf-http" {
|
||||||
| [service_account](variables.tf#L122) | Service account email. Unused if service account is auto-created. | <code>string</code> | | <code>null</code> |
|
| [service_account](variables.tf#L122) | Service account email. Unused if service account is auto-created. | <code>string</code> | | <code>null</code> |
|
||||||
| [service_account_create](variables.tf#L128) | Auto-create service account. | <code>bool</code> | | <code>false</code> |
|
| [service_account_create](variables.tf#L128) | Auto-create service account. | <code>bool</code> | | <code>false</code> |
|
||||||
| [trigger_config](variables.tf#L134) | Function trigger configuration. Leave null for HTTP trigger. | <code title="object({ event = string resource = string retry = bool })">object({…})</code> | | <code>null</code> |
|
| [trigger_config](variables.tf#L134) | Function trigger configuration. Leave null for HTTP trigger. | <code title="object({ event = string resource = string retry = bool })">object({…})</code> | | <code>null</code> |
|
||||||
|
| [v2](variables.tf#L163) | Whether to use Cloud Function version 2nd Gen or 1st Gen. | <code>bool</code> | | <code>false</code> |
|
||||||
| [vpc_connector](variables.tf#L144) | VPC connector configuration. Set create to 'true' if a new connector needs to be created. | <code title="object({ create = bool name = string egress_settings = string })">object({…})</code> | | <code>null</code> |
|
| [vpc_connector](variables.tf#L144) | VPC connector configuration. Set create to 'true' if a new connector needs to be created. | <code title="object({ create = bool name = string egress_settings = string })">object({…})</code> | | <code>null</code> |
|
||||||
| [vpc_connector_config](variables.tf#L154) | VPC connector network configuration. Must be provided if new VPC connector is being created. | <code title="object({ ip_cidr_range = string network = string })">object({…})</code> | | <code>null</code> |
|
| [vpc_connector_config](variables.tf#L154) | VPC connector network configuration. Must be provided if new VPC connector is being created. | <code title="object({ ip_cidr_range = string network = string })">object({…})</code> | | <code>null</code> |
|
||||||
|
|
||||||
|
@ -188,9 +189,10 @@ module "cf-http" {
|
||||||
| [bucket_name](outputs.tf#L24) | Bucket name. | |
|
| [bucket_name](outputs.tf#L24) | Bucket name. | |
|
||||||
| [function](outputs.tf#L29) | Cloud function resources. | |
|
| [function](outputs.tf#L29) | Cloud function resources. | |
|
||||||
| [function_name](outputs.tf#L34) | Cloud function name. | |
|
| [function_name](outputs.tf#L34) | Cloud function name. | |
|
||||||
| [service_account](outputs.tf#L39) | Service account resource. | |
|
| [service_account](outputs.tf#L42) | Service account resource. | |
|
||||||
| [service_account_email](outputs.tf#L44) | Service account email. | |
|
| [service_account_email](outputs.tf#L47) | Service account email. | |
|
||||||
| [service_account_iam_email](outputs.tf#L49) | Service account email. | |
|
| [service_account_iam_email](outputs.tf#L52) | Service account email. | |
|
||||||
| [vpc_connector](outputs.tf#L57) | VPC connector resource if created. | |
|
| [uri](outputs.tf#L38) | Cloud function service uri. | |
|
||||||
|
| [vpc_connector](outputs.tf#L60) | VPC connector resource if created. | |
|
||||||
|
|
||||||
<!-- END TFDOC -->
|
<!-- END TFDOC -->
|
||||||
|
|
|
@ -24,6 +24,11 @@ locals {
|
||||||
: null
|
: null
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
function = (
|
||||||
|
var.v2
|
||||||
|
? google_cloudfunctions2_function.function[0]
|
||||||
|
: google_cloudfunctions_function.function[0]
|
||||||
|
)
|
||||||
prefix = var.prefix == null ? "" : "${var.prefix}-"
|
prefix = var.prefix == null ? "" : "${var.prefix}-"
|
||||||
service_account_email = (
|
service_account_email = (
|
||||||
var.service_account_create
|
var.service_account_create
|
||||||
|
@ -55,6 +60,7 @@ resource "google_vpc_access_connector" "connector" {
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "google_cloudfunctions_function" "function" {
|
resource "google_cloudfunctions_function" "function" {
|
||||||
|
count = var.v2 ? 0 : 1
|
||||||
project = var.project_id
|
project = var.project_id
|
||||||
region = var.region
|
region = var.region
|
||||||
name = "${local.prefix}${var.name}"
|
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" {
|
resource "google_cloudfunctions_function_iam_binding" "default" {
|
||||||
for_each = var.iam
|
for_each = var.iam
|
||||||
project = var.project_id
|
project = var.project_id
|
||||||
region = var.region
|
region = var.region
|
||||||
cloud_function = google_cloudfunctions_function.function.name
|
cloud_function = local.function.name
|
||||||
role = each.key
|
role = each.key
|
||||||
members = each.value
|
members = each.value
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,14 +28,17 @@ output "bucket_name" {
|
||||||
|
|
||||||
output "function" {
|
output "function" {
|
||||||
description = "Cloud function resources."
|
description = "Cloud function resources."
|
||||||
value = google_cloudfunctions_function.function
|
value = local.function
|
||||||
}
|
}
|
||||||
|
|
||||||
output "function_name" {
|
output "function_name" {
|
||||||
description = "Cloud 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" {
|
output "service_account" {
|
||||||
description = "Service account resource."
|
description = "Service account resource."
|
||||||
value = try(google_service_account.service_account[0], null)
|
value = try(google_service_account.service_account[0], null)
|
||||||
|
|
|
@ -54,7 +54,7 @@ variable "function_config" {
|
||||||
type = object({
|
type = object({
|
||||||
entry_point = string
|
entry_point = string
|
||||||
instances = number
|
instances = number
|
||||||
memory = number
|
memory = number # Memory in MB
|
||||||
runtime = string
|
runtime = string
|
||||||
timeout = number
|
timeout = number
|
||||||
})
|
})
|
||||||
|
@ -160,3 +160,9 @@ variable "vpc_connector_config" {
|
||||||
default = null
|
default = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
variable "v2" {
|
||||||
|
description = "Whether to use Cloud Function version 2nd Gen or 1st Gen."
|
||||||
|
type = bool
|
||||||
|
default = false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue