Newer
Older
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Launch a docker image but bind the local directory inside the container
and define the module path automatically.
"""
import argparse
import logging

Vincent Hatakeyama
committed
import pwd
from subprocess import call
import sys
import os
import ConfigParser
from netifaces import interfaces, ifaddresses, AF_INET

Vincent Hatakeyama
committed
from psycopg2 import connect, OperationalError
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# TODO auto create list of module
_logger = logging.getLogger(__name__)
__version__ = '0.1.0'
__date__ = '2017-08-11'
__updated__ = '2017-08-11'
def main(argv=None): # IGNORE:C0111
"""Parse arguments and launch conversion
"""
if argv is None:
argv = sys.argv
else:
sys.argv.extend(argv)
program_version = __version__
program_build_date = str(__updated__)
program_version_message = '%%(prog)s %s (%s)' % (
program_version, program_build_date)
program_shortdesc = __doc__.split("\n")[1]
program_license = '''%s
Created by Vincent Hatakeyama on %s.
Copyright 2017 XCG Consulting. All rights reserved.
Licensed under the MIT License
Distributed on an "AS IS" basis without warranties
or conditions of any kind, either express or implied.
USAGE
''' % (
program_shortdesc,
str(__date__),
)

Vincent Hatakeyama
committed
# TODO the script assume it is launched from the parent super project
project_path = os.path.realpath('.')
project_name = os.path.basename(project_path)
setup_path = 'setup.cfg'
# Argument parsing
parser = argparse.ArgumentParser(
description=program_license,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument(
'-V', '--version', action='version',
version=program_version_message)
parser.add_argument(
'-v', '--verbose', dest='verbose', action='count',
help="set verbosity level [default: %(default)s]")
parser.add_argument(
'--db_user',
help="Database user [default: %(default)s]",
default=None,
)
parser.add_argument(
'--db_password',
help="Database user password [default: %(default)s]",
default=None,
)
parser.add_argument(
'-d',
'--database',
help="Database [default: %(default)s]",
default=None,
)
parser.add_argument(
'-u',
'--update',
help="Module to update (will also set --i18n-overwrite)"
"[default: %(default)s]",
default=None,
)
parser.add_argument(
'-i',
'--install',
help="Module to install [default: %(default)s]",
default=None,
)
parser.add_argument(
'--without-demo',
help="Module to avoid including demo data [default: %(default)s]",
default=None,
)

Vincent Hatakeyama
committed
parser.add_argument(
'--create',
help="Create user/database (using your user)",
action='store_true',
)
# TODO detect that user is member of docker group
# TODO add a way to add options to docker
# TODO add a way to add arg to odoo
nmspc = parser.parse_args()
verbose = nmspc.verbose
if not verbose:
logging.basicConfig(level=logging.WARN)
if verbose == 1:
logging.basicConfig(level=logging.INFO)
if verbose and verbose > 1:
logging.basicConfig(level=logging.DEBUG)
db_user = nmspc.db_user
db_password = nmspc.db_password
if project_name == 'odoo_scripts':
logging.fatal(
"You must run this script from the super project"
" (./odoo_scripts/docker_dev_start.py)")
return
c = ConfigParser.ConfigParser()
logging.debug('setup file path %s', setup_path)
# TODO test that setup file exists
c.read(setup_path)
addon_dirs = c.get('odoo_scripts', 'addon_dirs', '').split()
logging.debug("addon directories: %s", addon_dirs)
registry = (
c.has_section('odoo_scripts') and
c.has_option('odoo_scripts', 'registry') and
c.get('odoo_scripts', 'registry')) or 'dockerhub.xcg.io'
project = (
c.has_section('odoo_scripts') and
c.has_option('odoo_scripts', 'image') and
c.get('odoo_scripts', 'image')) or os.path.basename(project_path)
logging.debug("Docker image: %s", image)
# TODO detect if docker image already exists
options = [
'--rm',
'--publish',
'8069:8069',
'--tty',
'--interactive',
]
arg = [
'start',
]
if db_user:
arg.append('--db_user %s' % db_user)
if db_password:
arg.append('--db_password %s' % db_user)
if nmspc.update:
arg.append('-u %s' % nmspc.update)
arg.append('--i18n-overwrite')
if nmspc.database:
arg.append('-d %s' % nmspc.database)
if nmspc.install:
arg.append('-i %s' % nmspc.database)
if nmspc.without_demo:
arg.append('--without-demo %s' % nmspc.database)
# auto detect local ip
ifaceName = 'docker0'
addresses = [i['addr'] for i in ifaddresses(ifaceName).setdefault(AF_INET, [{'addr':'No IP addr'}])]
if addresses:
local_ip = addresses[0]
else:
import socket
local_ip = [(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]
arg.append('--db_host')
arg.append(local_ip)
# auto detect local conf
local_conf_path = 'conf/dev/odoo.conf'

Vincent Hatakeyama
committed
user = db_user
password = db_password
if os.path.isfile(local_conf_path):
logging.info('Local configuration file found: %s' % local_conf_path)
options.append('--volume')
options.append('%s:/opt/odoo/etc/odoo.conf' % os.path.join(
project_path, local_conf_path))

Vincent Hatakeyama
committed
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
cp_local = ConfigParser.ConfigParser()
cp_local.read(local_conf_path)
if not user:
user = cp_local.get('options', 'db_user', 'pg')
if not password:
password = cp_local.get('options', 'db_password', 'THIS-IS-NOT-USED-DONOT-CHANGE')
# Check that connection can be done, try to create user if asked to
try:
test_connection = connect(user=user, password=password, database='postgres', host=local_ip)
except OperationalError as exception:
if nmspc.create:
logging.info('Cannot connect to database with user %s', user)
logging.info(exception)
logging.info('Creating user %s', user)
loginname = pwd.getpwuid(os.getuid())[0]
connection = connect(user=loginname, database='postgres')
with connection.cursor() as cursor:
# not injection safe but you are on your own machine
# with already full access to db
cursor.execute(
'CREATE ROLE %s LOGIN CREATEDB PASSWORD %%s' % user, (password, ))
connection.commit()
connection.close()
else:
logging.warn('Cannot connect to database with user %s', user)
logging.warn(exception)
# volume magic
for addons_dir in addon_dirs:
options.append('--volume')
options.append('%s:/mnt/%s' % (os.path.join(project_path, addons_dir), addons_dir))
all_addons_dir = [
'/opt/odoo/sources/odoo/addons',
]
all_addons_dir.extend('/mnt/%s' % addons_dir for addons_dir in addon_dirs)
arg.append('--addons-path')
arg.append(','.join(all_addons_dir))
cmd = ['docker', 'run']
cmd.extend(options)
cmd.append(image)
cmd.extend(arg)
logging.debug(cmd)
call(cmd)
# TODO add handling of signal to reload
if __name__ == "__main__":
main()