Skip to content

Commit 504c532

Browse files
committed
feat: Add Docker image management endpoints for rebuilding and status checking
1 parent 4362d54 commit 504c532

File tree

1 file changed

+88
-3
lines changed

1 file changed

+88
-3
lines changed

backend/main.py

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,24 @@ async def stream_generate_and_run(user_query: str, model_name: str):
134134
image_tag = "robot-test-runner:latest"
135135
dockerfile_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'robot_tests')
136136

137-
# Stage 2a: Building Docker Image
138-
yield f"data: {json.dumps({'stage': 'execution', 'status': 'running', 'message': 'Building container image for test execution...'})}\n\n"
139-
client.images.build(path=dockerfile_path, tag=image_tag, rm=True)
137+
# Stage 2a: Check and Build Docker Image (only if needed)
138+
try:
139+
# Check if the image already exists
140+
existing_image = client.images.get(image_tag)
141+
logging.info(f"Docker image '{image_tag}' already exists. Skipping build.")
142+
yield f"data: {json.dumps({'stage': 'execution', 'status': 'running', 'message': 'Using existing container image for test execution...'})}\n\n"
143+
except docker.errors.ImageNotFound:
144+
# Image doesn't exist, need to build it
145+
logging.info(f"Docker image '{image_tag}' not found. Building new image.")
146+
yield f"data: {json.dumps({'stage': 'execution', 'status': 'running', 'message': 'Building container image for test execution (first time only)...'})}\n\n"
147+
try:
148+
client.images.build(path=dockerfile_path, tag=image_tag, rm=True)
149+
logging.info(f"Successfully built Docker image '{image_tag}'.")
150+
yield f"data: {json.dumps({'stage': 'execution', 'status': 'running', 'message': 'Container image built successfully!'})}\n\n"
151+
except docker.errors.BuildError as build_err:
152+
logging.error(f"Failed to build Docker image: {build_err}")
153+
yield f"data: {json.dumps({'stage': 'execution', 'status': 'error', 'message': f'Docker image build failed: {build_err}'})}\n\n"
154+
return
140155

141156
# Stage 2b: Running Docker Container
142157
yield f"data: {json.dumps({'stage': 'execution', 'status': 'running', 'message': 'Executing test inside the container...'})}\n\n"
@@ -219,6 +234,76 @@ async def generate_and_run_streaming(query: Query):
219234

220235
return StreamingResponse(stream_generate_and_run(user_query, model_name), media_type="text/event-stream")
221236

237+
@app.post('/rebuild-docker-image')
238+
async def rebuild_docker_image():
239+
"""Endpoint to force rebuild the Docker image when needed."""
240+
try:
241+
client = docker.from_env()
242+
image_tag = "robot-test-runner:latest"
243+
dockerfile_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'robot_tests')
244+
245+
# Remove existing image if it exists
246+
try:
247+
existing_image = client.images.get(image_tag)
248+
client.images.remove(image=image_tag, force=True)
249+
logging.info(f"Removed existing Docker image '{image_tag}'.")
250+
except docker.errors.ImageNotFound:
251+
logging.info(f"No existing Docker image '{image_tag}' to remove.")
252+
253+
# Build new image
254+
logging.info(f"Building new Docker image '{image_tag}'.")
255+
client.images.build(path=dockerfile_path, tag=image_tag, rm=True)
256+
logging.info(f"Successfully rebuilt Docker image '{image_tag}'.")
257+
258+
return {"status": "success", "message": f"Docker image '{image_tag}' rebuilt successfully."}
259+
260+
except docker.errors.DockerException as e:
261+
error_message = f"Docker error: {e}"
262+
logging.error(f"Failed to rebuild Docker image: {e}")
263+
raise HTTPException(status_code=500, detail=error_message)
264+
except Exception as e:
265+
error_message = f"Unexpected error: {e}"
266+
logging.error(f"Unexpected error during Docker image rebuild: {e}")
267+
raise HTTPException(status_code=500, detail=error_message)
268+
269+
@app.get('/docker-status')
270+
async def docker_status():
271+
"""Endpoint to check Docker status and image availability."""
272+
try:
273+
client = docker.from_env()
274+
client.ping()
275+
276+
image_tag = "robot-test-runner:latest"
277+
try:
278+
image = client.images.get(image_tag)
279+
image_info = {
280+
"exists": True,
281+
"id": image.id,
282+
"created": image.attrs.get('Created', 'Unknown'),
283+
"size": f"{image.attrs.get('Size', 0) / (1024*1024):.1f} MB"
284+
}
285+
except docker.errors.ImageNotFound:
286+
image_info = {"exists": False}
287+
288+
return {
289+
"status": "success",
290+
"docker_available": True,
291+
"image": image_info
292+
}
293+
294+
except docker.errors.DockerException as e:
295+
return {
296+
"status": "error",
297+
"docker_available": False,
298+
"error": str(e)
299+
}
300+
except Exception as e:
301+
return {
302+
"status": "error",
303+
"docker_available": False,
304+
"error": f"Unexpected error: {e}"
305+
}
306+
222307
# --- Static Files and Root Endpoint ---
223308
FRONTEND_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "frontend")
224309
ROBOT_TESTS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "robot_tests")

0 commit comments

Comments
 (0)