summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--op-mode-definitions/system-image.xml.in12
-rw-r--r--python/vyos/utils/io.py19
-rwxr-xr-xsrc/op_mode/image_manager.py42
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')