Remove database management from RPC

issue5384
review29311002
This commit is contained in:
Sergi Almacellas Abellana committed 2016-07-07 16:05:45 +02:00
1 parent 7e359d5c2b
commit 5967d21d46
9 files changed
+48 -384

No files matched your search

+2
View File
@@ -1,3 +1,5 @@
* Remove super password
* Remove database management from RPC
* Remove ModelView.view_header_get
* Remove string attribute from views
* Don't check write access on model for button with groups
-9
View File
@@ -219,15 +219,6 @@ The time in seconds until a session expires.
Default: `600`
super_pwd
~~~~~~~~~
The server password used to authenticate from the client for database
management tasks. It is encrypted using using the Unix `crypt(3)` routine.
A password can be generated using this command line::
python -c 'import getpass,crypt,random,string; print crypt.crypt(getpass.getpass(), "".join(random.sample(string.ascii_letters + string.digits, 8)))'
report
------
-21
View File
@@ -65,27 +65,6 @@ class DatabaseInterface(object):
'''
raise NotImplementedError
@staticmethod
def dump(database_name):
'''
Dump a database
:param database_name: the database name
:return: the dump
'''
raise NotImplementedError
@staticmethod
def restore(database_name, data):
'''
Restore a database
:param database_name: the database name
:param data: the data
:return: True if succeed
'''
raise NotImplementedError
def list(self):
'''
Get the list of database
-74
View File
@@ -9,7 +9,6 @@ from MySQLdb import IntegrityError as DatabaseIntegrityError
from MySQLdb import OperationalError as DatabaseOperationalError
import os
import time
import tempfile
import urllib
from sql import Flavor, Expression
@@ -126,79 +125,6 @@ class Database(DatabaseInterface):
cursor.execute('DROP DATABASE `' + database_name + '`')
cls._list_cache = None
@staticmethod
def dump(database_name):
from trytond.tools import exec_command_pipe
cmd = ['mysqldump', '--no-create-db']
uri = parse_uri(config.get('database', 'uri'))
if uri.username:
cmd.append('--user=' + uri.username)
if uri.hostname:
cmd.append('--host=' + uri.hostname)
if uri.port:
cmd.append('--port=' + str(uri.port))
if uri.password:
cmd.append('--password=' + uri.password)
cmd.append(database_name)
pipe = exec_command_pipe(*tuple(cmd))
pipe.stdin.close()
data = pipe.stdout.read()
res = pipe.wait()
if res:
raise Exception('Couldn\'t dump database!')
return data
@staticmethod
def restore(database_name, data):
from trytond.tools import exec_command_pipe
database = Database().connect()
cursor = database.cursor(autocommit=True)
database.create(cursor, database_name)
cursor.commit()
cursor.close()
cmd = ['mysql']
uri = parse_uri(config.get('database', 'uri'))
if uri.username:
cmd.append('--user=' + uri.username)
if uri.hostname:
cmd.append('--host=' + uri.hostname)
if uri.port:
cmd.append('--port=' + str(uri.port))
if uri.password:
cmd.append('--password=' + uri.password)
cmd.append(database_name)
fd, file_name = tempfile.mkstemp()
with os.fdopen(fd, 'wb+') as fd:
fd.write(data)
cmd.append('<')
cmd.append(file_name)
args2 = tuple(cmd)
pipe = exec_command_pipe(*args2)
pipe.stdin.close()
res = pipe.wait()
os.remove(file_name)
if res:
raise Exception('Couldn\'t restore database')
database = Database(database_name).connect()
cursor = database.cursor()
if not cursor.test():
cursor.close()
database.close()
raise Exception('Couldn\'t restore database!')
cursor.close()
database.close()
Database._list_cache = None
return True
def list(self):
now = time.time()
timeout = config.getint('session', 'timeout')
-78
View File
@@ -146,84 +146,6 @@ class Database(DatabaseInterface):
RE_VERSION.search(version).groups()))
return self._version_cache[self.name]
@staticmethod
def dump(database_name):
from trytond.tools import exec_command_pipe
cmd = ['pg_dump', '--format=c', '--no-owner']
env = {}
uri = parse_uri(config.get('database', 'uri'))
if uri.username:
cmd.append('--username=' + uri.username)
if uri.hostname:
cmd.append('--host=' + uri.hostname)
if uri.port:
cmd.append('--port=' + str(uri.port))
if uri.password:
# if db_password is set in configuration we should pass
# an environment variable PGPASSWORD to our subprocess
# see libpg documentation
env['PGPASSWORD'] = uri.password
cmd.append(database_name)
pipe = exec_command_pipe(*tuple(cmd), env=env)
pipe.stdin.close()
data = pipe.stdout.read()
res = pipe.wait()
if res:
raise Exception('Couldn\'t dump database!')
return data
@staticmethod
def restore(database_name, data):
from trytond.tools import exec_command_pipe
database = Database().connect()
connection = database.get_connection(autocommit=True)
database.create(connection, database_name)
database.close()
cmd = ['pg_restore', '--no-owner']
env = {}
uri = parse_uri(config.get('database', 'uri'))
if uri.username:
cmd.append('--username=' + uri.username)
if uri.hostname:
cmd.append('--host=' + uri.hostname)
if uri.port:
cmd.append('--port=' + str(uri.port))
if uri.password:
env['PGPASSWORD'] = uri.password
cmd.append('--dbname=' + database_name)
args2 = tuple(cmd)
if os.name == "nt":
tmpfile = (os.environ['TMP'] or 'C:\\') + os.tmpnam()
with open(tmpfile, 'wb') as fp:
fp.write(data)
args2 = list(args2)
args2.append(' ' + tmpfile)
args2 = tuple(args2)
pipe = exec_command_pipe(*args2, env=env)
if not os.name == "nt":
pipe.stdin.write(data)
pipe.stdin.close()
res = pipe.wait()
if res:
raise Exception('Couldn\'t restore database')
database = Database(database_name).connect()
cursor = database.get_connection().cursor()
if not database.test():
cursor.close()
database.close()
raise Exception('Couldn\'t restore database!')
cursor.close()
database.close()
Database._list_cache = None
return True
def list(self):
now = time.time()
timeout = config.getint('session', 'timeout')
-25
View File
@@ -279,31 +279,6 @@ class Database(DatabaseInterface):
os.remove(os.path.join(config.get('database', 'path'),
database_name + '.sqlite'))
@staticmethod
def dump(database_name):
if database_name == ':memory:':
raise Exception('Unable to dump memory database!')
if os.sep in database_name:
raise Exception('Wrong database name!')
path = os.path.join(config.get('database', 'path'),
database_name + '.sqlite')
with open(path, 'rb') as file_p:
data = file_p.read()
return data
@staticmethod
def restore(database_name, data):
if database_name == ':memory:':
raise Exception('Unable to restore memory database!')
if os.sep in database_name:
raise Exception('Wrong database name!')
path = os.path.join(config.get('database', 'path'),
database_name + '.sqlite')
if os.path.isfile(path):
raise Exception('Database already exists!')
with open(path, 'wb') as file_p:
file_p.write(data)
def list(self):
res = []
listdir = [':memory:']
-148
View File
@@ -2,7 +2,6 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import logging
import time
import pydoc
from functools import wraps
@@ -48,11 +47,6 @@ def rpc(request, database_name):
methods = {
'common.db.login': login,
'common.db.logout': logout,
'common.db.db_exist': db_exist,
'common.db.create': create,
'common.db.restore': restore,
'common.db.drop': drop,
'common.db.dump': dump,
'system.listMethods': list_method,
'system.methodHelp': help_method,
'system.methodSignature': lambda *a: 'signatures not supported',
@@ -96,7 +90,6 @@ def logout(request, database_name):
def root(request, *args):
methods = {
'common.server.version': lambda *a: __version__,
'common.db.list_lang': list_lang,
'common.db.list': db_list,
}
return methods[request.method](request, *request.params)
@@ -107,31 +100,6 @@ def home(request):
return redirect('/index.html') # XXX find a better way
def list_lang(*args):
return [
('bg_BG', 'Български'),
('ca_ES', 'Català'),
('cs_CZ', 'Čeština'),
('de_DE', 'Deutsch'),
('en_US', 'English'),
('es_AR', 'Español (Argentina)'),
('es_EC', 'Español (Ecuador)'),
('es_ES', 'Español (España)'),
('es_CO', 'Español (Colombia)'),
('es_MX', 'Español (México)'),
('fr_FR', 'Français'),
('hu_HU', 'Magyar'),
('it_IT', 'Italiano'),
('lt_LT', 'Lietuvių'),
('lo_LA', 'ລາວ'),
('nl_NL', 'Nederlands'),
('pt_BR', 'Português (Brasil)'),
('ru_RU', 'Russian'),
('sl_SI', 'Slovenščina'),
('zh_CN', '中国(简体)'),
]
def db_exist(request, database_name):
Database = backend.get('Database')
try:
@@ -237,119 +205,3 @@ def _dispatch(request, pool, *args, **kwargs):
logger.debug('Reset session failed', exc_info=True)
logger.debug('Result: %s', result)
return result
def create(request, database_name, password, lang, admin_password):
'''
Create a database
:param database_name: the database name
:param password: the server password
:param lang: the default language for the database
:param admin_password: the admin password
:return: True if succeed
'''
Database = backend.get('Database')
security.check_super(password)
res = False
try:
with Transaction().start(None, 0, close=True, autocommit=True) \
as transaction:
transaction.database.create(transaction.connection, database_name)
with Transaction().start(database_name, 0) as transaction,\
transaction.connection.cursor() as cursor:
Database(database_name).init()
cursor.execute(*ir_configuration.insert(
[ir_configuration.language], [[lang]]))
pool = Pool(database_name)
pool.init(update=['res', 'ir'], lang=[lang])
with Transaction().start(database_name, 0) as transaction:
User = pool.get('res.user')
Lang = pool.get('ir.lang')
language, = Lang.search([('code', '=', lang)])
language.translatable = True
language.save()
users = User.search([('login', '!=', 'root')])
User.write(users, {
'language': language.id,
})
admin, = User.search([('login', '=', 'admin')])
User.write([admin], {
'password': admin_password,
})
Module = pool.get('ir.module')
if Module:
Module.update_list()
res = True
except Exception:
logger.error('CREATE DB: %s failed', database_name, exc_info=True)
raise
else:
logger.info('CREATE DB: %s', database_name)
return res
def drop(request, database_name, password):
Database = backend.get('Database')
security.check_super(password)
database = Database(database_name)
database.close()
# Sleep to let connections close
time.sleep(1)
with Transaction().start(None, 0, close=True, autocommit=True) \
as transaction:
try:
database.drop(transaction.connection, database_name)
except Exception:
logger.error('DROP DB: %s failed', database_name, exc_info=True)
raise
else:
logger.info('DROP DB: %s', database_name)
Pool.stop(database_name)
Cache.drop(database_name)
return True
def dump(request, database_name, password):
Database = backend.get('Database')
security.check_super(password)
Database(database_name).close()
# Sleep to let connections close
time.sleep(1)
data = Database.dump(database_name)
logger.info('DUMP DB: %s', database_name)
if bytes == str:
return bytearray(data)
else:
return bytes(data)
def restore(request, database_name, password, data, update=False):
Database = backend.get('Database')
security.check_super(password)
try:
Database(database_name).connect()
existing = True
except Exception:
existing = False
if existing:
raise Exception('Database already exists!')
Database.restore(database_name, data)
logger.info('RESTORE DB: %s', database_name)
if update:
with Transaction().start(database_name, 0) as transaction,\
transaction.connection.cursor() as cursor:
cursor.execute(*ir_lang.select(ir_lang.code,
where=ir_lang.translatable))
lang = [x[0] for x in cursor.fetchall()]
cursor.execute(*ir_module.select(ir_module.name,
where=(ir_module.state == 'installed')))
update = [x[0] for x in cursor.fetchall()]
Pool(database_name).init(update=update, lang=lang)
logger.info('Update/Init succeed!')
return True
-12
View File
@@ -1,10 +1,5 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
try:
import crypt
except ImportError:
pass
from trytond.pool import Pool
from trytond.config import config
from trytond.transaction import Transaction
@@ -56,13 +51,6 @@ def logout(dbname, user, session):
return name
def check_super(passwd):
cryptedpasswd = config.get('session', 'super_pwd')
if cryptedpasswd and crypt.crypt(passwd, cryptedpasswd) == cryptedpasswd:
return True
raise Exception('AccessDenied')
def check(dbname, user, session):
DatabaseOperationalError = backend.get('DatabaseOperationalError')
for count in range(config.getint('database', 'retry'), -1, -1):
+46 -17
View File
@@ -11,31 +11,28 @@ import operator
from functools import wraps
from lxml import etree
from sql import Table
from trytond.pool import Pool, isregisteredby
from trytond import backend
from trytond.model import Workflow
from trytond.model.fields import get_eval_fields
from trytond.protocols.dispatcher import create, drop
from trytond.tools import is_instance_method
from trytond.transaction import Transaction
from trytond import security
from trytond.cache import Cache
__all__ = ['POOL', 'DB_NAME', 'USER', 'USER_PASSWORD', 'CONTEXT',
__all__ = ['POOL', 'DB_NAME', 'USER', 'CONTEXT',
'install_module', 'ModuleTestCase', 'with_transaction',
'doctest_setup', 'doctest_teardown', 'doctest_checker',
'suite', 'all_suite', 'modules_suite']
Pool.start()
USER = 1
USER_PASSWORD = 'admin'
CONTEXT = {}
DB_NAME = os.environ['DB_NAME']
DB = backend.get('Database')(DB_NAME)
Pool.test = True
POOL = Pool(DB_NAME)
security.check_super = lambda *a, **k: True
def install_module(name):
@@ -278,26 +275,58 @@ class ModuleTestCase(unittest.TestCase):
})
def db_exist():
def db_exist(name=DB_NAME):
Database = backend.get('Database')
database = Database().connect()
return DB_NAME in database.list()
return name in database.list()
def create_db():
if not db_exist():
create(None, DB_NAME, None, 'en_US', USER_PASSWORD)
def create_db(name=DB_NAME, lang='en_US'):
Database = backend.get('Database')
if not db_exist(name):
with Transaction().start(None, 0, close=True, autocommit=True) \
as transaction:
transaction.database.create(transaction.connection, name)
with Transaction().start(name, 0) as transaction,\
transaction.connection.cursor() as cursor:
Database(name).init()
ir_configuration = Table('ir_configuration')
cursor.execute(*ir_configuration.insert(
[ir_configuration.language], [[lang]]))
pool = Pool(name)
pool.init(update=['res', 'ir'], lang=[lang])
with Transaction().start(name, 0) as transaction:
User = pool.get('res.user')
Lang = pool.get('ir.lang')
language, = Lang.search([('code', '=', lang)])
language.translatable = True
language.save()
users = User.search([('login', '!=', 'root')])
User.write(users, {
'language': language.id,
})
Module = pool.get('ir.module')
Module.update_list()
def drop_db():
if db_exist():
drop(None, DB_NAME, None)
def drop_db(name=DB_NAME):
if db_exist(name):
Database = backend.get('Database')
database = Database(name)
with Transaction().start(None, 0, close=True, autocommit=True) \
as transaction:
database.drop(transaction.connection, name)
Pool.stop(name)
Cache.drop(name)
def drop_create():
if db_exist():
drop_db()
create_db()
def drop_create(name=DB_NAME, lang='en_US'):
if db_exist(name):
drop_db(name)
create_db(name, lang)
doctest_setup = lambda test: drop_create()
doctest_teardown = lambda test: drop_db()