From f06d9080eb94950b9b90973b31efa03f50a6e06e Mon Sep 17 00:00:00 2001
From: = <=>
Date: Wed, 6 Aug 2025 20:13:11 +0530
Subject: [PATCH 1/2] Add support for body-data encoding type
'x-www-form-urlencoded'
---
docs/cisco.dcnm.dcnm_rest_module.rst | 21 ++++++++++++++++
plugins/httpapi/dcnm.py | 5 ++++
plugins/module_utils/network/dcnm/dcnm.py | 2 ++
plugins/modules/dcnm_rest.py | 30 ++++++++++++++++++++---
4 files changed, 55 insertions(+), 3 deletions(-)
diff --git a/docs/cisco.dcnm.dcnm_rest_module.rst b/docs/cisco.dcnm.dcnm_rest_module.rst
index cf392f941..a0cd16b62 100644
--- a/docs/cisco.dcnm.dcnm_rest_module.rst
+++ b/docs/cisco.dcnm.dcnm_rest_module.rst
@@ -87,6 +87,21 @@ Parameters
REST API Path Endpoint
+
+
+
+ urlencoded_data
+
+
+ raw
+
+ |
+
+ |
+
+ Dictionary data to be url-encoded for x-www-form-urlencoded type REST API call
+ |
+
@@ -115,6 +130,12 @@ Examples
path: /rest/top-down/fabrics/fabric1/vrfs/attachments
json_data: '[{"vrfName":"sales66_vrf1","lanAttachList":[{"fabric":"fabric1","vrfName":"sales66_vrf1","serialNumber":"FDO21392QKM","vlan":2000,"freeformConfig":"","deployment":false,"extensionValues":"","instanceValues":"{"loopbackId":"","loopbackIpAddress":"","loopbackIpV6Address":""}"}]}]'
+ - name: Save Robot Credentials - (urlencoded)
+ dcnm_rest:
+ method: POST
+ path: /rest/lanConfig/saveRobotCredentials
+ urlencoded_data: '{"password": "password", "username": "admin"}'
+
# Read payload data from file and validate a template
- set_fact:
data: "{{ lookup('file', 'validate_payload') }}"
diff --git a/plugins/httpapi/dcnm.py b/plugins/httpapi/dcnm.py
index e0b702795..be4c9e633 100644
--- a/plugins/httpapi/dcnm.py
+++ b/plugins/httpapi/dcnm.py
@@ -66,6 +66,7 @@ class HttpApi(HttpApiBase):
def __init__(self, *args, **kwargs):
super(HttpApi, self).__init__(*args, **kwargs)
self.headers = {"Content-Type": "application/json"}
+ self.urlencoded_headers = {"Content-Type": "application/x-www-form-urlencoded"}
self.txt_headers = {"Content-Type": "text/plain"}
self.version = None
self.retrycount = DEFAULT_RETRY_COUNT
@@ -252,6 +253,10 @@ def send_request(self, method, path, json=None):
"""This method handles all DCNM REST API requests other than login"""
return self._send_request_internal(method, path, json or {}, self.headers)
+ def send_urlencoded_request(self, method, path, urlencoded=None):
+ """This method handles all DCNM REST API urlencoded requests other than login"""
+ return self._send_request_internal(method, path, urlencoded or {}, self.urlencoded_headers)
+
def send_txt_request(self, method, path, txt=None):
"""This method handles all DCNM REST API text requests other than login"""
return self._send_request_internal(method, path, txt or "", self.txt_headers)
diff --git a/plugins/module_utils/network/dcnm/dcnm.py b/plugins/module_utils/network/dcnm/dcnm.py
index 272c1664e..30234d1e4 100644
--- a/plugins/module_utils/network/dcnm/dcnm.py
+++ b/plugins/module_utils/network/dcnm/dcnm.py
@@ -500,6 +500,8 @@ def dcnm_send(module, method, path, data=None, data_type="json"):
if data_type == "json":
return conn.send_request(method, path, data)
+ elif data_type == "urlencoded":
+ return conn.send_urlencoded_request(method, path, data)
elif data_type == "text":
return conn.send_txt_request(method, path, data)
diff --git a/plugins/modules/dcnm_rest.py b/plugins/modules/dcnm_rest.py
index 103109c70..6d4b640b1 100644
--- a/plugins/modules/dcnm_rest.py
+++ b/plugins/modules/dcnm_rest.py
@@ -44,6 +44,11 @@
- json_data
required: no
type: raw
+ urlencoded_data:
+ description:
+ - 'Dictionary data to be url-encoded for x-www-form-urlencoded type REST API call'
+ required: no
+ type: raw
author:
- Mike Wiebe (@mikewiebe)
"""
@@ -66,6 +71,12 @@
path: /rest/top-down/fabrics/fabric1/vrfs/attachments
json_data: '[{"vrfName":"sales66_vrf1","lanAttachList":[{"fabric":"fabric1","vrfName":"sales66_vrf1","serialNumber":"FDO21392QKM","vlan":2000,"freeformConfig":"","deployment":false,"extensionValues":"","instanceValues":"{\"loopbackId\":\"\",\"loopbackIpAddress\":\"\",\"loopbackIpV6Address\":\"\"}"}]}]'
+- name: Save Robot Credentials - (urlencoded)
+ dcnm_rest:
+ method: POST
+ path: /rest/lanConfig/saveRobotCredentials
+ urlencoded_data: '{"password": "password", "username": "admin"}'
+
# Read payload data from file and validate a template
- set_fact:
data: "{{ lookup('file', 'validate_payload') }}"
@@ -89,6 +100,7 @@
"""
import json
+import urllib.parse
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.cisco.dcnm.plugins.module_utils.network.dcnm.dcnm import (
dcnm_send,
@@ -101,6 +113,7 @@ def main():
method=dict(required=True, choices=["GET", "POST", "PUT", "DELETE"]),
path=dict(required=True, type="str"),
data=dict(type="raw", required=False, default=None, aliases=["json_data"]),
+ urlencoded_data = dict(type="raw", required=False, default=None),
)
# seed the result dict
@@ -110,17 +123,28 @@ def main():
method = module.params["method"]
path = module.params["path"]
- for key in ["json_data", "data"]:
+ is_urlencoded = False
+
+ for key in ["json_data", "data", "urlencoded_data"]:
data = module.params.get(key)
if data is not None:
+ if key == "urlencoded_data":
+ is_urlencoded = True
break
if data is None:
data = "{}"
# Determine if this is valid JSON or not
try:
- json.loads(data)
- result["response"] = dcnm_send(module, method, path, data)
+ json_data = json.loads(data)
+ if is_urlencoded:
+ # If the data is valid JSON but marked as urlencoded, we need to convert it
+ # to a URL-encoded string before sending it.
+ urlencoded_data = urllib.parse.urlencode(json_data)
+ result["response"] = dcnm_send(module, method, path, urlencoded_data, "urlencoded")
+ else:
+ # If the data is valid JSON, send it as a JSON string
+ result["response"] = dcnm_send(module, method, path, data)
except json.JSONDecodeError:
# Resend data as text since it's not valid JSON
result["response"] = dcnm_send(module, method, path, data, "text")
From 499dd4a2d74bd6da0a2fe1a9e2306daa931bfade Mon Sep 17 00:00:00 2001
From: = <=>
Date: Wed, 6 Aug 2025 22:07:57 +0530
Subject: [PATCH 2/2] Fix Pep8 Error
---
plugins/modules/dcnm_rest.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/modules/dcnm_rest.py b/plugins/modules/dcnm_rest.py
index 6d4b640b1..d1895f4de 100644
--- a/plugins/modules/dcnm_rest.py
+++ b/plugins/modules/dcnm_rest.py
@@ -113,7 +113,7 @@ def main():
method=dict(required=True, choices=["GET", "POST", "PUT", "DELETE"]),
path=dict(required=True, type="str"),
data=dict(type="raw", required=False, default=None, aliases=["json_data"]),
- urlencoded_data = dict(type="raw", required=False, default=None),
+ urlencoded_data=dict(type="raw", required=False, default=None),
)
# seed the result dict