From 67ec8d23f6644f60579812b3cd9fc1fada44ceb3 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sat, 13 Jan 2024 16:31:46 +0100 Subject: [PATCH] poc: terranix --- .envrc | 1 + .gitignore | 6 ++ .gitlab-ci.yml | 53 ----------- .terraform.lock.hcl | 19 ++-- README.md | 18 +++- config.nix | 16 ++++ flake.lock | 161 ++++++++++++++++++++++++++++++++++ flake.nix | 102 ++++++++++++++++++++++ install_precommit_hook.sh | 3 - lint.sh | 4 - main.tf | 179 -------------------------------------- outputs.tf | 35 -------- precommit.sh | 11 --- treefmt.toml | 5 ++ variables.tf | 0 15 files changed, 320 insertions(+), 293 deletions(-) create mode 100644 .envrc delete mode 100644 .gitlab-ci.yml create mode 100644 config.nix create mode 100644 flake.lock create mode 100644 flake.nix delete mode 100644 install_precommit_hook.sh delete mode 100644 lint.sh delete mode 100644 main.tf delete mode 100644 outputs.tf delete mode 100644 precommit.sh create mode 100644 treefmt.toml delete mode 100644 variables.tf diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..8392d15 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8ede2d4..a0113e9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# Direnv directory +.direnv/ + # Local .terraform directories **/.terraform/* @@ -15,3 +18,6 @@ terraform.rc # Ignore local .tfvars *.tfvars + +# generated terraform files +*.json diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index db28874..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,53 +0,0 @@ -image: registry.gitlab.com/gitlab-org/terraform-images/stable:latest - -variables: - TF_ROOT: ${CI_PROJECT_DIR} - TF_ADDRESS: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/bij1 - -cache: - key: bij1 - paths: - - ${TF_ROOT}/.terraform - -before_script: - - cd ${TF_ROOT} - -stages: - - prepare - - validate - - build - - deploy - -init: - stage: prepare - script: - - gitlab-terraform init - -validate: - stage: validate - script: - - gitlab-terraform validate - -plan: - stage: build - script: - - gitlab-terraform plan - - gitlab-terraform plan-json - artifacts: - name: plan - paths: - - ${TF_ROOT}/plan.cache - reports: - terraform: ${TF_ROOT}/plan.json - -apply: - stage: deploy - environment: - name: production - script: - - gitlab-terraform apply - dependencies: - - plan - when: manual - only: - - master diff --git a/.terraform.lock.hcl b/.terraform.lock.hcl index 64ea73e..31ec08d 100644 --- a/.terraform.lock.hcl +++ b/.terraform.lock.hcl @@ -1,10 +1,19 @@ -# This file is maintained automatically by "terraform init". +# This file is maintained automatically by "tofu init". # Manual edits may be lost in future updates. -provider "registry.terraform.io/digitalocean/digitalocean" { - version = "2.21.0" - constraints = "~> 2.21.0" +provider "registry.opentofu.org/hashicorp/local" { + version = "2.4.1" hashes = [ - "h1:gndflVS5/+cwQbVVI6NwwB3dYK7W2QkmZuWmFBH/0tI=", + "h1:ZmiQvqAmblLC08P/NR+AVQtZrD+GGRpjFWcl+qX3+tE=", + "zh:0d4d7a980ba3479459ab8a231019588d38615b22b97600419c3c7482ee82bc8b", + "zh:16cf003a5bff1c5cae32e29af30f54376aec29b21ce26768d5fa59cc8b3bac3e", + "zh:469539918519547b2b87a9301ad811e59e50d4f217c36da01e0d981b45a393e9", + "zh:620234f4c7dcfd00fa4b7d15e71fa055ada4a8afe084f84a40d06d02fc7e7c08", + "zh:68fd2f982c5fecff972e03eced690077911083f782a237d5a026597ab387f737", + "zh:7bc30de9089a3d060f9866e08f6bd766351880026a458a4b7443cb110d47dc16", + "zh:ad772631dfa005fdd6f7cc2ce33d1771218574b5153c5d601d7584fe9e8a0da2", + "zh:cb6f16481607a3899e1d0a8f9fcacf246fb4927ee274da69c7d1e75fc4960713", + "zh:dcac954e9e401c53db3750ab3df22173f7ba288e978da348f97ddbbc4a33abb1", + "zh:eeeb0583e152403bdb473de5f133b48cef04af8f7c3f38ee7dc6d034df91534d", ] } diff --git a/README.md b/README.md index c651998..2fa6a6a 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ # terraform -Contains Terraform code used to manage our infrastructure. +Contains [Terraform](https://terraform.io/) code used to manage our infrastructure, Nix'ified for [Terranix](https://terranix.org/). ## Prerequisites +- [Nix](https://nix.dev/) with [Flakes](https://nixos.wiki/wiki/Flakes) enabled ### Pre-commit hook We want all our Terraform code to be well formatted and adhering to standards, @@ -25,13 +26,22 @@ a chance you push something that doesn't match our standards. As we're using GitLab's Terraform image for our CI/CD pipeline, we'll stick to using the latest version of Terraform. Instruction on how to install Terraform can be found here: +- [Terraform Cloud](https://app.terraform.io/) to use shared state + +### Usage + +- Run `nix develop -c $SHELL` to enter the development environment if not using [`direnv`](https://zero-to-flakes.com/direnv). +- Run `tofu login app.terraform.io` to log in to the Terraform Cloud backend +- Run `nix run` to apply changes. +- Run `nix flake update` to update dependencies. ### Authentication Create a file `terraform.tfvars` containing: + +```tfvars ``` -do_token = "" -``` + ... substituting in our actual key. ### Managed state @@ -41,6 +51,8 @@ do_token = "" - substitute in a personal access token in the shown command - run the command locally to access the shared state +## [HCL to Nix](https://gist.github.com/KiaraGrouwstra/249ede6a7dfc00ea44d85bc6bdbcd875) + ## Code-styling We try to adhere to the diff --git a/config.nix b/config.nix new file mode 100644 index 0000000..7bb9582 --- /dev/null +++ b/config.nix @@ -0,0 +1,16 @@ +{ config, lib, pkgs, options, specialArgs, ... }: + +let + var = options.variable; +in rec { + + resource = { + + local_file.test_import = { + filename = "test_import.txt"; + content = "A terranix created test file using imports. YEY!"; + }; + + }; + +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..d3a5404 --- /dev/null +++ b/flake.lock @@ -0,0 +1,161 @@ +{ + "nodes": { + "bats-assert": { + "flake": false, + "locked": { + "lastModified": 1636059754, + "narHash": "sha256-ewME0l27ZqfmAwJO4h5biTALc9bDLv7Bl3ftBzBuZwk=", + "owner": "bats-core", + "repo": "bats-assert", + "rev": "34551b1d7f8c7b677c1a66fc0ac140d6223409e5", + "type": "github" + }, + "original": { + "owner": "bats-core", + "repo": "bats-assert", + "type": "github" + } + }, + "bats-support": { + "flake": false, + "locked": { + "lastModified": 1548869839, + "narHash": "sha256-Gr4ntadr42F2Ks8Pte2D4wNDbijhujuoJi4OPZnTAZU=", + "owner": "bats-core", + "repo": "bats-support", + "rev": "d140a65044b2d6810381935ae7f0c94c7023c8c3", + "type": "github" + }, + "original": { + "owner": "bats-core", + "repo": "bats-support", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1701680307, + "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1704999660, + "narHash": "sha256-nKC1rq0+9uswJzkVyBH6aTzKrE31GPNZHmLWfGhvXL8=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "6cd98a7a7575e7ff7923b1c84259da0b43ba827e", + "type": "github" + }, + "original": { + "owner": "nixos", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "terranix": "terranix", + "terranix-hcloud": "terranix-hcloud" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "terranix": { + "inputs": { + "bats-assert": "bats-assert", + "bats-support": "bats-support", + "flake-utils": [ + "flake-utils" + ], + "nixpkgs": [ + "nixpkgs" + ], + "terranix-examples": "terranix-examples" + }, + "locked": { + "lastModified": 1695406838, + "narHash": "sha256-xiUfVD6rtsVWFotVtUW3Q1nQh4obKzgvpN1wqZuGXvM=", + "owner": "terranix", + "repo": "terranix", + "rev": "fc9077ca02ab5681935dbf0ecd725c4d889b9275", + "type": "github" + }, + "original": { + "owner": "terranix", + "repo": "terranix", + "type": "github" + } + }, + "terranix-examples": { + "locked": { + "lastModified": 1636300201, + "narHash": "sha256-0n1je1WpiR6XfCsvi8ZK7GrpEnMl+DpwhWaO1949Vbc=", + "owner": "terranix", + "repo": "terranix-examples", + "rev": "a934aa1cf88f6bd6c6ddb4c77b77ec6e1660bd5e", + "type": "github" + }, + "original": { + "owner": "terranix", + "repo": "terranix-examples", + "type": "github" + } + }, + "terranix-hcloud": { + "inputs": { + "flake-utils": [ + "flake-utils" + ], + "nixpkgs": [ + "nixpkgs" + ], + "terranix": [ + "terranix" + ] + }, + "locked": { + "lastModified": 1687791412, + "narHash": "sha256-5acZ+oKhoHmrlX1hRad6IisXyggR5prbCvMUuU7zlr0=", + "owner": "terranix", + "repo": "terranix-hcloud", + "rev": "6bcdfc395aeb37f83287f817eb620553534c3ff2", + "type": "github" + }, + "original": { + "owner": "terranix", + "repo": "terranix-hcloud", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..38c4ab3 --- /dev/null +++ b/flake.nix @@ -0,0 +1,102 @@ +{ + inputs = { + nixpkgs.url = "github:nixos/nixpkgs"; + flake-utils.url = "github:numtide/flake-utils"; + terranix = { + url = "github:terranix/terranix"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.flake-utils.follows = "flake-utils"; + }; + terranix-hcloud = { + url = "github:terranix/terranix-hcloud"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.flake-utils.follows = "flake-utils"; + inputs.terranix.follows = "terranix"; + }; + }; + + outputs = { self, nixpkgs, ... }@inputs: + inputs.flake-utils.lib.eachDefaultSystem (system: + let + pkgs = nixpkgs.legacyPackages.${system}; + terraformConfiguration = inputs.terranix.lib.terranixConfiguration { + inherit system; + modules = [ + inputs.terranix-hcloud.terranixModules.hcloud + ./config.nix + ]; + }; + tf = "${pkgs.opentofu}/bin/tofu"; + in + { + defaultPackage = terraformConfiguration; + + # Auto formatters. This also adds a flake check to ensure that the + # source tree was auto formatted. + treefmt.config = { + projectRootFile = "flake.nix"; + programs = { + nixpkgs-fmt.enable = true; + }; + }; + + # nix develop + devShell = pkgs.mkShell { + buildInputs = with pkgs; [ + treefmt + inputs.terranix.defaultPackage.${system} + (opentofu.withPlugins (p: with p; [ + hcloud # https://registry.terraform.io/providers/hetznercloud/hcloud/latest/docs + ])) + ]; + }; + + # nix run ".#compile" + apps.compile = { + type = "app"; + program = toString (pkgs.writers.writeBash "compile" '' + cp ${terraformConfiguration} config.tf.json + ''); + }; + + # nix run ".#check" + apps.check = { + type = "app"; + program = toString (pkgs.writers.writeBash "check" '' + if [[ -e config.tf.json ]]; then rm -f config.tf.json; fi + cp ${terraformConfiguration} config.tf.json \ + && ${tf} init \ + && ${tf} validate + ''); + }; + + # nix run ".#apply" + apps.apply = { + type = "app"; + program = toString (pkgs.writers.writeBash "apply" '' + if [[ -e config.tf.json ]]; then rm -f config.tf.json; fi + cp ${terraformConfiguration} config.tf.json \ + && ${tf} init \ + && ${tf} apply + ''); + }; + + # nix run ".#destroy" + apps.destroy = { + type = "app"; + program = toString (pkgs.writers.writeBash "destroy" '' + if [[ -e config.tf.json ]]; then rm -f config.tf.json; fi + cp ${terraformConfiguration} config.tf.json \ + && ${tf} init \ + && ${tf} destroy + rm ${toString ./.}/config.tf.json + rm ${toString ./.}/terraform.tfstate* + ''); + }; + + # nix run + defaultApp = self.apps.${system}.apply; + + formatter = pkgs.treefmt; + }); +} diff --git a/install_precommit_hook.sh b/install_precommit_hook.sh deleted file mode 100644 index 100df71..0000000 --- a/install_precommit_hook.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -cp precommit.sh .git/hooks/pre-commit diff --git a/lint.sh b/lint.sh deleted file mode 100644 index b23bd9d..0000000 --- a/lint.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash -set -e - -terraform fmt -recursive -check -diff diff --git a/main.tf b/main.tf deleted file mode 100644 index 45461f3..0000000 --- a/main.tf +++ /dev/null @@ -1,179 +0,0 @@ -terraform { - - backend "local" {} - - # cloud { - # hostname = "app.terraform.io" # Optional; defaults to app.terraform.io - # organization = "bij1" - # workspaces { - # name = "infra" - # } - # } - - required_providers { - digitalocean = { - # https://registry.terraform.io/providers/digitalocean/digitalocean/ - source = "digitalocean/digitalocean" - # source = "bij1/greenhost" - version = "~> 2.21.0" - } - } - -} - -# Set the variable value in *.tfvars file -# or using -var="do_token=..." CLI option -variable "do_token" {} - -# Configure the DigitalOcean Provider -provider "digitalocean" { - api_endpoint = "https://service.greenhost.net/api/" - token = var.do_token -} - -###### REGIONS - -data "digitalocean_regions" "available" { - # filter { - # key = "available" - # values = ["true"] - # } - # filter { - # key = "features" - # values = ["private_networking"] - # } - sort { - key = "name" - direction = "desc" - } -} - -###### IMAGES - -data "digitalocean_images" "available" { - # filter { - # key = "distribution" - # values = ["Ubuntu"] - # } - # filter { - # key = "regions" - # values = ["nyc3"] - # } - sort { - key = "created" - direction = "desc" - } -} - -###### SSH KEYS - -data "digitalocean_ssh_keys" "keys" { - # filter { - # key = "name" - # values = ["laptop", "desktop"] - # } - sort { - key = "name" - direction = "asc" - } -} - -data "digitalocean_ssh_key" "kiara" { - name = "kiara" -} - -# # Create a new SSH key -# resource "digitalocean_ssh_key" "key_kiara" { -# name = "kiara's key" -# public_key = file("/home/kiara/.ssh/id_rsa.pub") -# } - -###### DROPLETS - -# data "digitalocean_droplets" "droplets" { -# # filter { -# # key = "size" -# # values = ["s-1vcpu-1gb"] -# # } -# # filter { -# # key = "backups" -# # values = ["true"] -# # } -# sort { -# key = "created_at" -# direction = "desc" -# } -# } - -# data "digitalocean_droplet" "cloud" { -# id = "8864" -# # name = "cloud.bij1.org" -# } - -# # Create a new Droplet using the SSH key -# resource "digitalocean_droplet" "web" { -# image = "ubuntu-18-04-x64" -# name = "web-1" -# region = "nyc3" -# size = "s-1vcpu-1gb" -# ssh_keys = [digitalocean_ssh_key.default.fingerprint] -# } - -# # Create a new Web Droplet in the nyc2 region -# resource "digitalocean_droplet" "web" { -# image = "ubuntu-18-04-x64" -# name = "web-1" -# region = "nyc2" -# size = "s-1vcpu-1gb" -# backups = false -# monitoring = false -# ipv6 = false -# # vpc_uuid = "" -# # ssh_keys = [] # change = recreate! -# # resize_disk = true -# # tags = [] -# # user_data = "" -# # volume_ids = [] -# # droplet_agent = bool -# # graceful_shutdown = false -# } - -###### DNS RECORDS - -data "digitalocean_records" "records" { # records_bij1_net - domain = "bij1.net" - # filter { - # key = "type" - # values = ["MX"] - # } - sort { - key = "name" - direction = "asc" - } -} - -# data "digitalocean_records" "records_bij1_org" { -# domain = "bij1.org" -# # filter { -# # key = "type" -# # values = ["MX"] -# # } -# sort { -# key = "name" -# direction = "asc" -# } -# } - -data "digitalocean_record" "static" { - domain = "bij1.net" - name = "static" -} - -# # Add an A record to the domain. -# resource "digitalocean_record" "foo" { -# domain = "bij1.org" -# type = "A" -# name = "foo" -# value = "192.168.0.11" -# ttl = 86400 -# } diff --git a/outputs.tf b/outputs.tf deleted file mode 100644 index 1165867..0000000 --- a/outputs.tf +++ /dev/null @@ -1,35 +0,0 @@ -output "regions_output" { - value = data.digitalocean_regions.available.regions -} - -output "images_output" { - value = data.digitalocean_images.available -} - -output "keys_output" { - value = data.digitalocean_ssh_keys.keys -} - -output "key_output" { - value = data.digitalocean_ssh_key.kiara.public_key -} - -# output "droplets_output" { -# value = data.digitalocean_droplets.droplets -# } - -# output "droplet_output" { -# value = data.digitalocean_droplet.example.ipv4_address -# } - -output "records_output" { - value = data.digitalocean_records.records -} - -output "record_type" { - value = data.digitalocean_record.static.type -} - -# output "fqdn" { -# value = digitalocean_record.foo.fqdn -# } diff --git a/precommit.sh b/precommit.sh deleted file mode 100644 index 96021ae..0000000 --- a/precommit.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -echo "Checking if pre-commit hook is up to date" -diff precommit.sh .git/hooks/pre-commit -if [[ $? != 0 ]] -then - echo "Pre-commit hook is not up to date, please run ./install_precommit_hook.sh and commit again!" - exit 1 -fi -echo "${GIT_DIR}" -./lint.sh diff --git a/treefmt.toml b/treefmt.toml new file mode 100644 index 0000000..c396b28 --- /dev/null +++ b/treefmt.toml @@ -0,0 +1,5 @@ +# One CLI to format the code tree - https://github.com/numtide/treefmt + +[formatter.nix] +command = "nixpkgs-fmt" +includes = [ "*.nix"] diff --git a/variables.tf b/variables.tf deleted file mode 100644 index e69de29..0000000