Resolve the default security group UUID dynamically instead of hardcoding it
The "default" security group VK Cloud auto-creates in every project has a UUID unique to that project, but main.tf hardcoded one project's UUID across all 4 instance resources (router, priv_srv_01/02/03) - not portable to another project. Replaced with data.vkcs_networking_secgroup (matched by name = "default", verified against the real provider schema via terraform providers schema -json on the local provider mirror) behind local.default_security_group_id. The new default_security_group_id variable is a last-resort manual override via coalesce() for projects where the lookup doesn't fit (non-standard name/SDN) - not the normal path. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011hXR2ftXZZhJ4Y3XuSoR8r
This commit is contained in:
1 parent
1ef4b12143
commit
b5d6367fd8
7 files changed
+174
-6
No files matched your search
@@ -75,6 +75,21 @@ def find_variable(doc, name):
|
||||
return None
|
||||
|
||||
|
||||
def find_local(doc, name):
|
||||
"""main.tf has more than one `locals { ... }` block - search all of them."""
|
||||
for block in doc.get("locals", []):
|
||||
if name in block:
|
||||
return block[name]
|
||||
return None
|
||||
|
||||
|
||||
def find_data_sources(doc, dtype):
|
||||
"""Yield (name, attrs) for every data source of a given type in a parsed doc."""
|
||||
for block in doc.get("data", []):
|
||||
if dtype in block:
|
||||
yield from block[dtype].items()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Delivery layout
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -251,6 +266,21 @@ def test_router_count_validation_is_enforced(count, should_pass):
|
||||
assert ok == should_pass, f"unexpected result for router_count={count}:\n{output}"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"override,should_pass",
|
||||
[
|
||||
(None, True), # default null - no override, dynamic lookup is used
|
||||
("11111111-1111-1111-1111-111111111111", True), # explicit override accepted
|
||||
],
|
||||
)
|
||||
def test_default_security_group_id_override_accepted(override, should_pass):
|
||||
overrides = {}
|
||||
if override is not None:
|
||||
overrides["TF_VAR_default_security_group_id"] = override
|
||||
ok, output = _plan_variables_only(overrides)
|
||||
assert ok == should_pass, f"unexpected result for default_security_group_id={override!r}:\n{output}"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# HCL parses cleanly
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -343,8 +373,8 @@ def test_no_legacy_hardcoded_router_resources():
|
||||
|
||||
def test_private_roles_local_driven_by_variable():
|
||||
main = load_tf("main.tf")
|
||||
locals_block = main["locals"][0]
|
||||
assert locals_block["private_roles"] == [
|
||||
private_roles = find_local(main, "private_roles")
|
||||
assert private_roles == [
|
||||
'${[for idx in range(length(var.private_network_cidrs)) : "priv${idx + 1}"]}'
|
||||
], "locals.private_roles must be generated from length(var.private_network_cidrs)"
|
||||
|
||||
@@ -359,6 +389,54 @@ def test_router_network_blocks_scale_with_private_roles():
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# main.tf: the "default" security group UUID is resolved dynamically, not
|
||||
# hardcoded (it's unique per VK Cloud project)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_default_security_group_data_source_exists():
|
||||
main = load_tf("main.tf")
|
||||
secgroups = dict(find_data_sources(main, "vkcs_networking_secgroup"))
|
||||
assert "default" in secgroups, "expected data.vkcs_networking_secgroup.default"
|
||||
assert secgroups["default"]["name"] == ["default"]
|
||||
|
||||
|
||||
def test_default_security_group_id_local_prefers_override_then_lookup():
|
||||
main = load_tf("main.tf")
|
||||
value = find_local(main, "default_security_group_id")
|
||||
assert value == [
|
||||
"${coalesce(var.default_security_group_id,"
|
||||
"data.vkcs_networking_secgroup.default.id)}"
|
||||
], (
|
||||
"locals.default_security_group_id must fall back to the dynamic "
|
||||
"lookup unless var.default_security_group_id is explicitly overridden"
|
||||
)
|
||||
|
||||
|
||||
def test_no_hardcoded_security_group_uuid_in_main():
|
||||
text = (TERRAFORM_DIR / "main.tf").read_text()
|
||||
uuid_pattern = re.compile(
|
||||
r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", re.I
|
||||
)
|
||||
assert not uuid_pattern.search(text), (
|
||||
"main.tf must not contain a literal UUID (e.g. a hardcoded security "
|
||||
"group ID) - it's unique per project and must be resolved dynamically "
|
||||
"via data.vkcs_networking_secgroup or overridden via "
|
||||
"var.default_security_group_id"
|
||||
)
|
||||
|
||||
|
||||
def test_all_instances_use_default_security_group_local():
|
||||
main = load_tf("main.tf")
|
||||
for name, attrs in find_resources(main, "vkcs_compute_instance"):
|
||||
sg_ids = attrs["security_group_ids"][0]
|
||||
assert "${local.default_security_group_id}" in sg_ids, (
|
||||
f"vkcs_compute_instance.{name} does not reference "
|
||||
f"local.default_security_group_id in security_group_ids"
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# terraform.tfvars example CIDRs: sanity-check the values actually shipped
|
||||
# (no auto-carving anymore - these come straight from the admin/example)
|
||||
|
||||
Reference in new issue
Block a user