mirror of
https://github.com/blackboxprogramming/BlackRoad-Operating-System.git
synced 2026-03-17 09:37:55 -05:00
Add comprehensive service status infrastructure
- Add SERVICE_STATUS.md: Complete analysis of all blackroad.systems services - Add check_all_services.sh: Automated service health checker script - Add minimal-service template: Production-ready FastAPI service template Service Status Findings: - All 9 services return 403 Forbidden (Cloudflare blocking) - Services are deployed and DNS is working correctly - Issue is Cloudflare WAF/security rules, not service implementation Template Features: - Complete syscall API compliance (/v1/sys/*) - Railway deployment ready - CORS configuration - Health and version endpoints - HTML "Hello World" landing page - OpenAPI documentation Existing Service Implementations: ✓ Core API (services/core-api) ✓ Public API (services/public-api) ✓ Operator (operator_engine) ✓ Prism Console (prism-console) ✓ App/Shell (backend) Next Steps: 1. Configure Cloudflare WAF to allow health check endpoints 2. Use minimal-service template for missing services 3. Implement full syscall API in existing services 4. Test inter-service RPC communication Refs: #125
This commit is contained in:
326
docs/SERVICE_STATUS.md
Normal file
326
docs/SERVICE_STATUS.md
Normal file
@@ -0,0 +1,326 @@
|
|||||||
|
# BlackRoad OS - Service Status Report
|
||||||
|
|
||||||
|
**Generated**: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
|
||||||
|
**Status**: Pre-Production / Configuration Phase
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This document tracks the deployment status of all BlackRoad OS services across the distributed infrastructure.
|
||||||
|
|
||||||
|
## Service Registry
|
||||||
|
|
||||||
|
According to `infra/DNS.md` and `INFRASTRUCTURE.md`, BlackRoad OS consists of 9 core services:
|
||||||
|
|
||||||
|
| Service | DNS | Railway URL | Satellite Repo | Monorepo Path | Status |
|
||||||
|
|---------|-----|-------------|----------------|---------------|--------|
|
||||||
|
| **Operator** | operator.blackroad.systems | blackroad-os-operator-production-3983.up.railway.app | blackroad-os-operator | `/operator_engine` | ⚠️ 403 |
|
||||||
|
| **Core API** | core.blackroad.systems | 9gw4d0h2.up.railway.app | blackroad-os-core | `/services/core-api` | ⚠️ Unreachable |
|
||||||
|
| **Public API** | api.blackroad.systems | ac7bx15h.up.railway.app | blackroad-os-api | `/services/public-api` | ⚠️ 403 |
|
||||||
|
| **App/Shell** | app.blackroad.systems | blackroad-operating-system-production.up.railway.app | blackroad-operating-system | `/backend` | ⚠️ 403 |
|
||||||
|
| **Console** | console.blackroad.systems | qqr1r4hd.up.railway.app | blackroad-os-prism-console | `/prism-console` | ⚠️ 403 |
|
||||||
|
| **Docs** | docs.blackroad.systems | 2izt9kog.up.railway.app | blackroad-os-docs | `/docs` | ⚠️ 403 |
|
||||||
|
| **Web Client** | web.blackroad.systems | blackroad-os-web-production-3bbb.up.railway.app | blackroad-os-web | `/web-client` | ⚠️ 403 |
|
||||||
|
| **OS Interface** | os.blackroad.systems | vtrb1hrx.up.railway.app | blackroad-os-interface | `/blackroad-os` | ⚠️ 403 |
|
||||||
|
| **Root** | blackroad.systems | kng9hpna.up.railway.app | blackroad-os-root | N/A | ⚠️ 403 |
|
||||||
|
|
||||||
|
## Status Legend
|
||||||
|
|
||||||
|
- ✅ **Healthy**: Service responding with 200 OK on `/health` endpoint
|
||||||
|
- ⚠️ **Forbidden (403)**: Service exists but Cloudflare is blocking access
|
||||||
|
- ❌ **Unreachable**: Cannot connect to service (DNS or Railway issue)
|
||||||
|
- 🚧 **Not Deployed**: Service code exists in monorepo but not deployed
|
||||||
|
- 📝 **Stub Only**: Only README or placeholder exists
|
||||||
|
|
||||||
|
## Current Issues
|
||||||
|
|
||||||
|
### Issue 1: Cloudflare Access Control (403 Errors)
|
||||||
|
|
||||||
|
**Symptoms**:
|
||||||
|
- All services (except core) return "Access denied" or 403 Forbidden
|
||||||
|
- Services are reachable but blocked by Cloudflare
|
||||||
|
|
||||||
|
**Likely Causes**:
|
||||||
|
1. Cloudflare WAF (Web Application Firewall) rules blocking requests
|
||||||
|
2. Cloudflare Bot Fight Mode enabled
|
||||||
|
3. IP-based rate limiting
|
||||||
|
4. Cloudflare Access authentication required
|
||||||
|
|
||||||
|
**Resolution Steps**:
|
||||||
|
```bash
|
||||||
|
# 1. Check Cloudflare WAF rules
|
||||||
|
# Visit: https://dash.cloudflare.com → Security → WAF
|
||||||
|
|
||||||
|
# 2. Temporarily disable Bot Fight Mode to test
|
||||||
|
# Visit: https://dash.cloudflare.com → Security → Bots
|
||||||
|
|
||||||
|
# 3. Check Firewall Rules
|
||||||
|
# Visit: https://dash.cloudflare.com → Security → Firewall Rules
|
||||||
|
|
||||||
|
# 4. Verify CNAME records are proxied (orange cloud)
|
||||||
|
# Visit: https://dash.cloudflare.com → DNS → Records
|
||||||
|
```
|
||||||
|
|
||||||
|
### Issue 2: Core API Unreachable (000 Error)
|
||||||
|
|
||||||
|
**Symptoms**:
|
||||||
|
- `core.blackroad.systems` returns connection error
|
||||||
|
- Railway URL `9gw4d0h2.up.railway.app` may not be responding
|
||||||
|
|
||||||
|
**Likely Causes**:
|
||||||
|
1. Railway service not running
|
||||||
|
2. Railway URL changed
|
||||||
|
3. DNS CNAME pointing to wrong URL
|
||||||
|
4. Service crashed or failed to deploy
|
||||||
|
|
||||||
|
**Resolution Steps**:
|
||||||
|
```bash
|
||||||
|
# 1. Check Railway service status
|
||||||
|
railway status --service blackroad-os-core-production
|
||||||
|
|
||||||
|
# 2. View logs
|
||||||
|
railway logs --service blackroad-os-core-production
|
||||||
|
|
||||||
|
# 3. Redeploy if needed
|
||||||
|
cd /path/to/blackroad-os-core
|
||||||
|
git push origin main
|
||||||
|
|
||||||
|
# 4. Verify CNAME in Cloudflare
|
||||||
|
dig core.blackroad.systems CNAME
|
||||||
|
```
|
||||||
|
|
||||||
|
## Monorepo Service Implementations
|
||||||
|
|
||||||
|
### ✅ Services with Complete Implementations
|
||||||
|
|
||||||
|
1. **Core API** (`/services/core-api/app/main.py`):
|
||||||
|
- ✅ `/health` endpoint
|
||||||
|
- ✅ `/version` endpoint
|
||||||
|
- ✅ `/api/core/status` endpoint
|
||||||
|
- ✅ Error handlers
|
||||||
|
- **Lines**: 167
|
||||||
|
|
||||||
|
2. **Public API** (`/services/public-api/app/main.py`):
|
||||||
|
- ✅ `/health` endpoint (checks backend health)
|
||||||
|
- ✅ `/version` endpoint
|
||||||
|
- ✅ Proxy routes to Core API and Agents API
|
||||||
|
- ✅ Error handlers
|
||||||
|
- **Lines**: 263
|
||||||
|
|
||||||
|
3. **Operator** (`/operator_engine/server.py`):
|
||||||
|
- ✅ `/health` endpoint
|
||||||
|
- ✅ `/version` endpoint
|
||||||
|
- ✅ `/jobs` endpoints
|
||||||
|
- ✅ `/scheduler/status` endpoint
|
||||||
|
- **Lines**: 101
|
||||||
|
|
||||||
|
4. **Prism Console** (`/prism-console/server.py`):
|
||||||
|
- ✅ `/health` endpoint
|
||||||
|
- ✅ `/version` endpoint
|
||||||
|
- ✅ `/config.js` dynamic config
|
||||||
|
- ✅ Static file serving
|
||||||
|
- **Lines**: 132
|
||||||
|
|
||||||
|
5. **App/Shell** (`/backend/app/main.py`):
|
||||||
|
- ✅ Complete FastAPI application
|
||||||
|
- ✅ 33+ routers
|
||||||
|
- ✅ Static file serving
|
||||||
|
- ✅ Health endpoints (via `api_health` router)
|
||||||
|
- **Lines**: 100+ (main.py only)
|
||||||
|
|
||||||
|
### 🚧 Services Needing Implementation
|
||||||
|
|
||||||
|
6. **Web Client** (`/web-client/`):
|
||||||
|
- 📝 Only README exists
|
||||||
|
- **Action Needed**: Create simple static server with health endpoints
|
||||||
|
|
||||||
|
7. **Docs** (`/docs/`):
|
||||||
|
- 📝 Documentation files exist but no server
|
||||||
|
- **Action Needed**: Create static doc server with health endpoints
|
||||||
|
|
||||||
|
8. **OS Interface** (`/blackroad-os/`):
|
||||||
|
- ⚠️ May be superseded by `/backend/static/`
|
||||||
|
- **Action Needed**: Clarify if separate from app.blackroad.systems
|
||||||
|
|
||||||
|
9. **Root** (`blackroad.systems`):
|
||||||
|
- ❌ No implementation in monorepo
|
||||||
|
- **Action Needed**: Create landing page service
|
||||||
|
|
||||||
|
## Hello World Test Plan
|
||||||
|
|
||||||
|
To verify all services can respond with "Hello World":
|
||||||
|
|
||||||
|
### Phase 1: Verify Existing Implementations (Monorepo)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Test Core API locally
|
||||||
|
cd /home/user/BlackRoad-Operating-System/services/core-api
|
||||||
|
uvicorn app.main:app --port 8000
|
||||||
|
curl http://localhost:8000/health
|
||||||
|
|
||||||
|
# 2. Test Public API locally
|
||||||
|
cd /home/user/BlackRoad-Operating-System/services/public-api
|
||||||
|
uvicorn app.main:app --port 8001
|
||||||
|
curl http://localhost:8001/health
|
||||||
|
|
||||||
|
# 3. Test Operator locally
|
||||||
|
cd /home/user/BlackRoad-Operating-System/operator_engine
|
||||||
|
python server.py
|
||||||
|
curl http://localhost:8001/health
|
||||||
|
|
||||||
|
# 4. Test Prism Console locally
|
||||||
|
cd /home/user/BlackRoad-Operating-System/prism-console
|
||||||
|
python server.py
|
||||||
|
curl http://localhost:8000/health
|
||||||
|
|
||||||
|
# 5. Test App/Shell locally
|
||||||
|
cd /home/user/BlackRoad-Operating-System/backend
|
||||||
|
uvicorn app.main:app --reload
|
||||||
|
curl http://localhost:8000/health
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 2: Create Missing Service Implementations
|
||||||
|
|
||||||
|
See `templates/service-template/` for a minimal FastAPI service template with:
|
||||||
|
- `/health` endpoint
|
||||||
|
- `/version` endpoint
|
||||||
|
- `/v1/sys/identity` endpoint (syscall API compliance)
|
||||||
|
- CORS configuration
|
||||||
|
- Railway deployment support
|
||||||
|
|
||||||
|
### Phase 3: Fix Cloudflare Access Control
|
||||||
|
|
||||||
|
1. Access Cloudflare dashboard for `blackroad.systems`
|
||||||
|
2. Navigate to **Security** → **WAF**
|
||||||
|
3. Review and adjust rules to allow health check endpoints
|
||||||
|
4. Consider creating exception rule for `/health` and `/version` paths
|
||||||
|
|
||||||
|
### Phase 4: Verify Production Deployment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run the comprehensive service checker
|
||||||
|
bash scripts/check_all_services.sh
|
||||||
|
|
||||||
|
# Expected output:
|
||||||
|
# Testing https://operator.blackroad.systems ... ✓ HEALTHY
|
||||||
|
# Testing https://core.blackroad.systems ... ✓ HEALTHY
|
||||||
|
# Testing https://api.blackroad.systems ... ✓ HEALTHY
|
||||||
|
# ... (all services should show ✓ HEALTHY)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Syscall API Compliance
|
||||||
|
|
||||||
|
According to `SYSCALL_API.md`, all services MUST implement:
|
||||||
|
|
||||||
|
### Required Endpoints
|
||||||
|
|
||||||
|
| Endpoint | Method | Purpose | Status |
|
||||||
|
|----------|--------|---------|--------|
|
||||||
|
| `/health` | GET | Basic health check | ⚠️ Exists but 403 |
|
||||||
|
| `/version` | GET | Version info | ⚠️ Exists but 403 |
|
||||||
|
| `/v1/sys/identity` | GET | Service identity | ❌ Not implemented |
|
||||||
|
| `/v1/sys/health` | GET | Detailed health | ❌ Not implemented |
|
||||||
|
| `/v1/sys/rpc` | POST | Inter-service RPC | ❌ Not implemented |
|
||||||
|
|
||||||
|
### Implementation Status
|
||||||
|
|
||||||
|
- **Core API**: Has `/health` and `/version`, missing syscall endpoints
|
||||||
|
- **Public API**: Has `/health` and `/version`, missing syscall endpoints
|
||||||
|
- **Operator**: Has `/health` and `/version`, missing syscall endpoints
|
||||||
|
- **Prism Console**: Has `/health` and `/version`, missing syscall endpoints
|
||||||
|
- **App/Shell**: Has health via router, missing syscall endpoints
|
||||||
|
- **Others**: Not yet implemented
|
||||||
|
|
||||||
|
### Next Steps for Syscall Compliance
|
||||||
|
|
||||||
|
1. Add TypeScript kernel to all satellite repos (from `/kernel/typescript/`)
|
||||||
|
2. Implement `/v1/sys/*` endpoints in each service
|
||||||
|
3. Add RPC client for inter-service communication
|
||||||
|
4. Implement service registry lookups
|
||||||
|
5. Add event bus and job queue support
|
||||||
|
|
||||||
|
## Recommended Actions
|
||||||
|
|
||||||
|
### Immediate (Fix 403 Errors)
|
||||||
|
|
||||||
|
1. **Review Cloudflare Security Settings**:
|
||||||
|
- Check WAF rules
|
||||||
|
- Review Bot Fight Mode settings
|
||||||
|
- Verify rate limiting configuration
|
||||||
|
- Ensure health check paths are whitelisted
|
||||||
|
|
||||||
|
2. **Test Direct Railway URLs**:
|
||||||
|
```bash
|
||||||
|
# Bypass Cloudflare by testing Railway URLs directly
|
||||||
|
curl https://blackroad-os-operator-production-3983.up.railway.app/health
|
||||||
|
curl https://9gw4d0h2.up.railway.app/health
|
||||||
|
curl https://ac7bx15h.up.railway.app/health
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Update Cloudflare Firewall Rules**:
|
||||||
|
- Create exception for `/health` endpoint
|
||||||
|
- Create exception for `/version` endpoint
|
||||||
|
- Allow all HTTP methods on syscall paths
|
||||||
|
|
||||||
|
### Short Term (Complete Missing Services)
|
||||||
|
|
||||||
|
1. **Create Web Client Service**:
|
||||||
|
- Simple static file server
|
||||||
|
- Health and version endpoints
|
||||||
|
- Sync to `blackroad-os-web` satellite
|
||||||
|
|
||||||
|
2. **Create Docs Service**:
|
||||||
|
- Markdown renderer or static site
|
||||||
|
- Health and version endpoints
|
||||||
|
- Sync to `blackroad-os-docs` satellite
|
||||||
|
|
||||||
|
3. **Create Root Landing Page**:
|
||||||
|
- Simple welcome page for `blackroad.systems`
|
||||||
|
- Links to all services
|
||||||
|
- Service status dashboard
|
||||||
|
|
||||||
|
### Medium Term (Syscall API Compliance)
|
||||||
|
|
||||||
|
1. **Integrate TypeScript Kernel**:
|
||||||
|
- Copy `/kernel/typescript/` to each satellite
|
||||||
|
- Implement syscall endpoints
|
||||||
|
- Add RPC client support
|
||||||
|
|
||||||
|
2. **Service Discovery**:
|
||||||
|
- Implement service registry lookups
|
||||||
|
- Use Railway internal DNS for inter-service communication
|
||||||
|
- Add health checks for dependencies
|
||||||
|
|
||||||
|
3. **Monitoring & Observability**:
|
||||||
|
- Add structured logging
|
||||||
|
- Implement metrics collection
|
||||||
|
- Create service dependency graph
|
||||||
|
|
||||||
|
## Testing Checklist
|
||||||
|
|
||||||
|
- [ ] All services respond to `/health` with 200 OK
|
||||||
|
- [ ] All services respond to `/version` with version info
|
||||||
|
- [ ] All services return "Hello World" or equivalent on root path
|
||||||
|
- [ ] Cloudflare is not blocking legitimate traffic
|
||||||
|
- [ ] Railway services are all running
|
||||||
|
- [ ] DNS CNAME records are correct
|
||||||
|
- [ ] Satellite repos are in sync with monorepo
|
||||||
|
- [ ] Each service has proper CORS configuration
|
||||||
|
- [ ] Each service implements syscall API endpoints
|
||||||
|
- [ ] Inter-service RPC communication works
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- **DNS Configuration**: `infra/DNS.md`
|
||||||
|
- **Service Registry**: `INFRASTRUCTURE.md`
|
||||||
|
- **Syscall API Spec**: `SYSCALL_API.md`
|
||||||
|
- **Railway Deployment**: `docs/RAILWAY_DEPLOYMENT.md`
|
||||||
|
- **Kernel Implementation**: `kernel/typescript/README.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Document Version**: 1.0
|
||||||
|
**Last Updated**: 2025-11-20
|
||||||
|
**Author**: Claude (AI Assistant)
|
||||||
|
**Status**: 🚧 Pre-Production Analysis
|
||||||
94
scripts/check_all_services.sh
Executable file
94
scripts/check_all_services.sh
Executable file
@@ -0,0 +1,94 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# BlackRoad OS - Service Status Checker
|
||||||
|
# Tests all *.blackroad.systems services for health endpoints
|
||||||
|
|
||||||
|
echo "========================================"
|
||||||
|
echo "BlackRoad OS Service Status Check"
|
||||||
|
echo "Date: $(date -u +"%Y-%m-%d %H:%M:%S UTC")"
|
||||||
|
echo "========================================"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Service list from DNS.md
|
||||||
|
SERVICES=(
|
||||||
|
"operator"
|
||||||
|
"core"
|
||||||
|
"api"
|
||||||
|
"app"
|
||||||
|
"console"
|
||||||
|
"docs"
|
||||||
|
"web"
|
||||||
|
"os"
|
||||||
|
"blackroad.systems"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Function to test a service
|
||||||
|
test_service() {
|
||||||
|
local service=$1
|
||||||
|
local url=""
|
||||||
|
|
||||||
|
if [ "$service" == "blackroad.systems" ]; then
|
||||||
|
url="https://blackroad.systems"
|
||||||
|
else
|
||||||
|
url="https://$service.blackroad.systems"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "Testing $url ... "
|
||||||
|
|
||||||
|
# Test /health endpoint
|
||||||
|
health_code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$url/health" 2>&1)
|
||||||
|
health_response=$(curl -s --max-time 10 "$url/health" 2>&1)
|
||||||
|
|
||||||
|
# Test /version endpoint
|
||||||
|
version_code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$url/version" 2>&1)
|
||||||
|
|
||||||
|
# Test root endpoint
|
||||||
|
root_code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$url/" 2>&1)
|
||||||
|
|
||||||
|
# Determine status
|
||||||
|
if [[ "$health_code" == "200" ]]; then
|
||||||
|
echo -e "${GREEN}✓ HEALTHY${NC} (health: $health_code, version: $version_code, root: $root_code)"
|
||||||
|
echo " Response: $health_response" | head -c 100
|
||||||
|
echo ""
|
||||||
|
elif [[ "$health_code" == "403" ]]; then
|
||||||
|
echo -e "${YELLOW}⚠ FORBIDDEN${NC} (health: $health_code, version: $version_code, root: $root_code)"
|
||||||
|
echo " Note: Service exists but Cloudflare is blocking access"
|
||||||
|
elif [[ "$health_code" == "000" || "$health_code" == "" ]]; then
|
||||||
|
echo -e "${RED}✗ UNREACHABLE${NC} (health: $health_code, version: $version_code, root: $root_code)"
|
||||||
|
echo " Error: Cannot connect to service"
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}⚠ UNKNOWN${NC} (health: $health_code, version: $version_code, root: $root_code)"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Test all services
|
||||||
|
for service in "${SERVICES[@]}"; do
|
||||||
|
test_service "$service"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "========================================"
|
||||||
|
echo "Service Status Summary"
|
||||||
|
echo "========================================"
|
||||||
|
echo ""
|
||||||
|
echo "Legend:"
|
||||||
|
echo " ✓ HEALTHY - Service is responding with 200 OK"
|
||||||
|
echo " ⚠ FORBIDDEN - Service exists but Cloudflare is blocking (403)"
|
||||||
|
echo " ✗ UNREACHABLE - Cannot connect to service"
|
||||||
|
echo ""
|
||||||
|
echo "Next Steps:"
|
||||||
|
echo " 1. Check Cloudflare WAF rules for 403 errors"
|
||||||
|
echo " 2. Verify Railway deployment for unreachable services"
|
||||||
|
echo " 3. Check DNS configuration in Cloudflare dashboard"
|
||||||
|
echo " 4. Review satellite repo deployment status"
|
||||||
|
echo ""
|
||||||
|
echo "Documentation:"
|
||||||
|
echo " - DNS Map: infra/DNS.md"
|
||||||
|
echo " - Infrastructure: INFRASTRUCTURE.md"
|
||||||
|
echo " - Syscall API: SYSCALL_API.md"
|
||||||
|
echo ""
|
||||||
27
templates/minimal-service/.env.example
Normal file
27
templates/minimal-service/.env.example
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# BlackRoad OS - Minimal Service Environment Configuration
|
||||||
|
|
||||||
|
# Service Identity
|
||||||
|
SERVICE_NAME=blackroad-os-example
|
||||||
|
SERVICE_ROLE=example
|
||||||
|
SERVICE_VERSION=1.0.0
|
||||||
|
|
||||||
|
# Environment
|
||||||
|
ENVIRONMENT=development # production | development
|
||||||
|
PORT=8000
|
||||||
|
|
||||||
|
# CORS Configuration
|
||||||
|
ALLOWED_ORIGINS=http://localhost:8000,http://localhost:3000,https://blackroad.systems
|
||||||
|
|
||||||
|
# DNS (auto-configured in production)
|
||||||
|
CLOUDFLARE_URL=https://example.blackroad.systems
|
||||||
|
RAILWAY_STATIC_URL= # Auto-provided by Railway
|
||||||
|
RAILWAY_PRIVATE_URL= # Auto-provided by Railway
|
||||||
|
|
||||||
|
# Optional: Railway metadata (auto-provided)
|
||||||
|
RAILWAY_GIT_COMMIT_SHA=
|
||||||
|
RAILWAY_REGION=
|
||||||
|
RAILWAY_SERVICE_ID=
|
||||||
|
RAILWAY_DEPLOYMENT_ID=
|
||||||
|
|
||||||
|
# Optional: Build metadata
|
||||||
|
BUILD_TIME=
|
||||||
16
templates/minimal-service/Dockerfile
Normal file
16
templates/minimal-service/Dockerfile
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
FROM python:3.11-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
# Copy application
|
||||||
|
COPY main.py .
|
||||||
|
|
||||||
|
# Expose port (Railway will override with PORT env var)
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
# Run the application
|
||||||
|
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "${PORT:-8000}"]
|
||||||
260
templates/minimal-service/README.md
Normal file
260
templates/minimal-service/README.md
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
# BlackRoad OS - Minimal Service Template
|
||||||
|
|
||||||
|
A production-ready FastAPI service template that implements the BlackRoad OS syscall API specification.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
✅ **Core Endpoints**:
|
||||||
|
- `/` - Hello World landing page (HTML)
|
||||||
|
- `/health` - Basic health check (required by Railway)
|
||||||
|
- `/version` - Version information
|
||||||
|
|
||||||
|
✅ **Syscall API Endpoints** (BlackRoad OS standard):
|
||||||
|
- `/v1/sys/identity` - Complete service identity
|
||||||
|
- `/v1/sys/health` - Detailed health metrics
|
||||||
|
- `/v1/sys/version` - Extended version info
|
||||||
|
- `/v1/sys/config` - Service configuration
|
||||||
|
|
||||||
|
✅ **Additional Features**:
|
||||||
|
- CORS middleware
|
||||||
|
- Custom error handlers (404, 500)
|
||||||
|
- OpenAPI documentation (`/api/docs`, `/api/redoc`)
|
||||||
|
- Railway deployment support
|
||||||
|
- Environment-based configuration
|
||||||
|
- Startup/shutdown hooks
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### 1. Local Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install dependencies
|
||||||
|
pip install fastapi uvicorn
|
||||||
|
|
||||||
|
# Set environment variables
|
||||||
|
export SERVICE_NAME="blackroad-os-example"
|
||||||
|
export SERVICE_ROLE="example"
|
||||||
|
export ENVIRONMENT="development"
|
||||||
|
export PORT=8000
|
||||||
|
|
||||||
|
# Run the service
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Visit: http://localhost:8000
|
||||||
|
|
||||||
|
### 2. Deploy to Railway
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Copy this template to your satellite repo
|
||||||
|
cp templates/minimal-service/main.py /path/to/satellite-repo/
|
||||||
|
|
||||||
|
# 2. Create Dockerfile
|
||||||
|
cat > Dockerfile <<EOF
|
||||||
|
FROM python:3.11-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
COPY main.py .
|
||||||
|
|
||||||
|
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "\${PORT:-8000}"]
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# 3. Create requirements.txt
|
||||||
|
cat > requirements.txt <<EOF
|
||||||
|
fastapi==0.104.1
|
||||||
|
uvicorn[standard]==0.24.0
|
||||||
|
python-multipart==0.0.6
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# 4. Push to satellite repo
|
||||||
|
git add .
|
||||||
|
git commit -m "Add minimal service implementation"
|
||||||
|
git push origin main
|
||||||
|
|
||||||
|
# Railway will automatically deploy
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Configure Environment Variables (Railway)
|
||||||
|
|
||||||
|
In Railway dashboard, set:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
SERVICE_NAME=blackroad-os-docs
|
||||||
|
SERVICE_ROLE=docs
|
||||||
|
ENVIRONMENT=production
|
||||||
|
ALLOWED_ORIGINS=https://blackroad.systems,https://api.blackroad.systems
|
||||||
|
CLOUDFLARE_URL=https://docs.blackroad.systems
|
||||||
|
```
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
| Variable | Required | Default | Description |
|
||||||
|
|----------|----------|---------|-------------|
|
||||||
|
| `SERVICE_NAME` | No | `blackroad-os-service` | Full service name |
|
||||||
|
| `SERVICE_ROLE` | No | `unknown` | Service role (docs, web, api, etc.) |
|
||||||
|
| `SERVICE_VERSION` | No | `1.0.0` | Service version |
|
||||||
|
| `ENVIRONMENT` | No | `development` | `production` or `development` |
|
||||||
|
| `PORT` | No | `8000` | Port to run on |
|
||||||
|
| `ALLOWED_ORIGINS` | No | `*` | CORS allowed origins (comma-separated) |
|
||||||
|
| `CLOUDFLARE_URL` | No | - | Public Cloudflare URL |
|
||||||
|
| `RAILWAY_STATIC_URL` | Auto | - | Provided by Railway |
|
||||||
|
| `RAILWAY_GIT_COMMIT_SHA` | Auto | - | Provided by Railway |
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test health endpoint
|
||||||
|
curl http://localhost:8000/health
|
||||||
|
|
||||||
|
# Test version endpoint
|
||||||
|
curl http://localhost:8000/version
|
||||||
|
|
||||||
|
# Test identity (syscall API)
|
||||||
|
curl http://localhost:8000/v1/sys/identity
|
||||||
|
|
||||||
|
# Test detailed health (syscall API)
|
||||||
|
curl http://localhost:8000/v1/sys/health
|
||||||
|
|
||||||
|
# View API docs
|
||||||
|
open http://localhost:8000/api/docs
|
||||||
|
```
|
||||||
|
|
||||||
|
## Customization
|
||||||
|
|
||||||
|
### Add Custom Endpoints
|
||||||
|
|
||||||
|
```python
|
||||||
|
@app.get("/api/custom")
|
||||||
|
async def custom_endpoint():
|
||||||
|
"""Your custom endpoint"""
|
||||||
|
return {"message": "Custom data"}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add Static File Serving
|
||||||
|
|
||||||
|
```python
|
||||||
|
from fastapi.staticfiles import StaticFiles
|
||||||
|
|
||||||
|
# Mount static files
|
||||||
|
app.mount("/static", StaticFiles(directory="static"), name="static")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add Database Connection
|
||||||
|
|
||||||
|
```python
|
||||||
|
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
|
||||||
|
|
||||||
|
# Add to startup event
|
||||||
|
@app.on_event("startup")
|
||||||
|
async def startup_event():
|
||||||
|
global engine
|
||||||
|
database_url = os.getenv("DATABASE_URL")
|
||||||
|
engine = create_async_engine(database_url)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add Health Checks
|
||||||
|
|
||||||
|
```python
|
||||||
|
@app.get("/v1/sys/health")
|
||||||
|
async def sys_health():
|
||||||
|
checks = {
|
||||||
|
"database": await check_database(),
|
||||||
|
"redis": await check_redis(),
|
||||||
|
"external_api": await check_external_api()
|
||||||
|
}
|
||||||
|
|
||||||
|
all_healthy = all(c["status"] == "ok" for c in checks.values())
|
||||||
|
|
||||||
|
return {
|
||||||
|
"status": "healthy" if all_healthy else "degraded",
|
||||||
|
"checks": checks,
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Integration with BlackRoad OS
|
||||||
|
|
||||||
|
### Service Registry
|
||||||
|
|
||||||
|
This template is compatible with the BlackRoad OS service registry (`INFRASTRUCTURE.md`).
|
||||||
|
|
||||||
|
Each service automatically reports its identity via `/v1/sys/identity`, which includes:
|
||||||
|
- DNS endpoints (Cloudflare, Railway, internal)
|
||||||
|
- Runtime information (host, port, uptime)
|
||||||
|
- Health status
|
||||||
|
- Capabilities
|
||||||
|
|
||||||
|
### Inter-Service Communication
|
||||||
|
|
||||||
|
To call other services:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import httpx
|
||||||
|
|
||||||
|
# Call another BlackRoad service
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
response = await client.get(
|
||||||
|
"http://blackroad-os-core.railway.internal:8000/v1/sys/identity"
|
||||||
|
)
|
||||||
|
core_identity = response.json()
|
||||||
|
```
|
||||||
|
|
||||||
|
### RPC Support (Optional)
|
||||||
|
|
||||||
|
To add RPC support, implement `/v1/sys/rpc`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
@app.post("/v1/sys/rpc")
|
||||||
|
async def sys_rpc(request: Request):
|
||||||
|
"""Handle RPC calls from other services"""
|
||||||
|
body = await request.json()
|
||||||
|
method = body.get("method")
|
||||||
|
params = body.get("params", {})
|
||||||
|
|
||||||
|
# Route to method handler
|
||||||
|
if method == "getStatus":
|
||||||
|
result = await get_status()
|
||||||
|
elif method == "getData":
|
||||||
|
result = await get_data(params)
|
||||||
|
else:
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=404,
|
||||||
|
content={"error": {"code": "METHOD_NOT_FOUND", "message": f"Method '{method}' not found"}}
|
||||||
|
)
|
||||||
|
|
||||||
|
return {"result": result}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Production Checklist
|
||||||
|
|
||||||
|
Before deploying to production:
|
||||||
|
|
||||||
|
- [ ] Set `ENVIRONMENT=production`
|
||||||
|
- [ ] Configure `ALLOWED_ORIGINS` (no wildcards)
|
||||||
|
- [ ] Set proper `SERVICE_NAME` and `SERVICE_ROLE`
|
||||||
|
- [ ] Add health check monitoring
|
||||||
|
- [ ] Enable structured logging
|
||||||
|
- [ ] Add error tracking (Sentry, etc.)
|
||||||
|
- [ ] Configure rate limiting
|
||||||
|
- [ ] Add authentication (if needed)
|
||||||
|
- [ ] Test all endpoints
|
||||||
|
- [ ] Verify CORS configuration
|
||||||
|
- [ ] Check Railway deployment logs
|
||||||
|
- [ ] Verify Cloudflare DNS routing
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- **Syscall API Spec**: `SYSCALL_API.md`
|
||||||
|
- **Service Registry**: `INFRASTRUCTURE.md`
|
||||||
|
- **DNS Configuration**: `infra/DNS.md`
|
||||||
|
- **Deployment Guide**: `docs/RAILWAY_DEPLOYMENT.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Template Version**: 1.0
|
||||||
|
**Compatible with**: BlackRoad OS v2.0
|
||||||
|
**Last Updated**: 2025-11-20
|
||||||
388
templates/minimal-service/main.py
Normal file
388
templates/minimal-service/main.py
Normal file
@@ -0,0 +1,388 @@
|
|||||||
|
"""
|
||||||
|
BlackRoad OS - Minimal Service Template
|
||||||
|
|
||||||
|
A minimal FastAPI service that implements the required syscall endpoints
|
||||||
|
for BlackRoad OS distributed architecture.
|
||||||
|
|
||||||
|
Use this template for:
|
||||||
|
- Creating new services
|
||||||
|
- Quick testing and deployment
|
||||||
|
- Service stub implementations
|
||||||
|
|
||||||
|
Required env vars:
|
||||||
|
- SERVICE_NAME: Name of the service (e.g., "blackroad-os-docs")
|
||||||
|
- SERVICE_ROLE: Role of the service (e.g., "docs", "web", "api")
|
||||||
|
- ENVIRONMENT: "production" or "development"
|
||||||
|
- PORT: Port to run on (default: 8000)
|
||||||
|
"""
|
||||||
|
from fastapi import FastAPI, Request
|
||||||
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
from fastapi.responses import JSONResponse, HTMLResponse
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import platform
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Dict, Any, Optional
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# CONFIGURATION
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# Service metadata
|
||||||
|
SERVICE_NAME = os.getenv("SERVICE_NAME", "blackroad-os-service")
|
||||||
|
SERVICE_ROLE = os.getenv("SERVICE_ROLE", "unknown")
|
||||||
|
VERSION = os.getenv("SERVICE_VERSION", "1.0.0")
|
||||||
|
COMMIT = os.getenv("RAILWAY_GIT_COMMIT_SHA", "local")[:7]
|
||||||
|
ENVIRONMENT = os.getenv("ENVIRONMENT", "development")
|
||||||
|
|
||||||
|
# CORS configuration
|
||||||
|
ALLOWED_ORIGINS = os.getenv("ALLOWED_ORIGINS", "*").split(",")
|
||||||
|
|
||||||
|
# Startup time for uptime calculation
|
||||||
|
START_TIME = time.time()
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# FASTAPI APPLICATION
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
app = FastAPI(
|
||||||
|
title=SERVICE_NAME,
|
||||||
|
description=f"BlackRoad OS - {SERVICE_ROLE.title()} Service",
|
||||||
|
version=VERSION,
|
||||||
|
docs_url="/api/docs",
|
||||||
|
redoc_url="/api/redoc",
|
||||||
|
openapi_url="/api/openapi.json"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add CORS middleware
|
||||||
|
app.add_middleware(
|
||||||
|
CORSMiddleware,
|
||||||
|
allow_origins=ALLOWED_ORIGINS,
|
||||||
|
allow_credentials=True,
|
||||||
|
allow_methods=["*"],
|
||||||
|
allow_headers=["*"],
|
||||||
|
)
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# HELPER FUNCTIONS
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
def get_uptime_seconds() -> int:
|
||||||
|
"""Get service uptime in seconds"""
|
||||||
|
return int(time.time() - START_TIME)
|
||||||
|
|
||||||
|
|
||||||
|
def get_identity() -> Dict[str, Any]:
|
||||||
|
"""Get service identity (syscall API compliant)"""
|
||||||
|
uptime = get_uptime_seconds()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"service": SERVICE_NAME,
|
||||||
|
"role": SERVICE_ROLE,
|
||||||
|
"version": VERSION,
|
||||||
|
"environment": ENVIRONMENT,
|
||||||
|
"dns": {
|
||||||
|
"cloudflare": os.getenv("CLOUDFLARE_URL", f"https://{SERVICE_ROLE}.blackroad.systems"),
|
||||||
|
"railway": os.getenv("RAILWAY_STATIC_URL", "unknown"),
|
||||||
|
"internal": os.getenv("RAILWAY_PRIVATE_URL", f"http://{SERVICE_NAME}.railway.internal:8000")
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"railwayHost": os.getenv("RAILWAY_STATIC_URL", "unknown"),
|
||||||
|
"internalHost": os.getenv("RAILWAY_PRIVATE_URL", "unknown"),
|
||||||
|
"port": int(os.getenv("PORT", 8000)),
|
||||||
|
"pid": os.getpid(),
|
||||||
|
"uptime": uptime
|
||||||
|
},
|
||||||
|
"health": {
|
||||||
|
"status": "healthy",
|
||||||
|
"uptime": uptime,
|
||||||
|
"lastCheck": datetime.utcnow().isoformat() + "Z"
|
||||||
|
},
|
||||||
|
"capabilities": ["http", "static"], # Add more as needed
|
||||||
|
"metadata": {
|
||||||
|
"commit": COMMIT,
|
||||||
|
"pythonVersion": platform.python_version(),
|
||||||
|
"platform": platform.system(),
|
||||||
|
"release": platform.release()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# CORE ENDPOINTS (Required)
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
async def root():
|
||||||
|
"""Root endpoint - Hello World"""
|
||||||
|
return HTMLResponse(content=f"""
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>{SERVICE_NAME}</title>
|
||||||
|
<style>
|
||||||
|
body {{
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 50px auto;
|
||||||
|
padding: 20px;
|
||||||
|
background: #0a0a0a;
|
||||||
|
color: #00ff00;
|
||||||
|
}}
|
||||||
|
h1 {{ color: #00ff00; border-bottom: 2px solid #00ff00; padding-bottom: 10px; }}
|
||||||
|
.info {{ background: #1a1a1a; padding: 15px; border-left: 4px solid #00ff00; margin: 20px 0; }}
|
||||||
|
.status {{ color: #ffff00; }}
|
||||||
|
a {{ color: #00aaff; text-decoration: none; }}
|
||||||
|
a:hover {{ text-decoration: underline; }}
|
||||||
|
pre {{ background: #1a1a1a; padding: 10px; overflow-x: auto; }}
|
||||||
|
.emoji {{ font-size: 2em; }}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1><span class="emoji">🛣️</span> BlackRoad OS - {SERVICE_ROLE.title()} Service</h1>
|
||||||
|
|
||||||
|
<div class="info">
|
||||||
|
<p><strong>Service:</strong> {SERVICE_NAME}</p>
|
||||||
|
<p><strong>Role:</strong> {SERVICE_ROLE}</p>
|
||||||
|
<p><strong>Version:</strong> {VERSION}</p>
|
||||||
|
<p><strong>Environment:</strong> {ENVIRONMENT}</p>
|
||||||
|
<p><strong>Status:</strong> <span class="status">✓ ONLINE</span></p>
|
||||||
|
<p><strong>Uptime:</strong> {get_uptime_seconds()} seconds</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Available Endpoints</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/health">/health</a> - Basic health check</li>
|
||||||
|
<li><a href="/version">/version</a> - Version information</li>
|
||||||
|
<li><a href="/v1/sys/identity">/v1/sys/identity</a> - Service identity (syscall API)</li>
|
||||||
|
<li><a href="/v1/sys/health">/v1/sys/health</a> - Detailed health (syscall API)</li>
|
||||||
|
<li><a href="/api/docs">/api/docs</a> - API documentation (Swagger UI)</li>
|
||||||
|
<li><a href="/api/redoc">/api/redoc</a> - API documentation (ReDoc)</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Hello World Test</h2>
|
||||||
|
<pre>
|
||||||
|
$ curl https://{SERVICE_ROLE}.blackroad.systems/health
|
||||||
|
{{"status": "healthy", "service": "{SERVICE_ROLE}", "version": "{VERSION}"}}
|
||||||
|
|
||||||
|
$ curl https://{SERVICE_ROLE}.blackroad.systems/version
|
||||||
|
{{"version": "{VERSION}", "commit": "{COMMIT}", "environment": "{ENVIRONMENT}"}}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<footer style="margin-top: 50px; padding-top: 20px; border-top: 1px solid #333; color: #666;">
|
||||||
|
<p>BlackRoad Operating System - Distributed OS Architecture</p>
|
||||||
|
<p>Part of the BlackRoad ecosystem | <a href="https://blackroad.systems">blackroad.systems</a></p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/health")
|
||||||
|
async def health_check():
|
||||||
|
"""
|
||||||
|
Basic health check endpoint (Required by Railway and syscall API).
|
||||||
|
Returns 200 OK if service is healthy.
|
||||||
|
"""
|
||||||
|
uptime = get_uptime_seconds()
|
||||||
|
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=200,
|
||||||
|
content={
|
||||||
|
"status": "healthy",
|
||||||
|
"service": SERVICE_ROLE,
|
||||||
|
"version": VERSION,
|
||||||
|
"commit": COMMIT,
|
||||||
|
"environment": ENVIRONMENT,
|
||||||
|
"timestamp": datetime.utcnow().isoformat() + "Z",
|
||||||
|
"uptime_seconds": uptime
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/version")
|
||||||
|
async def version_info():
|
||||||
|
"""
|
||||||
|
Version information endpoint (Required by syscall API).
|
||||||
|
Returns detailed version and build information.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"version": VERSION,
|
||||||
|
"service": SERVICE_NAME,
|
||||||
|
"role": SERVICE_ROLE,
|
||||||
|
"commit": COMMIT,
|
||||||
|
"environment": ENVIRONMENT,
|
||||||
|
"buildTime": os.getenv("BUILD_TIME", "unknown"),
|
||||||
|
"pythonVersion": platform.python_version(),
|
||||||
|
"deployment": {
|
||||||
|
"platform": "Railway",
|
||||||
|
"region": os.getenv("RAILWAY_REGION", "unknown"),
|
||||||
|
"serviceId": os.getenv("RAILWAY_SERVICE_ID", "unknown"),
|
||||||
|
"deploymentId": os.getenv("RAILWAY_DEPLOYMENT_ID", "unknown"),
|
||||||
|
"staticUrl": os.getenv("RAILWAY_STATIC_URL", "unknown")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# SYSCALL API ENDPOINTS (BlackRoad OS Standard)
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
@app.get("/v1/sys/identity")
|
||||||
|
async def sys_identity():
|
||||||
|
"""
|
||||||
|
Get complete service identity (syscall API).
|
||||||
|
Returns full identity object including DNS, runtime, and health info.
|
||||||
|
"""
|
||||||
|
return get_identity()
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/v1/sys/health")
|
||||||
|
async def sys_health():
|
||||||
|
"""
|
||||||
|
Detailed health check with extended metrics (syscall API).
|
||||||
|
Returns comprehensive health information.
|
||||||
|
"""
|
||||||
|
uptime = get_uptime_seconds()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"status": "healthy",
|
||||||
|
"timestamp": datetime.utcnow().isoformat() + "Z",
|
||||||
|
"uptime": uptime,
|
||||||
|
"memory": {
|
||||||
|
"rss": 0, # TODO: Add actual memory metrics
|
||||||
|
"heapTotal": 0,
|
||||||
|
"heapUsed": 0,
|
||||||
|
"external": 0
|
||||||
|
},
|
||||||
|
"checks": {
|
||||||
|
"self": {
|
||||||
|
"status": "ok",
|
||||||
|
"message": "Service is running"
|
||||||
|
},
|
||||||
|
# Add more health checks here (database, redis, etc.)
|
||||||
|
},
|
||||||
|
"service": {
|
||||||
|
"name": SERVICE_NAME,
|
||||||
|
"role": SERVICE_ROLE,
|
||||||
|
"version": VERSION
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/v1/sys/version")
|
||||||
|
async def sys_version():
|
||||||
|
"""
|
||||||
|
Extended version information (syscall API).
|
||||||
|
Returns comprehensive version and build details.
|
||||||
|
"""
|
||||||
|
return version_info()
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/v1/sys/config")
|
||||||
|
async def sys_config():
|
||||||
|
"""
|
||||||
|
Get non-sensitive service configuration (syscall API).
|
||||||
|
Returns partial config without secrets.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"service": {
|
||||||
|
"name": SERVICE_NAME,
|
||||||
|
"role": SERVICE_ROLE,
|
||||||
|
"version": VERSION,
|
||||||
|
"environment": ENVIRONMENT,
|
||||||
|
"port": int(os.getenv("PORT", 8000))
|
||||||
|
},
|
||||||
|
"features": {
|
||||||
|
"http": True,
|
||||||
|
"static": True,
|
||||||
|
"rpc": False, # Not implemented in minimal template
|
||||||
|
"events": False, # Not implemented in minimal template
|
||||||
|
"jobs": False, # Not implemented in minimal template
|
||||||
|
"state": False # Not implemented in minimal template
|
||||||
|
},
|
||||||
|
"cors": {
|
||||||
|
"enabled": True,
|
||||||
|
"allowedOrigins": ALLOWED_ORIGINS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# ERROR HANDLERS
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
@app.exception_handler(404)
|
||||||
|
async def not_found_handler(request: Request, exc):
|
||||||
|
"""Custom 404 handler"""
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=404,
|
||||||
|
content={
|
||||||
|
"error": "Not Found",
|
||||||
|
"path": str(request.url.path),
|
||||||
|
"message": "The requested resource was not found",
|
||||||
|
"service": SERVICE_NAME,
|
||||||
|
"suggestion": "Try /health, /version, or /v1/sys/identity"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.exception_handler(500)
|
||||||
|
async def internal_error_handler(request: Request, exc):
|
||||||
|
"""Custom 500 handler"""
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=500,
|
||||||
|
content={
|
||||||
|
"error": "Internal Server Error",
|
||||||
|
"message": "An unexpected error occurred",
|
||||||
|
"service": SERVICE_NAME
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# STARTUP
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
@app.on_event("startup")
|
||||||
|
async def startup_event():
|
||||||
|
"""Runs on application startup"""
|
||||||
|
print(f"🛣️ Starting {SERVICE_NAME}...")
|
||||||
|
print(f" Role: {SERVICE_ROLE}")
|
||||||
|
print(f" Version: {VERSION}")
|
||||||
|
print(f" Environment: {ENVIRONMENT}")
|
||||||
|
print(f" Port: {os.getenv('PORT', 8000)}")
|
||||||
|
print(f"✓ Service is ready!")
|
||||||
|
|
||||||
|
|
||||||
|
@app.on_event("shutdown")
|
||||||
|
async def shutdown_event():
|
||||||
|
"""Runs on application shutdown"""
|
||||||
|
print(f"Shutting down {SERVICE_NAME}...")
|
||||||
|
print("✓ Shutdown complete")
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# MAIN (for local development)
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import uvicorn
|
||||||
|
|
||||||
|
port = int(os.getenv("PORT", 8000))
|
||||||
|
reload = ENVIRONMENT == "development"
|
||||||
|
|
||||||
|
print(f"\n{'='*60}")
|
||||||
|
print(f"BlackRoad OS - {SERVICE_ROLE.title()} Service")
|
||||||
|
print(f"{'='*60}")
|
||||||
|
print(f"Service: {SERVICE_NAME}")
|
||||||
|
print(f"Version: {VERSION}")
|
||||||
|
print(f"Environment: {ENVIRONMENT}")
|
||||||
|
print(f"Port: {port}")
|
||||||
|
print(f"Reload: {reload}")
|
||||||
|
print(f"{'='*60}\n")
|
||||||
|
|
||||||
|
uvicorn.run(
|
||||||
|
"main:app",
|
||||||
|
host="0.0.0.0",
|
||||||
|
port=port,
|
||||||
|
reload=reload,
|
||||||
|
log_level="info"
|
||||||
|
)
|
||||||
3
templates/minimal-service/requirements.txt
Normal file
3
templates/minimal-service/requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fastapi==0.104.1
|
||||||
|
uvicorn[standard]==0.24.0
|
||||||
|
python-multipart==0.0.6
|
||||||
Reference in New Issue
Block a user