From 9190540120142d35595ac31b56100c66c3d709b4 Mon Sep 17 00:00:00 2001 From: fe51 <55736935+fe51@users.noreply.github.com> Date: Thu, 19 Mar 2026 12:28:26 +0100 Subject: [PATCH 1/6] minio clean up with stop --- data/minio/admin/.gitkeep | 0 data/minio/occlusion-masks/.gitkeep | 0 docker-compose.yml | 5 ++++- 3 files changed, 4 insertions(+), 1 deletion(-) delete mode 100644 data/minio/admin/.gitkeep delete mode 100644 data/minio/occlusion-masks/.gitkeep diff --git a/data/minio/admin/.gitkeep b/data/minio/admin/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/data/minio/occlusion-masks/.gitkeep b/data/minio/occlusion-masks/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/docker-compose.yml b/docker-compose.yml index 6abde8b..ac166bd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -49,7 +49,7 @@ services: - MINIO_ROOT_USER=${S3_ACCESS_KEY} - MINIO_ROOT_PASSWORD=${S3_SECRET_KEY} volumes: - - ./data/minio:/data + - minio_data:/data command: server /data --console-address ":9001" healthcheck: test: ["CMD", "mc", "ready", "local"] @@ -179,3 +179,6 @@ services: - PGADMIN_DEFAULT_PASSWORD=${DB_UI_PWD} depends_on: - db + +volumes: + minio_data: From 44b7707e50302eb89c3320d8d7c14a70cbf22750 Mon Sep 17 00:00:00 2001 From: fe51 <55736935+fe51@users.noreply.github.com> Date: Thu, 19 Mar 2026 12:29:27 +0100 Subject: [PATCH 2/6] remove mock reolink cam services --- containers/reolinkdev1/Dockerfile | 23 ------- containers/reolinkdev1/reolinkdev1.py | 83 ------------------------ containers/reolinkdev2/Dockerfile | 23 ------- containers/reolinkdev2/reolinkdev2.py | 90 --------------------------- docker-compose.yml | 32 ---------- 5 files changed, 251 deletions(-) delete mode 100644 containers/reolinkdev1/Dockerfile delete mode 100644 containers/reolinkdev1/reolinkdev1.py delete mode 100644 containers/reolinkdev2/Dockerfile delete mode 100644 containers/reolinkdev2/reolinkdev2.py diff --git a/containers/reolinkdev1/Dockerfile b/containers/reolinkdev1/Dockerfile deleted file mode 100644 index 248281c..0000000 --- a/containers/reolinkdev1/Dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -# Use the official Python image as the base image -FROM python:3.9-slim - -# hadolint ignore=DL3008 -RUN apt-get update \ - && apt-get install -y --no-install-recommends curl \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* - -# Set the working directory in the container -WORKDIR /app - -# Install dependencies -RUN pip install --no-cache-dir flask==3.0.3 - -# Copy the Flask server files into the container -COPY reolinkdev1.py /app/ - -# Expose port 5000 for Flask server -EXPOSE 443 - -# Command to run the Flask server -CMD ["python", "/app/reolinkdev1.py"] diff --git a/containers/reolinkdev1/reolinkdev1.py b/containers/reolinkdev1/reolinkdev1.py deleted file mode 100644 index f8ae60a..0000000 --- a/containers/reolinkdev1/reolinkdev1.py +++ /dev/null @@ -1,83 +0,0 @@ -import os -from flask import Flask, request, send_file -from urllib.request import urlretrieve - -app = Flask(__name__) - -username = os.environ.get("CAM_USER") -password = os.environ.get("CAM_PWD") - - -def generate_ssl_certificates(): - # Generate a private key - os.system("openssl genrsa -out key.pem 2048") - - # Generate a Certificate Signing Request (CSR) non-interactively - os.system("openssl req -new -key key.pem -out csr.pem -subj '/CN=reolinkdev1'") - - # Generate a self-signed certificate - os.system("openssl x509 -req -days 365 -in csr.pem -signkey key.pem -out cert.pem") - - # Remove the CSR file - os.system("rm csr.pem") - - -# Call the function to generate SSL certificates -generate_ssl_certificates() - -# Get a list of image filenames in the directory -image_dir = "data/images" -images_name = [ - "1465065360_-00240.jpg", - "1465065780_+00180.jpg", - "1465066800_+01200.jpg", - "1465066800_+01800.jpg", - "1465068000_+02400.jpg", -] -url = "https://github.com/pyronear/pyro-devops/releases/download/v0.0.1/" - -if not os.path.isfile(image_dir): - os.makedirs(image_dir, exist_ok=True) - for name in images_name: - print(f"Downloading images from {url + name} ...") - urlretrieve(url + name, image_dir + "/" + name) - -image_files = [ - f for f in os.listdir(image_dir) if os.path.isfile(os.path.join(image_dir, f)) -] -num_images = len(image_files) -current_index = 0 - - -@app.route("/cgi-bin/api.cgi") -def capture(): - global current_index - - # Get username and password from the URL query parameters - user = request.args.get("user") - passwd = request.args.get("password") - - # Check if username and password match - if user == username and passwd == password: - # Get the path to the current image - image_path = os.path.join(image_dir, image_files[current_index]) - current_index = (current_index + 1) % num_images # Move to the next image - - return send_file(image_path, mimetype="image/jpeg") - else: - return "Unauthorized", 401 - - -@app.route("/health") -def health_check(): - # Return a 200 OK response if the application is healthy - return "OK", 200 - - -if __name__ == "__main__": - app.run( - host="0.0.0.0", - ssl_context=("cert.pem", "key.pem"), - port=443, - debug=True, - ) diff --git a/containers/reolinkdev2/Dockerfile b/containers/reolinkdev2/Dockerfile deleted file mode 100644 index e9b4673..0000000 --- a/containers/reolinkdev2/Dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -# Use the official Python image as the base image -FROM python:3.9-slim - -# hadolint ignore=DL3008 -RUN apt-get update \ - && apt-get install -y --no-install-recommends curl \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* - -# Set the working directory in the container -WORKDIR /app - -# Install dependencies -RUN pip install --no-cache-dir flask==3.0.3 - -# Copy the Flask server files into the container -COPY reolinkdev2.py /app/ - -# Expose port 5000 for Flask server -EXPOSE 443 - -# Command to run the Flask server -CMD ["python", "/app/reolinkdev2.py"] diff --git a/containers/reolinkdev2/reolinkdev2.py b/containers/reolinkdev2/reolinkdev2.py deleted file mode 100644 index dc9677d..0000000 --- a/containers/reolinkdev2/reolinkdev2.py +++ /dev/null @@ -1,90 +0,0 @@ -import os -from flask import Flask, request, send_file -from urllib.request import urlretrieve - -app = Flask(__name__) - -username = os.environ.get("CAM_USER") -password = os.environ.get("CAM_PWD") - - -def generate_ssl_certificates(): - # Generate a private key - os.system("openssl genrsa -out key.pem 2048") - - # Generate a Certificate Signing Request (CSR) non-interactively - os.system("openssl req -new -key key.pem -out csr.pem -subj '/CN=reolinkdev2'") - - # Generate a self-signed certificate - os.system("openssl x509 -req -days 365 -in csr.pem -signkey key.pem -out cert.pem") - - # Remove the CSR file - os.system("rm csr.pem") - - -# Call the function to generate SSL certificates -generate_ssl_certificates() - -# Get a list of image filenames in the directory -image_dir = "data/images" -images_name = [ - "1465065360_-00240.jpg", - "1465065780_+00180.jpg", - "1465066800_+01200.jpg", - "1465066800_+01800.jpg", - "1465068000_+02400.jpg", -] -url = "https://github.com/pyronear/pyro-envdev/releases/download/v0.0.1/" - -if not os.path.isfile(image_dir): - os.makedirs(image_dir, exist_ok=True) - for name in images_name: - print(f"Downloading images from {url + name} ...") - urlretrieve(url + name, image_dir + "/" + name) - -image_files = [ - f for f in os.listdir(image_dir) if os.path.isfile(os.path.join(image_dir, f)) -] -num_images = len(image_files) -current_index = 0 - - -@app.route("/cgi-bin/api.cgi") -def capture(): - global current_index - - # Get username and password from the URL query parameters - user = request.args.get("user") - passwd = request.args.get("password") - - # Check if username and password match - if user == username and passwd == password: - # Get the path to the current image - image_path = os.path.join(image_dir, image_files[current_index]) - current_index = (current_index + 1) % num_images # Move to the next image - - return send_file(image_path, mimetype="image/jpeg") - else: - return "Unauthorized", 401 - - -@app.route("/cgi-bin/api.cgi", methods=["POST"]) -def capture_post(): - return [ - {"code": 0, "message": "Success", "data": {"id": 123, "name": "Sample Data"}} - ], 200 - - -@app.route("/health") -def health_check(): - # Return a 200 OK response if the application is healthy - return "OK", 200 - - -if __name__ == "__main__": - app.run( - host="0.0.0.0", - ssl_context=("cert.pem", "key.pem"), - port=443, - debug=True, - ) diff --git a/docker-compose.yml b/docker-compose.yml index ac166bd..a00607c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -78,10 +78,6 @@ services: condition: service_started pyro_api: condition: service_healthy - reolinkdev1: - condition: service_healthy - reolinkdev2: - condition: service_healthy etl_scripts: container_name: etl image: pyronear/pyro-etl:latest @@ -113,34 +109,6 @@ services: depends_on: pyro_api: condition: service_healthy - reolinkdev1: - image: pyronear/reolinkdev1:latest - profiles: - - engine - environment: - - CAM_USER=${CAM_USER} - - CAM_PWD=${CAM_PWD} - volumes: - - ./data:/app/data - healthcheck: - test: ["CMD-SHELL", "curl -X 'GET' -k 'https://reolinkdev1/health'"] - interval: 10s - timeout: 10s - retries: 5 - reolinkdev2: - image: pyronear/reolinkdev2:latest - profiles: - - engine - environment: - - CAM_USER=${CAM_USER} - - CAM_PWD=${CAM_PWD} - volumes: - - ./data:/app/data - healthcheck: - test: ["CMD-SHELL", "curl -X 'GET' -k 'https://reolinkdev2/health'"] - interval: 10s - timeout: 10s - retries: 5 frontend: image: pyronear/pyro-platform:latest command: python index.py --host 0.0.0.0 --port 8050 From 831f3a7779f993379f083e08d93cfd91497fc31d Mon Sep 17 00:00:00 2001 From: fe51 <55736935+fe51@users.noreply.github.com> Date: Thu, 19 Mar 2026 12:32:07 +0100 Subject: [PATCH 3/6] updates servics adding camera service and adapt engine --- Makefile | 45 +++++++++++++++++++++++++-------------------- docker-compose.yml | 34 ++++++++++++++++++++++++++++------ 2 files changed, 53 insertions(+), 26 deletions(-) diff --git a/Makefile b/Makefile index ddd9e03..fa4a91f 100644 --- a/Makefile +++ b/Makefile @@ -3,19 +3,21 @@ help: @echo "Targets:" - @echo " init Create .env from .env.test if missing" - @echo " build Build local images in this repo" - @echo " build-external Build images in sibling repos" - @echo " build-all Build local and external images" - @echo " run-backend Start base services only" - @echo " run-engine Start base services plus engine profile" - @echo " run-tools Start base services plus tools profile" - @echo " run Start base services plus front and tools profiles" - @echo " run-all Start base services plus front tools and engine profiles" - @echo " stop Stop and remove all services and volumes" - @echo " ps Show compose status" - @echo " logs Follow logs" - @echo " test Run pytest" + @echo " init Create .env from .env.test if missing" + @echo " build Build local images in this repo" + @echo " build-external Build images in sibling repos" + @echo " build-all Build local and external images" + @echo " run-backend Start base services only" + @echo " run-engine Start base services plus engine profile" + @echo " run-tools-and-engine Start base services plus tools and engine profiles" + @echo " run-tools Start base services plus tools profile" + @echo " run Start base services plus front and tools profiles" + @echo " stop-engine Stop only engine services (engine + pyro_camera_api)" + @echo " restart-engine Restart engine services without re-running init_script" + @echo " stop Stop and remove all services and volumes" + @echo " ps Show compose status" + @echo " logs Follow logs" + @echo " test Run pytest" # ------------------------------------------------------------------- # Init @@ -30,8 +32,6 @@ init: build: docker build -f containers/init_script/Dockerfile -t pyronear/pyro-api-init:latest containers/init_script/ - docker build -f containers/reolinkdev1/Dockerfile -t pyronear/reolinkdev1:latest containers/reolinkdev1/ - docker build -f containers/reolinkdev2/Dockerfile -t pyronear/reolinkdev2:latest containers/reolinkdev2/ docker build -f containers/notebooks/Dockerfile -t pyronear/notebooks:latest containers/notebooks/ # ------------------------------------------------------------------- @@ -42,7 +42,6 @@ build-external: cd ../pyro-api && make build cd ../pyro-engine && make build-lib cd ../pyro-engine && make build-app - cd ../pyro-platform && make build build-all: build build-external @@ -54,10 +53,14 @@ build-all: build build-external run-backend: docker compose up -d -# Engine profile adds pyro_engine, reolinkdev1, reolinkdev2 +# Engine profile adds engine + pyro_camera_api run-engine: docker compose --profile engine up -d +# Tools + engine +run-tools-and-engine: + docker compose --profile tools --profile engine up -d + # Tools profile adds notebooks, db-ui run-tools: docker compose --profile tools up -d @@ -66,9 +69,11 @@ run-tools: run: docker compose --profile front --profile tools up -d -# Everything including engine -run-all: - docker compose --profile front --profile tools --profile engine up -d +stop-engine: + docker compose --profile engine stop engine pyro_camera_api + +restart-engine: stop-engine + docker compose --profile engine up -d engine pyro_camera_api --no-deps stop: docker compose --profile front --profile engine --profile tools down -v diff --git a/docker-compose.yml b/docker-compose.yml index a00607c..dac18b4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -56,18 +56,37 @@ services: interval: 10s timeout: 10s retries: 5 - pyro_engine: - container_name: engine + pyro_camera_api: + image: pyronear/pyro-camera-api:latest + profiles: + - engine + environment: + - CAM_USER=${CAM_USER} + - CAM_PWD=${CAM_PWD} + - MEDIAMTX_SERVER_IP=${MEDIAMTX_SERVER_IP} + volumes: + - ./data:/usr/src/app/data + network_mode: host + logging: + driver: json-file + options: + max-size: 100m + max-file: '5' + depends_on: + init_script: + condition: service_started + engine: image: pyronear/pyro-engine:latest profiles: - engine environment: - - API_URL=${API_URL} - - CAM_USER=${CAM_USER} - - CAM_PWD=${CAM_PWD} + - API_URL=http://localhost:5050 + - CAM_USER=${CAM_USER} + - CAM_PWD=${CAM_PWD} command: python run.py volumes: - - ./data:/usr/src/app/data + - ./data:/usr/src/app/data + network_mode: host logging: driver: json-file options: @@ -78,6 +97,9 @@ services: condition: service_started pyro_api: condition: service_healthy + pyro_camera_api: + condition: service_started + etl_scripts: container_name: etl image: pyronear/pyro-etl:latest From d1eada2d1d2ac1927849d91972d0daae06ceae79 Mon Sep 17 00:00:00 2001 From: fe51 <55736935+fe51@users.noreply.github.com> Date: Thu, 19 Mar 2026 12:34:22 +0100 Subject: [PATCH 4/6] updates credentials --- .env.test | 1 + data/credentials.json | 27 +++++++++------------------ 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/.env.test b/.env.test index 254813f..2253499 100644 --- a/.env.test +++ b/.env.test @@ -1,6 +1,7 @@ API_URL=http://pyro_api:5050 CAM_USER=my_dummy_login CAM_PWD=my_dummy_pwd +MEDIAMTX_SERVER_IP=localhost LOKI_URL=http://my-loki-service.com PROMTAIL_DEVICE_SCOPE=tower_scope diff --git a/data/credentials.json b/data/credentials.json index 61ed6fe..49dfa9b 100644 --- a/data/credentials.json +++ b/data/credentials.json @@ -1,23 +1,14 @@ { - "reolinkdev1": { - "brand": "reolink", - "name": "cam-1", + "mock_camera_1": { + "name": "brison-01", + "adapter": "mock", "type": "static", - "token": "", - "azimuth": 124 - }, - "reolinkdev2": { - "brand": "reolink", - "name": "cam-2", - "type": "ptz", - "token": "", - "poses": [ - 1, - 2 + "pose_ids": [ + 29 ], - "azimuths": [ - 123.2, - 184 - ] + "id": "", + "poses": [], + "bbox_mask_url": "", + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5Iiwic2NvcGVzIjpbImNhbWVyYSJdLCJvcmdhbml6YXRpb25faWQiOjMsImV4cCI6MTgwNTM3NjEzMH0.Vr7GgDsEp1XI4UnXrW1h_yfoJkjcbiAni0SezwqPxq4" } } From 316482de40af5e9025adfde46dc183fa72ca6790 Mon Sep 17 00:00:00 2001 From: fe51 <55736935+fe51@users.noreply.github.com> Date: Fri, 20 Mar 2026 09:16:25 +0100 Subject: [PATCH 5/6] empty token --- data/credentials.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/credentials.json b/data/credentials.json index 49dfa9b..66a096e 100644 --- a/data/credentials.json +++ b/data/credentials.json @@ -9,6 +9,6 @@ "id": "", "poses": [], "bbox_mask_url": "", - "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5Iiwic2NvcGVzIjpbImNhbWVyYSJdLCJvcmdhbml6YXRpb25faWQiOjMsImV4cCI6MTgwNTM3NjEzMH0.Vr7GgDsEp1XI4UnXrW1h_yfoJkjcbiAni0SezwqPxq4" + "token": "" } } From 3c0314ac3eca1aa26fe29aec6fb6e133b1f193cd Mon Sep 17 00:00:00 2001 From: fe51 <55736935+fe51@users.noreply.github.com> Date: Fri, 20 Mar 2026 09:16:50 +0100 Subject: [PATCH 6/6] Removed deps on and updates make --- Makefile | 5 +++-- docker-compose.yml | 10 ---------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index fa4a91f..c57dcda 100644 --- a/Makefile +++ b/Makefile @@ -57,9 +57,10 @@ run-backend: run-engine: docker compose --profile engine up -d -# Tools + engine +# Tools + engine (tools must be up first so the API is ready when engine starts) run-tools-and-engine: - docker compose --profile tools --profile engine up -d + $(MAKE) run-tools + $(MAKE) run-engine # Tools profile adds notebooks, db-ui run-tools: diff --git a/docker-compose.yml b/docker-compose.yml index dac18b4..a03a372 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -72,9 +72,6 @@ services: options: max-size: 100m max-file: '5' - depends_on: - init_script: - condition: service_started engine: image: pyronear/pyro-engine:latest profiles: @@ -92,13 +89,6 @@ services: options: max-size: 100m max-file: '5' - depends_on: - init_script: - condition: service_started - pyro_api: - condition: service_healthy - pyro_camera_api: - condition: service_started etl_scripts: container_name: etl