diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..d55e8df --- /dev/null +++ b/.dockerignore @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: Apache-2.0 +# Docker build context exclusions + +# Git +.git +.github +.gitignore + +# Documentation +*.md +docs/ +LICENSE +NOTICE.md + +# MongoDB data (should use volumes, not baked in) +mongodb/db/ + +# IDE +.vscode/ +.idea/ +*.iml + +# OS +.DS_Store +Thumbs.db diff --git a/.github/workflows/makefile.yml b/.github/workflows/makefile.yml index 516c0b4..91f81cd 100644 --- a/.github/workflows/makefile.yml +++ b/.github/workflows/makefile.yml @@ -2,40 +2,71 @@ name: Makefile CI on: push: - branches: [ "add-license-1" ] + branches: [ "add-license-1", "main" ] pull_request: - branches: [ "add-license-1" ] + branches: [ "add-license-1", "main" ] jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - # - name: configure - # run: ./configure - - name: Install dependencies run: | - sudo apt install git - sudo apt install make - sudo apt install maven - sudo apt install groovy - sudo apt install python3-venv - sudo apt install python3-pip - sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 9DA31620334BD75D9DCB49F368818C72E52529D4 - echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.0.list - sudo apt install mongodb-org + sudo apt-get update + sudo apt-get install -y git make maven groovy python3-venv python3-pip curl + curl -fsSL https://www.mongodb.org/static/pgp/server-6.0.asc | sudo gpg --dearmor -o /usr/share/keyrings/mongodb-server-6.0.gpg + echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-6.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/6.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list + sudo apt-get update + sudo apt-get install -y mongodb-org - name: Build run: make build - + - name: Run - run: make run + run: | + make run + + wait_for_url() { + local url="$1" + local name="$2" + local attempts=18 + local delay=5 + + for ((i=1; i<=attempts; i++)); do + if curl -sf "$url" > /dev/null; then + echo "✓ $name is ready" + return 0 + fi + echo "Waiting for $name ($url) to become ready... attempt $i/$attempts" + sleep "$delay" + done + + echo "✗ Timed out waiting for $name ($url)" + return 1 + } + + wait_for_url "http://localhost:4382/" "Main Controller (4382)" + wait_for_url "http://localhost:4390/" "Emulator (4390)" + + - name: Health check + run: | + echo "Checking service health..." + curl -sf http://localhost:4382/ > /dev/null && echo "✓ Main Controller (4382) is up" || echo "✗ Main Controller (4382) is down" + curl -sf http://localhost:4390/ > /dev/null && echo "✓ Emulator (4390) is up" || echo "✗ Emulator (4390) is down" + curl -sf http://localhost:10000/ > /dev/null && echo "✓ Tester (10000) is up" || echo "✗ Tester (10000) is down" + curl -sf http://localhost:8000/static/ui_example/staff/visual.html > /dev/null && echo "✓ Service Center (8000) is up" || echo "✗ Service Center (8000) is down" + # Fail the job if any service is not responding + curl -sf http://localhost:4382/ > /dev/null + curl -sf http://localhost:4390/ > /dev/null + curl -sf http://localhost:10000/ > /dev/null + curl -sf http://localhost:8000/static/ui_example/staff/visual.html > /dev/null - name: Stop + if: always() run: make stop diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..a9046b2 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: Apache-2.0 +# Docker Compose for APIS (Autonomous Power Interchange System) +# +# Usage: +# docker compose up --build # Build from source and start +# docker compose up -d # Start in detached mode +# docker compose down # Stop all services +# docker compose logs -f apis # Follow APIS logs + +services: + mongodb: + image: mongo:6.0 + container_name: apis-mongodb + ports: + - "27017:27017" + volumes: + - mongodb_data:/data/db + healthcheck: + test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 10s + restart: unless-stopped + + apis: + build: + context: . + dockerfile: docker/Dockerfile + container_name: apis-app + depends_on: + mongodb: + condition: service_healthy + ports: + - "4382:4382" + - "4390:4390" + - "8000:8000" + - "10000:10000" + environment: + - MONGODB_HOST=mongodb + - MONGODB_PORT=27017 + restart: unless-stopped + +volumes: + mongodb_data: + driver: local diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..ad5ef18 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,98 @@ +# SPDX-License-Identifier: Apache-2.0 +# Multi-stage Dockerfile for APIS (Autonomous Power Interchange System) +# Builds all services from source for full reproducibility. + +# ============================================================================== +# Stage 1: Builder - Compile Java services and prepare Python virtual environments +# ============================================================================== +FROM ubuntu:20.04 AS builder + +ENV DEBIAN_FRONTEND=noninteractive +ENV TZ=Asia/Tokyo + +RUN apt-get update && apt-get install -y --no-install-recommends \ + git \ + make \ + maven \ + groovy \ + python3-venv \ + python3-pip \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /build + +# Clone and build all sub-repositories using the Makefile orchestrator +COPY Makefile runner.sh ./ + +# Clone all repositories +RUN make apis-bom apis-common apis-main apis-ccc apis-log apis-web \ + apis-emulator apis-main_controller apis-service_center apis-tester + +# Build Java dependencies first (order matters) +RUN cd apis-bom && make install +RUN cd apis-common && make install + +# Build Java services (produces fat JARs) +RUN cd apis-main && make package +RUN cd apis-ccc && make package +RUN cd apis-log && make package +RUN cd apis-web && make package + +# Build Python services (create virtual environments) +RUN cd apis-emulator && sh venv.sh +RUN cd apis-main_controller && sh venv.sh +RUN cd apis-service_center && sh venv.sh && sh initdb.sh +RUN cd apis-tester && sh venv.sh + +# ============================================================================== +# Stage 2: Runtime - Lean image with only what's needed to run +# ============================================================================== +FROM ubuntu:20.04 AS runtime + +ENV DEBIAN_FRONTEND=noninteractive +ENV TZ=Asia/Tokyo + +RUN apt-get update && apt-get install -y --no-install-recommends \ + default-jre-headless \ + python3 \ + python3-venv \ + curl \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /APIS + +# Copy built artifacts from builder +COPY --from=builder /build/apis-main /APIS/apis-main +COPY --from=builder /build/apis-ccc /APIS/apis-ccc +COPY --from=builder /build/apis-log /APIS/apis-log +COPY --from=builder /build/apis-web /APIS/apis-web +COPY --from=builder /build/apis-emulator /APIS/apis-emulator +COPY --from=builder /build/apis-main_controller /APIS/apis-main_controller +COPY --from=builder /build/apis-service_center /APIS/apis-service_center +COPY --from=builder /build/apis-tester /APIS/apis-tester + +# Copy orchestration files +COPY Makefile runner.sh mongodb/ /APIS/ + +# Fix MongoDB port in service_center demo settings (27018 -> 27017) +RUN for settings_file in \ + /APIS/apis-service_center/config/settings/apis_service_center_demo.py \ + /APIS/apis-service_center/config/settings/apis-service_center-demo.py; do \ + if [ -f "$settings_file" ]; then \ + sed -i 's/27018/27017/g' "$settings_file"; \ + fi; \ + done + +# Expose all service ports +EXPOSE 4382 4390 8000 10000 + +# Health check against the main controller +HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ + CMD curl -f http://localhost:4382/ || exit 1 + +# Entrypoint script to start all services +COPY docker/entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100644 index 0000000..1ed9ac4 --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,120 @@ +#!/bin/bash +# SPDX-License-Identifier: Apache-2.0 +# Entrypoint script for APIS container +# Starts all services and keeps the container running + +set -e + +APIS_DIR="/APIS" +cd "$APIS_DIR" + +echo "========================================" +echo " APIS - Autonomous Power Interchange System" +echo " Starting all services..." +echo "========================================" + +# Start apis-service_center (Django) +echo "[1/8] Starting apis-service_center on port 8000..." +cd "$APIS_DIR/apis-service_center" +. venv/bin/activate +python3 -m gunicorn config.wsgi:application --bind 0.0.0.0:8000 --env DJANGO_SETTINGS_MODULE=config.settings.apis_service_center_demo & +deactivate 2>/dev/null || true + +# Start apis-emulator +echo "[2/8] Starting apis-emulator on port 4390..." +cd "$APIS_DIR/apis-emulator" +. venv/bin/activate +python3 ./startEmul.py 4 & +deactivate 2>/dev/null || true + +# Start apis-main instances (4 nodes) +echo "[3/8] Starting apis-main (4 instances)..." +cd "$APIS_DIR/apis-main/exe" +java -Djava.net.preferIPv4Stack=true -Duser.timezone=Asia/Tokyo \ + -Djava.util.logging.config.file=./logging.properties \ + -Dvertx.hazelcast.config=./cluster.xml \ + -jar ../target/apis-main-3.0.0-fat.jar -conf ./config.json \ + -cluster -cluster-host 127.0.0.1 & + +java -Djava.net.preferIPv4Stack=true -Duser.timezone=Asia/Tokyo \ + -Djava.util.logging.config.file=./logging.properties \ + -Dvertx.hazelcast.config=./cluster.xml \ + -jar ../target/apis-main-3.0.0-fat.jar -conf ./config2.json \ + -cluster -cluster-host 127.0.0.1 & + +java -Djava.net.preferIPv4Stack=true -Duser.timezone=Asia/Tokyo \ + -Djava.util.logging.config.file=./logging.properties \ + -Dvertx.hazelcast.config=./cluster.xml \ + -jar ../target/apis-main-3.0.0-fat.jar -conf ./config3.json \ + -cluster -cluster-host 127.0.0.1 & + +java -Djava.net.preferIPv4Stack=true -Duser.timezone=Asia/Tokyo \ + -Djava.util.logging.config.file=./logging.properties \ + -Dvertx.hazelcast.config=./cluster.xml \ + -jar ../target/apis-main-3.0.0-fat.jar -conf ./config4.json \ + -cluster -cluster-host 127.0.0.1 & + +# Start apis-ccc +echo "[4/8] Starting apis-ccc..." +cd "$APIS_DIR/apis-ccc/exe" +java -Djava.net.preferIPv4Stack=true -Duser.timezone=Asia/Tokyo \ + -Djava.util.logging.config.file=./logging.properties \ + -Dvertx.hazelcast.config=./cluster.xml \ + -jar ../target/apis-ccc-3.0.0-fat.jar -conf ./config.json \ + -cluster -cluster-host 127.0.0.1 & + +# Start apis-log +echo "[5/8] Starting apis-log..." +cd "$APIS_DIR/apis-log/exe" +java -Djava.net.preferIPv4Stack=true -Duser.timezone=Asia/Tokyo \ + -Djava.util.logging.config.file=./logging.properties \ + -jar ../target/apis-log-3.0.0-fat.jar -conf ./config.json & + +# Start apis-web +echo "[6/8] Starting apis-web..." +cd "$APIS_DIR/apis-web/exe" +java -Djava.net.preferIPv4Stack=true -Duser.timezone=Asia/Tokyo \ + -Djava.util.logging.config.file=./logging.properties \ + -Dvertx.hazelcast.config=./cluster.xml \ + -jar ../target/apis-web-3.0.0-fat.jar run \ + jp.co.sony.csl.dcoes.apis.tools.web.util.Starter \ + --conf ./config.json --cluster --cluster-host 127.0.0.1 & + +# Start apis-main_controller +echo "[7/8] Starting apis-main_controller on port 4382..." +cd "$APIS_DIR/apis-main_controller" +. venv/bin/activate +python3 ./startMain.py & +deactivate 2>/dev/null || true + +# Start apis-tester +echo "[8/8] Starting apis-tester on port 10000..." +cd "$APIS_DIR/apis-tester" +. venv/bin/activate +python3 ./startTester.py & +deactivate 2>/dev/null || true + +echo "========================================" +echo " All services started!" +echo " Dashboard: http://localhost:4382" +echo " Emulator: http://localhost:4390" +echo " Tester: http://localhost:10000" +echo " Admin Panel: http://localhost:8000/static/ui_example/staff/visual.html" +echo "========================================" + +terminate_children() { + local pids + pids="$(jobs -pr)" + if [ -n "$pids" ]; then + kill -TERM $pids 2>/dev/null || true + fi +} + +trap 'terminate_children; wait || true; exit 143' TERM INT + +# Keep the container running, forward signals, and exit if any service stops +wait -n +status=$? +terminate_children +wait || true +exit "$status" diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md new file mode 100644 index 0000000..81fe5a2 --- /dev/null +++ b/docs/DEVELOPMENT.md @@ -0,0 +1,112 @@ +## 🛠️ Development Guide + +This guide covers local development setup for contributors. + +### Prerequisites + +| Tool | Version | Purpose | +|------|---------|---------| +| **Docker** | 20.10+ | Container runtime | +| **Docker Compose** | v2.0+ | Service orchestration | +| **Git** | 2.30+ | Version control | + +Optional (for native development without Docker): +- **JDK** 11+ and **Maven** 3.6+ +- **Groovy** 2.5+ +- **Python** 3.8+ with `python3-venv` +- **MongoDB** 6.0+ + +--- + +### Running with Docker Compose + +```bash +# Build from source and start all services +docker compose up --build + +# Run in detached mode +docker compose up --build -d + +# View logs +docker compose logs -f apis + +# Stop everything +docker compose down + +# Stop and clean volumes +docker compose down -v +``` + +### Running Natively + +See [Host Installation](INSTALL_HOST.md) for native setup instructions. + +```bash +# Build all components +make build + +# Start all services (requires MongoDB running on port 27017) +make run + +# Stop all services +make stop +``` + +--- + +### Project Architecture + +``` +APIS/ # Orchestrator repository +├── Makefile # Build/run/stop orchestrator +├── docker-compose.yml # Docker Compose configuration +├── docker/ +│ ├── Dockerfile # Multi-stage build +│ └── entrypoint.sh # Service startup script +├── mongodb/ # MongoDB scripts +├── apis-bom/ # [Java] Bill of Materials +├── apis-common/ # [Java] Shared libraries +├── apis-main/ # [Java/Vert.x] Core energy exchange engine +├── apis-ccc/ # [Java/Vert.x] Cluster coordination +├── apis-log/ # [Java] Log aggregation +├── apis-web/ # [Java/Vert.x] Web API layer +├── apis-emulator/ # [Python] Hardware simulator +├── apis-main_controller/ # [Python] Dashboard UI +├── apis-service_center/ # [Python/Django] Admin panel +└── apis-tester/ # [Python] Test framework +``` + +### Service Ports + +| Port | Service | Protocol | +|------|---------|----------| +| 4382 | Main Controller | HTTP | +| 4390 | Emulator | HTTP | +| 8000 | Service Center | HTTP | +| 10000 | Tester | HTTP | +| 27017 | MongoDB | TCP | + +### Build Order + +Java services must be built in order: + +1. `apis-bom` (Maven BOM — install first) +2. `apis-common` (Shared library — install second) +3. `apis-main`, `apis-ccc`, `apis-log`, `apis-web` (Can build in parallel) +4. Python services (`apis-emulator`, `apis-main_controller`, `apis-service_center`, `apis-tester`) can build in parallel + +--- + +### Troubleshooting + +**Port conflicts:** Ensure ports 4382, 4390, 8000, 10000, and 27017 are not in use. + +**Docker build fails:** Clear Docker cache and rebuild: +```bash +docker compose build --no-cache +``` + +**Services not connecting:** Services may take 30-60 seconds to fully start due to Hazelcast cluster formation. Check logs: +```bash +docker compose logs -f apis +``` diff --git a/docs/INSTALL_DOCKER.md b/docs/INSTALL_DOCKER.md index 1bfe1eb..7c7e58f 100644 --- a/docs/INSTALL_DOCKER.md +++ b/docs/INSTALL_DOCKER.md @@ -1,6 +1,44 @@ ## 💻 Docker Installation & Troubleshooting Guide -### 1. Environment Setup +### Quick Start (Recommended) + +The fastest way to get APIS running is with Docker Compose, which handles MongoDB and all services automatically: + +```bash +# Clone the repository +git clone https://github.com/hyphae/APIS.git +cd APIS + +# Build and start everything +docker compose up --build +``` + +**That's it!** Once the build completes, access the web interfaces: + +| Service | URL | +|---------|-----| +| **Main Controller** | http://localhost:4382 | +| **Emulator** | http://localhost:4390 | +| **Tester** | http://localhost:10000 | +| **Service Center** | http://localhost:8000/static/ui_example/staff/visual.html | + +To stop all services: +```bash +docker compose down +``` + +To stop and remove all data (including MongoDB): +```bash +docker compose down -v +``` + +--- + +### Manual Setup (Alternative) + +If you prefer manual control over the environment, follow the steps below. + +#### 1. Environment Setup The environment is containerized to ensure consistency and avoid host machine dependency issues. You must map the required ports during the initial run to access the web interfaces later. diff --git a/mongodb/start.sh b/mongodb/start.sh index fe46dc0..5d4a223 100644 --- a/mongodb/start.sh +++ b/mongodb/start.sh @@ -4,6 +4,6 @@ echo 'call start.sh' cd $(dirname "${0}") -mongod --dbpath ./db --port 27018 --bind_ip_all +mongod --dbpath ./db --port 27017 --bind_ip_all echo '... done' diff --git a/mongodb/stop.sh b/mongodb/stop.sh index 318bc44..0d925f9 100644 --- a/mongodb/stop.sh +++ b/mongodb/stop.sh @@ -4,7 +4,7 @@ echo 'call stop.sh' get_pids() { - ps -f -U $(whoami) | grep mongod | grep 'port 27018' | while read _USER_ _PID_ _OTHERS_ ; do + ps -f -U $(whoami) | grep mongod | grep 'port 27017' | while read _USER_ _PID_ _OTHERS_ ; do echo $_PID_ done }