Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
6fb537e
feat: migrate postdeployment to data http
glasnt Jul 19, 2023
10a979e
lint
glasnt Jul 19, 2023
2e55250
lint: add ignore to side-effect 'unused' data sources
glasnt Jul 19, 2023
03741e2
WIP NO MERGE: progress on cloudbuild-based deployments
glasnt Jul 20, 2023
751f8c3
WIP save
glasnt Jul 21, 2023
2f0d20d
Merge branch 'main' into feat/postjsstrigger
glasnt Jul 21, 2023
b839b62
remove unused code
glasnt Jul 21, 2023
ba1d223
cleanup todos
glasnt Jul 21, 2023
126c684
Add roles/pubsub.editor permissions
glasnt Jul 21, 2023
9a95c4a
terraform format
glasnt Jul 21, 2023
821bfb1
lint: trim whitespace
glasnt Jul 21, 2023
d2a720f
lint: ignore unused variable (for now)
glasnt Jul 21, 2023
604bda4
Add roles/cloudbuild.builds.editor permissions
glasnt Jul 21, 2023
d3dbb07
bump avocano version
glasnt Jul 21, 2023
323ef0e
bump avocano version
glasnt Jul 21, 2023
dc04522
use updated placeholder placeholder
glasnt Jul 21, 2023
cfd9c39
still use a client job, rather than a step.
glasnt Jul 21, 2023
c5830b3
move from distroless to ubuntu
glasnt Jul 21, 2023
4b0a2da
fix: ensure correct workdir used when using image in cloudbuild
glasnt Jul 21, 2023
fdcd270
make all init jobs optional; (debug) use init sa for permissions
glasnt Jul 21, 2023
f4fffbe
update optional resources
glasnt Jul 21, 2023
729b0a2
(maybe?) ensure broken placeholder looks identical to working init tr…
glasnt Jul 21, 2023
ae37622
lint
glasnt Jul 21, 2023
7ed09e4
the trigger execution needs to wait for the permissions to land
glasnt Jul 21, 2023
c505dc2
cleanup depends, don't give client perms it doesn't need anymore
glasnt Jul 21, 2023
0475b3a
add an wait to let iam consist eventually, attempt to fix race condit…
glasnt Jul 21, 2023
469df4a
debug: wait longer, and for more debugs
glasnt Jul 21, 2023
33ef1df
that's not a resource
glasnt Jul 21, 2023
782f6b6
neither is that
glasnt Jul 21, 2023
fc1c236
debug: improve iam reliability by artificially staggering triggers
glasnt Jul 21, 2023
c2d094f
remove duplicate cloud run job declaration
glasnt Jul 21, 2023
6d6a312
correct removal of tf-based client job
glasnt Jul 21, 2023
75af1dc
correct syntax
glasnt Jul 21, 2023
057953b
cleanup IAM, attempt to reduce concurrent policy changes
glasnt Jul 21, 2023
e74695c
lint, remove unused helpers
glasnt Jul 21, 2023
a75787e
fix syntax
glasnt Jul 21, 2023
1bca6da
cleanup client job
glasnt Jul 21, 2023
f153dbc
init needs firebase admin
glasnt Jul 21, 2023
fecf354
create the client job as early as possible, hopefully helping tests
glasnt Jul 21, 2023
6469113
temporary: Only run suffix tests
grayside Jul 21, 2023
9c236cd
fix: placeholder deploy depend on permissions instead of database
grayside Jul 21, 2023
126896e
introduce 2m delay before using init IAM permissions
grayside Jul 21, 2023
5400475
Increase init permissions propagation delay to 3 minutes
grayside Jul 21, 2023
0a600e4
increase placeholder delay to 4m
grayside Jul 21, 2023
3ddfa19
Reduce permissions delay to 2m, skip tests for placeholder deploy
grayside Jul 21, 2023
5130914
disable placeholder deploy
grayside Jul 21, 2023
5c89708
Add 1 minute sleep before go tests
grayside Jul 21, 2023
e3ca9dc
expand go test delay to 2 minutes at start of verify tests
grayside Jul 21, 2023
b763728
add activategcb build to shake loose IAM
grayside Jul 21, 2023
c61a8f9
fix tf style
grayside Jul 21, 2023
19c00f6
Run activategcb build after init permissions are assigned but without…
grayside Jul 21, 2023
d5933ad
add another minute delay before testing Cloud Run service
grayside Jul 21, 2023
7902c64
Consolidate Cloud Run testing delay and raise to 4m
grayside Jul 21, 2023
ca5a86d
Restore placeholder deploy
grayside Jul 21, 2023
ad9c5a4
return placeholder, simple tests
glasnt Jul 23, 2023
de72039
Insert polling for Cloud Run readiness
grayside Jul 24, 2023
fb58d4b
Update docs/logging about deploy delay
grayside Jul 24, 2023
7c21421
Remove unneeded example test for enabled service
grayside Jul 24, 2023
71fa008
Add time.Second to polling sleep duration
grayside Jul 24, 2023
db999c8
Improve retry logging and invert retry condition
grayside Jul 24, 2023
6469556
Enable pubsub.googleapis.com to test project setup
grayside Jul 24, 2023
8a9a923
Update log to state URL without implying it's serving yet
grayside Jul 24, 2023
e3ea3d7
Add success log to http assert
grayside Jul 24, 2023
157ce9d
Reduce init process delay from 120s to 60s
grayside Jul 24, 2023
41d7b6d
untag wip placeholder image with latest (refreshly built)
glasnt Jul 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,15 @@ The following dependencies must be available:
A service account with the following roles must be used to provision
the resources of this module:

