From 4f843ad11c2e3a9cdafad1b911437a660d885d2d Mon Sep 17 00:00:00 2001 From: Kanishk Pachauri Date: Mon, 17 Feb 2025 23:36:01 +0530 Subject: [PATCH 1/4] fix: Correctly handle environment variables in container creation Signed-off-by: Kanishk Pachauri --- podman/domain/containers_create.py | 43 +++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/podman/domain/containers_create.py b/podman/domain/containers_create.py index 80d7f7c8..da6c92df 100644 --- a/podman/domain/containers_create.py +++ b/podman/domain/containers_create.py @@ -383,6 +383,30 @@ def create( return self.get(container_id) + @staticmethod + def _convert_env_list_to_dict(env_list): + """Convert a list of environment variables to a dictionary. + + Args: + env_list (List[str]): List of environment variables in the format ["KEY=value"] + + Returns: + Dict[str, str]: Dictionary of environment variables + + Raises: + ValueError: If any environment variable is not in the correct format + """ + env_dict = {} + for env_var in env_list: + if '=' not in env_var: + raise ValueError( + f"Environment variable '{env_var}' is not in the correct format. " + "Expected format: 'KEY=value'" + ) + key, value = env_var.split('=', 1) # Split on first '=' only + env_dict[key] = value + return env_dict + # pylint: disable=too-many-locals,too-many-statements,too-many-branches @staticmethod def _render_payload(kwargs: MutableMapping[str, Any]) -> dict[str, Any]: @@ -410,6 +434,23 @@ def _render_payload(kwargs: MutableMapping[str, Any]) -> dict[str, Any]: with suppress(KeyError): del args[key] + # Handle environment variables + environment = args.pop("environment", None) + if environment is not None: + if isinstance(environment, list): + try: + environment = CreateMixin._convert_env_list_to_dict(environment) + except ValueError as e: + raise ValueError( + "Failed to convert environment variables list to dictionary. " + f"Error: {str(e)}" + ) from e + elif not isinstance(environment, dict): + raise TypeError( + "Environment variables must be provided as either a dictionary " + "or a list of strings in the format ['KEY=value']" + ) + # These keywords are not supported for various reasons. unsupported_keys = set(args.keys()).intersection( ( @@ -490,7 +531,7 @@ def to_bytes(size: Union[int, str, None]) -> Union[int, None]: "dns_search": pop("dns_search"), "dns_server": pop("dns"), "entrypoint": pop("entrypoint"), - "env": pop("environment"), + "env": environment, "env_host": pop("env_host"), # TODO document, podman only "expose": {}, "groups": pop("group_add"), From 23a0845b5ea4450d46bb1b3251c7cfe73a0c17c1 Mon Sep 17 00:00:00 2001 From: Kanishk Pachauri Date: Mon, 17 Feb 2025 23:36:39 +0530 Subject: [PATCH 2/4] test: Add tests for the enviroment variables Signed-off-by: Kanishk Pachauri --- .../integration/test_container_create.py | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/podman/tests/integration/test_container_create.py b/podman/tests/integration/test_container_create.py index 2c4b56d9..e3a97ac5 100644 --- a/podman/tests/integration/test_container_create.py +++ b/podman/tests/integration/test_container_create.py @@ -102,6 +102,46 @@ def test_container_extra_hosts(self): for hosts_entry in formatted_hosts: self.assertIn(hosts_entry, logs) + def test_container_environment_variables(self): + """Test environment variables passed to the container.""" + with self.subTest("Check environment variables as dictionary"): + env_dict = {"MY_VAR": "123", "ANOTHER_VAR": "456"} + container = self.client.containers.create( + self.alpine_image, command=["env"], environment=env_dict + ) + self.containers.append(container) + + self.assertEqual( + container.attrs.get('Config', {}).get('Env', []), + [f"{k}={v}" for k, v in env_dict.items()], + ) + + container.start() + container.wait() + logs = b"\n".join(container.logs()).decode() + + for key, value in env_dict.items(): + self.assertIn(f"{key}={value}", logs) + + with self.subTest("Check environment variables as list"): + env_list = ["MY_VAR=123", "ANOTHER_VAR=456"] + container = self.client.containers.create( + self.alpine_image, command=["env"], environment=env_list + ) + self.containers.append(container) + + self.assertEqual( + container.attrs.get('Config', {}).get('Env', []), + env_list, + ) + + container.start() + container.wait() + logs = b"\n".join(container.logs()).decode() + + for env in env_list: + self.assertIn(env, logs) + def _test_memory_limit(self, parameter_name, host_config_name, set_mem_limit=False): """Base for tests which checks memory limits""" memory_limit_tests = [ From 068e23330f6a2bc3fe24f5b5b9abb8cddb51f136 Mon Sep 17 00:00:00 2001 From: Kanishk Pachauri Date: Mon, 17 Feb 2025 23:51:20 +0530 Subject: [PATCH 3/4] fix: broken tests Signed-off-by: Kanishk Pachauri --- .../tests/integration/test_container_create.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/podman/tests/integration/test_container_create.py b/podman/tests/integration/test_container_create.py index e3a97ac5..62ed3063 100644 --- a/podman/tests/integration/test_container_create.py +++ b/podman/tests/integration/test_container_create.py @@ -111,11 +111,12 @@ def test_container_environment_variables(self): ) self.containers.append(container) - self.assertEqual( - container.attrs.get('Config', {}).get('Env', []), - [f"{k}={v}" for k, v in env_dict.items()], - ) + # Verify that the user-provided environment variables are in the container's configuration + container_env = container.attrs.get('Config', {}).get('Env', []) + for key, value in env_dict.items(): + self.assertIn(f"{key}={value}", container_env) + # Start the container and verify the environment variables are set container.start() container.wait() logs = b"\n".join(container.logs()).decode() @@ -130,11 +131,12 @@ def test_container_environment_variables(self): ) self.containers.append(container) - self.assertEqual( - container.attrs.get('Config', {}).get('Env', []), - env_list, - ) + # Verify that the user-provided environment variables are in the container's configuration + container_env = container.attrs.get('Config', {}).get('Env', []) + for env in env_list: + self.assertIn(env, container_env) + # Start the container and verify the environment variables are set container.start() container.wait() logs = b"\n".join(container.logs()).decode() From ee13b44943803210db0b439aa4aeea1ef1fd686c Mon Sep 17 00:00:00 2001 From: Kanishk Pachauri Date: Tue, 18 Feb 2025 00:12:00 +0530 Subject: [PATCH 4/4] chore: removed unuseful comments Signed-off-by: Kanishk Pachauri --- podman/tests/integration/test_container_create.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/podman/tests/integration/test_container_create.py b/podman/tests/integration/test_container_create.py index 62ed3063..a530b98d 100644 --- a/podman/tests/integration/test_container_create.py +++ b/podman/tests/integration/test_container_create.py @@ -111,12 +111,10 @@ def test_container_environment_variables(self): ) self.containers.append(container) - # Verify that the user-provided environment variables are in the container's configuration container_env = container.attrs.get('Config', {}).get('Env', []) for key, value in env_dict.items(): self.assertIn(f"{key}={value}", container_env) - # Start the container and verify the environment variables are set container.start() container.wait() logs = b"\n".join(container.logs()).decode() @@ -131,12 +129,10 @@ def test_container_environment_variables(self): ) self.containers.append(container) - # Verify that the user-provided environment variables are in the container's configuration container_env = container.attrs.get('Config', {}).get('Env', []) for env in env_list: self.assertIn(env, container_env) - # Start the container and verify the environment variables are set container.start() container.wait() logs = b"\n".join(container.logs()).decode()