diff --git a/terraform/README.md b/terraform/README.md new file mode 100644 index 000000000..8eac2f608 --- /dev/null +++ b/terraform/README.md @@ -0,0 +1,128 @@ +--- +title: Terraform +homepage: https://www.terraform.io/ +tagline: | + Provision, change, and version resources on any environment. +description: | + Terraform is an infrastructure as code (IaC) tool that allows you to build, change, and version infrastructure safely and efficiently. +--- + +To update or switch versions, run `webi terraform@stable` (or `@v1.6.1`, +`@beta`, etc). + +### Files + +These are the files / directories that are created and/or modified with this +install: + +```text +~/.config/envman/PATH.env +~/.local/bin/terraform +/main.tf +``` + +## Cheat Sheet + +> With HashiCorp Terraform, provisioning and security can be automated based on +> infrastructure and policy as code. Infrastructure and policies are codified, +> shared, managed, and executed within a workflow that is consistent across all +> infrastructure. + +### How to Define Infrastructure State + +Create configurations that provide an outline for Terraform to provision your +target infrastructure. For example: + +`main.tf`: + +```tf +terraform { + required_providers { + docker = { + source = "kreuzwerker/docker" + version = "~> 2.13.0" + } + } +} + +provider "docker" { + # provider-specific configuration goes here, e.g., + # browse provider documentation here https://registry.terraform.io/browse/providers +} + +# Define some resources! +resource "docker_image" "nginx" { + name = "nginx:latest" + keep_locally = false +} + +resource "docker_container" "nginx" { + image = docker_image.nginx.latest + name = "web-server" + ports { + internal = 80 + external = 8080 + } +} +``` + +### How to Initialize Terraform + +Terraform needs to install provider-specific plugins, generate lockfiles, etc. +before you can begin provisioning. + +```sh +terraform init +``` + +You should only need to run this on new configurations, or other configurations +checked-out from version control. + +### How to Lint / Check / Validate your Config + +To check you have a valid configuration + +```sh +terraform validate +``` + +To format your configuration files + +```sh +terraform fmt +``` + +### How to Provision Resources + +You can generate an execution plan before committing to provisioning real +resources. This command allows you to see exactly what Terraform will do when +running the next command. + +```sh +terraform plan +``` + +Then, **to apply your configurations and provision infrastructure** resources: + +```sh +terraform apply +``` + +Use `-auto-approve` to automatically accept all user prompts (non-interactive, +batch mode): + +```sh +terraform apply -auto-approve +``` + +### How to Execute Plans + +Execution plans generated by `terraform plan` also act as the _last working +state of your infrastructure_. You may wish to save the generated `.tfstate` +file so that you may re-provision these resources reliably. + +You can pass in the execution plan to `terraform apply` (example): + +```sh +terraform apply -auto-approve ./main.tf +``` diff --git a/terraform/install.ps1 b/terraform/install.ps1 new file mode 100644 index 000000000..98f84b96f --- /dev/null +++ b/terraform/install.ps1 @@ -0,0 +1,57 @@ +#!/usr/bin/env pwsh + +################# +# Install terraform # +################# + +# Every package should define these variables +$pkg_cmd_name = "terraform" + +$pkg_dst_cmd = "$Env:USERPROFILE\.local\bin\terraform.exe" +$pkg_dst_bin = "$Env:USERPROFILE\.local\bin" +$pkg_dst = "$pkg_dst_cmd" + +$pkg_src_cmd = "$Env:USERPROFILE\.local\opt\terraform-v$Env:WEBI_VERSION\bin\terraform.exe" +$pkg_src_bin = "$Env:USERPROFILE\.local\opt\terraform-v$Env:WEBI_VERSION\bin" +$pkg_src_dir = "$Env:USERPROFILE\.local\opt\terraform-v$Env:WEBI_VERSION" +$pkg_src = "$pkg_src_cmd" + +New-Item "$Env:USERPROFILE\Downloads\webi" -ItemType Directory -Force | out-null +$pkg_download = "$Env:USERPROFILE\Downloads\webi\$Env:WEBI_PKG_FILE" + +# Fetch archive +IF (!(Test-Path -Path "$Env:USERPROFILE\Downloads\webi\$Env:WEBI_PKG_FILE")) { + echo "Downloading terraform from $Env:WEBI_PKG_URL to $pkg_download" + & curl.exe -A "$Env:WEBI_UA" -fsSL "$Env:WEBI_PKG_URL" -o "$pkg_download.part" + & move "$pkg_download.part" "$pkg_download" +} + +IF (!(Test-Path -Path "$pkg_src_cmd")) { + echo "Installing terraform" + + # TODO: create package-specific temp directory + # Enter tmp + pushd .local\tmp + + # Remove any leftover tmp cruft + Remove-Item -Path ".\terraform-v*" -Recurse -ErrorAction Ignore + Remove-Item -Path ".\terraform.exe" -Recurse -ErrorAction Ignore + + # Unpack archive file into this temporary directory + # Windows BSD-tar handles zip. Imagine that. + echo "Unpacking $pkg_download" + & tar xf "$pkg_download" + + # Settle unpacked archive into place + echo "Install Location: $pkg_src_cmd" + New-Item "$pkg_src_bin" -ItemType Directory -Force | out-null + Move-Item -Path ".\terraform.exe" -Destination "$pkg_src_bin" + + # Exit tmp + popd +} + +echo "Copying into '$pkg_dst_cmd' from '$pkg_src_cmd'" +Remove-Item -Path "$pkg_dst_cmd" -Recurse -ErrorAction Ignore | out-null +New-Item "$pkg_dst_bin" -ItemType Directory -Force | out-null +Copy-Item -Path "$pkg_src" -Destination "$pkg_dst" -Recurse diff --git a/terraform/install.sh b/terraform/install.sh new file mode 100644 index 000000000..4a68d6b0f --- /dev/null +++ b/terraform/install.sh @@ -0,0 +1,38 @@ +#!/bin/sh +set -e +set -u + +pkg_cmd_name="terraform" + +WEBI_SINGLE=true + +pkg_get_current_version() { + # 'terraform -v' has output in this format: + # Terraform v1.6.1 + # on linux_amd64 + # This trims it down to just the version number: + # 1.6.1 + terraform -v 2> /dev/null | + head -n 1 | + cut -d' ' -f2 | + cut -c2- +} + +pkg_install() { + # $HOME/.local/bin/opt/terraform-v1.6.1/bin + mkdir -p "$pkg_src_bin" + + # mv ./terraform* "$HOME/.local/opt/terraform-v1.6.1/bin/terraform" + mv ./"$pkg_cmd_name"* "$pkg_src_cmd" + + # chmod a+x "$HOME/.local/opt/terraform-v1.6.1/bin/terraform" + chmod a+x "$pkg_src_cmd" +} + +pkg_link() { + # rm -f "$HOME/.local/bin/terraform" + rm -f "$pkg_dst_cmd" + + # ln -s "$HOME/.local/opt/terraform-v1.6.1/bin/terraform" "$HOME/.local/bin/terraform" + ln -s "$pkg_src_cmd" "$pkg_dst_cmd" +} diff --git a/terraform/releases.js b/terraform/releases.js new file mode 100644 index 000000000..61e1cb1c1 --- /dev/null +++ b/terraform/releases.js @@ -0,0 +1,55 @@ +'use strict'; + +let convert = { + freebsd: 'freebsd', + macos: 'darwin', + linux: 'linux', + windows: 'windows', + amd64: 'amd64', + arm: 'arm64', + 386: 'x86', +}; + +function getAllReleases(request) { + return request({ + url: 'https://releases.hashicorp.com/terraform/index.json', + json: true, + }).then(function (resp) { + let releases = resp.body; + let all = { + releases: [], + download: '', // Full URI provided in response body + }; + + function getBuildsForVersion(version) { + releases.versions[version].builds.forEach(function (build) { + let r = { + version: build.version, + download: build.url, + os: convert[build.os], + arch: convert[build.arch], + channel: 'stable', // No other channels + }; + all.releases.push(r); + }); + } + + // Releases are listed chronologically, we want the latest first. + const allVersions = Object.keys(releases.versions).reverse(); + + allVersions.forEach(function (version) { + getBuildsForVersion(version); + }); + + return all; + }); +} + +module.exports = getAllReleases; + +if (module === require.main) { + getAllReleases(require('@root/request')).then(function (all) { + all = require('../_webi/normalize.js')(all); + console.info(JSON.stringify(all)); + }); +} diff --git a/test/install.sh b/test/install.sh index 19178693e..7e0b4bcb7 100644 --- a/test/install.sh +++ b/test/install.sh @@ -76,6 +76,7 @@ __rmrf_local() { ssh-pubkey \ ssh-utils \ syncthing \ + terraform \ vim-ale \ vim-essentials \ vim-lastplace \ @@ -171,6 +172,7 @@ __rmrf_local() { ssh-pubkey \ ssh-utils \ syncthing \ + terraform \ vim-ale \ vim-essentials \ vim-go \ @@ -271,6 +273,7 @@ __test() { ssh-pubkey \ ssh-utils \ syncthing \ + terraform \ vim-ale \ vim-essentials \ vim-lastplace \