Last active
January 26, 2021 01:06
-
-
Save danbst/6a75f7381c0d5a2173dba80f4d888d64 to your computer and use it in GitHub Desktop.
nixos-infect PR https://github.com/elitak/nixos-infect/pull/27
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/env bash | |
# More info at: https://github.com/elitak/nixos-infect | |
set -o pipefail | |
set -e | |
makeConf() { | |
# Skip everything if main config already present | |
[[ -e /etc/nixos/configuration.nix ]] && return 0 | |
# NB <<"EOF" quotes / $ ` in heredocs, <<EOF does not | |
mkdir -p /etc/nixos | |
local IFS=$'\n'; keys=($(grep -vE '^[[:space:]]*(#|$)' /root/.ssh/authorized_keys)) | |
cat > /etc/nixos/configuration.nix << EOF | |
{ ... }: { | |
imports = [ | |
./hardware-configuration.nix | |
./networking.nix # generated at runtime by nixos-infect | |
$NIXOS_IMPORT | |
]; | |
boot.cleanTmpDir = true; | |
networking.hostName = "$(hostname)"; | |
networking.firewall.allowPing = true; | |
services.openssh.enable = true; | |
users.users.root.openssh.authorizedKeys.keys = [$(for key in "${keys[@]}"; do echo -n " | |
\"$key\""; done) | |
]; | |
} | |
EOF | |
# If you rerun this later, be sure to prune the filesSystems attr | |
cat > /etc/nixos/hardware-configuration.nix << EOF | |
{ ... }: | |
{ | |
imports = [ <nixpkgs/nixos/modules/profiles/qemu-guest.nix> ]; | |
boot.loader.grub.device = "/dev/$disk"; | |
fileSystems."/" = { device = "/dev/${disk}1"; fsType = "ext4"; }; | |
} | |
EOF | |
# XXX It'd be better if we used procfs for all this... | |
local IFS=$'\n' | |
eth0_name=$(ip address show | grep '^2:' | awk -F': ' '{print $2}') | |
eth0_ip4s=$(ip address show dev "$eth0_name" | grep 'inet ' | sed -r 's|.*inet ([0-9.]+)/([0-9]+).*|{ address="\1"; prefixLength=\2; }|') | |
eth0_ip6s=$(ip address show dev "$eth0_name" | grep 'inet6 ' | sed -r 's|.*inet6 ([0-9a-f:]+)/([0-9]+).*|{ address="\1"; prefixLength=\2; }|' || '') | |
gateway=$(ip route show dev "$eth0_name" | grep default | sed -r 's|default via ([0-9.]+).*|\1|') | |
ether0=$(ip address show dev "$eth0_name" | grep link/ether | sed -r 's|.*link/ether ([0-9a-f:]+) .*|\1|') | |
eth1_name=$(ip address show | grep '^3:' | awk -F': ' '{print $2}')||true | |
if [ -n "$eth1_name" ];then | |
eth1_ip4s=$(ip address show dev "$eth1_name" | grep 'inet ' | sed -r 's|.*inet ([0-9.]+)/([0-9]+).*|{ address="\1"; prefixLength=\2; }|') | |
eth1_ip6s=$(ip address show dev "$eth1_name" | grep 'inet6 ' | sed -r 's|.*inet6 ([0-9a-f:]+)/([0-9]+).*|{ address="\1"; prefixLength=\2; }|' || '') | |
ether1=$(ip address show dev "$eth1_name" | grep link/ether | sed -r 's|.*link/ether ([0-9a-f:]+) .*|\1|') | |
gateway6=$(ip -6 route show dev "$eth1_name" | grep default | sed -r 's|default via ([0-9a-f:]+).*|\1|' || true) | |
interfaces1=<< EOF | |
$eth1_name = { | |
ipv4.addresses = [$(for a in "${eth1_ip4s[@]}"; do echo -n " | |
$a"; done) | |
]; | |
ipv6.addresses = [$(for a in "${eth1_ip6s[@]}"; do echo -n " | |
$a"; done) | |
]; | |
EOF | |
extraRules1="ATTR{address}==\"${ether1}\", NAME=\"${eth1_name}\"" | |
else | |
interfaces1="" | |
extraRules1="" | |
fi | |
nameservers=($(grep ^nameserver /etc/resolv.conf | cut -f2 -d' ')) | |
if [ "$eth0_name" = eth* ]; then | |
predictable_inames="usePredictableInterfaceNames = lib.mkForce false;" | |
else | |
predictable_inames="usePredictableInterfaceNames = lib.mkForce true;" | |
fi | |
cat > /etc/nixos/networking.nix << EOF | |
{ lib, ... }: { | |
# This file was populated at runtime with the networking | |
# details gathered from the active system. | |
networking = { | |
nameservers = [$(for a in "${nameservers[@]}"; do echo -n " | |
\"$a\""; done) | |
]; | |
defaultGateway = "${gateway}"; | |
defaultGateway6 = "${gateway6}"; | |
dhcpcd.enable = false; | |
$predictable_inames | |
interfaces = { | |
$eth0_name = { | |
ipv4.addresses = [$(for a in "${eth0_ip4s[@]}"; do echo -n " | |
$a"; done) | |
]; | |
ipv6.addresses = [$(for a in "${eth0_ip6s[@]}"; do echo -n " | |
$a"; done) | |
]; | |
}; | |
$interfaces1 | |
}; | |
}; | |
services.udev.extraRules = '' | |
ATTR{address}=="${ether0}", NAME="${eth0_name}" | |
$extraRules1 | |
''; | |
} | |
EOF | |
#! /usr/bin/env bash | |
# NB put your semi-sensitive (not posted to github) configuration in a separate | |
# file and include it via this customConfig() function. e.g.: | |
# customConfig() { | |
# cat > /etc/nixos/custom.nix << EOF | |
# { config, lib, pkgs, ... }: { | |
# } | |
# EOF | |
# } | |
# | |
# then you can add the files in configuration.nix's imports above and run something like: | |
# cat customConfig nixos-infect | root@targethost bash | |
if [[ "$(type -t customConfig)" == "function" ]]; then customConfig; fi | |
} | |
makeSwap() { | |
# TODO check currently available swapspace first | |
swapFile=$(mktemp /tmp/nixos-infect.XXXXX.swp) | |
dd if=/dev/zero "of=$swapFile" bs=1M count=$((1*1024)) | |
chmod 0600 "$swapFile" | |
mkswap "$swapFile" | |
swapon -v "$swapFile" | |
} | |
removeSwap() { | |
swapoff -a | |
rm -vf /tmp/nixos-infect.*.swp | |
} | |
prepareEnv() { | |
# $disk is used in makeConf() | |
for disk in vda sda; do [[ -e /dev/$disk ]] && break; done | |
# DigitalOcean doesn't seem to set USER while running user data | |
export USER="root" | |
export HOME="/root" | |
# Use adapted wget if curl is missing | |
which curl || { \ | |
curl() { | |
eval "wget $( | |
(local isStdout=1 | |
for arg in "$@"; do | |
case "$arg" in | |
"-o") | |
echo "-O"; | |
isStdout=0 | |
;; | |
"-O") | |
isStdout=0 | |
;; | |
"-L") | |
;; | |
*) | |
echo "$arg" | |
;; | |
esac | |
done; | |
[[ $isStdout -eq 1 ]] && echo "-O-" | |
)| tr '\n' ' ' | |
)" | |
}; export -f curl; } | |
# Nix installer tries to use sudo regardless of whether we're already uid 0 | |
#which sudo || { sudo() { eval "$@"; }; export -f sudo; } | |
# shellcheck disable=SC2174 | |
mkdir -p -m 0755 /nix | |
} | |
req() { | |
type "$1" > /dev/null 2>&1 || which "$1" > /dev/null 2>&1 | |
} | |
checkEnv() { | |
# Perform some easy fixups before checking | |
which dnf && dnf install -y perl-Digest-SHA # Fedora 24 | |
which bzcat || (which yum && yum install -y bzip2) \ | |
|| (which apt-get && apt-get install bzip2) \ | |
|| true | |
[[ "$(whoami)" == "root" ]] || { echo "ERROR: Must run as root"; return 1; } | |
req curl || req wget || { echo "ERROR: Missing both curl and wget"; return 1; } | |
req bzcat || { echo "ERROR: Missing bzcat"; return 1; } | |
req groupadd || { echo "ERROR: Missing groupadd"; return 1; } | |
req useradd || { echo "ERROR: Missing useradd"; return 1; } | |
req ip || { echo "ERROR: Missing ip"; return 1; } | |
req awk || { echo "ERROR: Missing awk"; return 1; } | |
req cut || { echo "ERROR: Missing cut"; return 1; } | |
} | |
infect() { | |
# Add nix build users | |
# FIXME run only if necessary, rather than defaulting true | |
groupadd nixbld -g 30000 || true | |
for i in {1..10}; do useradd -c "Nix build user $i" -d /var/empty -g nixbld -G nixbld -M -N -r -s "$(which nologin)" nixbld$i || true; done | |
# TODO use addgroup and adduser as fallbacks | |
#addgroup nixbld -g 30000 || true | |
#for i in {1..10}; do adduser -DH -G nixbld nixbld$i || true; done | |
curl https://nixos.org/nix/install | $SHELL | |
# shellcheck disable=SC1090 | |
source ~/.nix-profile/etc/profile.d/nix.sh | |
[[ -z "$NIX_CHANNEL" ]] && NIX_CHANNEL="nixos-18.03" | |
nix-channel --remove nixpkgs | |
nix-channel --add "https://nixos.org/channels/$NIX_CHANNEL" nixos | |
nix-channel --update | |
export NIXOS_CONFIG=/etc/nixos/configuration.nix | |
nix-env --set \ | |
-I nixpkgs=$HOME/.nix-defexpr/channels/nixos \ | |
-f '<nixpkgs/nixos>' \ | |
-p /nix/var/nix/profiles/system \ | |
-A system | |
# Remove nix installed with curl | bash | |
rm -fv /nix/var/nix/profiles/default* | |
/nix/var/nix/profiles/system/sw/bin/nix-collect-garbage | |
# Reify resolv.conf | |
[[ -L /etc/resolv.conf ]] && mv -v /etc/resolv.conf /etc/resolv.conf.lnk && cat /etc/resolv.conf.lnk > /etc/resolv.conf | |
# Stage the Nix coup d'état | |
touch /etc/NIXOS | |
echo etc/nixos > /etc/NIXOS_LUSTRATE | |
echo etc/resolv.conf >> /etc/NIXOS_LUSTRATE | |
echo root/.nix-defexpr/channels >> /etc/NIXOS_LUSTRATE | |
rm -rf /boot.bak | |
mv -v /boot /boot.bak | |
/nix/var/nix/profiles/system/bin/switch-to-configuration boot | |
} | |
prepareEnv | |
checkEnv | |
makeConf | |
makeSwap # smallest (512MB) droplet needs extra memory! | |
infect | |
removeSwap | |
reboot |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment