fix tui os and backups clear

This commit is contained in:
phact 2025-12-03 11:32:38 -05:00
parent a93da15ae2
commit 19c96140a6
2 changed files with 87 additions and 11 deletions

View file

@ -1012,6 +1012,54 @@ class ContainerManager:
else: else:
yield False, "Some errors occurred during service restart", False yield False, "Some errors occurred during service restart", False
async def clear_opensearch_data_volume(self) -> AsyncIterator[tuple[bool, str]]:
"""Clear opensearch data using a temporary container with proper permissions."""
if not self.is_available():
yield False, "No container runtime available"
return
yield False, "Clearing OpenSearch data volume..."
# Get the absolute path to opensearch-data directory
opensearch_data_path = Path("opensearch-data").absolute()
if not opensearch_data_path.exists():
yield True, "OpenSearch data directory does not exist, skipping"
return
# Use the opensearch container with proper volume mount flags
# :Z flag ensures proper SELinux labeling and UID mapping for rootless containers
cmd = [
"run",
"--rm",
"-v", f"{opensearch_data_path}:/usr/share/opensearch/data:Z",
"langflowai/openrag-opensearch:latest",
"bash", "-c",
"rm -rf /usr/share/opensearch/data/* /usr/share/opensearch/data/.[!.]* && echo 'Cleared successfully'"
]
success, stdout, stderr = await self._run_runtime_command(cmd)
if success and "Cleared successfully" in stdout:
yield True, "OpenSearch data cleared successfully"
else:
# If it fails, try with the base opensearch image
yield False, "Retrying with base OpenSearch image..."
cmd = [
"run",
"--rm",
"-v", f"{opensearch_data_path}:/usr/share/opensearch/data:Z",
"opensearchproject/opensearch:3.0.0",
"bash", "-c",
"rm -rf /usr/share/opensearch/data/* /usr/share/opensearch/data/.[!.]* && echo 'Cleared successfully'"
]
success, stdout, stderr = await self._run_runtime_command(cmd)
if success and "Cleared successfully" in stdout:
yield True, "OpenSearch data cleared successfully"
else:
yield False, f"Failed to clear OpenSearch data: {stderr if stderr else 'Unknown error'}"
async def reset_services(self) -> AsyncIterator[tuple[bool, str]]: async def reset_services(self) -> AsyncIterator[tuple[bool, str]]:
"""Reset all services (stop, remove containers/volumes, clear data) and yield progress updates.""" """Reset all services (stop, remove containers/volumes, clear data) and yield progress updates."""
yield False, "Stopping all services..." yield False, "Stopping all services..."

View file

@ -4,7 +4,7 @@ import asyncio
import re import re
import shutil import shutil
from pathlib import Path from pathlib import Path
from typing import Literal, Any, Optional from typing import Literal, Any, Optional, AsyncIterator
# Define button variant type # Define button variant type
ButtonVariant = Literal["default", "primary", "success", "warning", "error"] ButtonVariant = Literal["default", "primary", "success", "warning", "error"]
@ -478,35 +478,36 @@ class MonitorScreen(Screen):
self.notify("Factory reset cancelled", severity="information") self.notify("Factory reset cancelled", severity="information")
return return
# Clear config, opensearch-data folders, and conversations.json # Clear config, conversations.json, and flow backups first (before stopping containers)
try: try:
config_path = Path("config") config_path = Path("config")
opensearch_data_path = Path("opensearch-data")
conversations_file = Path("conversations.json") conversations_file = Path("conversations.json")
flows_backup_path = Path("flows/backup")
if config_path.exists(): if config_path.exists():
shutil.rmtree(config_path) shutil.rmtree(config_path)
# Recreate empty config directory # Recreate empty config directory
config_path.mkdir(parents=True, exist_ok=True) config_path.mkdir(parents=True, exist_ok=True)
if opensearch_data_path.exists():
shutil.rmtree(opensearch_data_path)
# Recreate empty opensearch-data directory
opensearch_data_path.mkdir(parents=True, exist_ok=True)
if conversations_file.exists(): if conversations_file.exists():
conversations_file.unlink() conversations_file.unlink()
# Delete flow backups if they exist
if flows_backup_path.exists():
shutil.rmtree(flows_backup_path)
# Recreate empty backup directory
flows_backup_path.mkdir(parents=True, exist_ok=True)
except Exception as e: except Exception as e:
self.notify( self.notify(
f"Error clearing folders: {str(e)}", f"Error clearing config: {str(e)}",
severity="error", severity="error",
timeout=10, timeout=10,
) )
return return
# Show command output in modal dialog # Show command output in modal dialog for stopping services and clearing data
command_generator = self.container_manager.reset_services() command_generator = self._factory_reset_with_data_clear()
modal = CommandOutputModal( modal = CommandOutputModal(
"Factory Resetting Services", "Factory Resetting Services",
command_generator, command_generator,
@ -516,6 +517,33 @@ class MonitorScreen(Screen):
finally: finally:
self.operation_in_progress = False self.operation_in_progress = False
async def _factory_reset_with_data_clear(self) -> AsyncIterator[tuple[bool, str]]:
"""Generator that stops services and clears opensearch data."""
# First stop all services
async for success, message in self.container_manager.reset_services():
yield success, message
if not success and "failed" in message.lower():
return
# Now clear opensearch-data using container
yield False, "Clearing OpenSearch data..."
opensearch_data_path = Path("opensearch-data")
if opensearch_data_path.exists():
async for success, message in self.container_manager.clear_opensearch_data_volume():
yield success, message
if not success and "failed" in message.lower():
return
# Recreate empty opensearch-data directory
try:
opensearch_data_path.mkdir(parents=True, exist_ok=True)
yield True, "OpenSearch data directory recreated"
except Exception as e:
yield False, f"Error recreating opensearch-data directory: {e}"
return
yield True, "Factory reset completed successfully"
def _check_flow_backups(self) -> bool: def _check_flow_backups(self) -> bool:
"""Check if there are any flow backups in ./flows/backup directory.""" """Check if there are any flow backups in ./flows/backup directory."""
from pathlib import Path from pathlib import Path