Skip to content

Commit 5f0fbf2

Browse files
authored
Merge pull request #10 from livenson/claude/add-octavia-emulation-014nusUMpLNJZv5jWaUjCaE3
Add Octavia emulation support
2 parents d21169c + 6f0435a commit 5f0fbf2

10 files changed

Lines changed: 4544 additions & 11 deletions

File tree

‎CLAUDE.md‎

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,9 @@ pytest tests/test_<service>.py -v
222222

223223
## Pre-commit Requirements
224224

225-
**IMPORTANT: You MUST run the black linter and ensure it passes before committing any code.**
225+
**IMPORTANT: You MUST run all linters and ensure they pass before committing any code.**
226226

227-
### Black Linter
227+
### Black Formatter
228228

229229
All Python code must be formatted with black before committing. This is a strict requirement - commits with unformatted code are not acceptable.
230230

@@ -239,17 +239,43 @@ black .
239239
black emulator/ tests/
240240
```
241241

242+
### Ruff Linter
243+
244+
All Python code must pass ruff linting checks. Ruff catches common errors and enforces code quality standards.
245+
246+
```bash
247+
# Check for linting errors
248+
ruff check emulator tests
249+
250+
# Auto-fix some issues (where possible)
251+
ruff check --fix emulator tests
252+
```
253+
254+
Common ruff issues to avoid:
255+
- **E741**: Ambiguous variable names (e.g., use `listener` instead of `l`)
256+
- **F841**: Unused variables (remove or use them)
257+
258+
### Mypy Type Checker
259+
260+
All Python code must pass mypy type checking.
261+
262+
```bash
263+
# Run mypy type checker
264+
mypy emulator --ignore-missing-imports
265+
```
266+
242267
### Pre-commit Checklist
243268

244-
Before every commit, you MUST:
269+
Before every commit, you MUST run these commands in order:
245270

246-
1. **Run black formatter**: `black .`
247-
2. **Verify formatting passes**: `black --check .`
248-
3. **Run tests**: `pytest`
271+
1. **Run black formatter**: `black emulator tests`
272+
2. **Run ruff linter**: `ruff check emulator tests`
273+
3. **Run mypy type checker**: `mypy emulator --ignore-missing-imports`
274+
4. **Run tests**: `pytest`
249275

250-
If `black --check .` reports any formatting issues, run `black .` to fix them before committing.
276+
All four checks must pass before committing. Fix any errors before proceeding.
251277

252-
**DO NOT commit code that fails black formatting checks. This is mandatory.**
278+
**DO NOT commit code that fails any of these checks. This is mandatory.**
253279

254280
## Patterns and Best Practices
255281

‎emulator/__init__.py‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"cinder": 8776,
1919
"glance": 9292,
2020
"neutron": 9696,
21+
"octavia": 9876,
2122
"status": 10000,
2223
}
2324

@@ -27,6 +28,7 @@
2728
"cinder": "emulator.api.app_cinder:app",
2829
"glance": "emulator.api.app_glance:app",
2930
"neutron": "emulator.api.app_neutron:app",
31+
"octavia": "emulator.api.app_octavia:app",
3032
"status": "emulator.api.app_status:app",
3133
}
3234

@@ -61,6 +63,7 @@ def run_all_services(host: str, port_offset: int = 0) -> None:
6163
print(f" - Cinder (Block Storage): http://{host}:{ports['cinder']}")
6264
print(f" - Glance (Image): http://{host}:{ports['glance']}")
6365
print(f" - Neutron (Network): http://{host}:{ports['neutron']}")
66+
print(f" - Octavia (Load Balancer): http://{host}:{ports['octavia']}")
6467
print(f" - Status (Web UI): http://{host}:{ports['status']}")
6568
print("\nPress Ctrl+C to stop all services.\n")
6669

@@ -100,10 +103,10 @@ def main() -> None:
100103
)
101104
parser.add_argument(
102105
"--service",
103-
choices=["keystone", "nova", "cinder", "glance", "neutron", "status", "all"],
106+
choices=["keystone", "nova", "cinder", "glance", "neutron", "octavia", "status", "all"],
104107
default="all",
105108
help="Service to run: keystone (5000), nova (8774), cinder (8776), "
106-
"glance (9292), neutron (9696), status (10000), or all (default: all)",
109+
"glance (9292), neutron (9696), octavia (9876), status (10000), or all (default: all)",
107110
)
108111
parser.add_argument(
109112
"--port-offset",

‎emulator/api/app_octavia.py‎

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"""Octavia Load Balancer API application for OpenStack emulator.
2+
3+
Runs on port 9876 (standard OpenStack Octavia port).
4+
"""
5+
6+
from fastapi import FastAPI, Request
7+
from fastapi.middleware.cors import CORSMiddleware
8+
from fastapi.responses import JSONResponse
9+
10+
from emulator.api.octavia import router as octavia_router
11+
12+
app = FastAPI(
13+
title="OpenStack Octavia Emulator",
14+
description="A lightweight OpenStack Octavia (Load Balancer) API emulator",
15+
version="0.1.0",
16+
docs_url="/docs",
17+
redoc_url="/redoc",
18+
)
19+
20+
# Add CORS middleware for development
21+
app.add_middleware(
22+
CORSMiddleware,
23+
allow_origins=["*"],
24+
allow_credentials=True,
25+
allow_methods=["*"],
26+
allow_headers=["*"],
27+
)
28+
29+
30+
# Custom exception handler for OpenStack-style errors
31+
@app.exception_handler(Exception)
32+
async def openstack_exception_handler(request: Request, exc: Exception) -> JSONResponse:
33+
"""Handle exceptions in OpenStack error format."""
34+
return JSONResponse(
35+
status_code=500,
36+
content={
37+
"error": {
38+
"message": str(exc),
39+
"code": 500,
40+
}
41+
},
42+
)
43+
44+
45+
# Include Octavia router
46+
app.include_router(octavia_router)
47+
48+
49+
# Health check endpoint
50+
@app.get("/health")
51+
async def health_check() -> dict[str, str]:
52+
"""Health check endpoint."""
53+
return {"status": "healthy", "service": "octavia"}

0 commit comments

Comments
 (0)