mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-11-01 10:22:08 +00:00
feat(oci): the menu shows the saved records being brought up to date.
This commit is contained in:
+2
-1
@@ -7919,5 +7919,6 @@
|
||||
"⚠ Disk data will NOT be erased.": "⚠ Los datos del disco NO se borrarán.",
|
||||
"⚠ Disk will be unmounted and removed from /etc/fstab.": "⚠ El disco se desmontará y se eliminará de /etc/fstab.",
|
||||
"⚠ The /etc/fstab entry will be removed.": "⚠ Se eliminará la entrada /etc/fstab.",
|
||||
"⚠ The disk will be unmounted.": "⚠ El disco se desmontará."
|
||||
"⚠ The disk will be unmounted.": "⚠ El disco se desmontará.",
|
||||
"Updating the copy of the record...": "Actualizando la copia del registro..."
|
||||
}
|
||||
|
||||
@@ -439,7 +439,7 @@ def install_template(ui, template: dict[str, Any], identifier: str, mode: str) -
|
||||
return None
|
||||
if result:
|
||||
from .management import carry_records
|
||||
carry_records(PROJECT_ROOT)
|
||||
carry_records(PROJECT_ROOT, shown=True)
|
||||
vmids = {int(v) for v in [result.get("vmid"), *(result.get("stack_vmids") or {}).values()] if v}
|
||||
_, removed = images.offer_removal(ui, sorted(vmids))
|
||||
_print_installation_summary(result, removed)
|
||||
@@ -461,7 +461,7 @@ def _rclone_mount(catalog: Catalog, ui) -> None:
|
||||
result = run_remote_rclone_mount(PROJECT_ROOT, template, deployment, "auto")
|
||||
if result:
|
||||
from .management import carry_records
|
||||
carry_records(PROJECT_ROOT)
|
||||
carry_records(PROJECT_ROOT, shown=True)
|
||||
console.msg_ok(f"Remote: {result['remote']}:")
|
||||
console.msg_ok(f"{translate('Read/write')}: {result['read_write_path']}")
|
||||
console.msg_ok(f"{translate('Read-only')}: {result['read_only_path']}")
|
||||
@@ -562,6 +562,8 @@ def interactive(catalog: Catalog) -> int:
|
||||
f"{translate('All applications')} ({len(applications)})")
|
||||
elif selection == "manage":
|
||||
from .management import interactive_management
|
||||
console.show_logo()
|
||||
console.msg_title(translate("Manage installed OCI applications"))
|
||||
interactive_management(PROJECT_ROOT, ui)
|
||||
elif selection == "custom":
|
||||
from .custom import explore
|
||||
|
||||
@@ -125,22 +125,29 @@ def _run_lifecycle(command, title):
|
||||
console.msg_title(title)
|
||||
environment = dict(os.environ, OCI_SPINNER='1' if sys.stdout.isatty() else '0')
|
||||
completed = subprocess.run(command, env=environment, check=False)
|
||||
carry_records(images.PROJECT_ROOT)
|
||||
carry_records(images.PROJECT_ROOT, shown=True)
|
||||
if sys.stdin.isatty():
|
||||
console.wait_for_enter(translate('Press Enter to return to the menu...'))
|
||||
return completed.returncode == 0
|
||||
|
||||
|
||||
def carry_records(project, mount_stopped=True, vmids=None, verify=False):
|
||||
def carry_records(project, mount_stopped=True, vmids=None, verify=False, shown=False):
|
||||
"""Leave inside each container the copy of its record that a restore on
|
||||
another host needs. It is refreshed after every operation. Returns what
|
||||
was found for each container."""
|
||||
was found for each container. Every installed application is looked at,
|
||||
which takes a while with many of them: `shown` says so on the screen."""
|
||||
from . import console
|
||||
sys.path.insert(0, str(project / 'remote'))
|
||||
if shown:
|
||||
console.msg_info(translate('Updating the copy of the record...'))
|
||||
try:
|
||||
import oci_carried_record
|
||||
return oci_carried_record.sync(oci_carried_record.instances.ROOT, vmids, mount_stopped, verify)
|
||||
except (ImportError, OSError, ValueError, RuntimeError, subprocess.SubprocessError):
|
||||
return {}
|
||||
finally:
|
||||
if shown:
|
||||
console.stop_spinner()
|
||||
|
||||
|
||||
def recover_automatically(project):
|
||||
@@ -245,7 +252,7 @@ def _interactive_management(project, ui):
|
||||
_clean_orphans(project)
|
||||
recover_automatically(project)
|
||||
offer_recovery(project, ui)
|
||||
carry_records(project, mount_stopped=False)
|
||||
carry_records(project, mount_stopped=False, shown=True)
|
||||
rows = saved_inventory(project)
|
||||
if not rows:
|
||||
ui.message(translate('No registered OCI containers are available for selection on this host.'), translate('OCI management'))
|
||||
|
||||
@@ -77,5 +77,43 @@ class CarriedRecordTests(unittest.TestCase):
|
||||
self.assertEqual(carried.mapped_root(custom), (200000, 300000))
|
||||
|
||||
|
||||
|
||||
class ShownSyncTests(unittest.TestCase):
|
||||
"""Every installed application is looked at after an operation, which
|
||||
takes a while with many of them: the screen says what is being done."""
|
||||
|
||||
def setUp(self):
|
||||
sys.path.insert(0, str(ROOT / "src"))
|
||||
from proxmenux_oci import console, management
|
||||
self.console, self.management = console, management
|
||||
|
||||
def run_sync(self, outcome, **options):
|
||||
from unittest.mock import patch
|
||||
events = []
|
||||
with patch.object(self.console, "msg_info", side_effect=lambda text: events.append(("info", text))), \
|
||||
patch.object(self.console, "stop_spinner", side_effect=lambda *a, **k: events.append(("stop",))), \
|
||||
patch.object(carried, "sync", side_effect=outcome) as sync:
|
||||
result = self.management.carry_records(ROOT, **options)
|
||||
return result, events, sync
|
||||
|
||||
def test_the_sync_is_announced_and_the_notice_is_cleared(self):
|
||||
result, events, sync = self.run_sync(lambda *args: {120: "current"}, shown=True)
|
||||
self.assertEqual(result, {120: "current"})
|
||||
self.assertEqual([event[0] for event in events], ["info", "stop"])
|
||||
self.assertEqual(events[0][1], "Updating the copy of the record...")
|
||||
sync.assert_called_once()
|
||||
|
||||
def test_the_notice_is_cleared_when_the_sync_fails(self):
|
||||
result, events, _sync = self.run_sync(OSError("registry"), shown=True)
|
||||
self.assertEqual(result, {})
|
||||
self.assertEqual([event[0] for event in events], ["info", "stop"])
|
||||
|
||||
def test_nothing_is_shown_unless_asked(self):
|
||||
_result, events, sync = self.run_sync(lambda *args: {}, vmids=[120], verify=True)
|
||||
self.assertEqual(events, [])
|
||||
self.assertEqual(sync.call_args.args[1:], ([120], True, True))
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user