Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
22 changes: 22 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Docker Compose profile selector: dev | prod
COMPOSE_PROFILES=dev

# Frontend API base URL used at build time
VITE_API_BASE_URL_DEV=http://localhost:8000
VITE_API_BASE_URL_PROD=/api

# Backend CORS policies
CORS_ALLOW_ORIGINS_DEV=http://localhost,http://localhost:80,http://localhost:5173,http://127.0.0.1,http://127.0.0.1:80,http://127.0.0.1:5173
CORS_ALLOW_ORIGINS_PROD=https://openbinding.score.us.es,https://openbinding.us.es

# TLS certificates directory for production nginx
# This directory must contain:
# - fullchain.pem
# - privkey.pem
NGINX_SSL_DIR=./nginx/ssl

# Optional corporate proxy (primarily used during Docker build)
# Leave empty if you are not behind a proxy.
HTTP_PROXY_ARG=
HTTPS_PROXY_ARG=
NO_PROXY_ARG=localhost,127.0.0.1,gateway,gateway-dev,engine-minizinc,engine-random-search,engine-many-heuristic,frontend-dev,frontend-prod,nginx,nginx-dev
22 changes: 16 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,32 @@ on:
jobs:
test:
runs-on: ubuntu-latest
env:
COMPOSE_PROFILES: dev

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker Compose
- name: Prepare environment
run: |
sudo apt-get update
sudo apt-get install -y docker-compose
if [ ! -f .env ]; then
cp .env.example .env
fi

- name: Validate Docker Compose configuration
run: docker compose config

- name: Build and start services
run: docker-compose up --build -d
run: docker compose up --build -d --wait gateway-dev

- name: Run Tests
run: docker-compose exec -T gateway test
run: docker compose exec -T gateway-dev test

- name: Show service logs on failure
if: failure()
run: docker compose logs --no-color gateway-dev engine-minizinc engine-random-search engine-many-heuristic

- name: Shutdown services
if: always()
run: docker-compose down
run: docker compose down --volumes --remove-orphans
41 changes: 29 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,19 +102,36 @@ Example payloads that follow these schemas live in `examples/`.

### Installation & Running

1. **Start the Stack**:
1. **Configure environment variables**:
```bash
docker compose up --build
cp .env.example .env
```

