diff --git a/plugins/modules/aci_rest.py b/plugins/modules/aci_rest.py
index 2029330de..43986592a 100644
--- a/plugins/modules/aci_rest.py
+++ b/plugins/modules/aci_rest.py
@@ -312,13 +312,18 @@ def update_qsl(url, params):
def add_annotation(annotation, payload):
"""Add annotation to payload only if it has not already been added"""
- if annotation:
+ if annotation and isinstance(payload, dict):
for key, val in payload.items():
if key in ANNOTATION_UNSUPPORTED:
- return
+ continue
att = val.get("attributes", {})
if "annotation" not in att.keys():
att["annotation"] = annotation
+ # Recursively add annotation to children
+ children = val.get("children", None)
+ if children:
+ for child in children:
+ add_annotation(annotation, child)
def add_annotation_xml(annotation, tree):
@@ -326,7 +331,7 @@ def add_annotation_xml(annotation, tree):
if annotation:
for element in tree.iter():
if element.tag in ANNOTATION_UNSUPPORTED:
- return
+ continue
ann = element.get("annotation")
if ann is None:
element.set("annotation", annotation)
diff --git a/tests/integration/targets/aci_rest/tasks/json_inline.yml b/tests/integration/targets/aci_rest/tasks/json_inline.yml
index 0260d588e..854950af6 100644
--- a/tests/integration/targets/aci_rest/tasks/json_inline.yml
+++ b/tests/integration/targets/aci_rest/tasks/json_inline.yml
@@ -275,10 +275,66 @@
}
register: nm_add_tag_no_annotation
+- name: Remove tenant
+ cisco.aci.aci_rest: *tenant_absent
+
+- name: Add tenant with children objects including annotation
+ cisco.aci.aci_rest:
+ host: '{{ aci_hostname }}'
+ username: '{{ aci_username }}'
+ password: '{{ aci_password }}'
+ validate_certs: '{{ aci_validate_certs | default(false) }}'
+ use_ssl: '{{ aci_use_ssl | default(true) }}'
+ use_proxy: '{{ aci_use_proxy | default(true) }}'
+ output_level: '{{ aci_output_level | default("info") }}'
+ path: /api/mo/uni.json
+ method: post
+ annotation: test:inoption
+ content:
+ {
+ "fvTenant": {
+ "attributes": {
+ "descr": "Ansible test tenant",
+ "name": "ansible_test"
+ },
+ "children": [
+ {
+ "fvCtx": {
+ "attributes": {
+ "name": "VRF1"
+ }
+ }
+ },
+ {
+ "fvAp": {
+ "attributes": {
+ "name": "Application1"
+ },
+ "children": [
+ {
+ "fvAEPg": {
+ "attributes": {
+ "name": "WebTier",
+ "annotation": "test:inchild"
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+ register: nm_add_tenant_annotation_children
+
- name: Verify annotation support
assert:
that:
- nm_add_tenant_annotation_option.imdata.0.fvTenant.attributes.annotation == "test:inoption"
- nm_add_tenant_annotation_content.imdata.0.fvTenant.attributes.annotation == "test:incontent"
- nm_add_tenant_annotation_option_content.imdata.0.fvTenant.attributes.annotation == "test:optionincontent"
- - nm_add_tag_no_annotation.imdata.0.tagTag.attributes.annotation is undefined
\ No newline at end of file
+ - nm_add_tag_no_annotation.imdata.0.tagTag.attributes.annotation is undefined
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.attributes.annotation == "test:inoption"
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.children.0.fvAp.attributes.annotation == "test:inoption"
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.children.0.fvAp.children.0.fvAEPg.attributes.annotation == "test:inchild"
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.children.2.fvCtx.attributes.annotation == "test:inoption"
\ No newline at end of file
diff --git a/tests/integration/targets/aci_rest/tasks/json_string.yml b/tests/integration/targets/aci_rest/tasks/json_string.yml
index 23e9900fe..2135c0219 100644
--- a/tests/integration/targets/aci_rest/tasks/json_string.yml
+++ b/tests/integration/targets/aci_rest/tasks/json_string.yml
@@ -263,7 +263,7 @@
use_ssl: '{{ aci_use_ssl | default(true) }}'
use_proxy: '{{ aci_use_proxy | default(true) }}'
output_level: '{{ aci_output_level | default("info") }}'
- path: /api/mo/uni/tn-ansible_test_annotation1/tagKey-foo.json
+ path: /api/mo/uni/tn-ansible_test/tagKey-foo.json
method: post
annotation: test:inoption
content: |
@@ -276,10 +276,66 @@
}
register: nm_add_tag_no_annotation
+- name: Remove tenant
+ cisco.aci.aci_rest: *tenant_absent
+
+- name: Add tenant with children objects including annotation
+ cisco.aci.aci_rest:
+ host: '{{ aci_hostname }}'
+ username: '{{ aci_username }}'
+ password: '{{ aci_password }}'
+ validate_certs: '{{ aci_validate_certs | default(false) }}'
+ use_ssl: '{{ aci_use_ssl | default(true) }}'
+ use_proxy: '{{ aci_use_proxy | default(true) }}'
+ output_level: '{{ aci_output_level | default("info") }}'
+ path: /api/mo/uni.json
+ method: post
+ annotation: test:inoption
+ content: |
+ {
+ "fvTenant": {
+ "attributes": {
+ "descr": "Ansible test tenant",
+ "name": "ansible_test"
+ },
+ "children": [
+ {
+ "fvCtx": {
+ "attributes": {
+ "name": "VRF1"
+ }
+ }
+ },
+ {
+ "fvAp": {
+ "attributes": {
+ "name": "Application1"
+ },
+ "children": [
+ {
+ "fvAEPg": {
+ "attributes": {
+ "name": "WebTier",
+ "annotation": "test:inchild"
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+ register: nm_add_tenant_annotation_children
+
- name: Verify annotation support
assert:
that:
- nm_add_tenant_annotation_option.imdata.0.fvTenant.attributes.annotation == "test:inoption"
- nm_add_tenant_annotation_content.imdata.0.fvTenant.attributes.annotation == "test:incontent"
- nm_add_tenant_annotation_option_content.imdata.0.fvTenant.attributes.annotation == "test:optionincontent"
- - nm_add_tag_no_annotation.imdata.0.tagTag.attributes.annotation is undefined
\ No newline at end of file
+ - nm_add_tag_no_annotation.imdata.0.tagTag.attributes.annotation is undefined
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.attributes.annotation == "test:inoption"
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.children.0.fvAp.attributes.annotation == "test:inoption"
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.children.0.fvAp.children.0.fvAEPg.attributes.annotation == "test:inchild"
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.children.2.fvCtx.attributes.annotation == "test:inoption"
\ No newline at end of file
diff --git a/tests/integration/targets/aci_rest/tasks/xml_file.yml b/tests/integration/targets/aci_rest/tasks/xml_file.yml
index 52b67fc7c..0da42b009 100644
--- a/tests/integration/targets/aci_rest/tasks/xml_file.yml
+++ b/tests/integration/targets/aci_rest/tasks/xml_file.yml
@@ -17,7 +17,7 @@
output_path: "/tmp/ansible_output_file.log"
- name: Ensure tenant does not exists using ans_test_delete xml template
- cisco.aci.aci_rest:
+ cisco.aci.aci_rest: &tenant_delete
<<: *aci_info
path: /api/mo/uni.xml
src: "./targets/aci_rest/tasks/xml_files/tn-ans_test_delete.xml"
@@ -260,6 +260,9 @@
src: "./targets/aci_rest/tasks/xml_files/tn-ans_test_annotation.xml"
register: nm_add_tenant_annotation_content
+- name: Remove tenant
+ cisco.aci.aci_rest: *tenant_delete
+
- name: Add tenant with annotation in content and option
cisco.aci.aci_rest:
host: '{{ aci_hostname }}'
@@ -290,10 +293,32 @@
src: "./targets/aci_rest/tasks/xml_files/tag.xml"
register: nm_add_tag_no_annotation
+- name: Remove tenant
+ cisco.aci.aci_rest: *tenant_delete
+
+- name: Add tenant with children objects including annotation
+ cisco.aci.aci_rest:
+ host: '{{ aci_hostname }}'
+ username: '{{ aci_username }}'
+ password: '{{ aci_password }}'
+ validate_certs: '{{ aci_validate_certs | default(false) }}'
+ use_ssl: '{{ aci_use_ssl | default(true) }}'
+ use_proxy: '{{ aci_use_proxy | default(true) }}'
+ output_level: '{{ aci_output_level | default("info") }}'
+ path: /api/mo/uni.xml
+ method: post
+ annotation: test:inoption
+ src: "./targets/aci_rest/tasks/xml_files/tn-ans_test_annotation_children.xml"
+ register: nm_add_tenant_annotation_children
+
- name: Verify annotation support
assert:
that:
- nm_add_tenant_annotation_option.imdata.0.fvTenant.attributes.annotation == "test:inoption"
- - nm_add_tenant_annotation_content.imdata.0.fvTenant.attributes.annotation == "test:incontent"
+ - nm_add_tenant_annotation_content.imdata.0.fvTenant.attributes.annotation == "test:optionincontent"
- nm_add_tenant_annotation_option_content.imdata.0.fvTenant.attributes.annotation == "test:optionincontent"
- - nm_add_tag_no_annotation.imdata.0.tagTag.attributes.annotation is undefined
\ No newline at end of file
+ - nm_add_tag_no_annotation.imdata.0.tagTag.attributes.annotation is undefined
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.attributes.annotation == "test:inoption"
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.children.0.fvAp.attributes.annotation == "test:inoption"
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.children.0.fvAp.children.0.fvAEPg.attributes.annotation == "test:inchild"
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.children.1.fvCtx.attributes.annotation == "test:inoption"
\ No newline at end of file
diff --git a/tests/integration/targets/aci_rest/tasks/xml_files/tn-ans_test_annotation_children.xml b/tests/integration/targets/aci_rest/tasks/xml_files/tn-ans_test_annotation_children.xml
new file mode 100644
index 000000000..448998bf6
--- /dev/null
+++ b/tests/integration/targets/aci_rest/tasks/xml_files/tn-ans_test_annotation_children.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/integration/targets/aci_rest/tasks/xml_string.yml b/tests/integration/targets/aci_rest/tasks/xml_string.yml
index d4a4304bc..34e43abb7 100644
--- a/tests/integration/targets/aci_rest/tasks/xml_string.yml
+++ b/tests/integration/targets/aci_rest/tasks/xml_string.yml
@@ -259,7 +259,7 @@
method: post
annotation: test:inoption
content:
-
+
register: nm_add_tenant_annotation_option
- name: Add tenant with annotation in content
@@ -274,7 +274,7 @@
path: /api/mo/uni.xml
method: post
content:
-
+
register: nm_add_tenant_annotation_content
- name: Add tenant with annotation in content and option
@@ -290,7 +290,7 @@
method: post
annotation: test:inoption
content:
-
+
register: nm_add_tenant_annotation_option_content
- name: Add tag to tenant with annotation unsupported
@@ -302,17 +302,45 @@
use_ssl: '{{ aci_use_ssl | default(true) }}'
use_proxy: '{{ aci_use_proxy | default(true) }}'
output_level: '{{ aci_output_level | default("info") }}'
- path: /api/mo/uni/tn-ansible_test/tagKey-foo.json
+ path: /api/mo/uni/tn-ansible_test/tagKey-foo.xml
method: post
annotation: test:inoption
content:
register: nm_add_tag_no_annotation
+- name: Remove tenant
+ cisco.aci.aci_rest: *tenant_absent
+
+- name: Add tenant with children objects including annotation
+ cisco.aci.aci_rest:
+ host: '{{ aci_hostname }}'
+ username: '{{ aci_username }}'
+ password: '{{ aci_password }}'
+ validate_certs: '{{ aci_validate_certs | default(false) }}'
+ use_ssl: '{{ aci_use_ssl | default(true) }}'
+ use_proxy: '{{ aci_use_proxy | default(true) }}'
+ output_level: '{{ aci_output_level | default("info") }}'
+ path: /api/mo/uni.xml
+ method: post
+ annotation: test:inoption
+ content:
+
+
+
+
+
+
+ register: nm_add_tenant_annotation_children
+
- name: Verify annotation support
assert:
that:
- nm_add_tenant_annotation_option.imdata.0.fvTenant.attributes.annotation == "test:inoption"
- nm_add_tenant_annotation_content.imdata.0.fvTenant.attributes.annotation == "test:incontent"
- nm_add_tenant_annotation_option_content.imdata.0.fvTenant.attributes.annotation == "test:optionincontent"
- - nm_add_tag_no_annotation.imdata.0.tagTag.attributes.annotation is undefined
\ No newline at end of file
+ - nm_add_tag_no_annotation.imdata.0.tagTag.attributes.annotation is undefined
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.attributes.annotation == "test:inoption"
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.children.0.fvAp.attributes.annotation == "test:inoption"
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.children.0.fvAp.children.0.fvAEPg.attributes.annotation == "test:inchild"
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.children.1.fvCtx.attributes.annotation == "test:inoption"
\ No newline at end of file
diff --git a/tests/integration/targets/aci_rest/tasks/yaml_inline.yml b/tests/integration/targets/aci_rest/tasks/yaml_inline.yml
index 50549aa7c..8f4bbef04 100644
--- a/tests/integration/targets/aci_rest/tasks/yaml_inline.yml
+++ b/tests/integration/targets/aci_rest/tasks/yaml_inline.yml
@@ -251,6 +251,40 @@
value: bar
register: nm_add_tag_no_annotation
+- name: Remove tenant
+ cisco.aci.aci_rest: *tenant_absent
+
+- name: Add tenant with children objects including annotation
+ cisco.aci.aci_rest:
+ host: '{{ aci_hostname }}'
+ username: '{{ aci_username }}'
+ password: '{{ aci_password }}'
+ validate_certs: '{{ aci_validate_certs | default(false) }}'
+ use_ssl: '{{ aci_use_ssl | default(true) }}'
+ use_proxy: '{{ aci_use_proxy | default(true) }}'
+ output_level: '{{ aci_output_level | default("info") }}'
+ path: /api/mo/uni.json
+ method: post
+ annotation: test:inoption
+ content:
+ fvTenant:
+ attributes:
+ descr: Ansible test tenant
+ name: ansible_test
+ children:
+ - fvCtx:
+ attributes:
+ name: VRF1
+ - fvAp:
+ attributes:
+ name: Application1
+ children:
+ - fvAEPg:
+ attributes:
+ name: WebTier
+ annotation: test:inchild
+ register: nm_add_tenant_annotation_children
+
- name: Verify annotation support
assert:
that:
@@ -258,3 +292,7 @@
- nm_add_tenant_annotation_content.imdata.0.fvTenant.attributes.annotation == "test:incontent"
- nm_add_tenant_annotation_option_content.imdata.0.fvTenant.attributes.annotation == "test:optionincontent"
- nm_add_tag_no_annotation.imdata.0.tagTag.attributes.annotation is undefined
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.attributes.annotation == "test:inoption"
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.children.0.fvAp.attributes.annotation == "test:inoption"
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.children.0.fvAp.children.0.fvAEPg.attributes.annotation == "test:inchild"
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.children.2.fvCtx.attributes.annotation == "test:inoption"
diff --git a/tests/integration/targets/aci_rest/tasks/yaml_string.yml b/tests/integration/targets/aci_rest/tasks/yaml_string.yml
index beb1fad54..f1b6c847b 100644
--- a/tests/integration/targets/aci_rest/tasks/yaml_string.yml
+++ b/tests/integration/targets/aci_rest/tasks/yaml_string.yml
@@ -251,10 +251,48 @@
value: bar
register: nm_add_tag_no_annotation
+- name: Remove tenant
+ cisco.aci.aci_rest: *tenant_absent
+
+- name: Add tenant with children objects including annotation
+ cisco.aci.aci_rest:
+ host: '{{ aci_hostname }}'
+ username: '{{ aci_username }}'
+ password: '{{ aci_password }}'
+ validate_certs: '{{ aci_validate_certs | default(false) }}'
+ use_ssl: '{{ aci_use_ssl | default(true) }}'
+ use_proxy: '{{ aci_use_proxy | default(true) }}'
+ output_level: '{{ aci_output_level | default("info") }}'
+ path: /api/mo/uni.json
+ method: post
+ annotation: test:inoption
+ content: |
+ fvTenant:
+ attributes:
+ descr: Ansible test tenant
+ name: ansible_test
+ children:
+ - fvCtx:
+ attributes:
+ name: VRF1
+ - fvAp:
+ attributes:
+ name: Application1
+ children:
+ - fvAEPg:
+ attributes:
+ name: WebTier
+ annotation: test:inchild
+ register: nm_add_tenant_annotation_children
+
- name: Verify annotation support
assert:
that:
- nm_add_tenant_annotation_option.imdata.0.fvTenant.attributes.annotation == "test:inoption"
- nm_add_tenant_annotation_content.imdata.0.fvTenant.attributes.annotation == "test:incontent"
- nm_add_tenant_annotation_option_content.imdata.0.fvTenant.attributes.annotation == "test:optionincontent"
- - nm_add_tag_no_annotation.imdata.0.tagTag.attributes.annotation is undefined
\ No newline at end of file
+ - nm_add_tag_no_annotation.imdata.0.tagTag.attributes.annotation is undefined
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.attributes.annotation == "test:inoption"
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.children.0.fvAp.attributes.annotation == "test:inoption"
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.children.0.fvAp.children.0.fvAEPg.attributes.annotation == "test:inchild"
+ - nm_add_tenant_annotation_children.imdata.0.fvTenant.children.2.fvCtx.attributes.annotation == "test:inoption"
\ No newline at end of file