nixos-install: Make compatible with Nix 2.0
The use of Nix 2.0 significantly simplifies the installer, since we can just pass a different store URI (--store /mnt) - it's no longer needed to set up a chroot environment for the build, and to bootstrap Nix into the chroot. Also, commands that need to run in the installation (namely boot loader installation and setting a root password) are now executed using nixos-enter. This also removes the need for nixos-prepare-root since any required initialisation is done by Nix or by the activation script.
This commit is contained in:
parent
60cb23001a
commit
e88f28965a
|
@ -11,15 +11,17 @@ tedious, so here is a quick way to see if the installer works
|
||||||
properly:
|
properly:
|
||||||
|
|
||||||
<screen>
|
<screen>
|
||||||
$ nix-build -A config.system.build.nixos-install
|
|
||||||
# mount -t tmpfs none /mnt
|
# mount -t tmpfs none /mnt
|
||||||
|
# nixos-generate-config --root /mnt
|
||||||
|
$ nix-build '<nixpkgs/nixos>' -A config.system.build.nixos-install
|
||||||
# ./result/bin/nixos-install</screen>
|
# ./result/bin/nixos-install</screen>
|
||||||
|
|
||||||
To start a login shell in the new NixOS installation in
|
To start a login shell in the new NixOS installation in
|
||||||
<filename>/mnt</filename>:
|
<filename>/mnt</filename>:
|
||||||
|
|
||||||
<screen>
|
<screen>
|
||||||
# ./result/bin/nixos-install --chroot
|
$ nix-build '<nixpkgs/nixos>' -A config.system.build.nixos-enter
|
||||||
|
# ./result/bin/nixos-enter
|
||||||
</screen>
|
</screen>
|
||||||
|
|
||||||
</para>
|
</para>
|
||||||
|
|
|
@ -1,30 +1,17 @@
|
||||||
#! @shell@
|
#! @shell@
|
||||||
|
|
||||||
# - make Nix store etc.
|
set -e
|
||||||
# - copy closure of Nix to target device
|
shopt -s nullglob
|
||||||
# - register validity
|
|
||||||
# - with a chroot to the target device:
|
export PATH=@path@:$PATH
|
||||||
# * nix-env -p /nix/var/nix/profiles/system -i <nix-expr for the configuration>
|
|
||||||
# * install the boot loader
|
|
||||||
|
|
||||||
# Ensure a consistent umask.
|
# Ensure a consistent umask.
|
||||||
umask 0022
|
umask 0022
|
||||||
|
|
||||||
# Re-exec ourselves in a private mount namespace so that our bind
|
|
||||||
# mounts get cleaned up automatically.
|
|
||||||
if [ "$(id -u)" = 0 ]; then
|
|
||||||
if [ -z "$NIXOS_INSTALL_REEXEC" ]; then
|
|
||||||
export NIXOS_INSTALL_REEXEC=1
|
|
||||||
exec unshare --mount --uts -- "$0" "$@"
|
|
||||||
else
|
|
||||||
mount --make-rprivate /
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Parse the command line for the -I flag
|
# Parse the command line for the -I flag
|
||||||
extraBuildFlags=()
|
extraBuildFlags=()
|
||||||
chrootCommand=(/run/current-system/sw/bin/bash)
|
|
||||||
buildUsersGroup="nixbld"
|
mountPoint=/mnt
|
||||||
|
|
||||||
while [ "$#" -gt 0 ]; do
|
while [ "$#" -gt 0 ]; do
|
||||||
i="$1"; shift 1
|
i="$1"; shift 1
|
||||||
|
@ -42,8 +29,8 @@ while [ "$#" -gt 0 ]; do
|
||||||
mountPoint="$1"; shift 1
|
mountPoint="$1"; shift 1
|
||||||
;;
|
;;
|
||||||
--closure)
|
--closure)
|
||||||
closure="$1"; shift 1
|
# FIXME: --closure is a misnomer
|
||||||
buildUsersGroup=""
|
system="$1"; shift 1
|
||||||
;;
|
;;
|
||||||
--no-channel-copy)
|
--no-channel-copy)
|
||||||
noChannelCopy=1
|
noChannelCopy=1
|
||||||
|
@ -57,17 +44,13 @@ while [ "$#" -gt 0 ]; do
|
||||||
--show-trace)
|
--show-trace)
|
||||||
extraBuildFlags+=("$i")
|
extraBuildFlags+=("$i")
|
||||||
;;
|
;;
|
||||||
--chroot)
|
|
||||||
runChroot=1
|
|
||||||
if [[ "$@" != "" ]]; then
|
|
||||||
chrootCommand=("$@")
|
|
||||||
fi
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
--help)
|
--help)
|
||||||
exec man nixos-install
|
exec man nixos-install
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
|
--debug)
|
||||||
|
set -x
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
echo "$0: unknown option \`$i'"
|
echo "$0: unknown option \`$i'"
|
||||||
exit 1
|
exit 1
|
||||||
|
@ -75,132 +58,78 @@ while [ "$#" -gt 0 ]; do
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
set -e
|
|
||||||
shopt -s nullglob
|
|
||||||
|
|
||||||
if test -z "$mountPoint"; then
|
|
||||||
mountPoint=/mnt
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! test -e "$mountPoint"; then
|
if ! test -e "$mountPoint"; then
|
||||||
echo "mount point $mountPoint doesn't exist"
|
echo "mount point $mountPoint doesn't exist"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get the path of the NixOS configuration file.
|
# Get the path of the NixOS configuration file.
|
||||||
if test -z "$NIXOS_CONFIG"; then
|
if [[ -z $NIXOS_CONFIG ]]; then
|
||||||
NIXOS_CONFIG=/etc/nixos/configuration.nix
|
NIXOS_CONFIG=$mountPoint/etc/nixos/configuration.nix
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -e "$mountPoint/$NIXOS_CONFIG" ] && [ -z "$closure" ]; then
|
if [[ ${NIXOS_CONFIG:0:1} != / ]]; then
|
||||||
echo "configuration file $mountPoint/$NIXOS_CONFIG doesn't exist"
|
echo "$0: \$NIXOS_CONFIG is not an absolute path"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ ! -e "$NIXOS_CONFIG" ] && [ -z "$closure" ]; then
|
||||||
# Builds will use users that are members of this group
|
echo "configuration file $NIXOS_CONFIG doesn't exist"
|
||||||
extraBuildFlags+=(--option "build-users-group" "$buildUsersGroup")
|
|
||||||
|
|
||||||
# Inherit binary caches from the host
|
|
||||||
# TODO: will this still work with Nix 1.12 now that it has no perl? Probably not...
|
|
||||||
binary_caches="$(@perl@/bin/perl -I @nix@/lib/perl5/site_perl/*/* -e 'use Nix::Config; Nix::Config::readConfig; print $Nix::Config::config{"binary-caches"};')"
|
|
||||||
extraBuildFlags+=(--option "binary-caches" "$binary_caches")
|
|
||||||
|
|
||||||
# We only need nixpkgs in the path if we don't already have a system closure to install
|
|
||||||
if [[ -z "$closure" ]]; then
|
|
||||||
nixpkgs="$(readlink -f "$(nix-instantiate --find-file nixpkgs)")"
|
|
||||||
export NIX_PATH="nixpkgs=$nixpkgs:nixos-config=$mountPoint/$NIXOS_CONFIG"
|
|
||||||
fi
|
|
||||||
unset NIXOS_CONFIG
|
|
||||||
|
|
||||||
# These get created in nixos-prepare-root as well, but we want to make sure they're here in case we're
|
|
||||||
# running with --chroot. TODO: --chroot should just be split into a separate tool.
|
|
||||||
mkdir -m 0755 -p "$mountPoint/dev" "$mountPoint/proc" "$mountPoint/sys"
|
|
||||||
|
|
||||||
# Set up some bind mounts we'll want regardless of chroot or not
|
|
||||||
mount --rbind /dev "$mountPoint/dev"
|
|
||||||
mount --rbind /proc "$mountPoint/proc"
|
|
||||||
mount --rbind /sys "$mountPoint/sys"
|
|
||||||
|
|
||||||
# If we asked for a chroot, that means we're not actually installing anything (yeah I was confused too)
|
|
||||||
# and we just want to run a command in the context of a $mountPoint that we're assuming has already been
|
|
||||||
# set up by a previous nixos-install invocation. In that case we set up some remaining bind mounts and
|
|
||||||
# exec the requested command, skipping the rest of the installation procedure.
|
|
||||||
if [ -n "$runChroot" ]; then
|
|
||||||
mount -t tmpfs -o "mode=0755" none $mountPoint/run
|
|
||||||
rm -rf $mountPoint/var/run
|
|
||||||
ln -s /run $mountPoint/var/run
|
|
||||||
for f in /etc/resolv.conf /etc/hosts; do rm -f $mountPoint/$f; [ -f "$f" ] && cp -Lf $f $mountPoint/etc/; done
|
|
||||||
for f in /etc/passwd /etc/group; do touch $mountPoint/$f; [ -f "$f" ] && mount --rbind -o ro $f $mountPoint/$f; done
|
|
||||||
|
|
||||||
if ! [ -L $mountPoint/nix/var/nix/profiles/system ]; then
|
|
||||||
echo "$0: installation not finished; cannot chroot into installation directory"
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
ln -s /nix/var/nix/profiles/system $mountPoint/run/current-system
|
|
||||||
exec chroot $mountPoint "${chrootCommand[@]}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# A place to drop temporary closures
|
# A place to drop temporary stuff.
|
||||||
trap "rm -rf $tmpdir" EXIT
|
trap "rm -rf $tmpdir" EXIT
|
||||||
tmpdir="$(mktemp -d)"
|
tmpdir="$(mktemp -d)"
|
||||||
|
|
||||||
# Build a closure (on the host; we then copy it into the guest)
|
subs="local?trusted=1 https://cache.nixos.org/"
|
||||||
function closure() {
|
|
||||||
nix-build "${extraBuildFlags[@]}" --no-out-link -E "with import <nixpkgs> {}; runCommand \"closure\" { exportReferencesGraph = [ \"x\" (buildEnv { name = \"env\"; paths = [ ($1) stdenv ]; }) ]; } \"cp x \$out\""
|
|
||||||
}
|
|
||||||
|
|
||||||
system_closure="$tmpdir/system.closure"
|
# Build the system configuration in the target filesystem.
|
||||||
# Use a FIFO for piping nix-store --export into nix-store --import, saving disk
|
if [[ -z $system ]]; then
|
||||||
# I/O and space. nix-store --import is run by nixos-prepare-root.
|
echo "building the configuration in $NIXOS_CONFIG..."
|
||||||
mkfifo $system_closure
|
outLink="$tmpdir/system"
|
||||||
|
nix build --out-link "$outLink" --store "$mountPoint" "${extraBuildFlags[@]}" \
|
||||||
if [ -z "$closure" ]; then
|
--substituters "$subs" \
|
||||||
expr="(import <nixpkgs/nixos> {}).system"
|
-f '<nixpkgs/nixos>' system -I "nixos-config=$NIXOS_CONFIG"
|
||||||
system_root="$(nix-build -E "$expr")"
|
system=$(readlink -f $outLink)
|
||||||
system_closure="$(closure "$expr")"
|
|
||||||
else
|
|
||||||
system_root=$closure
|
|
||||||
# Create a temporary file ending in .closure (so nixos-prepare-root knows to --import it) to transport the store closure
|
|
||||||
# to the filesytem we're preparing. Also delete it on exit!
|
|
||||||
# Run in background to avoid blocking while trying to write to the FIFO
|
|
||||||
# $system_closure refers to
|
|
||||||
nix-store --export $(nix-store -qR $closure) > $system_closure &
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
channel_root="$(nix-env -p /nix/var/nix/profiles/per-user/root/channels -q nixos --no-name --out-path 2>/dev/null || echo -n "")"
|
# Set the system profile to point to the configuration. TODO: combine
|
||||||
channel_closure="$tmpdir/channel.closure"
|
# this with the previous step once we have a nix-env replacement with
|
||||||
nix-store --export $channel_root > $channel_closure
|
# a progress bar.
|
||||||
|
nix-env --store "$mountPoint" "${extraBuildFlags[@]}" \
|
||||||
|
--substituters "$subs" \
|
||||||
|
-p $mountPoint/nix/var/nix/profiles/system --set "$system"
|
||||||
|
|
||||||
# Populate the target root directory with the basics
|
# Copy the NixOS/Nixpkgs sources to the target as the initial contents
|
||||||
@prepare_root@/bin/nixos-prepare-root "$mountPoint" "$channel_root" "$system_root" @nixClosure@ "$system_closure" "$channel_closure"
|
# of the NixOS channel.
|
||||||
|
if [[ -z $noChannelCopy ]]; then
|
||||||
|
channelPath="$(nix-env -p /nix/var/nix/profiles/per-user/root/channels -q nixos --no-name --out-path 2>/dev/null || echo -n "")"
|
||||||
|
if [[ -n $channelPath ]]; then
|
||||||
|
echo "copying channel..."
|
||||||
|
mkdir -p $mountPoint/nix/var/nix/profiles/per-user/root
|
||||||
|
nix-env --store "$mountPoint" --substituters 'local?trusted=1' "${extraBuildFlags[@]}" \
|
||||||
|
-p $mountPoint/nix/var/nix/profiles/per-user/root/channels --set "$channelPath" --quiet
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# nixos-prepare-root doesn't currently do anything with file ownership, so we set it up here instead
|
# Mark the target as a NixOS installation, otherwise switch-to-configuration will chicken out.
|
||||||
chown @root_uid@:@nixbld_gid@ $mountPoint/nix/store
|
touch "$mountPoint/etc/NIXOS"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Grub needs an mtab.
|
|
||||||
ln -sfn /proc/mounts $mountPoint/etc/mtab
|
|
||||||
|
|
||||||
# Switch to the new system configuration. This will install Grub with
|
# Switch to the new system configuration. This will install Grub with
|
||||||
# a menu default pointing at the kernel/initrd/etc of the new
|
# a menu default pointing at the kernel/initrd/etc of the new
|
||||||
# configuration.
|
# configuration.
|
||||||
echo "finalising the installation..."
|
if [[ -z $noBootLoader ]]; then
|
||||||
if [ -z "$noBootLoader" ]; then
|
echo "installing the boot loader..."
|
||||||
NIXOS_INSTALL_BOOTLOADER=1 chroot $mountPoint \
|
# Grub needs an mtab.
|
||||||
/nix/var/nix/profiles/system/bin/switch-to-configuration boot
|
ln -sfn /proc/mounts $mountPoint/etc/mtab
|
||||||
|
NIXOS_INSTALL_BOOTLOADER=1 nixos-enter --root "$mountPoint" -- /run/current-system/bin/switch-to-configuration boot
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Run the activation script.
|
# Ask the user to set a root password, but only if the passwd command
|
||||||
chroot $mountPoint /nix/var/nix/profiles/system/activate
|
# exists (i.e. when mutable user accounts are enabled).
|
||||||
|
if [[ -z $noRootPasswd ]] && [ -t 0 ]; then
|
||||||
|
nixos-enter --root "$mountPoint" -c '[[ -e /nix/var/nix/profiles/system/sw/bin/passwd ]] && echo "setting root password..." && /nix/var/nix/profiles/system/sw/bin/passwd'
|
||||||
# Ask the user to set a root password.
|
|
||||||
if [ -z "$noRootPasswd" ] && chroot $mountPoint [ -x /run/wrappers/bin/passwd ] && [ -t 0 ]; then
|
|
||||||
echo "setting root password..."
|
|
||||||
chroot $mountPoint /run/wrappers/bin/passwd
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
echo "installation finished!"
|
echo "installation finished!"
|
||||||
|
|
|
@ -29,17 +29,8 @@ let
|
||||||
nixos-install = makeProg {
|
nixos-install = makeProg {
|
||||||
name = "nixos-install";
|
name = "nixos-install";
|
||||||
src = ./nixos-install.sh;
|
src = ./nixos-install.sh;
|
||||||
|
|
||||||
inherit (pkgs) perl pathsFromGraph rsync;
|
|
||||||
nix = config.nix.package.out;
|
nix = config.nix.package.out;
|
||||||
cacert = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
|
path = makeBinPath [ nixos-enter ];
|
||||||
root_uid = config.ids.uids.root;
|
|
||||||
nixbld_gid = config.ids.gids.nixbld;
|
|
||||||
prepare_root = nixos-prepare-root;
|
|
||||||
|
|
||||||
nixClosure = pkgs.runCommand "closure"
|
|
||||||
{ exportReferencesGraph = ["refs" config.nix.package.out]; }
|
|
||||||
"cp refs $out";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
nixos-rebuild =
|
nixos-rebuild =
|
||||||
|
|
Loading…
Reference in a new issue