Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fcac5b7

Browse files
committed
code review
1 parent c0f097c commit fcac5b7

File tree

4 files changed

+160
-97
lines changed

4 files changed

+160
-97
lines changed

‎localstack/utils/bootstrap.py

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ def random_gateway_port(cfg: ContainerConfiguration):
420420
@staticmethod
421421
def default_gateway_port(cfg: ContainerConfiguration):
422422
"""Adds 4566 to the list of port mappings"""
423-
cfg.ports.add(constants.DEFAULT_PORT_EDGE)
423+
return ContainerConfigurators.gateway_listen(constants.DEFAULT_PORT_EDGE)(cfg)
424424

425425
@staticmethod
426426
def gateway_listen(
@@ -546,10 +546,20 @@ def _cfg(cfg: ContainerConfiguration):
546546
@staticmethod
547547
def cli_params(params: Dict[str, Any]):
548548
"""
549-
Parse docker CLI parameters and add them to the config. The currently known CLI params are:
549+
Parse docker CLI parameters and add them to the config. The currently known CLI params are::
550550
551-
:param params:
552-
:return:
551+
--network=my-network <- stored in "network"
552+
-e FOO=BAR -e BAR=ed <- stored in "env"
553+
554+
When parsed by click, the parameters would look like this::
555+
556+
{
557+
"network": "my-network",
558+
"env": ("FOO=BAR", "BAR=ed"),
559+
}
560+
561+
:param params: a dict of parsed parameters
562+
:return: a configurator
553563
"""
554564
# TODO: consolidate with container_client.Util.parse_additional_flags
555565
def _cfg(cfg: ContainerConfiguration):
@@ -580,24 +590,27 @@ def get_gateway_port(container: Container) -> int:
580590
:param container: the localstack container
581591
:return: the gateway port reachable from the host
582592
"""
583-
edge_port = constants.DEFAULT_PORT_EDGE
593+
candidates: List[int]
584594

585595
gateway_listen = container.config.env_vars.get("GATEWAY_LISTEN")
586596
if gateway_listen:
587-
for value in gateway_listen.split(","):
588-
host_and_port = config.HostAndPort.parse(
597+
candidates = [
598+
HostAndPort.parse(
589599
value,
590600
default_host=constants.LOCALHOST_HOSTNAME,
591601
default_port=constants.DEFAULT_PORT_EDGE,
592-
)
593-
edge_port = host_and_port.port
594-
break
602+
).port
603+
for value in gateway_listen.split(",")
604+
]
605+
else:
606+
candidates = [constants.DEFAULT_PORT_EDGE]
595607

596-
ports = container.config.ports.to_dict()
608+
exposed = container.config.ports.to_dict()
597609

598-
port = ports.get(f"{edge_port}/tcp")
599-
if port:
600-
return port
610+
for candidate in candidates:
611+
port = exposed.get(f"{candidate}/tcp")
612+
if port:
613+
return port
601614

602615
raise ValueError("no gateway port mapping found")
603616

‎localstack/utils/container_utils/container_client.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -422,9 +422,9 @@ class VolumeInfo(NamedTuple):
422422
class ContainerConfiguration:
423423
image_name: str
424424
name: Optional[str] = None
425-
volumes: Optional[VolumeMappings] = None
426-
ports: Optional[PortMappings] = None
427-
exposed_ports: Optional[List[str]] = None
425+
volumes: VolumeMappings = dataclasses.field(default_factory=VolumeMappings)
426+
ports: PortMappings = dataclasses.field(default_factory=PortMappings)
427+
exposed_ports: List[str] = dataclasses.field(default_factory=list)
428428
entrypoint: Optional[str] = None
429429
additional_flags: Optional[str] = None
430430
command: Optional[List[str]] = None

‎tests/bootstrap/test_container_configurators.py

Lines changed: 78 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -35,44 +35,44 @@ def test_common_container_fixture_configurators(
3535
]
3636
)
3737

38-
with container.start() as running_container:
39-
wait_for_localstack_ready(running_container)
40-
url = get_gateway_url(container)
41-
42-
# port was exposed correctly
43-
response = requests.get(f"{url}/_localstack/health")
44-
assert response.ok
45-
46-
# volume was mounted and directories were created correctly
47-
assert (volume / "cache" / "machine.json").exists()
48-
49-
inspect = running_container.inspect()
50-
# volume was mounted correctly
51-
assert {
52-
"Type": "bind",
53-
"Source": str(volume),
54-
"Destination": "/var/lib/localstack",
55-
"Mode": "",
56-
"RW": True,
57-
"Propagation": "rprivate",
58-
} in inspect["Mounts"]
59-
# docker socket was mounted correctly
60-
assert {
61-
"Type": "bind",
62-
"Source": "/var/run/docker.sock",
63-
"Destination": "/var/run/docker.sock",
64-
"Mode": "",
65-
"RW": True,
66-
"Propagation": "rprivate",
67-
} in inspect["Mounts"]
68-
69-
# debug was set
70-
assert "DEBUG=1" in inspect["Config"]["Env"]
71-
# environment variables were set
72-
assert "FOOBAR=foobar" in inspect["Config"]["Env"]
73-
assert "MY_TEST_ENV=test" in inspect["Config"]["Env"]
74-
# container name was set
75-
assert f"MAIN_CONTAINER_NAME={container.config.name}" in inspect["Config"]["Env"]
38+
running_container = container.start()
39+
wait_for_localstack_ready(running_container)
40+
url = get_gateway_url(container)
41+
42+
# port was exposed correctly
43+
response = requests.get(f"{url}/_localstack/health")
44+
assert response.ok
45+
46+
# volume was mounted and directories were created correctly
47+
assert (volume / "cache" / "machine.json").exists()
48+
49+
inspect = running_container.inspect()
50+
# volume was mounted correctly
51+
assert {
52+
"Type": "bind",
53+
"Source": str(volume),
54+
"Destination": "/var/lib/localstack",
55+
"Mode": "",
56+
"RW": True,
57+
"Propagation": "rprivate",
58+
} in inspect["Mounts"]
59+
# docker socket was mounted correctly
60+
assert {
61+
"Type": "bind",
62+
"Source": "/var/run/docker.sock",
63+
"Destination": "/var/run/docker.sock",
64+
"Mode": "",
65+
"RW": True,
66+
"Propagation": "rprivate",
67+
} in inspect["Mounts"]
68+
69+
# debug was set
70+
assert "DEBUG=1" in inspect["Config"]["Env"]
71+
# environment variables were set
72+
assert "FOOBAR=foobar" in inspect["Config"]["Env"]
73+
assert "MY_TEST_ENV=test" in inspect["Config"]["Env"]
74+
# container name was set
75+
assert f"MAIN_CONTAINER_NAME={container.config.name}" in inspect["Config"]["Env"]
7676

7777

7878
def test_custom_command_configurator(container_factory, tmp_path, stream_container_logs):
@@ -101,9 +101,9 @@ def test_custom_command_configurator(container_factory, tmp_path, stream_contain
101101
remove=False,
102102
)
103103

104-
with container.start() as running_container:
105-
assert running_container.wait_until_ready(timeout=5)
106-
assert running_container.get_logs().strip() == "foobar\nhello world"
104+
running_container = container.start()
105+
assert running_container.wait_until_ready(timeout=5)
106+
assert running_container.get_logs().strip() == "foobar\nhello world"
107107

108108

109109
def test_default_localstack_container_configurator(
@@ -125,41 +125,40 @@ def test_default_localstack_container_configurator(
125125
container: Container = container_factory()
126126
configure_container(container)
127127

128-
with container.start() as running_container:
129-
stream_container_logs(container)
130-
wait_for_localstack_ready(running_container)
131-
132-
# check startup works correctly
133-
response = requests.get("http://localhost:4566/_localstack/health")
134-
assert response.ok
135-
136-
# check docker-flags was created correctly
137-
response = requests.get("http://localhost:23456/_localstack/health")
138-
assert response.ok, "couldn't reach localstack on port 23456 - does DOCKER_FLAGS work?"
139-
140-
response = requests.get("http://localhost:4566/_localstack/diagnose")
141-
assert response.ok, "couldn't reach diagnose endpoint. is DEBUG=1 set?"
142-
diagnose = response.json()
143-
144-
# a few smoke tests of important configs
145-
assert diagnose["config"]["GATEWAY_LISTEN"] == ["0.0.0.0:4566"]
146-
# check that docker-socket was mounted correctly
147-
assert diagnose["docker-inspect"], "was the docker socket mounted?"
148-
assert diagnose["docker-inspect"]["Config"]["Image"] == "localstack/localstack"
149-
assert diagnose["docker-inspect"]["Path"] == "docker-entrypoint.sh"
150-
assert {
151-
"Type": "bind",
152-
"Source": str(volume),
153-
"Destination": "/var/lib/localstack",
154-
"Mode": "",
155-
"RW": True,
156-
"Propagation": "rprivate",
157-
} in diagnose["docker-inspect"]["Mounts"]
158-
159-
# from DOCKER_FLAGS
160-
assert "MY_TEST_VAR=foobar" in diagnose["docker-inspect"]["Config"]["Env"]
161-
162-
# check that external service ports were mapped correctly
163-
ports = diagnose["docker-inspect"]["NetworkSettings"]["Ports"]
164-
for port in external_service_ports:
165-
assert ports[f"{port}/tcp"] == [{"HostIp": "127.0.0.1", "HostPort": f"{port}"}]
128+
stream_container_logs(container)
129+
wait_for_localstack_ready(container.start())
130+
131+
# check startup works correctly
132+
response = requests.get("http://localhost:4566/_localstack/health")
133+
assert response.ok
134+
135+
# check docker-flags was created correctly
136+
response = requests.get("http://localhost:23456/_localstack/health")
137+
assert response.ok, "couldn't reach localstack on port 23456 - does DOCKER_FLAGS work?"
138+
139+
response = requests.get("http://localhost:4566/_localstack/diagnose")
140+
assert response.ok, "couldn't reach diagnose endpoint. is DEBUG=1 set?"
141+
diagnose = response.json()
142+
143+
# a few smoke tests of important configs
144+
assert diagnose["config"]["GATEWAY_LISTEN"] == ["0.0.0.0:4566"]
145+
# check that docker-socket was mounted correctly
146+
assert diagnose["docker-inspect"], "was the docker socket mounted?"
147+
assert diagnose["docker-inspect"]["Config"]["Image"] == "localstack/localstack"
148+
assert diagnose["docker-inspect"]["Path"] == "docker-entrypoint.sh"
149+
assert {
150+
"Type": "bind",
151+
"Source": str(volume),
152+
"Destination": "/var/lib/localstack",
153+
"Mode": "",
154+
"RW": True,
155+
"Propagation": "rprivate",
156+
} in diagnose["docker-inspect"]["Mounts"]
157+
158+
# from DOCKER_FLAGS
159+
assert "MY_TEST_VAR=foobar" in diagnose["docker-inspect"]["Config"]["Env"]
160+
161+
# check that external service ports were mapped correctly
162+
ports = diagnose["docker-inspect"]["NetworkSettings"]["Ports"]
163+
for port in external_service_ports:
164+
assert ports[f"{port}/tcp"] == [{"HostIp": "127.0.0.1", "HostPort": f"{port}"}]

‎tests/unit/utils/test_bootstrap.py

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
import pytest
66

7-
from localstack.utils.bootstrap import get_enabled_apis
7+
from localstack import constants
8+
from localstack.utils.bootstrap import Container, get_enabled_apis, get_gateway_port
9+
from localstack.utils.container_utils.container_client import ContainerConfiguration
810

911

1012
@contextmanager
@@ -71,3 +73,52 @@ def test_resolve_meta(self):
7173
"cognito-idp",
7274
"cognito-identity",
7375
}
76+
77+
78+
class TestGetGatewayPort:
79+
def test_fails_if_nothing_set(self):
80+
# error case
81+
with pytest.raises(ValueError):
82+
get_gateway_port(Container(ContainerConfiguration("")))
83+
84+
def test_fails_if_not_exposed(self):
85+
# gateway_listen set but not exposed
86+
c = Container(ContainerConfiguration(""))
87+
c.config.env_vars["GATEWAY_LISTEN"] = ":4566"
88+
with pytest.raises(ValueError):
89+
get_gateway_port(Container(ContainerConfiguration("")))
90+
91+
def test_default(self):
92+
# default case
93+
c = Container(ContainerConfiguration(""))
94+
c.config.ports.add(constants.DEFAULT_PORT_EDGE)
95+
assert get_gateway_port(c) == constants.DEFAULT_PORT_EDGE
96+
97+
def test_single_mapping(self):
98+
# gateway_listen set and exposed to different port
99+
c = Container(ContainerConfiguration(""))
100+
c.config.env_vars["GATEWAY_LISTEN"] = ":4566"
101+
c.config.ports.add(5000, 4566)
102+
assert get_gateway_port(c) == 5000
103+
104+
def test_in_port_range_mapping(self):
105+
# gateway_listen set and port range exposed
106+
c = Container(ContainerConfiguration(""))
107+
c.config.env_vars["GATEWAY_LISTEN"] = ":4566"
108+
c.config.ports.add([4000, 5000])
109+
assert get_gateway_port(c) == 4566
110+
111+
def test_multiple_gateway_listen_ports_returns_first(self):
112+
# gateway_listen set to multiple values returns first case
113+
c = Container(ContainerConfiguration(""))
114+
c.config.env_vars["GATEWAY_LISTEN"] = ":5000,:443"
115+
c.config.ports.add(443)
116+
c.config.ports.add(5000)
117+
assert get_gateway_port(c) == 5000
118+
119+
def test_multiple_gateway_listen_ports_only_one_exposed(self):
120+
# gateway_listen set to multiple values but first port not exposed
121+
c = Container(ContainerConfiguration(""))
122+
c.config.env_vars["GATEWAY_LISTEN"] = ":4566,:443"
123+
c.config.ports.add(443)
124+
assert get_gateway_port(c) == 443

0 commit comments

Comments
 (0)