Reprovisioning Guix on a new machine

2023/03/15

No matter how often you backup, if you never test your recovery procedures - you’ll be surprised when it comes to it. So let’s make a recovery plan and give it a test.

Back up user files

Having ~/.config/borgmatic/config.yaml in place it’s just one command:

borgmatic create

Disaster happens

I see two options:

  1. I just need to move my digital stuff to a new machine.
  2. I’ve lost access to my current machine.

Let’s follow the first option for now and prepare everything to migrate smoothly.

Make a raw disk image

Let’s define what the disk image should be.

;; NOTES: this image is WIP and requires patching guix
;; - https://issues.guix.gnu.org/62223
;; - https://git.sr.ht/~abcdw/rde/tree/044de83e980b7038b87d27a090aef24229df85eb/src/gnu/services/home.scm
(use-modules (gnu system) (gnu system image)
             (gnu image) (gnu home)
             (gnu services home))

(define (operating-system-with-homes os homes)
  (operating-system
    (inherit os)
    (packages
     (cons (@ (gnu packages backup) borg)
      (operating-system-packages os)))
    (services
     (cons
      (service guix-home-service-type
               (map (lambda (p)
                      (cons (car p)
                            (home-environment-with-provenance (cdr p))))
                    homes))

      (operating-system-user-services os)))))

(image
 (inherit efi-disk-image)
 (operating-system
   (operating-system-with-homes
    (operating-system-with-provenance (load "./vm.scm"))
    `(("sarg" . ,(load "./vm-home.scm")))))
 (volatile-root? #false))

And then ask guix to produce it.

guix system image image.scm
The following derivations will be built:
  /gnu/store/q0gvw0s79wkjlanfq4yjjyf2f9ddk4iq-disk-image.drv
  /gnu/store/dp0p01bzgb9aarzx040iv7k5w1r7z5xx-genimage.cfg.drv
  /gnu/store/kr39hrsyvwp17ny5hcrj6ynfn56i2cq8-partition.img.drv
  /gnu/store/758yrvd3m7016i5vflzjyg9232j75k2r-system.drv
  /gnu/store/58xsyrsaqaqh3dsxzb7zc0h72v7ha3as-etc.drv
  /gnu/store/5kifgf0yqnki7k9wg0a8jlviqibirmxy-activate.scm.drv
  /gnu/store/rqyl2kcj5q84daw4qriza38l0vkrax0m-activate-service.scm.drv
  /gnu/store/5lnmmgrgpy58nnkcpy8z22a0kf54yv0k-boot.drv
  /gnu/store/ri65rz6rgh5kv6ff8g2q313fr9fjd5ac-provenance.drv
  /gnu/store/z62g9qwy9k65awaaxg2f3jzdadsk5iha-grub.cfg.drv
  /gnu/store/x1zyd14c5xnpd51ql6bcfdv0q06nla8a-partition.img.drv

building /gnu/store/ri65rz6rgh5kv6ff8g2q313fr9fjd5ac-provenance.drv...
building /gnu/store/58xsyrsaqaqh3dsxzb7zc0h72v7ha3as-etc.drv...
building /gnu/store/rqyl2kcj5q84daw4qriza38l0vkrax0m-activate-service.scm.drv...
building /gnu/store/5kifgf0yqnki7k9wg0a8jlviqibirmxy-activate.scm.drv...
building /gnu/store/5lnmmgrgpy58nnkcpy8z22a0kf54yv0k-boot.drv...
building /gnu/store/758yrvd3m7016i5vflzjyg9232j75k2r-system.drv...
building /gnu/store/z62g9qwy9k65awaaxg2f3jzdadsk5iha-grub.cfg.drv...
building /gnu/store/kr39hrsyvwp17ny5hcrj6ynfn56i2cq8-partition.img.drv...
building /gnu/store/x1zyd14c5xnpd51ql6bcfdv0q06nla8a-partition.img.drv...
building /gnu/store/dp0p01bzgb9aarzx040iv7k5w1r7z5xx-genimage.cfg.drv...
building /gnu/store/q0gvw0s79wkjlanfq4yjjyf2f9ddk4iq-disk-image.drv...

And the disk image is: /gnu/store/rj2i98lw7vjj0k48dbwfs0q9aqnd9nxk-disk-image

Let’s check its partition table:

fdisk -l $disk_image
Disk /gnu/store/rj2i98lw7vjj0k48dbwfs0q9aqnd9nxk-disk-image: 2.32 GiB, 2488737792 bytes, 4860816 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 389B45C2-0EC7-42EC-9D96-49B40F820311

Device                                                  Start     End Sectors  Size Type
/gnu/store/rj2i98lw7vjj0k48dbwfs0q9aqnd9nxk-disk-image1  2048   83967   81920   40M EFI System
/gnu/store/rj2i98lw7vjj0k48dbwfs0q9aqnd9nxk-disk-image2 83968 4860775 4776808  2.3G Linux filesystem

And filesystems labels are:

alias kpartx=$(guix build multipath-tools)/sbin/kpartx
kpartx -av $disk_image >/dev/null
lsblk -o NAME,FSTYPE,FSVER,LABEL,UUID /dev/loop0
kpartx -d $disk_image
NAME      FSTYPE FSVER LABEL      UUID
loop0
|-loop0p1 vfat   FAT16 GNU-ESP    572A-DDF3
`-loop0p2 ext4   1.0   Guix_image f6bc8ad8-ff1a-1754-eb2b-35d0f6bc8ad8

Note that the partition labels chosen by guix system image are not taken from the operating-system definition. They’re hardcoded in the guix sources and therefore I have to hardcode the same values in my operating-system. Without matching labels the system would just refuse to boot as they’re used in the EFI loader to find the boot partition and also in the fstab.

LABEL=Guix_image  /      ext4  defaults
LABEL=GNU-ESP     /boot  vfat  defaults

Putting disk image on a real machine

I have a Ventoy USB stick with Lubuntu Live CD on it. Let’s just copy the resulting image to the stick. Note, you might need to follow this recipe: Access USB stick on live ISO as by default the USB drive will not be accessible.

eval $(lsblk -P -o LABEL,MOUNTPOINT | grep Ventoy)
cp $disk_image $MOUNTPOINT/guixdisk.img
eject $MOUNTPOINT

And then reboot to the Live CD environment and run the following provisioning script.

dd /media/lubuntu/Ventoy/guixdisk.img of=/dev/sda status=progress

parted /dev/sda print
# Warning: Not all of the space available to /dev/sda appears to be used, you
# can fix the GPT to use all of the space (an extra 346740088 blocks) or
# continue with the current setting?
# Fix/Ignore? fix

parted -s /dev/sda resizepart 2 100%
fsck -y -f /dev/sda2
resize2fs /dev/sda2
reboot

Restoring backup

Log in as root (password is empty)

borgmatic and borg are baked in the disk image, use it to restore /storage

mkdir -m 0700 /storage && chown sarg:users /storage
mount /dev/sdb1 /mnt

cd /
latest=$(borg list --last 1 --short /mnt)
# borg manual recommends using the same user which made the backup
su sarg -c "borg extract /mnt::$latest"
exit

Revitalising Guix

guix-home profile is already in the image and it’s activated using a one-off shepherd service. It takes some time, so don’t rush to log in under your user. Check herd status guix-home-sarg first and /var/log/messages.

passwd root
passwd sarg
login sarg

cd /storage/devel/dotfiles/guix
guix pull -C /run/current-system/channels.scm
sudo guix system reconfigure system.scm
guix home reconfigure home.scm

# app-specific restore commands
doom sync
mu init -m ~/.mail
mu index

logout # sarg
logout # root