avast / pytest-docker

Docker-based integration tests
MIT License
427 stars 71 forks source link

Support for other forms of `$DOCKER_HOST` passing #110

Open pyhedgehog opened 8 months ago

pyhedgehog commented 8 months ago

There are two cases when docker_ip fixture returns incorrect value:

  1. Non-default docker context used.
  2. Remote docker used via ssh://... schema instead of tcp://.

I have an idea:

import pytest_docker, json, re, shlex, socket

@pytest.fixture(scope="session")
def docker_ip() -> str:
    # These two statements supports all forms of passing dockerd endpoint to docker (ezcept -H option):
    # 1. DOCKER_HOST variable
    # 2. DOCKER_CONTEXT variable
    # 3. docker context use
    # 4. Defaults to unix://...
    context_name = (
        (pytest_docker.plugin.execute("docker context show") or b"default")
        .decode("utf-8")
        .strip()
    )

    # This block is almost same as in origin 
    docker_host = pytest_docker.plugin.execute(
        'docker context inspect -f "{{.Endpoints.docker.Host}}" '
        + shlex.quote(context_name)
    ).decode("utf-8")
    if not docker_host or docker_host.startswith("unix://"):
        return "127.0.0.1"
    match = re.match(r"^tcp://(.+?):\d+$", docker_host)
    if match:
        return match.group(1)

    # Last-chance failover for non-tcp remote docker daemons
    info = json.loads(pytest_docker.plugin.execute("docker info -f json"))
    if info["Name"] == os.environ.get("HOSTNAME"):
        return "127.0.0.1"
    return info.get("Swarm",{}).get("NodeAddr") or socket.gethostbyname(info["Name"])

Other options are much worse:

  1. Parse ~/.ssh/config to detect chain of ProxyJump and ProxyCommand.
  2. Use something like execute("docker run --rm alpine ip route get 8.8.8.8") which will not work in private network.
  3. Require swam-enabled daemons and force docker info -f {{.Swarm.NodeAddr}}.

Maybe somebody knows better way to discover connectable address of remote docker daemon, but note that it can be non-connectable at all if ssh goes throw firewall or if it has --ip=127.0.0.1 in parameters.

BTW: One can configure proxy of tcp:// daemon (like Portainer does).

As a last resort user of some very special config can rewrite docker_ip fixture in conftest.py.