Ingolf Wagner 5 months ago
commit
e4acfa4ffd
6 changed files with 302 additions and 0 deletions
  1. 9 0
      .gitignore
  2. 13 0
      README.md
  3. 7 0
      default.nix
  4. 111 0
      module/nixserver.nix
  5. 139 0
      module/server.nix
  6. 23 0
      shell.nix

+ 9 - 0
.gitignore

@@ -0,0 +1,9 @@
+.terraform
+*.tf.json
+*.swp
+
+
+plops/generated/**
+terraform.tfstate
+terraform.tfstate.backup
+.terraform.tfstate.lock.info

+ 13 - 0
README.md

@@ -0,0 +1,13 @@
+
+An opinionated hcloud
+[terranix](https://terranix.org/)
+module you can use.
+
+# terraform version 0.11
+
+This module currently only works with version 0.11
+
+# terraform version 0.12
+
+will comes soon
+

+ 7 - 0
default.nix

@@ -0,0 +1,7 @@
+{ pkgs, lib, ... }:
+{
+  imports = [
+    ./module/server.nix
+    ./module/nixserver.nix
+  ];
+}

+ 111 - 0
module/nixserver.nix

@@ -0,0 +1,111 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+  cfg = config.hcloud.nixserver;
+
+  nixosInfect = pkgs.fetchgit {
+    "url" = "https://github.com/elitak/nixos-infect.git";
+    "rev" = "6c6e63594dd831a9b0177add82c84a4ebbd6f7af";
+    "sha256" = "0817x7fzqlbbajy1wvkbd9i7mzm2lfzm45w15pc4mbag44bjc0vi";
+  };
+
+in {
+
+
+  options.hcloud.nixserver = mkOption {
+    default = {};
+    type = with types; attrsOf (submodule ({ name, ... }: {
+      options = {
+        enable = mkEnableOption "nixserver";
+
+        # todo eine option für zusätzlichen speicher
+        name = mkOption {
+          default = "nixserver-${name}";
+          type = with types; str;
+          description = ''
+            name of the server running nixos
+          '';
+        };
+        serverType = mkOption {
+          default = "cx11";
+          type = with types; str;
+          description = ''
+            server type (different costs)
+          '';
+        };
+        channel = mkOption {
+          default = "nixos-19.09";
+          type = with types; str;
+          description = ''
+            nixos channel to install
+          '';
+        };
+        backups = mkOption {
+          default = false;
+          type = with types; bool;
+          description = ''
+            enable backups or not
+          '';
+        };
+        configurationFile = mkOption {
+          default = null;
+          type = with types; nullOr path;
+          description = ''
+            additional configuration File
+          '';
+        };
+        provisioners = mkOption {
+          default = [];
+          type = with types; listOf attrs;
+        };
+      };
+    }));
+  };
+
+  config = mkIf (cfg != {}){
+
+    hcloud.server = mapAttrs' (
+      name: configuration:
+      {
+        name = "${configuration.name}";
+        value = {
+          inherit (configuration) enable serverType backups name;
+          provisioners = [
+            {
+              file.source = "${nixosInfect}/nixos-infect";
+              file.destination = "/root/nixos-infect";
+            }
+            (
+              optionalAttrs
+              (configuration.configurationFile != null)
+              {
+                file.source = configuration.configurationFile;
+                file.destination = "/etc/nixos_input.nix";
+              }
+            )
+          ]
+          ++ configuration.provisioners ++
+          [
+            {
+              remote-exec.inline = [
+                ''
+                  NO_REBOOT="dont" \
+                  PROVIDER=HCloud \
+                  NIX_CHANNEL=${configuration.channel} \
+                  ${
+                    optionalString
+                    (configuration.configurationFile != null)
+                    "NIXOS_IMPORT=/etc/nixos_input.nix"
+                  } \
+                  bash /root/nixos-infect 2>&1 | tee /tmp/infect.log
+                ''
+                ''shutdown -r +1''
+              ];
+            }
+          ];
+        };
+      }
+    ) cfg;
+  };
+
+}

+ 139 - 0
module/server.nix

@@ -0,0 +1,139 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+
+  cfg = config.hcloud.server;
+
+  allAdmins =
+    if ( hasAttr "admins" config.users )
+    then
+      config.users.admins
+    else
+      {};
+
+in {
+
+  options.hcloud.server = mkOption {
+    default = {};
+    type = with types; attrsOf (submodule ({ name, ... }: {
+      options = {
+        enable = mkEnableOption "server";
+        name = mkOption {
+          default = "${name}";
+          type = with types; str;
+          description = ''
+            name
+          '';
+        };
+        provisioners = mkOption {
+          default = [];
+          type = with types; listOf attrs;
+        };
+        image = mkOption {
+          default = "ubuntu-18.04";
+          type = with types; str;
+          description = ''
+            image to spawn on the server
+          '';
+        };
+        serverType = mkOption {
+          default = "cx11";
+          type = with types; str;
+          description = ''
+            server type (different costs)
+          '';
+        };
+        backups = mkOption {
+          default = false;
+          type = with types; bool;
+          description = ''
+            enable backups or not
+          '';
+        };
+
+      };
+    }));
+  };
+
+  config =
+    mkIf (cfg != {} ) {
+
+      hcloud.enable = true;
+
+      resource.hcloud_server =
+        let
+          allUsers = mapAttrsToList ( name: ignore: "\${ hcloud_ssh_key.server_${name}.id }" ) allAdmins;
+
+          allResources = mapAttrs' ( name: configuration: {
+            name = "${configuration.name}";
+            value = {
+              # todo : check if name contains _ which is not allowed by hcloud
+              name = configuration.name;
+              image  = configuration.image;
+              server_type = configuration.serverType;
+              backups = configuration.backups;
+              ssh_keys = allUsers;
+              provisioner = builtins.map (
+                provisioner:
+                if (builtins.hasAttr "file" provisioner)
+                then
+                {
+                  "file" = ({
+                    connection = {
+                      type = "ssh";
+                      user = "root";
+                      private_key = "\${ file(\"${config.provisioner.privateKeyFile}\") }";
+                    };
+                  }
+                  // provisioner.file
+                  );
+                }
+                else if (builtins.hasAttr "remote-exec" provisioner)
+                then
+                {
+                  "remote-exec" = ({
+                    connection = {
+                      type = "ssh";
+                      user = "root";
+                      private_key = "\${ file(\"${config.provisioner.privateKeyFile}\") }";
+                    };
+                  }
+                  // provisioner.remote-exec
+                  );
+                }
+                else provisioner
+              ) configuration.provisioners;
+            };
+          }) cfg;
+        in
+          allResources;
+
+      output =
+        let
+          ipv4Address = mapAttrs' ( ignore: configuration: {
+            name = "${configuration.name}_ipv4_address";
+            value = { value = "\${ hcloud_server.${configuration.name}.ipv4_address }"; } ;
+          } ) cfg;
+
+          ipv6Address = mapAttrs' ( ignore: configuration: {
+            name = "${configuration.name}_ipv6_address";
+            value = { value = "\${ hcloud_server.${configuration.name}.ipv6_address }"; } ;
+          } ) cfg;
+
+        in
+          ipv4Address // ipv6Address;
+
+      resource.hcloud_ssh_key =
+        let
+          allResources = mapAttrs' ( name: configuration: {
+            name = "server_${name}";
+            value = {
+              name = "SSH Key ${name}";
+              public_key = configuration.publicKey;
+            };
+          }) allAdmins;
+        in
+          allResources;
+
+      };
+}

+ 23 - 0
shell.nix

@@ -0,0 +1,23 @@
+{ pkgs ?  import <nixpkgs> {} }:
+
+let
+
+  terranix = pkgs.callPackage (pkgs.fetchgit {
+    url = "https://github.com/mrVanDalo/terranix.git";
+    rev = "6097722f3a94972a92d810f3a707351cd425a4be";
+    sha256 = "1d8w82mvgflmscvq133pz9ynr79cgd5qjggng85byk8axj6fg6jw";
+  }) { };
+
+in pkgs.mkShell {
+
+  buildInputs = with pkgs; [
+    terranix
+
+    # terraform wrapper
+    (pkgs.writeShellScriptBin "terraform" ''
+      export TF_VAR_hcloud_api_token=`${pkgs.pass}/bin/pass development/hetzner.com/api-token`
+      ${pkgs.terraform_0_11}/bin/terraform "$@"
+    '')
+  ];
+
+}