The services will be available at:
* **Frontend**: [http://localhost:80](http://localhost:80)
* **Gateway API**: [http://localhost:8000/docs](http://localhost:8000/docs)
* **MiniZinc Engine**: Port 3000 (Internal)
* **Random Search Engine**: Port 8081 (Internal)
* **Many-Heuristic Engine**: Port 8082 (Internal)
2. **Start development stack**:
```bash
COMPOSE_PROFILES=dev docker compose up --build
```

Development services:
* **Nginx (local)**: [http://localhost:80](http://localhost:80)
* **Frontend dev server**: [http://localhost:5173](http://localhost:5173)
* **Gateway API docs**: [http://localhost:8000/docs](http://localhost:8000/docs)

3. **Start production stack**:
```bash
COMPOSE_PROFILES=prod docker compose up --build -d
```

Production notes:
* **Nginx** listens on ports **80/443**.
* `frontend-prod` generates static assets; only Nginx serves them publicly.
* Configure DNS for `openbinding.score.us.es` and `openbinding.us.es`.
* Place TLS files in `nginx/ssl/` (or override `NGINX_SSL_DIR`) with names:
- `fullchain.pem`
- `privkey.pem`
* Gateway is exposed only internally behind Nginx.

2. **Stop the Stack**:
4. **Stop the Stack**:
```bash
docker compose down
```
Expand Down Expand Up @@ -182,13 +199,13 @@ To run the complete test suite in the Docker environment:

```bash
# 1. Ensure stack is running
docker compose up -d
COMPOSE_PROFILES=dev docker compose up -d

# 2. Run all tests
docker compose exec gateway test
docker compose exec gateway-dev test

# 3. Run specific test file
docker compose exec gateway test tests/test_analysis.py -v
docker compose exec gateway-dev test tests/test_analysis.py -v
```

### Running Tests (Local)
Expand Down
137 changes: 129 additions & 8 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,62 @@
x-proxy-build-args: &proxy-build-args
HTTP_PROXY: ${HTTP_PROXY_ARG:-}
HTTPS_PROXY: ${HTTPS_PROXY_ARG:-}
NO_PROXY: ${NO_PROXY_ARG:-localhost,127.0.0.1,gateway,gateway-dev,engine-minizinc,engine-random-search,engine-many-heuristic,frontend-dev,frontend-prod,nginx,nginx-dev}

services:
gateway:
build:
context: ./openbinding-gateway
dockerfile: Dockerfile
args:
<<: *proxy-build-args
profiles: ["prod"]
volumes:
- ./schemas:/app/schemas
- ./openbinding-gateway:/app
- ./examples/generated_instances:/app/examples/generated_instances
environment:
- APP_ENV=prod
- GENERAL_SCHEMA_PATH=/app/schemas/general/schema.json
- SCHEMAS_DIR=/app/schemas
- PYTHONPATH=/app/src
- CORS_ALLOW_ORIGINS=${CORS_ALLOW_ORIGINS_PROD:-https://openbinding.score.us.es,https://openbinding.us.es}
- ENGINE_MINIZINC_URL=http://engine-minizinc:3000
- ENGINE_RANDOM_SEARCH_URL=http://engine-random-search:8080
- ENGINE_MANY_HEURISTIC_URL=http://engine-many-heuristic:8080
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost:8000/health"]
interval: 10s
timeout: 3s
retries: 5
start_period: 10s
depends_on:
engine-minizinc:
condition: service_healthy
engine-random-search:
condition: service_healthy
engine-many-heuristic:
condition: service_healthy

gateway-dev:
build:
context: ./openbinding-gateway
dockerfile: Dockerfile
args:
<<: *proxy-build-args
profiles: ["dev"]
ports:
- "8000:8000"
volumes:
- ./schemas:/app/schemas
- ./openbinding-gateway:/app
- ./examples/generated_instances:/app/examples/generated_instances
environment:
- APP_ENV=dev
- GENERAL_SCHEMA_PATH=/app/schemas/general/schema.json
- SCHEMAS_DIR=/app/schemas
- PYTHONPATH=/app/src
- CORS_ALLOW_ORIGINS=${CORS_ALLOW_ORIGINS_DEV:-http://localhost,http://localhost:80,http://localhost:5173,http://127.0.0.1,http://127.0.0.1:80,http://127.0.0.1:5173}
- ENGINE_MINIZINC_URL=http://engine-minizinc:3000
- ENGINE_RANDOM_SEARCH_URL=http://engine-random-search:8080
- ENGINE_MANY_HEURISTIC_URL=http://engine-many-heuristic:8080
Expand All @@ -34,8 +78,9 @@ services:
build:
context: ./engines/minizinc-csp
dockerfile: Dockerfile
ports:
- "3000:3000"
args:
<<: *proxy-build-args
profiles: ["dev", "prod"]
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost:3000/health"]
interval: 10s
Expand All @@ -47,8 +92,9 @@ services:
build:
context: ./engines/random-search
dockerfile: Dockerfile
ports:
- "8081:8080"
args:
<<: *proxy-build-args
profiles: ["dev", "prod"]
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost:8080/health"]
interval: 10s
Expand All @@ -60,29 +106,104 @@ services:
build:
context: ./engines/many-heuristic
dockerfile: Dockerfile
ports:
- "8082:8080"
args:
<<: *proxy-build-args
profiles: ["dev", "prod"]
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost:8080/health"]
interval: 10s
timeout: 3s
retries: 5
start_period: 30s

frontend:
frontend-dev:
build:
context: ./frontend
dockerfile: Dockerfile
target: dev
args:
<<: *proxy-build-args
VITE_API_BASE_URL: ${VITE_API_BASE_URL_DEV:-http://localhost:8000}
profiles: ["dev"]
ports:
- "5173:5173"
depends_on:
gateway-dev:
condition: service_healthy
healthcheck:
test: ["CMD", "node", "-e", "require('http').get('http://127.0.0.1:5173/', (r) => process.exit(r.statusCode >= 200 && r.statusCode < 500 ? 0 : 1)).on('error', () => process.exit(1))"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s

frontend-prod:
build:
context: ./frontend
dockerfile: Dockerfile
target: prod-assets
args:
<<: *proxy-build-args
VITE_API_BASE_URL: ${VITE_API_BASE_URL_PROD:-/api}
profiles: ["prod"]
volumes:
- frontend_dist:/out
command: ["sh", "-c", "rm -rf /out/* && cp -a /dist/. /out/ && tail -f /dev/null"]
healthcheck:
test: ["CMD", "test", "-f", "/out/index.html"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s

nginx-dev:
build:
context: ./nginx/local
dockerfile: Dockerfile
args:
<<: *proxy-build-args
profiles: ["dev"]
ports:
- "80:80"
volumes:
- ./examples:/usr/share/nginx/html/examples:ro
depends_on:
gateway-dev:
condition: service_healthy
frontend-dev:
condition: service_healthy
healthcheck:
test: ["CMD", "nginx", "-t"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s

nginx:
build:
context: ./nginx/production
dockerfile: Dockerfile
args:
<<: *proxy-build-args
profiles: ["prod"]
ports:
- "80:80"
- "443:443"
volumes:
- frontend_dist:/usr/share/nginx/html:ro
- ./examples:/opt/openbinding/examples:ro
- ${NGINX_SSL_DIR:-./nginx/ssl}:/etc/nginx/ssl:ro
depends_on:
gateway:
condition: service_healthy
frontend-prod:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost/"]
test: ["CMD", "nginx", "-t"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s

volumes:
frontend_dist:
30 changes: 29 additions & 1 deletion engines/many-heuristic/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,39 @@
FROM maven:3.8-openjdk-8 as builder
ARG HTTP_PROXY
ARG HTTPS_PROXY
ARG NO_PROXY
ENV HTTP_PROXY=$HTTP_PROXY \
HTTPS_PROXY=$HTTPS_PROXY \
NO_PROXY=$NO_PROXY \
http_proxy=$HTTP_PROXY \
https_proxy=$HTTPS_PROXY \
no_proxy=$NO_PROXY

WORKDIR /app
COPY pom.xml .
COPY src ./src
# COPY lib ./lib # No lib present or empty
RUN mvn package -DskipTests
RUN mvn -DskipTests \
-Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false \
-Dhttp.proxyHost=$(echo "$HTTP_PROXY" | sed -E 's#^https?://([^:/]+).*$#\1#') \
-Dhttp.proxyPort=$(echo "$HTTP_PROXY" | sed -E 's#^https?://[^:/]+:([0-9]+).*$#\1#') \
-Dhttps.proxyHost=$(echo "$HTTPS_PROXY" | sed -E 's#^https?://([^:/]+).*$#\1#') \
-Dhttps.proxyPort=$(echo "$HTTPS_PROXY" | sed -E 's#^https?://[^:/]+:([0-9]+).*$#\1#') \
-Dhttp.nonProxyHosts="localhost|127.0.0.1|*.int.local|10.*|192.168.*|172.16.*" \
package

FROM eclipse-temurin:8-jre
ARG HTTP_PROXY
ARG HTTPS_PROXY
ARG NO_PROXY

ENV HTTP_PROXY=$HTTP_PROXY \
HTTPS_PROXY=$HTTPS_PROXY \
NO_PROXY=$NO_PROXY \
http_proxy=$HTTP_PROXY \
https_proxy=$HTTPS_PROXY \
no_proxy=$NO_PROXY

WORKDIR /app
RUN apt-get update && apt-get install -y --no-install-recommends curl && rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/ManyHeuristicQoSawareCWSBinding-0.0.1-SNAPSHOT.jar app.jar
Expand Down
Loading