# CMDB — Configuration Management Database Full-stack CMDB application: **FastAPI + PostgreSQL + React (MUI)** ## Architecture ``` ┌──────────┐ ┌────────────┐ ┌────────────┐ │ React │────▶│ Nginx │────▶│ FastAPI │ │ (MUI) │ │ (reverse │ │ (async) │ │ :3000 │ │ proxy) │ │ :8000 │ └──────────┘ │ :80 │ └─────┬──────┘ └────────────┘ │ ┌──────▼──────┐ │ PostgreSQL │ │ :5432 │ └─────────────┘ ``` ## Quick Start (Docker Compose) ```bash # Clone and start cd cmdb-app docker-compose up -d # Apply migrations (if not auto-applied) docker exec -i cmdb-postgres psql -U cmdb -d cmdb < backend/migrations/001_initial_schema.sql docker exec -i cmdb-postgres psql -U cmdb -d cmdb < backend/migrations/002_seed_data.sql # Open # API docs: http://localhost/api/docs # Frontend: http://localhost ``` ## Local Development ### Backend ```bash cd backend python -m venv .venv && source .venv/bin/activate pip install -r requirements.txt # Start PostgreSQL (Docker) docker run -d --name cmdb-pg -p 5432:5432 \ -e POSTGRES_DB=cmdb -e POSTGRES_USER=cmdb -e POSTGRES_PASSWORD=cmdb_secret \ postgres:16-alpine # Run migrations psql -h localhost -U cmdb -d cmdb < migrations/001_initial_schema.sql psql -h localhost -U cmdb -d cmdb < migrations/002_seed_data.sql # Start backend uvicorn app.main:app --reload --port 8000 ``` ### Frontend ```bash cd frontend npm install npm run dev # → http://localhost:5173 ``` ## API Reference ### Authentication ```bash # Login curl -X POST http://localhost:8000/api/auth/login \ -H "Content-Type: application/json" \ -d '{"username":"admin","password":"admin123"}' # → {"access_token":"eyJ...","token_type":"bearer"} # Get current user curl -H "Authorization: Bearer " http://localhost:8000/api/auth/me ``` ### Configuration Items ```bash # List CIs (paginated, filtered) curl -H "Authorization: Bearer " \ "http://localhost:8000/api/ci?page=1&page_size=10&status=active&search=proxmox" # Get single CI with all details curl -H "Authorization: Bearer " \ http://localhost:8000/api/ci/ # Create CI curl -X POST http://localhost:8000/api/ci \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "name": "new-server", "ci_type_id": "", "status": "active", "tags": ["new", "production"], "attributes": {"cpu": "Xeon", "ram_gb": 32} }' # Update CI curl -X PATCH http://localhost:8000/api/ci/ \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"status": "maintenance"}' # Delete (soft) curl -X DELETE -H "Authorization: Bearer " \ http://localhost:8000/api/ci/ # Export CSV curl -H "Authorization: Bearer " \ http://localhost:8000/api/ci/export?format=csv > cmdb_export.csv ``` ### Relationships & Graph ```bash # Add relationship curl -X POST http://localhost:8000/api/ci//relationships \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "source_ci_id": "", "target_ci_id": "", "relationship": "depends_on", "description": "Service depends on server" }' # Get relationship graph curl -H "Authorization: Bearer " \ "http://localhost:8000/api/ci/graph/visualize?depth=2" ``` ### Bulk Import ```bash curl -X POST http://localhost:8000/api/ci/bulk/import \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "items": [ {"name": "server-1", "ci_type_name": "PhysicalServer", "status": "active"}, {"name": "vm-web", "ci_type_name": "VirtualMachine", "status": "active"} ] }' ``` ### Dashboard ```bash curl -H "Authorization: Bearer " \ http://localhost:8000/api/dashboard/stats ``` ## Query Parameters (CI List) | Parameter | Type | Description | |-------------|--------|--------------------------------------| | page | int | Page number (default: 1) | | page_size | int | Items per page (1-100, default: 20) | | search | string | Full-text search on name/desc/serial | | status | string | Filter by status | | ci_type_id | UUID | Filter by CI type | | location_id | UUID | Filter by location | | tag | string | Filter by tag | | owner_id | UUID | Filter by owner | | sort_by | string | Sort field (default: name) | | sort_order | string | asc/desc (default: asc) | ## Testing ```bash cd backend pytest tests/ -v ``` ## Deployment ### Docker Compose (production) ```bash # Set secrets export JWT_SECRET=$(openssl rand -hex 32) export POSTGRES_PASSWORD=$(openssl rand -hex 32) docker-compose -f docker-compose.yml up -d ``` ### Kubernetes ```bash # Create namespace kubectl create namespace cmdb # Create secrets kubectl -n cmdb create secret generic cmdb-secrets \ --from-literal=db-user=cmdb \ --from-literal=db-password=$(openssl rand -hex 16) \ --from-literal=jwt-secret=$(openssl rand -hex 32) # Deploy kubectl apply -f k8s/postgres.yaml kubectl apply -f k8s/backend.yaml kubectl apply -f k8s/frontend.yaml # Check kubectl -n cmdb get pods ``` ## Security Checklist - [ ] Change `JWT_SECRET` in production - [ ] Change PostgreSQL password - [ ] Enable SSL/TLS for PostgreSQL (`sslmode=require`) - [ ] Run backend as non-root user - [ ] Configure CORS for production domain only - [ ] Set up `pg_hba.conf` to restrict DB access - [ ] Enable rate limiting (configured: 120 req/min) - [ ] Run `pg_dump` backups daily - [ ] Review audit trail in `changelog` table ## Database Schema ### ER Diagram (simplified) ``` ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ ci_classes │────▶│ ci_types │────▶│ cis │ └──────────────┘ └──────────────┘ └──────┬───────┘ │ ┌─────────────────────────────┼───────────────────────┐ │ │ │ │ │ ┌─────▼─────┐ ┌────▼─────┐ ┌──────▼──────┐ ┌───▼────┐ ┌──▼──────────┐ │ip_addresses│ │ nics │ │ hw_details │ │sw_inst │ │relationships│ └───────────┘ └──────────┘ └─────────────┘ └────────┘ └─────────────┘ ``` ### Key Design Decisions 1. **Soft delete everywhere** — `deleted_at` column, never hard delete 2. **JSONB attributes** — extensible key-value store for class-specific fields 3. **Audit trail** — `changelog` table + PostgreSQL triggers 4. **Versioning** — CI `version` column incremented on every update 5. **UUID primary keys** — safe for distributed/multi-instance 6. **INET type** — native PostgreSQL IP address handling ## Ansible Integration ```yaml # playbooks/cmdb-import.yml - name: Import Ansible facts into CMDB hosts: all tasks: - name: Get system facts set_fact: ci_data: name: "{{ inventory_hostname }}" status: active attributes: os: "{{ ansible_distribution }} {{ ansible_distribution_version }}" cpu_cores: "{{ ansible_processor_vcpus }}" ram_gb: "{{ (ansible_memtotal_mb / 1024) | round(1) }}" ip: "{{ ansible_default_ipv4.address }}" - name: Register in CMDB uri: url: "http://cmdb-host:8000/api/ci" method: POST headers: Authorization: "Bearer {{ cmdb_token }}" body_format: json body: "{{ ci_data }}" status_code: [201, 409] ``` ## Roadmap 1. **Discovery integration** — nmap, arp-scan, SNMP polling 2. **CMDB reconciliation** — compare discovered vs. recorded state 3. **Change management** — RFC workflow, approval chain 4. **Dependency impact analysis** — cascade failure simulation 5. **SSO/LDAP** — corporate directory integration 6. **Webhook notifications** — Slack/Teams alerts on CI changes 7. **API versioning** — `/api/v2/` with backward compatibility 8. **GraphQL** — alternative API layer for complex queries 9. **RBAC per CI type** — fine-grained access control 10. **Terraform/Pulumi integration** — import IaC resources as CIs