1
0
mirror of https://github.com/home-assistant/supervisor.git synced 2026-02-15 07:27:13 +00:00

Fix 'DockerMount is not JSON serializable' in DockerAPI.run_command (#6477)

This commit is contained in:
Jan Čermák
2026-01-14 15:21:11 +01:00
committed by GitHub
parent 3e3db696d3
commit 753021d4d5
2 changed files with 69 additions and 0 deletions

View File

@@ -27,6 +27,7 @@ from docker.api.client import APIClient
from docker.client import DockerClient from docker.client import DockerClient
from docker.models.containers import Container, ContainerCollection from docker.models.containers import Container, ContainerCollection
from docker.models.networks import Network from docker.models.networks import Network
from docker.types import Mount
from docker.types.daemon import CancellableStream from docker.types.daemon import CancellableStream
import requests import requests
@@ -621,6 +622,8 @@ class DockerAPI(CoreSysAttributes):
image: str, image: str,
version: str = "latest", version: str = "latest",
command: str | list[str] | None = None, command: str | list[str] | None = None,
*,
mounts: list[DockerMount] | None = None,
**kwargs: Any, **kwargs: Any,
) -> CommandReturn: ) -> CommandReturn:
"""Create a temporary container and run command. """Create a temporary container and run command.
@@ -641,6 +644,11 @@ class DockerAPI(CoreSysAttributes):
detach=True, detach=True,
network=self.network.name, network=self.network.name,
use_config_proxy=False, use_config_proxy=False,
mounts=(
[cast(Mount, mount.to_dict()) for mount in mounts]
if mounts
else None
),
**kwargs, **kwargs,
) )

View File

@@ -10,6 +10,7 @@ import pytest
from requests import RequestException from requests import RequestException
from supervisor.coresys import CoreSys from supervisor.coresys import CoreSys
from supervisor.docker.const import DockerMount, MountBindOptions, MountType
from supervisor.docker.manager import CommandReturn, DockerAPI from supervisor.docker.manager import CommandReturn, DockerAPI
from supervisor.exceptions import DockerError from supervisor.exceptions import DockerError
@@ -43,6 +44,7 @@ async def test_run_command_success(docker: DockerAPI):
use_config_proxy=False, use_config_proxy=False,
stdout=True, stdout=True,
stderr=True, stderr=True,
mounts=None,
) )
# Verify container cleanup # Verify container cleanup
@@ -74,6 +76,7 @@ async def test_run_command_with_defaults(docker: DockerAPI):
detach=True, detach=True,
network=docker.network.name, network=docker.network.name,
use_config_proxy=False, use_config_proxy=False,
mounts=None,
) )
# Verify container.logs was called with default stdout/stderr # Verify container.logs was called with default stdout/stderr
@@ -140,6 +143,64 @@ async def test_run_command_custom_stdout_stderr(docker: DockerAPI):
assert result.output == b"output" assert result.output == b"output"
async def test_run_command_with_mounts(docker: DockerAPI):
"""Test command execution with mounts are correctly converted."""
# Mock container and its methods
mock_container = MagicMock()
mock_container.wait.return_value = {"StatusCode": 0}
mock_container.logs.return_value = b"output"
# Mock docker containers.run to return our mock container
docker.dockerpy.containers.run.return_value = mock_container
# Create test mounts
mounts = [
DockerMount(
type=MountType.BIND,
source="/dev",
target="/dev",
read_only=True,
bind_options=MountBindOptions(read_only_non_recursive=True),
),
DockerMount(
type=MountType.VOLUME,
source="my_volume",
target="/data",
read_only=False,
),
]
# Execute the command with mounts
result = docker.run_command(image="alpine", command="test", mounts=mounts)
# Verify the result
assert result.exit_code == 0
# Check that mounts were converted correctly
docker.dockerpy.containers.run.assert_called_once_with(
"alpine:latest",
command="test",
detach=True,
network=docker.network.name,
use_config_proxy=False,
mounts=[
{
"Type": "bind",
"Source": "/dev",
"Target": "/dev",
"ReadOnly": True,
"BindOptions": {"ReadOnlyNonRecursive": True},
},
{
"Type": "volume",
"Source": "my_volume",
"Target": "/data",
"ReadOnly": False,
},
],
)
@pytest.mark.usefixtures("path_extern", "tmp_supervisor_data") @pytest.mark.usefixtures("path_extern", "tmp_supervisor_data")
async def test_run_container_with_cidfile(coresys: CoreSys, docker: DockerAPI): async def test_run_container_with_cidfile(coresys: CoreSys, docker: DockerAPI):
"""Test container creation with cidfile and bind mount.""" """Test container creation with cidfile and bind mount."""