aci_rest: Fix error handling and improve documentation (#36295)
This PR includes: - A fix for a recently introduced issue wrt. error handling - Added integration tests for provoked errors - Influence standard return values using aci library for aci_rest - Add proxy support documentation - Documentation update related to #34175
This commit is contained in:
parent
cd9d554186
commit
79d00adc52
13 changed files with 279 additions and 82 deletions
|
@ -1,7 +1,7 @@
|
|||
Cisco ACI Guide
|
||||
===============
|
||||
|
||||
.. _aci_intro:
|
||||
.. _aci_guide_intro:
|
||||
|
||||
What is Cisco ACI ?
|
||||
-------------------
|
||||
|
@ -39,6 +39,8 @@ Various resources exist to start learning ACI, here is a list of interesting art
|
|||
- `Cisco DevNet Learning Labs about ACI <https://learninglabs.cisco.com/labs/tags/ACI>`_
|
||||
|
||||
|
||||
.. _aci_guide_modules:
|
||||
|
||||
Using the ACI modules
|
||||
---------------------
|
||||
The Ansible ACI modules provide a user-friendly interface to managing your ACI environment using Ansible playbooks.
|
||||
|
@ -57,7 +59,7 @@ For instance ensuring that a specific tenant exists, is done using the following
|
|||
description: Customer XYZ
|
||||
state: present
|
||||
|
||||
A complete list of existing ACI modules is available for `the latest stable release <http://docs.ansible.com/ansible/latest/list_of_network_modules.html#aci>`_ as well as `the current development version <http://docs.ansible.com/ansible/devel/module_docs/list_of_network_modules.html#aci>`_.
|
||||
A complete list of existing ACI modules is available for `the latest stable release <http://docs.ansible.com/ansible/latest/modules/list_of_network_modules.html#aci>`_ as well as `the current development version <http://docs.ansible.com/ansible/devel/modules/list_of_network_modules.html#aci>`_.
|
||||
|
||||
Standard module parameters
|
||||
..........................
|
||||
|
@ -75,9 +77,19 @@ Every Ansible ACI module accepts the following parameters that influence the mod
|
|||
- ``validate_certs`` -- Validate certificate when using HTTPS communication (defaults to ``yes``)
|
||||
- ``output_level`` -- Influence the level of detail ACI modules return to the user (one of ``normal``, ``info`` or ``debug``)
|
||||
|
||||
Proxy support
|
||||
.............
|
||||
By default, if an environment variable ``<protocol>_proxy`` is set on the target host, requests will be sent through that proxy. This behaviour can be overridden by setting a variable for this task (see setting the environment), or by using the ``use_proxy`` module parameter.
|
||||
|
||||
HTTP redirects can redirect from HTTP to HTTPS so you should be sure that your proxy environment for both protocols is correct.
|
||||
|
||||
If you don't need proxy support, but the system may have it configured nevertheless, you can add this parameter setting: ``use_proxy: no`` to avoid accidental proxy usage.
|
||||
|
||||
.. note:: Selective proxy support using the ``no_proxy`` environment variable is also supported.
|
||||
|
||||
Module return values
|
||||
....................
|
||||
By default the ACI modules (excluding :ref:`aci_rest <aci_rest>`) return the resulting state of the managed object in a key ``current``.
|
||||
By default the ACI modules (excluding :ref:`the aci_rest module <aci_rest>`) return the resulting state of the managed object in a key ``current``.
|
||||
|
||||
By increasing the ``output_level`` to ``info``, the modules give access to the ``previous`` state of the object, but also the ``proposed`` and ``sent`` configuration payload.
|
||||
|
||||
|
@ -93,7 +105,7 @@ Various resources exist to start learn more about ACI programmability, we recomm
|
|||
- `Cisco DevNet Learning Labs about ACI and Ansible <https://learninglabs.cisco.com/labs/tags/ACI,Ansible>`_
|
||||
|
||||
|
||||
.. _aci_auth:
|
||||
.. _aci_guide_auth:
|
||||
|
||||
ACI authentication
|
||||
------------------
|
||||
|
@ -178,17 +190,17 @@ More information
|
|||
More information about Signature-based Authentication is available from `Cisco APIC Signature-Based Transactions <https://www.cisco.com/c/en/us/td/docs/switches/datacenter/aci/apic/sw/kb/b_KB_Signature_Based_Transactions.html>`_.
|
||||
|
||||
|
||||
.. _aci_rest:
|
||||
.. _aci_guide_rest:
|
||||
|
||||
Using ACI REST with Ansible
|
||||
---------------------------
|
||||
While already a lot of ACI modules exists in the Ansible distribution, and the most common actions can be performed with these existing modules, there's always something that may not be possible with off-the-shelf modules.
|
||||
|
||||
The :ref:`aci_rest <aci_rest>` module provides you with direct access to the APIC REST API and enables you to perform any task not already covered by the existing modules. This may seem like a complex undertaking, but you can generate the needed REST payload for any action performed in the ACI web interface effortlessly.
|
||||
:ref:`The aci_rest module <aci_rest>` provides you with direct access to the APIC REST API and enables you to perform any task not already covered by the existing modules. This may seem like a complex undertaking, but you can generate the needed REST payload for any action performed in the ACI web interface effortlessly.
|
||||
|
||||
Using the aci-rest module
|
||||
.........................
|
||||
The :ref:`aci_rest <aci_rest>` module accepts the native XML and JSON payloads, but additionally accepts inline YAML payload (structured like JSON). The XML payload requires you to use a path ending with ``.xml`` whereas JSON or YAML require path to end with ``.json``.
|
||||
:ref:`The aci_rest module <aci_rest>` accepts the native XML and JSON payloads, but additionally accepts inline YAML payload (structured like JSON). The XML payload requires you to use a path ending with ``.xml`` whereas JSON or YAML require path to end with ``.json``.
|
||||
|
||||
When you're making modifications, you can use the POST or DELETE methods, whereas doing just queries require the GET method.
|
||||
|
||||
|
@ -259,12 +271,12 @@ More information
|
|||
................
|
||||
Plenty of resources exist to learn about ACI's APIC REST interface, we recommend the links below:
|
||||
|
||||
- `The apic_rest Ansible module <http://docs.ansible.com/ansible/devel/module_docs/aci_rest_module.html>`_
|
||||
- :ref:`The apic_rest Ansible module <aci_rest>`
|
||||
- `APIC REST API Configuration Guide <https://www.cisco.com/c/en/us/td/docs/switches/datacenter/aci/apic/sw/2-x/rest_cfg/2_1_x/b_Cisco_APIC_REST_API_Configuration_Guide.html>`_
|
||||
- `Cisco DevNet Learning Labs about ACI and REST <https://learninglabs.cisco.com/labs/tags/ACI,REST>`_
|
||||
|
||||
|
||||
.. _aci_ops:
|
||||
.. _aci_guide_ops:
|
||||
|
||||
Operational examples
|
||||
--------------------
|
||||
|
@ -316,7 +328,7 @@ The below example waits until the cluster is fully-fit. In this example you know
|
|||
delay: 30
|
||||
|
||||
|
||||
.. _aci_errors:
|
||||
.. _aci_guide_errors:
|
||||
|
||||
APIC error messages
|
||||
-------------------
|
||||
|
@ -329,19 +341,19 @@ The following error messages may occur and this section can help you understand
|
|||
|
||||
- **APIC Error 400: invalid data at line '1'. Attributes are missing, tag 'attributes' must be specified first, before any other tag**
|
||||
|
||||
While JSON does not care about the order of dictionary keys, the APIC is very strict in accepting only ``attributes`` before ``children``. So you need to ensure that your payload conforms to this requirement. Sorting your dictionary keys will do the trick just fine.
|
||||
Although the JSON specification allows unordered elements, the APIC REST API requires that the JSON ``attributes`` element precede the ``children`` array or other elements. So you need to ensure that your payload conforms to this requirement. Sorting your dictionary keys will do the trick just fine. If you don't have any attributes, it may be necessary to add: ``attributes: {}`` as the APIC does expect the entry to proceed any ``children``.
|
||||
|
||||
|
||||
- **APIC Error 801: property descr of uni/tn-TENANT/ap-AP failed validation for value 'A "legacy" network'**
|
||||
|
||||
Some values in the APIC have strict format-rules to comply to, and the internal APIC validation check for the provided value failed. In the above case, the ``description`` parameter (internally known as ``descr``) only accepts values conforming to `Regex: [a-zA-Z0-9\\!#$%()*,-./:;@ _{|}~?&+]+ <https://pubhub-prod.s3.amazonaws.com/media/apic-mim-ref/docs/MO-fvAp.html#descr>`_ so it must not include quotes.
|
||||
Some values in the APIC have strict format-rules to comply to, and the internal APIC validation check for the provided value failed. In the above case, the ``description`` parameter (internally known as ``descr``) only accepts values conforming to `Regex: [a-zA-Z0-9\\!#$%()*,-./:;@ _{|}~?&+]+ <https://pubhub-prod.s3.amazonaws.com/media/apic-mim-ref/docs/MO-fvAp.html#descr>`_, in general it must not include quotes or square brackets.
|
||||
|
||||
|
||||
.. _aci_issues:
|
||||
.. _aci_guide_issues:
|
||||
|
||||
Known issues
|
||||
------------
|
||||
The :ref:`aci_rest <aci_rest>` module is a wrapper around the APIC REST API. As a result any issues related to the APIC will be reflected in the use of the :ref:`aci_rest <aci_rest>` module.
|
||||
:ref:`The aci_rest module <aci_rest>` is a wrapper around the APIC REST API. As a result any issues related to the APIC will be reflected in the use of :ref:`the aci_rest module <aci_rest>`.
|
||||
|
||||
All below issues either have been reported to the vendor, or can simply be avoided.
|
||||
|
||||
|
@ -358,7 +370,7 @@ All below issues either have been reported to the vendor, or can simply be avoid
|
|||
|
||||
More information from: `#35401 aci_rest: change not detected <https://github.com/ansible/ansible/issues/35041>`_
|
||||
|
||||
**NOTE:** Fortunately the behaviour is consistent, so if you have a working example you can trust that it will keep on working.
|
||||
**NOTE:** A workaround is to register the task return values (e.g. ``register: this``) and influence when the task should report a change by adding: ``changed_when: this.imdata != []``.
|
||||
|
||||
|
||||
- **Specific requests are known to not be idempotent**
|
||||
|
@ -379,7 +391,7 @@ All below issues either have been reported to the vendor, or can simply be avoid
|
|||
**NOTE:** There is no workaround for this issue.
|
||||
|
||||
|
||||
.. _aci_community:
|
||||
.. _aci_guide_community:
|
||||
|
||||
ACI Ansible community
|
||||
---------------------
|
||||
|
|
|
@ -930,33 +930,36 @@ class ACIModule(object):
|
|||
|
||||
def exit_json(self, **kwargs):
|
||||
|
||||
if self.params['state'] in ('absent', 'present'):
|
||||
if self.params['output_level'] in ('debug', 'info'):
|
||||
self.result['previous'] = self.existing
|
||||
if 'state' in self.params:
|
||||
if self.params['state'] in ('absent', 'present'):
|
||||
if self.params['output_level'] in ('debug', 'info'):
|
||||
self.result['previous'] = self.existing
|
||||
|
||||
# Return the gory details when we need it
|
||||
if self.params['output_level'] == 'debug':
|
||||
self.result['filter_string'] = self.filter_string
|
||||
if 'state' in self.params:
|
||||
self.result['filter_string'] = self.filter_string
|
||||
self.result['method'] = self.method
|
||||
# self.result['path'] = self.path # Adding 'path' in result causes state: absent in output
|
||||
self.result['response'] = self.response
|
||||
self.result['status'] = self.status
|
||||
self.result['url'] = self.url
|
||||
|
||||
self.original = self.existing
|
||||
if self.params['state'] in ('absent', 'present'):
|
||||
self.get_existing()
|
||||
if 'state' in self.params:
|
||||
self.original = self.existing
|
||||
if self.params['state'] in ('absent', 'present'):
|
||||
self.get_existing()
|
||||
|
||||
# if self.module._diff and self.original != self.existing:
|
||||
# self.result['diff'] = dict(
|
||||
# before=json.dumps(self.original, sort_keys=True, indent=4),
|
||||
# after=json.dumps(self.existing, sort_keys=True, indent=4),
|
||||
# )
|
||||
self.result['current'] = self.existing
|
||||
self.result['current'] = self.existing
|
||||
|
||||
if self.params['output_level'] in ('debug', 'info'):
|
||||
self.result['sent'] = self.config
|
||||
self.result['proposed'] = self.proposed
|
||||
if self.params['output_level'] in ('debug', 'info'):
|
||||
self.result['sent'] = self.config
|
||||
self.result['proposed'] = self.proposed
|
||||
|
||||
self.result.update(**kwargs)
|
||||
self.module.exit_json(**self.result)
|
||||
|
@ -967,27 +970,31 @@ class ACIModule(object):
|
|||
if self.error['code'] is not None and self.error['text'] is not None:
|
||||
self.result['error'] = self.error
|
||||
|
||||
if self.params['state'] in ('absent', 'present'):
|
||||
if self.params['output_level'] in ('debug', 'info'):
|
||||
self.result['previous'] = self.existing
|
||||
if 'state' in self.params:
|
||||
if self.params['state'] in ('absent', 'present'):
|
||||
if self.params['output_level'] in ('debug', 'info'):
|
||||
self.result['previous'] = self.existing
|
||||
|
||||
# Return the gory details when we need it
|
||||
if self.params['output_level'] == 'debug':
|
||||
if self.imdata is not None:
|
||||
self.result['imdata'] = self.imdata
|
||||
self.result['totalCount'] = self.totalCount
|
||||
|
||||
# Return the gory details when we need it
|
||||
if self.params['output_level'] == 'debug':
|
||||
if self.imdata is not None:
|
||||
self.result['imdata'] = self.imdata
|
||||
self.result['totalCount'] = self.totalCount
|
||||
|
||||
if self.url is not None:
|
||||
self.result['filter_string'] = self.filter_string
|
||||
if 'state' in self.params:
|
||||
self.result['filter_string'] = self.filter_string
|
||||
self.result['method'] = self.method
|
||||
# self.result['path'] = self.path # Adding 'path' in result causes state: absent in output
|
||||
self.result['response'] = self.response
|
||||
self.result['status'] = self.status
|
||||
self.result['url'] = self.url
|
||||
|
||||
if self.params['output_level'] in ('debug', 'info'):
|
||||
self.result['sent'] = self.config
|
||||
self.result['proposed'] = self.proposed
|
||||
if 'state' in self.params:
|
||||
if self.params['output_level'] in ('debug', 'info'):
|
||||
self.result['sent'] = self.config
|
||||
self.result['proposed'] = self.proposed
|
||||
|
||||
self.result.update(**kwargs)
|
||||
self.module.fail_json(msg=msg, **self.result)
|
||||
|
|
|
@ -285,7 +285,7 @@ class ACIRESTModule(ACIModule):
|
|||
|
||||
return False
|
||||
|
||||
def response_any(self, rawoutput, rest_type='xml'):
|
||||
def response_type(self, rawoutput, rest_type='xml'):
|
||||
''' Handle APIC response output '''
|
||||
|
||||
if rest_type == 'json':
|
||||
|
@ -388,31 +388,27 @@ def main():
|
|||
timeout=aci.params['timeout'],
|
||||
use_proxy=aci.params['use_proxy'])
|
||||
|
||||
if aci.params['output_level'] == 'debug':
|
||||
aci.result['filter_string'] = aci.filter_string
|
||||
aci.result['method'] = aci.params['method'].upper()
|
||||
# aci.result['path'] = aci.path # Adding 'path' in result causes state: absent in output
|
||||
aci.result['response'] = info['msg']
|
||||
aci.result['status'] = info['status']
|
||||
aci.result['url'] = aci.url
|
||||
aci.method = aci.params['method'].upper()
|
||||
aci.response = info['msg']
|
||||
aci.status = info['status']
|
||||
|
||||
# Report failure
|
||||
if info['status'] != 200:
|
||||
try:
|
||||
# APIC error
|
||||
aci.response(info['body'], rest_type)
|
||||
aci.fail_json(msg='Request failed: %(code)s %(text)s' % aci.error)
|
||||
aci.response_type(info['body'], rest_type)
|
||||
aci.fail_json(msg='APIC Error %(code)s: %(text)s' % aci.error)
|
||||
except KeyError:
|
||||
# Connection error
|
||||
aci.fail_json(msg='Request connection failed for %(url)s. %(msg)s' % info)
|
||||
aci.fail_json(msg='Connection failed for %(url)s. %(msg)s' % info)
|
||||
|
||||
aci.response_any(resp.read(), rest_type)
|
||||
aci.response_type(resp.read(), rest_type)
|
||||
|
||||
aci.result['imdata'] = aci.imdata
|
||||
aci.result['totalCount'] = aci.totalCount
|
||||
|
||||
# Report success
|
||||
module.exit_json(**aci.result)
|
||||
aci.exit_json(**aci.result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
195
test/integration/targets/aci_rest/tasks/error_handling.yml
Normal file
195
test/integration/targets/aci_rest/tasks/error_handling.yml
Normal file
|
@ -0,0 +1,195 @@
|
|||
# Test code for the ACI modules
|
||||
# Copyright: (c) 2018, Dag Wieers (@dagwieers) <dag@wieers.com>
|
||||
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
|
||||
# PROVOKE ERRORS
|
||||
- name: Error on name resolution
|
||||
aci_rest:
|
||||
host: foo.bar.cisco.com
|
||||
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: debug
|
||||
path: /api/mo/uni.json
|
||||
method: post
|
||||
content:
|
||||
fvTenant:
|
||||
attributes:
|
||||
name: ansible_test
|
||||
ignore_errors: yes
|
||||
register: error_on_name_resolution
|
||||
|
||||
- name: Verify error_on_name_resolution
|
||||
assert:
|
||||
that:
|
||||
- error_on_name_resolution.failed == true
|
||||
- "error_on_name_resolution.msg == 'Connection failed for https://foo.bar.cisco.com/api/aaaLogin.json. Request failed: <urlopen error [Errno -2] Name or service not known>'"
|
||||
- "'current' not in error_on_name_resolution"
|
||||
- "'previous' not in error_on_name_resolution"
|
||||
- "'sent' not in error_on_name_resolution"
|
||||
- "'proposed' not in error_on_name_resolution"
|
||||
- "'filter_string' not in error_on_name_resolution"
|
||||
|
||||
- name: Error when required parameter is missing
|
||||
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: debug
|
||||
method: post
|
||||
content:
|
||||
fvTenant:
|
||||
attributes:
|
||||
name: ansible_test
|
||||
ignore_errors: yes
|
||||
register: error_on_missing_required_param
|
||||
|
||||
- name: Verify error_on_missing_required_param
|
||||
assert:
|
||||
that:
|
||||
- error_on_missing_required_param.failed == true
|
||||
- 'error_on_missing_required_param.msg == "missing required arguments: path"'
|
||||
- "'current' not in error_on_missing_required_param"
|
||||
- "'previous' not in error_on_missing_required_param"
|
||||
- "'sent' not in error_on_missing_required_param"
|
||||
- "'proposed' not in error_on_missing_required_param"
|
||||
- "'filter_string' not in error_on_missing_required_param"
|
||||
|
||||
- name: Error when attributes are missing
|
||||
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: debug
|
||||
path: /api/mo/uni/tn-ansible_test.json
|
||||
method: post
|
||||
content:
|
||||
fvTenant:
|
||||
children:
|
||||
ignore_errors: yes
|
||||
register: error_on_missing_attributes
|
||||
|
||||
- name: Verify error_on_missing_attributes
|
||||
assert:
|
||||
that:
|
||||
- error_on_missing_attributes.failed == true
|
||||
- error_on_missing_attributes.method == 'POST'
|
||||
- "error_on_missing_attributes.msg == 'APIC Error 400: invalid data at line \\'1\\'. Attributes are missing, tag \\'attributes\\' must be specified first, before any other tag'"
|
||||
- 'error_on_missing_attributes.response == "HTTP Error 400: Bad Request"'
|
||||
- error_on_missing_attributes.status == 400
|
||||
- error_on_missing_attributes.url == 'https://sandboxapicdc.cisco.com/api/mo/uni/tn-ansible_test.json?rsp-subtree=modified'
|
||||
- "'current' not in error_on_missing_attributes"
|
||||
- "'previous' not in error_on_missing_attributes"
|
||||
- "'sent' not in error_on_missing_attributes"
|
||||
- "'proposed' not in error_on_missing_attributes"
|
||||
- "'filter_string' not in error_on_missing_attributes"
|
||||
|
||||
- name: Error when input does not validate
|
||||
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: debug
|
||||
path: /api/mo/uni.json
|
||||
method: post
|
||||
content:
|
||||
fvTenant:
|
||||
attributes:
|
||||
name: ansible_test
|
||||
descr: This is an [invalid] description
|
||||
ignore_errors: yes
|
||||
register: error_on_input_validation
|
||||
|
||||
- name: Verify error_on_input_validation
|
||||
assert:
|
||||
that:
|
||||
- error_on_input_validation.failed == true
|
||||
- error_on_input_validation.method == 'POST'
|
||||
- "error_on_input_validation.msg == 'APIC Error 801: property descr of uni/tn-ansible_test failed validation for value \\'This is an [invalid] description\\''"
|
||||
- 'error_on_input_validation.response == "HTTP Error 400: Bad Request"'
|
||||
- error_on_input_validation.status == 400
|
||||
- error_on_input_validation.url == 'https://sandboxapicdc.cisco.com/api/mo/uni.json?rsp-subtree=modified'
|
||||
- "'current' not in error_on_input_validation"
|
||||
- "'previous' not in error_on_input_validation"
|
||||
- "'sent' not in error_on_input_validation"
|
||||
- "'proposed' not in error_on_input_validation"
|
||||
- "'filter_string' not in error_on_input_validation"
|
||||
|
||||
- name: Error when invalid attributes are used
|
||||
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: debug
|
||||
path: /api/mo/uni.json
|
||||
method: post
|
||||
content:
|
||||
fvTenant:
|
||||
attributes:
|
||||
name: ansible_test
|
||||
description: This is an "invalid" description
|
||||
ignore_errors: yes
|
||||
register: error_on_invalid_attributes
|
||||
|
||||
- name: Verify error_on_invalid_attributes
|
||||
assert:
|
||||
that:
|
||||
- error_on_invalid_attributes.failed == true
|
||||
- error_on_invalid_attributes.method == 'POST'
|
||||
- "error_on_invalid_attributes.msg == 'APIC Error 400: unknown attribute \\'description\\' in element \\'fvTenant\\''"
|
||||
- 'error_on_invalid_attributes.response == "HTTP Error 400: Bad Request"'
|
||||
- error_on_invalid_attributes.status == 400
|
||||
- error_on_invalid_attributes.url == 'https://sandboxapicdc.cisco.com/api/mo/uni.json?rsp-subtree=modified'
|
||||
- "'current' not in error_on_invalid_attributes"
|
||||
- "'previous' not in error_on_invalid_attributes"
|
||||
- "'sent' not in error_on_invalid_attributes"
|
||||
- "'proposed' not in error_on_invalid_attributes"
|
||||
- "'filter_string' not in error_on_invalid_attributes"
|
||||
|
||||
- name: Error on invalid object
|
||||
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: debug
|
||||
path: /api/mo/uni.json
|
||||
method: post
|
||||
content:
|
||||
fvFoobar:
|
||||
attributes:
|
||||
name: ansible_test
|
||||
ignore_errors: yes
|
||||
register: error_on_invalid_object
|
||||
|
||||
- name: Verify error_on_invalid_object
|
||||
assert:
|
||||
that:
|
||||
- error_on_invalid_object.failed == true
|
||||
- error_on_invalid_object.method == 'POST'
|
||||
- "error_on_invalid_object.msg == 'APIC Error 122: unknown managed object class fvFoobar'"
|
||||
- 'error_on_invalid_object.response == "HTTP Error 400: Bad Request"'
|
||||
- error_on_invalid_object.status == 400
|
||||
- error_on_invalid_object.url == 'https://sandboxapicdc.cisco.com/api/mo/uni.json?rsp-subtree=modified'
|
||||
- "'current' not in error_on_invalid_object"
|
||||
- "'previous' not in error_on_invalid_object"
|
||||
- "'sent' not in error_on_invalid_object"
|
||||
- "'proposed' not in error_on_invalid_object"
|
|
@ -1,12 +1,8 @@
|
|||
# Test code for the ACI modules
|
||||
# Copyright 2017, Dag Wieers <dag@wieers.com>
|
||||
# Copyright: (c) 2017, Dag Wieers (@dagwieers) <dag@wieers.com>
|
||||
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
- name: Test that we have an ACI APIC host, ACI username and ACI password
|
||||
fail:
|
||||
msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.'
|
||||
when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined
|
||||
|
||||
# CLEAN ENVIRONMENT
|
||||
- name: Remove tenant
|
||||
|
@ -19,7 +15,6 @@
|
|||
use_proxy: '{{ aci_use_proxy | default(true) }}'
|
||||
path: /api/mo/uni/tn-[ansible_test].json
|
||||
method: delete
|
||||
delegate_to: localhost
|
||||
|
||||
# ADD TENANT
|
||||
- name: Add tenant (normal mode)
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
# Test code for the ACI modules
|
||||
# Copyright 2017, Dag Wieers <dag@wieers.com>
|
||||
# Copyright: (c) 2017, Dag Wieers (@dagwieers) <dag@wieers.com>
|
||||
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
- name: Test that we have an ACI APIC host, ACI username and ACI password
|
||||
fail:
|
||||
msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.'
|
||||
when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined
|
||||
|
||||
# CLEAN ENVIRONMENT
|
||||
- name: Remove tenant
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
# Test code for the ACI modules
|
||||
# Copyright 2017, Dag Wieers <dag@wieers.com>
|
||||
# Copyright: (c) 2017, Dag Wieers (@dagwieers) <dag@wieers.com>
|
||||
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
- name: Test that we have an ACI APIC host, ACI username and ACI password
|
||||
fail:
|
||||
msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.'
|
||||
when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined
|
||||
|
||||
- include_tasks: yaml_inline.yml
|
||||
tags: yaml_inline
|
||||
|
||||
|
@ -17,3 +22,6 @@
|
|||
|
||||
- include_tasks: xml_string.yml
|
||||
tags: xml_string
|
||||
|
||||
- include_tasks: error_handling.yml
|
||||
tags: error_handling
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
# Test code for the ACI modules
|
||||
# Copyright 2017, Dag Wieers <dag@wieers.com>
|
||||
# Copyright: (c) 2017, Dag Wieers (@dagwieers) <dag@wieers.com>
|
||||
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
- name: Test that we have an ACI APIC host, ACI username and ACI password
|
||||
fail:
|
||||
msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.'
|
||||
when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined
|
||||
|
||||
# CLEAN ENVIRONMENT
|
||||
- name: Remove tenant
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
# Test code for the ACI modules
|
||||
# Copyright 2017, Dag Wieers <dag@wieers.com>
|
||||
# Copyright: (c) 2017, Dag Wieers (@dagwieers) <dag@wieers.com>
|
||||
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
- name: Test that we have an ACI APIC host, ACI username and ACI password
|
||||
fail:
|
||||
msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.'
|
||||
when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined
|
||||
|
||||
# CLEAN ENVIRONMENT
|
||||
- name: Remove tenant
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
# Test code for the ACI modules
|
||||
# Copyright 2017, Dag Wieers <dag@wieers.com>
|
||||
# Copyright: (c) 2017, Dag Wieers (@dagwieers) <dag@wieers.com>
|
||||
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
- name: Test that we have an ACI APIC host, ACI username and ACI password
|
||||
fail:
|
||||
msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.'
|
||||
when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined
|
||||
|
||||
# CLEAN ENVIRONMENT
|
||||
- name: Remove tenant
|
||||
|
|
|
@ -268,7 +268,7 @@
|
|||
ignore_errors: yes
|
||||
register: error_on_missing_required_param
|
||||
|
||||
- name: Assertion test - present
|
||||
- name: Verify error_on_missing_required_param
|
||||
assert:
|
||||
that:
|
||||
- error_on_missing_required_param.failed == true
|
||||
|
|
|
@ -258,7 +258,7 @@
|
|||
ignore_errors: yes
|
||||
register: error_on_missing_required_param
|
||||
|
||||
- name: Assertion test - present
|
||||
- name: Verify error_on_missing_required_param
|
||||
assert:
|
||||
that:
|
||||
- error_on_missing_required_param.failed == true
|
||||
|
|
|
@ -258,7 +258,7 @@
|
|||
ignore_errors: yes
|
||||
register: error_on_missing_required_param
|
||||
|
||||
- name: Assertion test - present
|
||||
- name: Verify error_on_missing_required_param
|
||||
assert:
|
||||
that:
|
||||
- error_on_missing_required_param.failed == true
|
||||
|
|
Loading…
Reference in a new issue