- Add Dockerfile

- Add Config in backend using env vars
- Clean up mock actor
This commit is contained in:
Dorian Zedler 2021-08-19 11:27:39 +02:00
parent cbffbc92a6
commit b6f8b54bc2
Signed by: dozedler
GPG key ID: 989DE36109AFA354
9 changed files with 121 additions and 36 deletions

1
backend/.dockerignore Normal file
View file

@ -0,0 +1 @@
__pycache__

8
backend/Dockerfile Normal file
View file

@ -0,0 +1,8 @@
FROM python:3-alpine
RUN apk --no-cache add build-base openldap-dev python2-dev python3-dev
RUN pip3 install python-ldap requests coloredlogs
COPY ./* ./
ENTRYPOINT [ "python3", "mlmAccess.py" ]

6
backend/actor.py Normal file
View file

@ -0,0 +1,6 @@
class MaActor:
def __init__(self, id):
self._id = id
def _mqttOnConnect(self, client, userdata, flags, rc):
client.subscribe("mlmAccess/pair/request/actor")

View file

@ -2,22 +2,23 @@ import pymysql
import json import json
class MaDbHelper: class MaDbHelper:
def __init__(self): def __init__(self, config):
self.mysqlConn = pymysql.connect(host='localhost', self.mysqlConn = pymysql.connect(host=config["MYSQL_HOST"],
user='root', user=config["MYSQL_USER"],
passwd='MlmAccess', passwd=config["MYSQL_PASSWORD"],
db='MlmAccess', db=config["MYSQL_DATABASE"],
port=4306) port=config["MYSQL_PORT"])
self.mysqlCur = self.mysqlConn.cursor() self.mysqlCur = self.mysqlConn.cursor()
self._initDb()
def _initDb(self): def _initDb(self):
""" """
Generates required tables and users Generates required tables
""" """
""" query = """
CREATE TABLE vmq_auth_acl CREATE TABLE IF NOT EXISTS vmq_auth_acl
( (
mountpoint VARCHAR(10) NOT NULL, mountpoint VARCHAR(10) NOT NULL,
client_id VARCHAR(128) NOT NULL, client_id VARCHAR(128) NOT NULL,
@ -29,6 +30,12 @@ class MaDbHelper:
) )
""" """
self.mysqlCur.execute(
query
)
self.mysqlConn.commit()
def addUser(self, username, password, publishAclPatterns, subscribeAclPatterns): def addUser(self, username, password, publishAclPatterns, subscribeAclPatterns):
if self.userExists(username): if self.userExists(username):

View file

@ -1,7 +1,7 @@
import paho.mqtt.client as mqtt import paho.mqtt.client as mqtt
from dbHelper import MaDbHelper from dbHelper import MaDbHelper
from pairingHandler import MaPairingHandler from pairingHandler import MaPairingHandler
import logging, coloredlogs import logging, coloredlogs, os, sys, random, string
coloredlogs.install(level='INFO', fmt='%(asctime)s - [%(levelname)s] %(message)s') coloredlogs.install(level='INFO', fmt='%(asctime)s - [%(levelname)s] %(message)s')
@ -9,6 +9,8 @@ class MlmAccess:
def __init__(self): def __init__(self):
logging.info("=== MlmAccess ===") logging.info("=== MlmAccess ===")
self._config = self._readConfig()
self._initDb() self._initDb()
self._initMqtt() self._initMqtt()
@ -18,10 +20,10 @@ class MlmAccess:
def _initDb(self): def _initDb(self):
logging.info("Initializing Database") logging.info("Initializing Database")
self._db = MaDbHelper() self._db = MaDbHelper(self._config)
initUsers = [ initUsers = [
("backend", "backend", ["mlmAccess/#"], ["mlmAccess/#"]), ("backend", self._config["MQTT_BACKEND_PASSWORD"], ["mlmAccess/#"], ["mlmAccess/#"]),
("pair-actor", "pair-actor", ["mlmAccess/pair/request/actor"], ["mlmAccess/pair/response/actor"]) ("pair-actor", self._config["PAIR_SECRET"], ["mlmAccess/pair/request/actor"], ["mlmAccess/pair/response/actor"])
] ]
for username, password, publishAclPatterns, subscribeAclPatterns in initUsers: for username, password, publishAclPatterns, subscribeAclPatterns in initUsers:
@ -31,12 +33,12 @@ class MlmAccess:
def _initMqtt(self): def _initMqtt(self):
logging.info("Initializing MQTT") logging.info("Initializing MQTT")
self._mqtt = client = mqtt.Client(client_id="backend") self._mqtt = client = mqtt.Client(client_id="backend")
self._mqtt.username_pw_set("backend", "backend") self._mqtt.username_pw_set("backend", self._config["MQTT_BACKEND_PASSWORD"])
self._mqtt.on_connect = self._mqttOnConnect self._mqtt.on_connect = self._mqttOnConnect
self._mqtt.on_message = self._mqttOnMessage self._mqtt.on_message = self._mqttOnMessage
self._mqtt.connect("localhost", 1883, 60) self._mqtt.connect(self._config["MQTT_HOST"], self._config["MQTT_PORT"], 60)
def _mqttOnConnect(self, client, userdata, flags, rc): def _mqttOnConnect(self, client, userdata, flags, rc):
if rc != 0: if rc != 0:
@ -65,5 +67,48 @@ class MlmAccess:
if topic.startswith("pair"): if topic.startswith("pair"):
self._pairingHanlder.handlePairingRequest(topic, messageContent) self._pairingHanlder.handlePairingRequest(topic, messageContent)
def _readConfig(self):
configKeyPrefix = "MLMACCESS_"
requiredConfigKeys = [
'MYSQL_USER',
'MYSQL_PASSWORD',
'MYSQL_DATABASE',
'PAIR_SECRET'
]
allowedConfigKeys = [
'MYSQL_HOST',
'MYSQL_PORT',
'MQTT_HOST',
'MQTT_PORT',
]
backendPassword = ''.join(random.choices(string.ascii_uppercase + string.ascii_lowercase + string.digits, k=20))
config = {
"MYSQL_HOST": "mysql",
"MYSQL_PORT": 4306,
"MQTT_HOST": "mqtt",
"MQTT_PORT": 1883,
"MQTT_BACKEND_PASSWORD": backendPassword
}
for configKey in requiredConfigKeys:
if configKeyPrefix + configKey not in os.environ:
logging.error(f"Required environment value {configKeyPrefix + configKey} is not set")
sys.exit(1)
config[configKey] = os.environ[configKeyPrefix + configKey]
for configKey in allowedConfigKeys:
if configKeyPrefix + configKey in os.environ:
config[configKey] = os.environ[configKeyPrefix + configKey]
logging.info("CONFIG:")
for key, value in config.items():
logging.info(" * {:25}: {}".format(key, value))
return config
if __name__ == "__main__": if __name__ == "__main__":
MlmAccess() MlmAccess()

View file

@ -1,5 +1,5 @@
services: services:
broker: mqtt:
image: vernemq/vernemq:1.11.0 image: vernemq/vernemq:1.11.0
environment: environment:
- DOCKER_VERNEMQ_ACCEPT_EULA=yes - DOCKER_VERNEMQ_ACCEPT_EULA=yes
@ -7,7 +7,7 @@ services:
- DOCKER_VERNEMQ_PLUGINS__VMQ_ACL=off - DOCKER_VERNEMQ_PLUGINS__VMQ_ACL=off
- DOCKER_VERNEMQ_PLUGINS__VMQ_DIVERSITY=on - DOCKER_VERNEMQ_PLUGINS__VMQ_DIVERSITY=on
- DOCKER_VERNEMQ_VMQ_DIVERSITY__AUTH_MYSQL__ENABLED=on - DOCKER_VERNEMQ_VMQ_DIVERSITY__AUTH_MYSQL__ENABLED=on
- DOCKER_VERNEMQ_VMQ_DIVERSITY__MYSQL__HOST=mysql-server - DOCKER_VERNEMQ_VMQ_DIVERSITY__MYSQL__HOST=mysql
- DOCKER_VERNEMQ_VMQ_DIVERSITY__MYSQL__PORT=3306 - DOCKER_VERNEMQ_VMQ_DIVERSITY__MYSQL__PORT=3306
- DOCKER_VERNEMQ_VMQ_DIVERSITY__MYSQL__USER=root - DOCKER_VERNEMQ_VMQ_DIVERSITY__MYSQL__USER=root
- DOCKER_VERNEMQ_VMQ_DIVERSITY__MYSQL__PASSWORD=MlmAccess - DOCKER_VERNEMQ_VMQ_DIVERSITY__MYSQL__PASSWORD=MlmAccess
@ -21,7 +21,7 @@ services:
- ./data/vernemq/data:/vernemq/data - ./data/vernemq/data:/vernemq/data
- ./data/vernemq/log:/vernemq/log - ./data/vernemq/log:/vernemq/log
mysql-server: mysql:
image: mariadb image: mariadb
restart: always restart: always
command: --default-authentication-plugin=mysql_native_password command: --default-authentication-plugin=mysql_native_password
@ -37,7 +37,7 @@ services:
image: phpmyadmin/phpmyadmin image: phpmyadmin/phpmyadmin
restart: always restart: always
environment: environment:
- PMA_HOST=mysql-server - PMA_HOST=mysql
- PMA_USER=root - PMA_USER=root
- PMA_PASSWORD=MlmAccess - PMA_PASSWORD=MlmAccess
- UPLOAD_LIMIT=512M - UPLOAD_LIMIT=512M

View file

@ -3,7 +3,7 @@ import logging, coloredlogs
coloredlogs.install(level='INFO', fmt='%(asctime)s - [%(levelname)s] %(message)s') coloredlogs.install(level='INFO', fmt='%(asctime)s - [%(levelname)s] %(message)s')
PAIR_ID = "106" PAIR_ID = "101"
def on_connect(client, userdata, flags, rc): def on_connect(client, userdata, flags, rc):
global PAIR_ID global PAIR_ID

View file

@ -1,28 +1,36 @@
import paho.mqtt.client as mqtt import paho.mqtt.client as mqtt
import logging, coloredlogs
coloredlogs.install(level='INFO', fmt='%(asctime)s - [%(levelname)s] %(message)s')
ACTOR_ID = "101"
ACTOR_PASSWORD = "MgUiSW1dloFt9TVKJM5E"
# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc): def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc)) global ACTOR_ID
# Subscribing in on_connect() means that if we lose the connection and
# reconnect then subscriptions will be renewed. if rc != 0:
print("Subscribing to topic","mlmAccess/pair/response/actor") logging.error(f"Error connecting to MQTT broker: {rc}")
print(client.subscribe("mlmAccess/actor/102/action")) return
print("Publishing message to topic","mlmAccess/pair/request/actor")
print(client.publish("mlmAccess/actor/102/status", "0", retain=True)) logging.info("Successfully connected to MQTT broker")
client.subscribe(f"mlmAccess/actor/{ACTOR_ID}/action")
client.publish(f"mlmAccess/actor/{ACTOR_ID}/status", "0", retain=True)
def on_message(client, userdata, message): def on_message(client, userdata, message):
print("message received " ,str(message.payload.decode("utf-8"))) messageContent = str(message.payload.decode("utf-8"))
print("message topic=",message.topic) logging.info(f"Got request to perform action: {messageContent}")
print("message qos=",message.qos) # report back action to let the backend know that it was executed successfully
print("message retain flag=",message.retain) client.publish(f"mlmAccess/actor/{ACTOR_ID}/status", messageContent, retain=True)
client = mqtt.Client(client_id="actor-102") client = mqtt.Client(client_id=f"actor-{ACTOR_ID}")
client.username_pw_set("actor-102", "YWT2JPOEZH") client.username_pw_set(f"actor-{ACTOR_ID}", ACTOR_PASSWORD)
client.on_connect = on_connect client.on_connect = on_connect
client.on_message = on_message client.on_message = on_message
print("connecting to broker") logging.info("Initializing MQTT")
print(client.connect("localhost", 1883, 60)) client.connect("localhost", 1883, 60)
client.loop_forever() client.loop_forever()

10
runBackend.sh Executable file
View file

@ -0,0 +1,10 @@
#!/bin/bash
export MLMACCESS_MYSQL_USER=root
export MLMACCESS_MYSQL_PASSWORD=MlmAccess
export MLMACCESS_MYSQL_DATABASE=MlmAccess
export MLMACCESS_MYSQL_HOST=localhost
export MLMACCESS_MQTT_HOST=localhost
export MLMACCESS_PAIR_SECRET=pair-actor
python3 backend/mlmAccess.py