Skip to content

Commit c8f8d71

Browse files
authored
fix s3control endpoint override and respect config for mwaa (#91)
1 parent e97f179 commit c8f8d71

File tree

4 files changed

+76
-4
lines changed

4 files changed

+76
-4
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ ADDITIONAL_TF_OVERRIDE_LOCATIONS=/path/to/module1,path/to/module2 tflocal plan
7777

7878
## Change Log
7979

80+
* v0.25.0: Improve `s3control` local endpoint override and respect `AWS_ENDPOINT_URL` configuration for `mwaa`
8081
* v0.24.1: Exclude broken `python-hcl2` version from requirements
8182
* v0.24.0: Add support to return `terraform-local` version when calling `tflocal -version` and fix AWS provider detection
8283
* v0.23.1: Fix endpoint overrides for Terraform AWS provider >= 6.0.0-beta2

bin/tflocal

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ CUSTOMIZE_ACCESS_KEY = str(os.environ.get("CUSTOMIZE_ACCESS_KEY")).strip().lower
3535
"1",
3636
"true",
3737
]
38+
LOCALHOST = "localhost"
3839
LOCALHOST_HOSTNAME = "localhost.localstack.cloud"
3940
S3_HOSTNAME = os.environ.get("S3_HOSTNAME") or f"s3.{LOCALHOST_HOSTNAME}"
4041
USE_EXEC = str(os.environ.get("USE_EXEC")).strip().lower() in ["1", "true"]
@@ -53,7 +54,7 @@ LS_PROVIDERS_FILE = (
5354
LOCALSTACK_HOSTNAME = (
5455
urlparse(AWS_ENDPOINT_URL).hostname
5556
or os.environ.get("LOCALSTACK_HOSTNAME")
56-
or "localhost"
57+
or LOCALHOST
5758
)
5859
EDGE_PORT = int(urlparse(AWS_ENDPOINT_URL).port or os.environ.get("EDGE_PORT") or 4566)
5960
AWS_PROVIDER_NAME_SUFFIX = "/hashicorp/aws"
@@ -541,10 +542,16 @@ def get_service_endpoint(service: str) -> str:
541542

542543
# some services need specific hostnames
543544
hostname = LOCALSTACK_HOSTNAME
545+
# if the user has not set the LOCALSTACK_HOSTNAME, and it fell back to `localhost`, we must force the endpoint to
546+
# be make sure it can resolve subdomains
547+
subdomain_compatible_endpoint = LOCALHOST_HOSTNAME if hostname == LOCALHOST else hostname
544548
if service == "s3":
545549
hostname = S3_HOSTNAME
546550
elif service == "mwaa":
547-
hostname = f"mwaa.{LOCALHOST_HOSTNAME}"
551+
hostname = f"mwaa.{subdomain_compatible_endpoint}"
552+
elif service == "s3control":
553+
# `s3control` sets the account-id as part of the subdomain of the endpoint
554+
hostname = subdomain_compatible_endpoint
548555

549556
return f"http://{hostname}:{EDGE_PORT}"
550557

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = terraform-local
3-
version = 0.24.1
3+
version = 0.25.0
44
url = https://github.com/localstack/terraform-local
55
author = LocalStack Team
66
author_email = info@localstack.cloud

tests/test_apply.py

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,6 @@ def test_versioned_endpoints(monkeypatch, provider_version):
409409
secret_key = "test"
410410
skip_credentials_validation = true
411411
skip_metadata_api_check = true
412-
skip_requesting_account_id = true
413412
endpoints {
414413
sns = "http://localhost:4566"
415414
}
@@ -444,6 +443,71 @@ def test_versioned_endpoints(monkeypatch, provider_version):
444443
assert "iotevents" not in endpoints
445444

446445

446+
@pytest.mark.parametrize("endpoint_host", ["", "test-host"])
447+
def test_subdomain_endpoints(monkeypatch, endpoint_host):
448+
# we are using the `AWS_ENDPOINT_URL`, but setting the `LOCALSTACK_HOSTNAME` and `EDGE_PORT` (both deprecated)
449+
# would have the same behavior
450+
aws_endpoint_url = f"http://{endpoint_host}:4566" if endpoint_host else ""
451+
monkeypatch.setenv("AWS_ENDPOINT_URL", aws_endpoint_url)
452+
bucket_name = f"bucket-{short_uid()}"
453+
config = """
454+
terraform {
455+
required_providers {
456+
aws = {
457+
source = "hashicorp/aws"
458+
version = ">= 6.23"
459+
}
460+
}
461+
}
462+
463+
provider "aws" {
464+
region = "us-east-1"
465+
access_key = "test"
466+
secret_key = "test"
467+
skip_credentials_validation = true
468+
skip_metadata_api_check = true
469+
}
470+
471+
resource "aws_s3_bucket" "example" {
472+
name = "%s"
473+
}
474+
""" % bucket_name
475+
476+
with tempfile.TemporaryDirectory(delete=True) as temp_dir:
477+
with open(os.path.join(temp_dir, "test.tf"), "w") as f:
478+
f.write(config)
479+
480+
# we need the `terraform init` command to create a lock file, so it cannot be a `DRY_RUN`
481+
run([TFLOCAL_BIN, "init"], cwd=temp_dir, env=dict(os.environ))
482+
monkeypatch.setenv("DRY_RUN", "1")
483+
run([TFLOCAL_BIN, "apply", "-auto-approve"], cwd=temp_dir, env=dict(os.environ))
484+
485+
override_file = os.path.join(temp_dir, "localstack_providers_override.tf")
486+
assert check_override_file_exists(override_file)
487+
488+
with open(override_file, "r") as fp:
489+
result = hcl2.load(fp)
490+
endpoints = result["provider"][0]["aws"]["endpoints"][0]
491+
assert "s3control" in endpoints
492+
assert "mwaa" in endpoints
493+
494+
if aws_endpoint_url == "":
495+
# we assert that if the `LOCALSTACK_HOSTNAME` isn't set, the default endpooint value is `localhost`
496+
assert endpoints["sns"] == "http://localhost:4566"
497+
# the MWAA endpoint needs to be "subdomain resolvable", so we override it with the default localhost
498+
# localstack hostname
499+
assert endpoints["mwaa"] == "http://mwaa.localhost.localstack.cloud:4566"
500+
# s3 control will set the account id of the requested as a host prefix, so we also need a subdomain
501+
# compatible host
502+
assert endpoints["s3control"] == "http://localhost.localstack.cloud:4566"
503+
else:
504+
# if the user is manipulating the `LOCALSTACK_HOSTNAME`, they are responsible to make sure that the
505+
# domain they set is subdomain compatible, so we respect their configuration
506+
assert endpoints["sns"] == f"http://{endpoint_host}:4566"
507+
assert endpoints["mwaa"] == f"http://mwaa.{endpoint_host}:4566"
508+
assert endpoints["s3control"] == f"http://{endpoint_host}:4566"
509+
510+
447511
def test_dry_run(monkeypatch):
448512
monkeypatch.setenv("DRY_RUN", "1")
449513
state_bucket = "tf-state-dry-run"

0 commit comments

Comments
 (0)