You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
635 lines
22 KiB
Python
635 lines
22 KiB
Python
1 year ago
|
from __future__ import print_function
|
||
|
|
||
|
import os
|
||
|
import shutil
|
||
|
import sys
|
||
|
import subprocess
|
||
|
import tempfile
|
||
|
from seiscomp import config, kernel, system
|
||
|
|
||
|
# Python version depended string conversion
|
||
|
if sys.version_info[0] < 3:
|
||
|
py3bstr = str
|
||
|
py3ustr = str
|
||
|
|
||
|
else:
|
||
|
py3bstr = lambda s: s.encode('utf-8')
|
||
|
py3ustr = lambda s: s.decode('utf-8', 'replace')
|
||
|
|
||
|
|
||
|
class DBParams:
|
||
|
def __init__(self):
|
||
|
self.db = None
|
||
|
self.rwuser = None
|
||
|
self.rwpwd = None
|
||
|
self.rouser = None
|
||
|
self.ropwd = None
|
||
|
self.rohost = None
|
||
|
self.rwhost = None
|
||
|
self.drop = False
|
||
|
self.create = False
|
||
|
|
||
|
|
||
|
def check_output(cmd):
|
||
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
||
|
stderr=subprocess.PIPE, shell=True)
|
||
|
out = proc.communicate()
|
||
|
return [py3ustr(out[0]), py3ustr(out[1]), proc.returncode]
|
||
|
|
||
|
|
||
|
def addEntry(cfg, param, item):
|
||
|
# Adds an item to a parameter list
|
||
|
try:
|
||
|
items = cfg.getStrings(param)
|
||
|
except ValueError:
|
||
|
items = config.VectorStr()
|
||
|
|
||
|
if item not in items:
|
||
|
items.push_back(item)
|
||
|
cfg.setStrings(param, items)
|
||
|
|
||
|
|
||
|
def removeEntry(cfg, param, item):
|
||
|
# Removes an items from a parameter list
|
||
|
try:
|
||
|
items = cfg.getStrings(param)
|
||
|
for i in range(items.size()):
|
||
|
if items[i] == item:
|
||
|
items.erase(items.begin() + i)
|
||
|
cfg.setStrings(param, items)
|
||
|
break
|
||
|
except ValueError:
|
||
|
# No parameter set, nothing to do
|
||
|
pass
|
||
|
|
||
|
|
||
|
# The kernel module which starts scmaster if enabled
|
||
|
class Module(kernel.CoreModule):
|
||
|
def __init__(self, env):
|
||
|
kernel.CoreModule.__init__(
|
||
|
self, env, env.moduleName(__file__))
|
||
|
# High priority
|
||
|
self.order = -1
|
||
|
|
||
|
# Default values
|
||
|
self.messaging = True
|
||
|
self.messagingBind = None
|
||
|
|
||
|
try:
|
||
|
self.messaging = self.env.getBool("messaging.enable")
|
||
|
except ValueError:
|
||
|
pass
|
||
|
try:
|
||
|
self.messagingBind = self.env.getString("messaging.bind")
|
||
|
except ValueError:
|
||
|
pass
|
||
|
|
||
|
# Add master port
|
||
|
def _get_start_params(self):
|
||
|
if self.messagingBind:
|
||
|
return kernel.Module._get_start_params(self) + \
|
||
|
" --bind %s" % self.messagingBind
|
||
|
|
||
|
return kernel.Module._get_start_params(self)
|
||
|
|
||
|
def start(self):
|
||
|
if not self.messaging:
|
||
|
print("[kernel] {} is disabled by config".format(self.name),
|
||
|
file=sys.stderr)
|
||
|
return 1
|
||
|
|
||
|
appConfig = system.Environment.Instance().appConfigFileName(self.name)
|
||
|
localConfig = system.Environment.Instance().configFileName(self.name)
|
||
|
lockFile = os.path.join(self.env.SEISCOMP_ROOT, self.env.lockFile(self.name))
|
||
|
try:
|
||
|
needRestart = False
|
||
|
started = os.path.getmtime(lockFile)
|
||
|
try:
|
||
|
needRestart = started < os.path.getmtime(appConfig)
|
||
|
except Exception:
|
||
|
pass
|
||
|
try:
|
||
|
needRestart = started < os.path.getmtime(localConfig)
|
||
|
except Exception:
|
||
|
pass
|
||
|
|
||
|
if needRestart:
|
||
|
self.stop()
|
||
|
except Exception:
|
||
|
pass
|
||
|
|
||
|
return kernel.CoreModule.start(self)
|
||
|
|
||
|
def check(self):
|
||
|
if not self.messaging:
|
||
|
print("[kernel] {} is disabled by config".format(self.name),
|
||
|
file=sys.stderr)
|
||
|
return 0
|
||
|
|
||
|
return kernel.CoreModule.check(self)
|
||
|
|
||
|
def status(self, shouldRun):
|
||
|
if not self.messaging:
|
||
|
shouldRun = False
|
||
|
return kernel.CoreModule.status(self, shouldRun)
|
||
|
|
||
|
def readDBParams(self, params, setup_config):
|
||
|
try:
|
||
|
params.db = setup_config.getString(self.name
|
||
|
+ ".database.enable.backend.db")
|
||
|
except ValueError as err:
|
||
|
print(err)
|
||
|
print(" - database name not set, ignoring setup",
|
||
|
file=sys.stderr)
|
||
|
return False
|
||
|
|
||
|
try:
|
||
|
params.rwhost = setup_config.getString(
|
||
|
self.name + ".database.enable.backend.rwhost")
|
||
|
except ValueError:
|
||
|
print(" - database host (rw) not set, ignoring setup",
|
||
|
file=sys.stderr)
|
||
|
return False
|
||
|
|
||
|
try:
|
||
|
params.rwuser = setup_config.getString(
|
||
|
self.name + ".database.enable.backend.rwuser")
|
||
|
except ValueError:
|
||
|
print(" - database user (rw) not set, ignoring setup",
|
||
|
file=sys.stderr)
|
||
|
return False
|
||
|
|
||
|
try:
|
||
|
params.rwpwd = setup_config.getString(
|
||
|
self.name + ".database.enable.backend.rwpwd")
|
||
|
except ValueError:
|
||
|
print(" - database password (rw) not set, ignoring setup",
|
||
|
file=sys.stderr)
|
||
|
return False
|
||
|
|
||
|
try:
|
||
|
params.rohost = setup_config.getString(
|
||
|
self.name + ".database.enable.backend.rohost")
|
||
|
except ValueError:
|
||
|
print(" - database host (ro) not set, ignoring setup",
|
||
|
file=sys.stderr)
|
||
|
return False
|
||
|
|
||
|
try:
|
||
|
params.rouser = setup_config.getString(
|
||
|
self.name + ".database.enable.backend.rouser")
|
||
|
except ValueError:
|
||
|
print(" - database user (ro) not set, ignoring setup",
|
||
|
file=sys.stderr)
|
||
|
return False
|
||
|
|
||
|
try:
|
||
|
params.ropwd = setup_config.getString(
|
||
|
self.name + ".database.enable.backend.ropwd")
|
||
|
except ValueError:
|
||
|
print(" - database password (ro) not set, ignoring setup",
|
||
|
file=sys.stderr)
|
||
|
return False
|
||
|
|
||
|
try:
|
||
|
params.create = setup_config.getBool(
|
||
|
self.name + ".database.enable.backend.create")
|
||
|
except ValueError:
|
||
|
params.create = False
|
||
|
|
||
|
try:
|
||
|
params.drop = setup_config.getBool(
|
||
|
self.name + ".database.enable.backend.create.drop")
|
||
|
except ValueError:
|
||
|
params.drop = False
|
||
|
|
||
|
return True
|
||
|
|
||
|
def setup(self, setup_config):
|
||
|
schemapath = os.path.join(self.env.SEISCOMP_ROOT, "share", "db")
|
||
|
|
||
|
cfg = config.Config()
|
||
|
system.Environment.Instance().initConfig(cfg, self.name)
|
||
|
|
||
|
try:
|
||
|
dbenable = setup_config.getBool(self.name + ".database.enable")
|
||
|
except ValueError:
|
||
|
print(" - database.enable not set, ignoring setup",
|
||
|
file=sys.stderr)
|
||
|
return 0
|
||
|
|
||
|
dbBackend = None
|
||
|
|
||
|
if not dbenable:
|
||
|
removeEntry(cfg, "queues.production.plugins", "dbstore")
|
||
|
removeEntry(
|
||
|
cfg, "queues.production.processors.messages", "dbstore")
|
||
|
cfg.remove("queues.production.processors.messages.dbstore.driver")
|
||
|
cfg.remove("queues.production.processors.messages.dbstore.read")
|
||
|
cfg.remove("queues.production.processors.messages.dbstore.write")
|
||
|
else:
|
||
|
try:
|
||
|
dbBackend = setup_config.getString(
|
||
|
self.name + ".database.enable.backend")
|
||
|
except ValueError:
|
||
|
print(" - database backend not set, ignoring setup",
|
||
|
file=sys.stderr)
|
||
|
return 1
|
||
|
|
||
|
if dbBackend == "mysql/mariadb":
|
||
|
dbBackend = "mysql"
|
||
|
try:
|
||
|
rootpwd = setup_config.getString(
|
||
|
self.name + ".database.enable.backend.create.rootpw")
|
||
|
except ValueError:
|
||
|
rootpwd = ""
|
||
|
|
||
|
try:
|
||
|
runAsSuperUser = setup_config.getBool(
|
||
|
self.name + ".database.enable.backend.create.runAsSuperUser")
|
||
|
except ValueError:
|
||
|
runAsSuperUser = False
|
||
|
|
||
|
params = DBParams()
|
||
|
if not self.readDBParams(params, setup_config):
|
||
|
return 1
|
||
|
|
||
|
cfg.setString("queues.production.processors.messages.dbstore.read",
|
||
|
"{}:{}@{}/{}"
|
||
|
.format(params.rouser, params.ropwd, params.rohost, params.db))
|
||
|
cfg.setString("queues.production.processors.messages.dbstore.write",
|
||
|
"{}:{}@{}/{}"
|
||
|
.format(params.rwuser, params.rwpwd, params.rwhost, params.db))
|
||
|
|
||
|
if params.create:
|
||
|
dbScript = os.path.join(schemapath, "mysql_setup.py")
|
||
|
options = [
|
||
|
params.db,
|
||
|
params.rwuser,
|
||
|
params.rwpwd,
|
||
|
params.rouser,
|
||
|
params.ropwd,
|
||
|
params.rwhost,
|
||
|
rootpwd,
|
||
|
str(params.drop),
|
||
|
schemapath
|
||
|
]
|
||
|
|
||
|
binary = os.path.join(schemapath, "pkexec_wrapper.sh")
|
||
|
print("+ Running MySQL database setup script {}"
|
||
|
.format(dbScript), file=sys.stderr)
|
||
|
if runAsSuperUser:
|
||
|
cmd = "{} seiscomp-python {} {}".format(binary, dbScript, " ".join(options))
|
||
|
else:
|
||
|
cmd = "{} {}".format(dbScript, " ".join(options))
|
||
|
|
||
|
p = subprocess.Popen(cmd, shell=True)
|
||
|
ret = p.wait()
|
||
|
if ret != 0:
|
||
|
print(" - Failed to setup database", file=sys.stderr)
|
||
|
return 1
|
||
|
|
||
|
elif dbBackend == "postgresql":
|
||
|
dbBackend = "postgresql"
|
||
|
|
||
|
params = DBParams()
|
||
|
if not self.readDBParams(params, setup_config):
|
||
|
return 1
|
||
|
|
||
|
cfg.setString("queues.production.processors.messages.dbstore.read",
|
||
|
"{}:{}@{}/{}"
|
||
|
.format(params.rouser, params.ropwd,
|
||
|
params.rohost, params.db))
|
||
|
cfg.setString("queues.production.processors.messages.dbstore.write",
|
||
|
"{}:{}@{}/{}"
|
||
|
.format(params.rwuser, params.rwpwd,
|
||
|
params.rwhost, params.db))
|
||
|
|
||
|
if params.create:
|
||
|
try:
|
||
|
tmpPath = tempfile.mkdtemp()
|
||
|
os.chmod(tmpPath, 0o755)
|
||
|
tmpPath = os.path.join(tmpPath, "setup")
|
||
|
try:
|
||
|
shutil.copytree(schemapath, tmpPath)
|
||
|
filename = os.path.join(self.env.SEISCOMP_ROOT,
|
||
|
"bin", "seiscomp-python")
|
||
|
shutil.copy(filename, tmpPath)
|
||
|
except Exception as err:
|
||
|
print(err)
|
||
|
return 1
|
||
|
|
||
|
dbScript = os.path.join(tmpPath, "postgres_setup.py")
|
||
|
options = [
|
||
|
params.db,
|
||
|
params.rwuser,
|
||
|
params.rwpwd,
|
||
|
params.rouser,
|
||
|
params.ropwd,
|
||
|
params.rwhost,
|
||
|
str(params.drop),
|
||
|
tmpPath
|
||
|
]
|
||
|
|
||
|
binary = os.path.join(schemapath, "pkexec_wrapper.sh")
|
||
|
print("+ Running PostgreSQL database setup script {}"
|
||
|
.format(dbScript), file=sys.stderr)
|
||
|
cmd = "{} su postgres -c \"{}/seiscomp-python {} {}\"" \
|
||
|
.format(binary, tmpPath, dbScript, " ".join(options))
|
||
|
|
||
|
p = subprocess.Popen(cmd, shell=True)
|
||
|
ret = p.wait()
|
||
|
if ret != 0:
|
||
|
print(" - Failed to setup database",
|
||
|
file=sys.stderr)
|
||
|
return 1
|
||
|
finally:
|
||
|
try:
|
||
|
shutil.rmtree(tmpPath)
|
||
|
except OSError:
|
||
|
pass
|
||
|
|
||
|
elif dbBackend == "sqlite3":
|
||
|
dbBackend = "sqlite3"
|
||
|
dbScript = os.path.join(schemapath, "sqlite3_setup.py")
|
||
|
|
||
|
try:
|
||
|
create = setup_config.getBool(
|
||
|
self.name + ".database.enable.backend.create")
|
||
|
except BaseException:
|
||
|
create = False
|
||
|
|
||
|
try:
|
||
|
filename = setup_config.getString(
|
||
|
self.name + ".database.enable.backend.filename")
|
||
|
filename = system.Environment.Instance().absolutePath(filename)
|
||
|
except BaseException:
|
||
|
filename = os.path.join(self.env.SEISCOMP_ROOT, "var",
|
||
|
"lib", "seiscomp.db")
|
||
|
|
||
|
if not filename:
|
||
|
print(" - location not set, ignoring setup",
|
||
|
file=sys.stderr)
|
||
|
return 1
|
||
|
|
||
|
try:
|
||
|
override = setup_config.getBool(
|
||
|
self.name + ".database.enable.backend.create.override")
|
||
|
except BaseException:
|
||
|
override = False
|
||
|
|
||
|
options = [
|
||
|
filename,
|
||
|
schemapath
|
||
|
]
|
||
|
|
||
|
if create:
|
||
|
print("+ Running SQLite3 database setup script {}"
|
||
|
.format(dbScript), file=sys.stderr)
|
||
|
cmd = "seiscomp-python {} {} {}".format(dbScript, " ".join(options), override)
|
||
|
p = subprocess.Popen(cmd, shell=True)
|
||
|
ret = p.wait()
|
||
|
if ret != 0:
|
||
|
print(" - Failed to setup database", file=sys.stderr)
|
||
|
return 1
|
||
|
|
||
|
cfg.setString("queues.production.processors.messages.dbstore.read",
|
||
|
filename)
|
||
|
cfg.setString("queues.production.processors.messages.dbstore.write",
|
||
|
filename)
|
||
|
|
||
|
# Configure db backend for scmaster
|
||
|
cfg.setString("core.plugins", "db" + dbBackend)
|
||
|
cfg.setString(
|
||
|
"queues.production.processors.messages.dbstore.driver",
|
||
|
dbBackend)
|
||
|
|
||
|
addEntry(cfg, "queues.production.plugins", "dbstore")
|
||
|
addEntry(cfg, "queues.production.processors.messages", "dbstore")
|
||
|
|
||
|
cfg.writeConfig(
|
||
|
system.Environment.Instance().configFileLocation(
|
||
|
self.name, system.Environment.CS_CONFIG_APP))
|
||
|
|
||
|
# Now we need to insert the corresponding plugin to etc/global.cfg
|
||
|
# that all connected local clients can handle the database backend
|
||
|
if dbBackend:
|
||
|
cfgfile = os.path.join(self.env.SEISCOMP_ROOT, "etc", "global.cfg")
|
||
|
cfg = config.Config()
|
||
|
cfg.readConfig(cfgfile)
|
||
|
cfg.setString("core.plugins", "db" + dbBackend)
|
||
|
cfg.writeConfig()
|
||
|
|
||
|
return 0
|
||
|
|
||
|
def updateConfig(self):
|
||
|
cfg = config.Config()
|
||
|
system.Environment.Instance().initConfig(cfg, self.name)
|
||
|
|
||
|
try:
|
||
|
queues = cfg.getStrings("queues")
|
||
|
except ValueError:
|
||
|
queues = []
|
||
|
|
||
|
# iterate through all queues and check DB schema version if message
|
||
|
# processor dbstore is present
|
||
|
for queue in queues:
|
||
|
print("INFO: Checking queue '{}'".format(queue), file=sys.stderr)
|
||
|
try:
|
||
|
msgProcs = cfg.getStrings("queues.{}.processors.messages"
|
||
|
.format(queue))
|
||
|
if "dbstore" in msgProcs and not self.checkDBStore(cfg, queue):
|
||
|
return 1
|
||
|
except ValueError:
|
||
|
print(" * ignoring - no database backend configured",
|
||
|
file=sys.stderr)
|
||
|
|
||
|
return 0
|
||
|
|
||
|
def checkDBStore(self, cfg, queue):
|
||
|
prefix = "queues.{}.processors.messages.dbstore".format(queue)
|
||
|
|
||
|
print(" * checking DB schema version", file=sys.stderr)
|
||
|
|
||
|
try:
|
||
|
backend = cfg.getString("{}.driver".format(prefix))
|
||
|
except ValueError:
|
||
|
print("WARNING: dbstore message processor activated but no "
|
||
|
"database backend configured", file=sys.stderr)
|
||
|
return True
|
||
|
|
||
|
if backend not in ("mysql", "postgresql"):
|
||
|
print("WARNING: Only MySQL and PostgreSQL migrations are "
|
||
|
"supported right now. Please check and upgrade the "
|
||
|
"database schema version yourselves.", file=sys.stderr)
|
||
|
return True
|
||
|
|
||
|
print(" * check database write access ... ", end='', file=sys.stderr)
|
||
|
|
||
|
# 1. Parse connection
|
||
|
try:
|
||
|
params = cfg.getString("{}.write".format(prefix))
|
||
|
except ValueError:
|
||
|
print("failed", file=sys.stderr)
|
||
|
print("WARNING: dbstore message processor activated but no "
|
||
|
"write connection configured", file=sys.stderr)
|
||
|
return True
|
||
|
|
||
|
user = 'sysop'
|
||
|
pwd = 'sysop'
|
||
|
host = 'localhost'
|
||
|
db = 'seiscomp'
|
||
|
port = None
|
||
|
|
||
|
tmp = params.split('@')
|
||
|
if len(tmp) > 1:
|
||
|
params = tmp[1]
|
||
|
|
||
|
tmp = tmp[0].split(':')
|
||
|
if len(tmp) == 1:
|
||
|
user = tmp[0]
|
||
|
pwd = None
|
||
|
elif len(tmp) == 2:
|
||
|
user = tmp[0]
|
||
|
pwd = tmp[1]
|
||
|
else:
|
||
|
print("failed", file=sys.stderr)
|
||
|
print("WARNING: Invalid scmaster.cfg:{}.write, cannot check "
|
||
|
"schema version".format(prefix), file=sys.stderr)
|
||
|
return True
|
||
|
|
||
|
tmp = params.split('/')
|
||
|
if len(tmp) > 1:
|
||
|
tmpHost = tmp[0]
|
||
|
db = tmp[1]
|
||
|
else:
|
||
|
tmpHost = tmp[0]
|
||
|
|
||
|
# get host name and port
|
||
|
tmp = tmpHost.split(':')
|
||
|
host = tmp[0]
|
||
|
if len(tmp) == 2:
|
||
|
try:
|
||
|
port = int(tmp[1])
|
||
|
except ValueError:
|
||
|
print("ERROR: Invalid port number {}".format(tmp[1]),
|
||
|
file=sys.stderr)
|
||
|
return True
|
||
|
|
||
|
db = db.split('?')[0]
|
||
|
|
||
|
# 2. Try to login
|
||
|
if backend == "mysql":
|
||
|
cmd = "mysql -u \"%s\" -h \"%s\" -D\"%s\" --skip-column-names" % (
|
||
|
user, host, db)
|
||
|
if port:
|
||
|
cmd += " -P %d" % (port)
|
||
|
if pwd:
|
||
|
cmd += " -p\"%s\"" % pwd.replace('$', '\\$')
|
||
|
cmd += " -e \"SELECT value from Meta where name='Schema-Version'\""
|
||
|
else:
|
||
|
if pwd:
|
||
|
os.environ['PGPASSWORD'] = pwd
|
||
|
cmd = "psql -U \"%s\" -h \"%s\" -t \"%s\"" % (user, host, db)
|
||
|
if port:
|
||
|
cmd += " -p %d" % (port)
|
||
|
cmd += " -c \"SELECT value from Meta where name='Schema-Version'\""
|
||
|
|
||
|
out = check_output(cmd)
|
||
|
if out[2] != 0:
|
||
|
print("failed", file=sys.stderr)
|
||
|
print("WARNING: {} returned with error:".format(backend),
|
||
|
file=sys.stderr)
|
||
|
print(out[1].strip(), file=sys.stderr)
|
||
|
return False
|
||
|
|
||
|
print("passed", file=sys.stderr)
|
||
|
|
||
|
version = out[0].strip()
|
||
|
print(" * database schema version is {}".format(version),
|
||
|
file=sys.stderr)
|
||
|
|
||
|
try:
|
||
|
vmaj, vmin = [int(t) for t in version.split('.')]
|
||
|
except ValueError:
|
||
|
print("WARNING: wrong version format: expected MAJOR.MINOR",
|
||
|
file=sys.stderr)
|
||
|
return True
|
||
|
|
||
|
strictVersionMatch = True
|
||
|
try:
|
||
|
strictVersionMatch = cfg.getBool("{}.strictVersionMatch"
|
||
|
.format(prefix))
|
||
|
except ValueError:
|
||
|
pass
|
||
|
|
||
|
if not strictVersionMatch:
|
||
|
print(" * database version check is disabled", file=sys.stderr)
|
||
|
return True
|
||
|
|
||
|
migrations = os.path.join(self.env.SEISCOMP_ROOT, "share", "db",
|
||
|
"migrations", backend)
|
||
|
migration_paths = {}
|
||
|
|
||
|
vcurrmaj = 0
|
||
|
vcurrmin = 0
|
||
|
|
||
|
for f in os.listdir(migrations):
|
||
|
if os.path.isfile(os.path.join(migrations, f)):
|
||
|
name, ext = os.path.splitext(f)
|
||
|
if ext != '.sql':
|
||
|
continue
|
||
|
try:
|
||
|
vfrom, vto = name.split('_to_')
|
||
|
except ValueError:
|
||
|
continue
|
||
|
|
||
|
try:
|
||
|
vfrommaj, vfrommin = [int(t) for t in vfrom.split('_')]
|
||
|
except ValueError:
|
||
|
continue
|
||
|
|
||
|
try:
|
||
|
vtomaj, vtomin = [int(t) for t in vto.split('_')]
|
||
|
except ValueError:
|
||
|
continue
|
||
|
|
||
|
migration_paths[(vfrommaj, vfrommin)] = (vtomaj, vtomin)
|
||
|
|
||
|
if (vtomaj > vcurrmaj) or ((vtomaj == vcurrmaj) and (vtomin > vcurrmin)):
|
||
|
vcurrmaj = vtomaj
|
||
|
vcurrmin = vtomin
|
||
|
|
||
|
print(" * last migration version is %d.%d" % (vcurrmaj, vcurrmin),
|
||
|
file=sys.stderr)
|
||
|
|
||
|
if vcurrmaj == vmaj and vcurrmin == vmin:
|
||
|
print(" * schema up-to-date", file=sys.stderr)
|
||
|
return True
|
||
|
|
||
|
if (vmaj, vmin) not in migration_paths:
|
||
|
print(" * no migrations found", file=sys.stderr)
|
||
|
return True
|
||
|
|
||
|
print(" * migration to the current version is required. Apply the "
|
||
|
"following", file=sys.stderr)
|
||
|
print(" database migration scripts in exactly the given order:",
|
||
|
file=sys.stderr)
|
||
|
while (vmaj, vmin) in migration_paths:
|
||
|
(vtomaj, vtomin) = migration_paths[(vmaj, vmin)]
|
||
|
fname = "%d_%d_to_%d_%d.sql" % (vmaj, vmin, vtomaj, vtomin)
|
||
|
if backend == "mysql":
|
||
|
print(" * mysql -u {} -h {} -p {} < {}"
|
||
|
.format(user, host, db, os.path.join(migrations, fname)),
|
||
|
file=sys.stderr)
|
||
|
elif backend == "postgresql":
|
||
|
print(" * psql -U {} -h {} -d {} -W -f {}"
|
||
|
.format(user, host, db, os.path.join(migrations, fname)),
|
||
|
file=sys.stderr)
|
||
|
else:
|
||
|
print(" * {}".format(os.path.join(migrations, fname)),
|
||
|
file=sys.stderr)
|
||
|
(vmaj, vmin) = (vtomaj, vtomin)
|
||
|
|
||
|
return False
|