From f1086ee02104b41365b401ec46e14b39f0154e3d Mon Sep 17 00:00:00 2001 From: wen587 Date: Tue, 14 Sep 2021 09:34:08 +0800 Subject: [PATCH] [sonic_installer]Add --skip-platform-check option for sonic_installer when image mismatch (#1791) What I did Add --skip-platform-check option for sonic_installer; How I did it Add --skip-platform-check option for sonic_installer when image ASIC mismatch; Split verify_binary_image to verify_secureboot_image and verify_image_platform to handle image verification more accurately. How to verify it Installing a bin file which differs the running platform's ASIC will fail. Previous command output (if the output of a command-line utility has changed) sudo sonic-installer install --help Usage: sonic-installer install [OPTIONS] URL Install image from local binary or URL Options: -y, --yes -f, --force_install Force installation of an image of a type which differs from that of the current running image --skip_migration Do not migrate current configuration to the newly installed image --skip-package-migration Do not migrate current packages to the newly installed image --help Show this message and exit. New command output (if the output of a command-line utility has changed) Options: -y, --yes -f, --force, --skip-secure-check Force installation of an image of a non- secure type than secure running image --skip-platform-check Force installation of an image of a type which is not of the same platform --skip_migration Do not migrate current configuration to the newly installed image --skip-package-migration Do not migrate current packages to the newly installed image --help Show this message and exit. --- sonic_installer/bootloader/aboot.py | 5 +++- sonic_installer/bootloader/bootloader.py | 8 ++++-- sonic_installer/bootloader/grub.py | 34 ++++++++++++++++++++++++ sonic_installer/bootloader/onie.py | 2 +- sonic_installer/bootloader/uboot.py | 3 +++ sonic_installer/main.py | 21 ++++++++++----- 6 files changed, 63 insertions(+), 10 deletions(-) diff --git a/sonic_installer/bootloader/aboot.py b/sonic_installer/bootloader/aboot.py index 47e9c5db5fde..a44c44fdd785 100644 --- a/sonic_installer/bootloader/aboot.py +++ b/sonic_installer/bootloader/aboot.py @@ -163,7 +163,10 @@ def get_binary_image_version(self, image_path): return None return IMAGE_PREFIX + version.strip() - def verify_binary_image(self, image_path): + def verify_image_platform(self, image_path): + return os.path.isfile(image_path) + + def verify_secureboot_image(self, image_path): try: subprocess.check_call(['/usr/bin/unzip', '-tq', image_path]) return self._verify_secureboot_image(image_path) diff --git a/sonic_installer/bootloader/bootloader.py b/sonic_installer/bootloader/bootloader.py index b953dd2715ec..aaeddeba2ffd 100644 --- a/sonic_installer/bootloader/bootloader.py +++ b/sonic_installer/bootloader/bootloader.py @@ -49,8 +49,12 @@ def get_binary_image_version(self, image_path): """returns the version of the image""" raise NotImplementedError - def verify_binary_image(self, image_path): - """verify that the image is supported by the bootloader""" + def verify_image_platform(self, image_path): + """verify that the image is of the same platform than running platform""" + raise NotImplementedError + + def verify_secureboot_image(self, image_path): + """verify that the image is secure running image""" raise NotImplementedError def verify_next_image(self): diff --git a/sonic_installer/bootloader/grub.py b/sonic_installer/bootloader/grub.py index 794f1ce20e19..0202da76bd81 100644 --- a/sonic_installer/bootloader/grub.py +++ b/sonic_installer/bootloader/grub.py @@ -8,6 +8,7 @@ import click +from sonic_py_common import device_info from ..common import ( HOST_PATH, IMAGE_DIR_PREFIX, @@ -15,6 +16,9 @@ run_command, ) from .onie import OnieInstallerBootloader +from .onie import default_sigpipe + +MACHINE_CONF = "installer/machine.conf" class GrubBootloader(OnieInstallerBootloader): @@ -81,6 +85,36 @@ def remove_image(self, image): run_command('grub-set-default --boot-directory=' + HOST_PATH + ' 0') click.echo('Image removed') + def verify_image_platform(self, image_path): + if not os.path.isfile(image_path): + return False + + # Get running platform's ASIC + try: + version_info = device_info.get_sonic_version_info() + if version_info: + asic_type = version_info['asic_type'] + else: + asic_type = None + except (KeyError, TypeError) as e: + click.echo("Caught an exception: " + str(e)) + + # Get installing image's ASIC + p1 = subprocess.Popen(["sed", "-e", "1,/^exit_marker$/d", image_path], stdout=subprocess.PIPE, preexec_fn=default_sigpipe) + p2 = subprocess.Popen(["tar", "xf", "-", MACHINE_CONF, "-O"], stdin=p1.stdout, stdout=subprocess.PIPE, preexec_fn=default_sigpipe) + p3 = subprocess.Popen(["sed", "-n", r"s/^machine=\(.*\)/\1/p"], stdin=p2.stdout, stdout=subprocess.PIPE, preexec_fn=default_sigpipe, text=True) + + stdout = p3.communicate()[0] + image_asic = stdout.rstrip('\n') + + # Return false if machine is not found or unexpected issue occur + if not image_asic: + return False + + if asic_type == image_asic: + return True + return False + @classmethod def detect(cls): return os.path.isfile(os.path.join(HOST_PATH, 'grub/grub.cfg')) diff --git a/sonic_installer/bootloader/onie.py b/sonic_installer/bootloader/onie.py index 3a0115347634..aa23c347a21e 100644 --- a/sonic_installer/bootloader/onie.py +++ b/sonic_installer/bootloader/onie.py @@ -44,5 +44,5 @@ def get_binary_image_version(self, image_path): return IMAGE_PREFIX + version_num - def verify_binary_image(self, image_path): + def verify_secureboot_image(self, image_path): return os.path.isfile(image_path) diff --git a/sonic_installer/bootloader/uboot.py b/sonic_installer/bootloader/uboot.py index ae54c64e43c3..cb6c75609156 100644 --- a/sonic_installer/bootloader/uboot.py +++ b/sonic_installer/bootloader/uboot.py @@ -77,6 +77,9 @@ def remove_image(self, image): subprocess.call(['rm','-rf', HOST_PATH + '/' + image_dir]) click.echo('Done') + def verify_image_platform(self, image_path): + return os.path.isfile(image_path) + @classmethod def detect(cls): arch = platform.machine() diff --git a/sonic_installer/main.py b/sonic_installer/main.py index 79022408e15b..72646531a9e1 100644 --- a/sonic_installer/main.py +++ b/sonic_installer/main.py @@ -480,8 +480,10 @@ def sonic_installer(): @sonic_installer.command('install') @click.option('-y', '--yes', is_flag=True, callback=abort_if_false, expose_value=False, prompt='New image will be installed, continue?') -@click.option('-f', '--force', is_flag=True, - help="Force installation of an image of a type which differs from that of the current running image") +@click.option('-f', '--force', '--skip-secure-check', is_flag=True, + help="Force installation of an image of a non-secure type than secure running image") +@click.option('--skip-platform-check', is_flag=True, + help="Force installation of an image of a type which is not of the same platform") @click.option('--skip_migration', is_flag=True, help="Do not migrate current configuration to the newly installed image") @click.option('--skip-package-migration', is_flag=True, @@ -500,7 +502,7 @@ def sonic_installer(): cls=clicommon.MutuallyExclusiveOption, mutually_exclusive=['skip_setup_swap'], callback=validate_positive_int) @click.argument('url') -def install(url, force, skip_migration=False, skip_package_migration=False, +def install(url, force, skip_platform_check=False, skip_migration=False, skip_package_migration=False, skip_setup_swap=False, swap_mem_size=None, total_mem_threshold=None, available_mem_threshold=None): """ Install image from local binary or URL""" bootloader = get_bootloader() @@ -530,10 +532,17 @@ def install(url, force, skip_migration=False, skip_package_migration=False, echo_and_log('Error: Failed to set image as default', LOG_ERR) raise click.Abort() else: - # Verify that the binary image is of the same type as the running image - if not bootloader.verify_binary_image(image_path) and not force: + # Verify not installing non-secure image in a secure running image + if not bootloader.verify_secureboot_image(image_path) and not force: echo_and_log("Image file '{}' is of a different type than running image.\n".format(url) + - "If you are sure you want to install this image, use -f|--force.\n" + + "If you are sure you want to install this image, use -f|--force|--skip-secure-check.\n" + + "Aborting...", LOG_ERR) + raise click.Abort() + + # Verify that the binary image is of the same platform type as running platform + if not bootloader.verify_image_platform(image_path) and not skip_platform_check: + echo_and_log("Image file '{}' is of a different platform type than running platform.\n".format(url) + + "If you are sure you want to install this image, use --skip-platform-check.\n" + "Aborting...", LOG_ERR) raise click.Abort()