Example #1
0
def _remove_auto_reload(file, orig_file):
    with open(orig_file, "r") as fd:
        orig_docker_config = yaml.safe_load(fd.read())
    odoo_command = orig_docker_config["services"]["odoo"]["command"]
    new_odoo_command = []
    for flag in odoo_command:
        if flag.startswith("--dev"):
            flag = flag.replace("reload,", "")
        new_odoo_command.append(flag)
    _override_docker_command("odoo", new_odoo_command, file, orig_file=orig_file)
def _load_yaml(yaml_path):
    """Load a yaml file."""
    with open(yaml_path) as yaml_fd:
        # HACK https://stackoverflow.com/a/44875714/1468388
        # TODO Remove hack when https://github.com/pyinvoke/invoke/issues/708 is fixed
        with mock.patch.object(
                yaml.reader.Reader,
                "NON_PRINTABLE",
                re.compile("[^\x09\x0A\x0D\x20-\x7E\x85\xA0-"
                           "\uD7FF\uE000-\uFFFD\U00010000-\U0010FFFF]"),
        ):
            return yaml.safe_load(yaml_fd)
Example #3
0
def _override_docker_command(service, command, file, orig_file=None):
    # Read config from main file
    if orig_file:
        with open(orig_file, "r") as fd:
            orig_docker_config = yaml.safe_load(fd.read())
            docker_compose_file_version = orig_docker_config.get("version")
    else:
        docker_compose_file_version = "2.4"
    docker_config = {
        "version": docker_compose_file_version,
        "services": {service: {"command": command}},
    }
    docker_config_yaml = yaml.dump(docker_config)
    file.write(docker_config_yaml)
    file.flush()
Example #4
0
from datetime import datetime
from itertools import chain
from logging import getLogger
from pathlib import Path
from shutil import which

from invoke import exceptions, task
from invoke.util import yaml

PROJECT_ROOT = Path(__file__).parent.absolute()
SRC_PATH = PROJECT_ROOT / "odoo" / "custom" / "src"
UID_ENV = {"GID": str(os.getgid()), "UID": str(os.getuid()), "UMASK": "27"}
SERVICES_WAIT_TIME = int(os.environ.get("SERVICES_WAIT_TIME", 4))
ODOO_VERSION = float(
    yaml.safe_load(
        (PROJECT_ROOT / "common.yaml"
         ).read_text())["services"]["odoo"]["build"]["args"]["ODOO_VERSION"])

_logger = getLogger(__name__)


