Skip to main content
Glama
templates.py5.39 kB
"""Template operation handlers.""" import os import json import base64 import tarfile import io from pathlib import Path from ludus_mcp.core.client import LudusAPIClient from ludus_mcp.schemas.templates import Template, TemplateApply, TemplateAdd, TemplateBuild from ludus_mcp.utils.logging import get_logger logger = get_logger(__name__) class TemplateHandler: """Handler for template operations.""" def __init__(self, client: LudusAPIClient) -> None: """Initialize the template handler.""" self.client = client async def list_templates(self, user_id: str | None = None) -> list[Template]: """List available templates.""" logger.debug("Listing available templates") results = await self.client.list_templates() return [Template(**r) for r in results] async def apply_template( self, range_id: str, host_id: str, data: TemplateApply ) -> dict: """Apply a template to a host.""" logger.debug( f"Applying template {data.template_name} to host {host_id} in range {range_id}" ) return await self.client.apply_template( range_id, host_id, data.template_name, data.parameters ) async def add_template( self, data: TemplateAdd, user_id: str | None = None ) -> dict: """Add a new template to Ludus. Args: data: Template add configuration user_id: Optional user ID (admin only) Returns: API response with add status """ logger.info(f"Adding template from directory: {data.directory}") # Verify directory exists template_dir = Path(data.directory) if not template_dir.exists(): raise ValueError(f"Template directory does not exist: {data.directory}") if not template_dir.is_dir(): raise ValueError(f"Path is not a directory: {data.directory}") # Create template payload with directory structure # The Ludus API expects either: # 1. A tar archive (base64 encoded) # 2. A directory structure as JSON template_payload = { "directory": str(template_dir.absolute()), "force": data.force } # If we need to send files, tar them up if data.include_files: tar_data = self._create_tar_archive(template_dir) template_payload["archive"] = base64.b64encode(tar_data).decode('utf-8') template_payload["archive_format"] = "tar.gz" return await self.client.add_template(template_payload, user_id) async def build_template( self, data: TemplateBuild, user_id: str | None = None ) -> dict: """Build a template. Args: data: Template build configuration user_id: Optional user ID (admin only) Returns: API response with build status """ template_name = data.template_name if data.template_name != "all" else None logger.info(f"Building template: {data.template_name} (parallel={data.parallel})") return await self.client.build_template( template_name=template_name, parallel=data.parallel, user_id=user_id ) async def delete_template( self, template_name: str, user_id: str | None = None ) -> dict: """Delete a template. Args: template_name: Name of template to delete user_id: Optional user ID (admin only) Returns: API response with delete status """ logger.info(f"Deleting template: {template_name}") return await self.client.delete_template(template_name, user_id) async def get_template_status(self, user_id: str | None = None) -> dict: """Get template build status. Args: user_id: Optional user ID (admin only) Returns: Template build status information """ logger.debug("Getting template build status") return await self.client.get_template_status(user_id) async def get_template_logs( self, user_id: str | None = None, tail: int | None = None ) -> str: """Get template build logs. Args: user_id: Optional user ID (admin only) tail: Number of lines to tail (optional) Returns: Template build logs """ logger.debug("Getting template build logs") return await self.client.get_template_logs(user_id, tail) async def abort_template_operation(self, user_id: str | None = None) -> dict: """Abort template build operation. Args: user_id: Optional user ID (admin only) Returns: API response """ logger.info("Aborting template operation") return await self.client.abort_template_operation(user_id) def _create_tar_archive(self, directory: Path) -> bytes: """Create a tar.gz archive of a directory. Args: directory: Path to directory to archive Returns: Bytes of tar.gz archive """ tar_buffer = io.BytesIO() with tarfile.open(fileobj=tar_buffer, mode='w:gz') as tar: tar.add(str(directory), arcname=directory.name) tar_buffer.seek(0) return tar_buffer.read()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/tjnull/Ludus-FastMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server