- roles/cloudbuild.builds.editor
- roles/cloudsql.admin
- roles/compute.admin
- roles/compute.networkAdmin
- roles/firebase.managementServiceAgent
- roles/firebasehosting.admin
- roles/iam.serviceAccountAdmin
- roles/iam.serviceAccountUser
- roles/pubsub.editor
- roles/resourcemanager.projectIamAdmin
- roles/run.admin
- roles/secretmanager.admin
Expand Down
7 changes: 4 additions & 3 deletions app/placeholder/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@
# Execute with "docker run --build-arg PROJECT_ID=$PROJECT_ID ..."
ARG PROJECT_ID=YOURPROJECTID
FROM gcr.io/$PROJECT_ID/firebase
WORKDIR /app

RUN apk add gettext
RUN apk add gettext curl
RUN npm install -g json
COPY . ./
COPY . /app/

ENTRYPOINT ./placeholder-deploy.sh
ENTRYPOINT ["/app/placeholder-deploy.sh"]
26 changes: 24 additions & 2 deletions app/placeholder/placeholder-deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,32 @@
# any errors? exit immediately.
set -e

# Ensure we got to the right directory. Cloud Build may start us in /workspace
cd /app

# escape if firebase_url not defined (mandatory, required later)
if [[ -z $FIREBASE_URL ]]; then
echo "FIREBASE_URL not defined. Cannot deploy. Exiting."
exit 1
fi

# Only run the placeholder script if the site has been deployed before.
# Check if the firebase url has "Site Not Found" (the pre-deployment state)
if curl "$FIREBASE_URL" | grep -q "Site Not Found"; then
echo "Firebase site $FIREBASE_URL hasn't been deployed before, so it needs a placeholder."
else
echo "Firebase site $FIREBASE_URL has been deployed before. Not going to deploy placeholder. Exiting."
exit 0
fi

# if deploying with a suffix (from infra/jobs.tf), adjust the config to suit the custom site
# https://firebase.google.com/docs/hosting/multisites#set_up_deploy_targets
if [[ -n $SUFFIX ]]; then
json -I -f firebase.json -e "this.hosting.target='$SUFFIX'"
UPDATED=true

# Use template file to generate configuration
envsubst < firebaserc.tmpl > .firebaserc
envsubst <firebaserc.tmpl >.firebaserc
echo "Customised .firebaserc created to support site."
cat .firebaserc
fi
Expand All @@ -35,6 +53,10 @@ if [[ -n $UPDATED ]]; then
cat firebase.json
fi

# Finally, deploy the application
echo "Deploying placeholder to Firebase..."

firebase deploy --project "$PROJECT_ID" --only hosting

