Skip to content

Commit

Permalink
Webfaction shared database support
Browse files Browse the repository at this point in the history
  • Loading branch information
eantones committed Feb 12, 2020
1 parent 9180740 commit eeb496d
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 0 deletions.
30 changes: 30 additions & 0 deletions addons/bus/models/bus.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ def sendmany(self, notifications):
# transaction is not commited yet, there will be nothing to fetch,
# and the longpolling will return no notification.
def notify():
wf = odoo.tools.config.get('webfaction', default=False)
if wf:
db_base = odoo.tools.config["webfaction_db_base"]
with odoo.sql_db.db_connect(db_base).cursor() as cr2:
cr2.execute("notify imbus, %s", (json_dump(list(channels)),))
return

with odoo.sql_db.db_connect('postgres').cursor() as cr:
cr.execute("notify imbus, %s", (json_dump(list(channels)),))
self._cr.after('commit', notify)
Expand Down Expand Up @@ -155,6 +162,29 @@ def poll(self, dbname, channels, last, options=None, timeout=TIMEOUT):
def loop(self):
""" Dispatch postgres notifications to the relevant polling threads/greenlets """
_logger.info("Bus.loop listen imbus on db postgres")
wf = odoo.tools.config.get('webfaction', default=False)
if wf:
db_base = odoo.tools.config["webfaction_db_base"]
with odoo.sql_db.db_connect(db_base).cursor() as cr:
conn = cr._cnx
cr.execute("listen imbus")
cr.commit();
while True:
if select.select([conn], [], [], TIMEOUT) == ([], [], []):
pass
else:
conn.poll()
channels = []
while conn.notifies:
channels.extend(json.loads(conn.notifies.pop().payload))
# dispatch to local threads/greenlets
events = set()
for channel in channels:
events.update(self.channels.pop(hashable(channel), []))
for event in events:
event.set()
return

with odoo.sql_db.db_connect('postgres').cursor() as cr:
conn = cr._cnx
cr.execute("listen imbus")
Expand Down
91 changes: 91 additions & 0 deletions odoo/service/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,29 @@ def _initialize_db(id, db_name, demo, lang, user_password, login='admin', countr
_logger.exception('CREATE DATABASE failed:')

def _create_empty_database(name):
wf = odoo.tools.config.get('webfaction', default=False)
if wf:
_logger.info("WebFaction: Creating database '%s'...", name)
db_base = odoo.tools.config["webfaction_db_base"]
db_user = odoo.tools.config["db_user"]
res = exec_webfaction_sql(db_base, db_user, "SELECT datname FROM pg_database WHERE datname = %s", (name,))
if res!=[]:
raise DatabaseExists("database %r already exists!" % (name,))

db_password = odoo.tools.config["db_password"]

import xmlrpclib
server = xmlrpclib.ServerProxy(odoo.tools.config['webfaction_url'])
session_id, _ = server.login(odoo.tools.config['webfaction_user'], odoo.tools.config['webfaction_password'])
dbus = [ y['username'] for y in filter(lambda x: x['db_type']=='postgresql', server.list_db_users(session_id))]

server.create_db(session_id, name, 'postgresql', db_password)
server.make_user_owner_of_db(session_id, db_user, name, 'postgresql')
if name not in dbus:
server.delete_db_user(session_id, name, 'postgresql')
_logger.info("WebFaction: Database '%s' created.", name)
return

db = odoo.sql_db.db_connect('postgres')
with closing(db.cursor()) as cr:
chosen_template = odoo.tools.config['db_template']
Expand All @@ -97,6 +120,10 @@ def exp_create_database(db_name, demo, lang, user_password='admin', login='admin
return True

def exp_duplicate_database(db_original_name, db_name):
wf = odoo.tools.config.get('webfaction', default=False)
if wf:
raise Exception("A WebFaction database duplication is not yet implemented")

_logger.info('Duplicate database `%s` to `%s`.', db_original_name, db_name)
odoo.sql_db.close_db(db_original_name)
db = odoo.sql_db.db_connect('postgres')
Expand Down Expand Up @@ -139,6 +166,16 @@ def exp_drop(db_name):
odoo.modules.registry.Registry.delete(db_name)
odoo.sql_db.close_db(db_name)

wf = odoo.tools.config.get('webfaction', default=False)
if wf:
_logger.info("WebFaction: Dropping database '%s'...", db_name)
import xmlrpclib
server = xmlrpclib.ServerProxy(odoo.tools.config['webfaction_url'])
session_id, _ = server.login(odoo.tools.config['webfaction_user'], odoo.tools.config['webfaction_password'])
server.delete_db(session_id, db_name, 'postgresql')
_logger.info("WebFaction: Database '%s' dropped.", db_name)
return True

db = odoo.sql_db.db_connect('postgres')
with closing(db.cursor()) as cr:
cr.autocommit(True) # avoid transaction block
Expand Down Expand Up @@ -282,6 +319,10 @@ def restore_db(db, dump_file, copy=False):
_logger.info('RESTORE DB: %s', db)

def exp_rename(old_name, new_name):
wf = odoo.tools.config.get('webfaction', default=False)
if wf:
raise Exception("A WebFaction database cannot be renamed. Not supported by Webfaction API")

odoo.modules.registry.Registry.delete(old_name)
odoo.sql_db.close_db(old_name)

Expand Down Expand Up @@ -336,6 +377,19 @@ def list_dbs(force=False):

chosen_template = odoo.tools.config['db_template']
templates_list = tuple(set(['postgres', chosen_template]))

wf = odoo.tools.config.get('webfaction', default=False)
if wf:
_logger.info("WebFaction: Listing databases (force=%s)..." % force)
db_base = odoo.tools.config["webfaction_db_base"]
templates_list = tuple(list(templates_list) + [db_base])
db_user = odoo.tools.config["db_user"]
res = exec_webfaction_sql(db_base, db_user, "select datname from pg_database where datdba=(select usesysid from pg_user where usename=%s) and datname not in %s order by datname", (db_user, templates_list))
res = [odoo.tools.ustr(name) for (name,) in res]
_logger.info("WebFaction: Database listing done. %s" % res)
res.sort()
return res

db = odoo.sql_db.db_connect('postgres')
with closing(db.cursor()) as cr:
try:
Expand Down Expand Up @@ -396,3 +450,40 @@ def dispatch(method, params):
return g[exp_method_name](*params)
else:
raise KeyError("Method not found: %s" % method)

def exec_webfaction_sql(db_base, db_user, sql, params=()):
db = odoo.sql_db.db_connect(db_base)
ok = False
while not ok:
try:
with closing(db.cursor()) as cr:
cr.execute(sql, params)
res = cr.fetchall()
ok = True
except psycopg2.OperationalError as e:
# The next use of regular expressions is just a temporary solution. It's dirty, unelegant, unstable but fast to implement, really fast.
# Of course, it needs to be corrected ASAP and implement an elegant solution.
import re
m1 = re.search('^FATAL: no pg_hba.conf entry for host "[0-9.]+", user "%(db_user)s", database "%(db_base)s", SSL on\nFATAL: no pg_hba.conf entry for host "[0-9.]+", user "%(db_user)s", database "%(db_base)s", SSL off\n$' % dict(db_user=db_user, db_base=db_base), unicode(e))
m2 = re.search('^FATAL: no pg_hba.conf entry for host "\[local\]", user "%(db_user)s", database "%(db_base)s", SSL off\n$' % dict(db_user=db_user, db_base=db_base), unicode(e))
if m1 is None and m2 is None:
m = re.search('^FATAL: permission denied for database "%s"\nDETAIL: User does not have CONNECT privilege.$' % db_base, unicode(e))
if m is not None:
_logger.info('WebFaction: Base database "%s" already created but user "%s" has no permissions -> Granting full access...' % (db_base, db_user))
import xmlrpclib
server = xmlrpclib.ServerProxy(odoo.tools.config['webfaction_url'])
session_id, _ = server.login(odoo.tools.config['webfaction_user'], odoo.tools.config['webfaction_password'])
server.grant_db_permissions(session_id, db_user, db_base, 'postgresql')
_logger.info('WebFaction: User "%s" permissions to base database "%s" granted successfully.' % (db_user, db_base))
else:
raise Exception("Unexpected error message string '%s'" % unicode(e))
else:
_logger.info('WebFaction: Base database "%s" does not exist -> Creating...' % db_base)
import xmlrpclib
server = xmlrpclib.ServerProxy(odoo.tools.config['webfaction_url'])
session_id, _ = server.login(odoo.tools.config['webfaction_user'], odoo.tools.config['webfaction_password'])
server.create_db(session_id, db_base, 'postgresql', db_base)
server.make_user_owner_of_db(session_id, db_user, db_base, 'postgresql')
server.delete_db_user(session_id, db_base, 'postgresql')
_logger.info('WebFaction: Base database "%s" created successfully.' % db_base)
return res

0 comments on commit eeb496d

Please sign in to comment.