Add chroot context manager example to debootstrap

Closes #132
This commit is contained in:
Joshua Boniface 2021-07-11 23:10:41 -04:00
parent c76149141f
commit 8c975e5c46
2 changed files with 43 additions and 39 deletions

View File

@ -34,6 +34,29 @@
# with that. # with that.
import os import os
from contextlib import contextmanager
# Create a chroot context manager
# This can be used later in the script to chroot to the destination directory
# for instance to run commands within the target.
@contextmanager
def chroot_target(destination):
try:
real_root = os.open("/", os.O_RDONLY)
os.chroot(destination)
fake_root = os.open("/", os.O_RDONLY)
os.fchdir(fake_root)
yield
finally:
os.fchdir(real_root)
os.chroot(".")
os.fchdir(real_root)
os.close(fake_root)
os.close(real_root)
del fake_root
del real_root
# Installation function - performs a debootstrap install of a Debian system # Installation function - performs a debootstrap install of a Debian system
# Note that the only arguments are keyword arguments. # Note that the only arguments are keyword arguments.
@ -193,40 +216,25 @@ GRUB_DISABLE_LINUX_UUID=false
fh.write(data) fh.write(data)
# Chroot, do some in-root tasks, then exit the chroot # Chroot, do some in-root tasks, then exit the chroot
# EXITING THE CHROOT IS VERY IMPORTANT OR THE FOLLOWING STAGES OF THE PROVISIONER with chroot_target(temporary_directory):
# WILL FAIL IN UNEXPECTED WAYS! Keep this in mind when using chroot in your scripts. # Install and update GRUB
real_root = os.open("/", os.O_RDONLY) os.system(
os.chroot(temporary_directory) "grub-install --force /dev/rbd/{}/{}_{}".format(root_disk['pool'], vm_name, root_disk['disk_id'])
fake_root = os.open("/", os.O_RDONLY) )
os.fchdir(fake_root) os.system(
"update-grub"
# Install and update GRUB )
os.system( # Set a really dumb root password [TEMPORARY]
"grub-install --force /dev/rbd/{}/{}_{}".format(root_disk['pool'], vm_name, root_disk['disk_id']) os.system(
) "echo root:test123 | chpasswd"
os.system( )
"update-grub" # Enable cloud-init target on (first) boot
) # NOTE: Your user-data should handle this and disable it once done, or things get messy.
# Set a really dumb root password [TEMPORARY] # That cloud-init won't run without this hack seems like a bug... but even the official
os.system( # Debian cloud images are affected, so who knows.
"echo root:test123 | chpasswd" os.system(
) "systemctl enable cloud-init.target"
# Enable cloud-init target on (first) boot )
# NOTE: Your user-data should handle this and disable it once done, or things get messy.
# That cloud-init won't run without this hack seems like a bug... but even the official
# Debian cloud images are affected, so who knows.
os.system(
"systemctl enable cloud-init.target"
)
# Restore our original root/exit the chroot
# EXITING THE CHROOT IS VERY IMPORTANT OR THE FOLLOWING STAGES OF THE PROVISIONER
# WILL FAIL IN UNEXPECTED WAYS! Keep this in mind when using chroot in your scripts.
os.fchdir(real_root)
os.chroot(".")
os.fchdir(real_root)
os.close(fake_root)
os.close(real_root)
# Unmount the bound devfs # Unmount the bound devfs
os.system( os.system(
@ -235,8 +243,4 @@ GRUB_DISABLE_LINUX_UUID=false
) )
) )
# Clean up file handles so paths can be unmounted
del fake_root
del real_root
# Everything else is done via cloud-init user-data # Everything else is done via cloud-init user-data

View File

@ -29,7 +29,7 @@
# This script will run under root privileges as the provisioner does. Be careful # This script will run under root privileges as the provisioner does. Be careful
# with that. # with that.
# Installation function - performs a debootstrap install of a Debian system # Installation function - performs no actions then returns
# Note that the only arguments are keyword arguments. # Note that the only arguments are keyword arguments.
def install(**kwargs): def install(**kwargs):
# The provisioner has already mounted the disks on kwargs['temporary_directory']. # The provisioner has already mounted the disks on kwargs['temporary_directory'].