summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Breunig <christian@breunig.cc>2026-07-22 21:34:02 +0200
committerGitHub <noreply@github.com>2026-07-22 21:34:02 +0200
commitbf2b506e45b574b18cf8be5dfd2c8e33ac999732 (patch)
tree00ff79613a63b369109039e91aac0fdb8ea88ba3 /src
parent9a02328fd8f68f24a66c9cb559219541508f5f9d (diff)
parentb12a8c5aef72c0adaca197c98f5dfa9cbb8a73d2 (diff)
downloadvyos-1x-bf2b506e45b574b18cf8be5dfd2c8e33ac999732.tar.gz
vyos-1x-bf2b506e45b574b18cf8be5dfd2c8e33ac999732.zip
Merge pull request #5344 from alexandr-san4ez/T9021-rolling
image: T9021: Save bash history during image upgrade
Diffstat (limited to 'src')
-rwxr-xr-xsrc/op_mode/image_installer.py109
1 files changed, 93 insertions, 16 deletions
diff --git a/src/op_mode/image_installer.py b/src/op_mode/image_installer.py
index ea5aed088..4e7a70893 100755
--- a/src/op_mode/image_installer.py
+++ b/src/op_mode/image_installer.py
@@ -812,6 +812,18 @@ def copy_ssh_known_hosts() -> bool:
return known_hosts_files and ask_yes_no(msg, default=True)
+def copy_bash_history() -> bool:
+ """Ask user to copy bash history
+
+ Returns:
+ bool: user's decision
+ """
+
+ history_files = get_bash_history_files()
+ msg = 'Would you like to copy bash history?'
+ return bool(history_files) and ask_yes_no(msg, default=False)
+
+
def console_hint() -> str:
pid = getppid() if 'SUDO_USER' in environ else getpid()
try:
@@ -1116,36 +1128,62 @@ def install_image() -> None:
exit(1)
-def get_known_hosts_files(for_root=True, for_users=True) -> list:
- """Collect all existing `known_hosts` files for root and/or users under /home"""
+def _get_users_relative_paths(
+ relative_paths: list, for_root=True, for_users=True
+) -> list:
+ """
+ Retrieve a list of file paths based on given relative paths, optionally
+ including files from the root directory and user home directories.
+ """
files = []
if for_root:
- base_files = ('/root/.ssh/known_hosts', '/etc/ssh/ssh_known_hosts')
- for file_path in base_files:
- root_known_hosts = Path(file_path)
- if root_known_hosts.exists():
- files.append(root_known_hosts)
+ for relative_path in relative_paths:
+ file_path = Path('/root') / relative_path
+ if file_path.exists():
+ files.append(file_path)
if for_users: # for each non-system user
for user in get_local_users():
home_dir = Path(get_user_home_dir(user))
if home_dir.exists():
- known_hosts = home_dir / '.ssh' / 'known_hosts'
- if known_hosts.exists():
- files.append(known_hosts)
+ for relative_path in relative_paths:
+ file_path = home_dir / relative_path
+ if file_path.exists():
+ files.append(file_path)
+
+ return [file_path.absolute() for file_path in files]
+
+
+def get_known_hosts_files(for_root=True, for_users=True) -> list:
+ """Collect all existing `known_hosts` files for root and/or users under /home"""
+
+ files = _get_users_relative_paths(
+ ['.ssh/known_hosts'],
+ for_root=for_root,
+ for_users=for_users,
+ )
+
+ if for_root:
+ # Add also additional global 'ssh_known_hosts' file
+ root_known_hosts = Path('/etc/ssh/ssh_known_hosts')
+ if root_known_hosts.exists():
+ files.append(root_known_hosts)
return files
+def _mkdir_and_copy_file(source_path: Path, target_path: Path):
+ """Create the target directory if it doesn't exist and copy a file from source to target"""
+
+ target_path.parent.mkdir(parents=True, exist_ok=True)
+ copy(source_path, target_path)
+
+
def migrate_known_hosts(target_dir: str):
"""Copy `known_hosts` for root and all users to the new image directory"""
- def _mkdir_and_copy_file(known_hosts_file, target_known_hosts):
- target_known_hosts.parent.mkdir(parents=True, exist_ok=True)
- copy(known_hosts_file, target_known_hosts)
-
# Copy root only files using default path
known_hosts_files = get_known_hosts_files(for_root=True, for_users=False)
for known_hosts_file in known_hosts_files:
@@ -1165,6 +1203,36 @@ def migrate_known_hosts(target_dir: str):
_mkdir_and_copy_file(known_hosts_file, target_known_hosts)
+def get_bash_history_files(for_root=True, for_users=True) -> list:
+ """Collect all existing `.bash_history` files for root and/or users under /home"""
+
+ return _get_users_relative_paths(
+ ['.bash_history'],
+ for_root=for_root,
+ for_users=for_users,
+ )
+
+
+def migrate_bash_history(target_dir: str):
+ """Copy `.bash_history` for root and all users to the new image directory"""
+
+ # Copy root's history using its default path
+ history_files = get_bash_history_files(for_root=True, for_users=False)
+ for history_file in history_files:
+ target_history = Path(f'{target_dir}{history_file}')
+ _mkdir_and_copy_file(history_file, target_history)
+
+ # Preserve non-root users' bash history the same way known_hosts
+ # is backed up: under /var/.users_backups/{user}, since regular
+ # user home directories are not otherwise migrated.
+ history_files = get_bash_history_files(for_root=False, for_users=True)
+ for history_file in history_files:
+ username = history_file.parent.name
+ base_dir = Path(f'{target_dir}/var/.users_backups/{username}')
+ target_history = base_dir / '.bash_history'
+ _mkdir_and_copy_file(history_file, target_history)
+
+
@compat.grub_cfg_update
def add_image(image_path: str, vrf: str = None, username: str = '',
password: str = '', no_prompt: bool = False, force: bool = False) -> None:
@@ -1290,19 +1358,28 @@ def add_image(image_path: str, vrf: str = None, username: str = '',
chmod_2775(target_config_dir)
Path(f'{target_config_dir}/.vyatta_config').touch()
- target_ssh_dir: str = f'{root_dir}/boot/{image_name}/rw/etc/ssh/'
+ # Default persistence directory
+ target_persist_dir: str = f'{root_dir}/boot/{image_name}/rw'
+
if no_prompt or copy_ssh_host_keys():
print('Copying SSH host keys')
+ target_ssh_dir: str = f'{target_persist_dir}/etc/ssh/'
Path(target_ssh_dir).mkdir(parents=True)
host_keys: list[str] = glob('/etc/ssh/ssh_host*')
for host_key in host_keys:
copy(host_key, target_ssh_dir)
- target_ssh_known_hosts_dir: str = f'{root_dir}/boot/{image_name}/rw'
if no_prompt or copy_ssh_known_hosts():
print('Copying SSH known_hosts files')
+ target_ssh_known_hosts_dir: str = target_persist_dir
migrate_known_hosts(target_ssh_known_hosts_dir)
+ # By default we should disable auto-copy under '--no-prompt' mode
+ if no_prompt is False and copy_bash_history():
+ print('Copying bash history')
+ target_history_dir: str = target_persist_dir
+ migrate_bash_history(target_history_dir)
+
# copy system image and kernel files
print('Copying system image files')
for file in Path(f'{DIR_ISO_MOUNT}/live').iterdir():