No matter how often you backup, if you never test your recovery procedures - you’d be surprised when it comes to it. So let’s make a recovery plan and give it a test.
Back up user files
Having configured restic-backup-service
, it’s just one command:
restic-guix backup storage
Disaster happens
I see two options:
- I just need to move my digital stuff to a new machine.
- 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
That’s as simple as running guix system image
. The only trick is to add a
couple more services to the operating-system
.
(use-modules (gnu)
(gnu system)
(personal packages binary)
(gnu services admin)
(gnu services guix)
(gnu services shepherd)
(ice-9 textual-ports))
(define system (load "./system.scm"))
(define root-fs
(first (filter (lambda (fs)
(string=? "/" (file-system-mount-point fs)))
(operating-system-file-systems system))))
(operating-system
(inherit system)
(services
(cons*
;; auto-resize fs on boot
(service resize-file-system-service-type
(resize-file-system-configuration
(file-system root-fs)))
(simple-service 'activate-storage
activation-service-type
#~(begin
(use-modules (guix build utils))
(let ((dir "/storage")
(%user (getpw "sarg")))
(mkdir-p dir)
(chown dir (passwd:uid %user) (passwd:gid %user))
(chmod dir #o700))))
;; restore /storage
(simple-service
'restore-storage-from-backup shepherd-root-service-type
(list (shepherd-service
(requirement '(user-processes file-systems file-system-/media/500GB))
(provision '(restore-storage))
(one-shot? #t)
(start #~(lambda _ (invoke #$(file-append restic "/bin/restic")
"-r" "/media/500GB/restic"
"-p" "/media/500GB/restic/pass"
"restore" "latest")))
(stop #f))))
;; install user profile
(service guix-home-service-type
`(("sarg" ,(load "./home.scm"))))
(operating-system-user-services system))))
guix system image --volatile --image-type=efi-raw system-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 install the image.
dd /media/lubuntu/Ventoy/guixdisk.img of=/dev/sda status=progress
reboot
Revitalising Guix
One-off shepherd services added to operating-system
earlier take care of
restoring /storage
from backup and activate the user home profile.
Check that everything worked as expected examining /var/log/messages
.
echo "Wait guix-home-sarg to complete"
until herd status guix-home-sarg | grep 'It is stopped'; do echo -n .; sleep 1; done
passwd root
passwd sarg
login sarg
# app-specific restore commands
doom sync
mu init -m ~/.mail
mu index
logout # sarg
logout # root