From c1a57ba5d198c77ecfefc89db1839a1ab1c8950d Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 6 Apr 2021 10:54:30 -0400 Subject: [PATCH] Many updates! terraform 0.14 formatting, nginx compat, error handling --- main.tf | 86 ++++++++++++++++++++----------------- spoke-app-provision | 9 ++-- spoke-app-provision-wrapper | 11 +++++ spoke-app-run | 3 ++ 4 files changed, 66 insertions(+), 43 deletions(-) create mode 100755 spoke-app-provision-wrapper diff --git a/main.tf b/main.tf index 200d146..0b8ed93 100644 --- a/main.tf +++ b/main.tf @@ -65,92 +65,97 @@ terraform { } } -variable server_name { +variable "server_name" { description = "Server name used in nginx config" type = string } -variable base_url { +variable "base_url" { description = "Fully qualified https URL of the app" type = string } -variable resource_prefix { +variable "resource_prefix" { description = "Prefix prepended to resource names" default = "spoke-" type = string } -variable node_options { +variable "nginx_site_override_conf" { + description = "Complete nginx site configuration override" + default = "" +} + +variable "node_options" { description = "Value defined at build time and run time as NODE_OPTIONS" default = "--max_old_space_size=8192" type = string } -variable node_env { +variable "node_env" { description = "Value defined at build time and run time as NODE_ENV" default = "production" type = string } -variable port { +variable "port" { description = "TCP port used to communicate between droplet and nginx" default = "3000" type = string } -variable droplet_image { +variable "droplet_image" { description = "Image to use when provisioning app droplet" default = "ubuntu-20-04-x64" type = string } -variable droplet_size { +variable "droplet_size" { description = "Size value passed when provisioning app droplet" default = "s-1vcpu-1gb" type = string } -variable region { +variable "region" { description = "Region in which all resources will be provisioned" default = "nyc1" type = string } -variable spoke_version { +variable "spoke_version" { description = "Git ref of MoveOnOrg/Spoke to deploy" default = "v8.0" type = string } -variable ssh_keys { +variable "ssh_keys" { type = list(string) description = "List of ssh public keys to pass to droplet provisioning" } -variable cert_private_key { +variable "cert_private_key" { description = "Certificate key to pass to nginx" type = string } -variable cert_certificate { +variable "cert_certificate" { description = "Certificate with leaf and intermediates to pass to nginx" type = string } -variable env { +variable "env" { description = "Arbitrary *additional* environment variables passed at build time and run time" default = {} type = map(string) } -resource digitalocean_ssh_key app { +resource "digitalocean_ssh_key" "app" { count = length(var.ssh_keys) name = "${var.resource_prefix}app-${count.index}" public_key = element(var.ssh_keys, count.index) } -resource digitalocean_droplet app { +resource "digitalocean_droplet" "app" { image = var.droplet_image name = "${var.resource_prefix}app" region = var.region @@ -159,17 +164,17 @@ resource digitalocean_droplet app { ssh_keys = digitalocean_ssh_key.app[*].id } -resource digitalocean_floating_ip app { +resource "digitalocean_floating_ip" "app" { droplet_id = digitalocean_droplet.app.id region = digitalocean_droplet.app.region } -resource digitalocean_firewall app { +resource "digitalocean_firewall" "app" { name = "pghdsa-spoke-app" droplet_ids = [digitalocean_droplet.app.id] - dynamic inbound_rule { + dynamic "inbound_rule" { for_each = ["22", "80", "443"] content { protocol = "tcp" @@ -183,7 +188,7 @@ resource digitalocean_firewall app { source_addresses = ["0.0.0.0/0", "::/0"] } - dynamic outbound_rule { + dynamic "outbound_rule" { for_each = ["tcp", "udp"] content { protocol = outbound_rule.value @@ -198,12 +203,12 @@ resource digitalocean_firewall app { } } -resource random_string session_secret { +resource "random_string" "session_secret" { length = 199 special = false } -resource random_string pg_password { +resource "random_string" "pg_password" { length = 31 } @@ -231,7 +236,7 @@ locals { }, var.env) } -resource null_resource app_provision { +resource "null_resource" "app_provision" { triggers = { droplet_id = digitalocean_droplet.app.id provision_script_sha1 = filesha1("${path.module}/spoke-app-provision") @@ -251,17 +256,17 @@ resource null_resource app_provision { host = digitalocean_droplet.app.ipv4_address } - provisioner file { + provisioner "file" { source = "${path.module}/spoke-app-provision" destination = "/tmp/spoke-app-provision" } - provisioner file { + provisioner "file" { source = "${path.module}/spoke-app-run" destination = "/tmp/spoke-app-run" } - provisioner file { + provisioner "file" { content = templatefile("${path.module}/nginx-sites-default.conf.tpl", { server_name = var.server_name, port = var.port, @@ -269,17 +274,22 @@ resource null_resource app_provision { destination = "/tmp/nginx-sites-default.conf" } - provisioner file { + provisioner "file" { + content = var.nginx_site_override_conf + destination = "/tmp/nginx-sites-default-override.conf" + } + + provisioner "file" { content = var.cert_certificate destination = "/tmp/spoke.crt" } - provisioner file { + provisioner "file" { content = var.cert_private_key destination = "/tmp/spoke.key" } - provisioner file { + provisioner "file" { content = <<-ENVTMPL %{for key, value in local.env_map~} ${key}='${value}' @@ -289,36 +299,32 @@ ENVTMPL destination = "/tmp/app.env" } - provisioner file { + provisioner "file" { source = "${path.module}/spoke.service" destination = "/tmp/spoke.service" } - provisioner remote-exec { - inline = [ - "bash /tmp/spoke-app-provision system0", - "sudo -H -u spoke bash /tmp/spoke-app-provision spoke0", - "bash /tmp/spoke-app-provision system1", - ] + provisioner "remote-exec" { + script = "${path.module}/spoke-app-provision-wrapper" } } -output droplet_urn { +output "droplet_urn" { description = "urn of the droplet suitable for adding to project resources" value = digitalocean_droplet.app.urn } -output droplet_ipv4_address { +output "droplet_ipv4_address" { description = "ipv4 address of the droplet" value = digitalocean_droplet.app.ipv4_address } -output floating_ip_address { +output "floating_ip_address" { description = "floating IP address assigned to the droplet suitable for creating a DNS A record" value = digitalocean_floating_ip.app.ip_address } -output floating_ip_urn { +output "floating_ip_urn" { description = "urn of the floating IP address assigned to the droplet suitable for adding to project resources" value = digitalocean_floating_ip.app.urn } diff --git a/spoke-app-provision b/spoke-app-provision index 681904f..92d0449 100755 --- a/spoke-app-provision +++ b/spoke-app-provision @@ -40,15 +40,15 @@ _run_system0() { redis dpkg --get-selections || true | - if ! grep -qE '^postgresql-client-11.+install$'; then + if ! grep -qE '^postgresql-client-13.+install$'; then echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list &>/dev/null curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - sudo apt-get update -y - sudo apt-get install -y postgresql-11 postgresql-client-11 + sudo apt-get install -y postgresql-13 postgresql-client-13 fi - pg_ctlcluster 11 main start + pg_ctlcluster 13 main start sudo -H -u postgres bash <