mirror of
https://github.com/containers/podman-compose.git
synced 2025-06-19 19:27:47 +02:00
Merge pull request #1238 from uosis/env-var-override
Add support for providing x-podman settings using environment variables
This commit is contained in:
commit
9cde3993f2
@ -156,6 +156,9 @@ x-podman:
|
||||
By default `default_net_name_compat` is `false`. This will change to `true` at some point and the
|
||||
setting will be removed.
|
||||
|
||||
This setting can also be changed by setting `PODMAN_COMPOSE_DEFAULT_NET_NAME_COMPAT` environment
|
||||
variable.
|
||||
|
||||
## Compatibility of default network behavior between docker-compose and podman-compose
|
||||
|
||||
When there is no network defined (neither network-mode nor networks) in service,
|
||||
@ -176,6 +179,9 @@ x-podman:
|
||||
default_net_behavior_compat: true
|
||||
```
|
||||
|
||||
This setting can also be changed by setting `PODMAN_COMPOSE_DEFAULT_NET_BEHAVIOR_COMPAT` environment
|
||||
variable.
|
||||
|
||||
## Custom pods management
|
||||
|
||||
Podman-compose can have containers in pods. This can be controlled by extension key x-podman in_pod.
|
||||
@ -195,6 +201,9 @@ x-podman:
|
||||
in_pod: false
|
||||
```
|
||||
|
||||
This setting can also be changed by setting `PODMAN_COMPOSE_IN_POD` environment
|
||||
variable.
|
||||
|
||||
It is also possible to override the default arguments for pod creation that are
|
||||
used when --pod-args is not passed on the command line:
|
||||
```yml
|
||||
@ -208,3 +217,6 @@ x-podman:
|
||||
```
|
||||
When not set in docker-compose.yml or on the command line, the pod args default
|
||||
to `["--infra=false", "--share="]`.
|
||||
|
||||
This setting can also be changed by setting `PODMAN_COMPOSE_POD_ARGS` environment
|
||||
variable.
|
1
newsfragments/x-podman-env-vars.feature
Normal file
1
newsfragments/x-podman-env-vars.feature
Normal file
@ -0,0 +1 @@
|
||||
- Add support for setting x-podman values using PODMAN_COMPOSE_* environment variables.
|
@ -370,7 +370,9 @@ def default_network_name_for_project(compose: PodmanCompose, net: str, is_ext: A
|
||||
|
||||
assert compose.project_name is not None
|
||||
|
||||
default_net_name_compat = compose.x_podman.get("default_net_name_compat", False)
|
||||
default_net_name_compat = compose.x_podman.get(
|
||||
PodmanCompose.XPodmanSettingKey.DEFAULT_NET_NAME_COMPAT, False
|
||||
)
|
||||
if default_net_name_compat is True:
|
||||
return f"{compose.project_name.replace('-', '')}_{net}"
|
||||
return f"{compose.project_name}_{net}"
|
||||
@ -1968,6 +1970,12 @@ COMPOSE_DEFAULT_LS = [
|
||||
|
||||
|
||||
class PodmanCompose:
|
||||
class XPodmanSettingKey(Enum):
|
||||
DEFAULT_NET_NAME_COMPAT = "default_net_name_compat"
|
||||
DEFAULT_NET_BEHAVIOR_COMPAT = "default_net_behavior_compat"
|
||||
IN_POD = "in_pod"
|
||||
POD_ARGS = "pod_args"
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.podman: Podman
|
||||
self.podman_version: str | None = None
|
||||
@ -1988,7 +1996,7 @@ class PodmanCompose:
|
||||
self.services: dict[str, Any]
|
||||
self.all_services: set[Any] = set()
|
||||
self.prefer_volume_over_mount = True
|
||||
self.x_podman: dict[str, Any] = {}
|
||||
self.x_podman: dict[PodmanCompose.XPodmanSettingKey, Any] = {}
|
||||
self.merged_yaml: Any
|
||||
self.yaml_hash = ""
|
||||
self.console_colors = [
|
||||
@ -2059,7 +2067,7 @@ class PodmanCompose:
|
||||
|
||||
def resolve_in_pod(self) -> bool:
|
||||
if self.global_args.in_pod in (None, ''):
|
||||
self.global_args.in_pod = self.x_podman.get("in_pod", "1")
|
||||
self.global_args.in_pod = self.x_podman.get(PodmanCompose.XPodmanSettingKey.IN_POD, "1")
|
||||
# otherwise use `in_pod` value provided by command line
|
||||
return self.global_args.in_pod
|
||||
|
||||
@ -2070,7 +2078,43 @@ class PodmanCompose:
|
||||
# - Default value
|
||||
if self.global_args.pod_args is not None:
|
||||
return shlex.split(self.global_args.pod_args)
|
||||
return self.x_podman.get("pod_args", ["--infra=false", "--share="])
|
||||
return self.x_podman.get(
|
||||
PodmanCompose.XPodmanSettingKey.POD_ARGS, ["--infra=false", "--share="]
|
||||
)
|
||||
|
||||
def _parse_x_podman_settings(self, compose: dict[str, Any], environ: dict[str, str]) -> None:
|
||||
known_keys = {s.value: s for s in PodmanCompose.XPodmanSettingKey}
|
||||
|
||||
self.x_podman = {}
|
||||
|
||||
for k, v in compose.get("x-podman", {}).items():
|
||||
known_key = known_keys.get(k)
|
||||
if known_key:
|
||||
self.x_podman[known_key] = v
|
||||
else:
|
||||
log.warning(
|
||||
"unknown x-podman key [%s] in compose file, supported keys: %s",
|
||||
k,
|
||||
", ".join(known_keys.keys()),
|
||||
)
|
||||
|
||||
env = {
|
||||
key.removeprefix("PODMAN_COMPOSE_").lower(): value
|
||||
for key, value in environ.items()
|
||||
if key.startswith("PODMAN_COMPOSE_")
|
||||
and key not in {"PODMAN_COMPOSE_PROVIDER", "PODMAN_COMPOSE_WARNING_LOGS"}
|
||||
}
|
||||
|
||||
for k, v in env.items():
|
||||
known_key = known_keys.get(k)
|
||||
if known_key:
|
||||
self.x_podman[known_key] = v
|
||||
else:
|
||||
log.warning(
|
||||
"unknown PODMAN_COMPOSE_ key [%s] in environment, supported keys: %s",
|
||||
k,
|
||||
", ".join(known_keys.keys()),
|
||||
)
|
||||
|
||||
def _parse_compose_file(self) -> None:
|
||||
args = self.global_args
|
||||
@ -2219,6 +2263,8 @@ class PodmanCompose:
|
||||
log.debug(" ** merged:\n%s", json.dumps(compose, indent=2))
|
||||
# ver = compose.get('version')
|
||||
|
||||
self._parse_x_podman_settings(compose, self.environ)
|
||||
|
||||
services: dict | None = compose.get("services")
|
||||
if services is None:
|
||||
services = {}
|
||||
@ -2236,7 +2282,7 @@ class PodmanCompose:
|
||||
nets["default"] = None
|
||||
|
||||
self.networks = nets
|
||||
if compose.get("x-podman", {}).get("default_net_behavior_compat", False):
|
||||
if self.x_podman.get(PodmanCompose.XPodmanSettingKey.DEFAULT_NET_BEHAVIOR_COMPAT, False):
|
||||
# If there is no network_mode and networks in service,
|
||||
# docker-compose will create default network named '<project_name>_default'
|
||||
# and add the service to the default network.
|
||||
@ -2353,8 +2399,6 @@ class PodmanCompose:
|
||||
given_containers.sort(key=lambda c: len(c.get("_deps", [])))
|
||||
# log("sorted:", [c["name"] for c in given_containers])
|
||||
|
||||
self.x_podman = compose.get("x-podman", {})
|
||||
|
||||
args.in_pod = self.resolve_in_pod()
|
||||
args.pod_arg_list = self.resolve_pod_args()
|
||||
pods, containers = transform(args, project_name, given_containers)
|
||||
|
@ -467,6 +467,57 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
||||
# can not actually find this pod because it was not created
|
||||
self.run_subprocess_assert_returncode(command_rm_pod, 1)
|
||||
|
||||
def test_x_podman_in_pod_not_exists_command_line_in_pod_not_exists_env_var(self) -> None:
|
||||
"""
|
||||
Test that podman-compose will not create a pod when env var is set.
|
||||
"""
|
||||
command_up = [
|
||||
"python3",
|
||||
os.path.join(base_path(), "podman_compose.py"),
|
||||
"-f",
|
||||
os.path.join(
|
||||
base_path(),
|
||||
"tests",
|
||||
"integration",
|
||||
"in_pod",
|
||||
"custom_x-podman_not_exists",
|
||||
"docker-compose.yml",
|
||||
),
|
||||
"up",
|
||||
"-d",
|
||||
]
|
||||
|
||||
down_cmd = [
|
||||
"python3",
|
||||
podman_compose_path(),
|
||||
"-f",
|
||||
os.path.join(
|
||||
base_path(),
|
||||
"tests",
|
||||
"integration",
|
||||
"in_pod",
|
||||
"custom_x-podman_not_exists",
|
||||
"docker-compose.yml",
|
||||
),
|
||||
"down",
|
||||
]
|
||||
|
||||
env = {
|
||||
"PODMAN_COMPOSE_IN_POD": "0",
|
||||
}
|
||||
|
||||
try:
|
||||
self.run_subprocess_assert_returncode(
|
||||
command_up, failure_exitcode_when_rootful(), env=env
|
||||
)
|
||||
|
||||
finally:
|
||||
self.run_subprocess_assert_returncode(down_cmd, env=env)
|
||||
|
||||
command_rm_pod = ["podman", "pod", "rm", "pod_custom_x-podman_not_exists"]
|
||||
# can not actually find this pod because it was not created
|
||||
self.run_subprocess_assert_returncode(command_rm_pod, 1)
|
||||
|
||||
def test_x_podman_in_pod_custom_name(self) -> None:
|
||||
"""
|
||||
Test that podman-compose will create a pod with a custom name
|
||||
|
@ -34,7 +34,7 @@ class RunSubprocessMixin:
|
||||
def is_debug_enabled(self) -> bool:
|
||||
return "TESTS_DEBUG" in os.environ
|
||||
|
||||
def run_subprocess(self, args: list[str]) -> tuple[bytes, bytes, int]:
|
||||
def run_subprocess(self, args: list[str], env: dict[str, str] = {}) -> tuple[bytes, bytes, int]:
|
||||
begin = time.time()
|
||||
if self.is_debug_enabled():
|
||||
print("TEST_CALL", args)
|
||||
@ -42,6 +42,7 @@ class RunSubprocessMixin:
|
||||
args,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
env=os.environ | env,
|
||||
)
|
||||
out, err = proc.communicate()
|
||||
if self.is_debug_enabled():
|
||||
@ -51,9 +52,9 @@ class RunSubprocessMixin:
|
||||
return out, err, proc.returncode
|
||||
|
||||
def run_subprocess_assert_returncode(
|
||||
self, args: list[str], expected_returncode: int = 0
|
||||
self, args: list[str], expected_returncode: int = 0, env: dict[str, str] = {}
|
||||
) -> tuple[bytes, bytes]:
|
||||
out, err, returncode = self.run_subprocess(args)
|
||||
out, err, returncode = self.run_subprocess(args, env=env)
|
||||
decoded_out = out.decode('utf-8')
|
||||
decoded_err = err.decode('utf-8')
|
||||
self.assertEqual( # type: ignore[attr-defined]
|
||||
|
@ -650,7 +650,7 @@ class TestContainerToArgs(unittest.IsolatedAsyncioTestCase):
|
||||
self, name: str, is_compat: bool, project_name: str, expected_network_name: str
|
||||
) -> None:
|
||||
c = create_compose_mock(project_name)
|
||||
c.x_podman = {"default_net_name_compat": is_compat}
|
||||
c.x_podman = {PodmanCompose.XPodmanSettingKey.DEFAULT_NET_NAME_COMPAT: is_compat}
|
||||
c.networks = {'network1': {}}
|
||||
|
||||
cnt = get_minimal_container()
|
||||
|
Loading…
x
Reference in New Issue
Block a user