def _override_docker_command(service, command, file, orig_file=None):
    # Read config from main file
    if orig_file:
        with open(orig_file, "r") as fd:
            orig_docker_config = yaml.safe_load(fd.read())
            docker_compose_file_version = orig_docker_config.get("version")
    else:
        docker_compose_file_version = "2.4"
    docker_config = {
        "version": docker_compose_file_version,
Example #5
0
def test_multiple_domains(
    cloned_template: Path,
    supported_odoo_version: float,
    tmp_path: Path,
    traefik_host: dict,
    environment: str,
):
    """Test multiple domains are produced properly."""
    base_domain = traefik_host["hostname"]
    base_path = f"{base_domain}/web/login"
    # XXX Remove traefik1 specific stuff some day
    is_traefik1 = version.parse(traefik_host["traefik_version"]) < version.parse("2")
    data = {
        "odoo_listdb": True,
        "odoo_version": supported_odoo_version,
        "paths_without_crawlers": ["/web/login", "/web/database"],
        "project_name": uuid.uuid4().hex,
        f"domains_{environment}": [
            # main0 has no TLS
            {"hosts": [f"main0.{base_domain}"], "cert_resolver": False},
            {
                "hosts": [f"alt0.main0.{base_domain}", f"alt1.main0.{base_domain}"],
                "cert_resolver": None,
                "redirect_to": f"main0.{base_domain}",
            },
            # main1 has self-signed certificates
            {"hosts": [f"main1.{base_domain}"], "cert_resolver": True},
            {
                "hosts": [f"alt0.main1.{base_domain}", f"alt1.main1.{base_domain}"],
                "cert_resolver": True,
                "redirect_to": f"main1.{base_domain}",
                "redirect_permanent": True,
            },
            # main2 only serves certain routes
            {
                "hosts": [f"main2.{base_domain}"],
                "path_prefixes": ["/insecure/"],
                "entrypoints": ["web-insecure"],
                "cert_resolver": False,
            },
            # main3 only serves certain routes in web-alt entrypoint
            {
                "hosts": [f"main3.{base_domain}"],
                "path_prefixes": ["/alt/"],
                "entrypoints": ["web-alt"],
                "cert_resolver": False,
            },
        ],
    }
    dc = docker_compose["-f", f"{environment}.yaml"]
    with local.cwd(tmp_path):
        copy(
            src_path=str(cloned_template),
            dst_path=".",
            vcs_ref="test",
            force=True,
            data=data,
        )
        # Check if Odoo options were passed correctly
        _ret_code, _stdout, _stderr = dc.run(["config"])
        docker_compose_config = yaml.safe_load(
            _stdout or _stderr
        )  # docker-compose sometimes prints to STDERR and others to STDOUT, so we check both
        assert (
            docker_compose_config["services"]["odoo"]["environment"]["LIST_DB"]
            == "true"
        )
        try:
            dc("build")
            dc(
                "run",
                "--rm",
                "odoo",
                "--stop-after-init",
                "-i",
                "base",
            )
            dc("up", "-d")
            time.sleep(10)
            # XXX Remove all Traefik 1 tests once it disappears
            if is_traefik1:
                # main0, globally redirected to TLS
                response = requests.get(f"http://main0.{base_path}", verify=False)
                assert response.ok
                assert response.url == f"https://main0.{base_domain}:443/web/login"
                assert response.headers["X-Robots-Tag"] == "noindex, nofollow"
                # alt0 and alt1, globally redirected to TLS
                for alt_num in range(2):
                    response = requests.get(
                        f"http://alt{alt_num}.main0.{base_path}", verify=False
                    )
                    assert response.ok
                    assert response.url == f"https://main0.{base_path}"
                    assert response.history[0].status_code == 302
                # main2 serves https on port 80; returns a 404 from Traefik (not from
                # Odoo) with global HTTPS redirection
                bad_response = requests.get(
                    f"http://main2.{base_domain}/insecure/path",
                    verify=False,
                )
                assert not bad_response.ok
                assert bad_response.status_code == 404
                assert "Server" not in bad_response.headers  # 404 comes from Traefik
                assert (
                    bad_response.url == f"https://main2.{base_domain}:443/insecure/path"
                )
            else:
                # main0, no TLS
                response = requests.get(f"http://main0.{base_path}")
                assert response.ok
                assert response.url == f"http://main0.{base_path}"
                assert response.headers["X-Robots-Tag"] == "noindex, nofollow"
                # alt0 and alt1, no TLS
                for alt_num in range(2):
                    response = requests.get(f"http://alt{alt_num}.main0.{base_path}")
                    assert response.ok
                    assert response.url == f"http://main0.{base_path}"
                    assert response.history[0].status_code == 302
                # main2 serves https on port 80; returns a 404 from Odoo (not from
                # Traefik) without HTTPS redirection
                bad_response = requests.get(
                    f"http://main2.{base_domain}/insecure/path",
                    verify=False,
                )
                assert not bad_response.ok
                assert bad_response.status_code == 404
                assert "Werkzeug" in bad_response.headers.get("Server")
                assert bad_response.url == f"http://main2.{base_domain}/insecure/path"
            # main3 cannot find /web on port 8080; no HTTPS redirection
            bad_response = requests.get(
                f"http://main3.{base_domain}:8080/web",
            )
            assert not bad_response.ok
            assert bad_response.status_code == 404
            assert "Server" not in bad_response.headers  # 404 comes from Traefik
            assert bad_response.url == f"http://main3.{base_domain}:8080/web"
            # main3 will route to odoo in /alt/foo but fail with 404 from there, no HTTPS
            bad_response = requests.get(
                f"http://main3.{base_domain}:8080/alt/foo",
            )
            assert not bad_response.ok
            assert bad_response.status_code == 404
            assert "Werkzeug" in bad_response.headers.get("Server")
            assert bad_response.url == f"http://main3.{base_domain}:8080/alt/foo"
            # main1, with self-signed TLS
            response = requests.get(f"http://main1.{base_path}", verify=False)
            assert response.ok
            assert response.url == (
                f"https://main1.{base_domain}:443/web/login"
                if is_traefik1
                else f"https://main1.{base_path}"
            )
            assert response.headers["X-Robots-Tag"] == "noindex, nofollow"
            # alt0 and alt1, with self-signed TLS
            for alt_num in range(2):
                response = requests.get(
                    f"http://alt{alt_num}.main1.{base_domain}/web/database/selector",
                    verify=False,
                )
                assert response.ok
                assert (
                    response.url == f"https://main1.{base_domain}/web/database/selector"
                )
                assert response.headers["X-Robots-Tag"] == "noindex, nofollow"
                # Search for a response in the chain with the 301 return code
                # as several will be made during the redirection
                assert filter(lambda r: r.status_code == 301, response.history)
            # missing, which fails with Traefik 404, both with and without TLS
            bad_response = requests.get(
                f"http://missing.{base_path}", verify=not is_traefik1
            )
            assert bad_response.status_code == 404
            assert "Server" not in bad_response.headers
            bad_response = requests.get(f"https://missing.{base_path}", verify=False)
            assert bad_response.status_code == 404
            assert "Server" not in bad_response.headers
        finally:
            dc("down", "--volumes", "--remove-orphans")