|
|
|
@ -70,7 +70,22 @@ EXAMPLES = r'''
|
|
|
|
|
src: /home/cisco/ansible/aci/configs/aci_config.xml
|
|
|
|
|
delegate_to: localhost
|
|
|
|
|
|
|
|
|
|
- name: Add a tenant
|
|
|
|
|
- name: Add a tenant using inline YAML
|
|
|
|
|
aci_rest:
|
|
|
|
|
hostname: '{{ inventory_hostname }}'
|
|
|
|
|
username: '{{ aci_username }}'
|
|
|
|
|
password: '{{ aci_password }}'
|
|
|
|
|
validate_certs: no
|
|
|
|
|
path: /api/mo/uni/tn-[Sales].json
|
|
|
|
|
method: post
|
|
|
|
|
content:
|
|
|
|
|
fvTenant:
|
|
|
|
|
attributes:
|
|
|
|
|
name: Sales
|
|
|
|
|
descr: Sales departement
|
|
|
|
|
delegate_to: localhost
|
|
|
|
|
|
|
|
|
|
- name: Add a tenant using a JSON string
|
|
|
|
|
aci_rest:
|
|
|
|
|
hostname: '{{ inventory_hostname }}'
|
|
|
|
|
username: '{{ aci_username }}'
|
|
|
|
@ -89,6 +104,18 @@ EXAMPLES = r'''
|
|
|
|
|
}
|
|
|
|
|
delegate_to: localhost
|
|
|
|
|
|
|
|
|
|
- name: Add a tenant using an XML string
|
|
|
|
|
aci_rest:
|
|
|
|
|
hostname: '{{ inventory_hostname }}'
|
|
|
|
|
username: '{{ aci_username }}'
|
|
|
|
|
password: '{{ aci_password }}'
|
|
|
|
|
validate_certs: no
|
|
|
|
|
path: /api/mo/uni/tn-[Sales].xml
|
|
|
|
|
method: post
|
|
|
|
|
content: |
|
|
|
|
|
<fvTenant name="Sales" descr="Sales departement"/>
|
|
|
|
|
delegate_to: localhost
|
|
|
|
|
|
|
|
|
|
- name: Get tenants
|
|
|
|
|
aci_rest:
|
|
|
|
|
hostname: '{{ inventory_hostname }}'
|
|
|
|
@ -187,6 +214,7 @@ url:
|
|
|
|
|
sample: https://1.2.3.4/api/mo/uni/tn-[Dag].json?rsp-subtree=modified
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
import json
|
|
|
|
|
import os
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
@ -211,9 +239,17 @@ try:
|
|
|
|
|
except ImportError:
|
|
|
|
|
HAS_XMLJSON_COBRA = False
|
|
|
|
|
|
|
|
|
|
# Optional, only used for YAML validation
|
|
|
|
|
try:
|
|
|
|
|
import yaml
|
|
|
|
|
HAS_YAML = True
|
|
|
|
|
except:
|
|
|
|
|
HAS_YAML = False
|
|
|
|
|
|
|
|
|
|
from ansible.module_utils.aci import ACIModule, aci_argument_spec, aci_response_json, aci_response_xml
|
|
|
|
|
from ansible.module_utils.basic import AnsibleModule
|
|
|
|
|
from ansible.module_utils.urls import fetch_url
|
|
|
|
|
from ansible.module_utils._text import to_text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def update_qsl(url, params):
|
|
|
|
@ -267,7 +303,7 @@ def main():
|
|
|
|
|
path=dict(type='str', required=True, aliases=['uri']),
|
|
|
|
|
method=dict(type='str', default='get', choices=['delete', 'get', 'post'], aliases=['action']),
|
|
|
|
|
src=dict(type='path', aliases=['config_file']),
|
|
|
|
|
content=dict(type='str'),
|
|
|
|
|
content=dict(type='raw'),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
module = AnsibleModule(
|
|
|
|
@ -311,6 +347,30 @@ def main():
|
|
|
|
|
# TODO: Would be nice to template this, requires action-plugin
|
|
|
|
|
payload = config_object.read()
|
|
|
|
|
|
|
|
|
|
# Validate content
|
|
|
|
|
if rest_type == 'json':
|
|
|
|
|
if content and isinstance(content, dict):
|
|
|
|
|
# Validate inline YAML/JSON
|
|
|
|
|
payload = json.dumps(payload)
|
|
|
|
|
elif payload and isinstance(payload, str) and HAS_YAML:
|
|
|
|
|
try:
|
|
|
|
|
# Validate YAML/JSON string
|
|
|
|
|
payload = json.dumps(yaml.load(payload))
|
|
|
|
|
except Exception as e:
|
|
|
|
|
module.fail_json(msg='Failed to parse provided JSON/YAML content: %s' % 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
|
|
|
|
|
# FIXME: Converting from a dictionary to XML is unsupported at this time
|
|
|
|
|
# payload = etree.tostring(payload)
|
|
|
|
|
pass
|
|
|
|
|
elif payload and isinstance(payload, str):
|
|
|
|
|
try:
|
|
|
|
|
# Validate XML string
|
|
|
|
|
payload = lxml.etree.tostring(lxml.etree.fromstring(payload))
|
|
|
|
|
except Exception as e:
|
|
|
|
|
module.fail_json(msg='Failed to parse provided XML content: %s' % to_text(e), payload=payload)
|
|
|
|
|
|
|
|
|
|
# Perform actual request using auth cookie (Same as aci_request,but also supports XML)
|
|
|
|
|
url = '%(protocol)s://%(hostname)s/' % aci.params + path.lstrip('/')
|
|
|
|
|
if method != 'get':
|
|
|
|
@ -325,9 +385,9 @@ def main():
|
|
|
|
|
if info['status'] != 200:
|
|
|
|
|
try:
|
|
|
|
|
aci_response(aci.result, info['body'], rest_type)
|
|
|
|
|
module.fail_json(msg='Request failed: %(error_code)s %(error_text)s' % aci.result, **aci.result)
|
|
|
|
|
module.fail_json(msg='Request failed: %(error_code)s %(error_text)s' % aci.result, payload=payload, **aci.result)
|
|
|
|
|
except KeyError:
|
|
|
|
|
module.fail_json(msg='Request failed for %(url)s. %(msg)s' % info, **aci.result)
|
|
|
|
|
module.fail_json(msg='Request failed for %(url)s. %(msg)s' % info, payload=payload, **aci.result)
|
|
|
|
|
|
|
|
|
|
aci_response(aci.result, resp.read(), rest_type)
|
|
|
|
|
|
|
|
|
|