forked from M-Labs/nix-scripts
wfvm: reorganize, add demo-ssh
This commit is contained in:
parent
18f84a65c6
commit
4510ae7552
|
@ -3,4 +3,5 @@
|
||||||
{
|
{
|
||||||
makeWindowsImage = attrs: import ./win.nix ({ inherit pkgs; } // attrs);
|
makeWindowsImage = attrs: import ./win.nix ({ inherit pkgs; } // attrs);
|
||||||
layers = (import ./layers { inherit pkgs; });
|
layers = (import ./layers { inherit pkgs; });
|
||||||
|
utils = (import ./utils.nix { inherit pkgs; });
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
{ pkgs ? import <nixpkgs> {}, impureMode ? false }:
|
{ pkgs ? import <nixpkgs> {}, impureMode ? false }:
|
||||||
|
|
||||||
let
|
let
|
||||||
win = (import ./default.nix { inherit pkgs; });
|
wfvm = (import ./default.nix { inherit pkgs; });
|
||||||
in
|
in
|
||||||
win.makeWindowsImage {
|
wfvm.makeWindowsImage {
|
||||||
|
# Build install script & skip building iso
|
||||||
|
inherit impureMode;
|
||||||
|
|
||||||
# Custom base iso
|
# Custom base iso
|
||||||
# windowsImage = pkgs.fetchurl {
|
# windowsImage = pkgs.fetchurl {
|
||||||
|
@ -11,6 +13,10 @@ win.makeWindowsImage {
|
||||||
# sha256 = "668fe1af70c2f7416328aee3a0bb066b12dc6bbd2576f40f812b95741e18bc3a";
|
# sha256 = "668fe1af70c2f7416328aee3a0bb066b12dc6bbd2576f40f812b95741e18bc3a";
|
||||||
# };
|
# };
|
||||||
|
|
||||||
|
# impureShellCommands = [
|
||||||
|
# "powershell.exe echo Hello"
|
||||||
|
# ];
|
||||||
|
|
||||||
# User accounts
|
# User accounts
|
||||||
users = {
|
users = {
|
||||||
artiq = {
|
artiq = {
|
||||||
|
@ -23,23 +29,15 @@ win.makeWindowsImage {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# Build install script & skip building iso
|
|
||||||
inherit impureMode;
|
|
||||||
|
|
||||||
# impureShellCommands = [
|
|
||||||
# "powershell.exe echo Hello"
|
|
||||||
# ];
|
|
||||||
|
|
||||||
fullName = "M-Labs";
|
|
||||||
organization = "m-labs";
|
|
||||||
|
|
||||||
administratorPassword = "12345";
|
|
||||||
|
|
||||||
# Auto login
|
# Auto login
|
||||||
defaultUser = "artiq";
|
defaultUser = "artiq";
|
||||||
|
|
||||||
|
fullName = "M-Labs";
|
||||||
|
organization = "m-labs";
|
||||||
|
administratorPassword = "12345";
|
||||||
|
|
||||||
# Imperative installation commands, to be installed incrementally
|
# Imperative installation commands, to be installed incrementally
|
||||||
installCommands = with win.layers; [ anaconda3 msys2 msys2-packages ];
|
installCommands = with wfvm.layers; [ anaconda3 msys2 msys2-packages ];
|
||||||
|
|
||||||
# services = {
|
# services = {
|
||||||
# # Enable remote management
|
# # Enable remote management
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
{ pkgs ? import <nixpkgs> {} }:
|
||||||
|
|
||||||
|
let
|
||||||
|
wfvm = (import ./default.nix { inherit pkgs; });
|
||||||
|
in
|
||||||
|
wfvm.utils.wfvm-run {
|
||||||
|
name = "demo-ssh";
|
||||||
|
image = import ./demo-image.nix { inherit pkgs; };
|
||||||
|
display = true;
|
||||||
|
script = "${pkgs.openssh}/bin/ssh -p 2022 wfvm@localhost";
|
||||||
|
}
|
|
@ -10,7 +10,7 @@
|
||||||
};
|
};
|
||||||
in ''
|
in ''
|
||||||
ln -s ${Anaconda3} ./Anaconda3.exe
|
ln -s ${Anaconda3} ./Anaconda3.exe
|
||||||
win-put Anaconda3.exe 'C:\Users\artiq'
|
win-put Anaconda3.exe 'C:\Users\wfvm'
|
||||||
echo Running Anaconda installer...
|
echo Running Anaconda installer...
|
||||||
win-exec 'start /wait "" .\Anaconda3.exe /S /D=%UserProfile%\Anaconda3'
|
win-exec 'start /wait "" .\Anaconda3.exe /S /D=%UserProfile%\Anaconda3'
|
||||||
echo Anaconda installer finished
|
echo Anaconda installer finished
|
||||||
|
@ -32,8 +32,8 @@
|
||||||
in ''
|
in ''
|
||||||
ln -s ${msys2} ./msys2.exe
|
ln -s ${msys2} ./msys2.exe
|
||||||
ln -s ${msys2-auto-install} ./auto-install.js
|
ln -s ${msys2-auto-install} ./auto-install.js
|
||||||
win-put msys2.exe 'C:\Users\artiq'
|
win-put msys2.exe 'C:\Users\wfvm'
|
||||||
win-put auto-install.js 'C:\Users\artiq'
|
win-put auto-install.js 'C:\Users\wfvm'
|
||||||
echo Running MSYS2 installer...
|
echo Running MSYS2 installer...
|
||||||
# work around MSYS2 installer bug that prevents it from closing at the end of unattended install
|
# work around MSYS2 installer bug that prevents it from closing at the end of unattended install
|
||||||
expect -c 'set timeout 600; spawn win-exec ".\\msys2.exe --script auto-install.js -v InstallPrefix=C:\\msys64"; expect FinishedPageCallback { close }'
|
expect -c 'set timeout 600; spawn win-exec ".\\msys2.exe --script auto-install.js -v InstallPrefix=C:\\msys64"; expect FinishedPageCallback { close }'
|
||||||
|
@ -45,7 +45,7 @@
|
||||||
script = let
|
script = let
|
||||||
msys-packages = import ./msys_packages.nix { inherit pkgs; };
|
msys-packages = import ./msys_packages.nix { inherit pkgs; };
|
||||||
msys-packages-put = pkgs.lib.strings.concatStringsSep "\n"
|
msys-packages-put = pkgs.lib.strings.concatStringsSep "\n"
|
||||||
(map (package: ''win-put ${package} 'C:\Users\artiq\msyspackages' '') msys-packages);
|
(map (package: ''win-put ${package} 'C:\Users\wfvm\msyspackages' '') msys-packages);
|
||||||
in
|
in
|
||||||
# Windows command line is so shitty it can't even do glob expansion. Why do people use Windows?
|
# Windows command line is so shitty it can't even do glob expansion. Why do people use Windows?
|
||||||
''
|
''
|
||||||
|
@ -55,9 +55,9 @@
|
||||||
set MSYS=c:\msys64
|
set MSYS=c:\msys64
|
||||||
set ARCH=64
|
set ARCH=64
|
||||||
set PATH=%MSYS%\usr\bin;%MSYS%\mingw%ARCH%\bin;%PATH%
|
set PATH=%MSYS%\usr\bin;%MSYS%\mingw%ARCH%\bin;%PATH%
|
||||||
bash -c "pacman -U --noconfirm C:/Users/artiq/msyspackages/*"
|
bash -c "pacman -U --noconfirm C:/Users/wfvm/msyspackages/*"
|
||||||
EOF
|
EOF
|
||||||
win-put installmsyspackages.bat 'C:\Users\artiq'
|
win-put installmsyspackages.bat 'C:\Users\wfvm'
|
||||||
win-exec installmsyspackages
|
win-exec installmsyspackages
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
{ pkgs, baseRtc ? "2020-04-20T14:21:42", cores ? "4", qemuMem ? "4G" }:
|
||||||
|
|
||||||
|
rec {
|
||||||
|
# qemu_test is a smaller closure only building for a single system arch
|
||||||
|
qemu = pkgs.qemu_test;
|
||||||
|
|
||||||
|
mkQemuFlags = extraFlags: [
|
||||||
|
"-enable-kvm"
|
||||||
|
"-cpu host"
|
||||||
|
"-smp ${cores}"
|
||||||
|
"-m ${qemuMem}"
|
||||||
|
"-bios ${pkgs.OVMF.fd}/FV/OVMF.fd"
|
||||||
|
"-vga virtio"
|
||||||
|
"-rtc base=${baseRtc}"
|
||||||
|
"-device piix3-usb-uhci"
|
||||||
|
"-device e1000,netdev=n1"
|
||||||
|
] ++ extraFlags;
|
||||||
|
|
||||||
|
# Pass empty config file to prevent ssh from failing to create ~/.ssh
|
||||||
|
sshOpts = "-F /dev/null -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=\$TMP/known_hosts -o ConnectTimeout=1";
|
||||||
|
win-exec = pkgs.writeShellScriptBin "win-exec" ''
|
||||||
|
${pkgs.sshpass}/bin/sshpass -p1234 -- \
|
||||||
|
${pkgs.openssh}/bin/ssh -np 2022 ${sshOpts} \
|
||||||
|
wfvm@localhost \
|
||||||
|
$1
|
||||||
|
'';
|
||||||
|
win-wait = pkgs.writeShellScriptBin "win-wait" ''
|
||||||
|
# If the machine is not up within 10 minutes it's likely never coming up
|
||||||
|
timeout=600
|
||||||
|
|
||||||
|
# Wait for VM to be accessible
|
||||||
|
sleep 20
|
||||||
|
echo "Waiting for SSH..."
|
||||||
|
while true; do
|
||||||
|
if test "$timeout" -eq 0; then
|
||||||
|
echo "SSH connection timed out"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
output=$(${win-exec}/bin/win-exec 'echo|set /p="Ran command"' || echo "")
|
||||||
|
if test "$output" = "Ran command"; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Retrying in 1 second, timing out in $timeout seconds"
|
||||||
|
|
||||||
|
((timeout=$timeout-1))
|
||||||
|
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
echo "SSH OK"
|
||||||
|
'';
|
||||||
|
win-put = pkgs.writeShellScriptBin "win-put" ''
|
||||||
|
echo scp windows $1 -\> $2
|
||||||
|
${pkgs.sshpass}/bin/sshpass -p1234 -- \
|
||||||
|
${pkgs.openssh}/bin/scp -P 2022 ${sshOpts} \
|
||||||
|
$1 wfvm@localhost:$2
|
||||||
|
'';
|
||||||
|
|
||||||
|
wfvm-run = { name, image, script, display ? false, isolateNetwork ? true, forwardedPorts ? [] }:
|
||||||
|
let
|
||||||
|
restrict =
|
||||||
|
if isolateNetwork
|
||||||
|
then "on"
|
||||||
|
else "off";
|
||||||
|
# use socat instead of `tcp:...` to allow multiple connections
|
||||||
|
guestfwds =
|
||||||
|
builtins.concatStringsSep ""
|
||||||
|
(map ({ listenAddr, targetAddr, port }:
|
||||||
|
",guestfwd=tcp:${listenAddr}:${toString port}-cmd:${pkgs.socat}/bin/socat\\ -\\ tcp:${targetAddr}:${toString port}"
|
||||||
|
) forwardedPorts);
|
||||||
|
qemuParams = mkQemuFlags (pkgs.lib.optional (!display) "-nographic" ++ [
|
||||||
|
"-drive"
|
||||||
|
"file=${image},index=0,media=disk,cache=unsafe"
|
||||||
|
"-snapshot"
|
||||||
|
"-netdev user,id=n1,net=192.168.1.0/24,restrict=${restrict},hostfwd=tcp::2022-:22${guestfwds}"
|
||||||
|
]);
|
||||||
|
in pkgs.writeShellScriptBin "wfvm-run-${name}" ''
|
||||||
|
set -m
|
||||||
|
qemu-system-x86_64 ${pkgs.lib.concatStringsSep " " qemuParams} &
|
||||||
|
|
||||||
|
${win-wait}/bin/win-wait
|
||||||
|
|
||||||
|
${script}
|
||||||
|
|
||||||
|
echo "Shutting down..."
|
||||||
|
${win-exec}/bin/win-exec 'shutdown /s'
|
||||||
|
echo "Waiting for VM to terminate..."
|
||||||
|
fg
|
||||||
|
echo "Done"
|
||||||
|
'';
|
||||||
|
}
|
|
@ -1,10 +1,8 @@
|
||||||
{ pkgs
|
{ pkgs
|
||||||
, diskImageSize ? "22G"
|
, diskImageSize ? "22G"
|
||||||
, qemuMem ? "4G"
|
|
||||||
, windowsImage ? null
|
, windowsImage ? null
|
||||||
, autoUnattendParams ? {}
|
, autoUnattendParams ? {}
|
||||||
, impureMode ? false
|
, impureMode ? false
|
||||||
, baseRtc ? "2020-04-20T14:21:42"
|
|
||||||
, installCommands ? []
|
, installCommands ? []
|
||||||
, users ? {}
|
, users ? {}
|
||||||
, ...
|
, ...
|
||||||
|
@ -12,8 +10,7 @@
|
||||||
|
|
||||||
let
|
let
|
||||||
lib = pkgs.lib;
|
lib = pkgs.lib;
|
||||||
# qemu_test is a smaller closure only building for a single system arch
|
utils = import ./utils.nix { inherit pkgs; };
|
||||||
qemu = pkgs.qemu_test;
|
|
||||||
libguestfs = pkgs.libguestfs-with-appliance;
|
libguestfs = pkgs.libguestfs-with-appliance;
|
||||||
|
|
||||||
# p7zip on >20.03 has known vulns but we have no better option
|
# p7zip on >20.03 has known vulns but we have no better option
|
||||||
|
@ -24,7 +21,7 @@ let
|
||||||
});
|
});
|
||||||
|
|
||||||
runQemuCommand = name: command: (
|
runQemuCommand = name: command: (
|
||||||
pkgs.runCommandNoCC name { buildInputs = [ p7zip qemu libguestfs ]; }
|
pkgs.runCommandNoCC name { buildInputs = [ p7zip utils.qemu libguestfs ]; }
|
||||||
(
|
(
|
||||||
''
|
''
|
||||||
if ! test -f; then
|
if ! test -f; then
|
||||||
|
@ -45,6 +42,15 @@ let
|
||||||
autounattend = import ./autounattend.nix (
|
autounattend = import ./autounattend.nix (
|
||||||
attrs // {
|
attrs // {
|
||||||
inherit pkgs;
|
inherit pkgs;
|
||||||
|
users = users // {
|
||||||
|
wfvm = {
|
||||||
|
password = "1234";
|
||||||
|
description = "WFVM Administrator";
|
||||||
|
groups = [
|
||||||
|
"Administrators"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -66,27 +72,9 @@ let
|
||||||
virt-make-fs --partition --type=fat pkgs/ $out
|
virt-make-fs --partition --type=fat pkgs/ $out
|
||||||
'';
|
'';
|
||||||
|
|
||||||
mkQemuFlags = extraFlags: [
|
|
||||||
"-enable-kvm"
|
|
||||||
"-cpu"
|
|
||||||
"host"
|
|
||||||
"-smp"
|
|
||||||
"$NIX_BUILD_CORES"
|
|
||||||
"-m"
|
|
||||||
"${qemuMem}"
|
|
||||||
"-bios"
|
|
||||||
"${pkgs.OVMF.fd}/FV/OVMF.fd"
|
|
||||||
"-vga"
|
|
||||||
"virtio"
|
|
||||||
"-device"
|
|
||||||
"piix3-usb-uhci" # USB root hub
|
|
||||||
"-rtc base=${baseRtc}"
|
|
||||||
"-device e1000,netdev=n1"
|
|
||||||
] ++ lib.optional (!impureMode) "-nographic" ++ extraFlags;
|
|
||||||
|
|
||||||
installScript = pkgs.writeScript "windows-install-script" (
|
installScript = pkgs.writeScript "windows-install-script" (
|
||||||
let
|
let
|
||||||
qemuParams = mkQemuFlags [
|
qemuParams = utils.mkQemuFlags (lib.optional (!impureMode) "-nographic" ++ [
|
||||||
# "CD" drive with bootstrap pkgs
|
# "CD" drive with bootstrap pkgs
|
||||||
"-drive"
|
"-drive"
|
||||||
"id=virtio-win,file=${bootstrapPkgs},if=none,format=raw,readonly=on"
|
"id=virtio-win,file=${bootstrapPkgs},if=none,format=raw,readonly=on"
|
||||||
|
@ -102,16 +90,12 @@ let
|
||||||
"file=c.img,index=0,media=disk,cache=unsafe"
|
"file=c.img,index=0,media=disk,cache=unsafe"
|
||||||
# Network
|
# Network
|
||||||
"-netdev user,id=n1,net=192.168.1.0/24,restrict=on"
|
"-netdev user,id=n1,net=192.168.1.0/24,restrict=on"
|
||||||
];
|
]);
|
||||||
in
|
in
|
||||||
''
|
''
|
||||||
#!${pkgs.runtimeShell}
|
#!${pkgs.runtimeShell}
|
||||||
set -euxo pipefail
|
set -euxo pipefail
|
||||||
export PATH=${lib.makeBinPath [ p7zip qemu libguestfs ]}:$PATH
|
export PATH=${lib.makeBinPath [ p7zip utils.qemu libguestfs ]}:$PATH
|
||||||
|
|
||||||
if test -z "''${NIX_BUILD_CORES+x}"; then
|
|
||||||
export NIX_BUILD_CORES=$(nproc)
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create a bootable "USB" image
|
# Create a bootable "USB" image
|
||||||
# Booting in USB mode circumvents the "press any key to boot from cdrom" prompt
|
# Booting in USB mode circumvents the "press any key to boot from cdrom" prompt
|
||||||
|
@ -128,7 +112,7 @@ let
|
||||||
|
|
||||||
# Qemu requires files to be rw
|
# Qemu requires files to be rw
|
||||||
qemu-img create -f qcow2 c.img ${diskImageSize}
|
qemu-img create -f qcow2 c.img ${diskImageSize}
|
||||||
env NIX_BUILD_CORES="''${NIX_BUILD_CORES:4}" qemu-system-x86_64 ${lib.concatStringsSep " " qemuParams}
|
qemu-system-x86_64 ${lib.concatStringsSep " " qemuParams}
|
||||||
''
|
''
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -137,36 +121,19 @@ let
|
||||||
mv c.img $out
|
mv c.img $out
|
||||||
'';
|
'';
|
||||||
|
|
||||||
# Pass empty config file to prevent ssh from failing to create ~/.ssh
|
|
||||||
sshOpts = "-F /dev/null -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=\$TMP/known_hosts -o ConnectTimeout=1";
|
|
||||||
win-exec = pkgs.writeShellScriptBin "win-exec" ''
|
|
||||||
${pkgs.sshpass}/bin/sshpass -p${users.artiq.password} -- \
|
|
||||||
${pkgs.openssh}/bin/ssh -np 2022 ${sshOpts} \
|
|
||||||
artiq@localhost \
|
|
||||||
$1
|
|
||||||
'';
|
|
||||||
win-put = pkgs.writeShellScriptBin "win-put" ''
|
|
||||||
echo scp windows $1 -\> $2
|
|
||||||
${pkgs.sshpass}/bin/sshpass -p${users.artiq.password} -- \
|
|
||||||
${pkgs.openssh}/bin/scp -P 2022 ${sshOpts} \
|
|
||||||
$1 artiq@localhost:$2
|
|
||||||
'';
|
|
||||||
|
|
||||||
finalImage = builtins.foldl' (acc: v: pkgs.runCommandNoCC "${v.name}.img" {
|
finalImage = builtins.foldl' (acc: v: pkgs.runCommandNoCC "${v.name}.img" {
|
||||||
buildInputs = [
|
buildInputs = with utils; [
|
||||||
win-exec
|
qemu win-wait win-exec win-put
|
||||||
win-put
|
|
||||||
qemu
|
|
||||||
] ++ (v.buildInputs or []);
|
] ++ (v.buildInputs or []);
|
||||||
} (let
|
} (let
|
||||||
script = pkgs.writeScript "${v.name}-script" v.script;
|
script = pkgs.writeScript "${v.name}-script" v.script;
|
||||||
qemuParams = mkQemuFlags [
|
qemuParams = utils.mkQemuFlags (lib.optional (!impureMode) "-nographic" ++ [
|
||||||
# Output image
|
# Output image
|
||||||
"-drive"
|
"-drive"
|
||||||
"file=c.img,index=0,media=disk,cache=unsafe"
|
"file=c.img,index=0,media=disk,cache=unsafe"
|
||||||
# Network - enable SSH forwarding
|
# Network - enable SSH forwarding
|
||||||
"-netdev user,id=n1,net=192.168.1.0/24,restrict=on,hostfwd=tcp::2022-:22"
|
"-netdev user,id=n1,net=192.168.1.0/24,restrict=on,hostfwd=tcp::2022-:22"
|
||||||
];
|
]);
|
||||||
|
|
||||||
in ''
|
in ''
|
||||||
# Create an image referencing the previous image in the chain
|
# Create an image referencing the previous image in the chain
|
||||||
|
@ -175,33 +142,11 @@ let
|
||||||
set -m
|
set -m
|
||||||
qemu-system-x86_64 ${lib.concatStringsSep " " qemuParams} &
|
qemu-system-x86_64 ${lib.concatStringsSep " " qemuParams} &
|
||||||
|
|
||||||
# If the machine is not up within 10 minutes it's likely never coming up
|
win-wait
|
||||||
timeout=600
|
|
||||||
|
|
||||||
# Wait for VM to be accessible
|
echo "Executing script to build layer..."
|
||||||
sleep 20
|
|
||||||
echo "Waiting for SSH"
|
|
||||||
while true; do
|
|
||||||
if test "$timeout" -eq 0; then
|
|
||||||
echo "SSH connection timed out"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
output=$(win-exec 'echo|set /p="Ran command"' || echo "")
|
|
||||||
if test "$output" = "Ran command"; then
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Retrying in 1 second, timing out in $timeout seconds"
|
|
||||||
|
|
||||||
((timeout=$timeout-1))
|
|
||||||
|
|
||||||
sleep 1
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "Executing user script..."
|
|
||||||
${script}
|
${script}
|
||||||
echo "User script done"
|
echo "Layer script done"
|
||||||
|
|
||||||
echo "Shutting down..."
|
echo "Shutting down..."
|
||||||
win-exec 'shutdown /s'
|
win-exec 'shutdown /s'
|
||||||
|
|
Loading…
Reference in New Issue