mirror of
https://github.com/Monadical-SAS/cubbi.git
synced 2025-12-20 20:29:06 +00:00
fix(goose): rename mai to mc, add initialization status
This commit is contained in:
@@ -20,16 +20,21 @@ RUN sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' /etc/ssh/
|
|||||||
# Create app directory
|
# Create app directory
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install python dependencies
|
||||||
|
# This is done before copying scripts for better cache management
|
||||||
|
RUN pip install --no-cache-dir goose-ai langfuse
|
||||||
|
|
||||||
# Copy initialization scripts
|
# Copy initialization scripts
|
||||||
COPY mai-init.sh /mai-init.sh
|
COPY mc-init.sh /mc-init.sh
|
||||||
COPY entrypoint.sh /entrypoint.sh
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
COPY mai-driver.yaml /mai-driver.yaml
|
COPY mc-driver.yaml /mc-driver.yaml
|
||||||
|
COPY init-status.sh /init-status.sh
|
||||||
|
|
||||||
# Make scripts executable
|
# Make scripts executable
|
||||||
RUN chmod +x /mai-init.sh /entrypoint.sh
|
RUN chmod +x /mc-init.sh /entrypoint.sh /init-status.sh
|
||||||
|
|
||||||
# Install python dependencies
|
# Set up initialization status check on login
|
||||||
RUN pip install --no-cache-dir goose-ai langfuse
|
RUN echo '[ -x /init-status.sh ] && /init-status.sh' >> /etc/bash.bashrc
|
||||||
|
|
||||||
# Set up environment
|
# Set up environment
|
||||||
ENV PYTHONUNBUFFERED=1
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# Entrypoint script for Goose driver
|
# Entrypoint script for Goose driver
|
||||||
|
|
||||||
# Run the standard initialization script
|
# Run the standard initialization script
|
||||||
/mai-init.sh
|
/mc-init.sh
|
||||||
|
|
||||||
# Start SSH server in the background
|
# Start SSH server in the background
|
||||||
/usr/sbin/sshd
|
/usr/sbin/sshd
|
||||||
|
|||||||
65
drivers/goose/init-status.sh
Normal file
65
drivers/goose/init-status.sh
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Script to check and display initialization status
|
||||||
|
|
||||||
|
# Function to display initialization logs
|
||||||
|
show_init_logs() {
|
||||||
|
if [ -f "/init.log" ]; then
|
||||||
|
echo "Displaying initialization logs:"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
cat /init.log
|
||||||
|
echo "----------------------------------------"
|
||||||
|
else
|
||||||
|
echo "No initialization logs found."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to follow logs until initialization completes
|
||||||
|
follow_init_logs() {
|
||||||
|
if [ ! -f "/init.log" ]; then
|
||||||
|
echo "No initialization logs found."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Initialization is still in progress. Showing logs:"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
tail -f /init.log &
|
||||||
|
tail_pid=$!
|
||||||
|
|
||||||
|
# Check every second if initialization has completed
|
||||||
|
while true; do
|
||||||
|
if [ -f "/init.status" ] && grep -q "INIT_COMPLETE=true" "/init.status"; then
|
||||||
|
kill $tail_pid 2>/dev/null
|
||||||
|
echo "----------------------------------------"
|
||||||
|
echo "Initialization completed."
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if we're in an interactive shell
|
||||||
|
if [ -t 0 ]; then
|
||||||
|
INTERACTIVE=true
|
||||||
|
else
|
||||||
|
INTERACTIVE=false
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check initialization status
|
||||||
|
if [ -f "/init.status" ]; then
|
||||||
|
if grep -q "INIT_COMPLETE=true" "/init.status"; then
|
||||||
|
echo "MC initialization has completed."
|
||||||
|
# No longer prompt to show logs when initialization is complete
|
||||||
|
else
|
||||||
|
echo "MC initialization is still in progress."
|
||||||
|
follow_init_logs
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Cannot determine initialization status."
|
||||||
|
# Ask if user wants to see logs if they exist (only in interactive mode)
|
||||||
|
if [ -f "/init.log" ] && [ "$INTERACTIVE" = true ]; then
|
||||||
|
read -p "Do you want to see initialization logs? (y/n): " show_logs
|
||||||
|
if [[ "$show_logs" =~ ^[Yy] ]]; then
|
||||||
|
show_init_logs
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
@@ -4,7 +4,7 @@ version: 1.0.0
|
|||||||
maintainer: team@monadical.com
|
maintainer: team@monadical.com
|
||||||
|
|
||||||
init:
|
init:
|
||||||
pre_command: /mai-init.sh
|
pre_command: /mc-init.sh
|
||||||
command: /entrypoint.sh
|
command: /entrypoint.sh
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
@@ -1,6 +1,13 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Standardized initialization script for MC drivers
|
# Standardized initialization script for MC drivers
|
||||||
|
|
||||||
|
# Redirect all output to both stdout and the log file
|
||||||
|
exec > >(tee -a /init.log) 2>&1
|
||||||
|
|
||||||
|
# Mark initialization as started
|
||||||
|
echo "=== MC Initialization started at $(date) ==="
|
||||||
|
echo "INIT_COMPLETE=false" > /init.status
|
||||||
|
|
||||||
# Project initialization
|
# Project initialization
|
||||||
if [ -n "$MC_PROJECT_URL" ]; then
|
if [ -n "$MC_PROJECT_URL" ]; then
|
||||||
echo "Initializing project: $MC_PROJECT_URL"
|
echo "Initializing project: $MC_PROJECT_URL"
|
||||||
@@ -52,3 +59,7 @@ if [ -n "$LANGFUSE_SECRET_KEY" ] && [ -n "$LANGFUSE_PUBLIC_KEY" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "MC driver initialization complete"
|
echo "MC driver initialization complete"
|
||||||
|
|
||||||
|
# Mark initialization as complete
|
||||||
|
echo "=== MC Initialization completed at $(date) ==="
|
||||||
|
echo "INIT_COMPLETE=true" > /init.status
|
||||||
@@ -104,7 +104,9 @@ def create_session(
|
|||||||
False, "--no-connect", help="Don't automatically connect to the session"
|
False, "--no-connect", help="Don't automatically connect to the session"
|
||||||
),
|
),
|
||||||
no_mount: bool = typer.Option(
|
no_mount: bool = typer.Option(
|
||||||
False, "--no-mount", help="Don't mount local directory to /app"
|
False,
|
||||||
|
"--no-mount",
|
||||||
|
help="Don't mount local directory to /app (ignored if --project is used)",
|
||||||
),
|
),
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Create a new MC session"""
|
"""Create a new MC session"""
|
||||||
@@ -216,10 +218,28 @@ def connect_session(
|
|||||||
def session_logs(
|
def session_logs(
|
||||||
session_id: str = typer.Argument(..., help="Session ID to get logs from"),
|
session_id: str = typer.Argument(..., help="Session ID to get logs from"),
|
||||||
follow: bool = typer.Option(False, "--follow", "-f", help="Follow log output"),
|
follow: bool = typer.Option(False, "--follow", "-f", help="Follow log output"),
|
||||||
|
init: bool = typer.Option(
|
||||||
|
False, "--init", "-i", help="Show initialization logs instead of container logs"
|
||||||
|
),
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Stream logs from a MC session"""
|
"""Stream logs from a MC session"""
|
||||||
|
if init:
|
||||||
|
# Show initialization logs
|
||||||
if follow:
|
if follow:
|
||||||
console.print(f"Streaming logs from session {session_id}... (Ctrl+C to exit)")
|
console.print(
|
||||||
|
f"Streaming initialization logs from session {session_id}... (Ctrl+C to exit)"
|
||||||
|
)
|
||||||
|
container_manager.get_init_logs(session_id, follow=True)
|
||||||
|
else:
|
||||||
|
logs = container_manager.get_init_logs(session_id)
|
||||||
|
if logs:
|
||||||
|
console.print(logs)
|
||||||
|
else:
|
||||||
|
# Show regular container logs
|
||||||
|
if follow:
|
||||||
|
console.print(
|
||||||
|
f"Streaming logs from session {session_id}... (Ctrl+C to exit)"
|
||||||
|
)
|
||||||
container_manager.get_session_logs(session_id, follow=True)
|
container_manager.get_session_logs(session_id, follow=True)
|
||||||
else:
|
else:
|
||||||
logs = container_manager.get_session_logs(session_id)
|
logs = container_manager.get_session_logs(session_id)
|
||||||
@@ -255,7 +275,9 @@ def quick_create(
|
|||||||
False, "--no-connect", help="Don't automatically connect to the session"
|
False, "--no-connect", help="Don't automatically connect to the session"
|
||||||
),
|
),
|
||||||
no_mount: bool = typer.Option(
|
no_mount: bool = typer.Option(
|
||||||
False, "--no-mount", help="Don't mount local directory to /app"
|
False,
|
||||||
|
"--no-mount",
|
||||||
|
help="Don't mount local directory to /app (ignored if a project is specified)",
|
||||||
),
|
),
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Create a new MC session with a project repository"""
|
"""Create a new MC session with a project repository"""
|
||||||
|
|||||||
@@ -119,6 +119,10 @@ class ContainerManager:
|
|||||||
# Prepare environment variables
|
# Prepare environment variables
|
||||||
env_vars = environment or {}
|
env_vars = environment or {}
|
||||||
|
|
||||||
|
# Add project URL to environment if provided
|
||||||
|
if project:
|
||||||
|
env_vars["MC_PROJECT_URL"] = project
|
||||||
|
|
||||||
# Pull image if needed
|
# Pull image if needed
|
||||||
try:
|
try:
|
||||||
self.client.images.get(driver.image)
|
self.client.images.get(driver.image)
|
||||||
@@ -128,13 +132,19 @@ class ContainerManager:
|
|||||||
|
|
||||||
# Set up volume mounts
|
# Set up volume mounts
|
||||||
volumes = {}
|
volumes = {}
|
||||||
if mount_local:
|
# If project URL is provided, don't mount local directory (will clone into /app)
|
||||||
|
# If no project URL and mount_local is True, mount local directory to /app
|
||||||
|
if not project and mount_local:
|
||||||
# Mount current directory to /app in the container
|
# Mount current directory to /app in the container
|
||||||
import os
|
import os
|
||||||
|
|
||||||
current_dir = os.getcwd()
|
current_dir = os.getcwd()
|
||||||
volumes[current_dir] = {"bind": "/app", "mode": "rw"}
|
volumes[current_dir] = {"bind": "/app", "mode": "rw"}
|
||||||
print(f"Mounting local directory {current_dir} to /app")
|
print(f"Mounting local directory {current_dir} to /app")
|
||||||
|
elif project:
|
||||||
|
print(
|
||||||
|
f"Project URL provided - container will clone {project} into /app during initialization"
|
||||||
|
)
|
||||||
|
|
||||||
# Create container
|
# Create container
|
||||||
container = self.client.containers.create(
|
container = self.client.containers.create(
|
||||||
@@ -220,6 +230,8 @@ class ContainerManager:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
# Execute interactive shell in container
|
# Execute interactive shell in container
|
||||||
|
# The init-status.sh script will automatically show logs if needed
|
||||||
|
print(f"Connecting to session {session_id}...")
|
||||||
os.system(f"docker exec -it {session.container_id} /bin/bash")
|
os.system(f"docker exec -it {session.container_id} /bin/bash")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -345,3 +357,53 @@ class ContainerManager:
|
|||||||
except DockerException as e:
|
except DockerException as e:
|
||||||
print(f"Error getting session logs: {e}")
|
print(f"Error getting session logs: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def get_init_logs(self, session_id: str, follow: bool = False) -> Optional[str]:
|
||||||
|
"""Get initialization logs from a MC session
|
||||||
|
|
||||||
|
Args:
|
||||||
|
session_id: The session ID
|
||||||
|
follow: Whether to follow the logs
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The logs as a string, or None if there was an error
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
sessions = self.list_sessions()
|
||||||
|
for session in sessions:
|
||||||
|
if session.id == session_id and session.container_id:
|
||||||
|
container = self.client.containers.get(session.container_id)
|
||||||
|
|
||||||
|
# Check if initialization is complete
|
||||||
|
init_complete = False
|
||||||
|
try:
|
||||||
|
exit_code, output = container.exec_run(
|
||||||
|
"grep -q 'INIT_COMPLETE=true' /init.status"
|
||||||
|
)
|
||||||
|
init_complete = exit_code == 0
|
||||||
|
except DockerException:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if follow and not init_complete:
|
||||||
|
print(
|
||||||
|
f"Following initialization logs for session {session_id}..."
|
||||||
|
)
|
||||||
|
print("Press Ctrl+C to stop following")
|
||||||
|
container.exec_run(
|
||||||
|
"tail -f /init.log", stream=True, demux=True, tty=True
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
exit_code, output = container.exec_run("cat /init.log")
|
||||||
|
if exit_code == 0:
|
||||||
|
return output.decode()
|
||||||
|
else:
|
||||||
|
print("No initialization logs found")
|
||||||
|
return None
|
||||||
|
|
||||||
|
print(f"Session '{session_id}' not found")
|
||||||
|
return None
|
||||||
|
|
||||||
|
except DockerException as e:
|
||||||
|
print(f"Error getting initialization logs: {e}")
|
||||||
|
return None
|
||||||
|
|||||||
Reference in New Issue
Block a user