Introduction#
I recently had to deploy a scheduled Cloud Build job for a project at work. As this can be easily done through the GCP console, I was expecting to find a cloudbuild_target
argument in the google_cloud_scheduler_job
resource which unfortunately was not the case^.
The solution#
The idea is to define a google_cloud_scheduler_job
with a HTTP target since each build trigger comes with its own REST API URL.
The URL takes a triggerId
as path parameter, which can be retrieved using the below commands.
1
2
3
| $ TRIGGER_NAME=<YOUR_TRIGGER_NAME>
$ gcloud alpha builds triggers list --filter="(name:$TRIGGER_NAME)" --format=json | jq ".[] | .id"
"20cc4c01-aa55-4c44-8d47-XXXXXXXXXXXX"
|
We also need to take care of authorization to the Google API. Fortunately, google_cloud_scheduler_job
provides an oauth_token
argument for us to provide details for our authorized service account, which we will grant the following permissions:
roles/appengine.appAdmin
roles/appengine.appCreator
roles/cloudscheduler.admin
roles/cloudbuild.builds.builder
We can then define our resources in main.tf
as such:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
| # main.tf
locals {
# replace values accordingly
project_id = <YOUR_PROJECT_ID>
region = <YOUR_REGION>
tz = <YOUR_TIMEZONE>
trigger_id = <BUILD_TRIGGER_ID> # replace with triggerId retrieved earlier
branch = <BUILD_BRANCH>
schedule = "0 8 * * *"
}
resource "google_service_account" "cloud_scheduler" {
account_id = "cloud-scheduler"
display_name = "⏱ cloud-scheduler"
description = "Service account for scheduling jobs on Cloud Scheduler"
project = local.project_id
}
resource "google_project_iam_member" "cloud_scheduler" {
for_each = toset([
"roles/appengine.appAdmin",
"roles/appengine.appCreator",
"roles/cloudscheduler.admin",
"roles/cloudbuild.builds.builder",
])
project = local.project_id
role = each.key
member = "serviceAccount:${google_service_account.cloud_scheduler.email}"
}
resource "google_cloud_scheduler_job" "job" {
project = local.project_id
region = local.region
name = "example-job"
description = "sample scheduled build trigger"
schedule = local.schedule
time_zone = local.tz
attempt_deadline = "320s"
http_target {
http_method = "POST"
uri = "https://cloudbuild.googleapis.com/v1/projects/${local.project_id}/triggers/${local.trigger_id}:run"
body = base64encode("{\"branchName\":\"${local.branch}\"}")
headers = {
"Content-Type" = "application/octet-stream"
"User-Agent" = "Google-Cloud-Scheduler"
}
oauth_token {
service_account_email = google_service_account.cloud_scheduler.email
scope = "https://www.googleapis.com/auth/cloud-platform"
}
}
}
|
What our scheduled job looks like after deployment:

We can also see that the build trigger runs as intended. Great success!

Conclusion#
GCP’s extensive APIs makes it easy to schedule any task with an endpoint in Cloud Scheduler. While not intuitive, implementing it via the official provider is definitely possible as demonstrated.
^ accurate as of v4.22.0 of the Hashicorp google provider