mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-11-01 10:22:08 +00:00
open Manage straight to the list and simplify registry rows
This commit is contained in:
@@ -42,13 +42,13 @@ class SelectionSetupWording(TestCase):
|
||||
shutil=SimpleNamespace(which=lambda _: '/fake/pct'), saved_inventory=lambda _: [],
|
||||
_clean_orphans=lambda project: None,
|
||||
recover_automatically=lambda project: None, offer_recovery=lambda project, ui: None,
|
||||
carry_records=lambda project, **options: {},
|
||||
carry_records=lambda project, **options: {}, _records_unread=lambda project: False,
|
||||
translate=lambda s: s)
|
||||
fn(Path('/fixture'), ui)
|
||||
ui.message.assert_called_once_with(EMPTY, 'OCI management')
|
||||
ui.choose.assert_not_called()
|
||||
|
||||
def _menu(self, inventories, selections):
|
||||
def _menu(self, inventories, selections, unread=True):
|
||||
rows = iter(inventories)
|
||||
ui = SimpleNamespace(message=Mock(), choose=Mock(side_effect=selections))
|
||||
refresh = Mock(return_value={})
|
||||
@@ -57,7 +57,8 @@ class SelectionSetupWording(TestCase):
|
||||
shutil=SimpleNamespace(which=lambda _: '/fake/pct'), saved_inventory=lambda _: next(rows),
|
||||
_clean_orphans=lambda project: None,
|
||||
recover_automatically=lambda project: None, offer_recovery=lambda project, ui: None,
|
||||
carry_records=refresh, manage_instance=manage, menu_size=lambda: 10,
|
||||
carry_records=refresh, _records_unread=lambda project: unread,
|
||||
manage_instance=manage, menu_size=lambda: 10,
|
||||
STATUS_LABELS={}, translate=lambda s: s)
|
||||
fn(Path('/fixture'), ui)
|
||||
return ui, refresh, manage
|
||||
@@ -67,7 +68,14 @@ class SelectionSetupWording(TestCase):
|
||||
ui, refresh, manage = self._menu([[row], [row]], ['101', None])
|
||||
self.assertEqual(ui.choose.call_count, 2)
|
||||
manage.assert_called_once()
|
||||
refresh.assert_called_once_with(Path('/fixture'), mount_stopped=False, shown=True)
|
||||
refresh.assert_called_once_with(Path('/fixture'), mount_stopped=False, shown=True,
|
||||
heading='Manage installed OCI applications')
|
||||
|
||||
def test_the_list_opens_without_the_sync_notice_once_every_configuration_is_cached(self):
|
||||
row = {'vmid': 101, 'title': 'Jellyfin', 'hostname': 'jellyfin', 'status': 'installed', 'image': 'jellyfin/jellyfin'}
|
||||
_, refresh, _ = self._menu([[row]], [None], unread=False)
|
||||
refresh.assert_called_once_with(Path('/fixture'), mount_stopped=False, shown=False,
|
||||
heading='Manage installed OCI applications')
|
||||
|
||||
def test_removing_the_last_application_returns_without_a_message(self):
|
||||
row = {'vmid': 101, 'title': 'Jellyfin', 'hostname': 'jellyfin', 'status': 'installed', 'image': 'jellyfin/jellyfin'}
|
||||
|
||||
@@ -50,6 +50,7 @@ jobs:
|
||||
PYTHONDONTWRITEBYTECODE: '1'
|
||||
run: |
|
||||
python3 -m unittest discover -s oci/tests -p test_modify_menu.py -v
|
||||
python3 -m unittest discover -s oci/tests -p test_manage_sync_notice.py -v
|
||||
python3 -m unittest discover -s oci/tests -p test_recreation.py -v
|
||||
python3 -m unittest discover -s oci/tests -p test_shared_directories.py -v
|
||||
python3 -m unittest discover -s oci/tests -p 'test_wizard*.py' -v
|
||||
|
||||
@@ -578,8 +578,6 @@ 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 == "registries":
|
||||
from .registry_accounts import open_registry_accounts
|
||||
|
||||
@@ -132,7 +132,7 @@ def _run_lifecycle(command, title):
|
||||
return completed.returncode == 0
|
||||
|
||||
|
||||
def carry_records(project, mount_stopped=True, vmids=None, verify=False, shown=False):
|
||||
def carry_records(project, mount_stopped=True, vmids=None, verify=False, shown=False, heading=None):
|
||||
"""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. Every installed application is looked at,
|
||||
@@ -140,6 +140,9 @@ def carry_records(project, mount_stopped=True, vmids=None, verify=False, shown=F
|
||||
from . import console
|
||||
sys.path.insert(0, str(project / 'remote'))
|
||||
if shown:
|
||||
if heading:
|
||||
console.show_logo()
|
||||
console.msg_title(heading)
|
||||
console.msg_info(translate('Updating the copy of the record...'))
|
||||
try:
|
||||
import oci_carried_record
|
||||
@@ -234,6 +237,17 @@ def interactive_management(project, ui):
|
||||
ui.message(translate('OCI management could not be completed. Check the backend status; no additional cleanup has been authorized.'), translate('OCI management'))
|
||||
|
||||
|
||||
def _records_unread(project):
|
||||
"""Whether an installed application has no cached configuration yet; only
|
||||
then does the first sync read every container and take a while."""
|
||||
sys.path.insert(0, str(project / 'remote'))
|
||||
import oci_carried_record as carried
|
||||
return any(not (carried.instances.location(carried.instances.ROOT, row['vmid']).parent
|
||||
/ carried.CONFIG_CACHE).exists()
|
||||
for row in saved_inventory(project)
|
||||
if row.get('status') == 'installed' and not row.get('pending'))
|
||||
|
||||
|
||||
def _clean_orphans(project):
|
||||
"""Remove, silently, what is left of containers that exist on no node of the cluster."""
|
||||
sys.path.insert(0, str(project / 'remote'))
|
||||
@@ -253,7 +267,8 @@ def _interactive_management(project, ui):
|
||||
_clean_orphans(project)
|
||||
recover_automatically(project)
|
||||
offer_recovery(project, ui)
|
||||
carry_records(project, mount_stopped=False, shown=True)
|
||||
carry_records(project, mount_stopped=False, shown=_records_unread(project),
|
||||
heading=translate('Manage installed OCI applications'))
|
||||
# After each operation the list is shown again. Every operation leaves
|
||||
# the copies of the records up to date, so they are not all refreshed again.
|
||||
first = True
|
||||
|
||||
@@ -166,7 +166,7 @@ def registry_accounts_menu(ui, engine=ENGINE_ROOT, auth=None):
|
||||
return
|
||||
try:
|
||||
options = [('add', translate('Sign in to a registry'))]
|
||||
options += [(f'account-{index}', f"{row['registry']:<28} {row['account'] or row['method']} [{translate('saved')}]")
|
||||
options += [(f'account-{index}', f"{row['registry']:<28} [{translate('saved')}]")
|
||||
for index, row in enumerate(rows)]
|
||||
options += [('storage', translate('Credential storage and access'))]
|
||||
count = translate('{count} saved account.') if len(rows) == 1 else translate('{count} saved accounts.')
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
"""Opening Manage shows the sync notice only while some configuration is still unread."""
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT / 'src'))
|
||||
sys.path.insert(0, str(ROOT / 'remote'))
|
||||
|
||||
from proxmenux_oci import management
|
||||
import oci_carried_record as carried
|
||||
|
||||
|
||||
class ManageSyncNoticeTests(unittest.TestCase):
|
||||
def test_notice_only_while_an_installed_application_has_no_cache(self):
|
||||
rows = [{'vmid': 101, 'status': 'installed', 'pending': False},
|
||||
{'vmid': 102, 'status': 'installed', 'pending': True},
|
||||
{'vmid': 103, 'status': 'failed', 'pending': False}]
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = Path(directory)
|
||||
with patch.object(carried.instances, 'ROOT', root), \
|
||||
patch.object(management, 'saved_inventory', return_value=rows):
|
||||
self.assertTrue(management._records_unread(ROOT))
|
||||
cache = carried.instances.location(root, 101).parent / carried.CONFIG_CACHE
|
||||
cache.parent.mkdir(parents=True)
|
||||
cache.write_text('{}')
|
||||
# The pending and failed applications are never cached by the sync.
|
||||
self.assertFalse(management._records_unread(ROOT))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user