Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove the container in case of detach mode #427

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions podman/api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ def post(

Keyword Args:
compatible: Will override the default path prefix with compatible prefix
verify: Whether to verify TLS certificates.

Raises:
APIError: when service returns an error
Expand Down Expand Up @@ -400,6 +401,7 @@ def _request(

Keyword Args:
compatible: Will override the default path prefix with compatible prefix
verify: Whether to verify TLS certificates.

Raises:
APIError: when service returns an error
Expand All @@ -418,6 +420,7 @@ def _request(
# TODO should we have an option for HTTPS support?
# Build URL for operation from base_url
uri = urllib.parse.ParseResult(
# TODO: Does it make sense: "https" if kwargs.get("verify", None) else "http" ?
"http",
self.base_url.netloc,
urllib.parse.urljoin(path_prefix, path),
Expand All @@ -435,6 +438,7 @@ def _request(
data=data,
headers=(headers or {}),
stream=stream,
verify=kwargs.get("verify", None),
**timeout_kw,
)
)
Expand Down
14 changes: 14 additions & 0 deletions podman/domain/containers_run.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Mixin to provide Container run() method."""

import logging
import threading
from contextlib import suppress
from typing import Generator, Iterator, List, Union

Expand Down Expand Up @@ -67,7 +68,20 @@ def run(
container.start()
container.reload()

def remove_container(container_object: Container) -> None:
"""
Wait the container to finish and remove it.

Args:
container_object: Container object
"""
container_object.wait() # Wait for the container to finish
container_object.remove() # Remove the container

if kwargs.get("detach", False):
if remove:
# Start a background thread to remove the container after finishing
threading.Thread(target=remove_container, args=(container,)).start()
return container

with suppress(KeyError):
Expand Down
20 changes: 18 additions & 2 deletions podman/domain/images_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from podman.domain.images_build import BuildMixin
from podman.domain.manager import Manager
from podman.domain.registry_data import RegistryData
from podman.errors import APIError, ImageNotFound
from podman.errors import APIError, ImageNotFound, PodmanError

try:
from rich.progress import (
Expand Down Expand Up @@ -113,18 +113,34 @@ def get_registry_data(
collection=self,
)

def load(self, data: bytes) -> Generator[Image, None, None]:
def load(
self, data: Optional[bytes] = None, file_path: Optional[str] = None
) -> Generator[Image, None, None]:
"""Restore an image previously saved.
Args:
data: Image to be loaded in tarball format.
file_path: Path of the Tarball.
Raises:
APIError: when service returns an error
"""
# TODO fix podman swagger cannot use this header!
# headers = {"Content-type": "application/x-www-form-urlencoded"}

if not data and not file_path:
raise PodmanError("The 'data' or 'file_path' parameter should be set.")

if data and file_path:
raise PodmanError(
"Only one parameter should be set from 'data' and 'file_path' parameters."
)

if file_path:
# Load a tarball containing the image
with open(file_path, "rb") as tarball_file:
data = tarball_file.read() # Read the tarball file as bytes

response = self.client.post(
"/images/load", data=data, headers={"Content-type": "application/x-tar"}
)
Expand Down
15 changes: 14 additions & 1 deletion podman/domain/system.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""SystemManager to provide system level information from Podman service."""

import logging
from typing import Any, Dict, Optional
from typing import Any, Dict, Optional, Union

from podman.api.client import APIClient
from podman import api
Expand Down Expand Up @@ -44,6 +44,10 @@ def login( # pylint: disable=too-many-arguments,too-many-positional-arguments,u
registry: Optional[str] = None,
reauth: Optional[bool] = False, # pylint: disable=unused-argument
dockercfg_path: Optional[str] = None, # pylint: disable=unused-argument
auth: Optional[str] = None,
identitytoken: Optional[str] = None,
registrytoken: Optional[str] = None,
tls_verify: Optional[Union[bool, str]] = None,
) -> Dict[str, Any]:
"""Log into Podman service.

Expand All @@ -55,20 +59,29 @@ def login( # pylint: disable=too-many-arguments,too-many-positional-arguments,u
reauth: Ignored: If True, refresh existing authentication. Default: False
dockercfg_path: Ignored: Path to custom configuration file.
https://quay.io/v2
auth = None,
identitytoken: IdentityToken is used to authenticate the user and
get an access token for the registry.
registrytoken: RegistryToken is a bearer token to be sent to a registry
tls_verify: Whether to verify TLS certificates.
"""

payload = {
"username": username,
"password": password,
"email": email,
"serveraddress": registry,
"auth": auth,
"identitytoken": identitytoken,
"registrytoken": registrytoken,
}
payload = api.prepare_body(payload)
response = self.client.post(
path="/auth",
headers={"Content-type": "application/json"},
data=payload,
compatible=True,
verify=tls_verify, # Pass tls_verify to the client
)
response.raise_for_status()
return response.json()
Expand Down
34 changes: 33 additions & 1 deletion podman/tests/unit/test_imagesmanager.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import types
import unittest
from unittest.mock import mock_open, patch

try:
# Python >= 3.10
Expand All @@ -13,7 +14,7 @@
from podman import PodmanClient, tests
from podman.domain.images import Image
from podman.domain.images_manager import ImagesManager
from podman.errors import APIError, ImageNotFound
from podman.errors import APIError, ImageNotFound, PodmanError

FIRST_IMAGE = {
"Id": "sha256:326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab",
Expand Down Expand Up @@ -320,6 +321,37 @@ def test_remove(self, mock):

@requests_mock.Mocker()
def test_load(self, mock):
with self.assertRaises(PodmanError):
self.client.images.load()

with self.assertRaises(PodmanError):
self.client.images.load(b'data', b'file_path')

with self.assertRaises(PodmanError):
self.client.images.load(data=b'data', file_path=b'file_path')

with patch("builtins.open", mock_open(read_data=b"mock tarball data")) as mock_file:
mock.post(
tests.LIBPOD_URL + "/images/load",
json={"Names": ["quay.io/fedora:latest"]},
)
mock.get(
tests.LIBPOD_URL + "/images/quay.io%2ffedora%3Alatest/json",
json=FIRST_IMAGE,
)

# 3a. Test the case where only 'file_path' is provided
gntr = self.client.images.load(file_path="mock_file.tar")
self.assertIsInstance(gntr, types.GeneratorType)

report = list(gntr)
self.assertEqual(len(report), 1)
self.assertEqual(
report[0].id,
"sha256:326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab",
)
mock_file.assert_called_once_with("mock_file.tar", "rb")

mock.post(
tests.LIBPOD_URL + "/images/load",
json={"Names": ["quay.io/fedora:latest"]},
Expand Down
Loading