Tutorial: OS installation

Consfigurator implements a number of methods for installing operating systems.

Tutorial conventions

In these tutorials we assume that you have a workstation called laptop.example.com where you run the root Lisp. We also assume that Consfigurator knows about your laptop, and that it has a host deployment specified, so that you can use HOSTDEPLOY-THESE to deploy properties to the laptop as root. For example,:

(defhost laptop.example.com
    (:deploy ((:sudo :as "spwhitton@laptop.example.com") :sbcl))
  "Sean's laptop."
  (os:debian-stable "bullseye" :amd64))

We suppose that you’ve already set up sources of prerequisite data to provide sudo passwords and the like. See the introduction if you haven’t set this up yet.

Build and write out a raw disk image

This is the simplest method, and Consfigurator has decent support built-in: see the previous tutorial. It is less practical for systems which have large disks and/or complex, nested partitioning schemes, such as ext4 on LVM on LUKS, as is common for GNU/Linux laptops. In such cases it is nontrivial to expand the partitions to fill the whole physical disk after the first successful boot, so the disk image has to be the same size as the target disk, which can be unwieldy.

Installing directly to target host’s primary storage

This is similar to the previous method, but it avoids the problem of having to expand filesystems upon first boot. Suppose we have connected the target host’s hard disk to our laptop, or transferred its boot SD card to our laptop’s SD card reader, etc.. Then we can install to it directly::

CONSFIG> (hostdeploy-these laptop.example.com
           (disk:first-disk-installed-for nil test.example.com "/dev/mmcblk0"))

Live replacement of provider cloud images

See the docstring of the INSTALLER:CLEANLY-INSTALLED-ONCE property. This is an efficient way to handle machines in faraway datacentres. Consfigurator’s support for installing Debian stable this way has been fairly well tested, and the technique should work for other operating systems too, once Consfigurator has been taught how to bootstrap them.

Build a specialised live image

This fourth approach requires more work in your consfig. With this approach you build a live image containing everything you need to run Consfigurator on the hardware to which you want to install. After booting up the live system, you can either run Consfigurator manually, or you can set things up to have it run automatically upon boot.

Consfigurator’s ability to bootstrap fresh root filesystems typically requires Internet access, but an alternative is to build and customise a chroot corresponding to the root filesystem of the target system, and include that in the live image, such that after boot Consfigurator just needs to partition the disk, copy in the contents of the prebuilt chroot, and update /etc/fstab and /etc/crypttab with UUIDs. Here is a minimal version of something like that:

(try-register-data-source
 :git-snapshot :name "consfig"
 :repo #P"common-lisp/consfig/" :depth 1 :branch "master")

(defproplist live-installer-built-for :lisp (with-chroot-for)
  "Build a custom Debian Live system at /srv/live/installer.iso.

Typically this property is not applied in a DEFHOST form, but rather run as
needed at the REPL.  The reason for this is that otherwise the whole image will
get rebuilt each time a commit is made to ~/common-lisp/consfig/."
  (:desc "Debian Live system image built")
  (disk:debian-live-iso-built. nil "/srv/live/installer.iso"
    (os:debian-stable "bullseye" :amd64)
    (hostname:configured "debian")
    (apt:installed "sudo" "task-english" "emacs"
                   "sbcl" "slime" "cl-consfigurator" "build-essential"
                   "lvm2" "cryptsetup" "gdisk" "kpartx" "dosfstools")

    (user:has-account "user")
    (user:has-enabled-password "user" :initial-password "live")
    (file:exists-with-content "/etc/sudoers.d/user"
      '("user  ALL=(ALL:ALL) NOPASSWD: ALL") :mode #o600)
    (as "user" (git:snapshot-extracted "consfig" "common-lisp/" :replace t))

    (chroot:os-bootstrapped-for
     nil
     (merge-pathnames (get-hostname with-chroot-for) "/srv/chroot/")
     with-chroot-for)))

Supposing we’ve a DEFHOST form for test.example.com, on our laptop we could then use:

CONSFIG> (hostdeploy-these laptop.example.com
           (live-installer-built-for test.example.com))

Then once the live system has booted on the target host, you’d complete the installation using something like this::

CONSFIG> (deploy-these (:sudo :sbcl) "debian"
           (os:debian-stable "bullseye" :amd64)
           (disk:volumes-installed-for nil test.example.com :leave-open t
                                       :chroot "/srv/chroot/test.example.com")

This approach requires that a :DEVICE-FILE is specified for each of the host’s physical disks.

To prepare a live image that is capable of installing more than one system without an Internet connection, you’d probably need to investigate including an apt repo, or equivalent, in the live system, and point Consfigurator’s OS bootstrapping properties at that.