COMPONENT NAME
bigip_virtual_server.py
Environment
ANSIBLE VERSION
BIGIP VERSION
CONFIGURATION
N/A
OS / ENVIRONMENT
N/A
SUMMARY
STEPS TO REPRODUCE
I create a VS with metadata being a var (dictionary)
- name: set fact vs_metadata
set_fact:
vs_metadata:
run_caller: "{{ run_caller }}"
application: "{{ application | regex_replace('^[A-Z-]+_(.*)$', '\\1') }}"
- name: set fact vs_metadata - add conditionally httpver=2 (when http2_enabled)
set_fact:
vs_metadata: "{{ vs_metadata | combine({ 'httpver': '2' }) }}"
when: http2_enabled
- name: Add VS "{{ application }}_vs" - with config map
bigip_virtual_server:
provider: "{{ provider }}"
state: present
partition: Common
name: "{{ application }}_vs"
description: "{{ scope + ', ' + source_allowlist }}"
metadata: "{{ vs_metadata }}"
destination: "{{ int_vs_ip }}"
port: '443'
pool: "{{ application }}_pool"
snat: "{{ snat_pool_default }}"
profiles: "{{ vs_config_map['profiles'] }}"
policies: "{{ vs_config_map['policies'] | default([]) }}"
security_log_profiles: "{{ vs_config_map['security_log_profiles'] }}"
irules: "{{ (irules_list is defined and irules_list | length>0) | ternary(vs_config_map['irules'], []) }}"
check_profiles: no
default_persistence_profile: "{% if lb_mode is defined and lb_mode == 'lb' and ( pool_members_aggregate_list | length ) > 1 %}default_cookie_insert_persistence{% else %}{% endif %}"
delegate_to: localhost
EXPECTED RESULTS
At every playbook run, the metadata should be set as defined in the task, consistently.
ACTUAL RESULTS
Looking in the /var/log/audit file of the target BIG-IP I can see that in every 1 of 2 runs the metadata is not set.
1st run:
notice icrd_child[10785]: 01420002:5: AUDIT - pid=10785 user=XXXXX folder=/Common module=(tmos)# status=[Command OK] cmd_data=modify ltm virtual /Common/example.com_vs { metadata replace-all-with { run_caller { value managedservices } application { value example.com } httpver { value 2 } f5-ansible.version { value 2.16.9 persist true } f5-ansible.last_modified { value "2026-01-18 11:06:14.545560" persist true } } profiles replace-all-with { /Common/http { context all } /Common/websecurity { context all } /Common/default_serverssl { context serverside } /Common/internal_clientssl { context clientside } /Common/default_http2 { context all } /Common/httprouter { context all } } }
2nd run (re-run):
notice icrd_child[10785]: 01420002:5: AUDIT - pid=10785 user=XXXXX folder=/Common module=(tmos)# status=[Command OK] cmd_data=modify ltm virtual /Common/example.com_vs { profiles replace-all-with { /Common/http { context all } /Common/websecurity { context all } /Common/default_serverssl { context serverside } /Common/internal_clientssl { context clientside } /Common/default_http2 { context all } /Common/httprouter { context all } } metadata replace-all-with { f5-ansible.version { value 2.16.9 persist true } f5-ansible.last_modified { value "2026-01-18 11:07:54.975015" persist true } } }
3rd run will set it as 1st run, 4th as 2nd and so on.
The Bug is in this part of the code:
|
result = self._diff_complex_items(self.want.metadata, self.have.metadata) |
which calls that function (L3191 condition is the issue):
|
def _diff_complex_items(self, want, have): |
|
if want == [] and have is None: |
|
return None |
|
if want is None: |
|
return None |
|
w = self.to_tuple(want) |
|
h = self.to_tuple(have) |
|
if set(w).issubset(set(h)): |
|
return None |
|
else: |
|
return want |
Haven't digged that much into it but replacing L3453 with the following seems to fix it:
result = self.want.metadata
COMPONENT NAME
bigip_virtual_server.py
Environment
ANSIBLE VERSION
BIGIP VERSION
CONFIGURATION
N/A
OS / ENVIRONMENT
N/A
SUMMARY
STEPS TO REPRODUCE
I create a VS with metadata being a var (dictionary)
EXPECTED RESULTS
At every playbook run, the metadata should be set as defined in the task, consistently.
ACTUAL RESULTS
Looking in the /var/log/audit file of the target BIG-IP I can see that in every 1 of 2 runs the metadata is not set.
1st run:
2nd run (re-run):
3rd run will set it as 1st run, 4th as 2nd and so on.
The Bug is in this part of the code:
f5-ansible/ansible_collections/f5networks/f5_modules/plugins/modules/bigip_virtual_server.py
Line 3453 in 8eae545
which calls that function (L3191 condition is the issue):
f5-ansible/ansible_collections/f5networks/f5_modules/plugins/modules/bigip_virtual_server.py
Lines 3184 to 3194 in 8eae545
Haven't digged that much into it but replacing L3453 with the following seems to fix it: