Add hostname configuration to list database
issue7375 review44991002
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
* Add hostname configuration to list database
|
||||
* Add tree mixin
|
||||
* Rename "install-dependences" into "activate-dependencies"
|
||||
* Use recursive common table expression for child_of/parent_of operators
|
||||
|
||||
@@ -73,6 +73,7 @@ def run(options):
|
||||
with Transaction().start(db_name, 0) as transaction:
|
||||
pool = Pool()
|
||||
User = pool.get('res.user')
|
||||
Configuration = pool.get('ir.configuration')
|
||||
with transaction.set_context(active_test=False):
|
||||
admin, = User.search([('login', '=', 'admin')])
|
||||
|
||||
@@ -112,3 +113,7 @@ def run(options):
|
||||
admin.save()
|
||||
if options.reset_password:
|
||||
User.reset_password([admin])
|
||||
if options.hostname is not None:
|
||||
configuration = Configuration(1)
|
||||
configuration.hostname = options.hostname or None
|
||||
configuration.save()
|
||||
|
||||
@@ -69,7 +69,7 @@ class DatabaseInterface(object):
|
||||
'''
|
||||
raise NotImplementedError
|
||||
|
||||
def list(self):
|
||||
def list(self, hostname=None):
|
||||
'''
|
||||
Get the list of database
|
||||
|
||||
@@ -83,7 +83,7 @@ class DatabaseInterface(object):
|
||||
'''
|
||||
raise NotImplementedError
|
||||
|
||||
def test(self):
|
||||
def test(self, hostname=None):
|
||||
'''
|
||||
Test if it is a Tryton database.
|
||||
'''
|
||||
|
||||
@@ -71,8 +71,8 @@ class Database(DatabaseInterface):
|
||||
_lock = RLock()
|
||||
_databases = {}
|
||||
_connpool = None
|
||||
_list_cache = None
|
||||
_list_cache_timestamp = None
|
||||
_list_cache = {}
|
||||
_list_cache_timestamp = {}
|
||||
_version_cache = {}
|
||||
_search_path = None
|
||||
_current_user = None
|
||||
@@ -153,12 +153,12 @@ class Database(DatabaseInterface):
|
||||
cursor.execute('CREATE DATABASE "' + database_name + '" '
|
||||
'TEMPLATE "' + template + '" ENCODING \'unicode\'')
|
||||
connection.commit()
|
||||
cls._list_cache = None
|
||||
cls._list_cache.clear()
|
||||
|
||||
def drop(self, connection, database_name):
|
||||
cursor = connection.cursor()
|
||||
cursor.execute('DROP DATABASE "' + database_name + '"')
|
||||
self.__class__._list_cache = None
|
||||
self.__class__._list_cache.clear()
|
||||
|
||||
def get_version(self, connection):
|
||||
if self.name not in self._version_cache:
|
||||
@@ -170,11 +170,12 @@ class Database(DatabaseInterface):
|
||||
self._version_cache[self.name] = (major, minor, patch)
|
||||
return self._version_cache[self.name]
|
||||
|
||||
def list(self):
|
||||
def list(self, hostname=None):
|
||||
now = time.time()
|
||||
timeout = config.getint('session', 'timeout')
|
||||
res = self.__class__._list_cache
|
||||
if res and abs(self.__class__._list_cache_timestamp - now) < timeout:
|
||||
res = self.__class__._list_cache.get(hostname)
|
||||
timestamp = self.__class__._list_cache_timestamp.get(hostname, now)
|
||||
if res and abs(timestamp - now) < timeout:
|
||||
return res
|
||||
|
||||
connection = self.get_connection()
|
||||
@@ -186,15 +187,15 @@ class Database(DatabaseInterface):
|
||||
for db_name, in cursor:
|
||||
try:
|
||||
with connect(self.dsn(db_name)) as conn:
|
||||
if self._test(conn):
|
||||
if self._test(conn, hostname=hostname):
|
||||
res.append(db_name)
|
||||
except Exception:
|
||||
continue
|
||||
finally:
|
||||
self.put_connection(connection)
|
||||
|
||||
self.__class__._list_cache = res
|
||||
self.__class__._list_cache_timestamp = now
|
||||
self.__class__._list_cache[hostname] = res
|
||||
self.__class__._list_cache_timestamp[hostname] = now
|
||||
return res
|
||||
|
||||
def init(self):
|
||||
@@ -230,22 +231,33 @@ class Database(DatabaseInterface):
|
||||
finally:
|
||||
self.put_connection(connection)
|
||||
|
||||
def test(self):
|
||||
def test(self, hostname=None):
|
||||
connection = self.get_connection()
|
||||
is_tryton_database = self._test(connection)
|
||||
self.put_connection(connection)
|
||||
try:
|
||||
is_tryton_database = self._test(connection, hostname=hostname)
|
||||
except Exception:
|
||||
is_tryton_database = False
|
||||
finally:
|
||||
self.put_connection(connection)
|
||||
return is_tryton_database
|
||||
|
||||
@classmethod
|
||||
def _test(cls, connection):
|
||||
def _test(cls, connection, hostname=None):
|
||||
cursor = connection.cursor()
|
||||
cursor.execute('SELECT 1 FROM information_schema.tables '
|
||||
'WHERE table_name IN %s',
|
||||
(('ir_model', 'ir_model_field', 'ir_ui_view', 'ir_ui_menu',
|
||||
'res_user', 'res_group', 'ir_module',
|
||||
'ir_module_dependency', 'ir_translation',
|
||||
'ir_lang'),))
|
||||
return len(cursor.fetchall()) != 0
|
||||
tables = ('ir_model', 'ir_model_field', 'ir_ui_view', 'ir_ui_menu',
|
||||
'res_user', 'res_group', 'ir_module', 'ir_module_dependency',
|
||||
'ir_translation', 'ir_lang', 'ir_configuration')
|
||||
cursor.execute('SELECT table_name FROM information_schema.tables '
|
||||
'WHERE table_name IN %s', (tables,))
|
||||
if len(cursor.fetchall()) != len(tables):
|
||||
return False
|
||||
if hostname:
|
||||
cursor.execute(
|
||||
'SELECT hostname FROM ir_configuration')
|
||||
hostnames = {h for h, in cursor.fetchall() if h}
|
||||
if hostnames and hostname not in hostnames:
|
||||
return False
|
||||
return True
|
||||
|
||||
def nextid(self, connection, table):
|
||||
cursor = connection.cursor()
|
||||
|
||||
@@ -3,6 +3,7 @@ CREATE SEQUENCE ir_configuration_id_seq;
|
||||
CREATE TABLE ir_configuration (
|
||||
id INTEGER DEFAULT NEXTVAL('ir_configuration_id_seq') NOT NULL,
|
||||
language VARCHAR,
|
||||
hostname VARCHAR,
|
||||
PRIMARY KEY(id)
|
||||
);
|
||||
|
||||
|
||||
@@ -327,7 +327,7 @@ class Database(DatabaseInterface):
|
||||
os.remove(os.path.join(config.get('database', 'path'),
|
||||
database_name + '.sqlite'))
|
||||
|
||||
def list(self):
|
||||
def list(self, hostname=None):
|
||||
res = []
|
||||
listdir = [':memory:']
|
||||
try:
|
||||
@@ -344,7 +344,7 @@ class Database(DatabaseInterface):
|
||||
database = Database(db_name).connect()
|
||||
except Exception:
|
||||
continue
|
||||
if database.test():
|
||||
if database.test(hostname=hostname):
|
||||
res.append(db_name)
|
||||
database.close()
|
||||
return res
|
||||
@@ -384,29 +384,33 @@ class Database(DatabaseInterface):
|
||||
cursor.execute(*insert)
|
||||
conn.commit()
|
||||
|
||||
def test(self):
|
||||
def test(self, hostname=None):
|
||||
tables = ['ir_model', 'ir_model_field', 'ir_ui_view', 'ir_ui_menu',
|
||||
'res_user', 'res_group', 'ir_module', 'ir_module_dependency',
|
||||
'ir_translation', 'ir_lang', 'ir_configuration']
|
||||
sqlite_master = Table('sqlite_master')
|
||||
select = sqlite_master.select(sqlite_master.name)
|
||||
select.where = sqlite_master.type == 'table'
|
||||
select.where &= sqlite_master.name.in_([
|
||||
'ir_model',
|
||||
'ir_model_field',
|
||||
'ir_ui_view',
|
||||
'ir_ui_menu',
|
||||
'res_user',
|
||||
'res_group',
|
||||
'ir_module',
|
||||
'ir_module_dependency',
|
||||
'ir_translation',
|
||||
'ir_lang',
|
||||
])
|
||||
select.where &= sqlite_master.name.in_(tables)
|
||||
with self._conn as conn:
|
||||
cursor = conn.cursor()
|
||||
try:
|
||||
cursor.execute(*select)
|
||||
except Exception:
|
||||
return False
|
||||
return len(cursor.fetchall()) != 0
|
||||
if len(cursor.fetchall()) != len(tables):
|
||||
return False
|
||||
if hostname:
|
||||
configuration = Table('ir_configuration')
|
||||
try:
|
||||
cursor.execute(*configuration.select(
|
||||
configuration.hostname))
|
||||
except Exception:
|
||||
return False
|
||||
hostnames = {h for h, in cursor.fetchall() if h}
|
||||
if hostnames and hostname not in hostnames:
|
||||
return False
|
||||
return True
|
||||
|
||||
def lastid(self, cursor):
|
||||
# This call is not thread safe
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
CREATE TABLE ir_configuration (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
language VARCHAR
|
||||
language VARCHAR,
|
||||
hostname VARCHAR
|
||||
);
|
||||
|
||||
CREATE TABLE ir_model (
|
||||
|
||||
@@ -59,6 +59,8 @@ def get_parser_admin():
|
||||
dest="update_modules_list", help="Update list of tryton modules")
|
||||
parser.add_argument("-l", "--language", dest="languages", nargs='+',
|
||||
default=[], metavar='CODE', help="Load language translations")
|
||||
parser.add_argument("--hostname", dest="hostname", default=None,
|
||||
help="Limit database listing to the hostname")
|
||||
|
||||
parser.epilog = ('The first time a database is initialized '
|
||||
'or when the password is set, the admin password is read '
|
||||
|
||||
@@ -11,6 +11,7 @@ class Configuration(ModelSingleton, ModelSQL):
|
||||
'Configuration'
|
||||
__name__ = 'ir.configuration'
|
||||
language = fields.Char('language')
|
||||
hostname = fields.Char("Hostname")
|
||||
_get_language_cache = Cache('ir_configuration.get_language')
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -10,7 +10,7 @@ from sql import Table
|
||||
|
||||
from trytond import security
|
||||
from trytond import backend
|
||||
from trytond.config import config
|
||||
from trytond.config import config, get_hostname
|
||||
from trytond import __version__
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.exceptions import (
|
||||
@@ -100,10 +100,11 @@ def db_list(request, *args):
|
||||
if not config.getboolean('database', 'list'):
|
||||
raise Exception('AccessDenied')
|
||||
context = {'_request': request.context}
|
||||
hostname = get_hostname(request.host)
|
||||
with Transaction().start(
|
||||
None, 0, context=context, close=True, _nocache=True
|
||||
) as transaction:
|
||||
return transaction.database.list()
|
||||
return transaction.database.list(hostname=hostname)
|
||||
|
||||
|
||||
@app.auth_required
|
||||
|
||||
Reference in New Issue
Block a user