diff --git a/NEWS.rst b/NEWS.rst index 7caefd33faeb3f8547394b0906fd25e359299e71_TkVXUy5yc3Q=..9bdab72a5b2d0fabde74c2b952aae4992fb5a592_TkVXUy5yc3Q= 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -7,7 +7,9 @@ Use semver. -docker_dev_start and do_tests: use socket when starting postgresql rather than a port that might be used on the host +docker_dev_start and do_tests: use socket when starting postgresql rather than a port that might be used on the host. + +Add :ref:`docker_pg.py` command to start postgres like :ref:`docker_dev_start.py` does when using ``--start-postgresql``, but without starting odoo. 4.2.1 ----- diff --git a/README.rst b/README.rst index 7caefd33faeb3f8547394b0906fd25e359299e71_UkVBRE1FLnJzdA==..9bdab72a5b2d0fabde74c2b952aae4992fb5a592_UkVBRE1FLnJzdA== 100644 --- a/README.rst +++ b/README.rst @@ -117,5 +117,5 @@ docker_dev_start.py ------------------- -This script can be used to start an odoo from a docker but with the local addons modules mounted, and eventually a local copy of the odoo sources mounted too. +This script starts an odoo from a docker but with the local addons modules mounted, and eventually a local copy of the odoo sources mounted too. @@ -121,3 +121,5 @@ -Using it avoids having to create a virtual env for every project. +Using it avoids having to create a virtual environment for every project. + +Prerequisites: @@ -123,3 +125,4 @@ -Your user also needs to be in the docker group. +- Your user needs to be in the docker group. +- It expects the `configuration file <setup.cfg>`_ to have the following keys: @@ -125,9 +128,9 @@ -It expects the configuration file (`setup.cfg`_) to have the following keys: - -- ``modules``: list of directories and files to include -- … + ``modules`` + list of directories and files to include + … + … When the package is installed, the executable for this script is ``docker_dev_start``. This is part of the docker section. @@ -130,7 +133,21 @@ When the package is installed, the executable for this script is ``docker_dev_start``. This is part of the docker section. +docker_pg.py +------------ + +This script start a postgresql server the same way `docker_dev_start.py`_ does. + +By default it provides an interactive psql shell, but can also be used to run SQL commands, use an interactive shell or a shell command. + +Prerequisites: + +- Your user needs to be in the docker group. +- It uses the `configuration file <setup.cfg>`_’s keys: postgresql_version. + +This is part of the docker section. + docker_build.py --------------- @@ -198,6 +215,8 @@ postgresql extensions to install (unaccent is added automatically depending on odoo configuration) load-language languages to install into a newly created database +postgresql_version + version of postgresql to use. defaults to 9.6. Completion files for zsh ======================== @@ -219,7 +238,7 @@ Generate completion file for python scripts (from the superproject for the scripts that need to be run from there, and with the required requirements too):: - for command_name in docker_dev_start docker_build docker_build_copy docker_build_clean do_tests conf2reST import_base_import import_jsonrpc import_sql docker_flake8 docker_isort ; do + for command_name in docker_dev_start docker_build docker_build_copy docker_build_clean do_tests conf2reST import_base_import import_jsonrpc import_sql docker_flake8 docker_isort docker_pg; do $command_name --help | ~/src/zsh-completion-generator/help2comp.py $command_name > ~/.local/share/zsh/completion/_$command_name done diff --git a/odoo_scripts/docker_client.py b/odoo_scripts/docker_client.py index 7caefd33faeb3f8547394b0906fd25e359299e71_b2Rvb19zY3JpcHRzL2RvY2tlcl9jbGllbnQucHk=..9bdab72a5b2d0fabde74c2b952aae4992fb5a592_b2Rvb19zY3JpcHRzL2RvY2tlcl9jbGllbnQucHk= 100644 --- a/odoo_scripts/docker_client.py +++ b/odoo_scripts/docker_client.py @@ -1,6 +1,6 @@ import logging import os import tarfile -from typing import Dict +from typing import Dict, List import docker @@ -5,5 +5,6 @@ import docker +import dockerpty _logger = logging.getLogger(__name__) if docker.__version__ < "3.4.0": @@ -52,3 +53,29 @@ data = open(src + ".tar", "rb").read() container.put_archive(os.path.dirname(dst), data) + + @classmethod + def exec( + cls, + container: docker.models.containers.Container, + command: List[str], + user: str, + interactive: bool = False, + ) -> int: + """Execute a command in a container + + :param container: Container to exec on + :param command: Command to be executed + :param user: User to execute command as. + :param interactive: True if the container needs to be interactive + """ + if interactive: + dockerpty.exec_command(cls.client.api, container.id, command) + # it would be nice to return the exec command return code, but + # there is no way to do that apparently + result = 0 + else: + run_result = container.exec_run(command, user=user) + result = run_result.exit_code + print(run_result.output.decode()) + return result diff --git a/odoo_scripts/docker_dev_start.py b/odoo_scripts/docker_dev_start.py index 7caefd33faeb3f8547394b0906fd25e359299e71_b2Rvb19zY3JpcHRzL2RvY2tlcl9kZXZfc3RhcnQucHk=..9bdab72a5b2d0fabde74c2b952aae4992fb5a592_b2Rvb19zY3JpcHRzL2RvY2tlcl9kZXZfc3RhcnQucHk= 100755 --- a/odoo_scripts/docker_dev_start.py +++ b/odoo_scripts/docker_dev_start.py @@ -30,7 +30,7 @@ __version__ = "3.0.0" __date__ = "2017-08-11" -__updated__ = "2020-09-15" +__updated__ = "2020-11-10" def main(argv=None): # IGNORE:C0111 @@ -75,10 +75,7 @@ ) parser.add_argument( "--name", - help=( - "If you do not assign a container name with the " - "--name option, then project name can be used" - ), + help="Container name to use [default: %(default)s]", default=project_name, ) parser.add_argument( diff --git a/odoo_scripts/docker_postgresql.py b/odoo_scripts/docker_postgresql.py index 7caefd33faeb3f8547394b0906fd25e359299e71_b2Rvb19zY3JpcHRzL2RvY2tlcl9wb3N0Z3Jlc3FsLnB5..9bdab72a5b2d0fabde74c2b952aae4992fb5a592_b2Rvb19zY3JpcHRzL2RvY2tlcl9wb3N0Z3Jlc3FsLnB5 100644 --- a/odoo_scripts/docker_postgresql.py +++ b/odoo_scripts/docker_postgresql.py @@ -1,1 +1,2 @@ +#!/usr/bin/env python3 # vim: set shiftwidth=4 softtabstop=4: @@ -1,3 +2,6 @@ # vim: set shiftwidth=4 softtabstop=4: +"""Run a postgresql docker with volume based on project name. +""" +import argparse import atexit import logging @@ -2,8 +6,10 @@ import atexit import logging +import os +import sys import tempfile import time from typing import Callable, Tuple import docker @@ -4,7 +10,8 @@ import tempfile import time from typing import Callable, Tuple import docker +from .config import Config from .docker_client import DockerClient @@ -10,4 +17,5 @@ from .docker_client import DockerClient +from .parsing import apply, basic_parser _logger = logging.getLogger(__name__) @@ -11,4 +19,8 @@ _logger = logging.getLogger(__name__) +__version__ = "1.0.0" +__date__ = "2020-11-09" +__updated__ = "2020-11-10" + POSTGRES_PASSWORD = "this-could-be-anything" @@ -14,4 +26,6 @@ POSTGRES_PASSWORD = "this-could-be-anything" +PSQL = "psql" +SH = "SH" def docker_run_postgresql( @@ -48,7 +62,6 @@ # maybe by looking at pg.status # TODO factorized with other methods that start dockers try: - _logger.info("Stopping postgresql") - # Need to stop too? + _logger.info("Stopping postgresql %s", pg_container.name) pg_container.stop() pg_container.wait() @@ -53,5 +66,5 @@ pg_container.stop() pg_container.wait() - _logger.info("Removing container postgresql") + _logger.info("Removing postgresql container %s", pg_container.name) pg_container.remove() except docker.errors.NotFound: @@ -56,6 +69,8 @@ pg_container.remove() except docker.errors.NotFound: - _logger.info("Postgresql already stopped") + _logger.info( + "Postgresql container %s already stopped", pg_container.name + ) # crash because docker or pg changes the owner of the directory # temp_directory.cleanup() @@ -90,7 +105,7 @@ environment=env, ) - _logger.debug("Starting postgresql container") + _logger.info("Starting postgresql container %s", pg.name) pg.start() def stop_pg(): @@ -102,3 +117,112 @@ # give pg the time to start up time.sleep(5) return pg, stop_pg, path + + +def __parser() -> argparse.ArgumentParser: + program_version = __version__ + program_build_date = str(__updated__) + program_version_message = "%%(prog)s %s (%s)" % ( + program_version, + program_build_date, + ) + program_shortdesc = __doc__.split(".")[0] + program_license = """%s + + Created by Vincent Hatakeyama on %s. + Copyright 2020 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__), + ) + parser = basic_parser(program_license, program_version_message) + project_path = os.path.realpath(".") + project_name = os.path.basename(project_path) + parser.add_argument( + "--name", + help="Container name to use [default: %(default)s]", + default=project_name, + ) + parser.add_argument( + "-c", + "--command", + help="Command to run. If specified the command will not be interactive" + ", otherwise it will be interactive.", + metavar="command", + default=None, + ) + exec_group = parser.add_mutually_exclusive_group() + exec_group.add_argument( + "--psql", + help="Exec psql (default)", + action="store_const", + const=PSQL, + dest="exec", + default=PSQL, + ) + exec_group.add_argument( + "--sh", + help="Exec a shell", + action="store_const", + const=SH, + dest="exec", + ) + # no simple way to indicate that these options are only used with psql exec + parser.add_argument("-d", "--database", help="Database name", default=None) + parser.add_argument("-u", "--user", help="User", default=None) + return parser + + +def main(argv=None): + """Run postgresql docker, and exec a psql into it + """ + parser = __parser() + namespace = parser.parse_args(argv) + apply(namespace) + project_name = namespace.name + exec = namespace.exec + command = namespace.command + user = namespace.user + # get postgres version from config + c = Config() + postgresql_version = c.postgresql_version + pg, stop_pg, path = docker_run_postgresql(project_name, postgresql_version) + # run an exec command + docker_command = None + interactive = not bool(command) + if exec == PSQL: + if not user: + user = "postgres" + docker_command = ["psql", "--user", user] + if command: + _logger.info("Exec command in the container") + docker_command.extend(["-c", command]) + else: + _logger.info("Exec psql in the container") + if namespace.database: + docker_command.append(namespace.database) + user = "root" + elif exec == SH: + if not user: + user = "root" + docker_command = ["sh"] + if command: + _logger.info("Exec shell command in the container") + docker_command.extend(["-c", command]) + else: + _logger.info("Exec sh in the container") + if docker_command: + return DockerClient.exec(pg, docker_command, user, interactive) + + +if __name__ == "__main__": + return_code = main(sys.argv[1:]) + if return_code: + exit(return_code) diff --git a/setup.py b/setup.py index 7caefd33faeb3f8547394b0906fd25e359299e71_c2V0dXAucHk=..9bdab72a5b2d0fabde74c2b952aae4992fb5a592_c2V0dXAucHk= 100644 --- a/setup.py +++ b/setup.py @@ -42,6 +42,7 @@ "docker_build_copy=odoo_scripts.docker_build_copy:main", "docker_flake8=odoo_scripts.docker_flake8:main [docker]", "docker_isort=odoo_scripts.docker_isort:main [docker]", + "docker_pg=odoo_scripts.docker_postgresql:main [docker]", "conf2reST=odoo_scripts.conf2reST:main [conf2reST]", "list_modules=odoo_scripts.list_modules:main", "update_duplicate_sources="