Scheduled script run within Google Cloud
This terraform module configures a single-file Python script to be run regularly
in Google Cloud using a cron-style scheduling syntax. It supports single-file
scripts with requirements specified via a requirements.txt
-style list of
packages.
The scripts may have secrets passed to them by a Google Secret Manager secret created for this script.
A dedicated service account is created for the script which represents the identity which the script runs as within Google Cloud.
Monitoring is configured with alerts sent if the number of successful invocations of the script within a configurable time period falls below a given threshold.
This module is not suitable for multi-file scripts or scripts which need to be passed parameters which differ from run-to-run.
Versioning
The master
branch contains the tip of development. Releases are made automatically
using release automation.
Required APIs and services
The following APIs must be enabled to use this module:
appengine.googleapis.com
cloudbuild.googleapis.com
cloudfunctions.googleapis.com
cloudscheduler.googleapis.com
secretmanager.googleapis.com
In addition there must be an app engine application configured for your project.
This is a requirement to configure Cloud Scheduler jobs. You can ensure an app
engine application is configured by means of the google_app_engine_application
resource:
resource "google_app_engine_application" "app" {
location_id = "europe-west2"
}
Monitoring
Cloud Monitoring resources are associated with a Monitoring Workspace which may
be hosted in a project which differs from the project containing other
resources. The google.monitoring
provider is used when creating Monitoring
resources and it should be a provider configured with credentials able to create
monitoring resources.
Implementation
The script is implemented as a Cloud Function and so it should conform to the
Cloud Function Python
runtime. The
entrypoint to the function can be customised but the default is to use main
.
A dedicated Cloud Storage bucket is created to store the source code in. This is created with a random name.
Example
A minimal example of running a script:
module "scheduledscript" {
source = "..."
# Name used to form resource names and human readable description.
name = "my-script"
description = "Log a message."
# Project and region to create resources in.
project = "..."
region = "europe-west2"
# A directory which can be used to store local files which are not checked in
# to source control.
local_files_dir = "/terraform_data/local"
# The script itself.
script = <<-EOL
import logging
LOG = logging.getLogger()
logging.basicConfig(level=logging.INFO)
def main(request):
LOG.info('I ran!')
return '{ "status": "ok" }', {'Content-Type': 'application/json'}
EOL
# Cron-style schedule for running the job.
schedule = "*/5 * * * *"
# Alerting threshold. Specify the minimum number of successful invocations and
# the period over which this should be measured.
alert_success_threshold = 5
alert_success_period = "3600s" # == 1hr
# Email addresses to receive alerts if invocations are failing.
alert_email_addresses = ["someone@example.com"]
# Use a separate provider with rights over the Cloud Monitoring workspace for
# monitoring resource management.
providers = {
google.monitoring = google.monitoring
}
}
See the variables.tf file for all variables.
Additional Python package requirements can be specified in the requirements
variable which should be a list of Python packages, one per line, as used by
requirements.txt
files.
A custom entry point for the script can be configured via the entry_point
variable.
Configurations can be passed to the application via the secret_configuration
variable. This should be a string which is placed in a Google Secret Manager
secret and is made available to the script. The secret is passed as a URL of the
form sm://[PROJECT]/[SECRET]#[VERSION]
in the SECRET_CONFIGURATION_SOURCE
environment variable.
Requirements
Name | Version |
---|---|
terraform | >= 0.14 |
archive | >= 2.2.0 |
> 3.60 | |
random | >= 3.1 |
Inputs
Name | Description | Type | Default | Required |
---|---|---|---|---|
alert_email_addresses | DEPRECATED. An optional list of email addresses which should recieve alerts. This creates a separate Notification Channel for every email address in the list which is often not desired. Consider creating a Notification Channel separately and passing its ID to the alert_notification_channels variable instead. |
list(string) |
[] |
no |
alert_enabled | Flag indicating if alerting should be enabled for this script. | bool |
true |
no |
alert_failure_period | Period over which 'alert_failure_threshold' is used. | string |
"3600s" |
no |
alert_failure_threshold | The number of failures which will trigger a failure alert within 'alert_success_period'. | number |
1 |
no |
alert_notification_channels | A list of notification channel IDs to send alerts to. The format for the channel IDs should be as follows. [ "projects/[PROJECT_ID]/notificationChannels/[CHANNEL_ID]" ] |
list(string) |
[] |
no |
alert_success_period | Period over which 'alert_success_threshold' is used. Default: "3600s" which is one hour. |
string |
"3600s" |
no |
alert_success_threshold | The minimum number of successes within 'alert_success_period' below which an alert is fired. |
number |
5 |
no |
available_cpu | Maxiumum number of CPUs available to the script. See https://cloud.google.com/functions/docs/configuring/memory for valid values. When this value is set, available_memory_mb must also be specified.Otherwise, the default is based on the value of available_memory_mb . |
number |
n/a | yes |
available_memory_mb | Maxiumum memory available to the script in MiB. See https://cloud.google.com/functions/docs/configuring/memory for valid values. Default: 128 MiB. |
number |
128 |
no |
description | Longer human-friendly description of the script | string |
"" |
no |
enable_versioning | The bucket's versioning configuration. While set to true, versioning is fully enabled for the bucket. |
bool |
true |
no |
entry_point | Entrypoint to script. Defaults to 'main'. | string |
"main" |
no |
environment_variables | Additional environment variables to set on the function. | map(string) |
{} |
no |
failure_alert_enabled | Flag indicating if failure alerts should be enabled for this script, separate to the default alert which is raised if a successful invocation has not been detected within the alerting period. |
bool |
false |
no |
keep_versions | The number of file versions to keep if enable_versioning is set to true. Default: 1 |
number |
1 |
no |
local_files_dir | A local directory where files may be created which persist between runs but which are not checked into source control. |
string |
n/a | yes |
monitoring_project | Project to create Cloud Monitoring resources in. Defaults to the project used by the google.monitoring provider if not specified. |
string |
"" |
no |
name | Short resource-friendly name for the script. | string |
n/a | yes |
paused | Flag indicating if the schedule is in a paused state or not. The script runs automatically according to the schedule when the schedule is not paused. When paused, the script only runs when triggered manually. Defaults to true . |
bool |
false |
no |
project | Project to create resources in. Defaults to provider project. | string |
"" |
no |
region | Region to create resources in. Defaults to London, UK. | string |
"europe-west2" |
no |
requirements | requirements.txt-style file containing script dependencies | string |
"" |
no |
runtime | Python runtime for script. See https://cloud.google.com/functions/docs/concepts/exec. Default: "python38". |
string |
"python38" |
no |
schedule | Schedule for script running. Defaults to twice per hour. See https://cloud.google.com/scheduler/docs/configuring/cron-job-schedules for a description of the format. |
string |
"*/30 * * * *" |
no |
schedule_retry_config | If a scheduled job does not complete successfully, meaning that an acknowledgement is not received from the handler, then it will be retried with exponential backoff according to these configuration options. See https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/cloud_scheduler_job#nested_retry_config for more information about these options. |
object({ |
{} |
no |
script | The script to run. This should match the requirements for the Cloud Function Python runtime. The entrypoint defaults to "main" unless overridden via the "entry_point" variable. |
string |
"def main(request):\n return 'ok'\n" |
no |
secret_configuration | Configuration which is placed in a Google Secret which can be read by the service account identity which the script runs as. A path to the secret of the form "sm://[PROJECT]/[SECRET]#[VERSION]" appears as the "SECRET_CONFIGURATION_SOURCE" environment variable. |
string |
"" |
no |
service_account | Optional existing service account to run script as. If one is not provided then one is created. Either way, the relevant permissions will be given to the account. Note: one needs to pass the actual service account object here which will be mirrored to the service_account output. |
object({ |
null |
no |
time_zone | Time zone which "schedule" should be evaluated in. Default: 'Europe/London'. | string |
"Europe/London" |
no |
timeout | Maximum time, in seconds, that a script can take to execute. Invocations which take longer than this fail. Default: 120 seconds. |
number |
120 |
no |
Outputs
Name | Description |
---|---|
function | google_cloudfunctions2_function resource for the Cloud Function created to run the script. |
job | google_cloud_scheduler_job resource for the Scheduled Job which runs the script. |
service_account | google_service_account resource for the Service Account which the script runs as. |