Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

image-tools: T6176: fixes for boot console (backport #3443) #3444

Merged
merged 3 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions data/templates/grub/grub_compat.j2
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
KVM
{%- elif type == 'ttyS' -%}
Serial
{%- elif type == 'ttyUSB' -%}
USB
{%- else -%}
Unknown
{%- endif %}
Expand All @@ -25,8 +23,6 @@
console=ttyS0,{{ console_speed }} console=tty0
{%- elif type == 'ttyS' -%}
console=tty0 console=ttyS0,{{ console_speed }}
{%- elif type == 'ttyUSB' -%}
console=tty0 console=ttyUSB0,115200
{%- else -%}
console=tty0 console=ttyS0,{{ console_speed }}
{%- endif %}
Expand Down
6 changes: 0 additions & 6 deletions data/templates/grub/grub_options.j2
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,6 @@ submenu "Boot options" {
setup_serial
configfile ${prefix}/grub.cfg.d/*vyos-menu*.cfg
}
menuentry "ttyUSB (USB serial)" {
set console_type="ttyUSB"
export console_type
setup_serial
configfile ${prefix}/grub.cfg.d/*vyos-menu*.cfg
}
}
menuentry "Enter console number" {
read console_num
Expand Down
9 changes: 9 additions & 0 deletions op-mode-definitions/system-image.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,15 @@
<help>Set system operational parameters</help>
</properties>
<children>
<tagNode name="boot-console">
<properties>
<help>Set system console type at boot</help>
<completionHelp>
<script>sudo ${vyos_op_scripts_dir}/image_manager.py --action list_console_types</script>
</completionHelp>
</properties>
<command>sudo ${vyos_op_scripts_dir}/image_manager.py --action set_console_type --console-type "${4}"</command>
</tagNode>
<node name="image">
<properties>
<help>Set system image parameters</help>
Expand Down
10 changes: 3 additions & 7 deletions python/vyos/system/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,14 +220,8 @@ def get_default(data: dict, root_dir: str = '') -> Union[int, None]:

sublist = list(filter(lambda x: (x.get('version') == image_name and
x.get('console_type') == console_type and
x.get('console_num') == console_num and
x.get('bootmode') == 'normal'),
menu_entries))
# legacy images added with legacy tools omitted 'ttyUSB'; if entry not
# available, default to initial entry of version
if not sublist:
sublist = list(filter(lambda x: x.get('version') == image_name,
menu_entries))

if sublist:
return menu_entries.index(sublist[0])
Expand Down Expand Up @@ -268,7 +262,9 @@ def update_version_list(root_dir: str = '') -> list[dict]:
add = list(set(current_versions) - set(menu_versions))
for ver in add:
last = menu_entries[0].get('version')
new = deepcopy(list(filter(lambda x: x.get('version') == last,
# copy legacy format of menu entries; ignore deprecated ttyUSB
new = deepcopy(list(filter(lambda x: (x.get('version') == last and
x.get('console_type') != 'ttyUSB'),
menu_entries)))
for e in new:
boot_opts = grub.get_boot_opts(ver)
Expand Down
22 changes: 19 additions & 3 deletions src/op_mode/image_installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
from glob import glob
from sys import exit
from os import environ
from os import readlink
from os import getpid, getppid
from typing import Union
from urllib.parse import urlparse
from passlib.hosts import linux_context
Expand Down Expand Up @@ -63,7 +65,7 @@
MSG_INPUT_PASSWORD_CONFIRM: str = 'Please confirm password for the "vyos" user:'
MSG_INPUT_ROOT_SIZE_ALL: str = 'Would you like to use all the free space on the drive?'
MSG_INPUT_ROOT_SIZE_SET: str = 'Please specify the size (in GB) of the root partition (min is 1.5 GB)?'
MSG_INPUT_CONSOLE_TYPE: str = 'What console should be used by default? (K: KVM, S: Serial, U: USB-Serial)?'
MSG_INPUT_CONSOLE_TYPE: str = 'What console should be used by default? (K: KVM, S: Serial)?'
MSG_INPUT_COPY_DATA: str = 'Would you like to copy data to the new image?'
MSG_INPUT_CHOOSE_COPY_DATA: str = 'From which image would you like to save config information?'
MSG_WARN_ISO_SIGN_INVALID: str = 'Signature is not valid. Do you want to continue with installation?'
Expand Down Expand Up @@ -564,6 +566,20 @@ def copy_ssh_host_keys() -> bool:
return False


def console_hint() -> str:
pid = getppid() if 'SUDO_USER' in environ else getpid()
try:
path = readlink(f'/proc/{pid}/fd/1')
except OSError:
path = '/dev/tty'

name = Path(path).name
if name == 'ttyS0':
return 'S'
else:
return 'K'


def cleanup(mounts: list[str] = [], remove_items: list[str] = []) -> None:
"""Clean up after installation

Expand Down Expand Up @@ -660,8 +676,8 @@ def install_image() -> None:
# ask for default console
console_type: str = ask_input(MSG_INPUT_CONSOLE_TYPE,
default='K',
valid_responses=['K', 'S', 'U'])
console_dict: dict[str, str] = {'K': 'tty', 'S': 'ttyS', 'U': 'ttyUSB'}
valid_responses=['K', 'S'])
console_dict: dict[str, str] = {'K': 'tty', 'S': 'ttyS'}

config_boot_list = ['/opt/vyatta/etc/config/config.boot',
'/opt/vyatta/etc/config.boot.default']
Expand Down
28 changes: 26 additions & 2 deletions src/op_mode/image_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from pathlib import Path
from shutil import rmtree
from sys import exit
from typing import Optional
from typing import Optional, Literal, TypeAlias, get_args

from vyos.system import disk, grub, image, compat
from vyos.utils.io import ask_yes_no, select_entry
Expand All @@ -33,6 +33,8 @@
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'

ConsoleType: TypeAlias = Literal['tty', 'ttyS']

def annotate_list(images_list: list[str]) -> list[str]:
"""Annotate list of images with additional info

Expand Down Expand Up @@ -183,13 +185,29 @@ def rename_image(name_old: str, name_new: str) -> None:
exit(f'Unable to rename image "{name_old}" to "{name_new}": {err}')


@compat.grub_cfg_update
def set_console_type(console_type: ConsoleType) -> None:
console_choice = get_args(ConsoleType)
if console_type not in console_choice:
exit(f'console type \'{console_type}\' not available')

grub.set_console_type(console_type)


def list_images() -> None:
"""Print list of available images for CLI hints"""
images_list: list[str] = grub.version_list()
for image_name in images_list:
print(image_name)


def list_console_types() -> None:
"""Print list of console types for CLI hints"""
console_types: list[str] = list(get_args(ConsoleType))
for console_type in console_types:
print(console_type)


def parse_arguments() -> Namespace:
"""Parse arguments

Expand All @@ -198,7 +216,8 @@ def parse_arguments() -> Namespace:
"""
parser: ArgumentParser = ArgumentParser(description='Manage system images')
parser.add_argument('--action',
choices=['delete', 'set', 'rename', 'list'],
choices=['delete', 'set', 'set_console_type',
'rename', 'list', 'list_console_types'],
required=True,
help='action to perform with an image')
parser.add_argument('--no-prompt', action='store_true',
Expand All @@ -208,6 +227,7 @@ def parse_arguments() -> Namespace:
help=
'a name of an image to add, delete, install, rename, or set as default')
parser.add_argument('--image-new-name', help='a new name for image')
parser.add_argument('--console-type', help='console type for boot')
args: Namespace = parser.parse_args()
# Validate arguments
if args.action == 'rename' and (not args.image_name or
Expand All @@ -224,10 +244,14 @@ def parse_arguments() -> Namespace:
delete_image(args.image_name, args.no_prompt)
if args.action == 'set':
set_image(args.image_name)
if args.action == 'set_console_type':
set_console_type(args.console_type)
if args.action == 'rename':
rename_image(args.image_name, args.image_new_name)
if args.action == 'list':
list_images()
if args.action == 'list_console_types':
list_console_types()

exit()

Expand Down
Loading