Policy sorting doesn't work reliably with for_each loop
I'd like to draw some attention to way fortinet API and terraform interfere causing issues with terraform for_each. I'm pretty sure similar issue exists in other places, however I'm going to demonstrate an issue using policy fortios_firewall_security_policyseq resource.
in this particular scenario we have an array of objects, that defines policies. There are few helpers variables derived from it, which I'm going to omit here. Important point is that both fortios_firewall_policy and fortios_firewall_security_policyseq gets created using for_each loop.
resource "fortios_firewall_policy" "tr_policy" {
for_each = { for item in local.flatten_policies : format(local.resource_name_format, item.name, var.vdom) => item }
name = each.value.name
global_label = each.value.global_label
comments = format("Terraform - %s", each.value.comment)
action = each.value.action
schedule = each.value.schedule
....
}
resource "fortios_firewall_security_policyseq" "tr_policy_ordering" {
for_each = { for item in local.policies_order : item.key => item.value if item.value.next_policy_id != null}
vdomparam = each.value.vdom
policy_src_id = each.value.policy_id
policy_dst_id = each.value.next_policy_id
alter_position = "before"
enable_state_checking = true
}
The issue arise in fortios_firewall_security_policyseq, as terraform calling fortios_firewall_security_policyseq not sequentially, it least to final order mangled. Assume we have current policies order like this [16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1], and desired policy order is [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16].
Terraform would update fortios_firewall_security_policyseq resource for policy 9, and place it before policy 10. resulting in [16, 15, 14, 13, 12, 11, 9, 10, 8, 7, 6, 5, 4, 3, 2, 1]. Next it tries to order policy 10, and place it before policy 11, resulting in [16, 15, 14, 13, 12, 10, 11, 9, 8, 7, 6, 5, 4, 3, 2, 1], etc. as you can see it causes incorrect order to be applied, even if original srd-id and dst-id are sorted in the right order.
As far as I can see there is no way out of this, unless sorting is treated as an atomic operation that acts upon whole policy list within one resource.
So instead of fortios_firewall_security_policyseq, which takes only srd-id and dst-id, we need something that can sort policies in one operatino:
resource "fortios_firewall_security_policy_order" "tr_policy_ordering" {
dynamic "policy_order" {
for_each = local.policies_order
}
content {
policyid = policy_order.value.policyid
anchor_policyid = policy_order.value.anchor_policyid
relation = policy_order.value.relation
}
}
Hi @p-v-a ,
Thank you for raising this question, we have a resource called fortios_firewall_securitypolicy_sort to sort policies by policyid or name ascendingly, ascendingly or in a manual order. here is an example for your reference. let me know if that doesn't solve your question.
variable "name" {
type = list(any)
default = ["z", "b", "c", "d"]
description = "description"
}
# variable name {
# type = list
# default = ["a", "f", "zgt", "za", "zzz", "334", "25", "1689"]
# description = "description"
# }
resource "fortios_firewall_securitypolicy" "trname" {
for_each = toset(var.name)
action = "accept"
logtraffic = "utm"
name = each.key
schedule = "always"
dstaddr {
name = "all"
}
dstintf {
name = port2
}
srcaddr {
name = "all"
}
srcintf {
name = port3
}
}
resource "fortios_firewall_securitypolicy_sort" "test" {
sortby = "name" # ["name", "policyid"]
sortdirection = "manual" # ["descending", "ascending", "manual"]
force_recreate = join(" ", var.name)
manual_order = var.name #["z", "b", "c", "d"]
depends_on = [
fortios_firewall_securitypolicy.trname
]
}
Thanks, Maxx
I looked at this previously, but documentation is missing example, and from description of manual_order and sortby attributes I came to conclusion that it just sort by name, and you can't define an order.
Thank you for pointing this out, this simplifies things a lot!
Thank you for raising this flaw in our documents, sorry for the confusing, I will report that to the development team for improvement, Thank you again for pointing that out.
Just for the benefit of other who might be looking for a solution like i was.
- fortios_firewall_securitypolicy_sort doesn't support manual_order attribute, for that fortios_firewall_policy_sort should be used.
- fortios_firewall_policy_sort is available starting from provider version 1.18.0
- documentation completely oblivious to existence of fortios_firewall_policy_sort resource.