diff --git a/scripts/fast-reboot b/scripts/fast-reboot index 644955533b..bfce5add29 100755 --- a/scripts/fast-reboot +++ b/scripts/fast-reboot @@ -33,6 +33,7 @@ EXIT_SYNCD_SHUTDOWN=11 EXIT_FAST_REBOOT_DUMP_FAILURE=12 EXIT_FILTER_FDB_ENTRIES_FAILURE=13 EXIT_NO_CONTROL_PLANE_ASSISTANT=20 +EXIT_SONIC_INSTALLER_VERIFY_REBOOT=21 function error() { @@ -305,10 +306,12 @@ function reboot_pre_check() exit ${EXIT_FILE_SYSTEM_FULL} fi - # Make sure that the next image exists - if [[ ! -d ${IMAGE_PATH} ]]; then - debug "Next image ${NEXT_SONIC_IMAGE} doesn't exist ..." - exit ${EXIT_NEXT_IMAGE_NOT_EXISTS} + # Verify the next image by sonic_installer + INSTALLER_VERIFY_RC=0 + sonic_installer verify-next-image > /dev/null || INSTALLER_VERIFY_RC=$? + if [[ INSTALLER_VERIFY_RC -ne 0 ]]; then + error "Failed to verify next image. Exit code: $INSTALLER_VERIFY_RC" + exit ${EXIT_SONIC_INSTALLER_VERIFY_REBOOT} fi # Make sure ASIC configuration has not changed between images diff --git a/scripts/reboot b/scripts/reboot index 6a030c15c9..889634bbf4 100755 --- a/scripts/reboot +++ b/scripts/reboot @@ -16,6 +16,7 @@ PLAT_REBOOT="platform_reboot" REBOOT_CAUSE_FILE="/host/reboot-cause/reboot-cause.txt" VERBOSE=no EXIT_NEXT_IMAGE_NOT_EXISTS=4 +EXIT_SONIC_INSTALLER_VERIFY_REBOOT=21 function debug() { @@ -79,10 +80,11 @@ function reboot_pre_check() fi rm ${filename} - # Make sure that the next image exists - if [[ ! -d ${IMAGE_PATH} ]]; then - VERBOSE=yes debug "Next image ${NEXT_SONIC_IMAGE} doesn't exist ..." - exit ${EXIT_NEXT_IMAGE_NOT_EXISTS} + # Verify the next image by sonic_installer + local message=$(sonic_installer verify-next-image 2>&1) + if [ $? -ne 0 ]; then + VERBOSE=yes debug "Failed to verify next image: ${message}" + exit ${EXIT_SONIC_INSTALLER_VERIFY_REBOOT} fi } diff --git a/sonic_installer/bootloader/aboot.py b/sonic_installer/bootloader/aboot.py index 1933921512..3cc43a457f 100644 --- a/sonic_installer/bootloader/aboot.py +++ b/sonic_installer/bootloader/aboot.py @@ -23,6 +23,7 @@ from .bootloader import Bootloader _secureboot = None +DEFAULT_SWI_IMAGE = 'sonic.swi' # For the signature format, see: https://github.com/aristanetworks/swi-tools/tree/master/switools SWI_SIG_FILE_NAME = 'swi-signature' @@ -110,9 +111,9 @@ def remove_image(self, image): self._boot_config_set(SWI=image_path, SWI_DEFAULT=image_path) click.echo("Set next and default boot to current image %s" % current) - image_dir = image.replace(IMAGE_PREFIX, IMAGE_DIR_PREFIX) + image_path = self.get_image_path(image) click.echo('Removing image root filesystem...') - subprocess.call(['rm','-rf', os.path.join(HOST_PATH, image_dir)]) + subprocess.call(['rm','-rf', image_path]) click.echo('Image removed') def get_binary_image_version(self, image_path): @@ -129,6 +130,13 @@ def verify_binary_image(self, image_path): except subprocess.CalledProcessError: return False + def verify_next_image(self): + if not super(AbootBootloader, self).verify_next_image(): + return False + image = self.get_next_image() + image_path = os.path.join(self.get_image_path(image), DEFAULT_SWI_IMAGE) + return self._verify_secureboot_image(image_path) + def _verify_secureboot_image(self, image_path): if isSecureboot(): cert = self.getCert(image_path) diff --git a/sonic_installer/bootloader/bootloader.py b/sonic_installer/bootloader/bootloader.py index 78bd05c61c..54054d4c55 100644 --- a/sonic_installer/bootloader/bootloader.py +++ b/sonic_installer/bootloader/bootloader.py @@ -2,6 +2,14 @@ Abstract Bootloader class """ +from os import path + +from ..common import ( + HOST_PATH, + IMAGE_DIR_PREFIX, + IMAGE_PREFIX, +) + class Bootloader(object): NAME = None @@ -43,8 +51,20 @@ def verify_binary_image(self, image_path): """verify that the image is supported by the bootloader""" raise NotImplementedError + def verify_next_image(self): + """verify the next image for reboot""" + image = self.get_next_image() + image_path = self.get_image_path(image) + return path.exists(image_path) + @classmethod def detect(cls): """returns True if the bootloader is in use""" return False + @classmethod + def get_image_path(cls, image): + """returns the image path""" + prefix = path.join(HOST_PATH, IMAGE_DIR_PREFIX) + return image.replace(IMAGE_PREFIX, prefix) + diff --git a/sonic_installer/main.py b/sonic_installer/main.py index 3c68bcd843..ddd0bffdba 100644 --- a/sonic_installer/main.py +++ b/sonic_installer/main.py @@ -476,5 +476,15 @@ def rollback_docker(container_name): click.echo('Done') +# verify the next image +@cli.command('verify-next-image') +def verify_next_image(): + """ Verify the next image for reboot""" + bootloader = get_bootloader() + if not bootloader.verify_next_image(): + click.echo('Image verification failed') + sys.exit(1) + click.echo('Image successfully verified') + if __name__ == '__main__': cli()