-
Notifications
You must be signed in to change notification settings - Fork 98
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[minor change] Add support for annotation in aci_rest module (#437)
- Loading branch information
Showing
1 changed file
with
33 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
|
||
# Copyright: (c) 2017, Dag Wieers (@dagwieers) <[email protected]> | ||
# Copyright: (c) 2020, Cindy Zhao (@cizhao) <[email protected]> | ||
# Copyright: (c) 2023, Samita Bhattacharjee (@samitab) <[email protected]> | ||
# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
|
||
from __future__ import absolute_import, division, print_function | ||
|
@@ -62,6 +63,7 @@ | |
default: false | ||
extends_documentation_fragment: | ||
- cisco.aci.aci | ||
- cisco.aci.annotation | ||
notes: | ||
- Certain payloads are known not to be idempotent, so be careful when constructing payloads, | ||
|
@@ -73,6 +75,7 @@ | |
- XML payloads require the C(lxml) and C(xmljson) python libraries. For JSON payloads nothing special is needed. | ||
- If you do not have any attributes, it may be necessary to add the "attributes" key with an empty dictionnary "{}" for value | ||
as the APIC does expect the entry to precede any children. | ||
- Annotation set directly in c(src) or C(content) will take precedent over the C(annotation) parameter. | ||
seealso: | ||
- module: cisco.aci.aci_tenant | ||
- name: Cisco APIC REST API Configuration Guide | ||
|
@@ -81,6 +84,7 @@ | |
author: | ||
- Dag Wieers (@dagwieers) | ||
- Cindy Zhao (@cizhao) | ||
- Samita Bhattacharjee (@samitab) | ||
""" | ||
|
||
EXAMPLES = r""" | ||
|
@@ -284,7 +288,7 @@ | |
HAS_YAML = False | ||
|
||
from ansible.module_utils.basic import AnsibleModule | ||
from ansible_collections.cisco.aci.plugins.module_utils.aci import ACIModule, aci_argument_spec | ||
from ansible_collections.cisco.aci.plugins.module_utils.aci import ACIModule, aci_argument_spec, aci_annotation_spec | ||
from ansible.module_utils._text import to_text | ||
|
||
|
||
|
@@ -303,6 +307,24 @@ def update_qsl(url, params): | |
return url + "?" + "&".join(["%s=%s" % (k, v) for k, v in params.items()]) | ||
|
||
|
||
def add_annotation(annotation, payload): | ||
"""Add annotation to payload only if it has not already been added""" | ||
if annotation: | ||
for val in payload.values(): | ||
att = val.get("attributes", {}) | ||
if "annotation" not in att.keys(): | ||
att["annotation"] = annotation | ||
|
||
|
||
def add_annotation_xml(annotation, tree): | ||
"""Add annotation to payload xml only if it has not already been added""" | ||
if annotation: | ||
for element in tree.iter(): | ||
ann = element.get("annotation") | ||
if ann is None: | ||
element.set("annotation", annotation) | ||
|
||
|
||
class ACIRESTModule(ACIModule): | ||
def changed(self, d): | ||
"""Check ACI response for changes""" | ||
|
@@ -335,6 +357,7 @@ def response_type(self, rawoutput, rest_type="xml"): | |
|
||
def main(): | ||
argument_spec = aci_argument_spec() | ||
argument_spec.update(aci_annotation_spec()) | ||
argument_spec.update( | ||
path=dict(type="str", required=True, aliases=["uri"]), | ||
method=dict(type="str", default="get", choices=["delete", "get", "post"], aliases=["action"]), | ||
|
@@ -353,6 +376,7 @@ def main(): | |
path = module.params.get("path") | ||
src = module.params.get("src") | ||
rsp_subtree_preserve = module.params.get("rsp_subtree_preserve") | ||
annotation = module.params.get("annotation") | ||
|
||
# Report missing file | ||
file_exists = False | ||
|
@@ -388,21 +412,27 @@ def main(): | |
if rest_type == "json": | ||
if content and isinstance(content, dict): | ||
# Validate inline YAML/JSON | ||
add_annotation(annotation, payload) | ||
payload = json.dumps(payload) | ||
elif payload and isinstance(payload, str) and HAS_YAML: | ||
try: | ||
# Validate YAML/JSON string | ||
payload = json.dumps(yaml.safe_load(payload)) | ||
payload = yaml.safe_load(payload) | ||
add_annotation(annotation, payload) | ||
payload = json.dumps(payload) | ||
except Exception as e: | ||
module.fail_json(msg="Failed to parse provided JSON/YAML payload: {0}".format(to_text(e)), exception=to_text(e), payload=payload) | ||
elif rest_type == "xml" and HAS_LXML_ETREE: | ||
if content and isinstance(content, dict) and HAS_XMLJSON_COBRA: | ||
# Validate inline YAML/JSON | ||
add_annotation(annotation, payload) | ||
payload = etree.tostring(cobra.etree(payload)[0], encoding="unicode") | ||
elif payload and isinstance(payload, str): | ||
try: | ||
# Validate XML string | ||
payload = etree.tostring(etree.fromstring(payload), encoding="unicode") | ||
payload = etree.fromstring(payload) | ||
add_annotation_xml(annotation, payload) | ||
payload = etree.tostring(payload, encoding="unicode") | ||
except Exception as e: | ||
module.fail_json(msg="Failed to parse provided XML payload: {0}".format(to_text(e)), payload=payload) | ||
|
||
|