mirror of
https://github.com/fusion44/blitz_api.git
synced 2026-08-13 11:52:45 +02:00
fix(apps): honour keep_data on uninstall and fix install log name
- uninstall_app dropped input.keep_data; _manage_app always ran the
bonus script with a bare 'off', so the RaspiBlitz script fell back to
an interactive whiptail prompt that hangs the non-interactive API.
Thread keep_data through and pass the explicit
--keep-data/--delete-data flag the scripts expect.
- install.{app_id}.log rendered as install.AppId.MEMPOOL.log because
str-enum formatting includes the class name on Python 3.11+; use
app_id.value here and in the CLN-incompatibility message.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
d5a568da3e
commit
9912ff0bfa
3 changed files with 72 additions and 7 deletions
|
|
@ -253,10 +253,14 @@ class RaspiBlitzApps(AppsBase):
|
|||
yield result
|
||||
|
||||
async def uninstall_app(self, input: AppUninstallInput) -> AppManageResult:
|
||||
async for result in self._manage_app(input.app_id, InstallMode.OFF):
|
||||
async for result in self._manage_app(
|
||||
input.app_id, InstallMode.OFF, keep_data=input.keep_data
|
||||
):
|
||||
yield result
|
||||
|
||||
async def _manage_app(self, app_id: AppId, mode: InstallMode) -> AppManageResult:
|
||||
async def _manage_app(
|
||||
self, app_id: AppId, mode: InstallMode, keep_data: bool = True
|
||||
) -> AppManageResult:
|
||||
"""
|
||||
Manages the installation or uninstallation process for a specified application.
|
||||
|
||||
|
|
@ -315,16 +319,21 @@ class RaspiBlitzApps(AppsBase):
|
|||
state=AppManagementProcessState.FAILURE,
|
||||
message=ErrorMessage(
|
||||
error_code=ApiErrors.APP_INVALID_FOR_PLATFORM,
|
||||
detail=f"{app_id} not available for Core Lightning nodes",
|
||||
detail=f"{app_id.value} not available for Core Lightning nodes",
|
||||
),
|
||||
)
|
||||
)
|
||||
return
|
||||
|
||||
if installing:
|
||||
params = "on"
|
||||
else:
|
||||
# the bonus scripts require an explicit keep/delete flag,
|
||||
# otherwise they fall back to an interactive prompt
|
||||
params = f"off {'--keep-data' if keep_data else '--delete-data'}"
|
||||
|
||||
try:
|
||||
async for data in self.run_bonus_script(
|
||||
app_id, "on" if installing else "off"
|
||||
):
|
||||
async for data in self.run_bonus_script(app_id, params):
|
||||
if isinstance(data, str):
|
||||
yield Ok(
|
||||
AppManageTaskMessage(
|
||||
|
|
@ -377,7 +386,7 @@ class RaspiBlitzApps(AppsBase):
|
|||
return
|
||||
|
||||
try:
|
||||
log_file_name = f"/var/cache/raspiblitz/temp/install.{app_id}.log"
|
||||
log_file_name = f"/var/cache/raspiblitz/temp/install.{app_id.value}.log"
|
||||
stdout_full = ""
|
||||
stderr_full = ""
|
||||
data = {}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ _TEST_ENV_DEFAULTS = {
|
|||
"BAPI_BITCOIND_RPC_PW": "test",
|
||||
"BAPI_BITCOIND_ZMQ_BLOCK_RPC": "hashblock",
|
||||
"BAPI_BITCOIND_ZMQ_BLOCK_PORT": "28332",
|
||||
# must be an existing directory for the raspiblitz apps impl to import
|
||||
"BAPI_RB_SHELL_SCRIPT_PATH": "/tmp",
|
||||
}
|
||||
|
||||
for _key, _value in _TEST_ENV_DEFAULTS.items():
|
||||
|
|
|
|||
54
tests/test_apps_uninstall_keep_data.py
Normal file
54
tests/test_apps_uninstall_keep_data.py
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
"""
|
||||
Regression test: uninstalling an app must honour the keep_data choice.
|
||||
|
||||
_manage_app dropped input.keep_data and always ran the bonus script with a
|
||||
bare "off", so the RaspiBlitz bonus script fell back to an interactive
|
||||
whiptail prompt (which hangs the non-interactive API) instead of the
|
||||
requested keep/delete behaviour.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from app.apps.impl import raspiblitz
|
||||
from app.apps.models import AppId, AppUninstallInput
|
||||
from app.external.result_type.src.result.result import Ok
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def node(monkeypatch):
|
||||
n = raspiblitz.RaspiBlitzApps()
|
||||
|
||||
async def fake_valid(app_id, installing):
|
||||
return Ok(None)
|
||||
|
||||
monkeypatch.setattr(raspiblitz, "_validate_app_id", lambda app_id: Ok(None))
|
||||
monkeypatch.setattr(n, "_valid_installed_status", fake_valid)
|
||||
return n
|
||||
|
||||
|
||||
async def _run_uninstall(node, monkeypatch, keep_data: bool) -> str:
|
||||
captured = {}
|
||||
|
||||
async def fake_bonus(app_id, params):
|
||||
captured["params"] = params
|
||||
return
|
||||
yield # unreachable; makes this an async generator
|
||||
|
||||
monkeypatch.setattr(node, "run_bonus_script", fake_bonus)
|
||||
|
||||
async for _ in node.uninstall_app(
|
||||
AppUninstallInput(app_id=AppId.MEMPOOL, keep_data=keep_data)
|
||||
):
|
||||
pass
|
||||
|
||||
return captured["params"]
|
||||
|
||||
|
||||
async def test_uninstall_delete_data(node, monkeypatch):
|
||||
params = await _run_uninstall(node, monkeypatch, keep_data=False)
|
||||
assert params == "off --delete-data"
|
||||
|
||||
|
||||
async def test_uninstall_keep_data(node, monkeypatch):
|
||||
params = await _run_uninstall(node, monkeypatch, keep_data=True)
|
||||
assert params == "off --keep-data"
|
||||
Loading…
Add table
Add a link
Reference in a new issue