2019-09-24 18:34:35 +00:00
|
|
|
import importlib.util
|
2019-06-10 21:24:35 +00:00
|
|
|
from datetime import datetime
|
2019-09-24 18:34:35 +00:00
|
|
|
from pathlib import Path
|
2019-12-14 21:33:04 +00:00
|
|
|
from uuid import uuid4
|
2019-07-17 15:17:27 +00:00
|
|
|
|
2019-07-08 21:01:16 +00:00
|
|
|
import attr
|
2019-06-10 21:24:35 +00:00
|
|
|
from furl import furl
|
2019-09-24 18:34:35 +00:00
|
|
|
from mongoengine.connection import get_db
|
|
|
|
from semantic_version import Version
|
2019-06-10 21:24:35 +00:00
|
|
|
|
2019-09-24 18:34:35 +00:00
|
|
|
import database.utils
|
2019-10-25 12:36:58 +00:00
|
|
|
from bll.queue import QueueBLL
|
2019-06-10 21:24:35 +00:00
|
|
|
from config import config
|
2020-01-02 13:20:55 +00:00
|
|
|
from config.info import get_default_company
|
2019-09-24 18:34:35 +00:00
|
|
|
from database import Database
|
2019-06-10 21:24:35 +00:00
|
|
|
from database.model.auth import Role
|
2019-07-17 15:17:27 +00:00
|
|
|
from database.model.auth import User as AuthUser, Credentials
|
2019-06-10 21:24:35 +00:00
|
|
|
from database.model.company import Company
|
2019-10-25 12:36:58 +00:00
|
|
|
from database.model.queue import Queue
|
2019-12-14 21:33:04 +00:00
|
|
|
from database.model.settings import Settings
|
2019-07-17 15:17:27 +00:00
|
|
|
from database.model.user import User
|
2019-09-24 18:34:35 +00:00
|
|
|
from database.model.version import Version as DatabaseVersion
|
2019-06-10 21:24:35 +00:00
|
|
|
from elastic.apply_mappings import apply_mappings_to_host
|
2019-07-17 15:17:27 +00:00
|
|
|
from es_factory import get_cluster_config
|
2019-07-08 21:01:16 +00:00
|
|
|
from service_repo.auth.fixed_user import FixedUser
|
2019-06-10 21:24:35 +00:00
|
|
|
|
|
|
|
log = config.logger(__file__)
|
|
|
|
|
2019-12-29 06:58:54 +00:00
|
|
|
migration_dir = Path(__file__).resolve().parent / "mongo" / "migrations"
|
2019-09-24 18:34:35 +00:00
|
|
|
|
2019-06-10 21:24:35 +00:00
|
|
|
|
|
|
|
class MissingElasticConfiguration(Exception):
|
|
|
|
"""
|
|
|
|
Exception when cluster configuration is not found in config files
|
|
|
|
"""
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def init_es_data():
|
2019-07-17 15:17:27 +00:00
|
|
|
hosts_config = get_cluster_config("events").get("hosts")
|
2019-06-10 21:24:35 +00:00
|
|
|
if not hosts_config:
|
2019-07-17 15:17:27 +00:00
|
|
|
raise MissingElasticConfiguration("for cluster 'events'")
|
2019-06-10 21:24:35 +00:00
|
|
|
|
|
|
|
for conf in hosts_config:
|
|
|
|
host = furl(scheme="http", host=conf["host"], port=conf["port"]).url
|
|
|
|
log.info(f"Applying mappings to host: {host}")
|
|
|
|
res = apply_mappings_to_host(host)
|
|
|
|
log.info(res)
|
|
|
|
|
|
|
|
|
|
|
|
def _ensure_company():
|
2020-01-02 13:20:55 +00:00
|
|
|
company_id = get_default_company()
|
2019-06-10 21:24:35 +00:00
|
|
|
company = Company.objects(id=company_id).only("id").first()
|
|
|
|
if company:
|
|
|
|
return company_id
|
|
|
|
|
|
|
|
company_name = "trains"
|
|
|
|
log.info(f"Creating company: {company_name}")
|
|
|
|
company = Company(id=company_id, name=company_name)
|
|
|
|
company.save()
|
|
|
|
return company_id
|
|
|
|
|
|
|
|
|
2019-10-25 12:36:58 +00:00
|
|
|
def _ensure_default_queue(company):
|
|
|
|
"""
|
|
|
|
If no queue is present for the company then
|
|
|
|
create a new one and mark it as a default
|
|
|
|
"""
|
|
|
|
queue = Queue.objects(company=company).only("id").first()
|
|
|
|
if queue:
|
|
|
|
return
|
|
|
|
|
|
|
|
QueueBLL.create(company, name="default", system_tags=["default"])
|
|
|
|
|
|
|
|
|
2019-07-08 21:01:16 +00:00
|
|
|
def _ensure_auth_user(user_data, company_id):
|
|
|
|
ensure_credentials = {"key", "secret"}.issubset(user_data.keys())
|
|
|
|
if ensure_credentials:
|
|
|
|
user = AuthUser.objects(
|
|
|
|
credentials__match=Credentials(
|
|
|
|
key=user_data["key"], secret=user_data["secret"]
|
|
|
|
)
|
|
|
|
).first()
|
|
|
|
if user:
|
|
|
|
return user.id
|
2019-06-10 21:24:35 +00:00
|
|
|
|
|
|
|
log.info(f"Creating user: {user_data['name']}")
|
2019-07-08 21:01:16 +00:00
|
|
|
user = AuthUser(
|
|
|
|
id=user_data.get("id", f"__{user_data['name']}__"),
|
2019-06-10 21:24:35 +00:00
|
|
|
name=user_data["name"],
|
|
|
|
company=company_id,
|
|
|
|
role=user_data["role"],
|
|
|
|
email=user_data["email"],
|
|
|
|
created=datetime.utcnow(),
|
2019-07-08 21:01:16 +00:00
|
|
|
credentials=[Credentials(key=user_data["key"], secret=user_data["secret"])]
|
|
|
|
if ensure_credentials
|
|
|
|
else None,
|
2019-06-10 21:24:35 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
user.save()
|
|
|
|
|
|
|
|
return user.id
|
|
|
|
|
|
|
|
|
2019-07-08 21:01:16 +00:00
|
|
|
def _ensure_user(user: FixedUser, company_id: str):
|
|
|
|
if User.objects(id=user.user_id).first():
|
|
|
|
return
|
|
|
|
|
|
|
|
data = attr.asdict(user)
|
|
|
|
data["id"] = user.user_id
|
|
|
|
data["email"] = f"{user.user_id}@example.com"
|
|
|
|
data["role"] = Role.user
|
|
|
|
|
2019-12-14 21:33:04 +00:00
|
|
|
_ensure_auth_user(user_data=data, company_id=company_id)
|
2019-07-08 21:01:16 +00:00
|
|
|
|
|
|
|
given_name, _, family_name = user.name.partition(" ")
|
|
|
|
|
|
|
|
User(
|
|
|
|
id=user.user_id,
|
|
|
|
company=company_id,
|
|
|
|
name=user.name,
|
|
|
|
given_name=given_name,
|
|
|
|
family_name=family_name,
|
|
|
|
).save()
|
|
|
|
|
|
|
|
|
2019-09-24 18:34:35 +00:00
|
|
|
def _apply_migrations():
|
|
|
|
if not migration_dir.is_dir():
|
|
|
|
raise ValueError(f"Invalid migration dir {migration_dir}")
|
|
|
|
|
|
|
|
try:
|
|
|
|
previous_versions = sorted(
|
|
|
|
(Version(ver.num) for ver in DatabaseVersion.objects().only("num")),
|
|
|
|
reverse=True,
|
|
|
|
)
|
|
|
|
except ValueError as ex:
|
|
|
|
raise ValueError(f"Invalid database version number encountered: {ex}")
|
|
|
|
|
|
|
|
last_version = previous_versions[0] if previous_versions else Version("0.0.0")
|
|
|
|
|
|
|
|
try:
|
|
|
|
new_scripts = {
|
|
|
|
ver: path
|
2019-12-14 21:33:04 +00:00
|
|
|
for ver, path in ((Version(f.stem), f) for f in migration_dir.glob("*.py"))
|
2019-09-24 18:34:35 +00:00
|
|
|
if ver > last_version
|
|
|
|
}
|
|
|
|
except ValueError as ex:
|
|
|
|
raise ValueError(f"Failed parsing migration version from file: {ex}")
|
|
|
|
|
|
|
|
dbs = {Database.auth: "migrate_auth", Database.backend: "migrate_backend"}
|
|
|
|
|
|
|
|
migration_log = log.getChild("mongodb_migration")
|
|
|
|
|
|
|
|
for script_version in sorted(new_scripts.keys()):
|
|
|
|
script = new_scripts[script_version]
|
|
|
|
spec = importlib.util.spec_from_file_location(script.stem, str(script))
|
|
|
|
module = importlib.util.module_from_spec(spec)
|
|
|
|
spec.loader.exec_module(module)
|
|
|
|
|
|
|
|
for alias, func_name in dbs.items():
|
|
|
|
func = getattr(module, func_name, None)
|
|
|
|
if not func:
|
|
|
|
continue
|
|
|
|
try:
|
|
|
|
migration_log.info(f"Applying {script.stem}/{func_name}()")
|
|
|
|
func(get_db(alias))
|
|
|
|
except Exception:
|
|
|
|
migration_log.exception(f"Failed applying {script}:{func_name}()")
|
|
|
|
raise ValueError("Migration failed, aborting. Please restore backup.")
|
|
|
|
|
|
|
|
DatabaseVersion(
|
|
|
|
id=database.utils.id(),
|
|
|
|
num=script.stem,
|
|
|
|
created=datetime.utcnow(),
|
|
|
|
desc="Applied on server startup",
|
|
|
|
).save()
|
|
|
|
|
|
|
|
|
2019-12-14 21:33:04 +00:00
|
|
|
def _ensure_uuid():
|
|
|
|
Settings.add_value("server.uuid", str(uuid4()))
|
|
|
|
|
|
|
|
|
2019-06-10 21:24:35 +00:00
|
|
|
def init_mongo_data():
|
2019-07-08 21:01:16 +00:00
|
|
|
try:
|
2019-09-24 18:34:35 +00:00
|
|
|
_apply_migrations()
|
|
|
|
|
2019-12-14 21:33:04 +00:00
|
|
|
_ensure_uuid()
|
|
|
|
|
2019-07-08 21:01:16 +00:00
|
|
|
company_id = _ensure_company()
|
2019-10-25 12:36:58 +00:00
|
|
|
_ensure_default_queue(company_id)
|
|
|
|
|
2019-07-08 21:01:16 +00:00
|
|
|
users = [
|
2019-12-14 21:33:04 +00:00
|
|
|
{
|
|
|
|
"name": "apiserver",
|
|
|
|
"role": Role.system,
|
|
|
|
"email": "apiserver@example.com",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"name": "webserver",
|
|
|
|
"role": Role.system,
|
|
|
|
"email": "webserver@example.com",
|
|
|
|
},
|
2019-07-08 21:01:16 +00:00
|
|
|
{"name": "tests", "role": Role.user, "email": "tests@example.com"},
|
|
|
|
]
|
|
|
|
|
|
|
|
for user in users:
|
|
|
|
credentials = config.get(f"secure.credentials.{user['name']}")
|
|
|
|
user["key"] = credentials.user_key
|
|
|
|
user["secret"] = credentials.user_secret
|
|
|
|
_ensure_auth_user(user, company_id)
|
|
|
|
|
|
|
|
if FixedUser.enabled():
|
2019-07-17 15:17:27 +00:00
|
|
|
log.info("Fixed users mode is enabled")
|
2020-01-02 13:20:55 +00:00
|
|
|
FixedUser.validate()
|
2019-07-08 21:01:16 +00:00
|
|
|
for user in FixedUser.from_config():
|
2019-07-17 15:17:27 +00:00
|
|
|
try:
|
|
|
|
_ensure_user(user, company_id)
|
|
|
|
except Exception as ex:
|
2019-12-24 15:58:59 +00:00
|
|
|
log.error(f"Failed creating fixed user {user.name}: {ex}")
|
2019-07-08 21:01:16 +00:00
|
|
|
except Exception as ex:
|
2019-09-24 18:34:35 +00:00
|
|
|
log.exception("Failed initializing mongodb")
|