|
6 | 6 | import subprocess
|
7 | 7 | import tempfile
|
8 | 8 | import time
|
9 |
| -from typing import Any, Dict, List, Mapping, Tuple |
| 9 | +from dataclasses import dataclass |
| 10 | +from typing import Any, Dict, List, Mapping, Tuple, TypeVar |
10 | 11 |
|
| 12 | +from localstack import constants |
11 | 13 | from localstack.constants import (
|
12 | 14 | AWS_REGION_US_EAST_1,
|
13 | 15 | DEFAULT_BUCKET_MARKER_LOCAL,
|
14 | 16 | DEFAULT_DEVELOP_PORT,
|
15 | 17 | DEFAULT_LAMBDA_CONTAINER_REGISTRY,
|
16 |
| - DEFAULT_PORT_EDGE, |
17 | 18 | DEFAULT_SERVICE_PORTS,
|
18 | 19 | DEFAULT_VOLUME_DIR,
|
19 | 20 | DOCKER_IMAGE_NAME,
|
|
28 | 29 | TRUE_STRINGS,
|
29 | 30 | )
|
30 | 31 |
|
| 32 | +T = TypeVar("T", str, int) |
| 33 | + |
31 | 34 | # keep track of start time, for performance debugging
|
32 | 35 | load_start_time = time.time()
|
33 | 36 |
|
@@ -316,12 +319,6 @@ def in_docker():
|
316 | 319 | os.environ.get("DEFAULT_REGION") or os.environ.get("AWS_DEFAULT_REGION") or AWS_REGION_US_EAST_1
|
317 | 320 | )
|
318 | 321 |
|
319 |
| -# expose services on a specific host externally |
320 |
| -HOSTNAME_EXTERNAL = os.environ.get("HOSTNAME_EXTERNAL", "").strip() or LOCALHOST |
321 |
| - |
322 |
| -# name of the host under which the LocalStack services are available |
323 |
| -LOCALSTACK_HOSTNAME = os.environ.get("LOCALSTACK_HOSTNAME", "").strip() or LOCALHOST |
324 |
| - |
325 | 322 | # directory for persisting data (TODO: deprecated, simply use PERSISTENCE=1)
|
326 | 323 | DATA_DIR = os.environ.get("DATA_DIR", "").strip()
|
327 | 324 |
|
@@ -411,12 +408,120 @@ def in_docker():
|
411 | 408 | # whether to forward edge requests in-memory (instead of via proxy servers listening on backend ports)
|
412 | 409 | # TODO: this will likely become the default and may get removed in the future
|
413 | 410 | FORWARD_EDGE_INMEM = True
|
414 |
| -# Default bind address for the edge service |
415 |
| -EDGE_BIND_HOST = os.environ.get("EDGE_BIND_HOST", "").strip() or "127.0.0.1" |
416 |
| -# port number for the edge service, the main entry point for all API invocations |
417 |
| -EDGE_PORT = int(os.environ.get("EDGE_PORT") or 0) or DEFAULT_PORT_EDGE |
418 |
| -# fallback port for non-SSL HTTP edge service (in case HTTPS edge service cannot be used) |
419 |
| -EDGE_PORT_HTTP = int(os.environ.get("EDGE_PORT_HTTP") or 0) |
| 411 | + |
| 412 | +# expose services on a specific host externally |
| 413 | +# DEPRECATED: since v2.0.0 as we are moving to LOCALSTACK_HOST |
| 414 | +HOSTNAME_EXTERNAL = os.environ.get("HOSTNAME_EXTERNAL", "").strip() or LOCALHOST |
| 415 | + |
| 416 | +# name of the host under which the LocalStack services are available |
| 417 | +# DEPRECATED: if the user sets this since v2.0.0 as we are moving to LOCALSTACK_HOST |
| 418 | +LOCALSTACK_HOSTNAME = os.environ.get("LOCALSTACK_HOSTNAME", "").strip() or LOCALHOST |
| 419 | + |
| 420 | + |
| 421 | +def populate_legacy_edge_configuration( |
| 422 | + environment: Dict[str, str] |
| 423 | +) -> Tuple[str, str, str, int, int]: |
| 424 | + if is_in_docker: |
| 425 | + default_ip = "0.0.0.0" |
| 426 | + else: |
| 427 | + default_ip = "127.0.0.1" |
| 428 | + |
| 429 | + localstack_host_raw = environment.get("LOCALSTACK_HOST") |
| 430 | + gateway_listen_raw = environment.get("GATEWAY_LISTEN") |
| 431 | + |
| 432 | + # new for v2 |
| 433 | + # populate LOCALSTACK_HOST first since GATEWAY_LISTEN may be derived from LOCALSTACK_HOST |
| 434 | + localstack_host = localstack_host_raw |
| 435 | + if localstack_host is None: |
| 436 | + localstack_host = f"{constants.LOCALHOST_HOSTNAME}:{constants.DEFAULT_PORT_EDGE}" |
| 437 | + |
| 438 | + def parse_gateway_listen(value: str) -> str: |
| 439 | + if ":" in value: |
| 440 | + ip, port_s = value.split(":", 1) |
| 441 | + if not ip.strip(): |
| 442 | + ip = default_ip |
| 443 | + if not port_s.strip(): |
| 444 | + port_s = "4566" |
| 445 | + port = int(port_s) |
| 446 | + return f"{ip}:{port}" |
| 447 | + else: |
| 448 | + return f"{value}:4566" |
| 449 | + |
| 450 | + gateway_listen = gateway_listen_raw |
| 451 | + if gateway_listen is None: |
| 452 | + # default to existing behaviour |
| 453 | + port = int(localstack_host.split(":")[-1]) |
| 454 | + gateway_listen = f"{default_ip}:{port}" |
| 455 | + else: |
| 456 | + components = gateway_listen.split(",") |
| 457 | + if len(components) > 1: |
| 458 | + LOG.warning("multiple GATEWAY_LISTEN addresses are not currently supported") |
| 459 | + |
| 460 | + gateway_listen = ",".join( |
| 461 | + [parse_gateway_listen(component.strip()) for component in components] |
| 462 | + ) |
| 463 | + |
| 464 | + assert gateway_listen is not None |
| 465 | + assert localstack_host is not None |
| 466 | + |
| 467 | + def legacy_fallback(envar_name: str, default: T) -> T: |
| 468 | + result = default |
| 469 | + result_raw = environment.get(envar_name) |
| 470 | + if result_raw is not None and gateway_listen_raw is None: |
| 471 | + result = result_raw |
| 472 | + |
| 473 | + return result |
| 474 | + |
| 475 | + # derive legacy variables from GATEWAY_LISTEN unless GATEWAY_LISTEN is not given and |
| 476 | + # legacy variables are |
| 477 | + edge_bind_host = legacy_fallback("EDGE_BIND_HOST", get_gateway_listen(gateway_listen)[0].host) |
| 478 | + edge_port = int(legacy_fallback("EDGE_PORT", get_gateway_listen(gateway_listen)[0].port)) |
| 479 | + edge_port_http = int( |
| 480 | + legacy_fallback("EDGE_PORT_HTTP", get_gateway_listen(gateway_listen)[0].port) |
| 481 | + ) |
| 482 | + |
| 483 | + return localstack_host, gateway_listen, edge_bind_host, edge_port, edge_port_http |
| 484 | + |
| 485 | + |
| 486 | +@dataclass |
| 487 | +class HostAndPort: |
| 488 | + host: str |
| 489 | + port: int |
| 490 | + |
| 491 | + @classmethod |
| 492 | + def parse(cls, input: str) -> "HostAndPort": |
| 493 | + host, port_s = input.split(":") |
| 494 | + return cls(host=host, port=int(port_s)) |
| 495 | + |
| 496 | + def __eq__(self, other: Any) -> bool: |
| 497 | + if not isinstance(other, self.__class__): |
| 498 | + return False |
| 499 | + |
| 500 | + return self.host == other.host and self.port == other.port |
| 501 | + |
| 502 | + |
| 503 | +def get_gateway_listen(gateway_listen: str) -> List[HostAndPort]: |
| 504 | + result = [] |
| 505 | + for bind_address in gateway_listen.split(","): |
| 506 | + result.append(HostAndPort.parse(bind_address)) |
| 507 | + return result |
| 508 | + |
| 509 | + |
| 510 | +# How to access LocalStack |
| 511 | +( |
| 512 | + # -- Cosmetic |
| 513 | + LOCALSTACK_HOST, |
| 514 | + # -- Edge configuration |
| 515 | + # Main configuration of the listen address of the hypercorn proxy. Of the form |
| 516 | + # <ip_address>:<port>(,<ip_address>:port>)* |
| 517 | + GATEWAY_LISTEN, |
| 518 | + # -- Legacy variables |
| 519 | + EDGE_BIND_HOST, |
| 520 | + EDGE_PORT, |
| 521 | + EDGE_PORT_HTTP, |
| 522 | +) = populate_legacy_edge_configuration(os.environ) |
| 523 | + |
| 524 | + |
420 | 525 | # optional target URL to forward all edge requests to
|
421 | 526 | EDGE_FORWARD_URL = os.environ.get("EDGE_FORWARD_URL", "").strip()
|
422 | 527 |
|
|
0 commit comments