Compare commits

..
8 Commits
Author SHA1 Message Date
brb f0caebbfda defined build of container 2023-07-10 16:46:53 +02:00
brb 3002990e43 defined build of container 2023-07-10 16:46:46 +02:00
brb 7a35d300e0 installed packages 2023-07-10 16:46:33 +02:00
brb 599e0e376e updated service description 2023-07-10 16:46:19 +02:00
brb b02c6d240f added code to run main loop of service 2023-07-10 16:45:49 +02:00
brb 2b2dd14493 added code to initialise service 2023-07-10 16:45:37 +02:00
brb 40b8b2aac6 added code to interact with database 2023-07-10 16:45:24 +02:00
brb b3ee0a5cc6 added function to measure bandwidth 2023-07-10 16:45:01 +02:00
8 changed files with 234 additions and 1 deletions
+49
View File
@@ -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 -1
View File
@@ -1,3 +1,3 @@
# bandwidth_probing # 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.
+22
View File
@@ -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)
+31
View File
@@ -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)
+55
View File
@@ -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')
+51
View File
@@ -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)
+8
View File
@@ -0,0 +1,8 @@
version: "3.9"
services:
bandwidth-probing:
build: .
container_name: bandwidth-probing
restart: unless-stopped
env_file:
- .env
+17
View File
@@ -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