From 2d88b4213e38bf957acf7f42dabfbc7bf2980e60 Mon Sep 17 00:00:00 2001 From: Cameron Stokes Date: Sat, 10 Feb 2018 07:49:31 -0800 Subject: [PATCH] Initial working example. (#1) * Initial working example. * Add READMEs. * Remove comments from example in main README. --- .gitignore | 9 ++ README.md | 72 ++++++++++++++ examples/basic-with-provisioning/README.md | 23 +++++ examples/basic-with-provisioning/main.tf | 56 +++++++++++ examples/basic-with-provisioning/outputs.tf | 14 +++ examples/basic-with-provisioning/variables.tf | 7 ++ main.tf | 75 +++++++++++++++ outputs.tf | 14 +++ packer/scripts/install_redash.sh | 96 +++++++++++++++++++ provisioners.tf | 42 ++++++++ variables.tf | 94 ++++++++++++++++++ 11 files changed, 502 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 examples/basic-with-provisioning/README.md create mode 100644 examples/basic-with-provisioning/main.tf create mode 100644 examples/basic-with-provisioning/outputs.tf create mode 100644 examples/basic-with-provisioning/variables.tf create mode 100644 main.tf create mode 100644 outputs.tf create mode 100644 packer/scripts/install_redash.sh create mode 100644 provisioners.tf create mode 100644 variables.tf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d9da639 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +# terraform # +############# +.terraform +*.tfstate* +terraform.tfvars + +# packer # +########## +*-vars.json diff --git a/README.md b/README.md new file mode 100644 index 0000000..c8d8844 --- /dev/null +++ b/README.md @@ -0,0 +1,72 @@ +# Triton Presto Terraform Module + +A Terraform module to create a [Redash](https://prestodb.io/) server. Redash can then be used to +query a [Presto cluster](https://github.com/joyent/terraform-triton-presto) and Triton Object Storage data. + +## Usage + +```hcl +data "triton_image" "ubuntu" { + name = "ubuntu-16.04" + type = "lx-dataset" + most_recent = true +} + +data "triton_network" "public" { + name = "Joyent-SDC-Public" +} + +data "triton_network" "private" { + name = "My-Fabric-Network" +} + +module "bastion" { + source = "github.com/joyent/terraform-triton-bastion" + + name = "redash-basic-with-provisioning" + image = "${data.triton_image.ubuntu.id}" + package = "g4-general-4G" + + networks = [ + "${data.triton_network.public.id}", + "${data.triton_network.private.id}", + ] +} + +module "redash" { + source = "github.com/joyent/terraform-triton-redash" + + name = "redash-basic-with-provisioning" + image = "${data.triton_image.ubuntu.id}" + package = "g4-general-4G" + + networks = [ + "${data.triton_network.public.id}", + "${data.triton_network.private.id}", + ] + + provision = "true" + private_key_path = "${var.private_key_path}" + + client_access = ["any"] + + bastion_host = "${element(module.bastion.bastion_ip,0)}" + bastion_user = "${module.bastion.bastion_user}" + bastion_role_tag = "${module.bastion.bastion_role_tag}" +} +``` + +## Examples +- [basic-with-provisioning](examples/basic-with-provisioning) - Deploys a Redash server. Redash server +will be _provisioned_ by Terraform. + - _Note: This method with Terraform provisioning is only recommended for prototyping and light testing._ + +## Resources created + +- [`triton_machine.redash`](https://www.terraform.io/docs/providers/triton/r/triton_machine.html): The Redash machine. +- [`triton_firewall_rule.ssh`](https://www.terraform.io/docs/providers/triton/r/triton_firewall_rule.html): The firewall +rule(s) allowing SSH access FROM the bastion machine(s) TO the Redash machine. +- [`triton_firewall_rule.client_access`](https://www.terraform.io/docs/providers/triton/r/triton_firewall_rule.html): The +firewall rule(s) allowing access FROM client machines or addresses TO Redash web ports. +- [`triton_firewall_rule.redash_to_presto_coordinator`](https://www.terraform.io/docs/providers/triton/r/triton_firewall_rule.html): The +firewall rule(s) allowing access FROM the Redash machine TO Presto coordinator web ports. diff --git a/examples/basic-with-provisioning/README.md b/examples/basic-with-provisioning/README.md new file mode 100644 index 0000000..3b3f356 --- /dev/null +++ b/examples/basic-with-provisioning/README.md @@ -0,0 +1,23 @@ +# Redash with Provisioning + +Creates one Redash machine. Terraform to create and manage the infrastructure resources and provision the machines. + +> :warning: _Note: This method with Terraform provisioning is only recommended for prototyping and light testing._ + +## Usage + +Initialize and create the environment: + +``` +terraform init +terraform plan +terraform apply +``` + +## Cleanup + +Remove all resources created by Terraform: + +``` +terraform destroy +``` diff --git a/examples/basic-with-provisioning/main.tf b/examples/basic-with-provisioning/main.tf new file mode 100644 index 0000000..9329ad1 --- /dev/null +++ b/examples/basic-with-provisioning/main.tf @@ -0,0 +1,56 @@ +# +# Data Sources +# +data "triton_image" "ubuntu" { + name = "ubuntu-16.04" + type = "lx-dataset" + most_recent = true +} + +data "triton_network" "public" { + name = "Joyent-SDC-Public" +} + +data "triton_network" "private" { + name = "My-Fabric-Network" +} + +# +# Modules +# +module "bastion" { + source = "github.com/joyent/terraform-triton-bastion" + + name = "redash-basic-with-provisioning" + image = "${data.triton_image.ubuntu.id}" + package = "g4-general-4G" + + # Public and Private + networks = [ + "${data.triton_network.public.id}", + "${data.triton_network.private.id}", + ] +} + +module "redash" { + source = "../../" + + name = "redash-basic-with-provisioning" + image = "${data.triton_image.ubuntu.id}" # note: using the UBUNTU image here + package = "g4-general-4G" + + # Public and Private + networks = [ + "${data.triton_network.public.id}", + "${data.triton_network.private.id}", + ] + + provision = "true" # note: we ARE provisioning as we are NOT using pre-built images. + private_key_path = "${var.private_key_path}" + + client_access = ["any"] + + bastion_host = "${element(module.bastion.bastion_ip,0)}" + bastion_user = "${module.bastion.bastion_user}" + bastion_role_tag = "${module.bastion.bastion_role_tag}" +} diff --git a/examples/basic-with-provisioning/outputs.tf b/examples/basic-with-provisioning/outputs.tf new file mode 100644 index 0000000..a05d1d0 --- /dev/null +++ b/examples/basic-with-provisioning/outputs.tf @@ -0,0 +1,14 @@ +# +# Outputs +# +output "bastion_ip" { + value = ["${module.bastion.bastion_ip}"] +} + +output "redash_ip" { + value = ["${module.redash.redash_ip}"] +} + +output "redash_address" { + value = ["${module.redash.redash_address}"] +} diff --git a/examples/basic-with-provisioning/variables.tf b/examples/basic-with-provisioning/variables.tf new file mode 100644 index 0000000..c63a607 --- /dev/null +++ b/examples/basic-with-provisioning/variables.tf @@ -0,0 +1,7 @@ +# +# Variables +# +variable "private_key_path" { + description = "The path to the private key to use for provisioning machines." + type = "string" +} diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..2b74257 --- /dev/null +++ b/main.tf @@ -0,0 +1,75 @@ +# +# Terraform/Providers +# +terraform { + required_version = ">= 0.11.0" +} + +provider "triton" { + version = ">= 0.4.1" +} + +# +# Data sources +# +data "triton_datacenter" "current" {} + +data "triton_account" "current" {} + +# +# Locals +# +locals { + redash_address = "${var.cns_service_name_redash}.svc.${data.triton_account.current.id}.${data.triton_datacenter.current.name}.${var.cns_fqdn_base}" + presto_coordinator_address = "${var.cns_service_name_presto_coordinator}.svc.${data.triton_account.current.id}.${data.triton_datacenter.current.name}.${var.cns_fqdn_base}" +} + +# +# Machines +# +resource "triton_machine" "redash" { + name = "${var.name}-redash" + package = "${var.package}" + image = "${var.image}" + + firewall_enabled = true + + networks = ["${var.networks}"] + + tags { + role = "${var.role_tag}" + } + + cns { + services = ["${var.cns_service_name_redash}"] + } + + metadata { + version_redash = "${var.version_redash}" + } +} + +# +# Firewall Rules +# +resource "triton_firewall_rule" "ssh" { + rule = "FROM tag \"role\" = \"${var.bastion_role_tag}\" TO tag \"role\" = \"${var.role_tag}\" ALLOW tcp PORT 22" + enabled = true + description = "${var.name} - Allow access from bastion hosts to Redash servers." +} + +resource "triton_firewall_rule" "client_access" { + count = "${length(var.client_access)}" + + rule = "FROM ${var.client_access[count.index]} TO tag \"role\" = \"${var.role_tag}\" ALLOW tcp PORT 80" + enabled = true + description = "${var.name} - Allow access from clients to Redash servers." +} + +resource "triton_firewall_rule" "redash_to_presto_coordinator" { + count = "${length(var.client_access)}" + + rule = "FROM ${var.client_access[count.index]} TO tag \"triton.cns.services\" = \"${var.cns_service_name_presto_coordinator}\" ALLOW tcp PORT 8080" + enabled = true + description = "${var.name} - Allow access from Redash to Presto servers." +} diff --git a/outputs.tf b/outputs.tf new file mode 100644 index 0000000..5a21450 --- /dev/null +++ b/outputs.tf @@ -0,0 +1,14 @@ +# +# Outputs +# +output "redash_ip" { + value = ["${triton_machine.redash.*.primaryip}"] +} + +output "redash_role_tag" { + value = "${var.role_tag}" +} + +output "redash_address" { + value = "${local.redash_address}" +} diff --git a/packer/scripts/install_redash.sh b/packer/scripts/install_redash.sh new file mode 100644 index 0000000..40705b1 --- /dev/null +++ b/packer/scripts/install_redash.sh @@ -0,0 +1,96 @@ +#!/bin/bash +# +# Installs Redash with some customizations specific to the overall project. +# +# Note: Generally follows guidelines at https://web.archive.org/web/20170701145736/https://google.github.io/styleguide/shell.xml. +# + +set -e + +# check_prerequisites - exits if distro is not supported. +# +# Parameters: +# None. +function check_prerequisites() { + local distro + if [[ -f "/etc/lsb-release" ]]; then + distro="Ubuntu" + fi + + if [[ -z "${distro}" ]]; then + log "Unsupported platform. Exiting..." + exit 1 + fi +} + +# install_dependencies - installs dependencies +# +# Parameters: +# $1: the name of the distribution. +function install_dependencies() { + log "Updating package index..." + apt-get -qq -y update + log "Upgrading existing packages" + apt-get -qq -y upgrade + log "Installing prerequisites..." + apt-get -qq -y install --no-install-recommends \ + wget +} + +# check_arguments - exits if prerequisites are NOT satisfied +# +# Parameters: +# $1: the version of redash +function check_arguments() { + local -r version_redash=${1} + + if [[ -z "${version_redash}" ]]; then + log "No Redash version provided. Exiting..." + exit 1 + fi + +} + +# install - downloads and installs the specified tool and version +# +# Parameters: +# $1: the version of redash +function install_redash() { + local -r version_redash=${1} + + local -r path_file="redash_bootstrap.sh" + + log "Downloading Redash install script..." + wget -q -O ${path_file} "https://raw.githubusercontent.com/getredash/redash/master/setup/ubuntu/bootstrap.sh" + + log "Installing Redash ${version_redash}..." + REDASH_VERSION=${version_redash} sh ${path_file} + +} + +# log - prints an informational message +# +# Parameters: +# $1: the message +function log() { + local -r message=${1} + local -r script_name=$(basename ${0}) + echo -e "==> ${script_name}: ${message}" +} + +# main +function main() { + check_prerequisites + + local -r arg_version_redash=$(mdata-get 'version_redash') + check_arguments \ + ${arg_version_redash} + + install_dependencies + install_redash \ + ${arg_version_redash} + + log "Done." +} + +main diff --git a/provisioners.tf b/provisioners.tf new file mode 100644 index 0000000..d71dcb5 --- /dev/null +++ b/provisioners.tf @@ -0,0 +1,42 @@ +resource "null_resource" "redash_install" { + count = "${var.provision == "true" ? "1" : 0}" + + triggers { + machine_ids = "${triton_machine.redash.*.id[count.index]}" + } + + connection { + bastion_host = "${var.bastion_host}" + bastion_user = "${var.bastion_user}" + bastion_private_key = "${file(var.private_key_path)}" + + host = "${triton_machine.redash.*.primaryip[count.index]}" + user = "${var.user}" + private_key = "${file(var.private_key_path)}" + } + + provisioner "remote-exec" { + inline = [ + "mkdir -p /tmp/redash_installer/", + ] + } + + provisioner "file" { + source = "${path.module}/packer/scripts/install_redash.sh" + destination = "/tmp/redash_installer/install_redash.sh" + } + + provisioner "remote-exec" { + inline = [ + "chmod 0755 /tmp/redash_installer/install_redash.sh", + "sudo /tmp/redash_installer/install_redash.sh", + ] + } + + # clean up + provisioner "remote-exec" { + inline = [ + "rm -rf /tmp/redash_installer/", + ] + } +} diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..3133c68 --- /dev/null +++ b/variables.tf @@ -0,0 +1,94 @@ +# +# Variables +# +variable "name" { + description = "The name of the environment." + type = "string" +} + +variable "image" { + description = "The image to deploy as the Presto machine(s)." + type = "string" +} + +variable "package" { + description = "The package to deploy as the Presto machine(s)." + type = "string" +} + +variable "networks" { + description = "The networks to deploy the Presto machine(s) within." + type = "list" +} + +variable "private_key_path" { + description = "The path to the private key to use for provisioning machines." + type = "string" +} + +variable "user" { + description = "The user to use for provisioning machines." + type = "string" + default = "root" +} + +variable "role_tag" { + description = "The 'role' tag for the Presto machine(s)." + type = "string" + default = "presto" +} + +variable "provision" { + description = "Boolean 'switch' to indicate if Terraform should do the machine provisioning to install and configure Presto." + type = "string" +} + +variable "version_redash" { + default = "3.0.0.b3134" + description = "The version of Presto to install. See https://repo1.maven.org/maven2/com/facebook/presto/presto-server/." + type = "string" +} + +variable "cns_service_name_redash" { + description = "The Redash service name. Note: this is the service name only, not the full CNS record." + type = "string" + default = "redash" +} + +variable "cns_service_name_presto_coordinator" { + description = "The Presto Coordinator CNS service name. Note: this is the service name only, not the full CNS record." + type = "string" + default = "presto-coordinator" +} + +variable "client_access" { + description = <