# Backend (Flask Simulation API)

This project contains all cloud simulation logic.

- API server: `backend/app.py`
- Simulation engine: `backend/simulator.py`
- Services split by file under `backend/services/`:
  - `vm_service.py`
  - `load_balancer_service.py` (round robin, weighted round robin, least connections, random)
  - `autoscaler_service.py` (scale up + scale down)
  - `request_queue_service.py` (paid queue capacity and overflow)
  - `cloud_armor_service.py` (basic checks + rate limit)
  - `script_runtime_service.py` (runs python script VMs on reserved ports)
  - `postgres_service.py` (online PostgreSQL status + SQL execution)
  - `mongo_service.py` (online MongoDB status + collection operations)

## Run

```bash
python -m pip install -r requirements.txt
python app.py
```

Set `DATABASE_URL` to enable online PostgreSQL:

```bash
set DATABASE_URL=postgresql://user:password@host:5432/dbname
```

Set `MONGODB_URI` (and optionally `MONGODB_DB`) to enable online MongoDB:

```bash
set MONGODB_URI=mongodb+srv://user:password@cluster-host
set MONGODB_DB=cloud_sim
```

## Main API routes

- `GET /api/health`
- `GET /api/state`
- `POST /api/vms`
- `POST /api/load-balancers`
- `POST /api/simulate`
- `GET /api/sql/status`
- `POST /api/sql/execute`
- `GET /api/mongo/status`
- `POST /api/mongo/execute`

## DNS Resolution Model

This is how public URL -> internal VM port routing works:

1. VM internal port is stored in DB:
   - VM field: `reserved_port` (`reservedPort` in app objects)
2. Public DNS mapping is stored in DB:
   - table: `dns_records`
   - field: `domain` (for example `project-db-c055e0c2.us-central1.cloudsim.local`)
3. Public URL is generated dynamically:
   - domain-only URL (no port): `http://<domain>`
4. Gateway resolves internally:
   - `backend/app.py` `internal_dns_proxy()` reads `Host`, resolves VM ID, fetches VM record, and proxies to `127.0.0.1:<reservedPort>`.

So the user sees a clean public URL, while backend routes to the correct internal port.

## CLI

Use the built-in CLI client from `backend/cli.py`.

From repo root, use the launcher alias:

```bash
cloudsim health
cloudsim state --summary
```

Or from PowerShell explicitly in repo:

```bash
.\cloudsim health
.\cloudsim state --summary
```

Direct Python form still works:

```bash
cd backend
python cli.py health
python cli.py state --summary
```

Configure API URL if backend is not on `http://127.0.0.1:5000`:

```bash
set CLOUDSIM_API_URL=http://127.0.0.1:5050
cloudsim health
```

Optional persistent PowerShell alias:

```powershell
Add-Content -Path $PROFILE -Value 'Set-Alias cloudsim "E:\codex\cloud_sim_site\cloudsim.cmd"'
```

Examples:

```bash
python cli.py vm create --name vm1 --region us-central1 --machine-type e2-standard-2 --image "Ubuntu 22.04 LTS" --backend-profile-id python-fastapi --runtime-mode python_script --script-path scripts/sample_app.py
python cli.py lb create --name lb1 --type "HTTP(S)" --region global --backend-vm-id <VM_ID> --distribution-algorithm-id round_robin
python cli.py simulate --lb-id <LB_ID> --endpoint-key "GET /health" --requests 200 --client-id demo-client
python cli.py sql status
python cli.py mongo status
python cli.py autoscale-test --requests 500 --max-instances 5
```

### Interactive Autoscale Test

Use:

```bash
cloudsim autoscale-test --requests 500 --max-instances 5
```

Flow:
1. CLI asks confirmation to proceed.
2. It creates a temporary base VM + LB.
3. On confirmation, it sends a burst to trigger autoscale.
4. Terminal shows live spin-up animation and running instance list (up to target cap).
5. CLI asks if work is done, then can destroy auto-scaled VMs.
6. Optional prompt to destroy temporary base VM/LB too.

## Script VM mode

Create a VM with:
- `runtimeMode: "python_script"`
- `scriptPath: "scripts/sample_app.py"` (relative to `backend/`)

When the VM is running, backend starts the script on the VM reserved port. Auto-scaled clones run the same script on new ports.
