Skip to content
Open
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: 2 additions & 2 deletions .github/workflows/ci-community.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ on:

jobs:
track-modules:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- name: Checkout contents
uses: actions/checkout@v4
Expand All @@ -38,7 +38,7 @@ jobs:
outputs:
changed_modules: ${{ steps.compute-changes.outputs.computed_modules }}
test:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
needs: [track-modules]
if: ${{ needs.track-modules.outputs.changed_modules != '[]' }}
strategy:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ci-core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:

jobs:
run-tests-and-coverage:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -43,7 +43,7 @@ jobs:

coverage-compile:
needs: "run-tests-and-coverage"
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Set up Python
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:

jobs:
python:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Setup Env
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:

jobs:
build:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Set up Python
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pr-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ permissions:
jobs:
validate:
name: validate-pull-request-title
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- name: validate pull request title
uses: kontrolplane/pull-request-title-validator@ab2b54babb5337246f4b55cf8e0a1ecb0575e46d #v1
4 changes: 2 additions & 2 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:

jobs:
release:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
outputs:
release_created: ${{ steps.track-release.outputs.release_created }}
steps:
Expand All @@ -16,7 +16,7 @@ jobs:
manifest-file: .github/.release-please-manifest.json
config-file: .github/release-please-config.json
publish:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
environment: release
permissions:
id-token: write
Expand Down
2 changes: 1 addition & 1 deletion .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ sphinx:
configuration: conf.py

build:
os: ubuntu-22.04
os: ubuntu-24.04
tools:
python: "3.10"

Expand Down
9 changes: 9 additions & 0 deletions core/testcontainers/podman/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# flake8: noqa: F401
from testcontainers.podman.kube_play import (
KubePlay
)

__all__ = [
"KubePlay",
]

88 changes: 88 additions & 0 deletions core/testcontainers/podman/kube_play.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
from dataclasses import dataclass
from logging import getLogger
from os import PathLike, path
from subprocess import CompletedProcess, CalledProcessError, run as subprocess_run
from types import TracebackType
from typing import Optional, Union
import re

logger = getLogger(__name__)

def parse_kube_play_stdout(stdout: str) -> dict[str, list[str]]:
pattern = re.compile(r"(^.+?):\n((?:[a-f0-9]+\n?)*)", re.MULTILINE)
result = {}
for key, values in pattern.findall(stdout):
# split values by newline, remove empties
value_list = [v for v in values.strip().splitlines() if v]
result[key] = value_list
return result

@dataclass
class KubePlay:
kube_play_file: Union[str, PathLike[str]]
context: Optional[str] = None
podman_command_path: str = "podman"
build: bool = False
keep_volumes: bool = False
replace: bool = False


_pods: Optional[list[str]] = None

def __enter__(self) -> "KubePlay":
self.start()
return self

def __exit__(
self, exc_type: Optional[type[BaseException]], exc_val: Optional[BaseException], exc_tb: Optional[TracebackType]
) -> None:
self.stop(force=not self.keep_volumes)

def start(self) -> None:
start_cmd = [self.podman_command_path, "kube", "play", str(self.kube_play_file)]

# build means modifying the up command
if self.build:
start_cmd.append("--build")

if self.replace:
start_cmd.append("--replace")

result = self._run_command(cmd=start_cmd)
if result.returncode != 0:
raise RuntimeError(f"Podman command failed with exit code {result.returncode}")

info = parse_kube_play_stdout(result.stdout.decode("utf-8"))
self._pods = info['Pod']


def stop(self, force: bool = False) -> None:
down_cmd = [self.podman_command_path, "kube", "down", str(self.kube_play_file)]

if force:
# Tear down the volumes linked to the PersistentVolumeClaims as part of --down
down_cmd.append("--force")

self._run_command(cmd=down_cmd)
self._pods = None

def get_pods(self) -> list[str]:
return self._pods if self._pods is not None else []

def _run_command(
self,
cmd: Union[str, list[str]],
) -> CompletedProcess[bytes]:
context = self.context if self.context else path.dirname(self.kube_play_file)
try:
return subprocess_run(
cmd,
capture_output=True,
check=True,
cwd=context,
)
except CalledProcessError as e:
logger.error(f"Command '{e.cmd}' failed with exit code {e.returncode}")
logger.error(f"STDOUT:\n{e.stdout.decode(errors='ignore')}")
logger.error(f"STDERR:\n{e.stderr.decode(errors='ignore')}")
raise e from e
10 changes: 10 additions & 0 deletions core/tests/podman_fixtures/kube_play/basic/play.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
13 changes: 13 additions & 0 deletions core/tests/test_podman_kube_play.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from pathlib import Path

from testcontainers.podman import KubePlay

FIXTURES = Path(__file__).parent.joinpath("podman_fixtures", "kube_play")

def test_podman_kube_play():
basic = KubePlay(
kube_play_file=FIXTURES.joinpath("basic", "play.yaml"),
)

with basic:
assert len(basic.get_pods()) == 1
Loading