From 088e6a2ec5f00018cd7c414f1d69f57f56220412 Mon Sep 17 00:00:00 2001 From: Thomas Rausch Date: Thu, 10 Aug 2023 23:03:40 +0200 Subject: [PATCH 1/2] refactor localstack container config hooks --- localstack/plugins.py | 2 +- localstack/utils/analytics/metadata.py | 2 +- localstack/utils/bootstrap.py | 61 +++++++------------------- 3 files changed, 17 insertions(+), 48 deletions(-) diff --git a/localstack/plugins.py b/localstack/plugins.py index 2cd97e1ad6701..7ee3bdabc1fca 100644 --- a/localstack/plugins.py +++ b/localstack/plugins.py @@ -12,7 +12,7 @@ def configure_edge_port(container): LOG.debug("configuring container with edge ports: %s", ports) for port in ports: if port: - container.ports.add(port) + container.config.ports.add(port) # Register the ArnPartitionRewriteListener only if the feature flag is enabled diff --git a/localstack/utils/analytics/metadata.py b/localstack/utils/analytics/metadata.py index d25fa5788128e..59202e1711e8d 100644 --- a/localstack/utils/analytics/metadata.py +++ b/localstack/utils/analytics/metadata.py @@ -185,4 +185,4 @@ def _mount_machine_file(container): machine_file = os.path.join(config.dirs.cache, "machine.json") if os.path.isfile(machine_file): target = os.path.join(config.dirs.for_container().cache, "machine.json") - container.volumes.add(VolumeBind(machine_file, target, read_only=True)) + container.config.volumes.add(VolumeBind(machine_file, target, read_only=True)) diff --git a/localstack/utils/bootstrap.py b/localstack/utils/bootstrap.py index f84b3d733bf2d..86068808d3680 100644 --- a/localstack/utils/bootstrap.py +++ b/localstack/utils/bootstrap.py @@ -1,4 +1,3 @@ -import copy import functools import logging import os @@ -375,8 +374,6 @@ def __init__(self, name: str = None): self.config = self._get_default_configuration(name) self.logfile = os.path.join(config.dirs.tmp, f"{self.config.name}_container.log") - self.additional_flags = [] # TODO: see comment in run() - def _get_default_configuration(self, name: str = None) -> ContainerConfiguration: """Returns a ContainerConfiguration populated with default values or values gathered from the environment for starting the LocalStack container.""" @@ -390,30 +387,20 @@ def _get_default_configuration(self, name: str = None) -> ContainerConfiguration entrypoint=os.environ.get("ENTRYPOINT"), command=shlex.split(os.environ.get("CMD", "")) or None, env_vars={}, + additional_flags="", ) def run(self): if isinstance(DOCKER_CLIENT, CmdDockerClient): DOCKER_CLIENT.default_run_outfile = self.logfile - # FIXME: this is pretty awkward, but additional_flags in the LocalstackContainer API was always a - # list of ["-e FOO=BAR", ...], whereas in the DockerClient it is expected to be a string. so we - # need to re-assemble it here. the better way would be to not use additional_flags here all - # together. it is still used in ext in `configure_pro_container` which could be refactored to use - # the additional port bindings. - cfg = copy.deepcopy(self.config) - if not cfg.additional_flags: - cfg.additional_flags = "" - if self.additional_flags: - cfg.additional_flags += " " + " ".join(self.additional_flags) - # TODO: there could be a --network flag in `additional_flags`. we solve a similar problem for the # ports using `extract_port_flags`. maybe it would be better to consolidate all this into the # ContainerConfig object, like ContainerConfig.update_from_flags(str). - self._ensure_container_network(cfg.network) + self._ensure_container_network(self.config.network) try: - return DOCKER_CLIENT.run_container_from_config(cfg) + return DOCKER_CLIENT.run_container_from_config(self.config) except ContainerException as e: if LOG.isEnabledFor(logging.DEBUG): LOG.exception("Error while starting LocalStack container") @@ -441,30 +428,10 @@ def truncate_log(self): # these properties are there to not break code that configures the container by using these values # that code should ideally be refactored soon-ish to use the config instead. - @property - def env_vars(self) -> Dict[str, str]: - return self.config.env_vars - - @property - def entrypoint(self) -> Optional[str]: - return self.config.entrypoint - - @entrypoint.setter - def entrypoint(self, value: str): - self.config.entrypoint = value - @property def name(self) -> str: return self.config.name - @property - def volumes(self) -> VolumeMappings: - return self.config.volumes - - @property - def ports(self) -> PortMappings: - return self.config.ports - class LocalstackContainerServer(Server): container: LocalstackContainer @@ -529,37 +496,39 @@ def configure_container(container: LocalstackContainer): Configuration routine for the LocalstackContainer. """ # get additional configured flags + cfg = container.config + user_flags = config.DOCKER_FLAGS - user_flags = extract_port_flags(user_flags, container.ports) - container.additional_flags.extend(shlex.split(user_flags)) + user_flags = extract_port_flags(user_flags, cfg.ports) + cfg.additional_flags += user_flags # get additional parameters from plugins hooks.configure_localstack_container.run(container) # construct default port mappings - container.ports.add(get_edge_port_http()) + cfg.ports.add(get_edge_port_http()) for port in range(config.EXTERNAL_SERVICE_PORTS_START, config.EXTERNAL_SERVICE_PORTS_END): - container.ports.add(port) + cfg.ports.add(port) if config.DEVELOP: - container.ports.add(config.DEVELOP_PORT) + cfg.ports.add(config.DEVELOP_PORT) # environment variables # pass through environment variables defined in config for env_var in config.CONFIG_ENV_VARS: value = os.environ.get(env_var, None) if value is not None: - container.env_vars[env_var] = value - container.env_vars["DOCKER_HOST"] = f"unix://{config.DOCKER_SOCK}" + cfg.env_vars[env_var] = value + cfg.env_vars["DOCKER_HOST"] = f"unix://{config.DOCKER_SOCK}" # TODO this is default now, remove once a considerate time is passed # to activate proper signal handling - container.env_vars["SET_TERM_HANDLER"] = "1" + cfg.env_vars["SET_TERM_HANDLER"] = "1" configure_volume_mounts(container) # mount docker socket - container.volumes.append((config.DOCKER_SOCK, config.DOCKER_SOCK)) + cfg.volumes.append((config.DOCKER_SOCK, config.DOCKER_SOCK)) container.privileged = True @@ -583,7 +552,7 @@ def configure_container_from_cli_params(container: LocalstackContainer, params: def configure_volume_mounts(container: LocalstackContainer): - container.volumes.add(VolumeBind(config.VOLUME_DIR, DEFAULT_VOLUME_DIR)) + container.config.volumes.add(VolumeBind(config.VOLUME_DIR, DEFAULT_VOLUME_DIR)) @log_duration() From 865748868b5c0bea41c93e6598ca85af851fbaf7 Mon Sep 17 00:00:00 2001 From: Thomas Rausch Date: Fri, 11 Aug 2023 00:49:51 +0200 Subject: [PATCH 2/2] fix container server test --- tests/bootstrap/test_localstack_container.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bootstrap/test_localstack_container.py b/tests/bootstrap/test_localstack_container.py index ad413a771a900..336615af6d53b 100644 --- a/tests/bootstrap/test_localstack_container.py +++ b/tests/bootstrap/test_localstack_container.py @@ -11,7 +11,7 @@ class TestLocalstackContainerServer: def test_lifecycle(self): server = LocalstackContainerServer() - server.container.ports.add(config.EDGE_PORT) + server.container.config.ports.add(config.EDGE_PORT) assert not server.is_up() try: