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/Makefile b/Makefile index ddd9e03..c57dcda 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,15 @@ 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 (tools must be up first so the API is ready when engine starts) +run-tools-and-engine: + $(MAKE) run-tools + $(MAKE) run-engine + # Tools profile adds notebooks, db-ui run-tools: docker compose --profile tools up -d @@ -66,9 +70,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/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/data/credentials.json b/data/credentials.json index 61ed6fe..66a096e 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": "" } } 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..a03a372 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -49,39 +49,47 @@ 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"] 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' + 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: max-size: 100m max-file: '5' - depends_on: - init_script: - 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 +121,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 @@ -179,3 +159,6 @@ services: - PGADMIN_DEFAULT_PASSWORD=${DB_UI_PWD} depends_on: - db + +volumes: + minio_data: