From 729af9ced9520f20c58bb45e5e02faea02212ab5 Mon Sep 17 00:00:00 2001 From: Vincent Mahnke Date: Sat, 1 Nov 2025 20:55:49 +0100 Subject: [PATCH 1/6] feat: `web` healthcheck returns 503 status code if database is unavailable --- docker-compose.yml | 5 ++--- web/www/sunders/sync-state.php | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 0224ddf..9b95e3e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -33,12 +33,11 @@ services: ports: - "8081:80" depends_on: - data_handler: + db: condition: service_started # all the way zoomed out, with hamburg at the center, at least one camera should be returned healthcheck: - test: > - ["CMD", "curl -s 'http://localhost/camera.php?bbox=-92.52991540527346,30.683278176916133,131.7689595947266,72.87186315234298&zoom=4&width=2552&height=867' | grep '^\[.+\]$'"] + test: ["CMD", "curl", "-f", "http://localhost/sync-state.php"] interval: 10s timeout: 5s start_period: 30s diff --git a/web/www/sunders/sync-state.php b/web/www/sunders/sync-state.php index 095e92c..11ecef5 100644 --- a/web/www/sunders/sync-state.php +++ b/web/www/sunders/sync-state.php @@ -6,8 +6,9 @@ /* Connect to database */ $mysqli = new mysqli(MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DB); if($mysqli->connect_errno) { + http_response_code(503); header('Content-type: application/json'); - $result = '{"error":"error while connecting to db : ' . $mysqli->error . '"}'; + $result = '{"error":"Database unavailable"}'; echo $result; exit; } From adab9b31756a78180d209f7fd4ef86e2a0eaeb71 Mon Sep 17 00:00:00 2001 From: Vincent Mahnke Date: Sat, 1 Nov 2025 21:23:38 +0100 Subject: [PATCH 2/6] docs: Adds instructions about `dev` override chore: Applies docker naming convention to files --- README.md | 6 ++-- docker-compose-dev.yml | 72 ------------------------------------------ docker-compose.dev.yml | 13 ++++++++ 3 files changed, 15 insertions(+), 76 deletions(-) delete mode 100644 docker-compose-dev.yml create mode 100644 docker-compose.dev.yml diff --git a/README.md b/README.md index 940c6a0..24cfb02 100644 --- a/README.md +++ b/README.md @@ -34,12 +34,10 @@ To run Surveillance using docker, decide between development/testing or producti 1. Clone this repository -2. Run `docker compose up` and wait for services to start up +2. Run `docker compose -f docker-compose.yml -f docker-compose.dev.yml up` and wait for services to start up 3. Visit `http://localhost:8080/` in a browser; you should see an interactive OpenStreetMap -_tbd.: Populate camera data_ - ### Production 1. Close this repository @@ -50,7 +48,7 @@ _tbd.: Populate camera data_ 3. Visit `http://localhost:8080/` in a browser to open the web interface -_tbd.: Populate camera data_ +4. ## Surveillance nodes diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml deleted file mode 100644 index 28c7c46..0000000 --- a/docker-compose-dev.yml +++ /dev/null @@ -1,72 +0,0 @@ -services: - db: - image: mariadb:12.0.2 - restart: unless-stopped - command: --max_allowed_packet=3250585600 - environment: - MYSQL_ROOT_PASSWORD: rootpassword # ${{secrets.MYSQL_ROOT_PASSWORD}} - MYSQL_DATABASE: camera # ${{secrets.MYSQL_DATABASE}} - MYSQL_USER: camera # ${{secrets.MYSQL_USER}} - MYSQL_PASSWORD: camerapassword # ${{secrets.MYSQL_PASSWORD}} - volumes: - - ./mariadb:/var/lib/mysql:Z - healthcheck: - test: ["CMD", "mariadb-admin", "ping", "-h", "localhost", "-uroot", "-prootpassword"] - interval: 10s - timeout: 5s - start_period: 30s - retries: 5 - - web: - image: git.hamburg.ccc.de/ccchh/sunders/web:latest - restart: unless-stopped - environment: - MYSQL_HOST: db - MYSQL_DB: camera # ${{secrets.MYSQL_DATABASE}} - CAMERA_SELECT_USER: camera_select # ${{secrets.CAMERA_SELECT_USER}} - CAMERA_SELECT_USER_PASSWORD: camera_selectpassword # ${{secrets.CAMERA_SELECT_USER_PASSWORD}} - DEFAULT_ZOOM: 12 - DEFAULT_LAT: 0 - DEFAULT_LON: 0 - DEFAULT_LANGUAGE: en - IMPRESSUM_URL: https://hamburg.ccc.de/imprint/ - ports: - - "8081:80" - volumes: - - ./web/www/sunders:/var/www/html:Z - depends_on: - db: - condition: service_started - # all the way zoomed out, with hamburg at the center, at least one camera should be returned - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost/sync-state.php"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 10s - - data_handler: - image: git.hamburg.ccc.de/ccchh/sunders/data_handler:latest - restart: unless-stopped - environment: - MYSQL_HOST: db - MYSQL_DB: camera # ${{secrets.MYSQL_DATABASE}} - MYSQL_USER: root # ${{secrets.MYSQL_USER}} - MYSQL_PASSWORD: rootpassword # ${{secrets.MYSQL_ROOT_PASSWORD}} - CAMERA_USER: camera # ${{secrets.CAMERA_USER}} - CAMERA_USER_PASSWORD: camerapassword # ${{secrets.CAMERA_USER_PASSWORD}} - CAMERA_SELECT_USER: camera_select # ${{secrets.CAMERA_SELECT_USER}} - CAMERA_SELECT_USER_PASSWORD: camera_selectpassword # ${{secrets.CAMERA_SELECT_USER_PASSWORD}} - depends_on: - db: - condition: service_healthy - restart: true - # if the latest `update_camera_*.log` contains "error", fail the healthcheck - healthcheck: - test: ["CMD", "sh", "-c", "ls /var/log | grep '^update_camera_' | xargs -I {} sh -c 'grep -q error /var/log/{} || exit 0; exit 1'"] - interval: 10s - timeout: 5s - retries: 5 - -volumes: - mariadb: \ No newline at end of file diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 0000000..15542fa --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,13 @@ +services: + db: + volumes: + - ./mariadb:/var/lib/mysql:Z + + web: + volumes: + - ./web/www/sunders:/var/www/html:Z + + data_handler: + volumes: + - ./data_handler/utils:/opt:Z + - ./data_handler/data_init:/opt/init/init.sql:Z \ No newline at end of file From 907c20bad29414d8d41f51503cebe9454d561c5c Mon Sep 17 00:00:00 2001 From: Vincent Mahnke Date: Sat, 1 Nov 2025 21:27:47 +0100 Subject: [PATCH 3/6] fix: Enables PHP log output when running in `development` --- .gitignore | 5 ++++- docker-compose.dev.yml | 2 ++ web/www/sunders/add-lists.php | 1 - web/www/sunders/camera.php | 1 - web/www/sunders/config.php | 11 +++++++++++ 5 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 09f94a6..1febf73 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,7 @@ lastState.txt lastStatisticsUpdate.txt log.* state.txt -migrations \ No newline at end of file +migrations + +# created when running development environment +mariadb/** \ No newline at end of file diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 15542fa..61d0016 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -6,6 +6,8 @@ services: web: volumes: - ./web/www/sunders:/var/www/html:Z + environment: + APP_ENV: development data_handler: volumes: diff --git a/web/www/sunders/add-lists.php b/web/www/sunders/add-lists.php index da9f396..12fc0c0 100644 --- a/web/www/sunders/add-lists.php +++ b/web/www/sunders/add-lists.php @@ -1,5 +1,4 @@ \ No newline at end of file From 590fb8647ab1b806a1598e020d81d4718332cd01 Mon Sep 17 00:00:00 2001 From: Vincent Mahnke Date: Sat, 1 Nov 2025 21:28:30 +0100 Subject: [PATCH 4/6] fix: Handles issue where error handler was skipped, if database DNS request fails --- web/www/sunders/sync-state.php | 40 ++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/web/www/sunders/sync-state.php b/web/www/sunders/sync-state.php index 11ecef5..3cb8ef0 100644 --- a/web/www/sunders/sync-state.php +++ b/web/www/sunders/sync-state.php @@ -2,27 +2,29 @@ error_reporting(0); include $pathToWebFolder.'config.php'; - - /* Connect to database */ - $mysqli = new mysqli(MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DB); - if($mysqli->connect_errno) { - http_response_code(503); - header('Content-type: application/json'); - $result = '{"error":"Database unavailable"}'; - echo $result; - exit; - } - - $syncstate_querry = $mysqli->query("SELECT * FROM sync_state WHERE k = 'sequenceNumber'"); - - while($row = $syncstate_querry->fetch_assoc()) { - $syncstate = array('sequenceNumber' => $row["v"]); + try { + $mysqli = new mysqli(MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DB); + if($mysqli->connect_errno) { + throw new Exception("Could not connect to database"); } - $result = json_encode($syncstate); + $syncstate_querry = $mysqli->query("SELECT * FROM sync_state WHERE k = 'sequenceNumber'"); - $mysqli->close(); + while($row = $syncstate_querry->fetch_assoc()) { + $syncstate = array('sequenceNumber' => $row["v"]); + } - header('Content-type: application/json; Charset : utf-8'); - echo $result; + $result = json_encode($syncstate); + + $mysqli->close(); + + header('Content-type: application/json; Charset : utf-8'); + echo $result; + mysqli_report(MYSQLI_REPORT_OFF); + } catch (Exception $e) { + http_response_code(503); + header('Content-type: application/json'); + $result = '{"error":"Database unavailable"}'; + echo $result; + } ?> From dbd0ff677f41a648bd759fa148bc0edf426833cf Mon Sep 17 00:00:00 2001 From: Vincent Mahnke Date: Sat, 1 Nov 2025 21:28:59 +0100 Subject: [PATCH 5/6] docs: Removes incorrect comment --- docker-compose.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 9b95e3e..6124c1d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -35,7 +35,6 @@ services: depends_on: db: condition: service_started - # all the way zoomed out, with hamburg at the center, at least one camera should be returned healthcheck: test: ["CMD", "curl", "-f", "http://localhost/sync-state.php"] interval: 10s From 34339b8021b14ee91cc744a59130e40210f46688 Mon Sep 17 00:00:00 2001 From: Vincent Mahnke Date: Sat, 1 Nov 2025 21:29:18 +0100 Subject: [PATCH 6/6] docs: Adds information about changes when running in a development environment --- README.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 24cfb02..2e35ead 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,17 @@ To run Surveillance using docker, decide between development/testing or producti 3. Visit `http://localhost:8080/` in a browser; you should see an interactive OpenStreetMap +4. You can see most cameras on the map immediately; the `data_handler` background process continuously applies updates from OpenStreetMap which become visible after refrshing the page + +5. Appending `-f docker-compose.dev.yml` applies these changes: + + - PHP won't supress any errors; to disable this, remove `return;` in `./web/www/sunders/config.php` + + - Making changes in the `web` will immediately apply them to the running containers; try modifying `web/www/sunders/index.php` + + - Making changes in the `data_handler` will immediately apply them to the running containers (try modifying `data_handler/utils/update_camera.sh`) + + - The host has access to database files at `./mariadb` ### Production 1. Close this repository @@ -46,9 +57,9 @@ To run Surveillance using docker, decide between development/testing or producti 3. Run `docker compose up` and wait for services to start up -3. Visit `http://localhost:8080/` in a browser to open the web interface +3. Visit `http://localhost:8080/` in a browser; you should see an interactive OpenStreetMap -4. +4. You can see most cameras on the map immediately; the `data_handler` background process continuously applies updates from OpenStreetMap which become visible after refrshing the page ## Surveillance nodes