summaryrefslogtreecommitdiffstats
path: root/tv/2configs/xu-qemu0.nix
blob: 355a3665051da02ec953885781e758b123b3a6bb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
{ config, lib, pkgs, ... }:

let
  # XXX cannot use config.build.host.name here because infinite recursion when
  # defining  krebs.hosts.${host-name}.nets.retiolum.aliases  below.
  host-name = "xu";
in

# usage:
#   echo set_password vnc correcthorze | xu-qemu0-monitor
#
#   vncdo -s xu:1 type 'curl init.xu.r' key shift-\\ type sh key return
#
#   http://vnc.xu/vnc_auto.html?port=5701&host=xu&password=correcthorze
#
#   make [install] system=xu-qemu0 target_host=10.56.0.101

with import <stockholm/lib>;

{
  networking.dhcpcd.denyInterfaces = [ "qemubr0" ];

  tv.iptables.extra = {
    nat.POSTROUTING = ["-j MASQUERADE"];
    filter.FORWARD = [
      "-m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT"
      "-i qemubr0 -s 10.56.0.1/24 -m conntrack --ctstate NEW -j ACCEPT"
    ];
    filter.INPUT = [
      "-i qemubr0 -p udp -m udp --dport bootps -j ACCEPT"
      "-i qemubr0 -p udp -m udp --dport domain -j ACCEPT"
    ];
  };

  systemd.network.enable = true;
  systemd.services.systemd-networkd-wait-online.enable = false;

  services.resolved.enable = mkForce false;

  boot.kernel.sysctl."net.ipv4.ip_forward" = 1;

  systemd.network.networks.qemubr0 = {
    matchConfig.Name = "qemubr0";
    address = ["10.56.0.1/24"];
    routes = [{
      routeConfig = {
        Gateway = "*";
        Destination = "10.56.0.0";
      };
    }];
  };
  systemd.network.netdevs.qemubr0 = {
    netdevConfig = {
      Name = "qemubr0";
      Kind = "bridge";
    };
  };

  users.groups.qemu-users.gid = genid "qemu-users";

  environment.etc."qemu/bridge.conf".text = ''
    allow qemubr0
  '';

  krebs.per-user.tv.packages = [
  ];

  users.users.xu-qemu0 = {
    createHome = true;
    group = "qemu-users";
    home = "/home/xu-qemu0";
    uid = genid "xu-qemu0";
  };

  systemd.services.xu-qemu0 = let
  in {
    after = [ "network.target" "systemd-resolved.service" ];
    serviceConfig = {
      User = "xu-qemu0";
      SyslogIdentifier = "xu-qemu0";
      ExecStart = pkgs.writeDash "xu-qemu0" ''
        set -efu
        ${pkgs.coreutils}/bin/mkdir -p "$HOME/tmp"
        img=$HOME/tmp/xu-qemu0.raw
        if ! test -e "$img"; then
          ${pkgs.kvm}/bin/qemu-img create "$img" 10G
        fi
        exec ${pkgs.kvm}/bin/qemu-kvm \
            -monitor unix:$HOME/tmp/xu-qemu0-monitor.sock,server,nowait \
            -boot order=cd \
            -cdrom ${pkgs.fetchurl {
              url = https://nixos.org/releases/nixos/15.09/nixos-15.09.1012.9fe0c23/nixos-minimal-15.09.1012.9fe0c23-x86_64-linux.iso;
              sha256 = "18bc9wrsrjnhj9rya75xliqkl99gxbsk4dmwqivhvwfzb5qb5yp9";
            }} \
            -m 1024 \
            -netdev bridge,br=qemubr0,id=hn0,helper=/var/setuid-wrappers/qemu-bridge-helper \
            -net nic,netdev=hn0,id=nic1,macaddr=52:54:00:12:34:56 \
            -drive file="$img",format=raw \
            -display vnc=:1,websocket=5701,password,lossy \
            -name xu-qemu0 \
      '';
    };
  };

  krebs.setuid.xu-qemu0-monitor = {
    filename = pkgs.writeDash "xu-qemu0-monitor" ''
      exec ${pkgs.socat}/bin/socat \
          stdio \
          UNIX-CONNECT:${config.users.users.xu-qemu0.home}/tmp/xu-qemu0-monitor.sock \
    '';
    owner = "xu-qemu0";
    group = "tv";
  };

  krebs.setuid.qemu-bridge-helper = {
    filename = "${pkgs.qemu}/libexec/qemu-bridge-helper";
    group = "qemu-users";
  };

  users.users.qemu-dnsmasq.uid = genid "qemu-dnsmasq";

  # TODO need custom etc/dbus-1/system.d/dnsmasq.conf for different BusName
  services.dbus.packages = [ pkgs.dnsmasq ];

  systemd.services.qemu-dnsmasq = let
    # bind-interfaces
    conf = pkgs.writeText "qemu-dnsmasq.conf" ''
      listen-address=10.56.0.1
      interface=qemubr0
      dhcp-range=10.56.0.200,10.56.0.250
      dhcp-no-override
      dhcp-leasefile=/tmp/qemu-dnsmasq.leases
      domain=${host-name}.local
      dhcp-host=52:54:00:12:34:56,xu-qemu0,10.56.0.101,1440m
    '';
  in {
    after = [ "network.target" "systemd-resolved.service" ];
    wantedBy = [ "multi-user.target" ];
    serviceConfig = {
      Type = "dbus";
      BusName = "uk.org.thekelleys.dnsmasq";
      # -1 --enable-dbus[=uk.org.thekelleys.dnsmasq]
      SyslogIdentifier = "qemu-dnsmasq";
      ExecStart = "${pkgs.dnsmasq}/bin/dnsmasq -1k -u qemu-dnsmasq -C ${conf}";
      ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
      PrivateTmp = "true";
    };
    restartTriggers = [ config.environment.etc.hosts.source ];
  };


  krebs.nginx.servers.init = {
    server-names = [
      "init.${host-name}"
      "init.${host-name}.r"
      "init.${host-name}.retiolum"
    ];
    extraConfig = ''
      index init.txt;
      root ${pkgs.writeTextFile {
        name = "init-pages";
        text = ''
          #! /bin/sh
          set -efu

          dev=/dev/sda
          pttype=dos # gpt

          case $pttype in
            dos)
              if ! test "$(blkid -o value -s PTTYPE "$dev")" = dos; then
                parted -s "$dev" mklabel msdos
              fi
              if ! test "$(blkid -o value -s PARTLABEL "$dev"1)" = primary; then
                parted -s "$dev" mkpart primary ext4 1MiB 513MiB
                parted -s "$dev" set 1 boot on
              fi
              ;;
            gpt)
              if ! test "$(blkid -o value -s PTTYPE "$dev")" = gpt; then
                parted -s "$dev" mklabel gpt
              fi
              if ! test "$(blkid -o value -s PARTLABEL "$dev"1)" = ESP; then
                parted -s "$dev" mkpart ESP fat32 1MiB 513MiB
                parted -s "$dev" set 1 boot on
              fi
              ;;
            *)
              echo "Error: bad pttype: $pttype" >&2
              exit -1
          esac

          if ! test "$(blkid -o value -s PARTLABEL "$dev"2)" = primary; then
            parted -s "$dev" mkpart primary btrfs 513MiB 100%
          fi
          if ! test "$(blkid -o value -s TYPE "$dev"1)" = vfat; then
            mkfs.vfat "$dev"1
          fi
          if ! test "$(blkid -o value -s TYPE "$dev"2)" = btrfs; then
            mkfs.btrfs "$dev"2
          fi

          parted "$dev" print

          if ! test "$(lsblk -n -o MOUNTPOINT "$dev"2)" = /mnt; then
            mount "$dev"2 /mnt
          fi
          if ! test "$(lsblk -n -o MOUNTPOINT "$dev"1)" = /mnt/boot; then
            mkdir -m 0000 -p /mnt/boot
            mount "$dev"1 /mnt/boot
          fi

          lsblk "$dev"

          key=${shell.escape config.krebs.users.tv-xu.pubkey}

          if [ "$(cat /root/.ssh/authorized_keys 2>/dev/null)" != "$key" ]; then
            mkdir -p /root/.ssh
            echo "$key" > /root/.ssh/authorized_keys
          fi
          systemctl start sshd
          ip route
          echo READY.
        '';
        destination = "/init.txt";
      }};
    '';
  };


  krebs.hosts.${host-name}.nets.retiolum.aliases = [
    "init.${host-name}.r"
    "init.${host-name}.retiolum"
    "vnc.${host-name}.r"
    "vnc.${host-name}.retiolum"
  ];

  krebs.nginx.servers.noVNC = {
    server-names = [
      "vnc.${host-name}"
      "vnc.${host-name}.r"
      "vnc.${host-name}.retiolum"
    ];
    #rewrite ^([^.]*)$ /vnc_auto.html?host=localhost&port=5701;
    locations = singleton (nameValuePair "/" ''
      index vnc.html;
      root ${pkgs.noVNC};
    '');
  };
}