Update config loading/validation
This commit is contained in:
parent
db1857a18f
commit
9e99695611
2
.gitignore
vendored
2
.gitignore
vendored
@ -3,6 +3,6 @@ data.db
|
|||||||
__pycache__
|
__pycache__
|
||||||
.DS_Store
|
.DS_Store
|
||||||
internal_notes.txt
|
internal_notes.txt
|
||||||
config.ini
|
config.yaml
|
||||||
data
|
data
|
||||||
docker-volume
|
docker-volume
|
@ -15,7 +15,7 @@ import random
|
|||||||
from models import User, Link
|
from models import User, Link
|
||||||
from database import *
|
from database import *
|
||||||
from app.util.log import log
|
from app.util.log import log
|
||||||
from var import BASE_URL
|
from config import BASE_URL
|
||||||
|
|
||||||
|
|
||||||
class FlaskUser(UserMixin):
|
class FlaskUser(UserMixin):
|
||||||
|
@ -4,7 +4,7 @@ from ua_parser import user_agent_parser
|
|||||||
from ip2locationio.ipgeolocation import IP2LocationIOAPIError
|
from ip2locationio.ipgeolocation import IP2LocationIOAPIError
|
||||||
|
|
||||||
from database import SessionLocal
|
from database import SessionLocal
|
||||||
from var import LOG, API_KEY, IP_TO_LOCATION
|
from config import LOG, API_KEY, IP_TO_LOCATION
|
||||||
from models import Link, Record
|
from models import Link, Record
|
||||||
|
|
||||||
configuration = ip2locationio.Configuration(API_KEY)
|
configuration = ip2locationio.Configuration(API_KEY)
|
||||||
|
101
config.py
Normal file
101
config.py
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import jsonschema
|
||||||
|
import os
|
||||||
|
import yaml
|
||||||
|
import validators
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
from colorlog import ColoredFormatter
|
||||||
|
|
||||||
|
log_level = logging.DEBUG
|
||||||
|
log_format = (
|
||||||
|
" %(log_color)s%(levelname)-8s%(reset)s |"
|
||||||
|
" %(log_color)s%(message)s%(reset)s"
|
||||||
|
)
|
||||||
|
|
||||||
|
logging.root.setLevel(log_level)
|
||||||
|
formatter = ColoredFormatter(log_format)
|
||||||
|
|
||||||
|
stream = logging.StreamHandler()
|
||||||
|
stream.setLevel(log_level)
|
||||||
|
stream.setFormatter(formatter)
|
||||||
|
|
||||||
|
LOG = logging.getLogger("pythonConfig")
|
||||||
|
LOG.setLevel(log_level)
|
||||||
|
LOG.addHandler(stream)
|
||||||
|
|
||||||
|
BASE_URL = None
|
||||||
|
IP_TO_LOCATION = None
|
||||||
|
API_KEY = None
|
||||||
|
|
||||||
|
schema = {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"config": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"base_url": {"type": "string"},
|
||||||
|
"ip_to_location": {"type": "boolean"},
|
||||||
|
"api_key": {"type": "string"},
|
||||||
|
},
|
||||||
|
"required": ["base_url", "ip_to_location"],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["config"],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Load config file or create new template
|
||||||
|
def load_config():
|
||||||
|
if os.path.exists("/.dockerenv"):
|
||||||
|
file_path = "/data/config.yaml"
|
||||||
|
else:
|
||||||
|
file_path = "config.yaml"
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(file_path, "r") as f:
|
||||||
|
file_contents = f.read()
|
||||||
|
validate_config(file_contents)
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
# Create new config.yaml w/ template
|
||||||
|
with open(file_path, "w") as f:
|
||||||
|
f.write(
|
||||||
|
"""
|
||||||
|
base_url: ""
|
||||||
|
ip_to_location: ""
|
||||||
|
api_key: ""
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
LOG.critical(
|
||||||
|
"`config.yaml` was not found, a template has been created."
|
||||||
|
" Please fill out the necessary information and restart."
|
||||||
|
)
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
|
||||||
|
# Validate the options within config.yaml
|
||||||
|
def validate_config(file_contents):
|
||||||
|
global BASE_URL, IP_TO_LOCATION, API_KEY
|
||||||
|
config = yaml.safe_load(file_contents)
|
||||||
|
|
||||||
|
try:
|
||||||
|
jsonschema.validate(config, schema)
|
||||||
|
except jsonschema.ValidationError as e:
|
||||||
|
LOG.error(e.message)
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
# Validate BASE_URL
|
||||||
|
if not validators.url(config["config"]["base_url"]):
|
||||||
|
LOG.error("BASE_URL is not a valid URL")
|
||||||
|
else:
|
||||||
|
BASE_URL = config["config"]["base_url"]
|
||||||
|
|
||||||
|
# Make IP_TO_LOCATION a boolean
|
||||||
|
IP_TO_LOCATION = bool(config["config"]["ip_to_location"])
|
||||||
|
|
||||||
|
# Validate API_KEY if IP_TO_LOCATION is set to TRUE
|
||||||
|
if IP_TO_LOCATION:
|
||||||
|
if not config["config"]["api_key"]:
|
||||||
|
LOG.error("API_KEY is not set")
|
||||||
|
else:
|
||||||
|
API_KEY = config["config"]["api_key"]
|
@ -1,7 +1,7 @@
|
|||||||
from werkzeug.middleware.dispatcher import DispatcherMiddleware
|
from werkzeug.middleware.dispatcher import DispatcherMiddleware
|
||||||
from a2wsgi import ASGIMiddleware
|
from a2wsgi import ASGIMiddleware
|
||||||
|
|
||||||
from validate_config import validate_config
|
from config import load_config
|
||||||
from app.main import app as flask_app
|
from app.main import app as flask_app
|
||||||
from api.main import app as fastapi_app
|
from api.main import app as fastapi_app
|
||||||
from database import Base, engine
|
from database import Base, engine
|
||||||
@ -17,5 +17,5 @@ flask_app.wsgi_app = DispatcherMiddleware(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
validate_config()
|
load_config()
|
||||||
flask_app.run(port=5252)
|
flask_app.run(port=5252)
|
||||||
|
@ -1,139 +0,0 @@
|
|||||||
import configparser
|
|
||||||
import validators
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from var import LOG
|
|
||||||
|
|
||||||
"""
|
|
||||||
Validate the config of a Docker run (environment variables)
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def validate_docker_config():
|
|
||||||
errors = 0
|
|
||||||
|
|
||||||
# Validate BASE_URL
|
|
||||||
try:
|
|
||||||
if not os.environ["BASE_URL"]:
|
|
||||||
LOG.error("BASE_URL is not set")
|
|
||||||
errors += 1
|
|
||||||
elif not validators.url(os.environ["BASE_URL"]):
|
|
||||||
LOG.error("BASE_URL is not a valid URL")
|
|
||||||
errors += 1
|
|
||||||
except KeyError:
|
|
||||||
LOG.critical("BASE_URL does not exist!")
|
|
||||||
errors += 1
|
|
||||||
|
|
||||||
# Validate IP_TO_LOCATION
|
|
||||||
try:
|
|
||||||
if not os.environ["IP_TO_LOCATION"]:
|
|
||||||
LOG.error("IP_TO_LOCATION is not set")
|
|
||||||
errors += 1
|
|
||||||
elif os.environ["IP_TO_LOCATION"].upper() not in ["TRUE", "FALSE", "T", "F"]:
|
|
||||||
LOG.error("IP_TO_LOCATION is not set to TRUE or FALSE")
|
|
||||||
errors += 1
|
|
||||||
else:
|
|
||||||
iptolocation = (
|
|
||||||
True if os.environ["IP_TO_LOCATION"].upper() in ["TRUE", "T"] else False
|
|
||||||
)
|
|
||||||
# Validate API_KEY if IP_TO_LOCATION is set to TRUE
|
|
||||||
if iptolocation:
|
|
||||||
try:
|
|
||||||
if not os.environ["API_KEY"]:
|
|
||||||
LOG.error("API_KEY is not set")
|
|
||||||
errors += 1
|
|
||||||
except KeyError:
|
|
||||||
LOG.critical("API_KEY does not exist!")
|
|
||||||
errors += 1
|
|
||||||
except KeyError:
|
|
||||||
LOG.critical("IP_TO_LOCATION does not exist!")
|
|
||||||
errors += 1
|
|
||||||
|
|
||||||
if errors > 0:
|
|
||||||
LOG.critical(f"{errors} error(s) found in environment variables")
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
Validate the config of a bare metal run (config.ini file)
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def validate_bare_metal_config(file_contents):
|
|
||||||
|
|
||||||
config = configparser.ConfigParser()
|
|
||||||
config.read_string(file_contents)
|
|
||||||
|
|
||||||
errors = 0
|
|
||||||
|
|
||||||
# Validate BASE_URL
|
|
||||||
try:
|
|
||||||
if not config["CONFIG"]["BASE_URL"]:
|
|
||||||
LOG.error("BASE_URL is not set")
|
|
||||||
errors += 1
|
|
||||||
elif not validators.url(config["CONFIG"]["BASE_URL"]):
|
|
||||||
LOG.error("BASE_URL is not a valid URL")
|
|
||||||
errors += 1
|
|
||||||
except ValueError:
|
|
||||||
LOG.critical("BASE_URL does not exist!")
|
|
||||||
errors += 1
|
|
||||||
|
|
||||||
# Validate IP_TO_LOCATION
|
|
||||||
try:
|
|
||||||
if not config["CONFIG"]["IP_TO_LOCATION"]:
|
|
||||||
LOG.error("IP_TO_LOCATION is not set")
|
|
||||||
errors += 1
|
|
||||||
elif config["CONFIG"]["IP_TO_LOCATION"].upper() not in [
|
|
||||||
"TRUE",
|
|
||||||
"FALSE",
|
|
||||||
"T",
|
|
||||||
"F",
|
|
||||||
]:
|
|
||||||
LOG.error("IP_TO_LOCATION is not set to TRUE or FALSE")
|
|
||||||
errors += 1
|
|
||||||
else:
|
|
||||||
iptolocation = (
|
|
||||||
True
|
|
||||||
if config["CONFIG"]["IP_TO_LOCATION"].upper() in ["TRUE", "T"]
|
|
||||||
else False
|
|
||||||
)
|
|
||||||
# Validate API_KEY if IP_TO_LOCATION is set to TRUE
|
|
||||||
if iptolocation:
|
|
||||||
try:
|
|
||||||
if not config["CONFIG"]["API_KEY"]:
|
|
||||||
LOG.error("API_KEY is not set")
|
|
||||||
errors += 1
|
|
||||||
except ValueError:
|
|
||||||
LOG.critical("API_KEY does not exist!")
|
|
||||||
errors += 1
|
|
||||||
except ValueError:
|
|
||||||
LOG.critical("IP_TO_LOCATION does not exist!")
|
|
||||||
errors += 1
|
|
||||||
|
|
||||||
if errors > 0:
|
|
||||||
LOG.critical(f"{errors} error(s) found in `config.ini`")
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
|
|
||||||
def validate_config():
|
|
||||||
# If the app is running in Docker
|
|
||||||
if "BASE_URL" in os.environ or "IP_TO_LOCATION" in os.environ:
|
|
||||||
return validate_docker_config()
|
|
||||||
|
|
||||||
# Otherwise, the app is running on bare metal
|
|
||||||
try:
|
|
||||||
with open("config.ini", "r") as f:
|
|
||||||
file_contents = f.read()
|
|
||||||
return validate_bare_metal_config(file_contents)
|
|
||||||
except FileNotFoundError:
|
|
||||||
config = configparser.ConfigParser()
|
|
||||||
config["CONFIG"] = {"BASE_URL": "", "IP_TO_LOCATION": "", "API_KEY": ""}
|
|
||||||
|
|
||||||
with open("config.ini", "w") as configfile:
|
|
||||||
config.write(configfile)
|
|
||||||
|
|
||||||
LOG.error(
|
|
||||||
"`config.ini` has been created. Fill out the necessary information then re-run."
|
|
||||||
)
|
|
||||||
sys.exit()
|
|
59
var.py
59
var.py
@ -1,59 +0,0 @@
|
|||||||
import configparser
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
from colorlog import ColoredFormatter
|
|
||||||
|
|
||||||
|
|
||||||
log_level = logging.DEBUG
|
|
||||||
log_format = "%(log_color)s%(levelname)-8s%(reset)s %(log_color)s%(message)s%(reset)s"
|
|
||||||
|
|
||||||
logging.root.setLevel(log_level)
|
|
||||||
formatter = ColoredFormatter(log_format)
|
|
||||||
|
|
||||||
stream = logging.StreamHandler()
|
|
||||||
stream.setLevel(log_level)
|
|
||||||
stream.setFormatter(formatter)
|
|
||||||
|
|
||||||
LOG = logging.getLogger("pythonConfig")
|
|
||||||
LOG.setLevel(log_level)
|
|
||||||
LOG.addHandler(stream)
|
|
||||||
|
|
||||||
|
|
||||||
# If the app is running in Docker
|
|
||||||
if "BASE_URL" in os.environ or "IP_TO_LOCATION" in os.environ:
|
|
||||||
BASE_URL = os.environ["BASE_URL"]
|
|
||||||
IP_TO_LOCATION = (
|
|
||||||
True if os.environ["IP_TO_LOCATION"].upper() in ["TRUE", "T"] else False
|
|
||||||
)
|
|
||||||
if IP_TO_LOCATION:
|
|
||||||
API_KEY = os.environ["API_KEY"]
|
|
||||||
else:
|
|
||||||
API_KEY = None
|
|
||||||
|
|
||||||
# Otherwise, the app is running on bare metal
|
|
||||||
try:
|
|
||||||
with open("config.ini", "r") as f:
|
|
||||||
config = configparser.ConfigParser()
|
|
||||||
config.read_string(f.read())
|
|
||||||
|
|
||||||
BASE_URL = config["CONFIG"]["BASE_URL"]
|
|
||||||
IP_TO_LOCATION = (
|
|
||||||
True
|
|
||||||
if config["CONFIG"]["IP_TO_LOCATION"].upper() in ["TRUE", "T"]
|
|
||||||
else False
|
|
||||||
)
|
|
||||||
if IP_TO_LOCATION:
|
|
||||||
API_KEY = config["CONFIG"]["API_KEY"]
|
|
||||||
else:
|
|
||||||
API_KEY = None
|
|
||||||
except FileNotFoundError:
|
|
||||||
config = configparser.ConfigParser()
|
|
||||||
config["CONFIG"] = {"BASE_URL": "", "IP_TO_LOCATION": "", "API_KEY": ""}
|
|
||||||
|
|
||||||
with open("config.ini", "w") as configfile:
|
|
||||||
config.write(configfile)
|
|
||||||
|
|
||||||
LOG.error(
|
|
||||||
"`config.ini` has been created. Fill out the necessary information then re-run."
|
|
||||||
)
|
|
||||||
exit()
|
|
Loading…
x
Reference in New Issue
Block a user