# Setup for greater chances of success by explicitly purging cache
echo "Purging firebase cache"
curl -X PURGE "${FIREBASE_URL}/"
4 changes: 3 additions & 1 deletion infra/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Functional examples are included in the
| database\_name | Cloud SQL database name | `string` | `"django"` | no |
| database\_username | Cloud SQL database name | `string` | `"server"` | no |
| enable\_apis | Whether or not to enable underlying apis in this solution. | `bool` | `true` | no |
| image\_version | Version of the Container Registry image to use | `string` | `"v1.8.2"` | no |
| image\_version | Version of the Container Registry image to use | `string` | `"v1.9.0"` | no |
| init | Initialize database? | `bool` | `true` | no |
| instance\_name | Cloud SQL Instance name | `string` | `"psql"` | no |
| labels | A set of key/value label pairs to assign to the resources deployed by this blueprint. | `map(string)` | `{}` | no |
Expand Down Expand Up @@ -89,13 +89,15 @@ The following dependencies must be available:
A service account with the following roles must be used to provision
the resources of this module:

- roles/cloudbuild.builds.editor
- roles/cloudsql.admin
- roles/compute.admin
- roles/compute.networkAdmin
- roles/firebase.managementServiceAgent
- roles/firebasehosting.admin
- roles/iam.serviceAccountAdmin
- roles/iam.serviceAccountUser
- roles/pubsub.editor
- roles/resourcemanager.projectIamAdmin
- roles/run.admin
- roles/secretmanager.admin
Expand Down
1 change: 1 addition & 0 deletions infra/apis.tf
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ module "project_services" {
"compute.googleapis.com",
"firebase.googleapis.com",
"firebasehosting.googleapis.com",
"pubsub.googleapis.com",
"iam.googleapis.com",
"run.googleapis.com",
"secretmanager.googleapis.com",
Expand Down
114 changes: 61 additions & 53 deletions infra/iam.tf
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,31 @@
* limitations under the License.
*/

# Service Accounts

locals {
# Helpers for the clunky formatting of these values
automation_SA = "serviceAccount:${google_service_account.automation.email}"
server_SA = "serviceAccount:${google_service_account.server.email}"
client_SA = "serviceAccount:${google_service_account.client.email}"
# Lists of required roles
server_iam_members = [
"roles/cloudsql.client",
"roles/run.viewer",
"roles/cloudtrace.agent"
]
client_iam_members = [
"roles/run.viewer",
"roles/firebasehosting.admin",
]
automation_iam_members = [
"roles/cloudsql.client"
]
init_iam_members = [
"roles/logging.logWriter",
"roles/cloudbuild.builds.builder",
"roles/iam.serviceAccountUser",
"roles/run.developer",
"roles/firebasehosting.admin"
]
}

# Accounts

resource "google_service_account" "server" {
account_id = var.random_suffix ? "api-backend-${random_id.suffix.hex}" : "api-backend"
display_name = "API Backend service account"
Expand All @@ -41,66 +57,58 @@ resource "google_service_account" "automation" {
depends_on = [module.project_services]
}

resource "google_service_account" "compute" {
account_id = var.random_suffix ? "compute-startup-${random_id.suffix.hex}" : "compute-startup"
display_name = "Head Start App Compute Instance SA"

resource "google_service_account" "init" {
account_id = var.random_suffix ? "init-startup-${random_id.suffix.hex}" : "init-startup"
display_name = "Jump Start App Init SA"
depends_on = [module.project_services]
count = var.init ? 1 : 0
}

# The Cloud Run server can access the database
# Permissions

resource "google_project_iam_member" "server_permissions" {
project = var.project_id
role = "roles/cloudsql.client"
member = local.server_SA
depends_on = [google_service_account.server]
}
count = length(local.server_iam_members)

# Cloud Build can access the database
resource "google_project_iam_member" "build_permissions" {
project = var.project_id
role = "roles/cloudsql.client"
member = local.automation_SA
depends_on = [google_service_account.automation]
project = var.project_id
role = local.server_iam_members[count.index]
member = "serviceAccount:${google_service_account.server.email}"
}

# Server needs introspection permissions
resource "google_project_iam_member" "server_introspection" {
project = var.project_id
role = "roles/run.viewer"
member = local.server_SA
depends_on = [google_service_account.server]
}
resource "google_project_iam_member" "client_permissions" {
count = length(local.client_iam_members)

# Client needs introspection permissions
resource "google_project_iam_member" "client_introspection" {
project = var.project_id
role = "roles/run.viewer"
member = local.client_SA
depends_on = [google_service_account.client]
project = var.project_id
role = local.client_iam_members[count.index]
member = "serviceAccount:${google_service_account.client.email}"
}

# Client may need permission to deploy the front end
resource "google_project_iam_member" "client_permissions" {
project = var.project_id
role = "roles/firebasehosting.admin"
member = local.client_SA
depends_on = [google_service_account.client]
resource "google_project_iam_member" "automation_permissions" {
count = length(local.automation_iam_members)

project = var.project_id
role = local.automation_iam_members[count.index]
member = "serviceAccount:${google_service_account.automation.email}"
}

# GCE instance needs access to start Jobs
resource "google_project_iam_member" "computestartup_permissions" {
project = var.project_id
role = "roles/run.developer"
member = "serviceAccount:${google_service_account.compute[0].email}"
depends_on = [google_service_account.compute]
count = var.init ? 1 : 0
resource "google_project_iam_member" "init_permissions" {
count = length(local.init_iam_members)

project = var.project_id
role = local.init_iam_members[count.index]
member = "serviceAccount:${google_service_account.init[0].email}"
}

# Server needs to write to Cloud Trace
resource "google_project_iam_member" "server_traceagent" {
project = var.project_id
role = "roles/cloudtrace.agent"
member = local.server_SA
depends_on = [google_service_account.server]
# Ensure google_service_account.init is not used before permissions are available.
# Introduced to allow for IAM policy propagation delay. Time selected to allow:
# propagation delay + ~2 minute firebase hosting deploy <= 5 minutes.
# Shortest delay preferred.
# Warning: Trying to meet IAM propagation delay on roles/logging.logWriter.
# Exceeded safe limit to avoid race conditions between placeholder and init process.
resource "time_sleep" "init_permissions_propagation" {
depends_on = [
google_project_iam_member.init_permissions
]

create_duration = "60s"
}
122 changes: 2 additions & 120 deletions infra/jobs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -14,54 +14,7 @@
* limitations under the License.
*/

resource "google_cloud_run_v2_job" "setup" {
name = var.random_suffix ? "setup-${random_id.suffix.hex}" : "setup"
location = var.region

labels = var.labels

template {
template {
service_account = google_service_account.automation.email
containers {
image = local.server_image
command = ["setup"]
env {
name = "DJANGO_ENV"
value_source {
secret_key_ref {
secret = google_secret_manager_secret.django_settings.secret_id
version = "latest"
}
}
}
env {
name = "DJANGO_SUPERUSER_PASSWORD"
value_source {
secret_key_ref {
secret = google_secret_manager_secret.django_admin_password.secret_id
version = "latest"
}
}
}
volume_mounts {
name = "cloudsql"
mount_path = "/cloudsql"
}
}
volumes {
name = "cloudsql"
cloud_sql_instance {
instances = [google_sql_database_instance.postgres.connection_name]
}
}
}
}
depends_on = [
google_secret_manager_secret_version.django_settings
]
}

# Job to apply server database updates
resource "google_cloud_run_v2_job" "migrate" {
name = var.random_suffix ? "migrate-${random_id.suffix.hex}" : "migrate"
location = var.region
Expand Down Expand Up @@ -101,75 +54,4 @@ resource "google_cloud_run_v2_job" "migrate" {
]
}



resource "google_cloud_run_v2_job" "client" {

name = var.random_suffix ? "client-${random_id.suffix.hex}" : "client"
location = var.region

labels = var.labels

template {
template {
service_account = google_service_account.client.email
containers {
image = local.client_image

# Variables used to customise Firebase configuration on deployment
# https://github.com/GoogleCloudPlatform/avocano/blob/main/client/docker-deploy.sh
env {
name = "SUFFIX"
value = var.random_suffix ? random_id.suffix.hex : ""
}
env {
name = "SERVICE_NAME"
value = google_cloud_run_v2_service.server.name
}
env {
name = "REGION"
value = var.region
}
env {
name = "PROJECT_ID"
value = var.project_id
}

}
}
}

depends_on = [
module.project_services
]
}


resource "google_cloud_run_v2_job" "placeholder" {
name = var.random_suffix ? "placeholder-${random_id.suffix.hex}" : "placeholder"
location = var.region

labels = var.labels

template {
template {
service_account = google_service_account.client.email
containers {
image = local.placeholder_image
env {
name = "PROJECT_ID"
value = var.project_id
}

env {
name = "SUFFIX"
value = var.random_suffix ? random_id.suffix.hex : ""
}
}
}
}

depends_on = [
module.project_services
]
}
# Other jobs defined in postdeployment.tf
Loading