Compare commits
8
Commits
4098c01ad0
...
f0caebbfda
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0caebbfda | ||
|
|
3002990e43 | ||
|
|
7a35d300e0 | ||
|
|
599e0e376e | ||
|
|
b02c6d240f | ||
|
|
2b2dd14493 | ||
|
|
40b8b2aac6 | ||
|
|
b3ee0a5cc6 |
+49
@@ -0,0 +1,49 @@
|
||||
###########
|
||||
# BUILDER #
|
||||
###########
|
||||
|
||||
# pull official base image
|
||||
FROM python:3.10-bookworm as BUILDER
|
||||
|
||||
# install Ookla's speedtest
|
||||
RUN apt update && \
|
||||
apt install -y speedtest-cli
|
||||
|
||||
# set environment variables
|
||||
ENV PYTHONDONTWRITEBYTECODE 1
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
|
||||
# install dependencies
|
||||
WORKDIR /usr/src/app
|
||||
COPY requirements.txt .
|
||||
RUN pip install --upgrade pip && \
|
||||
pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/app/wheels -r requirements.txt
|
||||
|
||||
#########
|
||||
# FINAL #
|
||||
#########
|
||||
|
||||
FROM python:3.10-bookworm
|
||||
|
||||
# create home direcroty and app user
|
||||
RUN mkdir -p /home/app && \
|
||||
addgroup --system app && \
|
||||
adduser --system --group app
|
||||
|
||||
# install packages from builder
|
||||
COPY --from=BUILDER /usr/src/app/wheels /wheels
|
||||
COPY --from=BUILDER /usr/src/app/requirements.txt requirements.txt
|
||||
RUN pip install --no-cache /wheels/*
|
||||
|
||||
# copy in files
|
||||
WORKDIR /home/app
|
||||
COPY ./code .
|
||||
|
||||
# change ownership to app user
|
||||
RUN chown -R app:app /home/app
|
||||
|
||||
# change to the app user
|
||||
USER app
|
||||
|
||||
# start execution
|
||||
ENTRYPOINT [ "python", "main.py" ]
|
||||
@@ -1,3 +1,3 @@
|
||||
# bandwidth_probing
|
||||
|
||||
Service that runs in a container and measures network bandwidth at a specified interval. The results are sent to a PostgreSQL database.
|
||||
Service that runs in a container and measures network bandwidth at a specified interval. The results are sent to a MongoDB database. Logs are sent to discord channel.
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
from speedtest import Speedtest
|
||||
from dotenv import load_dotenv
|
||||
from typing import List
|
||||
|
||||
|
||||
def measure():
|
||||
"""
|
||||
Measure bandwidth usiing Ookla/speedtest.
|
||||
"""
|
||||
s = Speedtest()
|
||||
s.get_servers(servers=[])
|
||||
s.get_best_server()
|
||||
s.download(threads=None)
|
||||
s.upload(threads=None)
|
||||
s.results.share()
|
||||
return s.results.dict()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
load_dotenv()
|
||||
res = measure()
|
||||
print(res)
|
||||
@@ -0,0 +1,31 @@
|
||||
from pymongo import MongoClient
|
||||
from dotenv import load_dotenv
|
||||
import logging
|
||||
import os
|
||||
|
||||
def connect(
|
||||
ip_addr: str | None = None,
|
||||
db_name: str | None = None,
|
||||
collection_name: str | None = None
|
||||
):
|
||||
"""
|
||||
Connect to MongoDB database and return collection.
|
||||
"""
|
||||
# ensure variables are set
|
||||
if ip_addr is None:
|
||||
ip_addr = os.getenv('DB_IP_ADDRESS')
|
||||
if db_name is None:
|
||||
db_name = os.getenv('DB_NAME')
|
||||
if collection_name is None:
|
||||
collection_name = os.getenv('DB_COLLECTION_NAME')
|
||||
# connect to database
|
||||
client = MongoClient(ip_addr)
|
||||
db = client[db_name]
|
||||
collection = db[collection_name]
|
||||
return collection
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
load_dotenv()
|
||||
collection = connect()
|
||||
print(collection)
|
||||
@@ -0,0 +1,55 @@
|
||||
from discord_logging.handler import DiscordHandler
|
||||
from dotenv import load_dotenv
|
||||
import logging
|
||||
import os
|
||||
|
||||
|
||||
def initialise_app():
|
||||
"""
|
||||
Convienience function that ensures eveything is ready before running main loop.
|
||||
"""
|
||||
# load environment variables from file
|
||||
load_dotenv()
|
||||
# setup logging
|
||||
fmt = '|%(asctime)s| %(levelname)s %(filename)s:%(funcName)s:%(message)s'
|
||||
datefmt = '%Y-%m-%d %H:%M:%S'
|
||||
logger_level = os.getenv('LOGGER_LEVEL', default=None)
|
||||
if logger_level is None:
|
||||
logger_level = 'info'
|
||||
logging.info(f'environment variable LOGGER_LEVEL not set. Using default (info)')
|
||||
level = getattr(logging, logger_level.upper())
|
||||
logging.basicConfig(format=fmt, datefmt=datefmt, level=level)
|
||||
# setup logging to discord
|
||||
discord_url = os.getenv('DISCORD_URL', default=None)
|
||||
assert discord_url is not None
|
||||
logger = logging.getLogger()
|
||||
discord_handler = DiscordHandler(
|
||||
service_name = 'bandwidth_probing',
|
||||
webhook_url = discord_url,
|
||||
)
|
||||
discord_handler.setFormatter(logging.Formatter('%(message)s'))
|
||||
discord_handler.setLevel(logging.WARNING)
|
||||
logger.addHandler(discord_handler)
|
||||
# ensure environment variables are set
|
||||
necessary_list = [
|
||||
'DB_IP_ADDRESS',
|
||||
'DB_NAME',
|
||||
'DB_COLLECTION_NAME'
|
||||
]
|
||||
for var in necessary_list:
|
||||
assert var in os.environ, f'environment variable {var} not set.'
|
||||
# set defaults if not yet handled
|
||||
default_dict = {
|
||||
'USER_ID': 0,
|
||||
'REPLICATES': 3,
|
||||
'TRIGGER_INTERVAL_SECONDS': 60
|
||||
}
|
||||
for k, v in default_dict.items():
|
||||
if not k in os.environ:
|
||||
logging.info(f'environment variable {k} not set. Using default ({v}).')
|
||||
os.environ[k] = str(v)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
initialise_app()
|
||||
logging.warning('test message')
|
||||
@@ -0,0 +1,51 @@
|
||||
import time
|
||||
import logging
|
||||
import time
|
||||
import os
|
||||
from initialise_app import initialise_app
|
||||
from bandwidth import measure as measure_bandwidth
|
||||
from database import connect
|
||||
|
||||
def event():
|
||||
logging.info('started event')
|
||||
# get env vars
|
||||
replicates = int(os.getenv('REPLICATES'))
|
||||
# setup database connection
|
||||
db = connect()
|
||||
# run event
|
||||
for rep_num in range(replicates):
|
||||
logging.info(f'running replicate {rep_num}')
|
||||
# do measurement
|
||||
try:
|
||||
res = measure_bandwidth()
|
||||
except Exception as e:
|
||||
logging.error(f'failed to measure bandwidth: {e}')
|
||||
continue
|
||||
# upload result to database
|
||||
payload_dict = {
|
||||
'user_id': os.getenv('USER_ID'),
|
||||
'data': res
|
||||
}
|
||||
try:
|
||||
db_id = db.insert_one(payload_dict).inserted_id
|
||||
except Exception as e:
|
||||
logging.error(f'failed sending results to database: {e}')
|
||||
continue
|
||||
logging.debug(f'data sent to database received db_id: {db_id}')
|
||||
time.sleep(1)
|
||||
logging.info('finished event')
|
||||
|
||||
if __name__ == '__main__':
|
||||
initialise_app()
|
||||
trigger_time = time.time()
|
||||
while True:
|
||||
if time.time() >= trigger_time:
|
||||
# set new trigger time
|
||||
trigger_time += int(os.getenv('TRIGGER_INTERVAL_SECONDS'))
|
||||
# run event
|
||||
try:
|
||||
event()
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
time.sleep(1)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
version: "3.9"
|
||||
services:
|
||||
bandwidth-probing:
|
||||
build: .
|
||||
container_name: bandwidth-probing
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env
|
||||
@@ -0,0 +1,17 @@
|
||||
aiosignal==1.3.1
|
||||
async-timeout==4.0.2
|
||||
attrs==23.1.0
|
||||
certifi==2023.5.7
|
||||
charset-normalizer==3.2.0
|
||||
discord-webhook==1.1.0
|
||||
dnspython==2.3.0
|
||||
frozenlist==1.3.3
|
||||
idna==3.4
|
||||
multidict==6.0.4
|
||||
pymongo==4.4.0
|
||||
python-dotenv==1.0.0
|
||||
python-logging-discord-handler==0.1.4
|
||||
requests==2.31.0
|
||||
speedtest-cli==2.1.3
|
||||
urllib3==2.0.3
|
||||
yarl==1.9.2
|
||||
Reference in New Issue
Block a user