Skip to content

Commit

Permalink
Add a method DockerService.Load to SystemService. (#198)
Browse files Browse the repository at this point in the history
The method will load a tar image to docker engine (equivalent to the CLI docker load)

The API is needed for implementing gnoi.containerz.deploy, where we deploy a docker image to the network device.
  • Loading branch information
hdwhdw authored Dec 31, 2024
1 parent 25bd8ff commit d5a250e
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 0 deletions.
23 changes: 23 additions & 0 deletions host_modules/docker_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,3 +251,26 @@ def run(self, image, command, kwargs):
return errno.ENOENT, "Image {} not found.".format(image)
except Exception as e:
return 1, "Failed to run image {}: {}".format(image, str(e))

@host_service.method(
host_service.bus_name(MOD_NAME), in_signature="s", out_signature="is"
)
def load(self, image):
"""
Load a Docker image from a tar archive.
Args:
image (str): The path to the tar archive containing the Docker image.
Returns:
tuple: A tuple containing the exit code (int) and a message indicating the result of the operation.
"""
try:
client = docker.from_env()
with open(image, 'rb') as image_tar:
client.images.load(image_tar)
return 0, "Image {} has been loaded.".format(image)
except FileNotFoundError:
return errno.ENOENT, "File {} not found.".format(image)
except Exception as e:
return 1, "Failed to load image {}: {}".format(image, str(e))
31 changes: 31 additions & 0 deletions tests/host_modules/docker_service_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,3 +287,34 @@ def test_docker_run_fail_non_empty_command(
docker_service = DockerService(MOD_NAME)
rc, msg = docker_service.run("docker-syncd-brcm:latest", "rm -rf /", {})
assert rc == errno.EPERM, "Return code is wrong"

@mock.patch("dbus.SystemBus")
@mock.patch("dbus.service.BusName")
@mock.patch("dbus.service.Object.__init__")
def test_docker_load_success(self, MockInit, MockBusName, MockSystemBus):
mock_docker_client = mock.Mock()
mock_docker_client.images.load.return_value = ["loaded_image"]

with mock.patch("builtins.open", mock.mock_open(read_data="data")) as MockOpen, \
mock.patch.object(docker, "from_env", return_value=mock_docker_client):
docker_service = DockerService(MOD_NAME)
rc, _ = docker_service.load("image.tar")

assert rc == 0, "Return code is wrong"
mock_docker_client.images.load.assert_called_once_with(MockOpen.return_value)
MockOpen.assert_called_once_with("image.tar", "rb")

@mock.patch("dbus.SystemBus")
@mock.patch("dbus.service.BusName")
@mock.patch("dbus.service.Object.__init__")
def test_docker_load_file_not_found(self, MockInit, MockBusName, MockSystemBus):
mock_docker_client = mock.Mock()

with mock.patch("builtins.open", mock.mock_open()) as MockOpen, \
mock.patch.object(docker, "from_env", return_value=mock_docker_client):
MockOpen.side_effect = FileNotFoundError
docker_service = DockerService(MOD_NAME)
rc, _ = docker_service.load("non_existent_image.tar")

assert rc == errno.ENOENT, "Return code is wrong"
MockOpen.assert_called_once_with("non_existent_image.tar", "rb")

0 comments on commit d5a250e

Please sign in to comment.