Files
mas/services/backend/tools/bash_tool.py
Mayne0213 e8dc4ff450 FIX(app): improve research_agent information retrieval
- Change execute_host to execute_bash (run kubectl in container)
- Return natural language instead of JSON in Information Query mode
- Add command guide for storage/memory distinction
- Improve to user-friendly response format
2025-12-24 23:22:59 +09:00

133 lines
4.5 KiB
Python

"""
Bash 명령어 실행 도구
"""
import subprocess
import shlex
from langchain_core.tools import tool
from typing import Optional
@tool
def execute_bash(command: str, timeout: int = 30, cwd: Optional[str] = None) -> str:
"""
Execute a bash command in the container.
Args:
command: Bash command to execute
timeout: Command timeout in seconds (default: 30)
cwd: Working directory (default: None)
Returns:
Command output or error message
Examples:
- execute_bash("ls -la /app")
- execute_bash("python --version")
- execute_bash("curl -s http://prometheus:9090/api/v1/query?query=up")
"""
try:
result = subprocess.run(
command,
shell=True,
capture_output=True,
text=True,
timeout=timeout,
cwd=cwd
)
# Combine stdout and stderr
output = result.stdout
if result.stderr:
output += f"\n[STDERR]:\n{result.stderr}"
if result.returncode != 0:
return f"❌ Command failed (exit code {result.returncode}):\n{output}"
return f"✅ Command executed successfully:\n{output}"
except subprocess.TimeoutExpired:
return f"❌ Command timed out after {timeout} seconds"
except Exception as e:
return f"❌ Error executing command: {str(e)}"
@tool
def execute_host(command: str, timeout: int = 30, use_sudo: bool = False) -> str:
"""
Execute command on the HOST system using nsenter (NO SSH needed!).
USE THIS for accessing the host system:
- kubectl commands (Kubernetes cluster management)
- Accessing /home/ubuntu/Projects/ (Git repositories)
- PostgreSQL queries (via psql)
- Git operations on host repositories
- File system operations on host
- ALL host system operations
This works by entering the host's namespaces directly from the container.
Much faster than SSH and no authentication needed!
NOTE: Projects folder is located at /home/ubuntu/Projects/ on oracle-master server.
Args:
command: Command to run on the host system
timeout: Command timeout in seconds (default: 30)
use_sudo: Whether to prepend 'sudo' to the command (default: False)
Returns:
Command output or error message
Examples:
- execute_host("kubectl get pods -n mas", use_sudo=True)
- execute_host("ls -la /home/ubuntu/Projects")
- execute_host("cat /home/ubuntu/Projects/mas/README.md")
- execute_host("cd /home/ubuntu/Projects/mas && git log -5 --oneline")
- execute_host("psql -U bluemayne -h postgresql-primary.postgresql.svc.cluster.local -d postgres -c 'SELECT version()'")
"""
try:
# Use nsenter to enter host namespaces
# -t 1: target PID 1 (init process on host)
# -m: mount namespace
# -u: UTS namespace (hostname)
# -n: network namespace
# -i: IPC namespace
# Run as ubuntu user to avoid git "dubious ownership" errors
# Use 'su ubuntu -c' (without -) to preserve current directory context
# This allows commands to work from SSH initial directory
if use_sudo:
# For sudo commands, run directly with sudo
# Use shlex.quote to safely quote the command while preserving shell expansion
nsenter_command = f"nsenter -t 1 -m -u -n -i -- sh -c {shlex.quote(f'sudo {command}')}"
else:
# For regular commands, run as ubuntu user
# Use 'su ubuntu -c' (not 'su - ubuntu -c') to preserve current directory
# This matches SSH behavior where you start from the initial directory
nsenter_command = f"nsenter -t 1 -m -u -n -i -- su ubuntu -c {shlex.quote(command)}"
result = subprocess.run(
nsenter_command,
shell=True,
capture_output=True,
text=True,
timeout=timeout
)
# Combine stdout and stderr
output = result.stdout
if result.stderr:
output += f"\n[STDERR]:\n{result.stderr}"
if result.returncode != 0:
return f"❌ Host command failed (exit code {result.returncode}):\n{output}"
return f"✅ Host command executed successfully:\n{output}"
except subprocess.TimeoutExpired:
return f"❌ Host command timed out after {timeout} seconds"
except Exception as e:
return f"❌ Error executing host command: {str(e)}"
# Export both tools
bash_tools = [execute_bash, execute_host]