feat: implement template-based documentation generation system for Proxmox
Some checks failed
CI/CD Pipeline / Run Tests (push) Has been cancelled
CI/CD Pipeline / Security Scanning (push) Has been cancelled
CI/CD Pipeline / Build and Push Docker Images (api) (push) Has been cancelled
CI/CD Pipeline / Build and Push Docker Images (chat) (push) Has been cancelled
CI/CD Pipeline / Build and Push Docker Images (frontend) (push) Has been cancelled
CI/CD Pipeline / Build and Push Docker Images (worker) (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / Generate Documentation (push) Has started running
CI/CD Pipeline / Lint Code (push) Has started running

Implement a scalable system for automatic documentation generation from infrastructure
systems, preventing LLM context overload through template-driven sectioning.

**New Features:**

1. **YAML Template System** (`templates/documentation/proxmox.yaml`)
   - Define documentation sections independently
   - Specify data requirements per section
   - Configure prompts, generation settings, and scheduling
   - Prevents LLM context overflow by sectioning data

2. **Template-Based Generator** (`src/datacenter_docs/generators/template_generator.py`)
   - Load and parse YAML templates
   - Generate documentation sections independently
   - Extract only required data for each section
   - Save sections individually to files and database
   - Combine sections with table of contents

3. **Celery Tasks** (`src/datacenter_docs/workers/documentation_tasks.py`)
   - `collect_and_generate_docs`: Collect data and generate docs
   - `generate_proxmox_docs`: Scheduled Proxmox documentation (daily at 2 AM)
   - `generate_all_docs`: Generate docs for all systems in parallel
   - `index_generated_docs`: Index generated docs into vector store for RAG
   - `full_docs_pipeline`: Complete workflow (collect → generate → index)

4. **Scheduled Jobs** (updated `celery_app.py`)
   - Daily Proxmox documentation generation
   - Every 6 hours: all systems documentation
   - Weekly: full pipeline with indexing
   - Proper task routing and rate limiting

5. **Test Script** (`scripts/test_proxmox_docs.py`)
   - End-to-end testing of documentation generation
   - Mock data collection from Proxmox
   - Template-based generation
   - File and database storage

6. **Configuration Updates** (`src/datacenter_docs/utils/config.py`)
   - Add port configuration fields for Docker services
   - Add MongoDB and Redis credentials
   - Support all required environment variables

**Proxmox Documentation Sections:**
- Infrastructure Overview (cluster, nodes, stats)
- Virtual Machines Inventory
- LXC Containers Inventory
- Storage Configuration
- Network Configuration
- Maintenance Procedures

**Benefits:**
- Scalable to multiple infrastructure systems
- Prevents LLM context window overflow
- Independent section generation
- Scheduled automatic updates
- Vector store integration for RAG chat
- Template-driven approach for consistency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-20 19:23:30 +02:00
parent 27dd9e00b6
commit 16fc8e2659
6 changed files with 1178 additions and 1 deletions

162
scripts/test_proxmox_docs.py Executable file
View File

@@ -0,0 +1,162 @@
#!/usr/bin/env python3
"""
Test script for Proxmox documentation generation
Tests the end-to-end workflow:
1. Collect data from Proxmox (using mock data)
2. Generate documentation using template
3. Save sections to files and database
4. Optionally index for RAG
"""
import asyncio
import logging
import sys
from pathlib import Path
# Add src to path
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
from datacenter_docs.collectors.proxmox_collector import ProxmoxCollector
from datacenter_docs.generators.template_generator import TemplateBasedGenerator
# Configure logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)
logger = logging.getLogger(__name__)
async def test_proxmox_documentation() -> None:
"""Test complete Proxmox documentation generation workflow"""
logger.info("=" * 80)
logger.info("PROXMOX DOCUMENTATION GENERATION TEST")
logger.info("=" * 80)
# Step 1: Collect data from Proxmox
logger.info("\n📊 STEP 1: Collecting data from Proxmox...")
logger.info("-" * 80)
collector = ProxmoxCollector()
collect_result = await collector.run()
if not collect_result["success"]:
logger.error(f"❌ Data collection failed: {collect_result.get('error')}")
return
logger.info("✅ Data collection successful!")
logger.info(f" Collected at: {collect_result['data']['metadata']['collected_at']}")
# Show statistics
stats = collect_result["data"]["data"].get("statistics", {})
logger.info("\n📈 Infrastructure Statistics:")
logger.info(f" Total VMs: {stats.get('total_vms', 0)}")
logger.info(f" Running VMs: {stats.get('running_vms', 0)}")
logger.info(f" Total Containers: {stats.get('total_containers', 0)}")
logger.info(f" Running Containers: {stats.get('running_containers', 0)}")
logger.info(f" Total Nodes: {stats.get('total_nodes', 0)}")
logger.info(f" Total CPU Cores: {stats.get('total_cpu_cores', 0)}")
logger.info(f" Total Memory: {stats.get('total_memory_gb', 0)} GB")
logger.info(f" Total Storage: {stats.get('total_storage_tb', 0)} TB")
# Step 2: Generate documentation using template
logger.info("\n📝 STEP 2: Generating documentation using template...")
logger.info("-" * 80)
template_path = "templates/documentation/proxmox.yaml"
try:
generator = TemplateBasedGenerator(template_path)
except FileNotFoundError:
logger.error(f"❌ Template not found: {template_path}")
logger.info(" Creating template directory and file...")
# Create template directory
template_dir = Path(template_path).parent
template_dir.mkdir(parents=True, exist_ok=True)
logger.error(
" Please ensure the template file exists at: "
f"{Path(template_path).absolute()}"
)
return
logger.info(f"✅ Template loaded: {generator.template.name}")
logger.info(f" Sections to generate: {len(generator.template.sections)}")
# List all sections
for i, section in enumerate(generator.template.sections, 1):
logger.info(f" {i}. {section.get('title')} (ID: {section.get('id')})")
# Step 3: Generate and save all sections
logger.info("\n🔨 STEP 3: Generating documentation sections...")
logger.info("-" * 80)
sections_results = await generator.generate_and_save_sections(
data=collect_result["data"], save_individually=True
)
# Show results
sections_generated = sum(1 for r in sections_results if r.get("success"))
sections_failed = sum(1 for r in sections_results if not r.get("success"))
logger.info(f"\n✅ Generation completed!")
logger.info(f" Sections generated: {sections_generated}")
logger.info(f" Sections failed: {sections_failed}")
# Show each section result
logger.info("\n📋 Section Results:")
for result in sections_results:
if result.get("success"):
logger.info(f"{result.get('title')}")
if "file_path" in result:
logger.info(f" File: {result.get('file_path')}")
else:
logger.info(f"{result.get('section_id')}: {result.get('error')}")
# Step 4: Summary
logger.info("\n" + "=" * 80)
logger.info("SUMMARY")
logger.info("=" * 80)
logger.info(f"✅ Data Collection: SUCCESS")
logger.info(
f"✅ Documentation Generation: {sections_generated}/{len(sections_results)} sections"
)
if sections_failed == 0:
logger.info("\n🎉 All tests passed successfully!")
else:
logger.warning(f"\n⚠️ {sections_failed} section(s) failed to generate")
# Show output directory
output_dir = Path(generator.template.output_config.get("directory", "output"))
if output_dir.exists():
logger.info(f"\n📁 Generated files available in: {output_dir.absolute()}")
md_files = list(output_dir.glob("**/*.md"))
if md_files:
logger.info(f" Total markdown files: {len(md_files)}")
for md_file in md_files[:10]: # Show first 10
logger.info(f" - {md_file.relative_to(output_dir)}")
if len(md_files) > 10:
logger.info(f" ... and {len(md_files) - 10} more")
logger.info("\n" + "=" * 80)
def main() -> None:
"""Main entry point"""
try:
asyncio.run(test_proxmox_documentation())
except KeyboardInterrupt:
logger.info("\n\n⚠️ Test interrupted by user")
sys.exit(1)
except Exception as e:
logger.error(f"\n\n❌ Test failed with error: {e}", exc_info=True)
sys.exit(1)
if __name__ == "__main__":
main()