Merge "edge01: systemd unit for running RIPE Atlas anchor VM"
diff --git a/bgpwtf/machines/edge01.waw.bgp.wtf-hardware.nix b/bgpwtf/machines/edge01.waw.bgp.wtf-hardware.nix
index d6ed36a..c93048a 100644
--- a/bgpwtf/machines/edge01.waw.bgp.wtf-hardware.nix
+++ b/bgpwtf/machines/edge01.waw.bgp.wtf-hardware.nix
@@ -27,6 +27,7 @@
     { device = "/dev/disk/by-uuid/D8BA-345D";
       fsType = "vfat";
     };
+  hscloud.anchorvm.blkdev = "/dev/janusz-vg/ripeanchor";
 
   swapDevices =
     [ { device = "/dev/disk/by-uuid/5dadcff4-fcd4-4e8d-81f6-be68fb630396"; }
diff --git a/bgpwtf/machines/edge01.waw.bgp.wtf.nix b/bgpwtf/machines/edge01.waw.bgp.wtf.nix
index 1ff21fb..cf61bd9 100644
--- a/bgpwtf/machines/edge01.waw.bgp.wtf.nix
+++ b/bgpwtf/machines/edge01.waw.bgp.wtf.nix
@@ -22,7 +22,7 @@
 
   imports = [
     ./modules/router.nix
-
+    ./modules/anchorvm.nix
     # Private configuration data - notably, customer data.
     ./secrets/plain/edge01.waw.bgp.wtf-private.nix
   ];
@@ -129,9 +129,22 @@
       ipv4.addresses = [ { address = "185.236.240.14"; prefixLength = 31; } ];
       ipv6.addresses = [ { address = "2a0d:eb00:2137:1::a"; prefixLength = 127; } ];
     };
+    # VM bridge
+    "br0" = {
+      ipv4.addresses = [ { address = "185.236.240.17"; prefixLength = 29; } ];
+      ipv6.addresses = [ { address = "2a0d:eb00:2137:3::1"; prefixLength = 64; } ];
+    };
 
     # Extra interface configs contained in //bgpwtf/machines/secrets/plain/edge01.waw.bgp.wtf-private.nix
   };
+  networking.bridges = {
+    "br0" = {
+      interfaces = [];
+    };
+  };
+  hscloud.anchorvm = {
+    bridge = "br0";
+  };
 
   hscloud.routing.enable = true;
   hscloud.routing.routerID = "185.236.240.1";
diff --git a/bgpwtf/machines/modules/anchorvm.nix b/bgpwtf/machines/modules/anchorvm.nix
new file mode 100644
index 0000000..9c7b17f
--- /dev/null
+++ b/bgpwtf/machines/modules/anchorvm.nix
@@ -0,0 +1,44 @@
+# This module runs the RIPE anchor VM in a bare qemu.
+# It's expected that a storage LV is created independently and passed as blkdev.
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.hscloud.anchorvm;
+
+in {
+  options.hscloud.anchorvm = {
+    blkdev = mkOption {
+      type = types.str;
+      description = "Root block device";
+    };
+    bridge = mkOption {
+      type = types.str;
+      description = "bridge interface";
+    };
+    ram = mkOption {
+      type = types.int;
+      description = "memory allocated to the vm";
+      default = 2048;
+    };
+  };
+
+  config.systemd.services.anchorvm = {
+    wantedBy = [ "multi-user.target" ];
+    after = [
+      "network.target"
+    ];
+    serviceConfig = {
+      Type = "simple";
+      # spawn=allow needed for bridge helper
+      ExecStart = ''${pkgs.qemu}/bin/qemu-kvm \
+        -nographic -m ${toString cfg.ram} -smp 2 \
+        -drive file=${cfg.blkdev},if=virtio,cache=none,format=raw \
+        -nic bridge,br=${cfg.bridge},model=virtio-net-pci \
+        -sandbox on,obsolete=deny,elevateprivileges=deny,spawn=allow,resourcecontrol=deny
+      '';
+      Restart = "always";
+    };
+  };
+}
diff --git a/bgpwtf/machines/tests/edge01-waw.nix b/bgpwtf/machines/tests/edge01-waw.nix
index e0298d2..535418f 100644
--- a/bgpwtf/machines/tests/edge01-waw.nix
+++ b/bgpwtf/machines/tests/edge01-waw.nix
@@ -163,6 +163,17 @@
         "e4-oob" = { virtual = true; virtualType = "tap"; };
         "e7-dcsw" = { virtual = true; virtualType = "tap"; };
       };
+      hscloud.anchorvm = {
+        blkdev = "/anchor.img";
+        ram = 32;
+      };
+      systemd.services.anchorTestImg = {
+        requiredBy = [ "anchorvm.service" ];
+        serviceConfig = {
+          Type = "oneshot";
+          ExecStart = "${pkgs.coreutils}/bin/truncate -s 128m /anchor.img";
+        };
+      };
     };
 
     speaker = mkBGPSpeaker;