about summary refs log tree commit diff
path: root/users/wpcarro/terraform/default.nix
diff options
context:
space:
mode:
Diffstat (limited to 'users/wpcarro/terraform/default.nix')
-rw-r--r--users/wpcarro/terraform/default.nix185
1 files changed, 185 insertions, 0 deletions
diff --git a/users/wpcarro/terraform/default.nix b/users/wpcarro/terraform/default.nix
new file mode 100644
index 0000000000..b3c16144a2
--- /dev/null
+++ b/users/wpcarro/terraform/default.nix
@@ -0,0 +1,185 @@
+{ depot, pkgs, lib, ... }:
+
+let
+  inherit (builtins) concatLists concatStringsSep toJSON unsafeDiscardStringContext;
+  inherit (depot.users) wpcarro;
+  inherit (pkgs) writeText;
+
+  images = import "${pkgs.path}/nixos/modules/virtualisation/gce-images.nix";
+  nixosImage = images."20.09";
+in {
+  googleCloudVM = {
+    project,
+    name,
+    region,
+    zone,
+    configuration,
+    extraConfig ? {},
+  }: let
+    inherit (configuration.users.users) root;
+    inherit (configuration.networking) firewall;
+
+    # Convert NixOS-style port numbers to Terraform-style.
+    asStrings = xs: map toString xs;
+    asRanges = xs: map (x: "${toString x.from}-${toString x.to}") xs;
+
+    sshKeys = concatStringsSep "\n"
+      (map (key: "root:${key}") root.openssh.authorizedKeys.keys);
+
+    os = depot.ops.nixos.nixosFor (_: {
+      imports = [
+        "${pkgs.path}/nixos/modules/virtualisation/google-compute-image.nix"
+        configuration
+      ];
+
+      networking.hostName = name;
+
+      fileSystems."/nix" = {
+        device = "/dev/disk/by-label/google-${name}-disk";
+        fsType = "ext4";
+      };
+    });
+
+    osRoot = os.config.system.build.toplevel;
+    osPath = unsafeDiscardStringContext (toString osRoot.outPath);
+    drvPath = unsafeDiscardStringContext (toString osRoot.drvPath);
+  in writeText "terraform.tf.json" (toJSON (lib.recursiveUpdate extraConfig {
+    provider.google = {
+      inherit project region zone;
+    };
+
+    resource.google_compute_instance."${name}" = {
+      inherit name zone;
+      machine_type = "e2-standard-2";
+  
+      tags = [
+        "http-server"
+        "https-server"
+        "${name}-firewall"
+      ];
+  
+      boot_disk = {
+        device_name = "boot";
+        initialize_params = {
+          size = 10;
+          image = "projects/nixos-cloud/global/images/${nixosImage.name}";
+        };
+      };
+  
+      attached_disk = {
+        source = "\${google_compute_disk.${name}.id}";
+        device_name = "${name}-disk";
+      };
+  
+      network_interface = {
+        network = "default";
+        subnetwork = "default";
+        access_config = {};
+      };
+  
+      # Copy root's SSH keys from the NixOS configuration and expose them to the
+      # metadata server.
+      metadata = {
+        inherit sshKeys;
+        ssh-keys = sshKeys;
+
+        # NixOS's fetch-instance-ssh-keys.bash relies on these fields being
+        # available on the metadata server.
+        ssh_host_ed25519_key = "\${tls_private_key.${name}.private_key_pem}";
+        ssh_host_ed25519_key_pub = "\${tls_private_key.${name}.public_key_pem}";
+
+        # Even though we have SSH access, having oslogin can still be useful for
+        # troubleshooting in the browser if for some reason SSH isn't working as
+        # expected.
+        enable-oslogin = "TRUE";
+      };
+  
+      service_account.scopes = ["cloud-platform"];
+    };
+
+    resource.tls_private_key."${name}" = {
+      algorithm = "ECDSA";
+      ecdsa_curve = "P384";
+    };
+
+    resource.google_compute_firewall."${name}" = {
+      name = "${name}-firewall";
+      network = "default";
+
+      # Read the firewall configuration from the NixOS configuration.
+      allow = [
+        {
+          protocol = "tcp";
+          ports = concatLists [
+            (asStrings (firewall.allowedTCPPorts or []))
+            (asRanges (firewall.allowedTCPPortRanges or []))
+          ];
+        }
+        {
+          protocol = "udp";
+          ports = concatLists [
+            (asStrings (firewall.allowedUDPPorts or []))
+            (asRanges (firewall.allowedUDPPortRanges or []))
+          ];
+        }
+      ];
+      source_tags = ["${name}-firewall"];
+    };
+  
+    resource.google_compute_disk."${name}" = {
+      inherit zone;
+      name = "${name}-disk";
+      size = 100;
+    };
+
+    resource.null_resource.deploy_nixos = {
+      triggers = {
+        # Redeploy when the NixOS configuration changes.
+        os = "${osPath}";
+        # Redeploy when a new machine is provisioned.
+        machine_id = "\${google_compute_instance.${name}.id}";
+      };
+
+      connection = {
+        host = "\${google_compute_instance.${name}.network_interface[0].access_config[0].nat_ip}";
+      };
+
+      provisioner = [
+        { remote-exec.inline = ["true"]; }
+        {
+          local-exec.command = ''
+            export PATH="${pkgs.openssh}/bin:$PATH"
+
+            scratch="$(mktemp -d)"
+            function cleanup() {
+              rm -rf $scratch
+            }
+            trap cleanup EXIT
+
+            # write out ssh key
+            echo -n "''${tls_private_key.${name}.private_key_pem}" > $scratch/id_rsa.pem
+            chmod 0600 $scratch/id_rsa.pem
+
+            export NIX_SSHOPTS="\
+              -o StrictHostKeyChecking=no\
+              -o UserKnownHostsFile=/dev/null\
+              -o GlobalKnownHostsFile=/dev/null\
+              -o IdentityFile=$scratch/id_rsa.pem
+            "
+
+            nix-build ${drvPath}
+            nix-copy-closure --to \
+              root@''${google_compute_instance.${name}.network_interface[0].access_config[0].nat_ip} \
+              ${osPath} --gzip --use-substitutes
+          '';
+        }
+        {
+          remote-exec.inline = [
+            "nix-env --profile /nix/var/nix/profiles/system --set ${osPath}"
+            "${osPath}/bin/switch-to-configuration switch"
+          ];
+        }
+      ];
+    };
+  }));
+}