Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
40ed857
feat: add services/ scaffold + unwpp-service (Phase 1)
May 1, 2026
210d871
feat: add gadm-service (Phase 2)
May 1, 2026
4427a2e
feat: add gadm-service web client (client.html)
May 1, 2026
ec238fc
fix: add CORS middleware to all services (allow file:// and cross-ori…
May 1, 2026
4ebc714
feat: add geoboundaries-service (Phase 3)
May 1, 2026
2c7c789
feat: add unocha-service (Phase 4)
May 1, 2026
47f5a08
feat: add worldpop-service (Phase 5)
May 1, 2026
552e3d4
feat: worldpop client.html + download lock + boundaries-only mode
May 1, 2026
1f4b5b6
feat: add worldpop prewarm script and improve client status message
May 1, 2026
7a30f07
feat: add services/generate.py — service-based laser-init data pipeline
May 1, 2026
55692ac
feat: generate.py --emit-scripts calls laser-init Load phase
May 1, 2026
6d799f8
refactor: simplify _emit_scripts after installing laser-init as package
May 1, 2026
89eef3e
fix: round WorldPop float populations to integers in build_gdf
May 2, 2026
2152174
feat: AKS deployment manifests for geodata microservices
May 2, 2026
2493960
fix: retry worldpop aggregate on Azure LB idle-timeout connection reset
May 2, 2026
234e92b
feat: update client.html to use AKS service IPs
May 2, 2026
7dfa007
fix: prewarm retry on Azure LB timeout + unbuffered output
May 4, 2026
d8e1e73
perf: vectorized raster aggregation — read once, rasterize all polygons
May 4, 2026
1d43445
fix: detailed error reporting in client.html
May 4, 2026
e8a57b9
fix: windowed aggregation — read raster once, mask per polygon in-memory
May 4, 2026
9bb3e23
fix: quantile colour classification for choropleth
May 4, 2026
80f779c
fix: handle missing CRS in GADM shapefiles (e.g. CAN)
May 4, 2026
5a30493
fix: hybrid windowed aggregation for very large country rasters
May 4, 2026
cc99fdb
feat: pre-flight size check + add GBR/DEU/FRA to prewarm list
May 4, 2026
966a0ea
fix: raise size threshold to 2 GB; check at aggregation time too
May 4, 2026
b31109a
fix: handle large-country WorldPop aggregation without OOM or LB timeout
May 5, 2026
9cace30
More obvious progress spinner.
May 5, 2026
d09e283
Add generate.py command strip to browser client
May 5, 2026
431f32f
Add laser-generate CLI entry point
May 5, 2026
53e330b
Add tests for laser.init.generate (laser-generate entry point)
May 5, 2026
cbce75e
Read service URLs from laser_config.yaml instead of hardcoding localhost
May 5, 2026
071a8f9
Add README for gadm-service
May 6, 2026
1ede688
Add READMEs for all five geodata microservices
May 6, 2026
af8a640
Lower large-country polygon bailout threshold; fix wrong ISO codes
May 6, 2026
f3ad77b
Address Copilot review comments on PR #18
Jul 6, 2026
40aa3c3
Fix ruff F841/I001 in generate.py flagged by main-branch CI
Jul 6, 2026
0ff681b
Revert accidental pyproject.toml update in prior commit
Jul 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ dependencies = [
"anthropic>=0.84.0",
"click>=8.3.1",
"geopandas>=1.1.2",
"httpx>=0.27",
"laser-generic>=1.0.1",
"matplotlib>=3.10.8",
"openai>=2.24.0",
Expand Down Expand Up @@ -48,6 +49,7 @@ dev = [

[project.scripts]
laser-init = "laser.init.cli:cli"
laser-generate = "laser.init.generate:main"

[tool.ruff]
line-length = 100
Expand Down
135 changes: 135 additions & 0 deletions services/AKS/DEPLOYMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# Geodata Services — AKS Deployment Guide

All five geodata microservices deploy into the existing `laser-ai` namespace.
Each gets its own LoadBalancer IP (matching the jenner-mcp pattern).
Each service mounts a PVC at `/cache` for persistent raster/shapefile storage
that survives pod restarts and redeployments.

## Services

| Name | Image | Port | Cache PVC | Notes |
|---|---|---|---|---|
| `laser-unwpp-svc` | `laser-unwpp-service` | 80 | 2 Gi | WPP CSVs; downloads on startup |
| `laser-gadm-svc` | `laser-gadm-service` | 80 | 20 Gi | GADM GDB per country; on-demand |
| `laser-geoboundaries-svc` | `laser-geoboundaries-service` | 80 | 10 Gi | geoBoundaries ZIPs; on-demand |
| `laser-unocha-svc` | `laser-unocha-service` | 80 | 5 Gi | UNOCHA global GDB (~2 GB); on first request |
| `laser-worldpop-svc` | `laser-worldpop-service` | 80 | 100 Gi | WorldPop rasters; on-demand or pre-warmed |

Registry: `idm-docker-staging.packages.idmod.org/`

---

## Quick Start

### 1. Push images

```bash
cd services/
make push-all-geodata TAG=v0.5.1a
```

### 2. Deploy PVCs, Deployments, and Services

```bash
make k8s-deploy
# or directly:
kubectl apply -f AKS/geodata-services.yaml --kubeconfig AKS/kube.conf
```

### 3. Wait for all pods to be Ready

```bash
make k8s-status
# or:
kubectl get deployment,svc,pvc -n laser-ai -l app.kubernetes.io/part-of=laser-geodata \
--kubeconfig AKS/kube.conf
```

### 4. Pre-warm the WorldPop raster cache (optional but recommended)

Wait for `laser-worldpop-svc` to be Ready, then:

```bash
make k8s-prewarm
# or directly:
kubectl apply -f AKS/worldpop-prewarm-job.yaml --kubeconfig AKS/kube.conf

# Monitor progress (~50 countries, 4 parallel workers):
kubectl logs -f job/laser-worldpop-prewarm -n laser-ai --kubeconfig AKS/kube.conf
```

The Job downloads ~50 commonly-used country rasters (~2–500 MB each) in parallel.
Total time ~15–30 min depending on network. Completes once, then stays in a
terminal state (safe to leave or delete).

---

## Get service IPs

After deployment, retrieve LoadBalancer IPs:

```bash
kubectl get svc -n laser-ai -l app.kubernetes.io/part-of=laser-geodata \
--kubeconfig AKS/kube.conf \
-o custom-columns='NAME:.metadata.name,IP:.status.loadBalancer.ingress[0].ip'
```

Use those IPs in `generate.py`:

```bash
python services/generate.py NGA 1 2015 2020 \
--shape-source unocha \
--shapes-url http://<unocha-ip> \
--worldpop-url http://<worldpop-ip> \
--unwpp-url http://<unwpp-ip> \
--emit-scripts
```

---

## Update a service

```bash
make push-worldpop TAG=v0.5.2a
kubectl set image deployment/laser-worldpop-svc \
laser-worldpop-svc=idm-docker-staging.packages.idmod.org/laser-worldpop-service:v0.5.2a \
-n laser-ai --kubeconfig AKS/kube.conf
kubectl rollout status deployment/laser-worldpop-svc -n laser-ai --kubeconfig AKS/kube.conf
```

## Rollback

```bash
kubectl rollout undo deployment/laser-worldpop-svc -n laser-ai --kubeconfig AKS/kube.conf
```

## Tail logs

```bash
kubectl logs -f deployment/laser-worldpop-svc -n laser-ai --kubeconfig AKS/kube.conf
```

## Tear down (preserves PVCs and cached data)

```bash
kubectl delete deployments,services \
laser-unwpp-svc laser-gadm-svc laser-geoboundaries-svc laser-unocha-svc laser-worldpop-svc \
-n laser-ai --kubeconfig AKS/kube.conf
```

To also delete the cached data (irreversible):

```bash
kubectl delete pvc \
laser-unwpp-cache laser-gadm-cache laser-geoboundaries-cache \
laser-unocha-cache laser-worldpop-cache \
-n laser-ai --kubeconfig AKS/kube.conf
```

---

## Image Tagging Convention

Matches the jenner-mcp pattern: `v0.<month>.<day><letter>`

Examples: `v0.5.1a`, `v0.5.7b`
Loading
Loading