Containerize scraper and externalize credentials

Move DB host/user/password, Discord webhook, and log path to env vars
so the script can be deployed via Docker compose. Discord notifications
are now skipped silently when DISCORD_WEBHOOK is unset (the old
hardcoded webhook is removed pending rotation). Adds Dockerfile,
docker-compose.yml, requirements.txt, .env.example, and .gitignore for
the cyrion deployment.
This commit is contained in:
wes
2026-05-06 23:20:12 -04:00
parent b9864b36b4
commit 10bdee8e1f
6 changed files with 237 additions and 181 deletions
+16
View File
@@ -0,0 +1,16 @@
# Knoebels scraper environment configuration.
# Copy to .env on the deploy host and fill in real values.
# Never commit the real .env.
# PostgreSQL connection (phlegethon by default)
DB_HOST=192.168.88.9
DB_PORT=5432
DB_USER=kuhnobowls
DB_PASSWORD=
# Optional Discord webhook for notifications.
# Leave empty/unset to skip Discord calls entirely.
DISCORD_WEBHOOK=
# Log path inside the container. Mapped to the knb_logs named volume by compose.
LOG_PATH=/var/log/kuh-no-bowls/kuh-no-bowls.log
+7
View File
@@ -0,0 +1,7 @@
.env
__pycache__/
*.pyc
.venv/
venv/
historical_data/
*.log
+10
View File
@@ -0,0 +1,10 @@
FROM python:3.13-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY attractions_api_logger.py .
ENTRYPOINT ["python", "-u", "attractions_api_logger.py"]
+18 -11
View File
@@ -1,21 +1,29 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os
from datetime import datetime, date, timedelta from datetime import datetime, date, timedelta
import json, requests, psycopg2, logging, sys import json, requests, psycopg2, logging, sys
from psycopg2 import sql from psycopg2 import sql
ATTRACTIONS_IO_ENDPOINT = "https://live-data.attractions.io/72f0ea9e-d196-508a-bee8-cce62c3228c7.json" ATTRACTIONS_IO_ENDPOINT = "https://live-data.attractions.io/72f0ea9e-d196-508a-bee8-cce62c3228c7.json"
DISCORD_WEBHOOK = 'https://discord.com/api/webhooks/878651005015842827/o_KXXiPgor-DhZQ9vgL-MNOYb-RDmQCAbuYmgUpsoEOqu3XCfBdUM6rDmF1cMrZg12b0' DISCORD_WEBHOOK = os.environ.get('DISCORD_WEBHOOK', '').strip()
DB_PASSWORD = os.environ.get('DB_PASSWORD')
if not DB_PASSWORD:
sys.stderr.write("ERROR: DB_PASSWORD env var is required\n")
sys.exit(1)
db_params = { db_params = {
'dbname': 'gp0', 'dbname': 'gp0',
'user': 'kuhnobowls', 'user': os.environ.get('DB_USER', 'kuhnobowls'),
'password': 'saddog095', 'password': DB_PASSWORD,
'host': '192.168.88.5', 'host': os.environ.get('DB_HOST', '192.168.88.9'),
'port': '5432', 'port': os.environ.get('DB_PORT', '5432'),
'options': '-c search_path=knoebels' 'options': '-c search_path=knoebels'
} }
LOG_PATH = os.environ.get('LOG_PATH', '/var/log/kuh-no-bowls.log')
park_hours_query = """ park_hours_query = """
SELECT * SELECT *
FROM knoebels."LZ_attractions_io_resort" FROM knoebels."LZ_attractions_io_resort"
@@ -24,16 +32,17 @@ LIMIT 1
""" """
def send_to_discord(message): def send_to_discord(message):
# The payload to send to the webhook if not DISCORD_WEBHOOK:
# Discord notifications disabled — skip silently.
return
data = { data = {
"content": message "content": message
} }
try: try:
# Send the POST request to the webhook URL
response = requests.post(DISCORD_WEBHOOK, json=data) response = requests.post(DISCORD_WEBHOOK, json=data)
# Check if the request was successful
if response.status_code == 204: if response.status_code == 204:
print("Message sent successfully.") print("Message sent successfully.")
else: else:
@@ -157,7 +166,7 @@ def pull_data_and_log(log_park_hours):
log_to_database('LZ_attractions_io_queuetimes', queueline_data) log_to_database('LZ_attractions_io_queuetimes', queueline_data)
logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=logging.DEBUG, filename="/home/hoid/git_repos/kuh-no-bowls/knb.log",filemode="a") logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=logging.DEBUG, filename=LOG_PATH, filemode="a")
logging.info('--------------------------------------------------------------------------------') logging.info('--------------------------------------------------------------------------------')
logging.info('Fetching most recent park hours entry from DB...') logging.info('Fetching most recent park hours entry from DB...')
@@ -177,5 +186,3 @@ if park_hours_pull[2].date() == date.today():
else: else:
logging.info('Park hours for today not in DB') logging.info('Park hours for today not in DB')
pull_data_and_log(True) pull_data_and_log(True)
+14
View File
@@ -0,0 +1,14 @@
services:
scraper:
build: .
image: kuh-no-bowls:latest
container_name: kuh-no-bowls-scraper
env_file: .env
environment:
LOG_PATH: /var/log/kuh-no-bowls/kuh-no-bowls.log
TZ: America/New_York
volumes:
- knb_logs:/var/log/kuh-no-bowls
volumes:
knb_logs:
+2
View File
@@ -0,0 +1,2 @@
requests
psycopg2-binary