From a66449541d0fd214e510fb29c594d7a28cea99ea Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Fri, 26 Jan 2024 15:41:34 -0500 Subject: [PATCH] Improve script error handling and variables --- .../examples/script/3-debootstrap.py | 37 +++++++--- .../provisioner/examples/script/4-rinse.py | 72 ++++++++++++++++--- 2 files changed, 90 insertions(+), 19 deletions(-) diff --git a/api-daemon/provisioner/examples/script/3-debootstrap.py b/api-daemon/provisioner/examples/script/3-debootstrap.py index b7e1bf94..f344541b 100644 --- a/api-daemon/provisioner/examples/script/3-debootstrap.py +++ b/api-daemon/provisioner/examples/script/3-debootstrap.py @@ -150,6 +150,10 @@ from daemon_lib.vmbuilder import VMBuilder +# These are some global variables used below +default_root_password = "test123" + + # The VMBuilderScript class must be named as such, and extend VMBuilder. class VMBuilderScript(VMBuilder): def setup(self): @@ -498,11 +502,15 @@ class VMBuilderScript(VMBuilder): ret = os.system( f"debootstrap --include={','.join(deb_packages)} {deb_release} {temp_dir} {deb_mirror}" ) + ret = int(ret >> 8) if ret > 0: - self.fail("Failed to run debootstrap") + self.fail(f"Debootstrap failed with exit code {ret}") # Bind mount the devfs so we can grub-install later - os.system("mount --bind /dev {}/dev".format(temp_dir)) + ret = os.system("mount --bind /dev {}/dev".format(temp_dir)) + ret = int(ret >> 8) + if ret > 0: + self.fail(f"/dev bind mount failed with exit code {ret}") # Create an fstab entry for each volume fstab_file = "{}/etc/fstab".format(temp_dir) @@ -688,23 +696,36 @@ GRUB_DISABLE_LINUX_UUID=false # Do some tasks inside the chroot using the provided context manager with chroot(temp_dir): # Install and update GRUB - os.system( + ret = os.system( "grub-install --force /dev/rbd/{}/{}_{}".format( root_volume["pool"], vm_name, root_volume["disk_id"] ) ) - os.system("update-grub") + ret = int(ret >> 8) + if ret > 0: + self.fail(f"GRUB install failed with exit code {ret}") + + ret = os.system("update-grub") + ret = int(ret >> 8) + if ret > 0: + self.fail(f"GRUB update failed with exit code {ret}") # Set a really dumb root password so the VM can be debugged # EITHER CHANGE THIS YOURSELF, here or in Userdata, or run something after install # to change the root password: don't leave it like this on an Internet-facing machine! - os.system("echo root:test123 | chpasswd") + ret = os.system(f"echo root:{default_root_password} | chpasswd") + ret = int(ret >> 8) + if ret > 0: + self.fail(f"Root password change failed with exit code {ret}") # Enable cloud-init target on (first) boot # 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") + ret = os.system("systemctl enable cloud-init.target") + ret = int(ret >> 8) + if ret > 0: + self.fail(f"Enable of cloud-init failed with exit code {ret}") def cleanup(self): """ @@ -729,7 +750,7 @@ GRUB_DISABLE_LINUX_UUID=false temp_dir = "/tmp/target" # Unmount the bound devfs - os.system("umount {}/dev".format(temp_dir)) + os.system("umount -f {}/dev".format(temp_dir)) # Use this construct for reversing the list, as the normal reverse() messes with the list for volume in list(reversed(self.vm_data["volumes"])): @@ -746,7 +767,7 @@ GRUB_DISABLE_LINUX_UUID=false ): # Unmount filesystem retcode, stdout, stderr = pvc_common.run_os_command( - f"umount {mount_path}" + f"umount -f {mount_path}" ) if retcode: self.log_err( diff --git a/api-daemon/provisioner/examples/script/4-rinse.py b/api-daemon/provisioner/examples/script/4-rinse.py index 4be370ff..535463eb 100644 --- a/api-daemon/provisioner/examples/script/4-rinse.py +++ b/api-daemon/provisioner/examples/script/4-rinse.py @@ -150,6 +150,11 @@ from daemon_lib.vmbuilder import VMBuilder +# These are some global variables used below +default_root_password = "test123" +default_local_time = "UTC" + + # The VMBuilderScript class must be named as such, and extend VMBuilder. class VMBuilderScript(VMBuilder): def setup(self): @@ -524,13 +529,23 @@ class VMBuilderScript(VMBuilder): ret = os.system( f"rinse --arch {rinse_architecture} --directory {temporary_directory} --distribution {rinse_release} --cache-dir {rinse_cache} --add-pkg-list /tmp/addpkg --verbose {mirror_arg}" ) + ret = int(ret >> 8) if ret > 0: - self.fail("Failed to run rinse") + self.fail(f"Rinse failed with exit code {ret}") # Bind mount the devfs, sysfs, and procfs so we can grub-install later - os.system("mount --bind /dev {}/dev".format(temporary_directory)) - os.system("mount --bind /sys {}/sys".format(temporary_directory)) - os.system("mount --bind /proc {}/proc".format(temporary_directory)) + ret = os.system("mount --bind /dev {}/dev".format(temporary_directory)) + ret = int(ret >> 8) + if ret > 0: + self.fail(f"/dev bind mount failed with exit code {ret}") + ret = os.system("mount --bind /sys {}/sys".format(temporary_directory)) + ret = int(ret >> 8) + if ret > 0: + self.fail(f"/sys bind mount failed with exit code {ret}") + ret = os.system("mount --bind /proc {}/proc".format(temporary_directory)) + ret = int(ret >> 8) + if ret > 0: + self.fail(f"/proc bind mount failed with exit code {ret}") # Create an fstab entry for each volume fstab_file = "{}/etc/fstab".format(temporary_directory) @@ -642,41 +657,76 @@ GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop= # Do some tasks inside the chroot using the provided context manager with chroot(temporary_directory): # Fix the broken kernel from rinse by setting a systemd machine ID and running the post scripts - os.system("systemd-machine-id-setup") - os.system( + ret = os.system("systemd-machine-id-setup") + ret = int(ret >> 8) + if ret > 0: + self.fail(f"Machine ID setup failed with exit code {ret}") + + ret = os.system( "rpm -q --scripts kernel-core | grep -A20 'posttrans scriptlet' | tail -n+2 | bash -x" ) + ret = int(ret >> 8) + if ret > 0: + self.fail(f"RPM kernel reinstall failed with exit code {ret}") # Install any post packages - os.system(f"dnf install -y {' '.join(post_packages)}") + if len(post_packages) > 0: + ret = os.system(f"dnf install -y {' '.join(post_packages)}") + ret = int(ret >> 8) + if ret > 0: + self.fail(f"DNF install failed with exit code {ret}") # Install and update GRUB config - os.system( + ret = os.system( "grub2-install --force /dev/rbd/{}/{}_{}".format( root_volume["pool"], vm_name, root_volume["disk_id"] ) ) + ret = int(ret >> 8) + if ret > 0: + self.fail(f"GRUB install failed with exit code {ret}") + os.system("grub2-mkconfig -o /boot/grub2/grub.cfg") + ret = int(ret >> 8) + if ret > 0: + self.fail(f"GRUB update failed with exit code {ret}") # Set a really dumb root password so the VM can be debugged # EITHER CHANGE THIS YOURSELF, here or in Userdata, or run something after install # to change the root password: don't leave it like this on an Internet-facing machine! - os.system("echo root:test123 | chpasswd") + ret = os.system(f"echo root:{default_root_password} | chpasswd") + ret = int(ret >> 8) + if ret > 0: + self.fail(f"Root password change failed with exit code {ret}") # Enable dbus-broker - os.system("systemctl enable dbus-broker.service") + ret = os.system("systemctl enable dbus-broker.service") + ret = int(ret >> 8) + if ret > 0: + self.fail(f"Enable of dbus-broker failed with exit code {ret}") # Enable NetworkManager os.system("systemctl enable NetworkManager.service") + ret = int(ret >> 8) + if ret > 0: + self.fail(f"Enable of NetworkManager failed with exit code {ret}") # Enable cloud-init target on (first) boot # 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") + ret = int(ret >> 8) + if ret > 0: + self.fail(f"Enable of cloud-init failed with exit code {ret}") # Set the timezone to UTC - os.system("ln -sf ../usr/share/zoneinfo/UTC /etc/localtime") + ret = os.system( + f"ln -sf ../usr/share/zoneinfo/{default_local_time} /etc/localtime" + ) + ret = int(ret >> 8) + if ret > 0: + self.fail(f"Localtime update failed with exit code {ret}") def cleanup(self): """