diff options
-rw-r--r-- | op-mode-definitions/system-image.xml.in | 12 | ||||
-rw-r--r-- | python/vyos/utils/io.py | 19 | ||||
-rwxr-xr-x | src/op_mode/image_manager.py | 42 |
3 files changed, 62 insertions, 11 deletions
diff --git a/op-mode-definitions/system-image.xml.in b/op-mode-definitions/system-image.xml.in index 57aeb7bb4..463b985d6 100644 --- a/op-mode-definitions/system-image.xml.in +++ b/op-mode-definitions/system-image.xml.in @@ -77,6 +77,12 @@ <help>Set system image parameters</help> </properties> <children> + <node name="default-boot"> + <properties> + <help>Set default image to boot.</help> + </properties> + <command>sudo ${vyos_op_scripts_dir}/image_manager.py --action set</command> + </node> <tagNode name="default-boot"> <properties> <help>Set default image to boot.</help> @@ -115,6 +121,12 @@ <help>Delete system objects</help> </properties> <children> + <node name="image"> + <properties> + <help>Remove an installed image from the system</help> + </properties> + <command>sudo ${vyos_op_scripts_dir}/image_manager.py --action delete</command> + </node> <tagNode name="image"> <properties> <help>Remove an installed image from the system</help> diff --git a/python/vyos/utils/io.py b/python/vyos/utils/io.py index 8790cbaac..e34a1ba32 100644 --- a/python/vyos/utils/io.py +++ b/python/vyos/utils/io.py @@ -72,3 +72,22 @@ def is_dumb_terminal(): """Check if the current TTY is dumb, so that we can disable advanced terminal features.""" import os return os.getenv('TERM') in ['vt100', 'dumb'] + +def select_entry(l: list, list_msg: str = '', prompt_msg: str = '') -> str: + """Select an entry from a list + + Args: + l (list): a list of entries + list_msg (str): a message to print before listing the entries + prompt_msg (str): a message to print as prompt for selection + + Returns: + str: a selected entry + """ + en = list(enumerate(l, 1)) + print(list_msg) + for i, e in en: + print(f'\t{i}: {e}') + select = ask_input(prompt_msg, numeric_only=True, + valid_responses=range(1, len(l)+1)) + return next(filter(lambda x: x[0] == select, en))[1] diff --git a/src/op_mode/image_manager.py b/src/op_mode/image_manager.py index 55fd5c07d..de53c4cf0 100755 --- a/src/op_mode/image_manager.py +++ b/src/op_mode/image_manager.py @@ -21,23 +21,39 @@ from argparse import ArgumentParser, Namespace from pathlib import Path from shutil import rmtree from sys import exit +from typing import Optional from vyos.system import disk, grub, image, compat -from vyos.utils.io import ask_yes_no +from vyos.utils.io import ask_yes_no, select_entry + +SET_IMAGE_LIST_MSG: str = 'The following images are available:' +SET_IMAGE_PROMPT_MSG: str = 'Select an image to set as default:' +DELETE_IMAGE_LIST_MSG: str = 'The following images are installed:' +DELETE_IMAGE_PROMPT_MSG: str = 'Select an image to delete:' +MSG_DELETE_IMAGE_RUNNING: str = 'Currently running image cannot be deleted; reboot into another image first' +MSG_DELETE_IMAGE_DEFAULT: str = 'Default image cannot be deleted; set another image as default first' @compat.grub_cfg_update -def delete_image(image_name: str) -> None: +def delete_image(image_name: Optional[str] = None, + prompt: bool = True) -> None: """Remove installed image files and boot entry Args: image_name (str): a name of image to delete """ + available_images: list[str] = grub.version_list() + if image_name is None: + if not prompt: + exit('An image name is required for delete action') + else: + image_name = select_entry(available_images, + DELETE_IMAGE_LIST_MSG, + DELETE_IMAGE_PROMPT_MSG) if image_name == image.get_running_image(): - exit('Currently running image cannot be deleted') + exit(MSG_DELETE_IMAGE_RUNNING) if image_name == image.get_default_image(): - exit('Default image cannot be deleted') - available_images: list[str] = grub.version_list() + exit(MSG_DELETE_IMAGE_DEFAULT) if image_name not in available_images: exit(f'The image "{image_name}" cannot be found') presistence_storage: str = disk.find_persistence() @@ -59,15 +75,23 @@ def delete_image(image_name: str) -> None: @compat.grub_cfg_update -def set_image(image_name: str) -> None: +def set_image(image_name: Optional[str] = None, + prompt: bool = True) -> None: """Set default boot image Args: image_name (str): an image name """ + available_images: list[str] = grub.version_list() + if image_name is None: + if not prompt: + exit('An image name is required for set action') + else: + image_name = select_entry(available_images, + SET_IMAGE_LIST_MSG, + SET_IMAGE_PROMPT_MSG) if image_name == image.get_default_image(): exit(f'The image "{image_name}" already configured as default') - available_images: list[str] = grub.version_list() if image_name not in available_images: exit(f'The image "{image_name}" cannot be found') presistence_storage: str = disk.find_persistence() @@ -154,10 +178,6 @@ def parse_arguments() -> Namespace: parser.add_argument('--image_new_name', help='a new name for image') args: Namespace = parser.parse_args() # Validate arguments - if args.action == 'delete' and not args.image_name: - exit('An image name is required for delete action') - if args.action == 'set' and not args.image_name: - exit('An image name is required for set action') if args.action == 'rename' and (not args.image_name or not args.image_new_name): exit('Both old and new image names are required for rename action') |