From fc5c38566a19d9a9226802a5c5b65cbc288c4155 Mon Sep 17 00:00:00 2001 From: Mark Edmondson Date: Mon, 15 Mar 2021 23:20:39 +0100 Subject: [PATCH] add cr_run_schedule_http #114 --- NAMESPACE | 1 + NEWS.md | 1 + R/buildsteps_templates.R | 47 +++++++++++++------------- R/cloudrun_schedule.R | 54 ++++++++++++++++++++++++++++++ _pkgdown.yml | 1 + man/HttpTarget.Rd | 1 + man/Job.Rd | 1 + man/cr_build_schedule_http.Rd | 1 + man/cr_run_schedule_http.Rd | 63 +++++++++++++++++++++++++++++++++++ man/cr_schedule.Rd | 1 + man/cr_schedule_delete.Rd | 1 + man/cr_schedule_get.Rd | 1 + man/cr_schedule_list.Rd | 1 + man/cr_schedule_pause.Rd | 1 + man/cr_schedule_run.Rd | 1 + vignettes/cloudrun.Rmd | 14 ++++++++ vignettes/cloudscheduler.Rmd | 14 ++++++++ 17 files changed, 181 insertions(+), 23 deletions(-) create mode 100644 R/cloudrun_schedule.R create mode 100644 man/cr_run_schedule_http.Rd diff --git a/NAMESPACE b/NAMESPACE index 36c119bf..e183ffa2 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -96,6 +96,7 @@ export(cr_region_set) export(cr_run) export(cr_run_get) export(cr_run_list) +export(cr_run_schedule_http) export(cr_schedule) export(cr_schedule_delete) export(cr_schedule_get) diff --git a/NEWS.md b/NEWS.md index 536ab296..ba839617 100644 --- a/NEWS.md +++ b/NEWS.md @@ -8,6 +8,7 @@ * Made Cloud Build status messages prettier * Add messaging to `cr_build_upload_gcs()` saying where deploy folder is (#110) and clean up tar.gz folder correctly * Add `gcloud_args` to `cr_buildstep_run()` and `cr_run()` to allow more customisation (#113) +* Add `cr_run_schedule_http()` to schedule Cloud Run HTTP calls # googleCloudRunner 0.4.1 diff --git a/R/buildsteps_templates.R b/R/buildsteps_templates.R index 120915cc..c3dc57b6 100644 --- a/R/buildsteps_templates.R +++ b/R/buildsteps_templates.R @@ -267,15 +267,15 @@ cr_buildstep_run <- function(name, if(allowUnauthenticated){ auth_calls <- "--allow-unauthenticated" #sometimes unauth fails, so attempt to fix as per warning suggestion - auth_step <- cr_buildstep_gcloud("gcloud", - c("run", "services", "add-iam-policy-binding", - "--region", region, - "--member=allUsers", - "--role=roles/run.invoker", - "--platform", "managed", - name), - id = "auth cloudrun", - ...) + auth_step <- cr_buildstep_gcloud( + args = c("run", "services", "add-iam-policy-binding", + "--region", region, + "--member=allUsers", + "--role=roles/run.invoker", + "--platform", "managed", + name), + id = "auth cloudrun", + ...) } if(is.null(port)){ @@ -292,19 +292,20 @@ cr_buildstep_run <- function(name, assert_that(is.character(gcloud_args)) } - deploy_step <- cr_buildstep_gcloud(c("beta","run","deploy", name, - "--image", image, - "--region", region, - "--platform", "managed", - "--concurrency", concurrency, - "--port", port, - "--max-instances", max_instances, - "--memory", memory, - "--cpu", cpu, - env_vars, - auth_calls, - gcloud_args), - id = "deploy cloudrun",...) + deploy_step <- cr_buildstep_gcloud( + args = c("beta","run","deploy", name, + "--image", image, + "--region", region, + "--platform", "managed", + "--concurrency", concurrency, + "--port", port, + "--max-instances", max_instances, + "--memory", memory, + "--cpu", cpu, + env_vars, + auth_calls, + gcloud_args), + id = "deploy cloudrun",...) c(deploy_step, auth_step) @@ -555,7 +556,7 @@ cr_buildstep_decrypt <- function(cipher, is.null(dots$prefix), is.null(dots$entrypoint) ) - cr_buildstep_gcloud(c("kms", "decrypt", + cr_buildstep_gcloud(args = c("kms", "decrypt", "--ciphertext-file", cipher, "--plaintext-file", plain, "--location", location, diff --git a/R/cloudrun_schedule.R b/R/cloudrun_schedule.R new file mode 100644 index 00000000..593d8776 --- /dev/null +++ b/R/cloudrun_schedule.R @@ -0,0 +1,54 @@ +#' Create a Cloud Scheduler HTTP target for a Cloud Run URI +#' +#' This enables Cloud Scheduler to trigger Cloud Run +#' +#' @seealso https://cloud.google.com/run/docs/triggering/using-scheduler +#' +#' @param uri The URI of your Cloud Run application +#' @param http_method The HTTP verb you have set up your Cloud Run application to receive +#' @param email The email that will authenticate the job set via \link{cr_email_set} +#' @param body (optional) An R list object that will be turned into JSON via \link[jsonlite]{toJSON} and turned into a base64-encoded string if you are doing a POST, PUT or PATCH request. +#' +#' @return A \link{HttpTarget} object for use in \link{cr_schedule} +#' +#' @details Ensure you have a service email with \link{cr_email_set} of format \code{service-{project-number}@gcp-sa-cloudscheduler.iam.gserviceaccount.com} with Cloud Scheduler Service Agent role as per https://cloud.google.com/scheduler/docs/http-target-auth#add +#' +#' @export +#' @import assertthat +#' @family Cloud Scheduler functions +#' @seealso \link{cr_build_schedule_http} +#' @examples +#' +#' run_me <- cr_run_schedule_http( +#' "https://example-ewjogewawq-ew.a.run.app/echo?msg=blah", +#' http_method = "GET" +#' ) +#' +#' \dontrun{ +#' +#' cr_schedule("cloud-run-scheduled", schedule = "16 4 * * *", +#' httpTarget = run_me) +#' +#' } +#' +cr_run_schedule_http <- function(uri, + http_method = "GET", + body = NULL, + email = cr_email_get()){ + + assert_that( + is.string(uri), + is.string(http_method), + is.string(email) + ) + + HttpTarget( + httpMethod = http_method, + uri = uri, + body = body, + oidcToken = list( + serviceAccountEmail = email, + audience = uri + ) + ) +} diff --git a/_pkgdown.yml b/_pkgdown.yml index 3ac804c5..48bdaa10 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -112,6 +112,7 @@ reference: contents: - matches("cr_schedule") - cr_build_schedule_http + - cr_run_schedule_http - Job - HttpTarget diff --git a/man/HttpTarget.Rd b/man/HttpTarget.Rd index cc688cce..54039e4e 100644 --- a/man/HttpTarget.Rd +++ b/man/HttpTarget.Rd @@ -38,6 +38,7 @@ https://cloud.google.com/scheduler/docs/reference/rest/v1/projects.locations.job Other Cloud Scheduler functions: \code{\link{Job}()}, \code{\link{cr_build_schedule_http}()}, +\code{\link{cr_run_schedule_http}()}, \code{\link{cr_schedule_delete}()}, \code{\link{cr_schedule_get}()}, \code{\link{cr_schedule_list}()}, diff --git a/man/Job.Rd b/man/Job.Rd index e6a6e725..210396a5 100644 --- a/man/Job.Rd +++ b/man/Job.Rd @@ -63,6 +63,7 @@ Configuration for a job.The maximum allowed size for a job is 100KB. Other Cloud Scheduler functions: \code{\link{HttpTarget}()}, \code{\link{cr_build_schedule_http}()}, +\code{\link{cr_run_schedule_http}()}, \code{\link{cr_schedule_delete}()}, \code{\link{cr_schedule_get}()}, \code{\link{cr_schedule_list}()}, diff --git a/man/cr_build_schedule_http.Rd b/man/cr_build_schedule_http.Rd index 57c17bcb..700f058d 100644 --- a/man/cr_build_schedule_http.Rd +++ b/man/cr_build_schedule_http.Rd @@ -51,6 +51,7 @@ https://cloud.google.com/cloud-build/docs/api/reference/rest/v1/projects.builds/ Other Cloud Scheduler functions: \code{\link{HttpTarget}()}, \code{\link{Job}()}, +\code{\link{cr_run_schedule_http}()}, \code{\link{cr_schedule_delete}()}, \code{\link{cr_schedule_get}()}, \code{\link{cr_schedule_list}()}, diff --git a/man/cr_run_schedule_http.Rd b/man/cr_run_schedule_http.Rd new file mode 100644 index 00000000..1305b6a6 --- /dev/null +++ b/man/cr_run_schedule_http.Rd @@ -0,0 +1,63 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/cloudrun_schedule.R +\name{cr_run_schedule_http} +\alias{cr_run_schedule_http} +\title{Create a Cloud Scheduler HTTP target for a Cloud Run URI} +\usage{ +cr_run_schedule_http( + uri, + http_method = "GET", + body = NULL, + email = cr_email_get() +) +} +\arguments{ +\item{uri}{The URI of your Cloud Run application} + +\item{http_method}{The HTTP verb you have set up your Cloud Run application to receive} + +\item{body}{(optional) An R list object that will be turned into JSON via \link[jsonlite]{toJSON} and turned into a base64-encoded string if you are doing a POST, PUT or PATCH request.} + +\item{email}{The email that will authenticate the job set via \link{cr_email_set}} +} +\value{ +A \link{HttpTarget} object for use in \link{cr_schedule} +} +\description{ +This enables Cloud Scheduler to trigger Cloud Run +} +\details{ +Ensure you have a service email with \link{cr_email_set} of format \code{service-{project-number}@gcp-sa-cloudscheduler.iam.gserviceaccount.com} with Cloud Scheduler Service Agent role as per https://cloud.google.com/scheduler/docs/http-target-auth#add +} +\examples{ + +run_me <- cr_run_schedule_http( + "https://example-ewjogewawq-ew.a.run.app/echo?msg=blah", + http_method = "GET" +) + +\dontrun{ + +cr_schedule("cloud-run-scheduled", schedule = "16 4 * * *", + httpTarget = run_me) + +} + +} +\seealso{ +https://cloud.google.com/run/docs/triggering/using-scheduler + +\link{cr_build_schedule_http} + +Other Cloud Scheduler functions: +\code{\link{HttpTarget}()}, +\code{\link{Job}()}, +\code{\link{cr_build_schedule_http}()}, +\code{\link{cr_schedule_delete}()}, +\code{\link{cr_schedule_get}()}, +\code{\link{cr_schedule_list}()}, +\code{\link{cr_schedule_pause}()}, +\code{\link{cr_schedule_run}()}, +\code{\link{cr_schedule}()} +} +\concept{Cloud Scheduler functions} diff --git a/man/cr_schedule.Rd b/man/cr_schedule.Rd index bbc3558f..a228e002 100644 --- a/man/cr_schedule.Rd +++ b/man/cr_schedule.Rd @@ -73,6 +73,7 @@ Other Cloud Scheduler functions: \code{\link{HttpTarget}()}, \code{\link{Job}()}, \code{\link{cr_build_schedule_http}()}, +\code{\link{cr_run_schedule_http}()}, \code{\link{cr_schedule_delete}()}, \code{\link{cr_schedule_get}()}, \code{\link{cr_schedule_list}()}, diff --git a/man/cr_schedule_delete.Rd b/man/cr_schedule_delete.Rd index 709137aa..77aae8f3 100644 --- a/man/cr_schedule_delete.Rd +++ b/man/cr_schedule_delete.Rd @@ -31,6 +31,7 @@ Other Cloud Scheduler functions: \code{\link{HttpTarget}()}, \code{\link{Job}()}, \code{\link{cr_build_schedule_http}()}, +\code{\link{cr_run_schedule_http}()}, \code{\link{cr_schedule_get}()}, \code{\link{cr_schedule_list}()}, \code{\link{cr_schedule_pause}()}, diff --git a/man/cr_schedule_get.Rd b/man/cr_schedule_get.Rd index be2cff36..1b739051 100644 --- a/man/cr_schedule_get.Rd +++ b/man/cr_schedule_get.Rd @@ -31,6 +31,7 @@ Other Cloud Scheduler functions: \code{\link{HttpTarget}()}, \code{\link{Job}()}, \code{\link{cr_build_schedule_http}()}, +\code{\link{cr_run_schedule_http}()}, \code{\link{cr_schedule_delete}()}, \code{\link{cr_schedule_list}()}, \code{\link{cr_schedule_pause}()}, diff --git a/man/cr_schedule_list.Rd b/man/cr_schedule_list.Rd index e3963d7c..4517bfe3 100644 --- a/man/cr_schedule_list.Rd +++ b/man/cr_schedule_list.Rd @@ -30,6 +30,7 @@ Other Cloud Scheduler functions: \code{\link{HttpTarget}()}, \code{\link{Job}()}, \code{\link{cr_build_schedule_http}()}, +\code{\link{cr_run_schedule_http}()}, \code{\link{cr_schedule_delete}()}, \code{\link{cr_schedule_get}()}, \code{\link{cr_schedule_pause}()}, diff --git a/man/cr_schedule_pause.Rd b/man/cr_schedule_pause.Rd index 3d94ffa4..5901590c 100644 --- a/man/cr_schedule_pause.Rd +++ b/man/cr_schedule_pause.Rd @@ -40,6 +40,7 @@ Other Cloud Scheduler functions: \code{\link{HttpTarget}()}, \code{\link{Job}()}, \code{\link{cr_build_schedule_http}()}, +\code{\link{cr_run_schedule_http}()}, \code{\link{cr_schedule_delete}()}, \code{\link{cr_schedule_get}()}, \code{\link{cr_schedule_list}()}, diff --git a/man/cr_schedule_run.Rd b/man/cr_schedule_run.Rd index ba678ce7..f54fd69f 100644 --- a/man/cr_schedule_run.Rd +++ b/man/cr_schedule_run.Rd @@ -31,6 +31,7 @@ Other Cloud Scheduler functions: \code{\link{HttpTarget}()}, \code{\link{Job}()}, \code{\link{cr_build_schedule_http}()}, +\code{\link{cr_run_schedule_http}()}, \code{\link{cr_schedule_delete}()}, \code{\link{cr_schedule_get}()}, \code{\link{cr_schedule_list}()}, diff --git a/vignettes/cloudrun.Rmd b/vignettes/cloudrun.Rmd index 7bc1edf3..7279b86e 100644 --- a/vignettes/cloudrun.Rmd +++ b/vignettes/cloudrun.Rmd @@ -415,6 +415,20 @@ res <- cr_jwt_with(GET("https://authenticated-cloudrun-ewjogewawq-ew.a.run.app/h content(res) ``` +## Scheduling Cloud Run applications + +Via [Cloud Scheduler](https://code.markedmondson.me/googleCloudRunner/articles/cloudscheduler.html) you can set up a scheduled hit of your HTTP endpoints, via GET, POST or any other methods you have coded into your app. `cr_run_schedule_http()` will help you create the HTTP endpoint for you to pass to `cr_schedule()`: + +```r +run_me <- cr_run_schedule_http( + "https://example-ewjogewawq-ew.a.run.app/echo?msg=blah", + http_method = "GET" + ) + +cr_schedule("cloud-run-scheduled", schedule = "4 16 * * *", httpTarget = run_me) + +``` + ## Deploying from another Google Cloud project By default the build will only allow deployments from the same Google Cloud Project - if you want to deploy container images from other projects you need to give the Cloud Run Service Agent for the Cloud Run project access to the source project. See this [Google help file](https://cloud.google.com/run/docs/deploying#other-projects). diff --git a/vignettes/cloudscheduler.Rmd b/vignettes/cloudscheduler.Rmd index 4cc63e4f..ff165823 100644 --- a/vignettes/cloudscheduler.Rmd +++ b/vignettes/cloudscheduler.Rmd @@ -33,6 +33,20 @@ Update a schedule by specifying the same name and the `overwrite=TRUE` flag. Yo cr_schedule("my-webhook", "12 6 * * *", overwrite=TRUE) ``` +## Schedule Cloud Run applications + +Via Cloud Scheduler you can set up a scheduled hit of your HTTP endpoints, via GET, POST or any other methods you have coded into your app. `cr_run_schedule_http()` will help you create the HTTP endpoint for you to pass to `cr_schedule()`: + +```r +run_me <- cr_run_schedule_http( + "https://example-ewjogewawq-ew.a.run.app/echo?msg=blah", + http_method = "GET" + ) + +cr_schedule("cloud-run-scheduled", schedule = "4 16 * * *", httpTarget = run_me) + +``` + ## Schedule an R script A common use case is scheduling an R script. This is provided by `cr_deploy_r()`