Migrated to cisco.aci

pull/68298/head
Ansible Core Team 5 years ago committed by Matt Martz
parent 14b0ab63ac
commit 3f1cea89fb

File diff suppressed because it is too large Load Diff

@ -1,367 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# 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)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_aaa_user
short_description: Manage AAA users (aaa:User)
description:
- Manage AAA users on Cisco ACI fabrics.
requirements:
- python-dateutil
version_added: '2.5'
options:
aaa_password:
description:
- The password of the locally-authenticated user.
type: str
aaa_password_lifetime:
description:
- The lifetime of the locally-authenticated user password.
type: int
aaa_password_update_required:
description:
- Whether this account needs password update.
type: bool
aaa_user:
description:
- The name of the locally-authenticated user user to add.
type: str
aliases: [ name, user ]
clear_password_history:
description:
- Whether to clear the password history of a locally-authenticated user.
type: bool
description:
description:
- Description for the AAA user.
type: str
aliases: [ descr ]
email:
description:
- The email address of the locally-authenticated user.
type: str
enabled:
description:
- The status of the locally-authenticated user account.
type: bool
expiration:
description:
- The expiration date of the locally-authenticated user account.
type: str
expires:
description:
- Whether to enable an expiration date for the locally-authenticated user account.
type: bool
first_name:
description:
- The first name of the locally-authenticated user.
type: str
last_name:
description:
- The last name of the locally-authenticated user.
type: str
phone:
description:
- The phone number of the locally-authenticated user.
type: str
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
notes:
- This module is not idempotent when C(aaa_password) is being used
(even if that password was already set identically). This
appears to be an inconsistency wrt. the idempotent nature
of the APIC REST API. The vendor has been informed.
More information in :ref:`the ACI documentation <aci_guide_known_issues>`.
seealso:
- module: aci_aaa_user_certificate
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(aaa:User).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Dag Wieers (@dagwieers)
'''
EXAMPLES = r'''
- name: Add a user
aci_aaa_user:
host: apic
username: admin
password: SomeSecretPassword
aaa_user: dag
aaa_password: AnotherSecretPassword
expiration: never
expires: no
email: dag@wieers.com
phone: 1-234-555-678
first_name: Dag
last_name: Wieers
state: present
delegate_to: localhost
- name: Remove a user
aci_aaa_user:
host: apic
username: admin
password: SomeSecretPassword
aaa_user: dag
state: absent
delegate_to: localhost
- name: Query a user
aci_aaa_user:
host: apic
username: admin
password: SomeSecretPassword
aaa_user: dag
state: query
delegate_to: localhost
register: query_result
- name: Query all users
aci_aaa_user:
host: apic
username: admin
password: SomeSecretPassword
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: '?rsp-prop-include=config-only'
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
try:
from dateutil.tz import tzutc
import dateutil.parser
HAS_DATEUTIL = True
except ImportError:
HAS_DATEUTIL = False
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
aaa_password=dict(type='str', no_log=True),
aaa_password_lifetime=dict(type='int'),
aaa_password_update_required=dict(type='bool'),
aaa_user=dict(type='str', aliases=['name']), # Not required for querying all objects
clear_password_history=dict(type='bool'),
description=dict(type='str', aliases=['descr']),
email=dict(type='str'),
enabled=dict(type='bool'),
expiration=dict(type='str'),
expires=dict(type='bool'),
first_name=dict(type='str'),
last_name=dict(type='str'),
phone=dict(type='str'),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['aaa_user']],
['state', 'present', ['aaa_user']],
['expires', True, ['expiration']],
],
)
aci = ACIModule(module)
if not HAS_DATEUTIL:
module.fail_json(msg='dateutil required for this module')
aaa_password = module.params.get('aaa_password')
aaa_password_lifetime = module.params.get('aaa_password_lifetime')
aaa_password_update_required = aci.boolean(module.params.get('aaa_password_update_required'))
aaa_user = module.params.get('aaa_user')
clear_password_history = aci.boolean(module.params.get('clear_password_history'), 'yes', 'no')
description = module.params.get('description')
email = module.params.get('email')
enabled = aci.boolean(module.params.get('enabled'), 'active', 'inactive')
expires = aci.boolean(module.params.get('expires'))
first_name = module.params.get('first_name')
last_name = module.params.get('last_name')
phone = module.params.get('phone')
state = module.params.get('state')
name_alias = module.params.get('name_alias')
expiration = module.params.get('expiration')
if expiration is not None and expiration != 'never':
try:
expiration = aci.iso8601_format(dateutil.parser.parse(expiration).replace(tzinfo=tzutc()))
except Exception as e:
module.fail_json(msg="Failed to parse date format '%s', %s" % (module.params.get('expiration'), e))
aci.construct_url(
root_class=dict(
aci_class='aaaUser',
aci_rn='userext/user-{0}'.format(aaa_user),
module_object=aaa_user,
target_filter={'name': aaa_user},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='aaaUser',
class_config=dict(
accountStatus=enabled,
clearPwdHistory=clear_password_history,
descr=description,
email=email,
expiration=expiration,
expires=expires,
firstName=first_name,
lastName=last_name,
name=aaa_user,
phone=phone,
pwd=aaa_password,
pwdLifeTime=aaa_password_lifetime,
pwdUpdateRequired=aaa_password_update_required,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='aaaUser')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,298 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# 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)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_aaa_user_certificate
short_description: Manage AAA user certificates (aaa:UserCert)
description:
- Manage AAA user certificates on Cisco ACI fabrics.
version_added: '2.5'
options:
aaa_user:
description:
- The name of the user to add a certificate to.
type: str
required: yes
aaa_user_type:
description:
- Whether this is a normal user or an appuser.
type: str
choices: [ appuser, user ]
default: user
certificate:
description:
- The PEM format public key extracted from the X.509 certificate.
type: str
aliases: [ cert_data, certificate_data ]
certificate_name:
description:
- The name of the user certificate entry in ACI.
type: str
aliases: [ cert_name ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
notes:
- The C(aaa_user) must exist before using this module in your playbook.
The M(aci_aaa_user) module can be used for this.
seealso:
- module: aci_aaa_user
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(aaa:UserCert).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Dag Wieers (@dagwieers)
'''
EXAMPLES = r'''
- name: Add a certificate to user
aci_aaa_user_certificate:
host: apic
username: admin
password: SomeSecretPassword
aaa_user: admin
certificate_name: admin
certificate_data: '{{ lookup("file", "pki/admin.crt") }}'
state: present
delegate_to: localhost
- name: Remove a certificate of a user
aci_aaa_user_certificate:
host: apic
username: admin
password: SomeSecretPassword
aaa_user: admin
certificate_name: admin
state: absent
delegate_to: localhost
- name: Query a certificate of a user
aci_aaa_user_certificate:
host: apic
username: admin
password: SomeSecretPassword
aaa_user: admin
certificate_name: admin
state: query
delegate_to: localhost
register: query_result
- name: Query all certificates of a user
aci_aaa_user_certificate:
host: apic
username: admin
password: SomeSecretPassword
aaa_user: admin
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
ACI_MAPPING = dict(
appuser=dict(
aci_class='aaaAppUser',
aci_mo='userext/appuser-',
),
user=dict(
aci_class='aaaUser',
aci_mo='userext/user-',
),
)
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
aaa_user=dict(type='str', required=True),
aaa_user_type=dict(type='str', default='user', choices=['appuser', 'user']),
certificate=dict(type='str', aliases=['cert_data', 'certificate_data']),
certificate_name=dict(type='str', aliases=['cert_name']), # Not required for querying all objects
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['aaa_user', 'certificate_name']],
['state', 'present', ['aaa_user', 'certificate', 'certificate_name']],
],
)
aaa_user = module.params.get('aaa_user')
aaa_user_type = module.params.get('aaa_user_type')
certificate = module.params.get('certificate')
certificate_name = module.params.get('certificate_name')
state = module.params.get('state')
name_alias = module.params.get('name_alias')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class=ACI_MAPPING.get(aaa_user_type).get('aci_class'),
aci_rn=ACI_MAPPING.get(aaa_user_type).get('aci_mo') + aaa_user,
module_object=aaa_user,
target_filter={'name': aaa_user},
),
subclass_1=dict(
aci_class='aaaUserCert',
aci_rn='usercert-{0}'.format(certificate_name),
module_object=certificate_name,
target_filter={'name': certificate_name},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='aaaUserCert',
class_config=dict(
data=certificate,
name=certificate_name,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='aaaUserCert')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,346 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2018, Simon Metzger <smnmtzgr@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_access_port_block_to_access_port
short_description: Manage port blocks of Fabric interface policy leaf profile interface selectors (infra:HPortS, infra:PortBlk)
description:
- Manage port blocks of Fabric interface policy leaf profile interface selectors on Cisco ACI fabrics.
version_added: '2.8'
options:
leaf_interface_profile:
description:
- The name of the Fabric access policy leaf interface profile.
type: str
required: yes
aliases: [ leaf_interface_profile_name ]
access_port_selector:
description:
- The name of the Fabric access policy leaf interface profile access port selector.
type: str
required: yes
aliases: [ name, access_port_selector_name ]
leaf_port_blk:
description:
- The name of the Fabric access policy leaf interface profile access port block.
type: str
required: yes
aliases: [ leaf_port_blk_name ]
leaf_port_blk_description:
description:
- The description to assign to the C(leaf_port_blk).
type: str
from_port:
description:
- The beginning (from-range) of the port range block for the leaf access port block.
type: str
required: yes
aliases: [ from, fromPort, from_port_range ]
to_port:
description:
- The end (to-range) of the port range block for the leaf access port block.
type: str
required: yes
aliases: [ to, toPort, to_port_range ]
from_card:
description:
- The beginning (from-range) of the card range block for the leaf access port block.
type: str
aliases: [ from_card_range ]
to_card:
description:
- The end (to-range) of the card range block for the leaf access port block.
type: str
aliases: [ to_card_range ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
extends_documentation_fragment: aci
seealso:
- name: APIC Management Information Model reference
description: More information about the internal APIC classes B(infra:HPortS) and B(infra:PortBlk).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Simon Metzger (@smnmtzgr)
'''
EXAMPLES = r'''
- name: Associate an access port block (single port) to an interface selector
aci_access_port_block_to_access_port:
host: apic
username: admin
password: SomeSecretPassword
leaf_interface_profile: leafintprfname
access_port_selector: accessportselectorname
leaf_port_blk: leafportblkname
from_port: 13
to_port: 13
state: present
delegate_to: localhost
- name: Associate an access port block (port range) to an interface selector
aci_access_port_block_to_access_port:
host: apic
username: admin
password: SomeSecretPassword
leaf_interface_profile: leafintprfname
access_port_selector: accessportselectorname
leaf_port_blk: leafportblkname
from_port: 13
to_port: 16
state: present
delegate_to: localhost
- name: Remove an access port block from an interface selector
aci_access_port_block_to_access_port:
host: apic
username: admin
password: SomeSecretPassword
leaf_interface_profile: leafintprfname
access_port_selector: accessportselectorname
leaf_port_blk: leafportblkname
from_port: 13
to_port: 13
state: absent
delegate_to: localhost
- name: Query Specific access port block under given access port selector
aci_access_port_block_to_access_port:
host: apic
username: admin
password: SomeSecretPassword
leaf_interface_profile: leafintprfname
access_port_selector: accessportselectorname
leaf_port_blk: leafportblkname
state: query
delegate_to: localhost
register: query_result
- name: Query all access port blocks under given leaf interface profile
aci_access_port_block_to_access_port:
host: apic
username: admin
password: SomeSecretPassword
leaf_interface_profile: leafintprfname
state: query
delegate_to: localhost
register: query_result
- name: Query all access port blocks in the fabric
aci_access_port_block_to_access_port:
host: apic
username: admin
password: SomeSecretPassword
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
leaf_interface_profile=dict(type='str', aliases=['leaf_interface_profile_name']), # Not required for querying all objects
access_port_selector=dict(type='str', aliases=['name', 'access_port_selector_name']), # Not required for querying all objects
leaf_port_blk=dict(type='str', aliases=['leaf_port_blk_name']), # Not required for querying all objects
leaf_port_blk_description=dict(type='str'),
from_port=dict(type='str', aliases=['from', 'fromPort', 'from_port_range']),
to_port=dict(type='str', aliases=['to', 'toPort', 'to_port_range']),
from_card=dict(type='str', aliases=['from_card_range']),
to_card=dict(type='str', aliases=['to_card_range']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['access_port_selector', 'leaf_port_blk', 'leaf_interface_profile']],
['state', 'present', ['access_port_selector', 'leaf_port_blk', 'from_port', 'to_port', 'leaf_interface_profile']],
],
)
leaf_interface_profile = module.params.get('leaf_interface_profile')
access_port_selector = module.params.get('access_port_selector')
leaf_port_blk = module.params.get('leaf_port_blk')
leaf_port_blk_description = module.params.get('leaf_port_blk_description')
from_port = module.params.get('from_port')
to_port = module.params.get('to_port')
from_card = module.params.get('from_card')
to_card = module.params.get('to_card')
state = module.params.get('state')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='infraAccPortP',
aci_rn='infra/accportprof-{0}'.format(leaf_interface_profile),
module_object=leaf_interface_profile,
target_filter={'name': leaf_interface_profile},
),
subclass_1=dict(
aci_class='infraHPortS',
# NOTE: normal rn: hports-{name}-typ-{type}, hence here hardcoded to range for purposes of module
aci_rn='hports-{0}-typ-range'.format(access_port_selector),
module_object=access_port_selector,
target_filter={'name': access_port_selector},
),
subclass_2=dict(
aci_class='infraPortBlk',
aci_rn='portblk-{0}'.format(leaf_port_blk),
module_object=leaf_port_blk,
target_filter={'name': leaf_port_blk},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='infraPortBlk',
class_config=dict(
descr=leaf_port_blk_description,
name=leaf_port_blk,
fromPort=from_port,
toPort=to_port,
fromCard=from_card,
toCard=to_card,
# type='range',
),
)
aci.get_diff(aci_class='infraPortBlk')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,397 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Bruno Calogero <brunocalogero@hotmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_access_port_to_interface_policy_leaf_profile
short_description: Manage Fabric interface policy leaf profile interface selectors (infra:HPortS, infra:RsAccBaseGrp, infra:PortBlk)
description:
- Manage Fabric interface policy leaf profile interface selectors on Cisco ACI fabrics.
version_added: '2.5'
options:
leaf_interface_profile:
description:
- The name of the Fabric access policy leaf interface profile.
type: str
required: yes
aliases: [ leaf_interface_profile_name ]
access_port_selector:
description:
- The name of the Fabric access policy leaf interface profile access port selector.
type: str
required: yes
aliases: [ name, access_port_selector_name ]
description:
description:
- The description to assign to the C(access_port_selector)
type: str
leaf_port_blk:
description:
- B(Deprecated)
- Starting with Ansible 2.8 we recommend using M(aci_access_port_block_to_access_port) instead.
- The parameter will be removed in Ansible 2.12.
- HORIZONTALLINE
- The name of the Fabric access policy leaf interface profile access port block.
type: str
required: yes
aliases: [ leaf_port_blk_name ]
leaf_port_blk_description:
description:
- B(Deprecated)
- Starting with Ansible 2.8 we recommend using M(aci_access_port_block_to_access_port) instead.
- The parameter will be removed in Ansible 2.12.
- HORIZONTALLINE
- The description to assign to the C(leaf_port_blk)
type: str
from_port:
description:
- B(Deprecated)
- Starting with Ansible 2.8 we recommend using M(aci_access_port_block_to_access_port) instead.
- The parameter will be removed in Ansible 2.12.
- HORIZONTALLINE
- The beginning (from-range) of the port range block for the leaf access port block.
type: str
required: yes
aliases: [ from, fromPort, from_port_range ]
to_port:
description:
- B(Deprecated)
- Starting with Ansible 2.8 we recommend using M(aci_access_port_block_to_access_port) instead.
- The parameter will be removed in Ansible 2.12.
- HORIZONTALLINE
- The end (to-range) of the port range block for the leaf access port block.
type: str
required: yes
aliases: [ to, toPort, to_port_range ]
from_card:
description:
- B(Deprecated)
- Starting with Ansible 2.8 we recommend using M(aci_access_port_block_to_access_port) instead.
- The parameter will be removed in Ansible 2.12.
- HORIZONTALLINE
- The beginning (from-range) of the card range block for the leaf access port block.
type: str
aliases: [ from_card_range ]
version_added: '2.6'
to_card:
description:
- B(Deprecated)
- Starting with Ansible 2.8 we recommend using M(aci_access_port_block_to_access_port) instead.
- The parameter will be removed in Ansible 2.12.
- HORIZONTALLINE
- The end (to-range) of the card range block for the leaf access port block.
type: str
aliases: [ to_card_range ]
version_added: '2.6'
policy_group:
description:
- The name of the fabric access policy group to be associated with the leaf interface profile interface selector.
type: str
aliases: [ policy_group_name ]
interface_type:
description:
- The type of interface for the static EPG deployment.
type: str
choices: [ breakout, fex, port_channel, switch_port, vpc ]
default: switch_port
version_added: '2.6'
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
extends_documentation_fragment: aci
seealso:
- module: aci_access_port_block_to_access_port
- name: APIC Management Information Model reference
description: More information about the internal APIC classes B(infra:HPortS), B(infra:RsAccBaseGrp) and B(infra:PortBlk).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Bruno Calogero (@brunocalogero)
'''
EXAMPLES = r'''
- name: Associate an Interface Access Port Selector to an Interface Policy Leaf Profile with a Policy Group
aci_access_port_to_interface_policy_leaf_profile:
host: apic
username: admin
password: SomeSecretPassword
leaf_interface_profile: leafintprfname
access_port_selector: accessportselectorname
leaf_port_blk: leafportblkname
from_port: 13
to_port: 16
policy_group: policygroupname
state: present
delegate_to: localhost
- name: Associate an interface access port selector to an Interface Policy Leaf Profile (w/o policy group) (check if this works)
aci_access_port_to_interface_policy_leaf_profile:
host: apic
username: admin
password: SomeSecretPassword
leaf_interface_profile: leafintprfname
access_port_selector: accessportselectorname
leaf_port_blk: leafportblkname
from_port: 13
to_port: 16
state: present
delegate_to: localhost
- name: Remove an interface access port selector associated with an Interface Policy Leaf Profile
aci_access_port_to_interface_policy_leaf_profile:
host: apic
username: admin
password: SomeSecretPassword
leaf_interface_profile: leafintprfname
access_port_selector: accessportselectorname
state: absent
delegate_to: localhost
- name: Query Specific access_port_selector under given leaf_interface_profile
aci_access_port_to_interface_policy_leaf_profile:
host: apic
username: admin
password: SomeSecretPassword
leaf_interface_profile: leafintprfname
access_port_selector: accessportselectorname
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
INTERFACE_TYPE_MAPPING = dict(
breakout='uni/infra/funcprof/brkoutportgrp-{0}',
fex='uni/infra/funcprof/accportgrp-{0}',
port_channel='uni/infra/funcprof/accbundle-{0}',
switch_port='uni/infra/funcprof/accportgrp-{0}',
vpc='uni/infra/funcprof/accbundle-{0}',
)
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
leaf_interface_profile=dict(type='str', aliases=['leaf_interface_profile_name']), # Not required for querying all objects
access_port_selector=dict(type='str', aliases=['name', 'access_port_selector_name']), # Not required for querying all objects
description=dict(type='str'),
leaf_port_blk=dict(type='str', aliases=['leaf_port_blk_name']),
leaf_port_blk_description=dict(type='str'),
from_port=dict(type='str', aliases=['from', 'fromPort', 'from_port_range']),
to_port=dict(type='str', aliases=['to', 'toPort', 'to_port_range']),
from_card=dict(type='str', aliases=['from_card_range']),
to_card=dict(type='str', aliases=['to_card_range']),
policy_group=dict(type='str', aliases=['policy_group_name']),
interface_type=dict(type='str', default='switch_port', choices=['breakout', 'fex', 'port_channel', 'switch_port', 'vpc']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['leaf_interface_profile', 'access_port_selector']],
['state', 'present', ['leaf_interface_profile', 'access_port_selector']],
],
)
leaf_interface_profile = module.params.get('leaf_interface_profile')
access_port_selector = module.params.get('access_port_selector')
description = module.params.get('description')
leaf_port_blk = module.params.get('leaf_port_blk')
leaf_port_blk_description = module.params.get('leaf_port_blk_description')
from_port = module.params.get('from_port')
to_port = module.params.get('to_port')
from_card = module.params.get('from_card')
to_card = module.params.get('to_card')
policy_group = module.params.get('policy_group')
interface_type = module.params.get('interface_type')
state = module.params.get('state')
# Build child_configs dynamically
child_configs = [dict(
infraPortBlk=dict(
attributes=dict(
descr=leaf_port_blk_description,
name=leaf_port_blk,
fromPort=from_port,
toPort=to_port,
fromCard=from_card,
toCard=to_card,
),
),
)]
# Add infraRsAccBaseGrp only when policy_group was defined
if policy_group is not None:
child_configs.append(dict(
infraRsAccBaseGrp=dict(
attributes=dict(
tDn=INTERFACE_TYPE_MAPPING[interface_type].format(policy_group),
),
),
))
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='infraAccPortP',
aci_rn='infra/accportprof-{0}'.format(leaf_interface_profile),
module_object=leaf_interface_profile,
target_filter={'name': leaf_interface_profile},
),
subclass_1=dict(
aci_class='infraHPortS',
# NOTE: normal rn: hports-{name}-typ-{type}, hence here hardcoded to range for purposes of module
aci_rn='hports-{0}-typ-range'.format(access_port_selector),
module_object=access_port_selector,
target_filter={'name': access_port_selector},
),
child_classes=['infraPortBlk', 'infraRsAccBaseGrp'],
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='infraHPortS',
class_config=dict(
descr=description,
name=access_port_selector,
# type='range',
),
child_configs=child_configs,
)
aci.get_diff(aci_class='infraHPortS')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,370 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Simon Metzger <smnmtzgr@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_access_sub_port_block_to_access_port
short_description: Manage sub port blocks of Fabric interface policy leaf profile interface selectors (infra:HPortS, infra:SubPortBlk)
description:
- Manage sub port blocks of Fabric interface policy leaf profile interface selectors on Cisco ACI fabrics.
seealso:
- name: APIC Management Information Model reference
description: More information about the internal APIC classes B(infra:HPortS) and B(infra:SubPortBlk).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Simon Metzger (@smnmtzgr)
version_added: '2.8'
options:
leaf_interface_profile:
description:
- The name of the Fabric access policy leaf interface profile.
type: str
required: yes
aliases: [ leaf_interface_profile_name ]
access_port_selector:
description:
- The name of the Fabric access policy leaf interface profile access port selector.
type: str
required: yes
aliases: [ name, access_port_selector_name ]
leaf_port_blk:
description:
- The name of the Fabric access policy leaf interface profile access port block.
type: str
required: yes
aliases: [ leaf_port_blk_name ]
leaf_port_blk_description:
description:
- The description to assign to the C(leaf_port_blk).
type: str
from_port:
description:
- The beginning (from-range) of the port range block for the leaf access port block.
type: str
required: yes
aliases: [ from, fromPort, from_port_range ]
to_port:
description:
- The end (to-range) of the port range block for the leaf access port block.
type: str
required: yes
aliases: [ to, toPort, to_port_range ]
from_sub_port:
description:
- The beginning (from-range) of the sub port range block for the leaf access port block.
type: str
required: yes
aliases: [ fromSubPort, from_sub_port_range ]
to_sub_port:
description:
- The end (to-range) of the sub port range block for the leaf access port block.
type: str
required: yes
aliases: [ toSubPort, to_sub_port_range ]
from_card:
description:
- The beginning (from-range) of the card range block for the leaf access port block.
type: str
aliases: [ from_card_range ]
to_card:
description:
- The end (to-range) of the card range block for the leaf access port block.
type: str
aliases: [ to_card_range ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
extends_documentation_fragment: aci
'''
EXAMPLES = r'''
- name: Associate an access sub port block (single port) to an interface selector
aci_access_sub_port_block_to_access_port:
host: apic
username: admin
password: SomeSecretPassword
leaf_interface_profile: leafintprfname
access_port_selector: accessportselectorname
leaf_port_blk: leafportblkname
from_port: 13
to_port: 13
from_sub_port: 1
to_sub_port: 1
state: present
delegate_to: localhost
- name: Associate an access sub port block (port range) to an interface selector
aci_access_sub_port_block_to_access_port:
host: apic
username: admin
password: SomeSecretPassword
leaf_interface_profile: leafintprfname
access_port_selector: accessportselectorname
leaf_port_blk: leafportblkname
from_port: 13
to_port: 13
from_sub_port: 1
to_sub_port: 3
state: present
delegate_to: localhost
- name: Remove an access sub port block from an interface selector
aci_access_sub_port_block_to_access_port:
host: apic
username: admin
password: SomeSecretPassword
leaf_interface_profile: leafintprfname
access_port_selector: accessportselectorname
leaf_port_blk: leafportblkname
from_port: 13
to_port: 13
from_sub_port: 1
to_sub_port: 1
state: absent
delegate_to: localhost
- name: Query Specific access sub port block under given access port selector
aci_access_sub_port_block_to_access_port:
host: apic
username: admin
password: SomeSecretPassword
leaf_interface_profile: leafintprfname
access_port_selector: accessportselectorname
leaf_port_blk: leafportblkname
state: query
delegate_to: localhost
register: query_result
- name: Query all access sub port blocks under given leaf interface profile
aci_access_sub_port_block_to_access_port:
host: apic
username: admin
password: SomeSecretPassword
leaf_interface_profile: leafintprfname
state: query
delegate_to: localhost
register: query_result
- name: Query all access sub port blocks in the fabric
aci_access_sub_port_block_to_access_port:
host: apic
username: admin
password: SomeSecretPassword
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
from ansible.module_utils.basic import AnsibleModule
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
leaf_interface_profile=dict(type='str', aliases=['leaf_interface_profile_name']), # Not required for querying all objects
access_port_selector=dict(type='str', aliases=['name', 'access_port_selector_name']), # Not required for querying all objects
leaf_port_blk=dict(type='str', aliases=['leaf_port_blk_name']), # Not required for querying all objects
leaf_port_blk_description=dict(type='str'),
from_port=dict(type='str', aliases=['from', 'fromPort', 'from_port_range']), # Not required for querying all objects and deleting sub port blocks
to_port=dict(type='str', aliases=['to', 'toPort', 'to_port_range']), # Not required for querying all objects and deleting sub port blocks
from_sub_port=dict(type='str', aliases=['fromSubPort', 'from_sub_port_range']), # Not required for querying all objects and deleting sub port blocks
to_sub_port=dict(type='str', aliases=['toSubPort', 'to_sub_port_range']), # Not required for querying all objects and deleting sub port blocks
from_card=dict(type='str', aliases=['from_card_range']),
to_card=dict(type='str', aliases=['to_card_range']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['access_port_selector', 'leaf_port_blk', 'leaf_interface_profile']],
['state', 'present', ['access_port_selector', 'leaf_port_blk', 'from_port', 'to_port', 'from_sub_port', 'to_sub_port', 'leaf_interface_profile']],
],
)
leaf_interface_profile = module.params.get('leaf_interface_profile')
access_port_selector = module.params.get('access_port_selector')
leaf_port_blk = module.params.get('leaf_port_blk')
leaf_port_blk_description = module.params.get('leaf_port_blk_description')
from_port = module.params.get('from_port')
to_port = module.params.get('to_port')
from_sub_port = module.params.get('from_sub_port')
to_sub_port = module.params.get('to_sub_port')
from_card = module.params.get('from_card')
to_card = module.params.get('to_card')
state = module.params.get('state')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='infraAccPortP',
aci_rn='infra/accportprof-{0}'.format(leaf_interface_profile),
module_object=leaf_interface_profile,
target_filter={'name': leaf_interface_profile},
),
subclass_1=dict(
aci_class='infraHPortS',
# NOTE: normal rn: hports-{name}-typ-{type}, hence here hardcoded to range for purposes of module
aci_rn='hports-{0}-typ-range'.format(access_port_selector),
module_object=access_port_selector,
target_filter={'name': access_port_selector},
),
subclass_2=dict(
aci_class='infraSubPortBlk',
aci_rn='subportblk-{0}'.format(leaf_port_blk),
module_object=leaf_port_blk,
target_filter={'name': leaf_port_blk},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='infraSubPortBlk',
class_config=dict(
descr=leaf_port_blk_description,
name=leaf_port_blk,
fromPort=from_port,
toPort=to_port,
fromSubPort=from_sub_port,
toSubPort=to_sub_port,
fromCard=from_card,
toCard=to_card,
# type='range',
),
)
aci.get_diff(aci_class='infraSubPortBlk')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,276 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_aep
short_description: Manage attachable Access Entity Profile (AEP) objects (infra:AttEntityP, infra:ProvAcc)
description:
- Connect to external virtual and physical domains by using
attachable Access Entity Profiles (AEP) on Cisco ACI fabrics.
version_added: '2.4'
options:
aep:
description:
- The name of the Attachable Access Entity Profile.
type: str
required: yes
aliases: [ aep_name, name ]
description:
description:
- Description for the AEP.
type: str
aliases: [ descr ]
infra_vlan:
description:
- Enable infrastructure VLAN.
- The hypervisor functions of the AEP.
- C(no) will disable the infrastructure vlan if it is enabled.
type: bool
aliases: [ infrastructure_vlan ]
version_added: '2.5'
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
default: present
choices: [ absent, present, query ]
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
seealso:
- module: aci_aep_to_domain
- name: APIC Management Information Model reference
description: More information about the internal APIC classes B(infra:AttEntityP) and B(infra:ProvAcc).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Swetha Chunduri (@schunduri)
'''
EXAMPLES = r'''
- name: Add a new AEP
aci_aep:
host: apic
username: admin
password: SomeSecretPassword
aep: ACI-AEP
description: default
state: present
delegate_to: localhost
- name: Remove an existing AEP
aci_aep:
host: apic
username: admin
password: SomeSecretPassword
aep: ACI-AEP
state: absent
delegate_to: localhost
- name: Query all AEPs
aci_aep:
host: apic
username: admin
password: SomeSecretPassword
state: query
delegate_to: localhost
register: query_result
- name: Query a specific AEP
aci_aep:
host: apic
username: admin
password: SomeSecretPassword
aep: ACI-AEP
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
aep=dict(type='str', aliases=['name', 'aep_name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
infra_vlan=dict(type='bool', aliases=['infrastructure_vlan']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['aep']],
['state', 'present', ['aep']],
],
)
aep = module.params.get('aep')
description = module.params.get('description')
infra_vlan = module.params.get('infra_vlan')
state = module.params.get('state')
name_alias = module.params.get('name_alias')
if infra_vlan:
child_configs = [dict(infraProvAcc=dict(attributes=dict(name='provacc')))]
elif infra_vlan is False:
child_configs = [dict(infraProvAcc=dict(attributes=dict(name='provacc', status='deleted')))]
else:
child_configs = []
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='infraAttEntityP',
aci_rn='infra/attentp-{0}'.format(aep),
module_object=aep,
target_filter={'name': aep},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='infraAttEntityP',
class_config=dict(
name=aep,
descr=description,
nameAlias=name_alias,
),
child_configs=child_configs,
)
aci.get_diff(aci_class='infraAttEntityP')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,312 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Dag Wieers <dag@wieers.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_aep_to_domain
short_description: Bind AEPs to Physical or Virtual Domains (infra:RsDomP)
description:
- Bind AEPs to Physical or Virtual Domains on Cisco ACI fabrics.
version_added: '2.5'
options:
aep:
description:
- The name of the Attachable Access Entity Profile.
type: str
aliases: [ aep_name ]
domain:
description:
- Name of the physical or virtual domain being associated with the AEP.
type: str
aliases: [ domain_name, domain_profile ]
domain_type:
description:
- Determines if the Domain is physical (phys) or virtual (vmm).
type: str
choices: [ fc, l2dom, l3dom, phys, vmm ]
aliases: [ type ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
vm_provider:
description:
- The VM platform for VMM Domains.
- Support for Kubernetes was added in ACI v3.0.
- Support for CloudFoundry, OpenShift and Red Hat was added in ACI v3.1.
type: str
choices: [ cloudfoundry, kubernetes, microsoft, openshift, openstack, redhat, vmware ]
extends_documentation_fragment: aci
notes:
- The C(aep) and C(domain) parameters should exist before using this module.
The M(aci_aep) and M(aci_domain) can be used for these.
seealso:
- module: aci_aep
- module: aci_domain
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(infra:RsDomP).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Dag Wieers (@dagwieers)
'''
EXAMPLES = r'''
- name: Add AEP to domain binding
aci_aep_to_domain: &binding_present
host: apic
username: admin
password: SomeSecretPassword
aep: test_aep
domain: phys_dom
domain_type: phys
state: present
delegate_to: localhost
- name: Remove AEP to domain binding
aci_aep_to_domain: &binding_absent
host: apic
username: admin
password: SomeSecretPassword
aep: test_aep
domain: phys_dom
domain_type: phys
state: absent
delegate_to: localhost
- name: Query our AEP to domain binding
aci_aep_to_domain:
host: apic
username: admin
password: SomeSecretPassword
aep: test_aep
domain: phys_dom
domain_type: phys
state: query
delegate_to: localhost
register: query_result
- name: Query all AEP to domain bindings
aci_aep_to_domain: &binding_query
host: apic
username: admin
password: SomeSecretPassword
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
VM_PROVIDER_MAPPING = dict(
cloudfoundry='CloudFoundry',
kubernetes='Kubernetes',
microsoft='Microsoft',
openshift='OpenShift',
openstack='OpenStack',
redhat='Redhat',
vmware='VMware',
)
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
aep=dict(type='str', aliases=['aep_name']), # Not required for querying all objects
domain=dict(type='str', aliases=['domain_name', 'domain_profile']), # Not required for querying all objects
domain_type=dict(type='str', choices=['fc', 'l2dom', 'l3dom', 'phys', 'vmm'], aliases=['type']), # Not required for querying all objects
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
vm_provider=dict(type='str', choices=['cloudfoundry', 'kubernetes', 'microsoft', 'openshift', 'openstack', 'redhat', 'vmware']),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['domain_type', 'vmm', ['vm_provider']],
['state', 'absent', ['aep', 'domain', 'domain_type']],
['state', 'present', ['aep', 'domain', 'domain_type']],
],
required_together=[
['domain', 'domain_type'],
],
)
aep = module.params.get('aep')
domain = module.params.get('domain')
domain_type = module.params.get('domain_type')
vm_provider = module.params.get('vm_provider')
state = module.params.get('state')
# Report when vm_provider is set when type is not virtual
if domain_type != 'vmm' and vm_provider is not None:
module.fail_json(msg="Domain type '{0}' cannot have a 'vm_provider'".format(domain_type))
# Compile the full domain for URL building
if domain_type == 'fc':
domain_mo = 'uni/fc-{0}'.format(domain)
elif domain_type == 'l2dom':
domain_mo = 'uni/l2dom-{0}'.format(domain)
elif domain_type == 'l3dom':
domain_mo = 'uni/l3dom-{0}'.format(domain)
elif domain_type == 'phys':
domain_mo = 'uni/phys-{0}'.format(domain)
elif domain_type == 'vmm':
domain_mo = 'uni/vmmp-{0}/dom-{1}'.format(VM_PROVIDER_MAPPING[vm_provider], domain)
else:
domain_mo = None
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='infraAttEntityP',
aci_rn='infra/attentp-{0}'.format(aep),
module_object=aep,
target_filter={'name': aep},
),
subclass_1=dict(
aci_class='infraRsDomP',
aci_rn='rsdomP-[{0}]'.format(domain_mo),
module_object=domain_mo,
target_filter={'tDn': domain_mo},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='infraRsDomP',
class_config=dict(tDn=domain_mo),
)
aci.get_diff(aci_class='infraRsDomP')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,280 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_ap
short_description: Manage top level Application Profile (AP) objects (fv:Ap)
description:
- Manage top level Application Profile (AP) objects on Cisco ACI fabrics
version_added: '2.4'
options:
tenant:
description:
- The name of an existing tenant.
type: str
required: yes
aliases: [ tenant_name ]
ap:
description:
- The name of the application network profile.
type: str
required: yes
aliases: [ app_profile, app_profile_name, name ]
description:
description:
- Description for the AP.
type: str
aliases: [ descr ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
notes:
- This module does not manage EPGs, see M(aci_epg) to do this.
- The used C(tenant) must exist before using this module in your playbook.
The M(aci_tenant) module can be used for this.
seealso:
- module: aci_tenant
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(fv:Ap).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Swetha Chunduri (@schunduri)
'''
EXAMPLES = r'''
- name: Add a new AP
aci_ap:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
ap: default
description: default ap
state: present
delegate_to: localhost
- name: Remove an AP
aci_ap:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
ap: default
state: absent
delegate_to: localhost
- name: Query an AP
aci_ap:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
ap: default
state: query
delegate_to: localhost
register: query_result
- name: Query all APs
aci_ap:
host: apic
username: admin
password: SomeSecretPassword
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
ap=dict(type='str', aliases=['app_profile', 'app_profile_name', 'name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['tenant', 'ap']],
['state', 'present', ['tenant', 'ap']],
],
)
ap = module.params.get('ap')
description = module.params.get('description')
state = module.params.get('state')
tenant = module.params.get('tenant')
name_alias = module.params.get('name_alias')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='fvAp',
aci_rn='ap-{0}'.format(ap),
module_object=ap,
target_filter={'name': ap},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='fvAp',
class_config=dict(
name=ap,
descr=description,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='fvAp')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,462 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_bd
short_description: Manage Bridge Domains (BD) objects (fv:BD)
description:
- Manages Bridge Domains (BD) on Cisco ACI fabrics.
version_added: '2.4'
options:
arp_flooding:
description:
- Determines if the Bridge Domain should flood ARP traffic.
- The APIC defaults to C(no) when unset during creation.
type: bool
bd:
description:
- The name of the Bridge Domain.
type: str
aliases: [ bd_name, name ]
bd_type:
description:
- The type of traffic on the Bridge Domain.
- The APIC defaults to C(ethernet) when unset during creation.
type: str
choices: [ ethernet, fc ]
description:
description:
- Description for the Bridge Domain.
type: str
enable_multicast:
description:
- Determines if PIM is enabled.
- The APIC defaults to C(no) when unset during creation.
type: bool
enable_routing:
description:
- Determines if IP forwarding should be allowed.
- The APIC defaults to C(yes) when unset during creation.
type: bool
endpoint_clear:
description:
- Clears all End Points in all Leaves when C(yes).
- The value is not reset to disabled once End Points have been cleared; that requires a second task.
- The APIC defaults to C(no) when unset during creation.
type: bool
endpoint_move_detect:
description:
- Determines if GARP should be enabled to detect when End Points move.
- The APIC defaults to C(garp) when unset during creation.
type: str
choices: [ default, garp ]
endpoint_retention_action:
description:
- Determines if the Bridge Domain should inherit or resolve the End Point Retention Policy.
- The APIC defaults to C(resolve) when unset during creation.
type: str
choices: [ inherit, resolve ]
endpoint_retention_policy:
description:
- The name of the End Point Retention Policy the Bridge Domain should use when
overriding the default End Point Retention Policy.
type: str
igmp_snoop_policy:
description:
- The name of the IGMP Snooping Policy the Bridge Domain should use when
overriding the default IGMP Snooping Policy.
type: str
ip_learning:
description:
- Determines if the Bridge Domain should learn End Point IPs.
- The APIC defaults to C(yes) when unset during creation.
type: bool
ipv6_nd_policy:
description:
- The name of the IPv6 Neighbor Discovery Policy the Bridge Domain should use when
overridding the default IPV6 ND Policy.
type: str
l2_unknown_unicast:
description:
- Determines what forwarding method to use for unknown l2 destinations.
- The APIC defaults to C(proxy) when unset during creation.
type: str
choices: [ proxy, flood ]
l3_unknown_multicast:
description:
- Determines the forwarding method to use for unknown multicast destinations.
- The APIC defaults to C(flood) when unset during creation.
type: str
choices: [ flood, opt-flood ]
limit_ip_learn:
description:
- Determines if the BD should limit IP learning to only subnets owned by the Bridge Domain.
- The APIC defaults to C(yes) when unset during creation.
type: bool
mac_address:
description:
- The MAC Address to assign to the C(bd) instead of using the default.
- The APIC defaults to C(00:22:BD:F8:19:FF) when unset during creation.
type: str
aliases: [ mac ]
version_added: '2.5'
multi_dest:
description:
- Determines the forwarding method for L2 multicast, broadcast, and link layer traffic.
- The APIC defaults to C(bd-flood) when unset during creation.
type: str
choices: [ bd-flood, drop, encap-flood ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
tenant:
description:
- The name of the Tenant.
type: str
aliases: [ tenant_name ]
vrf:
description:
- The name of the VRF.
type: str
aliases: [ vrf_name ]
extends_documentation_fragment: aci
notes:
- The C(tenant) used must exist before using this module in your playbook.
The M(aci_tenant) module can be used for this.
seealso:
- module: aci_tenant
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(fv:BD).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Jacob McGill (@jmcgill298)
'''
EXAMPLES = r'''
- name: Add Bridge Domain
aci_bd:
host: "{{ inventory_hostname }}"
username: "{{ username }}"
password: "{{ password }}"
validate_certs: no
tenant: prod
bd: web_servers
mac_address: 00:22:BD:F8:19:FE
vrf: prod_vrf
state: present
delegate_to: localhost
- name: Add an FC Bridge Domain
aci_bd:
host: "{{ inventory_hostname }}"
username: "{{ username }}"
password: "{{ password }}"
validate_certs: no
tenant: prod
bd: storage
bd_type: fc
vrf: fc_vrf
enable_routing: no
state: present
delegate_to: localhost
- name: Modify a Bridge Domain
aci_bd:
host: "{{ inventory_hostname }}"
username: "{{ username }}"
password: "{{ password }}"
validate_certs: yes
tenant: prod
bd: web_servers
arp_flooding: yes
l2_unknown_unicast: flood
state: present
delegate_to: localhost
- name: Query All Bridge Domains
aci_bd:
host: "{{ inventory_hostname }}"
username: "{{ username }}"
password: "{{ password }}"
validate_certs: yes
state: query
delegate_to: localhost
register: query_result
- name: Query a Bridge Domain
aci_bd:
host: "{{ inventory_hostname }}"
username: "{{ username }}"
password: "{{ password }}"
validate_certs: yes
tenant: prod
bd: web_servers
state: query
delegate_to: localhost
register: query_result
- name: Delete a Bridge Domain
aci_bd:
host: "{{ inventory_hostname }}"
username: "{{ username }}"
password: "{{ password }}"
validate_certs: yes
tenant: prod
bd: web_servers
state: absent
delegate_to: localhost
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
arp_flooding=dict(type='bool'),
bd=dict(type='str', aliases=['bd_name', 'name']), # Not required for querying all objects
bd_type=dict(type='str', choices=['ethernet', 'fc']),
description=dict(type='str'),
enable_multicast=dict(type='bool'),
enable_routing=dict(type='bool'),
endpoint_clear=dict(type='bool'),
endpoint_move_detect=dict(type='str', choices=['default', 'garp']),
endpoint_retention_action=dict(type='str', choices=['inherit', 'resolve']),
endpoint_retention_policy=dict(type='str'),
igmp_snoop_policy=dict(type='str'),
ip_learning=dict(type='bool'),
ipv6_nd_policy=dict(type='str'),
l2_unknown_unicast=dict(type='str', choices=['proxy', 'flood']),
l3_unknown_multicast=dict(type='str', choices=['flood', 'opt-flood']),
limit_ip_learn=dict(type='bool'),
mac_address=dict(type='str', aliases=['mac']),
multi_dest=dict(type='str', choices=['bd-flood', 'drop', 'encap-flood']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
vrf=dict(type='str', aliases=['vrf_name']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['bd', 'tenant']],
['state', 'present', ['bd', 'tenant']],
],
)
aci = ACIModule(module)
arp_flooding = aci.boolean(module.params.get('arp_flooding'))
bd = module.params.get('bd')
bd_type = module.params.get('bd_type')
if bd_type == 'ethernet':
# ethernet type is represented as regular, but that is not clear to the users
bd_type = 'regular'
description = module.params.get('description')
enable_multicast = aci.boolean(module.params.get('enable_multicast'))
enable_routing = aci.boolean(module.params.get('enable_routing'))
endpoint_clear = aci.boolean(module.params.get('endpoint_clear'))
endpoint_move_detect = module.params.get('endpoint_move_detect')
if endpoint_move_detect == 'default':
# the ACI default setting is an empty string, but that is not a good input value
endpoint_move_detect = ''
endpoint_retention_action = module.params.get('endpoint_retention_action')
endpoint_retention_policy = module.params.get('endpoint_retention_policy')
igmp_snoop_policy = module.params.get('igmp_snoop_policy')
ip_learning = aci.boolean(module.params.get('ip_learning'))
ipv6_nd_policy = module.params.get('ipv6_nd_policy')
l2_unknown_unicast = module.params.get('l2_unknown_unicast')
l3_unknown_multicast = module.params.get('l3_unknown_multicast')
limit_ip_learn = aci.boolean(module.params.get('limit_ip_learn'))
mac_address = module.params.get('mac_address')
multi_dest = module.params.get('multi_dest')
state = module.params.get('state')
tenant = module.params.get('tenant')
vrf = module.params.get('vrf')
name_alias = module.params.get('name_alias')
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='fvBD',
aci_rn='BD-{0}'.format(bd),
module_object=bd,
target_filter={'name': bd},
),
child_classes=['fvRsCtx', 'fvRsIgmpsn', 'fvRsBDToNdP', 'fvRsBdToEpRet'],
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='fvBD',
class_config=dict(
arpFlood=arp_flooding,
descr=description,
epClear=endpoint_clear,
epMoveDetectMode=endpoint_move_detect,
ipLearning=ip_learning,
limitIpLearnToSubnets=limit_ip_learn,
mac=mac_address,
mcastAllow=enable_multicast,
multiDstPktAct=multi_dest,
name=bd,
type=bd_type,
unicastRoute=enable_routing,
unkMacUcastAct=l2_unknown_unicast,
unkMcastAct=l3_unknown_multicast,
nameAlias=name_alias,
),
child_configs=[
{'fvRsCtx': {'attributes': {'tnFvCtxName': vrf}}},
{'fvRsIgmpsn': {'attributes': {'tnIgmpSnoopPolName': igmp_snoop_policy}}},
{'fvRsBDToNdP': {'attributes': {'tnNdIfPolName': ipv6_nd_policy}}},
{'fvRsBdToEpRet': {'attributes': {'resolveAct': endpoint_retention_action, 'tnFvEpRetPolName': endpoint_retention_policy}}},
],
)
aci.get_diff(aci_class='fvBD')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,466 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_bd_subnet
short_description: Manage Subnets (fv:Subnet)
description:
- Manage Subnets on Cisco ACI fabrics.
version_added: '2.4'
options:
bd:
description:
- The name of the Bridge Domain.
type: str
aliases: [ bd_name ]
description:
description:
- The description for the Subnet.
type: str
aliases: [ descr ]
enable_vip:
description:
- Determines if the Subnet should be treated as a VIP; used when the BD is extended to multiple sites.
- The APIC defaults to C(no) when unset during creation.
type: bool
gateway:
description:
- The IPv4 or IPv6 gateway address for the Subnet.
type: str
aliases: [ gateway_ip ]
mask:
description:
- The subnet mask for the Subnet.
- This is the number associated with CIDR notation.
- For IPv4 addresses, accepted values range between C(0) and C(32).
- For IPv6 addresses, accepted Values range between C(0) and C(128).
type: int
aliases: [ subnet_mask ]
nd_prefix_policy:
description:
- The IPv6 Neighbor Discovery Prefix Policy to associate with the Subnet.
type: str
preferred:
description:
- Determines if the Subnet is preferred over all available Subnets. Only one Subnet per Address Family (IPv4/IPv6).
can be preferred in the Bridge Domain.
- The APIC defaults to C(no) when unset during creation.
type: bool
route_profile:
description:
- The Route Profile to the associate with the Subnet.
type: str
route_profile_l3_out:
description:
- The L3 Out that contains the associated Route Profile.
type: str
scope:
description:
- Determines the scope of the Subnet.
- The C(private) option only allows communication with hosts in the same VRF.
- The C(public) option allows the Subnet to be advertised outside of the ACI Fabric, and allows communication with
hosts in other VRFs.
- The shared option limits communication to hosts in either the same VRF or the shared VRF.
- The value is a list of options, C(private) and C(public) are mutually exclusive, but both can be used with C(shared).
- The APIC defaults to C(private) when unset during creation.
type: list
choices:
- private
- public
- shared
subnet_control:
description:
- Determines the Subnet's Control State.
- The C(querier_ip) option is used to treat the gateway_ip as an IGMP querier source IP.
- The C(nd_ra) option is used to treat the gateway_ip address as a Neighbor Discovery Router Advertisement Prefix.
- The C(no_gw) option is used to remove default gateway functionality from the gateway address.
- The APIC defaults to C(nd_ra) when unset during creation.
type: str
choices: [ nd_ra, no_gw, querier_ip, unspecified ]
subnet_name:
description:
- The name of the Subnet.
type: str
aliases: [ name ]
tenant:
description:
- The name of the Tenant.
type: str
aliases: [ tenant_name ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
notes:
- The C(gateway) parameter is the root key used to access the Subnet (not name), so the C(gateway)
is required when the state is C(absent) or C(present).
- The C(tenant) and C(bd) used must exist before using this module in your playbook.
The M(aci_tenant) module and M(aci_bd) can be used for these.
seealso:
- module: aci_bd
- module: aci_tenant
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(fv:Subnet).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Jacob McGill (@jmcgill298)
'''
EXAMPLES = r'''
- name: Create a tenant
aci_tenant:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
state: present
delegate_to: localhost
- name: Create a bridge domain
aci_bd:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
bd: database
state: present
delegate_to: localhost
- name: Create a subnet
aci_bd_subnet:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
bd: database
gateway: 10.1.1.1
mask: 24
state: present
delegate_to: localhost
- name: Create a subnet with options
aci_bd_subnet:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
bd: database
subnet_name: sql
gateway: 10.1.2.1
mask: 23
description: SQL Servers
scope: public
route_profile_l3_out: corp
route_profile: corp_route_profile
state: present
delegate_to: localhost
- name: Update a subnets scope to private and shared
aci_bd_subnet:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
bd: database
gateway: 10.1.1.1
mask: 24
scope: [private, shared]
state: present
delegate_to: localhost
- name: Get all subnets
aci_bd_subnet:
host: apic
username: admin
password: SomeSecretPassword
state: query
delegate_to: localhost
- name: Get all subnets of specific gateway in specified tenant
aci_bd_subnet:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
gateway: 10.1.1.1
mask: 24
state: query
delegate_to: localhost
register: query_result
- name: Get specific subnet
aci_bd_subnet:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
bd: database
gateway: 10.1.1.1
mask: 24
state: query
delegate_to: localhost
register: query_result
- name: Delete a subnet
aci_bd_subnet:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
bd: database
gateway: 10.1.1.1
mask: 24
state: absent
delegate_to: localhost
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
SUBNET_CONTROL_MAPPING = dict(
nd_ra='nd',
no_gw='no-default-gateway',
querier_ip='querier',
unspecified='',
)
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
bd=dict(type='str', aliases=['bd_name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
enable_vip=dict(type='bool'),
gateway=dict(type='str', aliases=['gateway_ip']), # Not required for querying all objects
mask=dict(type='int', aliases=['subnet_mask']), # Not required for querying all objects
subnet_name=dict(type='str', aliases=['name']),
nd_prefix_policy=dict(type='str'),
preferred=dict(type='bool'),
route_profile=dict(type='str'),
route_profile_l3_out=dict(type='str'),
scope=dict(type='list', choices=['private', 'public', 'shared']),
subnet_control=dict(type='str', choices=['nd_ra', 'no_gw', 'querier_ip', 'unspecified']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_together=[['gateway', 'mask']],
required_if=[
['state', 'present', ['bd', 'gateway', 'mask', 'tenant']],
['state', 'absent', ['bd', 'gateway', 'mask', 'tenant']],
],
)
aci = ACIModule(module)
description = module.params.get('description')
enable_vip = aci.boolean(module.params.get('enable_vip'))
tenant = module.params.get('tenant')
bd = module.params.get('bd')
gateway = module.params.get('gateway')
mask = module.params.get('mask')
if mask is not None and mask not in range(0, 129):
# TODO: split checks between IPv4 and IPv6 Addresses
module.fail_json(msg='Valid Subnet Masks are 0 to 32 for IPv4 Addresses and 0 to 128 for IPv6 addresses')
if gateway is not None:
gateway = '{0}/{1}'.format(gateway, str(mask))
subnet_name = module.params.get('subnet_name')
nd_prefix_policy = module.params.get('nd_prefix_policy')
preferred = aci.boolean(module.params.get('preferred'))
route_profile = module.params.get('route_profile')
route_profile_l3_out = module.params.get('route_profile_l3_out')
scope = module.params.get('scope')
if scope is not None:
if 'private' in scope and 'public' in scope:
module.fail_json(msg="Parameter 'scope' cannot be both 'private' and 'public', got: %s" % scope)
else:
scope = ','.join(sorted(scope))
state = module.params.get('state')
subnet_control = module.params.get('subnet_control')
if subnet_control:
subnet_control = SUBNET_CONTROL_MAPPING[subnet_control]
name_alias = module.params.get('name_alias')
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='fvBD',
aci_rn='BD-{0}'.format(bd),
module_object=bd,
target_filter={'name': bd},
),
subclass_2=dict(
aci_class='fvSubnet',
aci_rn='subnet-[{0}]'.format(gateway),
module_object=gateway,
target_filter={'ip': gateway},
),
child_classes=['fvRsBDSubnetToProfile', 'fvRsNdPfxPol'],
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='fvSubnet',
class_config=dict(
ctrl=subnet_control,
descr=description,
ip=gateway,
name=subnet_name,
preferred=preferred,
scope=scope,
virtual=enable_vip,
nameAlias=name_alias,
),
child_configs=[
{'fvRsBDSubnetToProfile': {'attributes': {'tnL3extOutName': route_profile_l3_out, 'tnRtctrlProfileName': route_profile}}},
{'fvRsNdPfxPol': {'attributes': {'tnNdPfxPolName': nd_prefix_policy}}},
],
)
aci.get_diff(aci_class='fvSubnet')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,239 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_bd_to_l3out
short_description: Bind Bridge Domain to L3 Out (fv:RsBDToOut)
description:
- Bind Bridge Domain to L3 Out on Cisco ACI fabrics.
version_added: '2.4'
options:
bd:
description:
- The name of the Bridge Domain.
type: str
aliases: [ bd_name, bridge_domain ]
l3out:
description:
- The name of the l3out to associate with th Bridge Domain.
type: str
tenant:
description:
- The name of the Tenant.
type: str
aliases: [ tenant_name ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
extends_documentation_fragment: aci
notes:
- The C(bd) and C(l3out) parameters should exist before using this module.
The M(aci_bd) and C(aci_l3out) can be used for these.
seealso:
- module: aci_bd
- module: aci_l3out
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(fv:RsBDToOut).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Jacob McGill (@jmcgill298)
'''
EXAMPLES = r''' # '''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
SUBNET_CONTROL_MAPPING = dict(
nd_ra='nd',
no_gw='no-default-gateway',
querier_ip='querier',
unspecified='',
)
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
bd=dict(type='str', aliases=['bd_name', 'bridge_domain']), # Not required for querying all objects
l3out=dict(type='str'), # Not required for querying all objects
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_together=[['gateway', 'mask']],
required_if=[
['state', 'present', ['bd', 'l3out', 'tenant']],
['state', 'absent', ['bd', 'l3out', 'tenant']],
],
)
bd = module.params.get('bd')
l3out = module.params.get('l3out')
state = module.params.get('state')
tenant = module.params.get('tenant')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='fvBD',
aci_rn='BD-{0}'.format(bd),
module_object=bd,
target_filter={'name': bd},
),
subclass_2=dict(
aci_class='fvRsBDToOut',
aci_rn='rsBDToOut-{0}'.format(l3out),
module_object=l3out,
target_filter={'tnL3extOutName': l3out},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='fvRsBDToOut',
class_config=dict(tnL3extOutName=l3out),
)
aci.get_diff(aci_class='fvRsBDToOut')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,321 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_config_rollback
short_description: Provides rollback and rollback preview functionality (config:ImportP)
description:
- Provides rollback and rollback preview functionality for Cisco ACI fabrics.
- Config Rollbacks are done using snapshots C(aci_snapshot) with the configImportP class.
version_added: '2.4'
options:
compare_export_policy:
description:
- The export policy that the C(compare_snapshot) is associated to.
type: str
compare_snapshot:
description:
- The name of the snapshot to compare with C(snapshot).
type: str
description:
description:
- The description for the Import Policy.
type: str
aliases: [ descr ]
export_policy:
description:
- The export policy that the C(snapshot) is associated to.
type: str
required: yes
fail_on_decrypt:
description:
- Determines if the APIC should fail the rollback if unable to decrypt secured data.
- The APIC defaults to C(yes) when unset.
type: bool
import_mode:
description:
- Determines how the import should be handled by the APIC.
- The APIC defaults to C(atomic) when unset.
type: str
choices: [ atomic, best-effort ]
import_policy:
description:
- The name of the Import Policy to use for config rollback.
type: str
import_type:
description:
- Determines how the current and snapshot configuration should be compared for replacement.
- The APIC defaults to C(replace) when unset.
type: str
choices: [ merge, replace ]
snapshot:
description:
- The name of the snapshot to rollback to, or the base snapshot to use for comparison.
- The C(aci_snapshot) module can be used to query the list of available snapshots.
type: str
required: yes
state:
description:
- Use C(preview) for previewing the diff between two snapshots.
- Use C(rollback) for reverting the configuration to a previous snapshot.
type: str
choices: [ preview, rollback ]
default: rollback
extends_documentation_fragment: aci
seealso:
- module: aci_config_snapshot
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(config:ImportP).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Jacob McGill (@jmcgill298)
'''
EXAMPLES = r'''
---
- name: Create a Snapshot
aci_config_snapshot:
host: apic
username: admin
password: SomeSecretPassword
export_policy: config_backup
state: present
delegate_to: localhost
- name: Query Existing Snapshots
aci_config_snapshot:
host: apic
username: admin
password: SomeSecretPassword
export_policy: config_backup
state: query
delegate_to: localhost
- name: Compare Snapshot Files
aci_config_rollback:
host: apic
username: admin
password: SomeSecretPassword
export_policy: config_backup
snapshot: run-2017-08-28T06-24-01
compare_export_policy: config_backup
compare_snapshot: run-2017-08-27T23-43-56
state: preview
delegate_to: localhost
- name: Rollback Configuration
aci_config_rollback:
host: apic
username: admin
password: SomeSecretPassword
import_policy: rollback_config
export_policy: config_backup
snapshot: run-2017-08-28T06-24-01
state: rollback
delegate_to: localhost
- name: Rollback Configuration
aci_config_rollback:
host: apic
username: admin
password: SomeSecretPassword
import_policy: rollback_config
export_policy: config_backup
snapshot: run-2017-08-28T06-24-01
description: Rollback 8-27 changes
import_mode: atomic
import_type: replace
fail_on_decrypt: yes
state: rollback
delegate_to: localhost
'''
RETURN = r'''
preview:
description: A preview between two snapshots
returned: when state is preview
type: str
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_bytes
from ansible.module_utils.urls import fetch_url
# Optional, only used for rollback preview
try:
import lxml.etree
from xmljson import cobra
XML_TO_JSON = True
except ImportError:
XML_TO_JSON = False
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
compare_export_policy=dict(type='str'),
compare_snapshot=dict(type='str'),
description=dict(type='str', aliases=['descr']),
export_policy=dict(type='str'),
fail_on_decrypt=dict(type='bool'),
import_mode=dict(type='str', choices=['atomic', 'best-effort']),
import_policy=dict(type='str'),
import_type=dict(type='str', choices=['merge', 'replace']),
snapshot=dict(type='str', required=True),
state=dict(type='str', default='rollback', choices=['preview', 'rollback']),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=False,
required_if=[
['state', 'preview', ['compare_export_policy', 'compare_snapshot']],
['state', 'rollback', ['import_policy']],
],
)
aci = ACIModule(module)
description = module.params.get('description')
export_policy = module.params.get('export_policy')
fail_on_decrypt = aci.boolean(module.params.get('fail_on_decrypt'))
import_mode = module.params.get('import_mode')
import_policy = module.params.get('import_policy')
import_type = module.params.get('import_type')
snapshot = module.params.get('snapshot')
state = module.params.get('state')
if state == 'rollback':
if snapshot.startswith('run-'):
snapshot = snapshot.replace('run-', '', 1)
if not snapshot.endswith('.tar.gz'):
snapshot += '.tar.gz'
filename = 'ce2_{0}-{1}'.format(export_policy, snapshot)
aci.construct_url(
root_class=dict(
aci_class='configImportP',
aci_rn='fabric/configimp-{0}'.format(import_policy),
module_object=import_policy,
target_filter={'name': import_policy},
),
)
aci.get_existing()
aci.payload(
aci_class='configImportP',
class_config=dict(
adminSt='triggered',
descr=description,
failOnDecryptErrors=fail_on_decrypt,
fileName=filename,
importMode=import_mode,
importType=import_type,
name=import_policy,
snapshot='yes',
),
)
aci.get_diff(aci_class='configImportP')
aci.post_config()
elif state == 'preview':
aci.url = '%(protocol)s://%(host)s/mqapi2/snapshots.diff.xml' % module.params
aci.filter_string = (
'?s1dn=uni/backupst/snapshots-[uni/fabric/configexp-%(export_policy)s]/snapshot-%(snapshot)s&'
's2dn=uni/backupst/snapshots-[uni/fabric/configexp-%(compare_export_policy)s]/snapshot-%(compare_snapshot)s'
) % module.params
# Generate rollback comparison
get_preview(aci)
aci.exit_json()
def get_preview(aci):
'''
This function is used to generate a preview between two snapshots and add the parsed results to the aci module return data.
'''
uri = aci.url + aci.filter_string
resp, info = fetch_url(aci.module, uri, headers=aci.headers, method='GET', timeout=aci.module.params.get('timeout'),
use_proxy=aci.module.params.get('use_proxy'))
aci.method = 'GET'
aci.response = info.get('msg')
aci.status = info.get('status')
# Handle APIC response
if info.get('status') == 200:
xml_to_json(aci, resp.read())
else:
aci.result['raw'] = resp.read()
aci.fail_json(msg="Request failed: %(code)s %(text)s (see 'raw' output)" % aci.error)
def xml_to_json(aci, response_data):
'''
This function is used to convert preview XML data into JSON.
'''
if XML_TO_JSON:
xml = lxml.etree.fromstring(to_bytes(response_data))
xmldata = cobra.data(xml)
aci.result['preview'] = xmldata
else:
aci.result['preview'] = response_data
if __name__ == "__main__":
main()

@ -1,336 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_config_snapshot
short_description: Manage Config Snapshots (config:Snapshot, config:ExportP)
description:
- Manage Config Snapshots on Cisco ACI fabrics.
- Creating new Snapshots is done using the configExportP class.
- Removing Snapshots is done using the configSnapshot class.
version_added: '2.4'
options:
description:
description:
- The description for the Config Export Policy.
type: str
aliases: [ descr ]
export_policy:
description:
- The name of the Export Policy to use for Config Snapshots.
type: str
aliases: [ name ]
format:
description:
- Sets the config backup to be formatted in JSON or XML.
- The APIC defaults to C(json) when unset.
type: str
choices: [ json, xml ]
include_secure:
description:
- Determines if secure information should be included in the backup.
- The APIC defaults to C(yes) when unset.
type: bool
max_count:
description:
- Determines how many snapshots can exist for the Export Policy before the APIC starts to rollover.
- Accepted values range between C(1) and C(10).
- The APIC defaults to C(3) when unset.
type: int
snapshot:
description:
- The name of the snapshot to delete.
type: str
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
extends_documentation_fragment: aci
notes:
- The APIC does not provide a mechanism for naming the snapshots.
- 'Snapshot files use the following naming structure: ce_<config export policy name>-<yyyy>-<mm>-<dd>T<hh>:<mm>:<ss>.<mss>+<hh>:<mm>.'
- 'Snapshot objects use the following naming structure: run-<yyyy>-<mm>-<dd>T<hh>-<mm>-<ss>.'
seealso:
- module: aci_config_rollback
- name: APIC Management Information Model reference
description: More information about the internal APIC classes B(config:Snapshot) and B(config:ExportP).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Jacob McGill (@jmcgill298)
'''
EXAMPLES = r'''
- name: Create a Snapshot
aci_config_snapshot:
host: apic
username: admin
password: SomeSecretPassword
state: present
export_policy: config_backup
max_count: 10
description: Backups taken before new configs are applied.
delegate_to: localhost
- name: Query all Snapshots
aci_config_snapshot:
host: apic
username: admin
password: SomeSecretPassword
state: query
delegate_to: localhost
register: query_result
- name: Query Snapshots associated with a particular Export Policy
aci_config_snapshot:
host: apic
username: admin
password: SomeSecretPassword
export_policy: config_backup
state: query
delegate_to: localhost
register: query_result
- name: Delete a Snapshot
aci_config_snapshot:
host: apic
username: admin
password: SomeSecretPassword
export_policy: config_backup
snapshot: run-2017-08-24T17-20-05
state: absent
delegate_to: localhost
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
description=dict(type='str', aliases=['descr']),
export_policy=dict(type='str', aliases=['name']), # Not required for querying all objects
format=dict(type='str', choices=['json', 'xml']),
include_secure=dict(type='bool'),
max_count=dict(type='int'),
snapshot=dict(type='str'),
state=dict(type='str', choices=['absent', 'present', 'query'], default='present'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=False,
required_if=[
['state', 'absent', ['export_policy', 'snapshot']],
['state', 'present', ['export_policy']],
],
)
aci = ACIModule(module)
description = module.params.get('description')
export_policy = module.params.get('export_policy')
file_format = module.params.get('format')
include_secure = aci.boolean(module.params.get('include_secure'))
max_count = module.params.get('max_count')
if max_count is not None:
if max_count in range(1, 11):
max_count = str(max_count)
else:
module.fail_json(msg="Parameter 'max_count' must be a number between 1 and 10")
snapshot = module.params.get('snapshot')
if snapshot is not None and not snapshot.startswith('run-'):
snapshot = 'run-' + snapshot
state = module.params.get('state')
if state == 'present':
aci.construct_url(
root_class=dict(
aci_class='configExportP',
aci_rn='fabric/configexp-{0}'.format(export_policy),
module_object=export_policy,
target_filter={'name': export_policy},
),
)
aci.get_existing()
aci.payload(
aci_class='configExportP',
class_config=dict(
adminSt='triggered',
descr=description,
format=file_format,
includeSecureFields=include_secure,
maxSnapshotCount=max_count,
name=export_policy,
snapshot='yes',
),
)
aci.get_diff('configExportP')
# Create a new Snapshot
aci.post_config()
else:
# Prefix the proper url to export_policy
if export_policy is not None:
export_policy = 'uni/fabric/configexp-{0}'.format(export_policy)
aci.construct_url(
root_class=dict(
aci_class='configSnapshotCont',
aci_rn='backupst/snapshots-[{0}]'.format(export_policy),
module_object=export_policy,
target_filter={'name': export_policy},
),
subclass_1=dict(
aci_class='configSnapshot',
aci_rn='snapshot-{0}'.format(snapshot),
module_object=snapshot,
target_filter={'name': snapshot},
),
)
aci.get_existing()
if state == 'absent':
# Build POST request to used to remove Snapshot
aci.payload(
aci_class='configSnapshot',
class_config=dict(
name=snapshot,
retire="yes",
),
)
if aci.existing:
aci.get_diff('configSnapshot')
# Mark Snapshot for Deletion
aci.post_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,314 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_contract
short_description: Manage contract resources (vz:BrCP)
description:
- Manage Contract resources on Cisco ACI fabrics.
version_added: '2.4'
options:
contract:
description:
- The name of the contract.
type: str
required: yes
aliases: [ contract_name, name ]
description:
description:
- Description for the contract.
type: str
aliases: [ descr ]
tenant:
description:
- The name of the tenant.
type: str
required: yes
aliases: [ tenant_name ]
scope:
description:
- The scope of a service contract.
- The APIC defaults to C(context) when unset during creation.
type: str
choices: [ application-profile, context, global, tenant ]
priority:
description:
- The desired QoS class to be used.
- The APIC defaults to C(unspecified) when unset during creation.
type: str
choices: [ level1, level2, level3, unspecified ]
dscp:
description:
- The target Differentiated Service (DSCP) value.
- The APIC defaults to C(unspecified) when unset during creation.
type: str
choices: [ AF11, AF12, AF13, AF21, AF22, AF23, AF31, AF32, AF33, AF41, AF42, AF43, CS0, CS1, CS2, CS3, CS4, CS5, CS6, CS7, EF, VA, unspecified ]
aliases: [ target ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
notes:
- This module does not manage Contract Subjects, see M(aci_contract_subject) to do this.
Contract Subjects can still be removed using this module.
- The C(tenant) used must exist before using this module in your playbook.
The M(aci_tenant) module can be used for this.
seealso:
- module: aci_contract_subject
- module: aci_tenant
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(vz:BrCP).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Dag Wieers (@dagwieers)
'''
EXAMPLES = r'''
- name: Add a new contract
aci_contract:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
contract: web_to_db
description: Communication between web-servers and database
scope: application-profile
state: present
delegate_to: localhost
- name: Remove an existing contract
aci_contract:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
contract: web_to_db
state: absent
delegate_to: localhost
- name: Query a specific contract
aci_contract:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
contract: web_to_db
state: query
delegate_to: localhost
register: query_result
- name: Query all contracts
aci_contract:
host: apic
username: admin
password: SomeSecretPassword
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
contract=dict(type='str', aliases=['contract_name', 'name']), # Not required for querying all objects
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
scope=dict(type='str', choices=['application-profile', 'context', 'global', 'tenant']),
priority=dict(type='str', choices=['level1', 'level2', 'level3', 'unspecified']), # No default provided on purpose
dscp=dict(type='str',
choices=['AF11', 'AF12', 'AF13', 'AF21', 'AF22', 'AF23', 'AF31', 'AF32', 'AF33', 'AF41', 'AF42', 'AF43',
'CS0', 'CS1', 'CS2', 'CS3', 'CS4', 'CS5', 'CS6', 'CS7', 'EF', 'VA', 'unspecified'],
aliases=['target']), # No default provided on purpose
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['contract', 'tenant']],
['state', 'present', ['contract', 'tenant']],
],
)
contract = module.params.get('contract')
description = module.params.get('description')
scope = module.params.get('scope')
priority = module.params.get('priority')
dscp = module.params.get('dscp')
state = module.params.get('state')
tenant = module.params.get('tenant')
name_alias = module.params.get('name_alias')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='vzBrCP',
aci_rn='brc-{0}'.format(contract),
module_object=contract,
target_filter={'name': contract},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='vzBrCP',
class_config=dict(
name=contract,
descr=description,
scope=scope,
prio=priority,
targetDscp=dscp,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='vzBrCP')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,358 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_contract_subject
short_description: Manage initial Contract Subjects (vz:Subj)
description:
- Manage initial Contract Subjects on Cisco ACI fabrics.
version_added: '2.4'
options:
tenant:
description:
- The name of the tenant.
type: str
aliases: [ tenant_name ]
subject:
description:
- The contract subject name.
type: str
aliases: [ contract_subject, name, subject_name ]
contract:
description:
- The name of the Contract.
type: str
aliases: [ contract_name ]
reverse_filter:
description:
- Determines if the APIC should reverse the src and dst ports to allow the
return traffic back, since ACI is stateless filter.
- The APIC defaults to C(yes) when unset during creation.
type: bool
priority:
description:
- The QoS class.
- The APIC defaults to C(unspecified) when unset during creation.
type: str
choices: [ level1, level2, level3, unspecified ]
dscp:
description:
- The target DSCP.
- The APIC defaults to C(unspecified) when unset during creation.
type: str
choices: [ AF11, AF12, AF13, AF21, AF22, AF23, AF31, AF32, AF33, AF41, AF42, AF43,
CS0, CS1, CS2, CS3, CS4, CS5, CS6, CS7, EF, VA, unspecified ]
aliases: [ target ]
description:
description:
- Description for the contract subject.
type: str
aliases: [ descr ]
consumer_match:
description:
- The match criteria across consumers.
- The APIC defaults to C(at_least_one) when unset during creation.
type: str
choices: [ all, at_least_one, at_most_one, none ]
provider_match:
description:
- The match criteria across providers.
- The APIC defaults to C(at_least_one) when unset during creation.
type: str
choices: [ all, at_least_one, at_most_one, none ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
notes:
- The C(tenant) and C(contract) used must exist before using this module in your playbook.
The M(aci_tenant) and M(aci_contract) modules can be used for this.
seealso:
- module: aci_contract
- module: aci_tenant
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(vz:Subj).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Swetha Chunduri (@schunduri)
'''
EXAMPLES = r'''
- name: Add a new contract subject
aci_contract_subject:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
contract: web_to_db
subject: default
description: test
reverse_filter: yes
priority: level1
dscp: unspecified
state: present
register: query_result
- name: Remove a contract subject
aci_contract_subject:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
contract: web_to_db
subject: default
state: absent
delegate_to: localhost
- name: Query a contract subject
aci_contract_subject:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
contract: web_to_db
subject: default
state: query
delegate_to: localhost
register: query_result
- name: Query all contract subjects
aci_contract_subject:
host: apic
username: admin
password: SomeSecretPassword
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
MATCH_MAPPING = dict(
all='All',
at_least_one='AtleastOne',
at_most_one='AtmostOne',
none='None',
)
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
contract=dict(type='str', aliases=['contract_name']), # Not required for querying all objects
subject=dict(type='str', aliases=['contract_subject', 'name', 'subject_name']), # Not required for querying all objects
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
priority=dict(type='str', choices=['unspecified', 'level1', 'level2', 'level3']),
reverse_filter=dict(type='bool'),
dscp=dict(type='str', aliases=['target'],
choices=['AF11', 'AF12', 'AF13', 'AF21', 'AF22', 'AF23', 'AF31', 'AF32', 'AF33', 'AF41', 'AF42', 'AF43',
'CS0', 'CS1', 'CS2', 'CS3', 'CS4', 'CS5', 'CS6', 'CS7', 'EF', 'VA', 'unspecified']),
description=dict(type='str', aliases=['descr']),
consumer_match=dict(type='str', choices=['all', 'at_least_one', 'at_most_one', 'none']),
provider_match=dict(type='str', choices=['all', 'at_least_one', 'at_most_one', 'none']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['contract', 'subject', 'tenant']],
['state', 'present', ['contract', 'subject', 'tenant']],
],
)
aci = ACIModule(module)
subject = module.params.get('subject')
priority = module.params.get('priority')
reverse_filter = aci.boolean(module.params.get('reverse_filter'))
contract = module.params.get('contract')
dscp = module.params.get('dscp')
description = module.params.get('description')
consumer_match = module.params.get('consumer_match')
if consumer_match is not None:
consumer_match = MATCH_MAPPING.get(consumer_match)
provider_match = module.params.get('provider_match')
if provider_match is not None:
provider_match = MATCH_MAPPING.get(provider_match)
state = module.params.get('state')
tenant = module.params.get('tenant')
name_alias = module.params.get('name_alias')
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='vzBrCP',
aci_rn='brc-{0}'.format(contract),
module_object=contract,
target_filter={'name': contract},
),
subclass_2=dict(
aci_class='vzSubj',
aci_rn='subj-{0}'.format(subject),
module_object=subject,
target_filter={'name': subject},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='vzSubj',
class_config=dict(
name=subject,
prio=priority,
revFltPorts=reverse_filter,
targetDscp=dscp,
consMatchT=consumer_match,
provMatchT=provider_match,
descr=description,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='vzSubj')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,319 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_contract_subject_to_filter
short_description: Bind Contract Subjects to Filters (vz:RsSubjFiltAtt)
description:
- Bind Contract Subjects to Filters on Cisco ACI fabrics.
version_added: '2.4'
options:
contract:
description:
- The name of the contract.
type: str
aliases: [ contract_name ]
filter:
description:
- The name of the Filter to bind to the Subject.
type: str
aliases: [ filter_name ]
log:
description:
- Determines if the binding should be set to log.
- The APIC defaults to C(none) when unset during creation.
type: str
choices: [ log, none ]
aliases: [ directive ]
subject:
description:
- The name of the Contract Subject.
type: str
aliases: [ contract_subject, subject_name ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
tenant:
description:
- The name of the tenant.
type: str
required: yes
aliases: [ tenant_name ]
extends_documentation_fragment: aci
notes:
- The C(tenant), C(contract), C(subject), and C(filter_name) must exist before using this module in your playbook.
The M(aci_tenant), M(aci_contract), M(aci_contract_subject), and M(aci_filter) modules can be used for these.
seealso:
- module: aci_contract_subject
- module: aci_filter
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(vz:RsSubjFiltAtt).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Jacob McGill (@jmcgill298)
'''
EXAMPLES = r'''
- name: Add a new contract subject to filer binding
aci_contract_subject_to_filter:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
contract: web_to_db
subject: test
filter: '{{ filter }}'
log: '{{ log }}'
state: present
delegate_to: localhost
- name: Remove an existing contract subject to filter binding
aci_contract_subject_to_filter:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
contract: web_to_db
subject: test
filter: '{{ filter }}'
log: '{{ log }}'
state: present
delegate_to: localhost
- name: Query a specific contract subject to filter binding
aci_contract_subject_to_filter:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
contract: web_to_db
subject: test
filter: '{{ filter }}'
state: query
delegate_to: localhost
register: query_result
- name: Query all contract subject to filter bindings
aci_contract_subject_to_filter:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
contract: web_to_db
subject: test
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
contract=dict(type='str', aliases=['contract_name']), # Not required for querying all objects
filter=dict(type='str', aliases=['filter_name']), # Not required for querying all objects
subject=dict(type='str', aliases=['contract_subject', 'subject_name']), # Not required for querying all objects
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
log=dict(type='str', choices=['log', 'none'], aliases=['directive']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['contract', 'filter', 'subject', 'tenant']],
['state', 'present', ['contract', 'filter', 'subject', 'tenant']],
],
)
contract = module.params.get('contract')
filter_name = module.params.get('filter')
log = module.params.get('log')
subject = module.params.get('subject')
tenant = module.params.get('tenant')
state = module.params.get('state')
# Add subject_filter key to modul.params for building the URL
module.params['subject_filter'] = filter_name
# Convert log to empty string if none, as that is what API expects. An empty string is not a good option to present the user.
if log == 'none':
log = ''
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='vzBrCP',
aci_rn='brc-{0}'.format(contract),
module_object=contract,
target_filter={'name': contract},
),
subclass_2=dict(
aci_class='vzSubj',
aci_rn='subj-{0}'.format(subject),
module_object=subject,
target_filter={'name': subject},
),
subclass_3=dict(
aci_class='vzRsSubjFiltAtt',
aci_rn='rssubjFiltAtt-{0}'.format(filter_name),
module_object=filter_name,
target_filter={'tnVzFilterName': filter_name},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='vzRsSubjFiltAtt',
class_config=dict(
tnVzFilterName=filter_name,
directives=log,
),
)
aci.get_diff(aci_class='vzRsSubjFiltAtt')
aci.post_config()
elif state == 'absent':
aci.delete_config()
# Remove subject_filter used to build URL from module.params
module.params.pop('subject_filter')
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,394 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_domain
short_description: Manage physical, virtual, bridged, routed or FC domain profiles (phys:DomP, vmm:DomP, l2ext:DomP, l3ext:DomP, fc:DomP)
description:
- Manage physical, virtual, bridged, routed or FC domain profiles on Cisco ACI fabrics.
version_added: '2.5'
options:
domain:
description:
- Name of the physical, virtual, bridged routed or FC domain profile.
type: str
aliases: [ domain_name, domain_profile, name ]
domain_type:
description:
- The type of domain profile.
- 'C(fc): The FC domain profile is a policy pertaining to single FC Management domain'
- 'C(l2dom): The external bridged domain profile is a policy for managing L2 bridged infrastructure bridged outside the fabric.'
- 'C(l3dom): The external routed domain profile is a policy for managing L3 routed infrastructure outside the fabric.'
- 'C(phys): The physical domain profile stores the physical resources and encap resources that should be used for EPGs associated with this domain.'
- 'C(vmm): The VMM domain profile is a policy for grouping VM controllers with similar networking policy requirements.'
type: str
choices: [ fc, l2dom, l3dom, phys, vmm ]
aliases: [ type ]
dscp:
description:
- The target Differentiated Service (DSCP) value.
- The APIC defaults to C(unspecified) when unset during creation.
type: str
choices: [ AF11, AF12, AF13, AF21, AF22, AF23, AF31, AF32, AF33, AF41, AF42, AF43, CS0, CS1, CS2, CS3, CS4, CS5, CS6, CS7, EF, VA, unspecified ]
aliases: [ target ]
encap_mode:
description:
- The layer 2 encapsulation protocol to use with the virtual switch.
type: str
choices: [ unknown, vlan, vxlan ]
multicast_address:
description:
- The multicast IP address to use for the virtual switch.
type: str
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
vm_provider:
description:
- The VM platform for VMM Domains.
- Support for Kubernetes was added in ACI v3.0.
- Support for CloudFoundry, OpenShift and Red Hat was added in ACI v3.1.
type: str
choices: [ cloudfoundry, kubernetes, microsoft, openshift, openstack, redhat, vmware ]
vswitch:
description:
- The virtual switch to use for vmm domains.
- The APIC defaults to C(default) when unset during creation.
type: str
choices: [ avs, default, dvs, unknown ]
extends_documentation_fragment: aci
seealso:
- module: aci_aep_to_domain
- module: aci_domain_to_encap_pool
- module: aci_domain_to_vlan_pool
- name: APIC Management Information Model reference
description: More information about the internal APIC classes B(phys:DomP),
B(vmm:DomP), B(l2ext:DomP), B(l3ext:DomP) and B(fc:DomP)
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Dag Wieers (@dagwieers)
'''
EXAMPLES = r'''
- name: Add a new physical domain
aci_domain:
host: apic
username: admin
password: SomeSecretPassword
domain: phys_dom
domain_type: phys
state: present
- name: Remove a physical domain
aci_domain:
host: apic
username: admin
password: SomeSecretPassword
domain: phys_dom
domain_type: phys
state: absent
- name: Add a new VMM domain
aci_domain:
host: apic
username: admin
password: SomeSecretPassword
domain: hyperv_dom
domain_type: vmm
vm_provider: microsoft
state: present
delegate_to: localhost
- name: Remove a VMM domain
aci_domain:
host: apic
username: admin
password: SomeSecretPassword
domain: hyperv_dom
domain_type: vmm
vm_provider: microsoft
state: absent
delegate_to: localhost
- name: Query a specific physical domain
aci_domain:
host: apic
username: admin
password: SomeSecretPassword
domain: phys_dom
domain_type: phys
state: query
delegate_to: localhost
register: query_result
- name: Query all domains
aci_domain:
host: apic
username: admin
password: SomeSecretPassword
domain_type: phys
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
VM_PROVIDER_MAPPING = dict(
cloudfoundry='CloudFoundry',
kubernetes='Kubernetes',
microsoft='Microsoft',
openshift='OpenShift',
openstack='OpenStack',
redhat='Redhat',
vmware='VMware',
)
VSWITCH_MAPPING = dict(
avs='n1kv',
default='default',
dvs='default',
unknown='unknown',
)
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
domain_type=dict(type='str', required=True, choices=['fc', 'l2dom', 'l3dom', 'phys', 'vmm'], aliases=['type']),
domain=dict(type='str', aliases=['domain_name', 'domain_profile', 'name']), # Not required for querying all objects
dscp=dict(type='str',
choices=['AF11', 'AF12', 'AF13', 'AF21', 'AF22', 'AF23', 'AF31', 'AF32', 'AF33', 'AF41', 'AF42', 'AF43',
'CS0', 'CS1', 'CS2', 'CS3', 'CS4', 'CS5', 'CS6', 'CS7', 'EF', 'VA', 'unspecified'],
aliases=['target']),
encap_mode=dict(type='str', choices=['unknown', 'vlan', 'vxlan']),
multicast_address=dict(type='str'),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
vm_provider=dict(type='str', choices=['cloudfoundry', 'kubernetes', 'microsoft', 'openshift', 'openstack', 'redhat', 'vmware']),
vswitch=dict(type='str', choices=['avs', 'default', 'dvs', 'unknown']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['domain_type', 'vmm', ['vm_provider']],
['state', 'absent', ['domain', 'domain_type']],
['state', 'present', ['domain', 'domain_type']],
],
)
dscp = module.params.get('dscp')
domain = module.params.get('domain')
domain_type = module.params.get('domain_type')
encap_mode = module.params.get('encap_mode')
multicast_address = module.params.get('multicast_address')
vm_provider = module.params.get('vm_provider')
vswitch = module.params.get('vswitch')
if vswitch is not None:
vswitch = VSWITCH_MAPPING.get(vswitch)
state = module.params.get('state')
name_alias = module.params.get('name_alias')
if domain_type != 'vmm':
if vm_provider is not None:
module.fail_json(msg="Domain type '{0}' cannot have parameter 'vm_provider'".format(domain_type))
if encap_mode is not None:
module.fail_json(msg="Domain type '{0}' cannot have parameter 'encap_mode'".format(domain_type))
if multicast_address is not None:
module.fail_json(msg="Domain type '{0}' cannot have parameter 'multicast_address'".format(domain_type))
if vswitch is not None:
module.fail_json(msg="Domain type '{0}' cannot have parameter 'vswitch'".format(domain_type))
if dscp is not None and domain_type not in ['l2dom', 'l3dom']:
module.fail_json(msg="DSCP values can only be assigned to 'l2ext and 'l3ext' domains")
# Compile the full domain for URL building
if domain_type == 'fc':
domain_class = 'fcDomP'
domain_mo = 'uni/fc-{0}'.format(domain)
domain_rn = 'fc-{0}'.format(domain)
elif domain_type == 'l2dom':
domain_class = 'l2extDomP'
domain_mo = 'uni/l2dom-{0}'.format(domain)
domain_rn = 'l2dom-{0}'.format(domain)
elif domain_type == 'l3dom':
domain_class = 'l3extDomP'
domain_mo = 'uni/l3dom-{0}'.format(domain)
domain_rn = 'l3dom-{0}'.format(domain)
elif domain_type == 'phys':
domain_class = 'physDomP'
domain_mo = 'uni/phys-{0}'.format(domain)
domain_rn = 'phys-{0}'.format(domain)
elif domain_type == 'vmm':
domain_class = 'vmmDomP'
domain_mo = 'uni/vmmp-{0}/dom-{1}'.format(VM_PROVIDER_MAPPING.get(vm_provider), domain)
domain_rn = 'vmmp-{0}/dom-{1}'.format(VM_PROVIDER_MAPPING.get(vm_provider), domain)
# Ensure that querying all objects works when only domain_type is provided
if domain is None:
domain_mo = None
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class=domain_class,
aci_rn=domain_rn,
module_object=domain_mo,
target_filter={'name': domain},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class=domain_class,
class_config=dict(
encapMode=encap_mode,
mcastAddr=multicast_address,
mode=vswitch,
name=domain,
targetDscp=dscp,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class=domain_class)
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,376 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Dag Wieers <dag@wieers.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_domain_to_encap_pool
short_description: Bind Domain to Encap Pools (infra:RsVlanNs)
description:
- Bind Domain to Encap Pools on Cisco ACI fabrics.
notes:
- The C(domain) and C(encap_pool) parameters should exist before using this module.
The M(aci_domain) and M(aci_encap_pool) can be used for these.
version_added: '2.5'
options:
domain:
description:
- Name of the domain being associated with the Encap Pool.
type: str
aliases: [ domain_name, domain_profile ]
domain_type:
description:
- Determines if the Domain is physical (phys) or virtual (vmm).
type: str
choices: [ fc, l2dom, l3dom, phys, vmm ]
pool:
description:
- The name of the pool.
type: str
aliases: [ pool_name ]
pool_allocation_mode:
description:
- The method used for allocating encaps to resources.
- Only vlan and vsan support allocation modes.
type: str
choices: [ dynamic, static]
aliases: [ allocation_mode, mode ]
pool_type:
description:
- The encap type of C(pool).
type: str
required: yes
choices: [ vlan, vsan, vxlan ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
vm_provider:
description:
- The VM platform for VMM Domains.
- Support for Kubernetes was added in ACI v3.0.
- Support for CloudFoundry, OpenShift and Red Hat was added in ACI v3.1.
type: str
choices: [ cloudfoundry, kubernetes, microsoft, openshift, openstack, redhat, vmware ]
extends_documentation_fragment: aci
seealso:
- module: aci_domain
- module: aci_encap_pool
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(infra:RsVlanNs).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Dag Wieers (@dagwieers)
'''
EXAMPLES = r'''
- name: Add domain to VLAN pool binding
aci_domain_to_encap_pool:
host: apic
username: admin
password: SomeSecretPassword
domain: phys_dom
domain_type: phys
pool: test_pool
pool_type: vlan
pool_allocation_mode: dynamic
state: present
delegate_to: localhost
- name: Remove domain to VLAN pool binding
aci_domain_to_encap_pool:
host: apic
username: admin
password: SomeSecretPassword
domain: phys_dom
domain_type: phys
pool: test_pool
pool_type: vlan
pool_allocation_mode: dynamic
state: absent
delegate_to: localhost
- name: Query our domain to VLAN pool binding
aci_domain_to_encap_pool:
host: apic
username: admin
password: SomeSecretPassword
domain: phys_dom
pool: test_pool
pool_type: vlan
pool_allocation_mode: dynamic
state: query
delegate_to: localhost
register: query_result
- name: Query all domain to VLAN pool bindings
aci_domain_to_encap_pool:
host: apic
username: admin
password: SomeSecretPassword
domain_type: phys
pool_type: vlan
pool_allocation_mode: dynamic
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
VM_PROVIDER_MAPPING = dict(
cloudfoundry='CloudFoundry',
kubernetes='Kubernetes',
microsoft='Microsoft',
openshift='OpenShift',
openstack='OpenStack',
redhat='Redhat',
vmware='VMware',
)
POOL_MAPPING = dict(
vlan=dict(
aci_mo='uni/infra/vlanns-{0}',
child_class='infraRsVlanNs',
),
vxlan=dict(
aci_mo='uni/infra/vxlanns-{0}',
child_class='vmmRsVxlanNs',
),
vsan=dict(
aci_mo='uni/infra/vsanns-{0}',
child_class='fcRsVsanNs',
),
)
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
domain_type=dict(type='str', required=True, choices=['fc', 'l2dom', 'l3dom', 'phys', 'vmm']),
pool_type=dict(type='str', required=True, choices=['vlan', 'vsan', 'vxlan']),
domain=dict(type='str', aliases=['domain_name', 'domain_profile']), # Not required for querying all objects
pool=dict(type='str', aliases=['pool_name']), # Not required for querying all objects
pool_allocation_mode=dict(type='str', aliases=['allocation_mode', 'mode'], choices=['dynamic', 'static']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
vm_provider=dict(type='str', choices=['cloudfoundry', 'kubernetes', 'microsoft', 'openshift', 'openstack', 'redhat', 'vmware']),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['domain_type', 'vmm', ['vm_provider']],
['state', 'absent', ['domain', 'domain_type', 'pool', 'pool_type']],
['state', 'present', ['domain', 'domain_type', 'pool', 'pool_type']],
],
)
domain = module.params.get('domain')
domain_type = module.params.get('domain_type')
pool = module.params.get('pool')
pool_allocation_mode = module.params.get('pool_allocation_mode')
pool_type = module.params.get('pool_type')
vm_provider = module.params.get('vm_provider')
state = module.params.get('state')
# Report when vm_provider is set when type is not virtual
if domain_type != 'vmm' and vm_provider is not None:
module.fail_json(msg="Domain type '{0}' cannot have a 'vm_provider'".format(domain_type))
# ACI Pool URL requires the allocation mode for vlan and vsan pools (ex: uni/infra/vlanns-[poolname]-static)
pool_name = pool
if pool_type != 'vxlan' and pool is not None:
if pool_allocation_mode is not None:
pool_name = '[{0}]-{1}'.format(pool, pool_allocation_mode)
else:
module.fail_json(msg="ACI requires the 'pool_allocation_mode' for 'pool_type' of 'vlan' and 'vsan' when 'pool' is provided")
# Vxlan pools do not support allocation modes
if pool_type == 'vxlan' and pool_allocation_mode is not None:
module.fail_json(msg='vxlan pools do not support setting the allocation_mode; please remove this parameter from the task')
# Compile the full domain for URL building
if domain_type == 'fc':
domain_class = 'fcDomP'
domain_mo = 'uni/fc-{0}'.format(domain)
domain_rn = 'fc-{0}'.format(domain)
elif domain_type == 'l2ext':
domain_class = 'l2extDomP'
domain_mo = 'uni/l2dom-{0}'.format(domain)
domain_rn = 'l2dom-{0}'.format(domain)
elif domain_type == 'l3ext':
domain_class = 'l3extDomP'
domain_mo = 'uni/l3dom-{0}'.format(domain)
domain_rn = 'l3dom-{0}'.format(domain)
elif domain_type == 'phys':
domain_class = 'physDomP'
domain_mo = 'uni/phys-{0}'.format(domain)
domain_rn = 'phys-{0}'.format(domain)
elif domain_type == 'vmm':
domain_class = 'vmmDomP'
domain_mo = 'uni/vmmp-{0}/dom-{1}'.format(VM_PROVIDER_MAPPING[vm_provider], domain)
domain_rn = 'vmmp-{0}/dom-{1}'.format(VM_PROVIDER_MAPPING[vm_provider], domain)
# Ensure that querying all objects works when only domain_type is provided
if domain is None:
domain_mo = None
pool_mo = POOL_MAPPING[pool_type]['aci_mo'].format(pool_name)
child_class = POOL_MAPPING[pool_type]['child_class']
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class=domain_class,
aci_rn=domain_rn,
module_object=domain_mo,
target_filter={'name': domain},
),
child_classes=[child_class],
)
aci.get_existing()
if state == 'present':
# Filter out module params with null values
aci.payload(
aci_class=domain_class,
class_config=dict(name=domain),
child_configs=[
{child_class: {'attributes': {'tDn': pool_mo}}},
]
)
# Generate config diff which will be used as POST request body
aci.get_diff(aci_class=domain_class)
# Submit changes if module not in check_mode and the proposed is different than existing
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,364 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Dag Wieers <dag@wieers.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_domain_to_vlan_pool
short_description: Bind Domain to VLAN Pools (infra:RsVlanNs)
description:
- Bind Domain to VLAN Pools on Cisco ACI fabrics.
version_added: '2.5'
options:
domain:
description:
- Name of the domain being associated with the VLAN Pool.
type: str
aliases: [ domain_name, domain_profile ]
domain_type:
description:
- Determines if the Domain is physical (phys) or virtual (vmm).
type: str
choices: [ fc, l2dom, l3dom, phys, vmm ]
pool:
description:
- The name of the pool.
type: str
aliases: [ pool_name, vlan_pool ]
pool_allocation_mode:
description:
- The method used for allocating VLANs to resources.
type: str
required: yes
choices: [ dynamic, static]
aliases: [ allocation_mode, mode ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
vm_provider:
description:
- The VM platform for VMM Domains.
- Support for Kubernetes was added in ACI v3.0.
- Support for CloudFoundry, OpenShift and Red Hat was added in ACI v3.1.
type: str
choices: [ cloudfoundry, kubernetes, microsoft, openshift, openstack, redhat, vmware ]
extends_documentation_fragment: aci
notes:
- The C(domain) and C(vlan_pool) parameters should exist before using this module.
The M(aci_domain) and M(aci_vlan_pool) can be used for these.
seealso:
- module: aci_domain
- module: aci_vlan_pool
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(infra:RsVlanNs).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Dag Wieers (@dagwieers)
'''
EXAMPLES = r'''
- name: Bind a VMM domain to VLAN pool
aci_domain_to_vlan_pool:
host: apic
username: admin
password: SomeSecretPassword
domain: vmw_dom
domain_type: vmm
pool: vmw_pool
pool_allocation_mode: dynamic
vm_provider: vmware
state: present
delegate_to: localhost
- name: Remove a VMM domain to VLAN pool binding
aci_domain_to_vlan_pool:
host: apic
username: admin
password: SomeSecretPassword
domain: vmw_dom
domain_type: vmm
pool: vmw_pool
pool_allocation_mode: dynamic
vm_provider: vmware
state: absent
delegate_to: localhost
- name: Bind a physical domain to VLAN pool
aci_domain_to_vlan_pool:
host: apic
username: admin
password: SomeSecretPassword
domain: phys_dom
domain_type: phys
pool: phys_pool
pool_allocation_mode: static
state: present
delegate_to: localhost
- name: Bind a physical domain to VLAN pool
aci_domain_to_vlan_pool:
host: apic
username: admin
password: SomeSecretPassword
domain: phys_dom
domain_type: phys
pool: phys_pool
pool_allocation_mode: static
state: absent
delegate_to: localhost
- name: Query an domain to VLAN pool binding
aci_domain_to_vlan_pool:
host: apic
username: admin
password: SomeSecretPassword
domain: phys_dom
domain_type: phys
pool: phys_pool
pool_allocation_mode: static
state: query
delegate_to: localhost
register: query_result
- name: Query all domain to VLAN pool bindings
aci_domain_to_vlan_pool:
host: apic
username: admin
password: SomeSecretPassword
domain_type: phys
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
VM_PROVIDER_MAPPING = dict(
cloudfoundry='CloudFoundry',
kubernetes='Kubernetes',
microsoft='Microsoft',
openshift='OpenShift',
openstack='OpenStack',
redhat='Redhat',
vmware='VMware',
)
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
domain_type=dict(type='str', required=True, choices=['fc', 'l2dom', 'l3dom', 'phys', 'vmm']),
domain=dict(type='str', aliases=['domain_name', 'domain_profile']), # Not required for querying all objects
pool=dict(type='str', aliases=['pool_name', 'vlan_pool']), # Not required for querying all objects
pool_allocation_mode=dict(type='str', required=True, aliases=['allocation_mode', 'mode'], choices=['dynamic', 'static']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
vm_provider=dict(type='str', choices=['cloudfoundry', 'kubernetes', 'microsoft', 'openshift', 'openstack', 'redhat', 'vmware']),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['domain_type', 'vmm', ['vm_provider']],
['state', 'absent', ['domain', 'domain_type', 'pool']],
['state', 'present', ['domain', 'domain_type', 'pool']],
],
)
domain = module.params.get('domain')
domain_type = module.params.get('domain_type')
pool = module.params.get('pool')
pool_allocation_mode = module.params.get('pool_allocation_mode')
vm_provider = module.params.get('vm_provider')
state = module.params.get('state')
# Report when vm_provider is set when type is not virtual
if domain_type != 'vmm' and vm_provider is not None:
module.fail_json(msg="Domain type '{0}' cannot have a 'vm_provider'".format(domain_type))
# ACI Pool URL requires the allocation mode for vlan and vsan pools (ex: uni/infra/vlanns-[poolname]-static)
pool_name = pool
if pool is not None:
pool_name = '[{0}]-{1}'.format(pool, pool_allocation_mode)
# Compile the full domain for URL building
if domain_type == 'fc':
domain_class = 'fcDomP'
domain_mo = 'uni/fc-{0}'.format(domain)
domain_rn = 'fc-{0}'.format(domain)
elif domain_type == 'l2dom':
domain_class = 'l2extDomP'
domain_mo = 'uni/l2dom-{0}'.format(domain)
domain_rn = 'l2dom-{0}'.format(domain)
elif domain_type == 'l3dom':
domain_class = 'l3extDomP'
domain_mo = 'uni/l3dom-{0}'.format(domain)
domain_rn = 'l3dom-{0}'.format(domain)
elif domain_type == 'phys':
domain_class = 'physDomP'
domain_mo = 'uni/phys-{0}'.format(domain)
domain_rn = 'phys-{0}'.format(domain)
elif domain_type == 'vmm':
domain_class = 'vmmDomP'
domain_mo = 'uni/vmmp-{0}/dom-{1}'.format(VM_PROVIDER_MAPPING[vm_provider], domain)
domain_rn = 'vmmp-{0}/dom-{1}'.format(VM_PROVIDER_MAPPING[vm_provider], domain)
# Ensure that querying all objects works when only domain_type is provided
if domain is None:
domain_mo = None
aci_mo = 'uni/infra/vlanns-{0}'.format(pool_name)
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class=domain_class,
aci_rn=domain_rn,
module_object=domain_mo,
target_filter={'name': domain},
),
child_classes=['infraRsVlanNs'],
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class=domain_class,
class_config=dict(name=domain),
child_configs=[
{'infraRsVlanNs': {'attributes': {'tDn': aci_mo}}},
]
)
aci.get_diff(aci_class=domain_class)
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,316 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_encap_pool
short_description: Manage encap pools (fvns:VlanInstP, fvns:VxlanInstP, fvns:VsanInstP)
description:
- Manage vlan, vxlan, and vsan pools on Cisco ACI fabrics.
version_added: '2.5'
options:
description:
description:
- Description for the C(pool).
type: str
aliases: [ descr ]
pool:
description:
- The name of the pool.
type: str
aliases: [ name, pool_name ]
pool_allocation_mode:
description:
- The method used for allocating encaps to resources.
- Only vlan and vsan support allocation modes.
type: str
choices: [ dynamic, static ]
aliases: [ allocation_mode, mode ]
pool_type:
description:
- The encap type of C(pool).
type: str
required: yes
aliases: [ type ]
choices: [ vlan, vsan, vxlan ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
seealso:
- module: aci_encap_pool_range
- module: aci_vlan_pool
- name: APIC Management Information Model reference
description: More information about the internal APIC classes B(fvns:VlanInstP),
B(fvns:VxlanInstP) and B(fvns:VsanInstP)
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Jacob McGill (@jmcgill298)
'''
EXAMPLES = r'''
- name: Add a new vlan pool
aci_encap_pool:
host: apic
username: admin
password: SomeSecretPassword
pool: production
pool_type: vlan
description: Production VLANs
state: present
delegate_to: localhost
- name: Remove a vlan pool
aci_encap_pool:
host: apic
username: admin
password: SomeSecretPassword
pool: production
pool_type: vlan
state: absent
delegate_to: localhost
- name: Query a vlan pool
aci_encap_pool:
host: apic
username: admin
password: SomeSecretPassword
pool: production
pool_type: vlan
state: query
delegate_to: localhost
register: query_result
- name: Query all vlan pools
aci_encap_pool:
host: apic
username: admin
password: SomeSecretPassword
pool_type: vlan
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
ACI_POOL_MAPPING = dict(
vlan=dict(
aci_class='fvnsVlanInstP',
aci_mo='infra/vlanns-',
),
vxlan=dict(
aci_class='fvnsVxlanInstP',
aci_mo='infra/vxlanns-',
),
vsan=dict(
aci_class='fvnsVsanInstP',
aci_mo='infra/vsanns-',
),
)
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
pool_type=dict(type='str', required=True, aliases=['type'], choices=['vlan', 'vsan', 'vxlan']),
description=dict(type='str', aliases=['descr']),
pool=dict(type='str', aliases=['name', 'pool_name']), # Not required for querying all objects
pool_allocation_mode=dict(type='str', aliases=['allocation_mode', 'mode'], choices=['dynamic', 'static']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['pool']],
['state', 'present', ['pool']],
],
)
description = module.params.get('description')
pool = module.params.get('pool')
pool_type = module.params.get('pool_type')
pool_allocation_mode = module.params.get('pool_allocation_mode')
state = module.params.get('state')
name_alias = module.params.get('name_alias')
aci_class = ACI_POOL_MAPPING[pool_type]['aci_class']
aci_mo = ACI_POOL_MAPPING[pool_type]['aci_mo']
pool_name = pool
# ACI Pool URL requires the pool_allocation mode for vlan and vsan pools (ex: uni/infra/vlanns-[poolname]-static)
if pool_type != 'vxlan' and pool is not None:
if pool_allocation_mode is not None:
pool_name = '[{0}]-{1}'.format(pool, pool_allocation_mode)
else:
module.fail_json(msg="ACI requires parameter 'pool_allocation_mode' for 'pool_type' of 'vlan' and 'vsan' when parameter 'pool' is provided")
# Vxlan pools do not support pool allocation modes
if pool_type == 'vxlan' and pool_allocation_mode is not None:
module.fail_json(msg="vxlan pools do not support setting the 'pool_allocation_mode'; please remove this parameter from the task")
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class=aci_class,
aci_rn='{0}{1}'.format(aci_mo, pool_name),
module_object=pool,
target_filter={'name': pool},
),
)
aci.get_existing()
if state == 'present':
# Filter out module parameters with null values
aci.payload(
aci_class=aci_class,
class_config=dict(
allocMode=pool_allocation_mode,
descr=description,
name=pool,
nameAlias=name_alias,
)
)
# Generate config diff which will be used as POST request body
aci.get_diff(aci_class=aci_class)
# Submit changes if module not in check_mode and the proposed is different than existing
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,449 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_encap_pool_range
short_description: Manage encap ranges assigned to pools (fvns:EncapBlk, fvns:VsanEncapBlk)
description:
- Manage vlan, vxlan, and vsan ranges that are assigned to pools on Cisco ACI fabrics.
version_added: '2.5'
options:
allocation_mode:
description:
- The method used for allocating encaps to resources.
- Only vlan and vsan support allocation modes.
type: str
choices: [ dynamic, inherit, static]
aliases: [ mode ]
description:
description:
- Description for the pool range.
type: str
aliases: [ descr ]
pool:
description:
- The name of the pool that the range should be assigned to.
type: str
aliases: [ pool_name ]
pool_allocation_mode:
description:
- The method used for allocating encaps to resources.
- Only vlan and vsan support allocation modes.
type: str
choices: [ dynamic, static]
aliases: [ pool_mode ]
pool_type:
description:
- The encap type of C(pool).
type: str
required: yes
aliases: [ type ]
choices: [ vlan, vxlan, vsan]
range_end:
description:
- The end of encap range.
type: int
aliases: [ end ]
range_name:
description:
- The name to give to the encap range.
type: str
aliases: [ name, range ]
range_start:
description:
- The start of the encap range.
type: int
aliases: [ start ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
notes:
- The C(pool) must exist in order to add or delete a range.
seealso:
- module: aci_encap_pool
- module: aci_vlan_pool_encap_block
- name: APIC Management Information Model reference
description: More information about the internal APIC classes B(fvns:EncapBlk) and B(fvns:VsanEncapBlk).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Jacob McGill (@jmcgill298)
'''
EXAMPLES = r'''
- name: Add a new VLAN pool range
aci_encap_pool_range:
host: apic
username: admin
password: SomeSecretPassword
pool: production
pool_type: vlan
pool_allocation_mode: static
range_name: anstest
range_start: 20
range_end: 40
allocation_mode: inherit
state: present
delegate_to: localhost
- name: Remove a VLAN pool range
aci_encap_pool_range:
host: apic
username: admin
password: SomeSecretPassword
pool: production
pool_type: vlan
pool_allocation_mode: static
range_name: anstest
range_start: 20
range_end: 40
state: absent
delegate_to: localhost
- name: Query a VLAN range
aci_encap_pool_range:
host: apic
username: admin
password: SomeSecretPassword
pool: production
pool_type: vlan
pool_allocation_mode: static
range_name: anstest
range_start: 20
range_end: 50
state: query
delegate_to: localhost
register: query_result
- name: Query a VLAN pool for ranges by range_name
aci_encap_pool_range:
host: apic
username: admin
password: SomeSecretPassword
pool_type: vlan
range_name: anstest
state: query
delegate_to: localhost
register: query_result
- name: Query a VLAN pool for ranges by range_start
aci_encap_pool_range:
host: apic
username: admin
password: SomeSecretPassword
pool_type: vlan
range_start: 20
state: query
delegate_to: localhost
register: query_result
- name: Query a VLAN pool for ranges by range_start and range_end
aci_encap_pool_range:
host: apic
username: admin
password: SomeSecretPassword
pool_type: vlan
range_start: 20
range_end: 40
state: query
delegate_to: localhost
register: query_result
- name: Query all VLAN pool ranges
aci_encap_pool_range:
host: apic
username: admin
password: SomeSecretPassword
pool_type: vlan
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
ACI_POOL_MAPPING = dict(
vlan=dict(
aci_class='fvnsVlanInstP',
aci_mo='infra/vlanns-',
),
vxlan=dict(
aci_class='fvnsVxlanInstP',
aci_mo='infra/vxlanns-',
),
vsan=dict(
aci_class='fvnsVsanInstP',
aci_mo='infra/vsanns-',
),
)
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
pool_type=dict(type='str', required=True, aliases=['type'], choices=['vlan', 'vxlan', 'vsan']),
allocation_mode=dict(type='str', aliases=['mode'], choices=['dynamic', 'inherit', 'static']),
description=dict(type='str', aliases=['descr']),
pool=dict(type='str', aliases=['pool_name']), # Not required for querying all objects
pool_allocation_mode=dict(type='str', aliases=['pool_mode'], choices=['dynamic', 'static']),
range_end=dict(type='int', aliases=['end']), # Not required for querying all objects
range_name=dict(type='str', aliases=["name", "range"]), # Not required for querying all objects
range_start=dict(type='int', aliases=["start"]), # Not required for querying all objects
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['pool', 'range_end', 'range_name', 'range_start']],
['state', 'present', ['pool', 'range_end', 'range_name', 'range_start']],
],
)
allocation_mode = module.params.get('allocation_mode')
description = module.params.get('description')
pool = module.params.get('pool')
pool_allocation_mode = module.params.get('pool_allocation_mode')
pool_type = module.params.get('pool_type')
range_end = module.params.get('range_end')
range_name = module.params.get('range_name')
range_start = module.params.get('range_start')
state = module.params.get('state')
name_alias = module.params.get('name_alias')
if range_end is not None:
encap_end = '{0}-{1}'.format(pool_type, range_end)
else:
encap_end = None
if range_start is not None:
encap_start = '{0}-{1}'.format(pool_type, range_start)
else:
encap_start = None
ACI_RANGE_MAPPING = dict(
vlan=dict(
aci_class='fvnsEncapBlk',
aci_mo='from-[{0}]-to-[{1}]'.format(encap_start, encap_end),
),
vxlan=dict(
aci_class='fvnsEncapBlk',
aci_mo='from-[{0}]-to-[{1}]'.format(encap_start, encap_end),
),
vsan=dict(
aci_class='fvnsVsanEncapBlk',
aci_mo='vsanfrom-[{0}]-to-[{1}]'.format(encap_start, encap_end),
),
)
# Collect proper class and mo information based on pool_type
aci_range_class = ACI_RANGE_MAPPING[pool_type]["aci_class"]
aci_range_mo = ACI_RANGE_MAPPING[pool_type]["aci_mo"]
aci_pool_class = ACI_POOL_MAPPING[pool_type]["aci_class"]
aci_pool_mo = ACI_POOL_MAPPING[pool_type]["aci_mo"]
pool_name = pool
# Validate range_end and range_start are valid for its respective encap type
for encap_id in range_end, range_start:
if encap_id is not None:
if pool_type == 'vlan':
if not 1 <= encap_id <= 4094:
module.fail_json(msg='vlan pools must have "range_start" and "range_end" values between 1 and 4094')
elif pool_type == 'vxlan':
if not 5000 <= encap_id <= 16777215:
module.fail_json(msg='vxlan pools must have "range_start" and "range_end" values between 5000 and 16777215')
elif pool_type == 'vsan':
if not 1 <= encap_id <= 4093:
module.fail_json(msg='vsan pools must have "range_start" and "range_end" values between 1 and 4093')
if range_end is not None and range_start is not None:
# Validate range_start is less than range_end
if range_start > range_end:
module.fail_json(msg='The "range_start" must be less than or equal to the "range_end"')
elif range_end is None and range_start is None:
if range_name is None:
# Reset range managed object to None for aci util to properly handle query
aci_range_mo = None
# Vxlan does not support setting the allocation mode
if pool_type == 'vxlan' and allocation_mode is not None:
module.fail_json(msg='vxlan pools do not support setting the "allocation_mode"; please omit this parameter for vxlan pools')
# ACI Pool URL requires the allocation mode for vlan and vsan pools (ex: uni/infra/vlanns-[poolname]-static)
if pool_type != 'vxlan' and pool is not None:
if pool_allocation_mode is not None:
pool_name = '[{0}]-{1}'.format(pool, pool_allocation_mode)
else:
module.fail_json(msg='ACI requires the "pool_allocation_mode" for "pool_type" of "vlan" and "vsan" when the "pool" is provided')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class=aci_pool_class,
aci_rn='{0}{1}'.format(aci_pool_mo, pool_name),
module_object=pool,
target_filter={'name': pool},
),
subclass_1=dict(
aci_class=aci_range_class,
aci_rn='{0}'.format(aci_range_mo),
module_object=aci_range_mo,
target_filter={'from': encap_start, 'to': encap_end, 'name': range_name},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class=aci_range_class,
class_config={
"allocMode": allocation_mode,
"descr": description,
"from": encap_start,
"name": range_name,
"to": encap_end,
"nameAlias": name_alias,
},
)
aci.get_diff(aci_class=aci_range_class)
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,393 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_epg
short_description: Manage End Point Groups (EPG) objects (fv:AEPg)
description:
- Manage End Point Groups (EPG) on Cisco ACI fabrics.
version_added: '2.4'
options:
tenant:
description:
- Name of an existing tenant.
type: str
aliases: [ tenant_name ]
ap:
description:
- Name of an existing application network profile, that will contain the EPGs.
type: str
required: yes
aliases: [ app_profile, app_profile_name ]
epg:
description:
- Name of the end point group.
type: str
required: yes
aliases: [ epg_name, name ]
bd:
description:
- Name of the bridge domain being associated with the EPG.
type: str
aliases: [ bd_name, bridge_domain ]
priority:
description:
- The QoS class.
- The APIC defaults to C(unspecified) when unset during creation.
type: str
choices: [ level1, level2, level3, unspecified ]
intra_epg_isolation:
description:
- The Intra EPG Isolation.
- The APIC defaults to C(unenforced) when unset during creation.
type: str
choices: [ enforced, unenforced ]
description:
description:
- Description for the EPG.
type: str
aliases: [ descr ]
fwd_control:
description:
- The forwarding control used by the EPG.
- The APIC defaults to C(none) when unset during creation.
type: str
choices: [ none, proxy-arp ]
preferred_group:
description:
- Whether ot not the EPG is part of the Preferred Group and can communicate without contracts.
- This is very convenient for migration scenarios, or when ACI is used for network automation but not for policy.
- The APIC defaults to C(no) when unset during creation.
type: bool
version_added: '2.5'
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
notes:
- The C(tenant) and C(app_profile) used must exist before using this module in your playbook.
The M(aci_tenant) and M(aci_ap) modules can be used for this.
seealso:
- module: aci_tenant
- module: aci_ap
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(fv:AEPg).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Swetha Chunduri (@schunduri)
'''
EXAMPLES = r'''
- name: Add a new EPG
aci_epg:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
ap: intranet
epg: web_epg
description: Web Intranet EPG
bd: prod_bd
preferred_group: yes
state: present
delegate_to: localhost
- aci_epg:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
ap: ticketing
epg: "{{ item.epg }}"
description: Ticketing EPG
bd: "{{ item.bd }}"
priority: unspecified
intra_epg_isolation: unenforced
state: present
delegate_to: localhost
with_items:
- epg: web
bd: web_bd
- epg: database
bd: database_bd
- name: Remove an EPG
aci_epg:
host: apic
username: admin
password: SomeSecretPassword
validate_certs: no
tenant: production
app_profile: intranet
epg: web_epg
state: absent
delegate_to: localhost
- name: Query an EPG
aci_epg:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
ap: ticketing
epg: web_epg
state: query
delegate_to: localhost
register: query_result
- name: Query all EPGs
aci_epg:
host: apic
username: admin
password: SomeSecretPassword
state: query
delegate_to: localhost
register: query_result
- name: Query all EPGs with a Specific Name
aci_epg:
host: apic
username: admin
password: SomeSecretPassword
validate_certs: no
epg: web_epg
state: query
delegate_to: localhost
register: query_result
- name: Query all EPGs of an App Profile
aci_epg:
host: apic
username: admin
password: SomeSecretPassword
validate_certs: no
ap: ticketing
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
epg=dict(type='str', aliases=['epg_name', 'name']), # Not required for querying all objects
bd=dict(type='str', aliases=['bd_name', 'bridge_domain']),
ap=dict(type='str', aliases=['app_profile', 'app_profile_name']), # Not required for querying all objects
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
priority=dict(type='str', choices=['level1', 'level2', 'level3', 'unspecified']),
intra_epg_isolation=dict(choices=['enforced', 'unenforced']),
fwd_control=dict(type='str', choices=['none', 'proxy-arp']),
preferred_group=dict(type='bool'),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['ap', 'epg', 'tenant']],
['state', 'present', ['ap', 'epg', 'tenant']],
],
)
aci = ACIModule(module)
epg = module.params.get('epg')
bd = module.params.get('bd')
description = module.params.get('description')
priority = module.params.get('priority')
intra_epg_isolation = module.params.get('intra_epg_isolation')
fwd_control = module.params.get('fwd_control')
preferred_group = aci.boolean(module.params.get('preferred_group'), 'include', 'exclude')
state = module.params.get('state')
tenant = module.params.get('tenant')
ap = module.params.get('ap')
name_alias = module.params.get('name_alias')
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='fvAp',
aci_rn='ap-{0}'.format(ap),
module_object=ap,
target_filter={'name': ap},
),
subclass_2=dict(
aci_class='fvAEPg',
aci_rn='epg-{0}'.format(epg),
module_object=epg,
target_filter={'name': epg},
),
child_classes=['fvRsBd'],
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='fvAEPg',
class_config=dict(
name=epg,
descr=description,
prio=priority,
pcEnfPref=intra_epg_isolation,
fwdCtrl=fwd_control,
prefGrMemb=preferred_group,
nameAlias=name_alias,
),
child_configs=[dict(
fvRsBd=dict(
attributes=dict(
tnFvBDName=bd,
),
),
)],
)
aci.get_diff(aci_class='fvAEPg')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,248 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_epg_monitoring_policy
short_description: Manage monitoring policies (mon:EPGPol)
description:
- Manage monitoring policies on Cisco ACI fabrics.
version_added: '2.4'
options:
monitoring_policy:
description:
- The name of the monitoring policy.
type: str
required: yes
aliases: [ name ]
description:
description:
- Description for the monitoring policy.
type: str
aliases: [ descr ]
tenant:
description:
- The name of the tenant.
type: str
required: yes
aliases: [ tenant_name ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
notes:
- The C(tenant) used must exist before using this module in your playbook.
The M(aci_tenant) module can be used for this.
seealso:
- module: aci_tenant
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(mon:EPGPol).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Dag Wieers (@dagwieers)
'''
# FIXME: Add more, better examples
EXAMPLES = r'''
- aci_epg_monitoring_policy:
host: '{{ hostname }}'
username: '{{ username }}'
password: '{{ password }}'
monitoring_policy: '{{ monitoring_policy }}'
description: '{{ description }}'
tenant: '{{ tenant }}'
delegate_to: localhost
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
monitoring_policy=dict(type='str', aliases=['name']), # Not required for querying all objects
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['monitoring_policy', 'tenant']],
['state', 'present', ['monitoring_policy', 'tenant']],
],
)
monitoring_policy = module.params.get('monitoring_policy')
description = module.params.get('description')
state = module.params.get('state')
tenant = module.params.get('tenant')
name_alias = module.params.get('name_alias')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='monEPGPol',
aci_rn='monepg-{0}'.format(monitoring_policy),
module_object=monitoring_policy,
target_filter={'name': monitoring_policy},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='monEPGPol',
class_config=dict(
name=monitoring_policy,
descr=description,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='monEPGPol')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,350 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_epg_to_contract
short_description: Bind EPGs to Contracts (fv:RsCons, fv:RsProv)
description:
- Bind EPGs to Contracts on Cisco ACI fabrics.
notes:
- The C(tenant), C(app_profile), C(EPG), and C(Contract) used must exist before using this module in your playbook.
The M(aci_tenant), M(aci_ap), M(aci_epg), and M(aci_contract) modules can be used for this.
version_added: '2.4'
options:
ap:
description:
- Name of an existing application network profile, that will contain the EPGs.
type: str
aliases: [ app_profile, app_profile_name ]
contract:
description:
- The name of the contract.
type: str
aliases: [ contract_name ]
contract_type:
description:
- Determines if the EPG should Provide or Consume the Contract.
type: str
required: yes
choices: [ consumer, provider ]
epg:
description:
- The name of the end point group.
type: str
aliases: [ epg_name ]
priority:
description:
- QoS class.
- The APIC defaults to C(unspecified) when unset during creation.
type: str
choices: [ level1, level2, level3, unspecified ]
provider_match:
description:
- The matching algorithm for Provided Contracts.
- The APIC defaults to C(at_least_one) when unset during creation.
type: str
choices: [ all, at_least_one, at_most_one, none ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
tenant:
description:
- Name of an existing tenant.
type: str
aliases: [ tenant_name ]
extends_documentation_fragment: aci
seealso:
- module: aci_ap
- module: aci_epg
- module: aci_contract
- name: APIC Management Information Model reference
description: More information about the internal APIC classes B(fv:RsCons) and B(fv:RsProv).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Jacob McGill (@jmcgill298)
'''
EXAMPLES = r'''
- name: Add a new contract to EPG binding
aci_epg_to_contract:
host: apic
username: admin
password: SomeSecretPassword
tenant: anstest
ap: anstest
epg: anstest
contract: anstest_http
contract_type: provider
state: present
delegate_to: localhost
- name: Remove an existing contract to EPG binding
aci_epg_to_contract:
host: apic
username: admin
password: SomeSecretPassword
tenant: anstest
ap: anstest
epg: anstest
contract: anstest_http
contract_type: provider
state: absent
delegate_to: localhost
- name: Query a specific contract to EPG binding
aci_epg_to_contract:
host: apic
username: admin
password: SomeSecretPassword
tenant: anstest
ap: anstest
epg: anstest
contract: anstest_http
contract_type: provider
state: query
delegate_to: localhost
register: query_result
- name: Query all provider contract to EPG bindings
aci_epg_to_contract:
host: apic
username: admin
password: SomeSecretPassword
contract_type: provider
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
ACI_CLASS_MAPPING = dict(
consumer={
'class': 'fvRsCons',
'rn': 'rscons-',
},
provider={
'class': 'fvRsProv',
'rn': 'rsprov-',
},
)
PROVIDER_MATCH_MAPPING = dict(
all='All',
at_least_one='AtleastOne',
at_most_one='tmostOne',
none='None',
)
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
contract_type=dict(type='str', required=True, choices=['consumer', 'provider']),
ap=dict(type='str', aliases=['app_profile', 'app_profile_name']), # Not required for querying all objects
epg=dict(type='str', aliases=['epg_name']), # Not required for querying all objects
contract=dict(type='str', aliases=['contract_name']), # Not required for querying all objects
priority=dict(type='str', choices=['level1', 'level2', 'level3', 'unspecified']),
provider_match=dict(type='str', choices=['all', 'at_least_one', 'at_most_one', 'none']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['ap', 'contract', 'epg', 'tenant']],
['state', 'present', ['ap', 'contract', 'epg', 'tenant']],
],
)
ap = module.params.get('ap')
contract = module.params.get('contract')
contract_type = module.params.get('contract_type')
epg = module.params.get('epg')
priority = module.params.get('priority')
provider_match = module.params.get('provider_match')
if provider_match is not None:
provider_match = PROVIDER_MATCH_MAPPING[provider_match]
state = module.params.get('state')
tenant = module.params.get('tenant')
aci_class = ACI_CLASS_MAPPING[contract_type]["class"]
aci_rn = ACI_CLASS_MAPPING[contract_type]["rn"]
if contract_type == "consumer" and provider_match is not None:
module.fail_json(msg="the 'provider_match' is only configurable for Provided Contracts")
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='fvAp',
aci_rn='ap-{0}'.format(ap),
module_object=ap,
target_filter={'name': ap},
),
subclass_2=dict(
aci_class='fvAEPg',
aci_rn='epg-{0}'.format(epg),
module_object=epg,
target_filter={'name': epg},
),
subclass_3=dict(
aci_class=aci_class,
aci_rn='{0}{1}'.format(aci_rn, contract),
module_object=contract,
target_filter={'tnVzBrCPName': contract},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class=aci_class,
class_config=dict(
matchT=provider_match,
prio=priority,
tnVzBrCPName=contract,
),
)
aci.get_diff(aci_class=aci_class)
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,423 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_epg_to_domain
short_description: Bind EPGs to Domains (fv:RsDomAtt)
description:
- Bind EPGs to Physical and Virtual Domains on Cisco ACI fabrics.
version_added: '2.4'
options:
allow_useg:
description:
- Allows micro-segmentation.
- The APIC defaults to C(encap) when unset during creation.
type: str
choices: [ encap, useg ]
ap:
description:
- Name of an existing application network profile, that will contain the EPGs.
type: str
aliases: [ app_profile, app_profile_name ]
deploy_immediacy:
description:
- Determines when the policy is pushed to hardware Policy CAM.
- The APIC defaults to C(lazy) when unset during creation.
type: str
choices: [ immediate, lazy ]
domain:
description:
- Name of the physical or virtual domain being associated with the EPG.
type: str
aliases: [ domain_name, domain_profile ]
domain_type:
description:
- Specify whether the Domain is a physical (phys), a virtual (vmm) or an L2 external domain association (l2dom).
type: str
choices: [ l2dom, phys, vmm ]
aliases: [ type ]
encap:
description:
- The VLAN encapsulation for the EPG when binding a VMM Domain with static C(encap_mode).
- This acts as the secondary encap when using useg.
- Accepted values range between C(1) and C(4096).
type: int
encap_mode:
description:
- The encapsulation method to be used.
- The APIC defaults to C(auto) when unset during creation.
- If vxlan is selected, switching_mode must be "AVE".
type: str
choices: [ auto, vlan, vxlan ]
switching_mode:
description:
- Switching Mode used by the switch
type: str
choices: [ AVE, native ]
default: native
version_added: '2.9'
epg:
description:
- Name of the end point group.
type: str
aliases: [ epg_name, name ]
netflow:
description:
- Determines if netflow should be enabled.
- The APIC defaults to C(no) when unset during creation.
type: bool
primary_encap:
description:
- Determines the primary VLAN ID when using useg.
- Accepted values range between C(1) and C(4096).
type: int
resolution_immediacy:
description:
- Determines when the policies should be resolved and available.
- The APIC defaults to C(lazy) when unset during creation.
type: str
choices: [ immediate, lazy, pre-provision ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
tenant:
description:
- Name of an existing tenant.
type: str
aliases: [ tenant_name ]
vm_provider:
description:
- The VM platform for VMM Domains.
- Support for Kubernetes was added in ACI v3.0.
- Support for CloudFoundry, OpenShift and Red Hat was added in ACI v3.1.
type: str
choices: [ cloudfoundry, kubernetes, microsoft, openshift, openstack, redhat, vmware ]
extends_documentation_fragment: aci
notes:
- The C(tenant), C(ap), C(epg), and C(domain) used must exist before using this module in your playbook.
The M(aci_tenant) M(aci_ap), M(aci_epg) M(aci_domain) modules can be used for this.
- OpenStack VMM domains must not be created using this module. The OpenStack VMM domain is created directly
by the Cisco APIC Neutron plugin as part of the installation and configuration.
This module can be used to query status of an OpenStack VMM domain.
seealso:
- module: aci_ap
- module: aci_epg
- module: aci_domain
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(fv:RsDomAtt).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Jacob McGill (@jmcgill298)
'''
EXAMPLES = r'''
- name: Add a new physical domain to EPG binding
aci_epg_to_domain:
host: apic
username: admin
password: SomeSecretPassword
tenant: anstest
ap: anstest
epg: anstest
domain: anstest
domain_type: phys
state: present
delegate_to: localhost
- name: Remove an existing physical domain to EPG binding
aci_epg_to_domain:
host: apic
username: admin
password: SomeSecretPassword
tenant: anstest
ap: anstest
epg: anstest
domain: anstest
domain_type: phys
state: absent
delegate_to: localhost
- name: Query a specific physical domain to EPG binding
aci_epg_to_domain:
host: apic
username: admin
password: SomeSecretPassword
tenant: anstest
ap: anstest
epg: anstest
domain: anstest
domain_type: phys
state: query
delegate_to: localhost
register: query_result
- name: Query all domain to EPG bindings
aci_epg_to_domain:
host: apic
username: admin
password: SomeSecretPassword
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
VM_PROVIDER_MAPPING = dict(
cloudfoundry='CloudFoundry',
kubernetes='Kubernetes',
microsoft='Microsoft',
openshift='OpenShift',
openstack='OpenStack',
redhat='Redhat',
vmware='VMware',
)
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
allow_useg=dict(type='str', choices=['encap', 'useg']),
ap=dict(type='str', aliases=['app_profile', 'app_profile_name']), # Not required for querying all objects
deploy_immediacy=dict(type='str', choices=['immediate', 'lazy']),
domain=dict(type='str', aliases=['domain_name', 'domain_profile']), # Not required for querying all objects
domain_type=dict(type='str', choices=['l2dom', 'phys', 'vmm'], aliases=['type']), # Not required for querying all objects
encap=dict(type='int'),
encap_mode=dict(type='str', choices=['auto', 'vlan', 'vxlan']),
switching_mode=dict(type='str', default='native', choices=['AVE', 'native']),
epg=dict(type='str', aliases=['name', 'epg_name']), # Not required for querying all objects
netflow=dict(type='bool'),
primary_encap=dict(type='int'),
resolution_immediacy=dict(type='str', choices=['immediate', 'lazy', 'pre-provision']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
vm_provider=dict(type='str', choices=['cloudfoundry', 'kubernetes', 'microsoft', 'openshift', 'openstack', 'redhat', 'vmware']),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['domain_type', 'vmm', ['vm_provider']],
['state', 'absent', ['ap', 'domain', 'domain_type', 'epg', 'tenant']],
['state', 'present', ['ap', 'domain', 'domain_type', 'epg', 'tenant']],
],
)
aci = ACIModule(module)
allow_useg = module.params.get('allow_useg')
ap = module.params.get('ap')
deploy_immediacy = module.params.get('deploy_immediacy')
domain = module.params.get('domain')
domain_type = module.params.get('domain_type')
vm_provider = module.params.get('vm_provider')
encap = module.params.get('encap')
if encap is not None:
if encap in range(1, 4097):
encap = 'vlan-{0}'.format(encap)
else:
module.fail_json(msg='Valid VLAN assignments are from 1 to 4096')
encap_mode = module.params.get('encap_mode')
switching_mode = module.params.get('switching_mode')
epg = module.params.get('epg')
netflow = aci.boolean(module.params.get('netflow'), 'enabled', 'disabled')
primary_encap = module.params.get('primary_encap')
if primary_encap is not None:
if primary_encap in range(1, 4097):
primary_encap = 'vlan-{0}'.format(primary_encap)
else:
module.fail_json(msg='Valid VLAN assignments are from 1 to 4096')
resolution_immediacy = module.params.get('resolution_immediacy')
state = module.params.get('state')
tenant = module.params.get('tenant')
if domain_type in ['l2dom', 'phys'] and vm_provider is not None:
module.fail_json(msg="Domain type '%s' cannot have a 'vm_provider'" % domain_type)
# Compile the full domain for URL building
if domain_type == 'vmm':
epg_domain = 'uni/vmmp-{0}/dom-{1}'.format(VM_PROVIDER_MAPPING[vm_provider], domain)
elif domain_type == 'l2dom':
epg_domain = 'uni/l2dom-{0}'.format(domain)
elif domain_type == 'phys':
epg_domain = 'uni/phys-{0}'.format(domain)
else:
epg_domain = None
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='fvAp',
aci_rn='ap-{0}'.format(ap),
module_object=ap,
target_filter={'name': ap},
),
subclass_2=dict(
aci_class='fvAEPg',
aci_rn='epg-{0}'.format(epg),
module_object=epg,
target_filter={'name': epg},
),
subclass_3=dict(
aci_class='fvRsDomAtt',
aci_rn='rsdomAtt-[{0}]'.format(epg_domain),
module_object=epg_domain,
target_filter={'tDn': epg_domain},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='fvRsDomAtt',
class_config=dict(
classPref=allow_useg,
encap=encap,
encapMode=encap_mode,
switchingMode=switching_mode,
instrImedcy=deploy_immediacy,
netflowPref=netflow,
primaryEncap=primary_encap,
resImedcy=resolution_immediacy,
),
)
aci.get_diff(aci_class='fvRsDomAtt')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,288 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Bruno Calogero <brunocalogero@hotmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_fabric_node
short_description: Manage Fabric Node Members (fabric:NodeIdentP)
description:
- Manage Fabric Node Members on Cisco ACI fabrics.
version_added: '2.5'
options:
pod_id:
description:
- The pod id of the new Fabric Node Member.
type: int
serial:
description:
- Serial Number for the new Fabric Node Member.
type: str
aliases: [ serial_number ]
node_id:
description:
- Node ID Number for the new Fabric Node Member.
type: int
switch:
description:
- Switch Name for the new Fabric Node Member.
type: str
aliases: [ name, switch_name ]
description:
description:
- Description for the new Fabric Node Member.
type: str
aliases: [ descr ]
role:
description:
- Role for the new Fabric Node Member.
type: str
aliases: [ role_name ]
choices: [ leaf, spine, unspecified ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
seealso:
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(fabric:NodeIdentP).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Bruno Calogero (@brunocalogero)
'''
EXAMPLES = r'''
- name: Add fabric node
aci_fabric_node:
host: apic
username: admin
password: SomeSecretPassword
serial: FDO2031124L
node_id: 1011
switch: fab4-sw1011
state: present
delegate_to: localhost
- name: Remove fabric node
aci_fabric_node:
host: apic
username: admin
password: SomeSecretPassword
serial: FDO2031124L
node_id: 1011
state: absent
delegate_to: localhost
- name: Query fabric nodes
aci_fabric_node:
host: apic
username: admin
password: SomeSecretPassword
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: '?rsp-prop-include=config-only'
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
# NOTE: (This problem is also present on the APIC GUI)
# NOTE: When specifying a C(role) the new Fabric Node Member will be created but Role on GUI will be "unknown", hence not what seems to be a module problem
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
description=dict(type='str', aliases=['descr']),
node_id=dict(type='int'), # Not required for querying all objects
pod_id=dict(type='int'),
role=dict(type='str', choices=['leaf', 'spine', 'unspecified'], aliases=['role_name']),
serial=dict(type='str', aliases=['serial_number']), # Not required for querying all objects
switch=dict(type='str', aliases=['name', 'switch_name']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['node_id', 'serial']],
['state', 'present', ['node_id', 'serial']],
],
)
pod_id = module.params.get('pod_id')
serial = module.params.get('serial')
node_id = module.params.get('node_id')
switch = module.params.get('switch')
description = module.params.get('description')
role = module.params.get('role')
state = module.params.get('state')
name_alias = module.params.get('name_alias')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='fabricNodeIdentP',
aci_rn='controller/nodeidentpol/nodep-{0}'.format(serial),
module_object=serial,
target_filter={'serial': serial},
)
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='fabricNodeIdentP',
class_config=dict(
descr=description,
name=switch,
nodeId=node_id,
podId=pod_id,
# NOTE: Originally we were sending 'rn', but now we need 'dn' for idempotency
# FIXME: Did this change with ACI version ?
dn='uni/controller/nodeidentpol/nodep-{0}'.format(serial),
# rn='nodep-{0}'.format(serial),
role=role,
serial=serial,
nameAlias=name_alias,
)
)
aci.get_diff(aci_class='fabricNodeIdentP')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json(**aci.result)
if __name__ == "__main__":
main()

@ -1,333 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = '''
---
module: aci_fabric_scheduler
short_description: This modules creates ACI schedulers.
version_added: "2.8"
description:
- With the module you can create schedule policies that can be a shell, onetime execution or recurring
options:
name:
description:
- The name of the Scheduler.
type: str
required: yes
aliases: [ name, scheduler_name ]
description:
description:
- Description for the Scheduler.
type: str
aliases: [ descr ]
recurring:
description:
- If you want to make the Scheduler a recurring it would be a "True" and for a
oneTime execution it would be "False". For a shell just exclude this option from
the task
type: bool
default: 'no'
windowname:
description:
- This is the name for your what recurring or oneTime execution
type: str
concurCap:
description:
- This is the amount of devices that can be executed on at a time
type: int
maxTime:
description:
- This is the amount MAX amount of time a process can be executed
type: str
date:
description:
- This is the date and time that the scheduler will execute
type: str
hour:
description:
- This set the hour of execution
type: int
minute:
description:
- This sets the minute of execution, used in conjunction with hour
type: int
day:
description:
- This sets the day when execution will take place
type: str
default: "every-day"
choices: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday','Sunday', 'even-day', 'odd-day', 'every-day']
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
default: present
choices: [ absent, present, query ]
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
author:
- Steven Gerhart (@sgerhart)
'''
EXAMPLES = '''
- name: Simple Scheduler (Empty)
aci_fabric_scheduler:
host: "{{ inventory_hostname }}"
username: "{{ user }}"
password: "{{ pass }}"
validate_certs: no
name: simpleScheduler
state: present
- name: Remove Simple Scheduler
aci_fabric_scheduler:
host: "{{ inventory_hostname }}"
username: "{{ user }}"
password: "{{ pass }}"
validate_certs: no
name: simpleScheduler
state: absent
- name: One Time Scheduler
aci_fabric_scheduler:
host: "{{ inventory_hostname }}"
username: "{{ user }}"
password: "{{ pass }}"
validate_certs: no
name: OneTime
windowname: OneTime
recurring: False
concurCap: 20
date: "2018-11-20T24:00:00"
state: present
- name: Recurring Scheduler
aci_fabric_scheduler:
host: "{{ inventory_hostname }}"
username: "{{ user }}"
password: "{{ pass }}"
validate_certs: no
name: Recurring
windowname: Recurring
recurring: True
concurCap: 20
hour: 13
minute: 30
day: Tuesday
state: present
'''
RETURN = '''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
import json
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
from ansible.module_utils.basic import AnsibleModule
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
name=dict(type='str', aliases=['name', 'scheduler_name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
windowname=dict(type='str', aliases=['windowname']),
recurring=dict(type='bool'),
concurCap=dict(type='int'), # Number of devices it will run against concurrently
maxTime=dict(type='str'), # The amount of minutes a process will be able to run (unlimited or dd:hh:mm:ss)
date=dict(type='str', aliases=['date']), # The date the process will run YYYY-MM-DDTHH:MM:SS
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
hour=dict(type='int'),
minute=dict(type='int'),
day=dict(type='str', default='every-day', choices=['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday',
'Saturday', 'Sunday', 'every-day', 'even-day', 'odd-day']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['name']],
['state', 'present', ['name']],
],
)
state = module.params.get('state')
name = module.params.get('name')
windowname = module.params.get('windowname')
recurring = module.params.get('recurring')
date = module.params.get('date')
hour = module.params.get('hour')
minute = module.params.get('minute')
maxTime = module.params.get('maxTime')
concurCap = module.params.get('concurCap')
day = module.params.get('day')
description = module.params.get('description')
name_alias = module.params.get('name_alias')
if recurring:
child_configs = [dict(trigRecurrWindowP=dict(attributes=dict(name=windowname, hour=hour, minute=minute,
procCa=maxTime, concurCap=concurCap, day=day,)))]
elif recurring is False:
child_configs = [dict(trigAbsWindowP=dict(attributes=dict(name=windowname, procCap=maxTime,
concurCap=concurCap, date=date,)))]
else:
child_configs = []
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='trigSchedP',
aci_rn='fabric/schedp-{0}'.format(name),
target_filter={'name': name},
module_object=name,
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='trigSchedP',
class_config=dict(
name=name,
descr=description,
nameAlias=name_alias,
),
child_configs=child_configs,
)
aci.get_diff(aci_class='trigSchedP')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,281 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_filter
short_description: Manages top level filter objects (vz:Filter)
description:
- Manages top level filter objects on Cisco ACI fabrics.
- This modules does not manage filter entries, see M(aci_filter_entry) for this functionality.
version_added: '2.4'
options:
filter:
description:
- The name of the filter.
type: str
required: yes
aliases: [ filter_name, name ]
description:
description:
- Description for the filter.
type: str
aliases: [ descr ]
tenant:
description:
- The name of the tenant.
type: str
required: yes
aliases: [ tenant_name ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
notes:
- The C(tenant) used must exist before using this module in your playbook.
The M(aci_tenant) module can be used for this.
seealso:
- module: aci_tenant
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(vz:Filter).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Dag Wieers (@dagwieers)
'''
EXAMPLES = r'''
- name: Add a new filter to a tenant
aci_filter:
host: apic
username: admin
password: SomeSecretPassword
filter: web_filter
description: Filter for web protocols
tenant: production
state: present
delegate_to: localhost
- name: Remove a filter for a tenant
aci_filter:
host: apic
username: admin
password: SomeSecretPassword
filter: web_filter
tenant: production
state: absent
delegate_to: localhost
- name: Query a filter of a tenant
aci_filter:
host: apic
username: admin
password: SomeSecretPassword
filter: web_filter
tenant: production
state: query
delegate_to: localhost
register: query_result
- name: Query all filters for a tenant
aci_filter:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
filter=dict(type='str', aliases=['name', 'filter_name']), # Not required for querying all objects
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['filter', 'tenant']],
['state', 'present', ['filter', 'tenant']],
],
)
filter_name = module.params.get('filter')
description = module.params.get('description')
state = module.params.get('state')
tenant = module.params.get('tenant')
name_alias = module.params.get('name_alias')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='vzFilter',
aci_rn='flt-{0}'.format(filter_name),
module_object=filter_name,
target_filter={'name': filter_name},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='vzFilter',
class_config=dict(
name=filter_name,
descr=description,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='vzFilter')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,375 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_filter_entry
short_description: Manage filter entries (vz:Entry)
description:
- Manage filter entries for a filter on Cisco ACI fabrics.
version_added: '2.4'
options:
arp_flag:
description:
- The arp flag to use when the ether_type is arp.
- The APIC defaults to C(unspecified) when unset during creation.
type: str
choices: [ arp_reply, arp_request, unspecified ]
description:
description:
- Description for the Filter Entry.
type: str
aliases: [ descr ]
dst_port:
description:
- Used to set both destination start and end ports to the same value when ip_protocol is tcp or udp.
- Accepted values are any valid TCP/UDP port range.
- The APIC defaults to C(unspecified) when unset during creation.
type: str
dst_port_end:
description:
- Used to set the destination end port when ip_protocol is tcp or udp.
- Accepted values are any valid TCP/UDP port range.
- The APIC defaults to C(unspecified) when unset during creation.
type: str
dst_port_start:
description:
- Used to set the destination start port when ip_protocol is tcp or udp.
- Accepted values are any valid TCP/UDP port range.
- The APIC defaults to C(unspecified) when unset during creation.
type: str
entry:
description:
- Then name of the Filter Entry.
type: str
aliases: [ entry_name, filter_entry, name ]
ether_type:
description:
- The Ethernet type.
- The APIC defaults to C(unspecified) when unset during creation.
type: str
choices: [ arp, fcoe, ip, mac_security, mpls_ucast, trill, unspecified ]
filter:
description:
- The name of Filter that the entry should belong to.
type: str
aliases: [ filter_name ]
icmp_msg_type:
description:
- ICMPv4 message type; used when ip_protocol is icmp.
- The APIC defaults to C(unspecified) when unset during creation.
type: str
choices: [ dst_unreachable, echo, echo_reply, src_quench, time_exceeded, unspecified ]
icmp6_msg_type:
description:
- ICMPv6 message type; used when ip_protocol is icmpv6.
- The APIC defaults to C(unspecified) when unset during creation.
type: str
choices: [ dst_unreachable, echo_request, echo_reply, neighbor_advertisement, neighbor_solicitation, redirect, time_exceeded, unspecified ]
ip_protocol:
description:
- The IP Protocol type when ether_type is ip.
- The APIC defaults to C(unspecified) when unset during creation.
type: str
choices: [ eigrp, egp, icmp, icmpv6, igmp, igp, l2tp, ospfigp, pim, tcp, udp, unspecified ]
state:
description:
- present, absent, query
type: str
default: present
choices: [ absent, present, query ]
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
stateful:
description:
- Determines the statefulness of the filter entry.
type: bool
tenant:
description:
- The name of the tenant.
type: str
aliases: [ tenant_name ]
extends_documentation_fragment: aci
notes:
- The C(tenant) and C(filter) used must exist before using this module in your playbook.
The M(aci_tenant) and M(aci_filter) modules can be used for this.
seealso:
- module: aci_tenant
- module: aci_filter
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(vz:Entry).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Jacob McGill (@jmcgill298)
'''
EXAMPLES = r'''
- aci_filter_entry:
host: "{{ inventory_hostname }}"
username: "{{ user }}"
password: "{{ pass }}"
state: "{{ state }}"
entry: "{{ entry }}"
tenant: "{{ tenant }}"
ether_name: "{{ ether_name }}"
icmp_msg_type: "{{ icmp_msg_type }}"
filter: "{{ filter }}"
descr: "{{ descr }}"
delegate_to: localhost
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
VALID_ARP_FLAGS = ['arp_reply', 'arp_request', 'unspecified']
VALID_ETHER_TYPES = ['arp', 'fcoe', 'ip', 'mac_security', 'mpls_ucast', 'trill', 'unspecified']
VALID_ICMP_TYPES = ['dst_unreachable', 'echo', 'echo_reply', 'src_quench', 'time_exceeded', 'unspecified']
VALID_ICMP6_TYPES = ['dst_unreachable', 'echo_request', 'echo_reply', 'neighbor_advertisement',
'neighbor_solicitation', 'redirect', 'time_exceeded', 'unspecified']
VALID_IP_PROTOCOLS = ['eigrp', 'egp', 'icmp', 'icmpv6', 'igmp', 'igp', 'l2tp', 'ospfigp', 'pim', 'tcp', 'udp', 'unspecified']
# mapping dicts are used to normalize the proposed data to what the APIC expects, which will keep diffs accurate
ARP_FLAG_MAPPING = dict(arp_reply='reply', arp_request='req', unspecified=None)
FILTER_PORT_MAPPING = {'443': 'https', '25': 'smtp', '80': 'http', '20': 'ftpData', '53': 'dns', '110': 'pop3', '554': 'rtsp'}
ICMP_MAPPING = {'dst_unreachable': 'dst-unreach', 'echo': 'echo', 'echo_reply': 'echo-rep', 'src_quench': 'src-quench',
'time_exceeded': 'time-exceeded', 'unspecified': 'unspecified', 'echo-rep': 'echo-rep', 'dst-unreach': 'dst-unreach'}
ICMP6_MAPPING = dict(dst_unreachable='dst-unreach', echo_request='echo-req', echo_reply='echo-rep', neighbor_advertisement='nbr-advert',
neighbor_solicitation='nbr-solicit', redirect='redirect', time_exceeded='time-exceeded', unspecified='unspecified')
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
arp_flag=dict(type='str', choices=VALID_ARP_FLAGS),
description=dict(type='str', aliases=['descr']),
dst_port=dict(type='str'),
dst_port_end=dict(type='str'),
dst_port_start=dict(type='str'),
entry=dict(type='str', aliases=['entry_name', 'filter_entry', 'name']), # Not required for querying all objects
ether_type=dict(choices=VALID_ETHER_TYPES, type='str'),
filter=dict(type='str', aliases=['filter_name']), # Not required for querying all objects
icmp_msg_type=dict(type='str', choices=VALID_ICMP_TYPES),
icmp6_msg_type=dict(type='str', choices=VALID_ICMP6_TYPES),
ip_protocol=dict(choices=VALID_IP_PROTOCOLS, type='str'),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
stateful=dict(type='bool'),
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['entry', 'filter', 'tenant']],
['state', 'present', ['entry', 'filter', 'tenant']],
],
)
aci = ACIModule(module)
arp_flag = module.params.get('arp_flag')
if arp_flag is not None:
arp_flag = ARP_FLAG_MAPPING.get(arp_flag)
description = module.params.get('description')
dst_port = module.params.get('dst_port')
if FILTER_PORT_MAPPING.get(dst_port) is not None:
dst_port = FILTER_PORT_MAPPING.get(dst_port)
dst_end = module.params.get('dst_port_end')
if FILTER_PORT_MAPPING.get(dst_end) is not None:
dst_end = FILTER_PORT_MAPPING.get(dst_end)
dst_start = module.params.get('dst_port_start')
if FILTER_PORT_MAPPING.get(dst_start) is not None:
dst_start = FILTER_PORT_MAPPING.get(dst_start)
entry = module.params.get('entry')
ether_type = module.params.get('ether_type')
filter_name = module.params.get('filter')
icmp_msg_type = module.params.get('icmp_msg_type')
if icmp_msg_type is not None:
icmp_msg_type = ICMP_MAPPING.get(icmp_msg_type)
icmp6_msg_type = module.params.get('icmp6_msg_type')
if icmp6_msg_type is not None:
icmp6_msg_type = ICMP6_MAPPING.get(icmp6_msg_type)
ip_protocol = module.params.get('ip_protocol')
state = module.params.get('state')
stateful = aci.boolean(module.params.get('stateful'))
tenant = module.params.get('tenant')
name_alias = module.params.get('name_alias')
# validate that dst_port is not passed with dst_start or dst_end
if dst_port is not None and (dst_end is not None or dst_start is not None):
module.fail_json(msg="Parameter 'dst_port' cannot be used with 'dst_end' and 'dst_start'")
elif dst_port is not None:
dst_end = dst_port
dst_start = dst_port
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='vzFilter',
aci_rn='flt-{0}'.format(filter_name),
module_object=filter_name,
target_filter={'name': filter_name},
),
subclass_2=dict(
aci_class='vzEntry',
aci_rn='e-{0}'.format(entry),
module_object=entry,
target_filter={'name': entry},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='vzEntry',
class_config=dict(
arpOpc=arp_flag,
descr=description,
dFromPort=dst_start,
dToPort=dst_end,
etherT=ether_type,
icmpv4T=icmp_msg_type,
icmpv6T=icmp6_msg_type,
name=entry,
prot=ip_protocol,
stateful=stateful,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='vzEntry')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,240 +0,0 @@
#!/usr/bin/python
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = '''
---
module: aci_firmware_group
short_description: This module creates a firmware group
version_added: "2.8"
description:
- This module creates a firmware group, so that you can apply firmware policy to nodes.
options:
group:
description:
- This the name of the firmware group
type: str
required: true
firmwarepol:
description:
- This is the name of the firmware policy, which was create by aci_firmware_policy. It is important that
- you use the same name as the policy created with aci_firmware_policy
type: str
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
default: present
choices: [ absent, present, query ]
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment:
- aci
author:
- Steven Gerhart (@sgerhart)
'''
EXAMPLES = '''
- name: firmware group
aci_firmware_group:
host: "{{ inventory_hostname }}"
username: "{{ user }}"
password: "{{ pass }}"
validate_certs: no
group: testingfwgrp1
firmwarepol: test2FrmPol
state: present
'''
RETURN = '''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
import json
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
from ansible.module_utils.basic import AnsibleModule
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
group=dict(type='str', aliases=['group']), # Not required for querying all objects
firmwarepol=dict(type='str'), # Not required for querying all objects
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['group']],
['state', 'present', ['group', 'firmwarepol']],
],
)
state = module.params.get('state')
group = module.params.get('group')
firmwarepol = module.params.get('firmwarepol')
name_alias = module.params.get('name_alias')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='firmwareFwGrp',
aci_rn='fabric/fwgrp-{0}'.format(group),
target_filter={'name': group},
module_object=group,
),
child_classes=['firmwareRsFwgrpp'],
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='firmwareFwGrp',
class_config=dict(
name=group,
nameAlias=name_alias,
),
child_configs=[
dict(
firmwareRsFwgrpp=dict(
attributes=dict(
tnFirmwareFwPName=firmwarepol,
),
),
),
],
)
aci.get_diff(aci_class='firmwareFwGrp')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,252 +0,0 @@
#!/usr/bin/python
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = '''
---
module: aci_firmware_group_node
short_description: This modules adds and remove nodes from the firmware group
version_added: "2.8"
description:
- This module addes/deletes a node to the firmware group. This modules assigns 1 node at a time.
options:
group:
description:
- This is the name of the firmware group
type: str
required: true
node:
description:
- The node to be added to the firmware group - the value equals the NodeID
type: str
required: true
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
default: present
choices: [ absent, present, query ]
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment:
- aci
author:
- Steven Gerhart (@sgerhart)
'''
EXAMPLES = '''
- name: add firmware group node
aci_firmware_group_node:
host: "{{ inventory_hostname }}"
username: "{{ user }}"
password: "{{ pass }}"
validate_certs: no
group: testingfwgrp
node: 1001
state: present
- name: Remove firmware group node
aci_firmware_group_node:
host: "{{ inventory_hostname }}"
username: "{{ user }}"
password: "{{ pass }}"
validate_certs: no
group: testingfwgrp
node: 1001
state: absent
'''
RETURN = '''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
import json
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
from ansible.module_utils.basic import AnsibleModule
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
group=dict(type='str', aliases=['group']), # Not required for querying all objects
node=dict(type='str', aliases=['node']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['node', 'group']],
['state', 'present', ['node', 'group']],
],
)
state = module.params.get('state')
group = module.params.get('group')
node = module.params.get('node')
name_alias = module.params.get('name_alias')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='firmwareFwGrp',
aci_rn='fabric/fwgrp-{0}'.format(group),
target_filter={'name': group},
module_object=group,
),
subclass_1=dict(
aci_class='fabricNodeBlk',
aci_rn='nodeblk-blk{0}-{0}'.format(node),
target_filter={'name': node},
module_object=node,
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='fabricNodeBlk',
class_config=dict(
from_=node,
to_=node,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='fabricNodeBlk')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,255 +0,0 @@
#!/usr/bin/python
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = '''
---
module: aci_firmware_policy
short_description: This creates a firmware policy
version_added: "2.8"
description:
- This module creates a firmware policy for firmware groups. The firmware policy is create first and then
- referenced by the firmware group. You will assign the firmware and specify if you want to ignore the compatibility
- check
options:
name:
description:
- Name of the firmware policy
type: str
required: true
version:
description:
- The version of the firmware associated with this policy. This value is very import as well as constructing
- it correctly. The syntax for this field is n9000-xx.x. If you look at the firmware repository using the UI
- each version will have a "Full Version" column, this is the value you need to use. So, if the Full Version
- is 13.1(1i), the value for this field would be n9000-13.1(1i)
type: str
required: true
ignoreCompat:
description:
- Check if compatibility checks should be ignored
type: bool
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [absent, present, query]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment:
- aci
author:
- Steven Gerhart (@sgerhart)
'''
EXAMPLES = '''
- name: firmware policy
aci_firmware_policy:
host: "{{ inventory_hostname }}"
username: "{{ user }}"
password: "{{ pass }}"
validate_certs: no
name: test2FrmPol
version: n9000-13.2(1m)
ignoreCompat: False
state: present
'''
RETURN = '''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
from ansible.module_utils.basic import AnsibleModule
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
name=dict(type='str', aliases=['name']), # Not required for querying all objects
version=dict(type='str', aliases=['version']),
ignoreCompat=dict(type='bool'),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['name']],
['state', 'present', ['name', 'version']],
],
)
state = module.params.get('state')
name = module.params.get('name')
version = module.params.get('version')
name_alias = module.params.get('name_alias')
if module.params.get('ignoreCompat'):
ignore = 'yes'
else:
ignore = 'no'
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='firmwareFwP',
aci_rn='fabric/fwpol-{0}'.format(name),
target_filter={'name': name},
module_object=name,
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='firmwareFwP',
class_config=dict(
name=name,
version=version,
ignoreCompat=ignore,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='firmwareFwP')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,290 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# 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)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_firmware_source
short_description: Manage firmware image sources (firmware:OSource)
description:
- Manage firmware image sources on Cisco ACI fabrics.
version_added: '2.5'
options:
source:
description:
- The identifying name for the outside source of images, such as an HTTP or SCP server.
type: str
required: yes
aliases: [ name, source_name ]
polling_interval:
description:
- Polling interval in minutes.
type: int
url_protocol:
description:
- The Firmware download protocol.
type: str
choices: [ http, local, scp, usbkey ]
default: scp
aliases: [ url_proto ]
url:
description:
The firmware URL for the image(s) on the source.
type: str
url_password:
description:
The Firmware password or key string.
type: str
url_username:
description:
The username for the source.
type: str
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
seealso:
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(firmware:OSource).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Dag Wieers (@dagwieers)
'''
EXAMPLES = r'''
- name: Add firmware source
aci_firmware_source:
host: apic
username: admin
password: SomeSecretPassword
source: aci-msft-pkg-3.1.1i.zip
url: foo.bar.cisco.com/download/cisco/aci/aci-msft-pkg-3.1.1i.zip
url_protocol: http
state: present
delegate_to: localhost
- name: Remove firmware source
aci_firmware_source:
host: apic
username: admin
password: SomeSecretPassword
source: aci-msft-pkg-3.1.1i.zip
state: absent
delegate_to: localhost
- name: Query a specific firmware source
aci_firmware_source:
host: apic
username: admin
password: SomeSecretPassword
source: aci-msft-pkg-3.1.1i.zip
state: query
delegate_to: localhost
register: query_result
- name: Query all firmware sources
aci_firmware_source:
host: apic
username: admin
password: SomeSecretPassword
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
source=dict(type='str', aliases=['name', 'source_name']), # Not required for querying all objects
polling_interval=dict(type='int'),
url=dict(type='str'),
url_username=dict(type='str'),
url_password=dict(type='str', no_log=True),
url_protocol=dict(type='str', default='scp', choices=['http', 'local', 'scp', 'usbkey'], aliases=['url_proto']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['source']],
['state', 'present', ['url_protocol', 'source', 'url']],
],
)
polling_interval = module.params.get('polling_interval')
url_protocol = module.params.get('url_protocol')
state = module.params.get('state')
source = module.params.get('source')
url = module.params.get('url')
url_password = module.params.get('url_password')
url_username = module.params.get('url_username')
name_alias = module.params.get('name_alias')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='firmwareOSource',
aci_rn='fabric/fwrepop',
module_object=source,
target_filter={'name': source},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='firmwareOSource',
class_config=dict(
name=source,
url=url,
password=url_password,
pollingInterval=polling_interval,
proto=url_protocol,
user=url_username,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='firmwareOSource')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,257 +0,0 @@
#!/usr/bin/python
# Copyright: (c) 2019, Tim Knipper <tim.knipper@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = r'''
---
module: aci_interface_policy_cdp
short_description: Manage CDP interface policies (cdp:IfPol)
description:
- Manage CDP interface policies on Cisco ACI fabrics.
version_added: '2.9'
options:
cdp_policy:
description:
- The CDP interface policy name.
type: str
required: yes
aliases: [ cdp_interface, name ]
description:
description:
- The description for the CDP interface policy name.
type: str
aliases: [ descr ]
admin_state:
description:
- Enable or Disable CDP state.
- The APIC defaults to C(yes) when unset during creation.
type: bool
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
seealso:
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(cdp:IfPol).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Tim Knipper (@tknipper11)
'''
EXAMPLES = r'''
- name: Create CDP Test Policy
aci_interface_policy_cdp:
name: Ansible_CDP_Test_Policy
host: apic.example.com
username: admin
password: adminpass
state: present
- name: Remove CDP Test Policy
aci_interface_policy_cdp:
name: Ansible_CDP_Test_Policy
host: apic.example.com
username: admin
password: adminpass
output_level: debug
state: absent
- name: Query CDP Policy
aci_interface_policy_cdp:
host: apic.example.com
username: admin
password: adminpass
state: query
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"cdpIfPol": {
"attributes": {
"adminSt": "disabled",
"annotation": "",
"descr": "Ansible Created CDP Test Policy",
"dn": "uni/infra/cdpIfP-Ansible_CDP_Test_Policy",
"name": "Ansible_CDP_Test_Policy",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
from ansible.module_utils.basic import AnsibleModule
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
cdp_policy=dict(type='str', required=False, aliases=['cdp_interface', 'name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
admin_state=dict(type='bool'),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['cdp_policy']],
['state', 'present', ['cdp_policy']],
],
)
aci = ACIModule(module)
cdp_policy = module.params.get('cdp_policy')
description = module.params.get('description')
admin_state = aci.boolean(module.params.get('admin_state'), 'enabled', 'disabled')
state = module.params.get('state')
name_alias = module.params.get('name_alias')
aci.construct_url(
root_class=dict(
aci_class='cdpIfPol',
aci_rn='infra/cdpIfP-{0}'.format(cdp_policy),
module_object=cdp_policy,
target_filter={'name': cdp_policy},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='cdpIfPol',
class_config=dict(
name=cdp_policy,
descr=description,
adminSt=admin_state,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='cdpIfPol')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == '__main__':
main()

@ -1,239 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_interface_policy_fc
short_description: Manage Fibre Channel interface policies (fc:IfPol)
description:
- Manage ACI Fiber Channel interface policies on Cisco ACI fabrics.
version_added: '2.4'
options:
fc_policy:
description:
- The name of the Fiber Channel interface policy.
type: str
required: yes
aliases: [ name ]
description:
description:
- The description of the Fiber Channel interface policy.
type: str
aliases: [ descr ]
port_mode:
description:
- The Port Mode to use.
- The APIC defaults to C(f) when unset during creation.
type: str
choices: [ f, np ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
seealso:
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(fc:IfPol).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Dag Wieers (@dagwieers)
'''
EXAMPLES = r'''
- aci_interface_policy_fc:
host: '{{ hostname }}'
username: '{{ username }}'
password: '{{ password }}'
fc_policy: '{{ fc_policy }}'
port_mode: '{{ port_mode }}'
description: '{{ description }}'
state: present
delegate_to: localhost
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
fc_policy=dict(type='str', aliases=['name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
port_mode=dict(type='str', choices=['f', 'np']), # No default provided on purpose
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['fc_policy']],
['state', 'present', ['fc_policy']],
],
)
fc_policy = module.params.get('fc_policy')
port_mode = module.params.get('port_mode')
description = module.params.get('description')
state = module.params.get('state')
name_alias = module.params.get('name_alias')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='fcIfPol',
aci_rn='infra/fcIfPol-{0}'.format(fc_policy),
module_object=fc_policy,
target_filter={'name': fc_policy},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='fcIfPol',
class_config=dict(
name=fc_policy,
descr=description,
portMode=port_mode,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='fcIfPol')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,264 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_interface_policy_l2
short_description: Manage Layer 2 interface policies (l2:IfPol)
description:
- Manage Layer 2 interface policies on Cisco ACI fabrics.
version_added: '2.4'
options:
l2_policy:
description:
- The name of the Layer 2 interface policy.
type: str
required: yes
aliases: [ name ]
description:
description:
- The description of the Layer 2 interface policy.
type: str
aliases: [ descr ]
qinq:
description:
- Determines if QinQ is disabled or if the port should be considered a core or edge port.
- The APIC defaults to C(disabled) when unset during creation.
type: str
choices: [ core, disabled, edge ]
vepa:
description:
- Determines if Virtual Ethernet Port Aggregator is disabled or enabled.
- The APIC defaults to C(no) when unset during creation.
type: bool
vlan_scope:
description:
- The scope of the VLAN.
- The APIC defaults to C(global) when unset during creation.
type: str
choices: [ global, portlocal ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
seealso:
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(l2:IfPol).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Dag Wieers (@dagwieers)
'''
EXAMPLES = r'''
- aci_interface_policy_l2:
host: '{{ hostname }}'
username: '{{ username }}'
password: '{{ password }}'
l2_policy: '{{ l2_policy }}'
vlan_scope: '{{ vlan_policy }}'
description: '{{ description }}'
delegate_to: localhost
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
# Mapping dicts are used to normalize the proposed data to what the APIC expects, which will keep diffs accurate
QINQ_MAPPING = dict(
core='corePort',
disabled='disabled',
edge='edgePort',
)
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
l2_policy=dict(type='str', aliases=['name']), # Not required for querying all policies
description=dict(type='str', aliases=['descr']),
vlan_scope=dict(type='str', choices=['global', 'portlocal']), # No default provided on purpose
qinq=dict(type='str', choices=['core', 'disabled', 'edge']),
vepa=dict(type='bool'),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['l2_policy']],
['state', 'present', ['l2_policy']],
],
)
aci = ACIModule(module)
l2_policy = module.params.get('l2_policy')
vlan_scope = module.params.get('vlan_scope')
qinq = module.params.get('qinq')
if qinq is not None:
qinq = QINQ_MAPPING.get(qinq)
vepa = aci.boolean(module.params.get('vepa'), 'enabled', 'disabled')
description = module.params.get('description')
state = module.params.get('state')
name_alias = module.params.get('name_alias')
aci.construct_url(
root_class=dict(
aci_class='l2IfPol',
aci_rn='infra/l2IfP-{0}'.format(l2_policy),
module_object=l2_policy,
target_filter={'name': l2_policy},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='l2IfPol',
class_config=dict(
name=l2_policy,
descr=description,
vlanScope=vlan_scope,
qinq=qinq, vepa=vepa,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='l2IfPol')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,570 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Bruno Calogero <brunocalogero@hotmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_interface_policy_leaf_policy_group
short_description: Manage fabric interface policy leaf policy groups (infra:AccBndlGrp, infra:AccPortGrp)
description:
- Manage fabric interface policy leaf policy groups on Cisco ACI fabrics.
version_added: '2.5'
options:
policy_group:
description:
- Name of the leaf policy group to be added/deleted.
type: str
aliases: [ name, policy_group_name ]
description:
description:
- Description for the leaf policy group to be created.
type: str
aliases: [ descr ]
lag_type:
description:
- Selector for the type of leaf policy group we want to create.
- C(leaf) for Leaf Access Port Policy Group
- C(link) for Port Channel (PC)
- C(node) for Virtual Port Channel (VPC)
type: str
required: yes
choices: [ leaf, link, node ]
aliases: [ lag_type_name ]
link_level_policy:
description:
- Choice of link_level_policy to be used as part of the leaf policy group to be created.
type: str
aliases: [ link_level_policy_name ]
cdp_policy:
description:
- Choice of cdp_policy to be used as part of the leaf policy group to be created.
type: str
aliases: [ cdp_policy_name ]
mcp_policy:
description:
- Choice of mcp_policy to be used as part of the leaf policy group to be created.
type: str
aliases: [ mcp_policy_name ]
lldp_policy:
description:
- Choice of lldp_policy to be used as part of the leaf policy group to be created.
type: str
aliases: [ lldp_policy_name ]
stp_interface_policy:
description:
- Choice of stp_interface_policy to be used as part of the leaf policy group to be created.
type: str
aliases: [ stp_interface_policy_name ]
egress_data_plane_policing_policy:
description:
- Choice of egress_data_plane_policing_policy to be used as part of the leaf policy group to be created.
type: str
aliases: [ egress_data_plane_policing_policy_name ]
ingress_data_plane_policing_policy:
description:
- Choice of ingress_data_plane_policing_policy to be used as part of the leaf policy group to be created.
type: str
aliases: [ ingress_data_plane_policing_policy_name ]
priority_flow_control_policy:
description:
- Choice of priority_flow_control_policy to be used as part of the leaf policy group to be created.
type: str
aliases: [ priority_flow_control_policy_name ]
fibre_channel_interface_policy:
description:
- Choice of fibre_channel_interface_policy to be used as part of the leaf policy group to be created.
type: str
aliases: [ fibre_channel_interface_policy_name ]
slow_drain_policy:
description:
- Choice of slow_drain_policy to be used as part of the leaf policy group to be created.
type: str
aliases: [ slow_drain_policy_name ]
port_channel_policy:
description:
- Choice of port_channel_policy to be used as part of the leaf policy group to be created.
type: str
aliases: [ port_channel_policy_name ]
monitoring_policy:
description:
- Choice of monitoring_policy to be used as part of the leaf policy group to be created.
type: str
aliases: [ monitoring_policy_name ]
storm_control_interface_policy:
description:
- Choice of storm_control_interface_policy to be used as part of the leaf policy group to be created.
type: str
aliases: [ storm_control_interface_policy_name ]
l2_interface_policy:
description:
- Choice of l2_interface_policy to be used as part of the leaf policy group to be created.
type: str
aliases: [ l2_interface_policy_name ]
port_security_policy:
description:
- Choice of port_security_policy to be used as part of the leaf policy group to be created.
type: str
aliases: [ port_security_policy_name ]
aep:
description:
- Choice of attached_entity_profile (AEP) to be used as part of the leaf policy group to be created.
type: str
aliases: [ aep_name ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
notes:
- When using the module please select the appropriate link_aggregation_type (lag_type).
C(link) for Port Channel(PC), C(node) for Virtual Port Channel(VPC) and C(leaf) for Leaf Access Port Policy Group.
seealso:
- name: APIC Management Information Model reference
description: More information about the internal APIC classes B(infra:AccBndlGrp) and B(infra:AccPortGrp).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Bruno Calogero (@brunocalogero)
'''
EXAMPLES = r'''
- name: Create a Port Channel (PC) Interface Policy Group
aci_interface_policy_leaf_policy_group:
host: apic
username: admin
password: SomeSecretPassword
lag_type: link
policy_group: policygroupname
description: policygroupname description
link_level_policy: whateverlinklevelpolicy
fibre_channel_interface_policy: whateverfcpolicy
state: present
delegate_to: localhost
- name: Create a Virtual Port Channel (VPC) Interface Policy Group (no description)
aci_interface_policy_leaf_policy_group:
host: apic
username: admin
password: SomeSecretPassword
lag_type: node
policy_group: policygroupname
link_level_policy: whateverlinklevelpolicy
fibre_channel_interface_policy: whateverfcpolicy
state: present
delegate_to: localhost
- name: Create a Leaf Access Port Policy Group (no description)
aci_interface_policy_leaf_policy_group:
host: apic
username: admin
password: SomeSecretPassword
lag_type: leaf
policy_group: policygroupname
link_level_policy: whateverlinklevelpolicy
fibre_channel_interface_policy: whateverfcpolicy
state: present
delegate_to: localhost
- name: Query all Leaf Access Port Policy Groups of type link
aci_interface_policy_leaf_policy_group:
host: apic
username: admin
password: SomeSecretPassword
lag_type: link
state: query
delegate_to: localhost
register: query_result
- name: Query a specific Lead Access Port Policy Group
aci_interface_policy_leaf_policy_group:
host: apic
username: admin
password: SomeSecretPassword
lag_type: leaf
policy_group: policygroupname
state: query
delegate_to: localhost
register: query_result
- name: Delete an Interface policy Leaf Policy Group
aci_interface_policy_leaf_policy_group:
host: apic
username: admin
password: SomeSecretPassword
lag_type: type_name
policy_group: policygroupname
state: absent
delegate_to: localhost
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
# NOTE: Since this module needs to include both infra:AccBndlGrp (for PC and VPC) and infra:AccPortGrp (for leaf access port policy group):
# NOTE: I'll allow the user to make the choice here (link(PC), node(VPC), leaf(leaf-access port policy group))
lag_type=dict(type='str', required=True, aliases=['lag_type_name'], choices=['leaf', 'link', 'node']),
policy_group=dict(type='str', aliases=['name', 'policy_group_name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
link_level_policy=dict(type='str', aliases=['link_level_policy_name']),
cdp_policy=dict(type='str', aliases=['cdp_policy_name']),
mcp_policy=dict(type='str', aliases=['mcp_policy_name']),
lldp_policy=dict(type='str', aliases=['lldp_policy_name']),
stp_interface_policy=dict(type='str', aliases=['stp_interface_policy_name']),
egress_data_plane_policing_policy=dict(type='str', aliases=['egress_data_plane_policing_policy_name']),
ingress_data_plane_policing_policy=dict(type='str', aliases=['ingress_data_plane_policing_policy_name']),
priority_flow_control_policy=dict(type='str', aliases=['priority_flow_control_policy_name']),
fibre_channel_interface_policy=dict(type='str', aliases=['fibre_channel_interface_policy_name']),
slow_drain_policy=dict(type='str', aliases=['slow_drain_policy_name']),
port_channel_policy=dict(type='str', aliases=['port_channel_policy_name']),
monitoring_policy=dict(type='str', aliases=['monitoring_policy_name']),
storm_control_interface_policy=dict(type='str', aliases=['storm_control_interface_policy_name']),
l2_interface_policy=dict(type='str', aliases=['l2_interface_policy_name']),
port_security_policy=dict(type='str', aliases=['port_security_policy_name']),
aep=dict(type='str', aliases=['aep_name']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['policy_group']],
['state', 'present', ['policy_group']],
],
)
policy_group = module.params.get('policy_group')
description = module.params.get('description')
lag_type = module.params.get('lag_type')
link_level_policy = module.params.get('link_level_policy')
cdp_policy = module.params.get('cdp_policy')
mcp_policy = module.params.get('mcp_policy')
lldp_policy = module.params.get('lldp_policy')
stp_interface_policy = module.params.get('stp_interface_policy')
egress_data_plane_policing_policy = module.params.get('egress_data_plane_policing_policy')
ingress_data_plane_policing_policy = module.params.get('ingress_data_plane_policing_policy')
priority_flow_control_policy = module.params.get('priority_flow_control_policy')
fibre_channel_interface_policy = module.params.get('fibre_channel_interface_policy')
slow_drain_policy = module.params.get('slow_drain_policy')
port_channel_policy = module.params.get('port_channel_policy')
monitoring_policy = module.params.get('monitoring_policy')
storm_control_interface_policy = module.params.get('storm_control_interface_policy')
l2_interface_policy = module.params.get('l2_interface_policy')
port_security_policy = module.params.get('port_security_policy')
aep = module.params.get('aep')
state = module.params.get('state')
name_alias = module.params.get('name_alias')
if lag_type == 'leaf':
aci_class_name = 'infraAccPortGrp'
dn_name = 'accportgrp'
class_config_dict = dict(
name=policy_group,
descr=description,
nameAlias=name_alias,
)
# Reset for target_filter
lag_type = None
elif lag_type in ('link', 'node'):
aci_class_name = 'infraAccBndlGrp'
dn_name = 'accbundle'
class_config_dict = dict(
name=policy_group,
descr=description,
lagT=lag_type,
nameAlias=name_alias,
)
child_configs = [
dict(
infraRsCdpIfPol=dict(
attributes=dict(
tnCdpIfPolName=cdp_policy,
),
),
),
dict(
infraRsFcIfPol=dict(
attributes=dict(
tnFcIfPolName=fibre_channel_interface_policy,
),
),
),
dict(
infraRsHIfPol=dict(
attributes=dict(
tnFabricHIfPolName=link_level_policy,
),
),
),
dict(
infraRsL2IfPol=dict(
attributes=dict(
tnL2IfPolName=l2_interface_policy,
),
),
),
dict(
infraRsL2PortSecurityPol=dict(
attributes=dict(
tnL2PortSecurityPolName=port_security_policy,
),
),
),
dict(
infraRsLacpPol=dict(
attributes=dict(
tnLacpLagPolName=port_channel_policy,
),
),
),
dict(
infraRsLldpIfPol=dict(
attributes=dict(
tnLldpIfPolName=lldp_policy,
),
),
),
dict(
infraRsMcpIfPol=dict(
attributes=dict(
tnMcpIfPolName=mcp_policy,
),
),
),
dict(
infraRsMonIfInfraPol=dict(
attributes=dict(
tnMonInfraPolName=monitoring_policy,
),
),
),
dict(
infraRsQosEgressDppIfPol=dict(
attributes=dict(
tnQosDppPolName=egress_data_plane_policing_policy,
),
),
),
dict(
infraRsQosIngressDppIfPol=dict(
attributes=dict(
tnQosDppPolName=ingress_data_plane_policing_policy,
),
),
),
dict(
infraRsQosPfcIfPol=dict(
attributes=dict(
tnQosPfcIfPolName=priority_flow_control_policy,
),
),
),
dict(
infraRsQosSdIfPol=dict(
attributes=dict(
tnQosSdIfPolName=slow_drain_policy,
),
),
),
dict(
infraRsStormctrlIfPol=dict(
attributes=dict(
tnStormctrlIfPolName=storm_control_interface_policy,
),
),
),
dict(
infraRsStpIfPol=dict(
attributes=dict(
tnStpIfPolName=stp_interface_policy,
),
),
),
]
# Add infraRsattEntP binding only when aep was defined
if aep is not None:
child_configs.append(dict(
infraRsAttEntP=dict(
attributes=dict(
tDn='uni/infra/attentp-{0}'.format(aep),
),
),
))
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class=aci_class_name,
aci_rn='infra/funcprof/{0}-{1}'.format(dn_name, policy_group),
module_object=policy_group,
target_filter={'name': policy_group, 'lagT': lag_type},
),
child_classes=[
'infraRsAttEntP',
'infraRsCdpIfPol',
'infraRsFcIfPol',
'infraRsHIfPol',
'infraRsL2IfPol',
'infraRsL2PortSecurityPol',
'infraRsLacpPol',
'infraRsLldpIfPol',
'infraRsMcpIfPol',
'infraRsMonIfInfraPol',
'infraRsQosEgressDppIfPol',
'infraRsQosIngressDppIfPol',
'infraRsQosPfcIfPol',
'infraRsQosSdIfPol',
'infraRsStormctrlIfPol',
'infraRsStpIfPol',
],
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class=aci_class_name,
class_config=class_config_dict,
child_configs=child_configs,
)
aci.get_diff(aci_class=aci_class_name)
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,257 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Bruno Calogero <brunocalogero@hotmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_interface_policy_leaf_profile
short_description: Manage fabric interface policy leaf profiles (infra:AccPortP)
description:
- Manage fabric interface policy leaf profiles on Cisco ACI fabrics.
version_added: '2.5'
options:
leaf_interface_profile:
description:
- The name of the Fabric access policy leaf interface profile.
type: str
required: yes
aliases: [ name, leaf_interface_profile_name ]
description:
description:
- Description for the Fabric access policy leaf interface profile.
type: str
aliases: [ descr ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
seealso:
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(infra:AccPortP).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Bruno Calogero (@brunocalogero)
'''
EXAMPLES = r'''
- name: Add a new leaf_interface_profile
aci_interface_policy_leaf_profile:
host: apic
username: admin
password: SomeSecretPassword
leaf_interface_profile: leafintprfname
description: leafintprfname description
state: present
delegate_to: localhost
- name: Remove a leaf_interface_profile
aci_interface_policy_leaf_profile:
host: apic
username: admin
password: SomeSecretPassword
leaf_interface_profile: leafintprfname
state: absent
delegate_to: localhost
- name: Remove all leaf_interface_profiles
aci_interface_policy_leaf_profile:
host: apic
username: admin
password: SomeSecretPassword
state: absent
delegate_to: localhost
- name: Query a leaf_interface_profile
aci_interface_policy_leaf_profile:
host: apic
username: admin
password: SomeSecretPassword
leaf_interface_profile: leafintprfname
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
leaf_interface_profile=dict(type='str', aliases=['name', 'leaf_interface_profile_name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['leaf_interface_profile']],
['state', 'present', ['leaf_interface_profile']],
],
)
leaf_interface_profile = module.params.get('leaf_interface_profile')
description = module.params.get('description')
state = module.params.get('state')
name_alias = module.params.get('name_alias')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='infraAccPortP',
aci_rn='infra/accportprof-{0}'.format(leaf_interface_profile),
module_object=leaf_interface_profile,
target_filter={'name': leaf_interface_profile},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='infraAccPortP',
class_config=dict(
name=leaf_interface_profile,
descr=description,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='infraAccPortP')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,248 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_interface_policy_lldp
short_description: Manage LLDP interface policies (lldp:IfPol)
description:
- Manage LLDP interface policies on Cisco ACI fabrics.
version_added: '2.4'
options:
lldp_policy:
description:
- The LLDP interface policy name.
type: str
required: yes
aliases: [ name ]
description:
description:
- The description for the LLDP interface policy name.
type: str
aliases: [ descr ]
receive_state:
description:
- Enable or disable Receive state.
- The APIC defaults to C(yes) when unset during creation.
type: bool
transmit_state:
description:
- Enable or Disable Transmit state.
- The APIC defaults to C(yes) when unset during creation.
type: bool
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
seealso:
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(lldp:IfPol).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Dag Wieers (@dagwieers)
'''
# FIXME: Add more, better examples
EXAMPLES = r'''
- aci_interface_policy_lldp:
host: '{{ hostname }}'
username: '{{ username }}'
password: '{{ password }}'
lldp_policy: '{{ lldp_policy }}'
description: '{{ description }}'
receive_state: '{{ receive_state }}'
transmit_state: '{{ transmit_state }}'
delegate_to: localhost
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
lldp_policy=dict(type='str', aliases=['name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
receive_state=dict(type='bool'),
transmit_state=dict(type='bool'),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['lldp_policy']],
['state', 'present', ['lldp_policy']],
],
)
aci = ACIModule(module)
lldp_policy = module.params.get('lldp_policy')
description = module.params.get('description')
receive_state = aci.boolean(module.params.get('receive_state'), 'enabled', 'disabled')
transmit_state = aci.boolean(module.params.get('transmit_state'), 'enabled', 'disabled')
state = module.params.get('state')
name_alias = module.params.get('name_alias')
aci.construct_url(
root_class=dict(
aci_class='lldpIfPol',
aci_rn='infra/lldpIfP-{0}'.format(lldp_policy),
module_object=lldp_policy,
target_filter={'name': lldp_policy},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='lldpIfPol',
class_config=dict(
name=lldp_policy,
descr=description,
adminRxSt=receive_state,
adminTxSt=transmit_state,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='lldpIfPol')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,239 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_interface_policy_mcp
short_description: Manage MCP interface policies (mcp:IfPol)
description:
- Manage MCP interface policies on Cisco ACI fabrics.
version_added: '2.4'
options:
mcp:
description:
- The name of the MCP interface.
type: str
required: yes
aliases: [ mcp_interface, name ]
description:
description:
- The description for the MCP interface.
type: str
aliases: [ descr ]
admin_state:
description:
- Enable or disable admin state.
- The APIC defaults to C(yes) when unset during creation.
type: bool
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
seealso:
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(mcp:IfPol).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Dag Wieers (@dagwieers)
'''
# FIXME: Add more, better examples
EXAMPLES = r'''
- aci_interface_policy_mcp:
host: '{{ hostname }}'
username: '{{ username }}'
password: '{{ password }}'
mcp: '{{ mcp }}'
description: '{{ descr }}'
admin_state: '{{ admin_state }}'
delegate_to: localhost
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
mcp=dict(type='str', aliases=['mcp_interface', 'name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
admin_state=dict(type='bool'),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['mcp']],
['state', 'present', ['mcp']],
],
)
aci = ACIModule(module)
mcp = module.params.get('mcp')
description = module.params.get('description')
admin_state = aci.boolean(module.params.get('admin_state'), 'enabled', 'disabled')
state = module.params.get('state')
name_alias = module.params.get('name_alias')
aci.construct_url(
root_class=dict(
aci_class='mcpIfPol',
aci_rn='infra/mcpIfP-{0}'.format(mcp),
module_object=mcp,
target_filter={'name': mcp},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='mcpIfPol',
class_config=dict(
name=mcp,
descr=description,
adminSt=admin_state,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='mcpIfPol')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,406 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# 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)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_interface_policy_ospf
short_description: Manage OSPF interface policies (ospf:IfPol)
description:
- Manage OSPF interface policies on Cisco ACI fabrics.
version_added: '2.7'
options:
tenant:
description:
- The name of the Tenant the OSPF interface policy should belong to.
type: str
required: yes
aliases: [ tenant_name ]
ospf:
description:
- The OSPF interface policy name.
- This name can be between 1 and 64 alphanumeric characters.
- Note that you cannot change this name after the object has been saved.
type: str
required: yes
aliases: [ ospf_interface, name ]
description:
description:
- The description for the OSPF interface.
type: str
aliases: [ descr ]
network_type:
description:
- The OSPF interface policy network type.
- OSPF supports broadcast and point-to-point.
- The APIC defaults to C(unspecified) when unset during creation.
type: str
choices: [ bcast, p2p ]
cost:
description:
- The OSPF cost of the interface.
- The cost (also called metric) of an interface in OSPF is an indication of
the overhead required to send packets across a certain interface. The
cost of an interface is inversely proportional to the bandwidth of that
interface. A higher bandwidth indicates a lower cost. There is more
overhead (higher cost) and time delays involved in crossing a 56k serial
line than crossing a 10M ethernet line. The formula used to calculate the
cost is C(cost= 10000 0000/bandwith in bps) For example, it will cost
10 EXP8/10 EXP7 = 10 to cross a 10M Ethernet line and will cost
10 EXP8/1544000 = 64 to cross a T1 line.
- By default, the cost of an interface is calculated based on the bandwidth;
you can force the cost of an interface with the ip ospf cost value
interface subconfiguration mode command.
- Accepted values range between C(1) and C(450).
- The APIC defaults to C(0) when unset during creation.
type: int
controls:
description:
- The interface policy controls.
- 'This is a list of one or more of the following controls:'
- C(advert-subnet) -- Advertise IP subnet instead of a host mask in the router LSA.
- C(bfd) -- Bidirectional Forwarding Detection
- C(mtu-ignore) -- Disables MTU mismatch detection on an interface.
- C(passive) -- The interface does not participate in the OSPF protocol and
will not establish adjacencies or send routing updates. However the
interface is announced as part of the routing network.
type: list
choices: [ advert-subnet, bfd, mtu-ignore, passive ]
dead_interval:
description:
- The interval between hello packets from a neighbor before the router
declares the neighbor as down.
- This value must be the same for all networking devices on a specific network.
- Specifying a smaller dead interval (seconds) will give faster detection
of a neighbor being down and improve convergence, but might cause more
routing instability.
- Accepted values range between C(1) and C(65535).
- The APIC defaults to C(40) when unset during creation.
type: int
hello_interval:
description:
- The interval between hello packets that OSPF sends on the interface.
- Note that the smaller the hello interval, the faster topological changes will be detected, but more routing traffic will ensue.
- This value must be the same for all routers and access servers on a specific network.
- Accepted values range between C(1) and C(65535).
- The APIC defaults to C(10) when unset during creation.
type: int
prefix_suppression:
description:
- Whether prefix suppressions is enabled or disabled.
- The APIC defaults to C(inherit) when unset during creation.
type: bool
priority:
description:
- The priority for the OSPF interface profile.
- Accepted values ranges between C(0) and C(255).
- The APIC defaults to C(1) when unset during creation.
type: int
retransmit_interval:
description:
- The interval between LSA retransmissions.
- The retransmit interval occurs while the router is waiting for an acknowledgement from the neighbor router that it received the LSA.
- If no acknowledgment is received at the end of the interval, then the LSA is resent.
- Accepted values range between C(1) and C(65535).
- The APIC defaults to C(5) when unset during creation.
type: int
transmit_delay:
description:
- The delay time needed to send an LSA update packet.
- OSPF increments the LSA age time by the transmit delay amount before transmitting the LSA update.
- You should take into account the transmission and propagation delays for the interface when you set this value.
- Accepted values range between C(1) and C(450).
- The APIC defaults to C(1) when unset during creation.
type: int
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
seealso:
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(ospf:IfPol).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Dag Wieers (@dagwieers)
'''
EXAMPLES = r'''
- name: Ensure ospf interface policy exists
aci_interface_policy_ospf:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
ospf: ospf1
state: present
delegate_to: localhost
- name: Ensure ospf interface policy does not exist
aci_interface_policy_ospf:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
ospf: ospf1
state: present
delegate_to: localhost
- name: Query an ospf interface policy
aci_interface_policy_ospf:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
ospf: ospf1
state: query
delegate_to: localhost
register: query_result
- name: Query all ospf interface policies in tenant production
aci_interface_policy_ospf:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
ospf=dict(type='str', aliases=['ospf_interface', 'name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
network_type=dict(type='str', choices=['bcast', 'p2p']),
cost=dict(type='int'),
controls=dict(type='list', choices=['advert-subnet', 'bfd', 'mtu-ignore', 'passive']),
dead_interval=dict(type='int'),
hello_interval=dict(type='int'),
prefix_suppression=dict(type='bool'),
priority=dict(type='int'),
retransmit_interval=dict(type='int'),
transmit_delay=dict(type='int'),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['ospf', 'tenant']],
['state', 'present', ['ospf', 'tenant']],
],
)
aci = ACIModule(module)
tenant = module.params.get('tenant')
ospf = module.params.get('ospf')
description = module.params.get('description')
name_alias = module.params.get('name_alias')
if module.params.get('controls') is None:
controls = None
else:
controls = ','.join(module.params.get('controls'))
cost = module.params.get('cost')
if cost is not None and cost not in range(1, 451):
module.fail_json(msg="Parameter 'cost' is only valid in range between 1 and 450.")
dead_interval = module.params.get('dead_interval')
if dead_interval is not None and dead_interval not in range(1, 65536):
module.fail_json(msg="Parameter 'dead_interval' is only valid in range between 1 and 65536.")
hello_interval = module.params.get('hello_interval')
if hello_interval is not None and hello_interval not in range(1, 65536):
module.fail_json(msg="Parameter 'hello_interval' is only valid in range between 1 and 65536.")
network_type = module.params.get('network_type')
prefix_suppression = aci.boolean(module.params.get('prefix_suppression'), 'enabled', 'disabled')
priority = module.params.get('priority')
if priority is not None and priority not in range(0, 256):
module.fail_json(msg="Parameter 'priority' is only valid in range between 1 and 255.")
retransmit_interval = module.params.get('retransmit_interval')
if retransmit_interval is not None and retransmit_interval not in range(1, 65536):
module.fail_json(msg="Parameter 'retransmit_interval' is only valid in range between 1 and 65536.")
transmit_delay = module.params.get('transmit_delay')
if transmit_delay is not None and transmit_delay not in range(1, 451):
module.fail_json(msg="Parameter 'transmit_delay' is only valid in range between 1 and 450.")
state = module.params.get('state')
aci.construct_url(
root_class=dict(
aci_class='ospfIfPol',
aci_rn='tn-{0}/ospfIfPol-{1}'.format(tenant, ospf),
module_object=ospf,
target_filter={'name': ospf},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='ospfIfPol',
class_config=dict(
name=ospf,
descr=description,
cost=cost,
ctrl=controls,
deadIntvl=dead_interval,
helloIntvl=hello_interval,
nwT=network_type,
pfxSuppress=prefix_suppression,
prio=priority,
rexmitIntvl=retransmit_interval,
xmitDelay=transmit_delay,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='ospfIfPol')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,321 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_interface_policy_port_channel
short_description: Manage port channel interface policies (lacp:LagPol)
description:
- Manage port channel interface policies on Cisco ACI fabrics.
version_added: '2.4'
options:
port_channel:
description:
- Name of the port channel.
type: str
required: yes
aliases: [ name ]
description:
description:
- The description for the port channel.
type: str
aliases: [ descr ]
max_links:
description:
- Maximum links.
- Accepted values range between 1 and 16.
- The APIC defaults to C(16) when unset during creation.
type: int
min_links:
description:
- Minimum links.
- Accepted values range between 1 and 16.
- The APIC defaults to C(1) when unset during creation.
type: int
mode:
description:
- Port channel interface policy mode.
- Determines the LACP method to use for forming port-channels.
- The APIC defaults to C(off) when unset during creation.
type: str
choices: [ active, mac-pin, mac-pin-nicload, 'off', passive ]
fast_select:
description:
- Determines if Fast Select is enabled for Hot Standby Ports.
- This makes up the LACP Policy Control Policy; if one setting is defined, then all other Control Properties
left undefined or set to false will not exist after the task is ran.
- The APIC defaults to C(yes) when unset during creation.
type: bool
graceful_convergence:
description:
- Determines if Graceful Convergence is enabled.
- This makes up the LACP Policy Control Policy; if one setting is defined, then all other Control Properties
left undefined or set to false will not exist after the task is ran.
- The APIC defaults to C(yes) when unset during creation.
type: bool
load_defer:
description:
- Determines if Load Defer is enabled.
- This makes up the LACP Policy Control Policy; if one setting is defined, then all other Control Properties
left undefined or set to false will not exist after the task is ran.
- The APIC defaults to C(no) when unset during creation.
type: bool
suspend_individual:
description:
- Determines if Suspend Individual is enabled.
- This makes up the LACP Policy Control Policy; if one setting is defined, then all other Control Properties
left undefined or set to false will not exist after the task is ran.
- The APIC defaults to C(yes) when unset during creation.
type: bool
symmetric_hash:
description:
- Determines if Symmetric Hashing is enabled.
- This makes up the LACP Policy Control Policy; if one setting is defined, then all other Control Properties
left undefined or set to false will not exist after the task is ran.
- The APIC defaults to C(no) when unset during creation.
type: bool
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
seealso:
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(lacp:LagPol).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Dag Wieers (@dagwieers)
'''
EXAMPLES = r'''
- aci_interface_policy_port_channel:
host: '{{ inventory_hostname }}'
username: '{{ username }}'
password: '{{ password }}'
port_channel: '{{ port_channel }}'
description: '{{ description }}'
min_links: '{{ min_links }}'
max_links: '{{ max_links }}'
mode: '{{ mode }}'
delegate_to: localhost
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
port_channel=dict(type='str', aliases=['name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
min_links=dict(type='int'),
max_links=dict(type='int'),
mode=dict(type='str', choices=['active', 'mac-pin', 'mac-pin-nicload', 'off', 'passive']),
fast_select=dict(type='bool'),
graceful_convergence=dict(type='bool'),
load_defer=dict(type='bool'),
suspend_individual=dict(type='bool'),
symmetric_hash=dict(type='bool'),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['port_channel']],
['state', 'present', ['port_channel']],
],
)
port_channel = module.params.get('port_channel')
description = module.params.get('description')
min_links = module.params.get('min_links')
if min_links is not None and min_links not in range(1, 17):
module.fail_json(msg='The "min_links" must be a value between 1 and 16')
max_links = module.params.get('max_links')
if max_links is not None and max_links not in range(1, 17):
module.fail_json(msg='The "max_links" must be a value between 1 and 16')
mode = module.params.get('mode')
state = module.params.get('state')
name_alias = module.params.get('name_alias')
# Build ctrl value for request
ctrl = []
if module.params.get('fast_select') is True:
ctrl.append('fast-sel-hot-stdby')
if module.params.get('graceful_convergence') is True:
ctrl.append('graceful-conv')
if module.params.get('load_defer') is True:
ctrl.append('load-defer')
if module.params.get('suspend_individual') is True:
ctrl.append('susp-individual')
if module.params.get('symmetric_hash') is True:
ctrl.append('symmetric-hash')
if not ctrl:
ctrl = None
else:
ctrl = ",".join(ctrl)
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='lacpLagPol',
aci_rn='infra/lacplagp-{0}'.format(port_channel),
module_object=port_channel,
target_filter={'name': port_channel},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='lacpLagPol',
class_config=dict(
name=port_channel,
ctrl=ctrl,
descr=description,
minLinks=min_links,
maxLinks=max_links,
mode=mode,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='lacpLagPol')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,253 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_interface_policy_port_security
short_description: Manage port security (l2:PortSecurityPol)
description:
- Manage port security on Cisco ACI fabrics.
version_added: '2.4'
options:
port_security:
description:
- The name of the port security.
type: str
required: yes
aliases: [ name ]
description:
description:
- The description for the contract.
type: str
aliases: [ descr ]
max_end_points:
description:
- Maximum number of end points.
- Accepted values range between C(0) and C(12000).
- The APIC defaults to C(0) when unset during creation.
type: int
port_security_timeout:
version_added: '2.9'
description:
- The delay time in seconds before MAC learning is re-enabled
- Accepted values range between C(60) and C(3600)
- The APIC defaults to C(60) when unset during creation
type: int
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
seealso:
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(l2:PortSecurityPol).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Dag Wieers (@dagwieers)
'''
# FIXME: Add more, better examples
EXAMPLES = r'''
- aci_interface_policy_port_security:
host: '{{ inventory_hostname }}'
username: '{{ username }}'
password: '{{ password }}'
port_security: '{{ port_security }}'
description: '{{ descr }}'
max_end_points: '{{ max_end_points }}'
port_security_timeout: '{{ port_security_timeout }}'
delegate_to: localhost
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
port_security=dict(type='str', aliases=['name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
max_end_points=dict(type='int'),
port_security_timeout=dict(type='int'),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['port_security']],
['state', 'present', ['port_security']],
],
)
port_security = module.params.get('port_security')
description = module.params.get('description')
max_end_points = module.params.get('max_end_points')
port_security_timeout = module.params.get('port_security_timeout')
name_alias = module.params.get('name_alias')
if max_end_points is not None and max_end_points not in range(12001):
module.fail_json(msg='The "max_end_points" must be between 0 and 12000')
if port_security_timeout is not None and port_security_timeout not in range(60, 3601):
module.fail_json(msg='The "port_security_timeout" must be between 60 and 3600')
state = module.params.get('state')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='l2PortSecurityPol',
aci_rn='infra/portsecurityP-{0}'.format(port_security),
module_object=port_security,
target_filter={'name': port_security},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='l2PortSecurityPol',
class_config=dict(
name=port_security,
descr=description,
maximum=max_end_points,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='l2PortSecurityPol')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,253 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Bruno Calogero <brunocalogero@hotmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_interface_selector_to_switch_policy_leaf_profile
short_description: Bind interface selector profiles to switch policy leaf profiles (infra:RsAccPortP)
description:
- Bind interface selector profiles to switch policy leaf profiles on Cisco ACI fabrics.
version_added: '2.5'
options:
leaf_profile:
description:
- Name of the Leaf Profile to which we add a Selector.
type: str
aliases: [ leaf_profile_name ]
interface_selector:
description:
- Name of Interface Profile Selector to be added and associated with the Leaf Profile.
type: str
aliases: [ name, interface_selector_name, interface_profile_name ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
extends_documentation_fragment: aci
notes:
- This module requires an existing leaf profile, the module M(aci_switch_policy_leaf_profile) can be used for this.
seealso:
- module: aci_switch_policy_leaf_profile
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(infra:RsAccPortP).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Bruno Calogero (@brunocalogero)
'''
EXAMPLES = r'''
- name: Associating an interface selector profile to a switch policy leaf profile
aci_interface_selector_to_switch_policy_leaf_profile:
host: apic
username: admin
password: SomeSecretPassword
leaf_profile: sw_name
interface_selector: interface_profile_name
state: present
delegate_to: localhost
- name: Remove an interface selector profile associated with a switch policy leaf profile
aci_interface_selector_to_switch_policy_leaf_profile:
host: apic
username: admin
password: SomeSecretPassword
leaf_profile: sw_name
interface_selector: interface_profile_name
state: absent
delegate_to: localhost
- name: Query an interface selector profile associated with a switch policy leaf profile
aci_interface_selector_to_switch_policy_leaf_profile:
host: apic
username: admin
password: SomeSecretPassword
leaf_profile: sw_name
interface_selector: interface_profile_name
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
leaf_profile=dict(type='str', aliases=['leaf_profile_name']), # Not required for querying all objects
interface_selector=dict(type='str', aliases=['interface_profile_name', 'interface_selector_name', 'name']), # Not required for querying all objects
state=dict(type='str', default='present', choices=['absent', 'present', 'query'])
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['leaf_profile', 'interface_selector']],
['state', 'present', ['leaf_profile', 'interface_selector']]
],
)
leaf_profile = module.params.get('leaf_profile')
# WARNING: interface_selector accepts non existing interface_profile names and they appear on APIC gui with a state of "missing-target"
interface_selector = module.params.get('interface_selector')
state = module.params.get('state')
# Defining the interface profile tDn for clarity
interface_selector_tDn = 'uni/infra/accportprof-{0}'.format(interface_selector)
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='infraNodeP',
aci_rn='infra/nprof-{0}'.format(leaf_profile),
module_object=leaf_profile,
target_filter={'name': leaf_profile},
),
subclass_1=dict(
aci_class='infraRsAccPortP',
aci_rn='rsaccPortP-[{0}]'.format(interface_selector_tDn),
module_object=interface_selector,
target_filter={'name': interface_selector},
)
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='infraRsAccPortP',
class_config=dict(tDn=interface_selector_tDn),
)
aci.get_diff(aci_class='infraRsAccPortP')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,370 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_l3out
short_description: Manage Layer 3 Outside (L3Out) objects (l3ext:Out)
description:
- Manage Layer 3 Outside (L3Out) on Cisco ACI fabrics.
version_added: '2.6'
options:
tenant:
description:
- Name of an existing tenant.
type: str
required: yes
aliases: [ tenant_name ]
l3out:
description:
- Name of L3Out being created.
type: str
required: yes
aliases: [ l3out_name, name ]
vrf:
description:
- Name of the VRF being associated with the L3Out.
type: str
required: yes
aliases: [ vrf_name ]
domain:
description:
- Name of the external L3 domain being associated with the L3Out.
type: str
required: yes
aliases: [ ext_routed_domain_name, routed_domain ]
dscp:
description:
- The target Differentiated Service (DSCP) value.
- The APIC defaults to C(unspecified) when unset during creation.
type: str
choices: [ AF11, AF12, AF13, AF21, AF22, AF23, AF31, AF32, AF33, AF41, AF42, AF43, CS0, CS1, CS2, CS3, CS4, CS5, CS6, CS7, EF, VA, unspecified ]
aliases: [ target ]
route_control:
description:
- Route Control enforcement direction. The only allowed values are export or import,export.
type: list
choices: [ export, import ]
aliases: [ route_control_enforcement ]
l3protocol:
description:
- Routing protocol for the L3Out
type: list
choices: [ bgp, eigrp, ospf, pim, static ]
asn:
description:
- The AS number for the L3Out.
- Only applicable when using 'eigrp' as the l3protocol
type: int
aliases: [ as_number ]
version_added: '2.8'
description:
description:
- Description for the L3Out.
type: str
aliases: [ descr ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
notes:
- The C(tenant) and C(domain) and C(vrf) used must exist before using this module in your playbook.
The M(aci_tenant) and M(aci_domain) and M(aci_vrf) modules can be used for this.
seealso:
- module: aci_tenant
- module: aci_domain
- module: aci_vrf
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(l3ext:Out).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Rostyslav Davydenko (@rost-d)
'''
EXAMPLES = r'''
- name: Add a new L3Out
aci_l3out:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
name: prod_l3out
description: L3Out for Production tenant
domain: l3dom_prod
vrf: prod
l3protocol: ospf
state: present
delegate_to: localhost
- name: Delete L3Out
aci_l3out:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
name: prod_l3out
state: absent
delegate_to: localhost
- name: Query L3Out information
aci_l3out:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
name: prod_l3out
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
l3out=dict(type='str', aliases=['l3out_name', 'name']), # Not required for querying all objects
domain=dict(type='str', aliases=['ext_routed_domain_name', 'routed_domain']),
vrf=dict(type='str', aliases=['vrf_name']),
description=dict(type='str', aliases=['descr']),
route_control=dict(type='list', choices=['export', 'import'], aliases=['route_control_enforcement']),
dscp=dict(type='str',
choices=['AF11', 'AF12', 'AF13', 'AF21', 'AF22', 'AF23', 'AF31', 'AF32', 'AF33', 'AF41', 'AF42',
'AF43', 'CS0', 'CS1', 'CS2', 'CS3', 'CS4', 'CS5', 'CS6', 'CS7', 'EF', 'VA', 'unspecified'],
aliases=['target']),
l3protocol=dict(type='list', choices=['bgp', 'eigrp', 'ospf', 'pim', 'static']),
asn=dict(type='int', aliases=['as_number']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['l3out', 'tenant']],
['state', 'present', ['l3out', 'tenant', 'domain', 'vrf']],
],
)
aci = ACIModule(module)
l3out = module.params.get('l3out')
domain = module.params.get('domain')
dscp = module.params.get('dscp')
description = module.params.get('description')
enforceRtctrl = module.params.get('route_control')
vrf = module.params.get('vrf')
l3protocol = module.params.get('l3protocol')
asn = module.params.get('asn')
state = module.params.get('state')
tenant = module.params.get('tenant')
name_alias = module.params.get('name_alias')
if l3protocol:
if 'eigrp' in l3protocol and asn is None:
module.fail_json(msg="Parameter 'asn' is required when l3protocol is 'eigrp'")
if 'eigrp' not in l3protocol and asn is not None:
module.warn("Parameter 'asn' is only applicable when l3protocol is 'eigrp'. The ASN will be ignored")
enforce_ctrl = ''
if enforceRtctrl is not None:
if len(enforceRtctrl) == 1 and enforceRtctrl[0] == 'import':
aci.fail_json(
"The route_control parameter is invalid: allowed options are export or import,export only")
elif len(enforceRtctrl) == 1 and enforceRtctrl[0] == 'export':
enforce_ctrl = 'export'
else:
enforce_ctrl = 'export,import'
child_classes = ['l3extRsL3DomAtt', 'l3extRsEctx', 'bgpExtP', 'ospfExtP', 'eigrpExtP', 'pimExtP']
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='l3extOut',
aci_rn='out-{0}'.format(l3out),
module_object=l3out,
target_filter={'name': l3out},
),
child_classes=child_classes,
)
aci.get_existing()
child_configs = [
dict(l3extRsL3DomAtt=dict(attributes=dict(
tDn='uni/l3dom-{0}'.format(domain)))),
dict(l3extRsEctx=dict(attributes=dict(tnFvCtxName=vrf))),
]
if l3protocol is not None:
for protocol in l3protocol:
if protocol == 'bgp':
child_configs.append(
dict(bgpExtP=dict(attributes=dict(descr='', nameAlias=''))))
elif protocol == 'eigrp':
child_configs.append(
dict(eigrpExtP=dict(attributes=dict(descr='', nameAlias='', asn=asn))))
elif protocol == 'ospf':
child_configs.append(
dict(ospfExtP=dict(attributes=dict(descr='', nameAlias=''))))
elif protocol == 'pim':
child_configs.append(
dict(pimExtP=dict(attributes=dict(descr='', nameAlias=''))))
if state == 'present':
aci.payload(
aci_class='l3extOut',
class_config=dict(
name=l3out,
descr=description,
dn='uni/tn-{0}/out-{1}'.format(tenant, l3out),
enforceRtctrl=enforce_ctrl,
targetDscp=dscp,
nameAlias=name_alias,
),
child_configs=child_configs,
)
aci.get_diff(aci_class='l3extOut')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,312 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_l3out_extepg
short_description: Manage External Network Instance Profile (ExtEpg) objects (l3extInstP:instP)
description:
- Manage External Network Instance Profile (ExtEpg) objects (l3extInstP:instP)
version_added: '2.9'
options:
tenant:
description:
- Name of an existing tenant.
type: str
required: yes
aliases: [ tenant_name ]
l3out:
description:
- Name of an existing L3Out.
type: str
required: yes
aliases: [ l3out_name ]
extepg:
description:
- Name of ExtEpg being created.
type: str
required: yes
aliases: [ extepg_name, name ]
description:
description:
- Description for the ExtEpg.
type: str
aliases: [ descr ]
preferred_group:
description:
- Whether ot not the EPG is part of the Preferred Group and can communicate without contracts.
- This is very convenient for migration scenarios, or when ACI is used for network automation but not for policy.
- The APIC defaults to C(no) when unset during creation.
type: bool
dscp:
description:
- The target Differentiated Service (DSCP) value.
- The APIC defaults to C(unspecified) when unset during creation.
type: str
choices: [ AF11, AF12, AF13, AF21, AF22, AF23, AF31, AF32, AF33, AF41, AF42, AF43, CS0, CS1, CS2, CS3, CS4, CS5, CS6, CS7, EF, VA, unspecified ]
aliases: [ target ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
notes:
- The C(tenant) and C(domain) and C(vrf) used must exist before using this module in your playbook.
The M(aci_tenant) and M(aci_domain) and M(aci_vrf) modules can be used for this.
seealso:
- module: aci_tenant
- module: aci_domain
- module: aci_vrf
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(l3ext:Out).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Rostyslav Davydenko (@rost-d)
'''
EXAMPLES = r'''
- name: Add a new ExtEpg
aci_l3out_extepg:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
l3out: prod_l3out
name: prod_extepg
description: ExtEpg for Production L3Out
state: present
delegate_to: localhost
- name: Delete ExtEpg
extepg:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
l3out: prod_l3out
name: prod_extepg
state: absent
delegate_to: localhost
- name: Query ExtEpg information
aci_l3out_extepg:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
l3out: prod_l3out
name: prod_extepg
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
l3out=dict(type='str', aliases=['l3out_name']), # Not required for querying all objects
extepg=dict(type='str', aliases=['extepg_name', 'name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
preferred_group=dict(type='bool'),
dscp=dict(type='str',
choices=['AF11', 'AF12', 'AF13', 'AF21', 'AF22', 'AF23', 'AF31', 'AF32', 'AF33', 'AF41', 'AF42',
'AF43', 'CS0', 'CS1', 'CS2', 'CS3', 'CS4', 'CS5', 'CS6', 'CS7', 'EF', 'VA', 'unspecified'],
aliases=['target']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'present', ['extepg', 'l3out', 'tenant']],
['state', 'absent', ['extepg', 'l3out', 'tenant']],
],
)
aci = ACIModule(module)
tenant = module.params.get('tenant')
l3out = module.params.get('l3out')
extepg = module.params.get('extepg')
description = module.params.get('description')
preferred_group = aci.boolean(module.params.get('preferred_group'), 'include', 'exclude')
dscp = module.params.get('dscp')
state = module.params.get('state')
name_alias = module.params.get('name_alias')
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='l3extOut',
aci_rn='out-{0}'.format(l3out),
module_object=l3out,
target_filter={'name': l3out},
),
subclass_2=dict(
aci_class='l3extInstP',
aci_rn='instP-{0}'.format(extepg),
module_object=extepg,
target_filter={'name': extepg},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='l3extInstP',
class_config=dict(
name=extepg,
descr=description,
prefGrMemb=preferred_group,
targetDscp=dscp,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='l3extInstP')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,330 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_l3out_extsubnet
short_description: Manage External Subnet objects (l3extSubnet:extsubnet)
description:
- Manage External Subnet objects (l3extSubnet:extsubnet)
version_added: '2.9'
options:
tenant:
description:
- Name of an existing tenant.
type: str
required: yes
aliases: [ tenant_name ]
l3out:
description:
- Name of an existing L3Out.
type: str
required: yes
aliases: [ l3out_name ]
extepg:
description:
- Name of an existing ExtEpg.
type: str
required: yes
aliases: [ extepg_name ]
network:
description:
- The network address for the Subnet.
type: str
required: yes
aliases: [ address, ip ]
subnet_name:
description:
- Name of External Subnet being created.
type: str
aliases: [ name ]
description:
description:
- Description for the External Subnet.
type: str
aliases: [ descr ]
scope:
description:
- Determines the scope of the Subnet.
- The C(export-rtctrl) option controls which external networks are advertised out of the fabric using route-maps and IP prefix-lists.
- The C(import-security) option classifies for the external EPG.
The rules and contracts defined in this external EPG apply to networks matching this subnet.
- The C(shared-rtctrl) option controls which external prefixes are advertised to other tenants for shared services.
- The C(shared-security) option configures the classifier for the subnets in the VRF where the routes are leaked.
- The APIC defaults to C(import-security) when unset during creation.
type: list
choices: [ export-rtctrl, import-security, shared-rtctrl, shared-security ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
notes:
- The C(tenant) and C(domain) and C(vrf) used must exist before using this module in your playbook.
The M(aci_tenant) and M(aci_domain) and M(aci_vrf) modules can be used for this.
seealso:
- module: aci_tenant
- module: aci_domain
- module: aci_vrf
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(l3ext:Out).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Rostyslav Davydenko (@rost-d)
'''
EXAMPLES = r'''
- name: Add a new External Subnet
aci_l3out_extsubnet:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
l3out: prod_l3out
extepg: prod_extepg
description: External Subnet for Production ExtEpg
network: 192.0.2.0/24
scope: export-rtctrl
state: present
delegate_to: localhost
- name: Delete External Subnet
aci_l3out_extsubnet:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
l3out: prod_l3out
extepg: prod_extepg
network: 192.0.2.0/24
state: absent
delegate_to: localhost
- name: Query ExtEpg information
aci_l3out_extsubnet:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
l3out: prod_l3out
extepg: prod_extepg
network: 192.0.2.0/24
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
l3out=dict(type='str', aliases=['l3out_name']), # Not required for querying all objects
extepg=dict(type='str', aliases=['extepg_name', 'name']), # Not required for querying all objects
network=dict(type='str', aliases=['address', 'ip']),
description=dict(type='str', aliases=['descr']),
subnet_name=dict(type='str', aliases=['name']),
scope=dict(type='list', choices=['export-rtctrl', 'import-security', 'shared-rtctrl', 'shared-security']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'present', ['network']],
['state', 'absent', ['network']],
],
)
aci = ACIModule(module)
tenant = module.params.get('tenant')
l3out = module.params.get('l3out')
extepg = module.params.get('extepg')
network = module.params.get('network')
description = module.params.get('description')
subnet_name = module.params.get('subnet_name')
scope = ','.join(sorted(module.params.get('scope')))
state = module.params.get('state')
name_alias = module.params.get('name_alias')
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='l3extOut',
aci_rn='out-{0}'.format(l3out),
module_object=l3out,
target_filter={'name': l3out},
),
subclass_2=dict(
aci_class='l3extInstP',
aci_rn='instP-{0}'.format(extepg),
module_object=extepg,
target_filter={'name': extepg},
),
subclass_3=dict(
aci_class='l3extSubnet',
aci_rn='extsubnet-[{0}]'.format(network),
module_object=network,
target_filter={'name': network},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='l3extSubnet',
class_config=dict(
ip=network,
descr=description,
name=subnet_name,
scope=scope,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='l3extSubnet')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,257 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_l3out_route_tag_policy
short_description: Manage route tag policies (l3ext:RouteTagPol)
description:
- Manage route tag policies on Cisco ACI fabrics.
version_added: '2.4'
options:
rtp:
description:
- The name of the route tag policy.
type: str
required: yes
aliases: [ name, rtp_name ]
description:
description:
- The description for the route tag policy.
type: str
aliases: [ descr ]
tenant:
description:
- The name of the tenant.
type: str
required: yes
aliases: [ tenant_name ]
tag:
description:
- The value of the route tag.
- Accepted values range between C(0) and C(4294967295).
- The APIC defaults to C(4294967295) when unset during creation.
type: int
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
notes:
- The C(tenant) used must exist before using this module in your playbook.
The M(aci_tenant) module can be used for this.
seealso:
- module: aci_tenant
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(l3ext:RouteTagPol).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Dag Wieers (@dagwieers)
'''
# FIXME: Add more, better examples
EXAMPLES = r'''
- aci_l3out_route_tag_policy:
host: apic
username: admin
password: SomeSecretPassword
rtp: '{{ rtp_name }}'
tenant: production
tag: '{{ tag }}'
description: '{{ description }}'
delegate_to: localhost
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
rtp=dict(type='str', aliases=['name', 'rtp_name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
tag=dict(type='int'),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['rtp', 'tenant']],
['state', 'present', ['rtp', 'tenant']],
],
)
rtp = module.params.get('rtp')
description = module.params.get('description')
tag = module.params.get('tag')
state = module.params.get('state')
tenant = module.params.get('tenant')
name_alias = module.params.get('name_alias')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='l3extRouteTagPol',
aci_rn='rttag-{0}'.format(rtp),
module_object=rtp,
target_filter={'name': rtp},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='l3extRouteTagPol',
class_config=dict(
name=rtp,
descr=description, tag=tag,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='l3extRouteTagPol')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,238 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = '''
module: aci_maintenance_group
short_description: This creates an ACI maintenance group
version_added: "2.8"
notes:
- a maintenance policy (aci_maintenance_policy must be created prior to creating an aci maintenance group
description:
- This modules creates an ACI maintenance group
options:
group:
description:
- This is the name of the group
type: str
required: true
policy:
description:
- This is the name of the policy that was created using aci_maintenance_policy
type: str
required: true
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [absent, present, query]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment:
- aci
author:
- Steven Gerhart (@sgerhart)
'''
EXAMPLES = '''
- name: maintenance group
aci_maintenance_group:
host: "{{ inventory_hostname }}"
username: "{{ user }}"
password: "{{ pass }}"
validate_certs: no
group: maintenancegrp1
policy: maintenancePol1
state: present
'''
RETURN = '''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
from ansible.module_utils.basic import AnsibleModule
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
group=dict(type='str'), # Not required for querying all objects
policy=dict(type='str'), # Not required for querying all objects
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['group']],
['state', 'present', ['group']],
],
)
state = module.params.get('state')
group = module.params.get('group')
policy = module.params.get('policy')
name_alias = module.params.get('name_alias')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='maintMaintGrp',
aci_rn='fabric/maintgrp-{0}'.format(group),
target_filter={'name': group},
module_object=group,
),
child_classes=['maintRsMgrpp'],
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='maintMaintGrp',
class_config=dict(
name=group,
nameAlias=name_alias,
),
child_configs=[
dict(
maintRsMgrpp=dict(
attributes=dict(
tnMaintMaintPName=policy,
),
),
),
],
)
aci.get_diff(aci_class='maintMaintGrp')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,245 +0,0 @@
#!/usr/bin/python
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = r'''
---
module: aci_maintenance_group_node
short_description: Manage maintenance group nodes
version_added: '2.8'
description:
- Manage maintenance group nodes
options:
group:
description:
- The maintenance group name that you want to add the node to.
type: str
required: true
node:
description:
- The node to be added to the maintenance group.
- The value equals the nodeid.
type: str
required: true
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment:
- aci
author:
- Steven Gerhart (@sgerhart)
'''
EXAMPLES = r'''
- name: maintenance group
aci_maintenance_group_node:
host: "{{ inventory_hostname }}"
username: "{{ user }}"
password: "{{ pass }}"
validate_certs: no
group: maintenancegrp1
node: 1001
state: present
- name: maintenance group
aci_maintenance_group_node:
host: "{{ inventory_hostname }}"
username: "{{ user }}"
password: "{{ pass }}"
validate_certs: no
group: maintenancegrp1
node: 1002
state: absent
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
group=dict(type='str'), # Not required for querying all objects
node=dict(type='str'),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['node', 'group']],
['state', 'present', ['node', 'group']],
],
)
state = module.params.get('state')
group = module.params.get('group')
node = module.params.get('node')
name_alias = module.params.get('name_alias')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='maintMaintGrp',
aci_rn='fabric/maintgrp-{0}'.format(group),
target_filter={'name': group},
module_object=group,
),
subclass_1=dict(
aci_class='fabricNodeBlk',
aci_rn='nodeblk-blk{0}-{0}'.format(node),
target_filter={'name': 'blk{0}-{0}'.format(node)},
module_object=node,
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='fabricNodeBlk',
class_config=dict(
from_=node,
to_=node,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='fabricNodeBlk')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,279 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = r'''
---
module: aci_maintenance_policy
short_description: Manage firmware maintenance policies
version_added: '2.8'
description:
- Manage maintenance policies that defines behavior during an ACI upgrade.
options:
name:
description:
- The name for the maintenance policy.
type: str
required: true
aliases: [ maintenance_policy ]
runmode:
description:
- Whether the system pauses on error or just continues through it.
type: str
choices: [ pauseOnlyOnFailures, pauseNever ]
default: pauseOnlyOnFailures
graceful:
description:
- Whether the system will bring down the nodes gracefully during an upgrade, which reduces traffic lost.
- The APIC defaults to C(no) when unset during creation.
type: bool
scheduler:
description:
- The name of scheduler that is applied to the policy.
type: str
required: true
adminst:
description:
- Will trigger an immediate upgrade for nodes if adminst is set to triggered.
type: str
choices: [ triggered, untriggered ]
default: untriggered
ignoreCompat:
description:
- To check whether compatibility checks should be ignored
- The APIC defaults to C(no) when unset during creation.
type: bool
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment:
- aci
notes:
- A scheduler is required for this module, which could have been created using the M(aci_fabric_scheduler) module or via the UI.
author:
- Steven Gerhart (@sgerhart)
'''
EXAMPLES = r'''
- name: Ensure maintenance policy is present
aci_maintenance_policy:
host: '{{ inventory_hostname }}'
username: '{{ user }}'
password: '{{ pass }}'
validate_certs: no
name: maintenancePol1
scheduler: simpleScheduler
runmode: False
state: present
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
from ansible.module_utils.basic import AnsibleModule
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
name=dict(type='str', aliases=['maintenance_policy']), # Not required for querying all objects
runmode=dict(type='str', default='pauseOnlyOnFailures', choices=['pauseOnlyOnFailures', 'pauseNever']),
graceful=dict(type='bool'),
scheduler=dict(type='str'),
ignoreCompat=dict(type='bool'),
adminst=dict(type='str', default='untriggered', choices=['triggered', 'untriggered']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['name']],
['state', 'present', ['name', 'scheduler']],
],
)
aci = ACIModule(module)
state = module.params.get('state')
name = module.params.get('name')
runmode = module.params.get('runmode')
scheduler = module.params.get('scheduler')
adminst = module.params.get('adminst')
graceful = aci.boolean(module.params.get('graceful'))
ignoreCompat = aci.boolean(module.params.get('ignoreCompat'))
name_alias = module.params.get('name_alias')
aci.construct_url(
root_class=dict(
aci_class='maintMaintP',
aci_rn='fabric/maintpol-{0}'.format(name),
target_filter={'name': name},
module_object=name,
),
child_classes=['maintRsPolScheduler']
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='maintMaintP',
class_config=dict(
name=name,
runMode=runmode,
graceful=graceful,
adminSt=adminst,
ignoreCompat=ignoreCompat,
nameAlias=name_alias,
),
child_configs=[
dict(
maintRsPolScheduler=dict(
attributes=dict(
tnTrigSchedPName=scheduler,
),
),
),
],
)
aci.get_diff(aci_class='maintMaintP')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,442 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# 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)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_rest
short_description: Direct access to the Cisco APIC REST API
description:
- Enables the management of the Cisco ACI fabric through direct access to the Cisco APIC REST API.
- Thanks to the idempotent nature of the APIC, this module is idempotent and reports changes.
version_added: '2.4'
requirements:
- lxml (when using XML payload)
- xmljson >= 0.1.8 (when using XML payload)
- python 2.7+ (when using xmljson)
options:
method:
description:
- The HTTP method of the request.
- Using C(delete) is typically used for deleting objects.
- Using C(get) is typically used for querying objects.
- Using C(post) is typically used for modifying objects.
type: str
choices: [ delete, get, post ]
default: get
aliases: [ action ]
path:
description:
- URI being used to execute API calls.
- Must end in C(.xml) or C(.json).
type: str
required: yes
aliases: [ uri ]
content:
description:
- When used instead of C(src), sets the payload of the API request directly.
- This may be convenient to template simple requests.
- For anything complex use the C(template) lookup plugin (see examples)
or the M(template) module with parameter C(src).
type: raw
src:
description:
- Name of the absolute path of the filename that includes the body
of the HTTP request being sent to the ACI fabric.
- If you require a templated payload, use the C(content) parameter
together with the C(template) lookup plugin, or use M(template).
type: path
aliases: [ config_file ]
extends_documentation_fragment: aci
notes:
- Certain payloads are known not to be idempotent, so be careful when constructing payloads,
e.g. using C(status="created") will cause idempotency issues, use C(status="modified") instead.
More information in :ref:`the ACI documentation <aci_guide_known_issues>`.
- Certain payloads (and used paths) are known to report no changes happened when changes did happen.
This is a known APIC problem and has been reported to the vendor. A workaround for this issue exists.
More information in :ref:`the ACI documentation <aci_guide_known_issues>`.
- XML payloads require the C(lxml) and C(xmljson) python libraries. For JSON payloads nothing special is needed.
seealso:
- module: aci_tenant
- name: Cisco APIC REST API Configuration Guide
description: More information about the APIC REST API.
link: http://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
author:
- Dag Wieers (@dagwieers)
'''
EXAMPLES = r'''
- name: Add a tenant using certificate authentication
aci_rest:
host: apic
username: admin
private_key: pki/admin.key
method: post
path: /api/mo/uni.xml
src: /home/cisco/ansible/aci/configs/aci_config.xml
delegate_to: localhost
- name: Add a tenant from a templated payload file from templates/
aci_rest:
host: apic
username: admin
private_key: pki/admin.key
method: post
path: /api/mo/uni.xml
content: "{{ lookup('template', 'aci/tenant.xml.j2') }}"
delegate_to: localhost
- name: Add a tenant using inline YAML
aci_rest:
host: apic
username: admin
private_key: pki/admin.key
validate_certs: no
path: /api/mo/uni.json
method: post
content:
fvTenant:
attributes:
name: Sales
descr: Sales department
delegate_to: localhost
- name: Add a tenant using a JSON string
aci_rest:
host: apic
username: admin
private_key: pki/admin.key
validate_certs: no
path: /api/mo/uni.json
method: post
content:
{
"fvTenant": {
"attributes": {
"name": "Sales",
"descr": "Sales department"
}
}
}
delegate_to: localhost
- name: Add a tenant using an XML string
aci_rest:
host: apic
username: admin
private_key: pki/{{ aci_username }}.key
validate_certs: no
path: /api/mo/uni.xml
method: post
content: '<fvTenant name="Sales" descr="Sales departement"/>'
delegate_to: localhost
- name: Get tenants using password authentication
aci_rest:
host: apic
username: admin
password: SomeSecretPassword
method: get
path: /api/node/class/fvTenant.json
delegate_to: localhost
register: query_result
- name: Configure contracts
aci_rest:
host: apic
username: admin
private_key: pki/admin.key
method: post
path: /api/mo/uni.xml
src: /home/cisco/ansible/aci/configs/contract_config.xml
delegate_to: localhost
- name: Register leaves and spines
aci_rest:
host: apic
username: admin
private_key: pki/admin.key
validate_certs: no
method: post
path: /api/mo/uni/controller/nodeidentpol.xml
content: |
<fabricNodeIdentPol>
<fabricNodeIdentP name="{{ item.name }}" nodeId="{{ item.nodeid }}" status="{{ item.status }}" serial="{{ item.serial }}"/>
</fabricNodeIdentPol>
with_items:
- '{{ apic_leavesspines }}'
delegate_to: localhost
- name: Wait for all controllers to become ready
aci_rest:
host: apic
username: admin
private_key: pki/admin.key
validate_certs: no
path: /api/node/class/topSystem.json?query-target-filter=eq(topSystem.role,"controller")
register: apics
until: "'totalCount' in apics and apics.totalCount|int >= groups['apic']|count"
retries: 120
delay: 30
delegate_to: localhost
run_once: yes
'''
RETURN = r'''
error_code:
description: The REST ACI return code, useful for troubleshooting on failure
returned: always
type: int
sample: 122
error_text:
description: The REST ACI descriptive text, useful for troubleshooting on failure
returned: always
type: str
sample: unknown managed object class foo
imdata:
description: Converted output returned by the APIC REST (register this for post-processing)
returned: always
type: str
sample: [{"error": {"attributes": {"code": "122", "text": "unknown managed object class foo"}}}]
payload:
description: The (templated) payload send to the APIC REST API (xml or json)
returned: always
type: str
sample: '<foo bar="boo"/>'
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
response:
description: HTTP response string
returned: always
type: str
sample: 'HTTP Error 400: Bad Request'
status:
description: HTTP status code
returned: always
type: int
sample: 400
totalCount:
description: Number of items in the imdata array
returned: always
type: str
sample: '0'
url:
description: URL used for APIC REST call
returned: success
type: str
sample: https://1.2.3.4/api/mo/uni/tn-[Dag].json?rsp-subtree=modified
'''
import json
import os
try:
from ansible.module_utils.six.moves.urllib.parse import parse_qsl, urlencode, urlparse, urlunparse
HAS_URLPARSE = True
except Exception:
HAS_URLPARSE = False
# Optional, only used for XML payload
try:
import lxml.etree # noqa
HAS_LXML_ETREE = True
except ImportError:
HAS_LXML_ETREE = False
# Optional, only used for XML payload
try:
from xmljson import cobra # noqa
HAS_XMLJSON_COBRA = True
except ImportError:
HAS_XMLJSON_COBRA = False
# Optional, only used for YAML validation
try:
import yaml
HAS_YAML = True
except Exception:
HAS_YAML = False
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
from ansible.module_utils.urls import fetch_url
from ansible.module_utils._text import to_text
def update_qsl(url, params):
''' Add or update a URL query string '''
if HAS_URLPARSE:
url_parts = list(urlparse(url))
query = dict(parse_qsl(url_parts[4]))
query.update(params)
url_parts[4] = urlencode(query)
return urlunparse(url_parts)
elif '?' in url:
return url + '&' + '&'.join(['%s=%s' % (k, v) for k, v in params.items()])
else:
return url + '?' + '&'.join(['%s=%s' % (k, v) for k, v in params.items()])
class ACIRESTModule(ACIModule):
def changed(self, d):
''' Check ACI response for changes '''
if isinstance(d, dict):
for k, v in d.items():
if k == 'status' and v in ('created', 'modified', 'deleted'):
return True
elif self.changed(v) is True:
return True
elif isinstance(d, list):
for i in d:
if self.changed(i) is True:
return True
return False
def response_type(self, rawoutput, rest_type='xml'):
''' Handle APIC response output '''
if rest_type == 'json':
self.response_json(rawoutput)
else:
self.response_xml(rawoutput)
# Use APICs built-in idempotency
if HAS_URLPARSE:
self.result['changed'] = self.changed(self.imdata)
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
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='raw'),
)
module = AnsibleModule(
argument_spec=argument_spec,
mutually_exclusive=[['content', 'src']],
)
content = module.params.get('content')
path = module.params.get('path')
src = module.params.get('src')
# Report missing file
file_exists = False
if src:
if os.path.isfile(src):
file_exists = True
else:
module.fail_json(msg="Cannot find/access src '%s'" % src)
# Find request type
if path.find('.xml') != -1:
rest_type = 'xml'
if not HAS_LXML_ETREE:
module.fail_json(msg='The lxml python library is missing, or lacks etree support.')
if not HAS_XMLJSON_COBRA:
module.fail_json(msg='The xmljson python library is missing, or lacks cobra support.')
elif path.find('.json') != -1:
rest_type = 'json'
else:
module.fail_json(msg='Failed to find REST API payload type (neither .xml nor .json).')
aci = ACIRESTModule(module)
aci.result['status'] = -1 # Ensure we always return a status
# We include the payload as it may be templated
payload = content
if file_exists:
with open(src, 'r') as config_object:
# TODO: Would be nice to template this, requires action-plugin
payload = config_object.read()
# Validate payload
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.safe_load(payload))
except Exception as e:
module.fail_json(msg='Failed to parse provided JSON/YAML payload: %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 payload: %s' % to_text(e), payload=payload)
# Perform actual request using auth cookie (Same as aci.request(), but also supports XML)
if 'port' in aci.params and aci.params.get('port') is not None:
aci.url = '%(protocol)s://%(host)s:%(port)s/' % aci.params + path.lstrip('/')
else:
aci.url = '%(protocol)s://%(host)s/' % aci.params + path.lstrip('/')
if aci.params.get('method') != 'get':
path += '?rsp-subtree=modified'
aci.url = update_qsl(aci.url, {'rsp-subtree': 'modified'})
# Sign and encode request as to APIC's wishes
if aci.params.get('private_key') is not None:
aci.cert_auth(path=path, payload=payload)
aci.method = aci.params.get('method').upper()
# Perform request
resp, info = fetch_url(module, aci.url,
data=payload,
headers=aci.headers,
method=aci.method,
timeout=aci.params.get('timeout'),
use_proxy=aci.params.get('use_proxy'))
aci.response = info.get('msg')
aci.status = info.get('status')
# Report failure
if info.get('status') != 200:
try:
# APIC error
aci.response_type(info.get('body'), rest_type)
aci.fail_json(msg='APIC Error %(code)s: %(text)s' % aci.error)
except KeyError:
# Connection error
aci.fail_json(msg='Connection failed for %(url)s. %(msg)s' % info)
aci.response_type(resp.read(), rest_type)
aci.result['imdata'] = aci.imdata
aci.result['totalCount'] = aci.totalCount
# Report success
aci.exit_json(**aci.result)
if __name__ == '__main__':
main()

@ -1,440 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Bruno Calogero <brunocalogero@hotmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_static_binding_to_epg
short_description: Bind static paths to EPGs (fv:RsPathAtt)
description:
- Bind static paths to EPGs on Cisco ACI fabrics.
version_added: '2.5'
options:
tenant:
description:
- Name of an existing tenant.
type: str
aliases: [ tenant_name ]
ap:
description:
- Name of an existing application network profile, that will contain the EPGs.
type: str
aliases: [ app_profile, app_profile_name ]
epg:
description:
- The name of the end point group.
type: str
aliases: [ epg_name ]
description:
description:
- Description for the static path to EPG binding.
type: str
aliases: [ descr ]
version_added: '2.7'
encap_id:
description:
- The encapsulation ID associating the C(epg) with the interface path.
- This acts as the secondary C(encap_id) when using micro-segmentation.
- Accepted values are any valid encap ID for specified encap, currently ranges between C(1) and C(4096).
type: int
aliases: [ vlan, vlan_id ]
primary_encap_id:
description:
- Determines the primary encapsulation ID associating the C(epg)
with the interface path when using micro-segmentation.
- Accepted values are any valid encap ID for specified encap, currently ranges between C(1) and C(4096).
type: int
aliases: [ primary_vlan, primary_vlan_id ]
deploy_immediacy:
description:
- The Deployment Immediacy of Static EPG on PC, VPC or Interface.
- The APIC defaults to C(lazy) when unset during creation.
type: str
choices: [ immediate, lazy ]
interface_mode:
description:
- Determines how layer 2 tags will be read from and added to frames.
- Values C(802.1p) and C(native) are identical.
- Values C(access) and C(untagged) are identical.
- Values C(regular), C(tagged) and C(trunk) are identical.
- The APIC defaults to C(trunk) when unset during creation.
type: str
choices: [ 802.1p, access, native, regular, tagged, trunk, untagged ]
aliases: [ interface_mode_name, mode ]
interface_type:
description:
- The type of interface for the static EPG deployment.
type: str
choices: [ fex, port_channel, switch_port, vpc ]
default: switch_port
pod_id:
description:
- The pod number part of the tDn.
- C(pod_id) is usually an integer below C(10).
type: int
aliases: [ pod, pod_number ]
leafs:
description:
- The switch ID(s) that the C(interface) belongs to.
- When C(interface_type) is C(switch_port), C(port_channel), or C(fex), then C(leafs) is a string of the leaf ID.
- When C(interface_type) is C(vpc), then C(leafs) is a list with both leaf IDs.
- The C(leafs) value is usually something like '101' or '101-102' depending on C(connection_type).
type: list
aliases: [ leaves, nodes, paths, switches ]
interface:
description:
- The C(interface) string value part of the tDn.
- Usually a policy group like C(test-IntPolGrp) or an interface of the following format C(1/7) depending on C(interface_type).
type: str
extpaths:
description:
- The C(extpaths) integer value part of the tDn.
- C(extpaths) is only used if C(interface_type) is C(fex).
- Usually something like C(1011).
type: int
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
extends_documentation_fragment: aci
notes:
- The C(tenant), C(ap), C(epg) used must exist before using this module in your playbook.
The M(aci_tenant), M(aci_ap), M(aci_epg) modules can be used for this.
seealso:
- module: aci_tenant
- module: aci_ap
- module: aci_epg
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(fv:RsPathAtt).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Bruno Calogero (@brunocalogero)
'''
EXAMPLES = r'''
- name: Deploy Static Path binding for given EPG
aci_static_binding_to_epg:
host: apic
username: admin
password: SomeSecretPassword
tenant: accessport-code-cert
ap: accessport_code_app
epg: accessport_epg1
encap_id: 222
deploy_immediacy: lazy
interface_mode: untagged
interface_type: switch_port
pod_id: 1
leafs: 101
interface: '1/7'
state: present
delegate_to: localhost
- name: Remove Static Path binding for given EPG
aci_static_binding_to_epg:
host: apic
username: admin
password: SomeSecretPassword
tenant: accessport-code-cert
ap: accessport_code_app
epg: accessport_epg1
interface_type: switch_port
pod: 1
leafs: 101
interface: '1/7'
state: absent
delegate_to: localhost
- name: Get specific Static Path binding for given EPG
aci_static_binding_to_epg:
host: apic
username: admin
password: SomeSecretPassword
tenant: accessport-code-cert
ap: accessport_code_app
epg: accessport_epg1
interface_type: switch_port
pod: 1
leafs: 101
interface: '1/7'
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
INTERFACE_MODE_MAPPING = {
'802.1p': 'native',
'access': 'untagged',
'native': 'native',
'regular': 'regular',
'tagged': 'regular',
'trunk': 'regular',
'untagged': 'untagged',
}
INTERFACE_TYPE_MAPPING = dict(
fex='topology/pod-{pod_id}/paths-{leafs}/extpaths-{extpaths}/pathep-[eth{interface}]',
port_channel='topology/pod-{pod_id}/paths-{leafs}/pathep-[{interface}]',
switch_port='topology/pod-{pod_id}/paths-{leafs}/pathep-[eth{interface}]',
vpc='topology/pod-{pod_id}/protpaths-{leafs}/pathep-[{interface}]',
)
# TODO: change 'deploy_immediacy' to 'resolution_immediacy' (as seen in aci_epg_to_domain)?
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
ap=dict(type='str', aliases=['app_profile', 'app_profile_name']), # Not required for querying all objects
epg=dict(type='str', aliases=['epg_name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
encap_id=dict(type='int', aliases=['vlan', 'vlan_id']),
primary_encap_id=dict(type='int', aliases=['primary_vlan', 'primary_vlan_id']),
deploy_immediacy=dict(type='str', choices=['immediate', 'lazy']),
interface_mode=dict(type='str', choices=['802.1p', 'access', 'native', 'regular', 'tagged', 'trunk', 'untagged'],
aliases=['interface_mode_name', 'mode']),
interface_type=dict(type='str', default='switch_port', choices=['fex', 'port_channel', 'switch_port', 'vpc']),
pod_id=dict(type='int', aliases=['pod', 'pod_number']), # Not required for querying all objects
leafs=dict(type='list', aliases=['leaves', 'nodes', 'paths', 'switches']), # Not required for querying all objects
interface=dict(type='str'), # Not required for querying all objects
extpaths=dict(type='int'),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['interface_type', 'fex', ['extpaths']],
['state', 'absent', ['ap', 'epg', 'interface', 'leafs', 'pod_id', 'tenant']],
['state', 'present', ['ap', 'encap_id', 'epg', 'interface', 'leafs', 'pod_id', 'tenant']],
],
)
tenant = module.params.get('tenant')
ap = module.params.get('ap')
epg = module.params.get('epg')
description = module.params.get('description')
encap_id = module.params.get('encap_id')
primary_encap_id = module.params.get('primary_encap_id')
deploy_immediacy = module.params.get('deploy_immediacy')
interface_mode = module.params.get('interface_mode')
interface_type = module.params.get('interface_type')
pod_id = module.params.get('pod_id')
leafs = module.params.get('leafs')
if leafs is not None:
# Process leafs, and support dash-delimited leafs
leafs = []
for leaf in module.params.get('leafs'):
# Users are likely to use integers for leaf IDs, which would raise an exception when using the join method
leafs.extend(str(leaf).split('-'))
if len(leafs) == 1:
if interface_type == 'vpc':
module.fail_json(msg='A interface_type of "vpc" requires 2 leafs')
leafs = leafs[0]
elif len(leafs) == 2:
if interface_type != 'vpc':
module.fail_json(msg='The interface_types "switch_port", "port_channel", and "fex" \
do not support using multiple leafs for a single binding')
leafs = "-".join(leafs)
else:
module.fail_json(msg='The "leafs" parameter must not have more than 2 entries')
interface = module.params.get('interface')
extpaths = module.params.get('extpaths')
state = module.params.get('state')
if encap_id is not None:
if encap_id not in range(1, 4097):
module.fail_json(msg='Valid VLAN assigments are from 1 to 4096')
encap_id = 'vlan-{0}'.format(encap_id)
if primary_encap_id is not None:
if primary_encap_id not in range(1, 4097):
module.fail_json(msg='Valid VLAN assigments are from 1 to 4096')
primary_encap_id = 'vlan-{0}'.format(primary_encap_id)
static_path = INTERFACE_TYPE_MAPPING[interface_type].format(pod_id=pod_id, leafs=leafs, extpaths=extpaths, interface=interface)
path_target_filter = {}
if pod_id is not None and leafs is not None and interface is not None and (interface_type != 'fex' or extpaths is not None):
path_target_filter = {'tDn': static_path}
if interface_mode is not None:
interface_mode = INTERFACE_MODE_MAPPING[interface_mode]
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='fvAp',
aci_rn='ap-{0}'.format(ap),
module_object=ap,
target_filter={'name': ap},
),
subclass_2=dict(
aci_class='fvAEPg',
aci_rn='epg-{0}'.format(epg),
module_object=epg,
target_filter={'name': epg},
),
subclass_3=dict(
aci_class='fvRsPathAtt',
aci_rn='rspathAtt-[{0}]'.format(static_path),
module_object=static_path,
target_filter=path_target_filter,
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='fvRsPathAtt',
class_config=dict(
descr=description,
encap=encap_id,
primaryEncap=primary_encap_id,
instrImedcy=deploy_immediacy,
mode=interface_mode,
tDn=static_path,
),
)
aci.get_diff(aci_class='fvRsPathAtt')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,349 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Bruno Calogero <brunocalogero@hotmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_switch_leaf_selector
short_description: Bind leaf selectors to switch policy leaf profiles (infra:LeafS, infra:NodeBlk, infra:RsAccNodePGrep)
description:
- Bind leaf selectors (with node block range and policy group) to switch policy leaf profiles on Cisco ACI fabrics.
version_added: '2.5'
options:
description:
description:
- The description to assign to the C(leaf).
type: str
leaf_profile:
description:
- Name of the Leaf Profile to which we add a Selector.
type: str
aliases: [ leaf_profile_name ]
leaf:
description:
- Name of Leaf Selector.
type: str
aliases: [ name, leaf_name, leaf_profile_leaf_name, leaf_selector_name ]
leaf_node_blk:
description:
- Name of Node Block range to be added to Leaf Selector of given Leaf Profile.
type: str
aliases: [ leaf_node_blk_name, node_blk_name ]
leaf_node_blk_description:
description:
- The description to assign to the C(leaf_node_blk)
type: str
from:
description:
- Start of Node Block range.
type: int
aliases: [ node_blk_range_from, from_range, range_from ]
to:
description:
- Start of Node Block range.
type: int
aliases: [ node_blk_range_to, to_range, range_to ]
policy_group:
description:
- Name of the Policy Group to be added to Leaf Selector of given Leaf Profile.
type: str
aliases: [ name, policy_group_name ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
notes:
- This module is to be used with M(aci_switch_policy_leaf_profile).
One first creates a leaf profile (infra:NodeP) and then creates an associated selector (infra:LeafS),
seealso:
- module: aci_switch_policy_leaf_profile
- name: APIC Management Information Model reference
description: More information about the internal APIC classes B(infra:LeafS),
B(infra:NodeBlk) and B(infra:RsAccNodePGrp).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Bruno Calogero (@brunocalogero)
'''
EXAMPLES = r'''
- name: adding a switch policy leaf profile selector associated Node Block range (w/ policy group)
aci_switch_leaf_selector:
host: apic
username: admin
password: SomeSecretPassword
leaf_profile: sw_name
leaf: leaf_selector_name
leaf_node_blk: node_blk_name
from: 1011
to: 1011
policy_group: somepolicygroupname
state: present
delegate_to: localhost
- name: adding a switch policy leaf profile selector associated Node Block range (w/o policy group)
aci_switch_leaf_selector:
host: apic
username: admin
password: SomeSecretPassword
leaf_profile: sw_name
leaf: leaf_selector_name
leaf_node_blk: node_blk_name
from: 1011
to: 1011
state: present
delegate_to: localhost
- name: Removing a switch policy leaf profile selector
aci_switch_leaf_selector:
host: apic
username: admin
password: SomeSecretPassword
leaf_profile: sw_name
leaf: leaf_selector_name
state: absent
delegate_to: localhost
- name: Querying a switch policy leaf profile selector
aci_switch_leaf_selector:
host: apic
username: admin
password: SomeSecretPassword
leaf_profile: sw_name
leaf: leaf_selector_name
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update({
'description': dict(type='str'),
'leaf_profile': dict(type='str', aliases=['leaf_profile_name']), # Not required for querying all objects
'leaf': dict(type='str', aliases=['name', 'leaf_name', 'leaf_profile_leaf_name', 'leaf_selector_name']), # Not required for querying all objects
'leaf_node_blk': dict(type='str', aliases=['leaf_node_blk_name', 'node_blk_name']),
'leaf_node_blk_description': dict(type='str'),
# NOTE: Keyword 'from' is a reserved word in python, so we need it as a string
'from': dict(type='int', aliases=['node_blk_range_from', 'from_range', 'range_from']),
'to': dict(type='int', aliases=['node_blk_range_to', 'to_range', 'range_to']),
'policy_group': dict(type='str', aliases=['policy_group_name']),
'state': dict(type='str', default='present', choices=['absent', 'present', 'query']),
'name_alias': dict(type='str'),
})
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['leaf_profile', 'leaf']],
['state', 'present', ['leaf_profile', 'leaf', 'leaf_node_blk', 'from', 'to']]
]
)
description = module.params.get('description')
leaf_profile = module.params.get('leaf_profile')
leaf = module.params.get('leaf')
leaf_node_blk = module.params.get('leaf_node_blk')
leaf_node_blk_description = module.params.get('leaf_node_blk_description')
from_ = module.params.get('from')
to_ = module.params.get('to')
policy_group = module.params.get('policy_group')
state = module.params.get('state')
name_alias = module.params.get('name_alias')
# Build child_configs dynamically
child_configs = [
dict(
infraNodeBlk=dict(
attributes=dict(
descr=leaf_node_blk_description,
name=leaf_node_blk,
from_=from_,
to_=to_,
),
),
),
]
# Add infraRsAccNodePGrp only when policy_group was defined
if policy_group is not None:
child_configs.append(dict(
infraRsAccNodePGrp=dict(
attributes=dict(
tDn='uni/infra/funcprof/accnodepgrp-{0}'.format(policy_group),
),
),
))
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='infraNodeP',
aci_rn='infra/nprof-{0}'.format(leaf_profile),
module_object=leaf_profile,
target_filter={'name': leaf_profile},
),
subclass_1=dict(
aci_class='infraLeafS',
# NOTE: normal rn: leaves-{name}-typ-{type}, hence here hardcoded to range for purposes of module
aci_rn='leaves-{0}-typ-range'.format(leaf),
module_object=leaf,
target_filter={'name': leaf},
),
# NOTE: infraNodeBlk is not made into a subclass because there is a 1-1 mapping between node block and leaf selector name
child_classes=['infraNodeBlk', 'infraRsAccNodePGrp'],
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='infraLeafS',
class_config=dict(
descr=description,
name=leaf,
nameAlias=name_alias,
),
child_configs=child_configs,
)
aci.get_diff(aci_class='infraLeafS')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,250 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Bruno Calogero <brunocalogero@hotmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_switch_policy_leaf_profile
short_description: Manage switch policy leaf profiles (infra:NodeP)
description:
- Manage switch policy leaf profiles on Cisco ACI fabrics.
version_added: '2.5'
options:
leaf_profile:
description:
- The name of the Leaf Profile.
type: str
aliases: [ leaf_profile_name, name ]
description:
description:
- Description for the Leaf Profile.
type: str
aliases: [ descr ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
seealso:
- module: aci_switch_policy_leaf_profile
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(infra:NodeP).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Bruno Calogero (@brunocalogero)
'''
EXAMPLES = r'''
- name: creating a Leaf Profile with description
aci_switch_policy_leaf_profile:
host: apic
username: admin
password: SomeSecretPassword
leaf_profile: sw_name
description: sw_description
state: present
delegate_to: localhost
- name: Deleting a Leaf Profile
aci_switch_policy_leaf_profile:
host: apic
username: admin
password: SomeSecretPassword
leaf_profile: sw_name
state: absent
delegate_to: localhost
- name: Query a Leaf Profile
aci_switch_policy_leaf_profile:
host: apic
username: admin
password: SomeSecretPassword
leaf_profile: sw_name
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
leaf_profile=dict(type='str', aliases=['name', 'leaf_profile_name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['leaf_profile']],
['state', 'present', ['leaf_profile']],
],
)
leaf_profile = module.params.get('leaf_profile')
description = module.params.get('description')
state = module.params.get('state')
name_alias = module.params.get('name_alias')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='infraNodeP',
aci_rn='infra/nprof-{0}'.format(leaf_profile),
module_object=leaf_profile,
target_filter={'name': leaf_profile},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='infraNodeP',
class_config=dict(
name=leaf_profile,
descr=description,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='infraNodeP')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,308 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Bruno Calogero <brunocalogero@hotmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_switch_policy_vpc_protection_group
short_description: Manage switch policy explicit vPC protection groups (fabric:ExplicitGEp, fabric:NodePEp).
description:
- Manage switch policy explicit vPC protection groups on Cisco ACI fabrics.
version_added: '2.5'
options:
protection_group:
description:
- The name of the Explicit vPC Protection Group.
type: str
required: yes
aliases: [ name, protection_group_name ]
protection_group_id:
description:
- The Explicit vPC Protection Group ID.
type: int
required: yes
aliases: [ id ]
vpc_domain_policy:
description:
- The vPC domain policy to be associated with the Explicit vPC Protection Group.
type: str
aliases: [ vpc_domain_policy_name ]
switch_1_id:
description:
- The ID of the first Leaf Switch for the Explicit vPC Protection Group.
type: int
required: yes
switch_2_id:
description:
- The ID of the Second Leaf Switch for the Explicit vPC Protection Group.
type: int
required: yes
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
seealso:
- module: aci_switch_policy_leaf_profile
- name: APIC Management Information Model reference
description: More information about the internal APIC classes B(fabric:ExplicitGEp) and B(fabric:NodePEp).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Bruno Calogero (@brunocalogero)
'''
EXAMPLES = r'''
- name: Add vPC Protection Group
aci_switch_policy_vpc_protection_group:
host: apic
username: admin
password: SomeSecretPassword
protection_group: leafPair101-vpcGrp
protection_group_id: 6
switch_1_id: 1011
switch_2_id: 1012
state: present
delegate_to: localhost
- name: Remove Explicit vPC Protection Group
aci_switch_policy_vpc_protection_group:
host: apic
username: admin
password: SomeSecretPassword
protection_group: leafPair101-vpcGrp
state: absent
delegate_to: localhost
- name: Query vPC Protection Groups
aci_switch_policy_vpc_protection_group:
host: apic
username: admin
password: SomeSecretPassword
state: query
delegate_to: localhost
register: query_result
- name: Query our vPC Protection Group
aci_switch_policy_vpc_protection_group:
host: apic
username: admin
password: SomeSecretPassword
protection_group: leafPair101-vpcGrp
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
protection_group=dict(type='str', aliases=['name', 'protection_group_name']), # Not required for querying all objects
protection_group_id=dict(type='int', aliases=['id']),
vpc_domain_policy=dict(type='str', aliases=['vpc_domain_policy_name']),
switch_1_id=dict(type='int'),
switch_2_id=dict(type='int'),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['protection_group']],
['state', 'present', ['protection_group', 'protection_group_id', 'switch_1_id', 'switch_2_id']],
],
)
protection_group = module.params.get('protection_group')
protection_group_id = module.params.get('protection_group_id')
vpc_domain_policy = module.params.get('vpc_domain_policy')
switch_1_id = module.params.get('switch_1_id')
switch_2_id = module.params.get('switch_2_id')
state = module.params.get('state')
name_alias = module.params.get('name_alias')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='fabricExplicitGEp',
aci_rn='fabric/protpol/expgep-{0}'.format(protection_group),
module_object=protection_group,
target_filter={'name': protection_group},
),
child_classes=['fabricNodePEp', 'fabricNodePEp', 'fabricRsVpcInstPol'],
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='fabricExplicitGEp',
class_config=dict(
name=protection_group,
id=protection_group_id,
nameAlias=name_alias,
),
child_configs=[
dict(
fabricNodePEp=dict(
attributes=dict(
id='{0}'.format(switch_1_id),
),
),
),
dict(
fabricNodePEp=dict(
attributes=dict(
id='{0}'.format(switch_2_id),
),
),
),
dict(
fabricRsVpcInstPol=dict(
attributes=dict(
tnVpcInstPolName=vpc_domain_policy,
),
),
),
],
)
aci.get_diff(aci_class='fabricExplicitGEp')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,288 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# 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)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_taboo_contract
short_description: Manage taboo contracts (vz:BrCP)
description:
- Manage taboo contracts on Cisco ACI fabrics.
version_added: '2.4'
options:
taboo_contract:
description:
- The name of the Taboo Contract.
type: str
required: yes
aliases: [ name ]
description:
description:
- The description for the Taboo Contract.
type: str
aliases: [ descr ]
tenant:
description:
- The name of the tenant.
type: str
required: yes
aliases: [ tenant_name ]
scope:
description:
- The scope of a service contract.
- The APIC defaults to C(context) when unset during creation.
type: str
choices: [ application-profile, context, global, tenant ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
notes:
- The C(tenant) used must exist before using this module in your playbook.
The M(aci_tenant) module can be used for this.
seealso:
- module: aci_tenant
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(vz:BrCP).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Dag Wieers (@dagwieers)
'''
EXAMPLES = r'''
- name: Add taboo contract
aci_taboo_contract:
host: apic
username: admin
password: SomeSecretPassword
tenant: ansible_test
taboo_contract: taboo_contract_test
state: present
delegate_to: localhost
- name: Remove taboo contract
aci_taboo_contract:
host: apic
username: admin
password: SomeSecretPassword
tenant: ansible_test
taboo_contract: taboo_contract_test
state: absent
delegate_to: localhost
- name: Query all taboo contracts
aci_taboo_contract:
host: apic
username: admin
password: SomeSecretPassword
state: query
delegate_to: localhost
register: query_result
- name: Query a specific taboo contract
aci_taboo_contract:
host: apic
username: admin
password: SomeSecretPassword
tenant: ansible_test
taboo_contract: taboo_contract_test
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
taboo_contract=dict(type='str', aliases=['name']), # Not required for querying all contracts
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all contracts
scope=dict(type='str', choices=['application-profile', 'context', 'global', 'tenant']),
description=dict(type='str', aliases=['descr']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['tenant', 'taboo_contract']],
['state', 'present', ['tenant', 'taboo_contract']],
],
)
taboo_contract = module.params.get('taboo_contract')
description = module.params.get('description')
scope = module.params.get('scope')
state = module.params.get('state')
tenant = module.params.get('tenant')
name_alias = module.params.get('name_alias')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='vzTaboo',
aci_rn='taboo-{0}'.format(taboo_contract),
module_object=taboo_contract,
target_filter={'name': taboo_contract},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='vzTaboo',
class_config=dict(
name=taboo_contract,
descr=description,
scope=scope,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='vzTaboo')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,262 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_tenant
short_description: Manage tenants (fv:Tenant)
description:
- Manage tenants on Cisco ACI fabrics.
version_added: '2.4'
options:
tenant:
description:
- The name of the tenant.
type: str
required: yes
aliases: [ name, tenant_name ]
description:
description:
- Description for the tenant.
type: str
aliases: [ descr ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
seealso:
- module: aci_ap
- module: aci_bd
- module: aci_contract
- module: aci_filter
- module: aci_vrf
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(fv:Tenant).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Jacob McGill (@jmcgill298)
'''
EXAMPLES = r'''
- name: Add a new tenant
aci_tenant:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
description: Production tenant
state: present
delegate_to: localhost
- name: Remove a tenant
aci_tenant:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
state: absent
delegate_to: localhost
- name: Query a tenant
aci_tenant:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
state: query
delegate_to: localhost
register: query_result
- name: Query all tenants
aci_tenant:
host: apic
username: admin
password: SomeSecretPassword
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
tenant=dict(type='str', aliases=['name', 'tenant_name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['tenant']],
['state', 'present', ['tenant']],
],
)
description = module.params.get('description')
state = module.params.get('state')
tenant = module.params.get('tenant')
name_alias = module.params.get('name_alias')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='fvTenant',
class_config=dict(
name=tenant,
descr=description,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='fvTenant')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,246 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_tenant_action_rule_profile
short_description: Manage action rule profiles (rtctrl:AttrP)
description:
- Manage action rule profiles on Cisco ACI fabrics.
version_added: '2.4'
options:
action_rule:
description:
- The name of the action rule profile.
type: str
aliases: [ action_rule_name, name ]
description:
description:
- The description for the action rule profile.
type: str
aliases: [ descr ]
tenant:
description:
- The name of the tenant.
type: str
aliases: [ tenant_name ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
notes:
- The C(tenant) used must exist before using this module in your playbook.
The M(aci_tenant) module can be used for this.
seealso:
- module: aci_tenant
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(rtctrl:AttrP).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Dag Wieers (@dagwieers)
'''
# FIXME: Add more, better examples
EXAMPLES = r'''
- aci_tenant_action_rule_profile:
host: apic
username: admin
password: SomeSecretPassword
action_rule: '{{ action_rule }}'
description: '{{ descr }}'
tenant: '{{ tenant }}'
delegate_to: localhost
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
action_rule=dict(type='str', aliases=['action_rule_name', 'name']), # Not required for querying all objects
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['action_rule', 'tenant']],
['state', 'present', ['action_rule', 'tenant']],
],
)
action_rule = module.params.get('action_rule')
description = module.params.get('description')
state = module.params.get('state')
tenant = module.params.get('tenant')
name_alias = module.params.get('name_alias')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='rtctrlAttrP',
aci_rn='attr-{0}'.format(action_rule),
module_object=action_rule,
target_filter={'name': action_rule},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='rtctrlAttrP',
class_config=dict(
name=action_rule,
descr=description,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='rtctrlAttrP')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,361 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_tenant_ep_retention_policy
short_description: Manage End Point (EP) retention protocol policies (fv:EpRetPol)
description:
- Manage End Point (EP) retention protocol policies on Cisco ACI fabrics.
version_added: '2.4'
options:
tenant:
description:
- The name of an existing tenant.
type: str
aliases: [ tenant_name ]
epr_policy:
description:
- The name of the end point retention policy.
type: str
aliases: [ epr_name, name ]
bounce_age:
description:
- Bounce entry aging interval in seconds.
- Accepted values range between C(150) and C(65535); 0 is used for infinite.
- The APIC defaults to C(630) when unset during creation.
type: int
bounce_trigger:
description:
- Determines if the bounce entries are installed by RARP Flood or COOP Protocol.
- The APIC defaults to C(coop) when unset during creation.
type: str
choices: [ coop, flood ]
hold_interval:
description:
- Hold interval in seconds.
- Accepted values range between C(5) and C(65535).
- The APIC defaults to C(300) when unset during creation.
type: int
local_ep_interval:
description:
- Local end point aging interval in seconds.
- Accepted values range between C(120) and C(65535); 0 is used for infinite.
- The APIC defaults to C(900) when unset during creation.
type: int
remote_ep_interval:
description:
- Remote end point aging interval in seconds.
- Accepted values range between C(120) and C(65535); 0 is used for infinite.
- The APIC defaults to C(300) when unset during creation.
type: int
move_frequency:
description:
- Move frequency per second.
- Accepted values range between C(0) and C(65535); 0 is used for none.
- The APIC defaults to C(256) when unset during creation.
type: int
description:
description:
- Description for the End point retention policy.
type: str
aliases: [ descr ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
notes:
- The C(tenant) used must exist before using this module in your playbook.
The M(aci_tenant) module can be used for this.
seealso:
- module: aci_tenant
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(fv:EpRetPol).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Swetha Chunduri (@schunduri)
'''
EXAMPLES = r'''
- name: Add a new EPR policy
aci_tenant_ep_retention_policy:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
epr_policy: EPRPol1
bounce_age: 630
hold_interval: 300
local_ep_interval: 900
remote_ep_interval: 300
move_frequency: 256
description: test
state: present
delegate_to: localhost
- name: Remove an EPR policy
aci_tenant_ep_retention_policy:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
epr_policy: EPRPol1
state: absent
delegate_to: localhost
- name: Query an EPR policy
aci_tenant_ep_retention_policy:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
epr_policy: EPRPol1
state: query
delegate_to: localhost
register: query_result
- name: Query all EPR policies
aci_tenant_ep_retention_policy:
host: apic
username: admin
password: SomeSecretPassword
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
BOUNCE_TRIG_MAPPING = dict(
coop='protocol',
rarp='rarp-flood',
)
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
epr_policy=dict(type='str', aliases=['epr_name', 'name']), # Not required for querying all objects
bounce_age=dict(type='int'),
bounce_trigger=dict(type='str', choices=['coop', 'flood']),
hold_interval=dict(type='int'),
local_ep_interval=dict(type='int'),
remote_ep_interval=dict(type='int'),
description=dict(type='str', aliases=['descr']),
move_frequency=dict(type='int'),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['epr_policy', 'tenant']],
['state', 'present', ['epr_policy', 'tenant']],
],
)
epr_policy = module.params.get('epr_policy')
bounce_age = module.params.get('bounce_age')
if bounce_age is not None and bounce_age != 0 and bounce_age not in range(150, 65536):
module.fail_json(msg="The bounce_age must be a value of 0 or between 150 and 65535")
if bounce_age == 0:
bounce_age = 'infinite'
bounce_trigger = module.params.get('bounce_trigger')
if bounce_trigger is not None:
bounce_trigger = BOUNCE_TRIG_MAPPING[bounce_trigger]
description = module.params.get('description')
hold_interval = module.params.get('hold_interval')
if hold_interval is not None and hold_interval not in range(5, 65536):
module.fail_json(msg="The hold_interval must be a value between 5 and 65535")
local_ep_interval = module.params.get('local_ep_interval')
if local_ep_interval is not None and local_ep_interval != 0 and local_ep_interval not in range(120, 65536):
module.fail_json(msg="The local_ep_interval must be a value of 0 or between 120 and 65535")
if local_ep_interval == 0:
local_ep_interval = "infinite"
move_frequency = module.params.get('move_frequency')
if move_frequency is not None and move_frequency not in range(65536):
module.fail_json(msg="The move_frequency must be a value between 0 and 65535")
if move_frequency == 0:
move_frequency = "none"
remote_ep_interval = module.params.get('remote_ep_interval')
if remote_ep_interval is not None and remote_ep_interval not in range(120, 65536):
module.fail_json(msg="The remote_ep_interval must be a value of 0 or between 120 and 65535")
if remote_ep_interval == 0:
remote_ep_interval = "infinite"
state = module.params.get('state')
tenant = module.params.get('tenant')
name_alias = module.params.get('name_alias')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='fvEpRetPol',
aci_rn='epRPol-{0}'.format(epr_policy),
module_object=epr_policy,
target_filter={'name': epr_policy},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='fvEpRetPol',
class_config=dict(
name=epr_policy,
descr=description,
bounceAgeIntvl=bounce_age,
bounceTrig=bounce_trigger,
holdIntvl=hold_interval,
localEpAgeIntvl=local_ep_interval,
remoteEpAgeIntvl=remote_ep_interval,
moveFreq=move_frequency,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='fvEpRetPol')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,248 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_tenant_span_dst_group
short_description: Manage SPAN destination groups (span:DestGrp)
description:
- Manage SPAN destination groups on Cisco ACI fabrics.
version_added: '2.4'
options:
dst_group:
description:
- The name of the SPAN destination group.
type: str
required: yes
aliases: [ name ]
description:
description:
- The description of the SPAN destination group.
type: str
aliases: [ descr ]
tenant:
description:
- The name of the tenant.
type: str
required: yes
aliases: [ tenant_name ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
notes:
- The C(tenant) used must exist before using this module in your playbook.
The M(aci_tenant) module can be used for this.
seealso:
- module: aci_tenant
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(span:DestGrp).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Dag Wieers (@dagwieers)
'''
# FIXME: Add more, better examples
EXAMPLES = r'''
- aci_tenant_span_dst_group:
host: apic
username: admin
password: SomeSecretPassword
dst_group: '{{ dst_group }}'
description: '{{ descr }}'
tenant: '{{ tenant }}'
delegate_to: localhost
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
dst_group=dict(type='str', aliases=['name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['dst_group', 'tenant']],
['state', 'present', ['dst_group', 'tenant']],
],
)
dst_group = module.params.get('dst_group')
description = module.params.get('description')
state = module.params.get('state')
tenant = module.params.get('tenant')
name_alias = module.params.get('name_alias')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='spanDestGrp',
aci_rn='destgrp-{0}'.format(dst_group),
module_object=dst_group,
target_filter={'name': dst_group},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='spanDestGrp',
class_config=dict(
name=dst_group,
descr=description,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='spanDestGrp')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,264 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_tenant_span_src_group
short_description: Manage SPAN source groups (span:SrcGrp)
description:
- Manage SPAN source groups on Cisco ACI fabrics.
version_added: '2.4'
options:
admin_state:
description:
- Enable or disable the span sources.
- The APIC defaults to C(yes) when unset during creation.
type: bool
description:
description:
- The description for Span source group.
type: str
aliases: [ descr ]
dst_group:
description:
- The Span destination group to associate with the source group.
type: str
src_group:
description:
- The name of the Span source group.
type: str
aliases: [ name ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
tenant:
description:
- The name of the Tenant.
type: str
aliases: [ tenant_name ]
extends_documentation_fragment: aci
notes:
- The C(tenant) used must exist before using this module in your playbook.
The M(aci_tenant) module can be used for this.
seealso:
- module: aci_tenant
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(span:SrcGrp).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Jacob McGill (@jmcgill298)
'''
EXAMPLES = r'''
- aci_tenant_span_src_group:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
src_group: "{{ src_group }}"
dst_group: "{{ dst_group }}"
admin_state: "{{ admin_state }}"
description: "{{ description }}"
delegate_to: localhost
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
src_group=dict(type='str', aliases=['name']), # Not required for querying all objects
admin_state=dict(type='bool'),
description=dict(type='str', aliases=['descr']),
dst_group=dict(type='str'),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['src_group', 'tenant']],
['state', 'present', ['src_group', 'tenant']],
],
)
aci = ACIModule(module)
admin_state = aci.boolean(module.params.get('admin_state'), 'enabled', 'disabled')
description = module.params.get('description')
dst_group = module.params.get('dst_group')
src_group = module.params.get('src_group')
state = module.params.get('state')
tenant = module.params.get('tenant')
name_alias = module.params.get('name_alias')
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='spanSrcGrp',
aci_rn='srcgrp-{0}'.format(src_group),
module_object=src_group,
target_filter={'name': src_group},
),
child_classes=['spanSpanLbl'],
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='spanSrcGrp',
class_config=dict(
adminSt=admin_state,
descr=description,
name=src_group,
nameAlias=name_alias,
),
child_configs=[{'spanSpanLbl': {'attributes': {'name': dst_group}}}],
)
aci.get_diff(aci_class='spanSrcGrp')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,259 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_tenant_span_src_group_to_dst_group
short_description: Bind SPAN source groups to destination groups (span:SpanLbl)
description:
- Bind SPAN source groups to associated destination groups on Cisco ACI fabrics.
version_added: '2.4'
options:
description:
description:
- The description for Span source group to destination group binding.
type: str
aliases: [ descr ]
dst_group:
description:
- The Span destination group to associate with the source group.
type: str
src_group:
description:
- The name of the Span source group.
type: str
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
tenant:
description:
- The name of the Tenant.
type: str
aliases: [ tenant_name ]
extends_documentation_fragment: aci
notes:
- The C(tenant), C(src_group), and C(dst_group) must exist before using this module in your playbook.
The M(aci_tenant), M(aci_tenant_span_src_group), and M(aci_tenant_span_dst_group) modules can be used for this.
seealso:
- module: aci_tenant
- module: aci_tenant_span_src_group
- module: aci_tenant_span_dst_group
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(span:SrcGrp).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Jacob McGill (@jmcgill298)
'''
EXAMPLES = r'''
- aci_tenant_span_src_group_to_dst_group:
host: apic
username: admin
password: SomeSecretPassword
tenant: production
src_group: "{{ src_group }}"
dst_group: "{{ dst_group }}"
description: "{{ description }}"
delegate_to: localhost
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
dst_group=dict(type='str'), # Not required for querying all objects
src_group=dict(type='str'), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['dst_group', 'src_group', 'tenant']],
['state', 'present', ['dst_group', 'src_group', 'tenant']],
],
)
description = module.params.get('description')
dst_group = module.params.get('dst_group')
src_group = module.params.get('src_group')
state = module.params.get('state')
tenant = module.params.get('tenant')
name_alias = module.params.get('name_alias')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='spanSrcGrp',
aci_rn='srcgrp-{0}'.format(src_group),
module_object=src_group,
target_filter={'name': src_group},
),
subclass_2=dict(
aci_class='spanSpanLbl',
aci_rn='spanlbl-{0}'.format(dst_group),
module_object=dst_group,
target_filter={'name': dst_group},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='spanSpanLbl',
class_config=dict(
descr=description,
name=dst_group,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='spanSpanLbl')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,283 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Jacob McGill (@jmcgill298)
# 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)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_vlan_pool
short_description: Manage VLAN pools (fvns:VlanInstP)
description:
- Manage VLAN pools on Cisco ACI fabrics.
version_added: '2.5'
options:
pool_allocation_mode:
description:
- The method used for allocating VLANs to resources.
type: str
choices: [ dynamic, static]
aliases: [ allocation_mode, mode ]
description:
description:
- Description for the C(pool).
type: str
aliases: [ descr ]
pool:
description:
- The name of the pool.
type: str
aliases: [ name, pool_name ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
seealso:
- module: aci_encap_pool
- module: aci_vlan_pool_encap_block
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(fvns:VlanInstP).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Jacob McGill (@jmcgill298)
- Dag Wieers (@dagwieers)
'''
EXAMPLES = r'''
- name: Add a new VLAN pool
aci_vlan_pool:
host: apic
username: admin
password: SomeSecretPassword
pool: production
pool_allocation_mode: dynamic
description: Production VLANs
state: present
delegate_to: localhost
- name: Remove a VLAN pool
aci_vlan_pool:
host: apic
username: admin
password: SomeSecretPassword
pool: production
pool_allocation_mode: dynamic
state: absent
delegate_to: localhost
- name: Query a VLAN pool
aci_vlan_pool:
host: apic
username: admin
password: SomeSecretPassword
pool: production
pool_allocation_mode: dynamic
state: query
delegate_to: localhost
register: query_result
- name: Query all VLAN pools
aci_vlan_pool:
host: apic
username: admin
password: SomeSecretPassword
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
pool=dict(type='str', aliases=['name', 'pool_name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
pool_allocation_mode=dict(type='str', aliases=['allocation_mode', 'mode'], choices=['dynamic', 'static']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['pool']],
['state', 'present', ['pool']],
],
)
description = module.params.get('description')
pool = module.params.get('pool')
pool_allocation_mode = module.params.get('pool_allocation_mode')
state = module.params.get('state')
name_alias = module.params.get('name_alias')
pool_name = pool
# ACI Pool URL requires the allocation mode for vlan and vsan pools (ex: uni/infra/vlanns-[poolname]-static)
if pool is not None:
if pool_allocation_mode is not None:
pool_name = '[{0}]-{1}'.format(pool, pool_allocation_mode)
else:
module.fail_json(msg="ACI requires the 'pool_allocation_mode' when 'pool' is provided")
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='fvnsVlanInstP',
aci_rn='infra/vlanns-{0}'.format(pool_name),
module_object=pool,
target_filter={'name': pool},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='fvnsVlanInstP',
class_config=dict(
allocMode=pool_allocation_mode,
descr=description,
name=pool,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='fvnsVlanInstP')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,362 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Jacob McGill (jmcgill298)
# 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)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_vlan_pool_encap_block
short_description: Manage encap blocks assigned to VLAN pools (fvns:EncapBlk)
description:
- Manage VLAN encap blocks that are assigned to VLAN pools on Cisco ACI fabrics.
version_added: '2.5'
options:
allocation_mode:
description:
- The method used for allocating encaps to resources.
type: str
choices: [ dynamic, inherit, static]
aliases: [ mode ]
description:
description:
- Description for the pool encap block.
type: str
aliases: [ descr ]
pool:
description:
- The name of the pool that the encap block should be assigned to.
type: str
aliases: [ pool_name ]
pool_allocation_mode:
description:
- The method used for allocating encaps to resources.
type: str
choices: [ dynamic, static]
aliases: [ pool_mode ]
block_end:
description:
- The end of encap block.
type: int
aliases: [ end ]
block_name:
description:
- The name to give to the encap block.
type: str
aliases: [ name ]
block_start:
description:
- The start of the encap block.
type: int
aliases: [ start ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
notes:
- The C(pool) must exist in order to add or delete a encap block.
seealso:
- module: aci_encap_pool_range
- module: aci_vlan_pool
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(fvns:EncapBlk).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Jacob McGill (@jmcgill298)
- Dag Wieers (@dagwieers)
'''
EXAMPLES = r'''
- name: Add a new VLAN encap block
aci_vlan_pool_encap_block:
host: apic
username: admin
password: SomeSecretPassword
pool: production
block_start: 20
block_end: 50
state: present
delegate_to: localhost
- name: Remove a VLAN encap block
aci_vlan_pool_encap_block:
host: apic
username: admin
password: SomeSecretPassword
pool: production
block_start: 20
block_end: 50
state: absent
delegate_to: localhost
- name: Query a VLAN encap block
aci_vlan_pool_encap_block:
host: apic
username: admin
password: SomeSecretPassword
pool: production
block_start: 20
block_end: 50
state: query
delegate_to: localhost
register: query_result
- name: Query a VLAN pool for encap blocks
aci_vlan_pool_encap_block:
host: apic
username: admin
password: SomeSecretPassword
pool: production
state: query
delegate_to: localhost
register: query_result
- name: Query all VLAN encap blocks
aci_vlan_pool_encap_block:
host: apic
username: admin
password: SomeSecretPassword
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
pool=dict(type='str', aliases=['pool_name']), # Not required for querying all objects
block_name=dict(type='str', aliases=['name']), # Not required for querying all objects
block_end=dict(type='int', aliases=['end']), # Not required for querying all objects
block_start=dict(type='int', aliases=["start"]), # Not required for querying all objects
allocation_mode=dict(type='str', aliases=['mode'], choices=['dynamic', 'inherit', 'static']),
description=dict(type='str', aliases=['descr']),
pool_allocation_mode=dict(type='str', aliases=['pool_mode'], choices=['dynamic', 'static']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['pool', 'block_end', 'block_name', 'block_start']],
['state', 'present', ['pool', 'block_end', 'block_name', 'block_start']],
],
)
allocation_mode = module.params.get('allocation_mode')
description = module.params.get('description')
pool = module.params.get('pool')
pool_allocation_mode = module.params.get('pool_allocation_mode')
block_end = module.params.get('block_end')
block_name = module.params.get('block_name')
block_start = module.params.get('block_start')
state = module.params.get('state')
name_alias = module.params.get('name_alias')
if block_end is not None:
encap_end = 'vlan-{0}'.format(block_end)
else:
encap_end = None
if block_start is not None:
encap_start = 'vlan-{0}'.format(block_start)
else:
encap_start = None
# Collect proper mo information
aci_block_mo = 'from-[{0}]-to-[{1}]'.format(encap_start, encap_end)
pool_name = pool
# Validate block_end and block_start are valid for its respective encap type
for encap_id in block_end, block_start:
if encap_id is not None:
if not 1 <= encap_id <= 4094:
module.fail_json(msg="vlan pools must have 'block_start' and 'block_end' values between 1 and 4094")
if block_end is not None and block_start is not None:
# Validate block_start is less than block_end
if block_start > block_end:
module.fail_json(msg="The 'block_start' must be less than or equal to the 'block_end'")
elif block_end is None and block_start is None:
if block_name is None:
# Reset range managed object to None for aci util to properly handle query
aci_block_mo = None
# ACI Pool URL requires the allocation mode (ex: uni/infra/vlanns-[poolname]-static)
if pool is not None:
if pool_allocation_mode is not None:
pool_name = '[{0}]-{1}'.format(pool, pool_allocation_mode)
else:
module.fail_json(msg="ACI requires the 'pool_allocation_mode' when 'pool' is provided")
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='fvnsVlanInstP',
aci_rn='infra/vlanns-{0}'.format(pool_name),
module_object=pool,
target_filter={'name': pool},
),
subclass_1=dict(
aci_class='fvnsEncapBlk',
aci_rn=aci_block_mo,
module_object=aci_block_mo,
target_filter={'from': encap_start, 'to': encap_end, 'name': block_name},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='fvnsEncapBlk',
class_config={
"allocMode": allocation_mode,
"descr": description,
"from": encap_start,
"name": block_name,
"to": encap_end,
"nameAlias": name_alias,
},
)
aci.get_diff(aci_class='fvnsEncapBlk')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,316 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = r'''
---
module: aci_vmm_credential
short_description: Manage virtual domain credential profiles (vmm:UsrAccP)
description:
- Manage virtual domain credential profiles on Cisco ACI fabrics.
version_added: '2.9'
options:
name:
description:
- Name of the credential profile.
type: str
aliases: [ credential_name, credential_profile ]
credential_password:
description:
- VMM controller password.
type: str
aliases: []
credential_username:
description:
- VMM controller username.
type: str
aliases: []
description:
description:
- Description for the tenant.
type: str
aliases: [ descr ]
domain:
description:
- Name of the virtual domain profile.
type: str
aliases: [ domain_name, domain_profile, name ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
vm_provider:
description:
- The VM platform for VMM Domains.
- Support for Kubernetes was added in ACI v3.0.
- Support for CloudFoundry, OpenShift and Red Hat was added in ACI v3.1.
type: str
choices: [ cloudfoundry, kubernetes, microsoft, openshift, openstack, redhat, vmware ]
extends_documentation_fragment: aci
seealso:
- module: aci_domain
- name: APIC Management Information Model reference
description: More information about the internal APIC classes B(vmm:DomP)
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Jason Juenger (@jasonjuenger)
'''
EXAMPLES = r'''
- name: Add credential to VMware VMM domain
aci_vmm_credential:
host: apic
username: admin
password: SomeSecretPassword
domain: vmware_dom
description: secure credential
name: vCenterCredential
credential_username: vCenterUsername
credential_password: vCenterPassword
vm_provider: vmware
state: present
- name: Remove credential from VMware VMM domain
aci_vmm_credential:
host: apic
username: admin
password: SomeSecretPassword
domain: vmware_dom
name: myCredential
vm_provider: vmware
state: absent
- name: Query a specific VMware VMM credential
aci_vmm_credential:
host: apic
username: admin
password: SomeSecretPassword
domain: vmware_dom
name: vCenterCredential
vm_provider: vmware
state: query
delegate_to: localhost
register: query_result
- name: Query all VMware VMM credentials
aci_vmm_credential:
host: apic
username: admin
password: SomeSecretPassword
domain: vmware_dom
vm_provider: vmware
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
VM_PROVIDER_MAPPING = dict(
cloudfoundry='CloudFoundry',
kubernetes='Kubernetes',
microsoft='Microsoft',
openshift='OpenShift',
openstack='OpenStack',
redhat='Redhat',
vmware='VMware',
)
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
name=dict(type='str', aliases=['credential_name', 'credential_profile']),
credential_password=dict(type='str', no_log=True),
credential_username=dict(type='str'),
description=dict(type='str', aliases=['descr']),
domain=dict(type='str', aliases=['domain_name', 'domain_profile']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
vm_provider=dict(type='str', choices=VM_PROVIDER_MAPPING.keys()),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['domain']],
['state', 'present', ['domain']],
],
)
name = module.params.get('name')
credential_password = module.params.get('credential_password')
credential_username = module.params.get('credential_username')
description = module.params.get('description')
domain = module.params.get('domain')
state = module.params.get('state')
vm_provider = module.params.get('vm_provider')
name_alias = module.params.get('name_alias')
credential_class = 'vmmUsrAccP'
usracc_mo = 'uni/vmmp-{0}/dom-{1}/usracc-{2}'.format(VM_PROVIDER_MAPPING.get(vm_provider), domain, name)
usracc_rn = 'vmmp-{0}/dom-{1}/usracc-{2}'.format(VM_PROVIDER_MAPPING.get(vm_provider), domain, name)
# Ensure that querying all objects works when only domain is provided
if name is None:
usracc_mo = None
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class=credential_class,
aci_rn=usracc_rn,
module_object=usracc_mo,
target_filter={'name': domain, 'usracc': name},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class=credential_class,
class_config=dict(
descr=description,
name=name,
pwd=credential_password,
usr=credential_username,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class=credential_class)
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,296 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = r'''
---
module: aci_vrf
short_description: Manage contexts or VRFs (fv:Ctx)
description:
- Manage contexts or VRFs on Cisco ACI fabrics.
- Each context is a private network associated to a tenant, i.e. VRF.
version_added: '2.4'
options:
tenant:
description:
- The name of the Tenant the VRF should belong to.
type: str
aliases: [ tenant_name ]
vrf:
description:
- The name of the VRF.
type: str
aliases: [ context, name, vrf_name ]
policy_control_direction:
description:
- Determines if the policy should be enforced by the fabric on ingress or egress.
type: str
choices: [ egress, ingress ]
policy_control_preference:
description:
- Determines if the fabric should enforce contract policies to allow routing and packet forwarding.
type: str
choices: [ enforced, unenforced ]
description:
description:
- The description for the VRF.
type: str
aliases: [ descr ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
- Use C(query) for listing an object or multiple objects.
type: str
choices: [ absent, present, query ]
default: present
name_alias:
version_added: '2.10'
description:
- The alias for the current object. This relates to the nameAlias field in ACI.
type: str
extends_documentation_fragment: aci
notes:
- The C(tenant) used must exist before using this module in your playbook.
The M(aci_tenant) module can be used for this.
seealso:
- module: aci_tenant
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(fv:Ctx).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Jacob McGill (@jmcgill298)
'''
EXAMPLES = r'''
- name: Add a new VRF to a tenant
aci_vrf:
host: apic
username: admin
password: SomeSecretPassword
vrf: vrf_lab
tenant: lab_tenant
descr: Lab VRF
policy_control_preference: enforced
policy_control_direction: ingress
state: present
delegate_to: localhost
- name: Remove a VRF for a tenant
aci_vrf:
host: apic
username: admin
password: SomeSecretPassword
vrf: vrf_lab
tenant: lab_tenant
state: absent
delegate_to: localhost
- name: Query a VRF of a tenant
aci_vrf:
host: apic
username: admin
password: SomeSecretPassword
vrf: vrf_lab
tenant: lab_tenant
state: query
delegate_to: localhost
register: query_result
- name: Query all VRFs
aci_vrf:
host: apic
username: admin
password: SomeSecretPassword
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
vrf=dict(type='str', aliases=['context', 'name', 'vrf_name']), # Not required for querying all objects
description=dict(type='str', aliases=['descr']),
policy_control_direction=dict(type='str', choices=['egress', 'ingress']),
policy_control_preference=dict(type='str', choices=['enforced', 'unenforced']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
name_alias=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['tenant', 'vrf']],
['state', 'present', ['tenant', 'vrf']],
],
)
description = module.params.get('description')
policy_control_direction = module.params.get('policy_control_direction')
policy_control_preference = module.params.get('policy_control_preference')
state = module.params.get('state')
tenant = module.params.get('tenant')
vrf = module.params.get('vrf')
name_alias = module.params.get('name_alias')
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
module_object=tenant,
target_filter={'name': tenant},
),
subclass_1=dict(
aci_class='fvCtx',
aci_rn='ctx-{0}'.format(vrf),
module_object=vrf,
target_filter={'name': vrf},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class='fvCtx',
class_config=dict(
descr=description,
pcEnfDir=policy_control_direction,
pcEnfPref=policy_control_preference,
name=vrf,
nameAlias=name_alias,
),
)
aci.get_diff(aci_class='fvCtx')
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

@ -1,88 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Dag Wieers (@dagwieers) <dag@wieers.com>
# Copyright: (c) 2017, Swetha Chunduri (@schunduri)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
class ModuleDocFragment(object):
# Standard files documentation fragment
DOCUMENTATION = r'''
options:
host:
description:
- IP Address or hostname of APIC resolvable by Ansible control host.
type: str
required: yes
aliases: [ hostname ]
port:
description:
- Port number to be used for REST connection.
- The default value depends on parameter C(use_ssl).
type: int
username:
description:
- The username to use for authentication.
type: str
default: admin
aliases: [ user ]
password:
description:
- The password to use for authentication.
- This option is mutual exclusive with C(private_key). If C(private_key) is provided too, it will be used instead.
type: str
required: yes
private_key:
description:
- Either a PEM-formatted private key file or the private key content used for signature-based authentication.
- This value also influences the default C(certificate_name) that is used.
- This option is mutual exclusive with C(password). If C(password) is provided too, it will be ignored.
type: str
required: yes
aliases: [ cert_key ]
certificate_name:
description:
- The X.509 certificate name attached to the APIC AAA user used for signature-based authentication.
- If a C(private_key) filename was provided, this defaults to the C(private_key) basename, without extension.
- If PEM-formatted content was provided for C(private_key), this defaults to the C(username) value.
type: str
aliases: [ cert_name ]
output_level:
description:
- Influence the output of this ACI module.
- C(normal) means the standard output, incl. C(current) dict
- C(info) adds informational output, incl. C(previous), C(proposed) and C(sent) dicts
- C(debug) adds debugging output, incl. C(filter_string), C(method), C(response), C(status) and C(url) information
type: str
choices: [ debug, info, normal ]
default: normal
timeout:
description:
- The socket level timeout in seconds.
type: int
default: 30
use_proxy:
description:
- If C(no), it will not use a proxy, even if one is defined in an environment variable on the target hosts.
type: bool
default: yes
use_ssl:
description:
- If C(no), an HTTP connection will be used instead of the default HTTPS connection.
type: bool
default: yes
validate_certs:
description:
- If C(no), SSL certificates will not be validated.
- This should only set to C(no) when used on personally controlled sites using self-signed certificates.
type: bool
default: yes
seealso:
- ref: aci_guide
description: Detailed information on how to manage your ACI infrastructure using Ansible.
- ref: aci_dev_guide
description: Detailed guide on how to write your own Cisco ACI modules to contribute.
'''

@ -1,2 +0,0 @@
# No ACI simulator yet, so not enabled
unsupported

@ -1,235 +0,0 @@
# Test code for the ACI modules
# 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 any pre-existing user
aci_aaa_user: &user_absent
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") }}'
aaa_user: ansible
state: absent
# ADD USER
- name: Add user (check_mode)
aci_aaa_user: &user_present
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") }}'
aaa_user: ansible
description: Ansible test user
email: ansible@ansible.lan
enabled: yes
expiration: never
expires: no
first_name: Test
last_name: User
phone: 1-234-555-678
check_mode: yes
register: cm_add_user
# NOTE: Setting password is not idempotent, see #35544
- name: Add user (normal mode)
aci_aaa_user:
<<: *user_present
aaa_password: 12!Ab:cD!34
register: nm_add_user
- name: Add user again (check mode)
aci_aaa_user: *user_present
check_mode: yes
register: cm_add_user_again
- name: Add user again (normal mode)
aci_aaa_user: *user_present
register: nm_add_user_again
- name: Verify add user
assert:
that:
- cm_add_user is changed
- nm_add_user is changed
- nm_add_user.current.0.aaaUser.attributes.descr == 'Ansible test user'
- cm_add_user_again is not changed
- nm_add_user_again is not changed
- nm_add_user_again.current.0.aaaUser.attributes.descr == 'Ansible test user'
# MODIFY USER
- name: Modify user (check_mode)
aci_aaa_user: &user_changed
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") }}'
aaa_user: ansible
description: Ansible test user for integration tests
email: aci-ansible@ansible.lan
expiration: '2123-12-12'
expires: yes
phone: 2-345-555-678
check_mode: yes
register: cm_modify_user
- name: Modify user (normal mode)
aci_aaa_user: *user_changed
register: nm_modify_user
- name: Modify user again (check mode)
aci_aaa_user: *user_changed
check_mode: yes
register: cm_modify_user_again
- name: Modify user again (normal mode)
aci_aaa_user: *user_changed
register: nm_modify_user_again
- name: Verify modify user
assert:
that:
- cm_modify_user is changed
- nm_modify_user is changed
- nm_modify_user.current.0.aaaUser.attributes.descr == 'Ansible test user for integration tests'
- cm_modify_user_again is not changed
- nm_modify_user_again is not changed
- nm_modify_user_again.current.0.aaaUser.attributes.descr == 'Ansible test user for integration tests'
# CLEAR PASSWORD HISTORY
- name: Clear password history (check_mode)
aci_aaa_user: &clear_password_history
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") }}'
aaa_user: ansible
clear_password_history: yes
check_mode: yes
register: cm_clear_password_history
- name: Clear password history (normal mode)
aci_aaa_user: *clear_password_history
register: nm_clear_password_history
- name: Clear password history (check mode)
aci_aaa_user: *clear_password_history
check_mode: yes
register: cm_clear_password_history_again
- name: Clear password history (normal mode)
aci_aaa_user: *clear_password_history
register: nm_clear_password_history_again
- name: Verify clear password history
assert:
that:
# NOTE: Clearing password history is a changing action, everytime
- cm_clear_password_history is changed
- nm_clear_password_history is changed
- cm_clear_password_history_again is changed
- nm_clear_password_history_again is changed
# QUERY ALL USERS
- name: Query all users (check_mode)
aci_aaa_user: &user_query
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") }}'
aaa_user: ansible
state: query
check_mode: yes
register: cm_query_all_users
- name: Query all users (normal mode)
aci_aaa_user: *user_query
register: nm_query_all_users
- name: Verify query_all_users
assert:
that:
- cm_query_all_users is not changed
- nm_query_all_users is not changed
# NOTE: Order of users is not stable between calls
#- cm_query_all_users == nm_query_all_users
# QUERY OUR USER
- name: Query our user (check_mode)
aci_aaa_user:
<<: *user_query
check_mode: yes
register: cm_query_user
- name: Query our user (normal mode)
aci_aaa_user:
<<: *user_query
register: nm_query_user
- name: Verify query_user
assert:
that:
- cm_query_user is not changed
- nm_query_user is not changed
- cm_query_user == nm_query_user
- nm_query_user.current.0.aaaUser.attributes.accountStatus == 'active'
- nm_query_user.current.0.aaaUser.attributes.descr == 'Ansible test user for integration tests'
- nm_query_user.current.0.aaaUser.attributes.email == 'aci-ansible@ansible.lan'
- nm_query_user.current.0.aaaUser.attributes.expiration == '2123-12-12T00:00:00.000+00:00'
- nm_query_user.current.0.aaaUser.attributes.expires == 'yes'
- nm_query_user.current.0.aaaUser.attributes.phone == '2-345-555-678'
# REMOVE USER
- name: Remove user (check_mode)
aci_aaa_user: *user_absent
check_mode: yes
register: cm_remove_user
- name: Remove user (normal mode)
aci_aaa_user: *user_absent
register: nm_remove_user
- name: Remove user again (check_mode)
aci_aaa_user: *user_absent
check_mode: yes
register: cm_remove_user_again
- name: Remove user again (normal mode)
aci_aaa_user: *user_absent
register: nm_remove_user_again
- name: Verify remove_user
assert:
that:
- cm_remove_user is changed
- nm_remove_user is changed
- cm_remove_user_again is not changed
- nm_remove_user_again is not changed

@ -1,2 +0,0 @@
# No ACI simulator yet, so not enabled
unsupported

@ -1,14 +0,0 @@
-----BEGIN CERTIFICATE-----
MIICODCCAaGgAwIBAgIJAIt8XMntue0VMA0GCSqGSIb3DQEBCwUAMDQxDjAMBgNV
BAMMBUFkbWluMRUwEwYDVQQKDAxZb3VyIENvbXBhbnkxCzAJBgNVBAYTAlVTMCAX
DTE4MDEwOTAwNTk0NFoYDzIxMTcxMjE2MDA1OTQ0WjA0MQ4wDAYDVQQDDAVBZG1p
bjEVMBMGA1UECgwMWW91ciBDb21wYW55MQswCQYDVQQGEwJVUzCBnzANBgkqhkiG
9w0BAQEFAAOBjQAwgYkCgYEAohG/7axtt7CbSaMP7r+2mhTKbNgh0Ww36C7Ta14i
v+VmLyKkQHnXinKGhp6uy3Nug+15a+eIu7CrgpBVMQeCiWfsnwRocKcQJWIYDrWl
XHxGQn31yYKR6mylE7Dcj3rMFybnyhezr5D8GcP85YRPmwG9H2hO/0Y1FUnWu9Iw
AQkCAwEAAaNQME4wHQYDVR0OBBYEFD0jLXfpkrU/ChzRvfruRs/fy1VXMB8GA1Ud
IwQYMBaAFD0jLXfpkrU/ChzRvfruRs/fy1VXMAwGA1UdEwQFMAMBAf8wDQYJKoZI
hvcNAQELBQADgYEAOmvre+5tgZ0+F3DgsfxNQqLTrGiBgGCIymPkP/cBXXkNuJyl
3ac7tArHQc7WEA4U2R2rZbEq8FC3UJJm4nUVtCPvEh3G9OhN2xwYev79yt6pIn/l
KU0Td2OpVyo0eLqjoX5u2G90IBWzhyjFbo+CcKMrSVKj1YOdG0E3OuiJf00=
-----END CERTIFICATE-----

@ -1,16 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKIRv+2sbbewm0mj
D+6/tpoUymzYIdFsN+gu02teIr/lZi8ipEB514pyhoaerstzboPteWvniLuwq4KQ
VTEHgoln7J8EaHCnECViGA61pVx8RkJ99cmCkepspROw3I96zBcm58oXs6+Q/BnD
/OWET5sBvR9oTv9GNRVJ1rvSMAEJAgMBAAECgYByu3QO0qF9h7X3JEu0Ld4cKBnB
giQ2uJC/et7KxIJ/LOvw9GopBthyt27KwG1ntBkJpkTuAaQHkyNns7vLkNB0S0IR
+owVFEcKYq9VCHTaiQU8TDp24gN+yPTrpRuH8YhDVq5SfVdVuTMgHVQdj4ya4VlF
Gj+a7+ipxtGiLsVGrQJBAM7p0Fm0xmzi+tBOASUAcVrPLcteFIaTBFwfq16dm/ON
00Khla8Et5kMBttTbqbukl8mxFjBEEBlhQqb6EdQQ0sCQQDIhHx1a9diG7y/4DQA
4KvR3FCYwP8PBORlSamegzCo+P1OzxiEo0amX7yQMA5UyiP/kUsZrme2JBZgna8S
p4R7AkEAr7rMhSOPUnMD6V4WgsJ5g1Jp5kqkzBaYoVUUSms5RASz4+cwJVCwTX91
Y1jcpVIBZmaaY3a0wrx13ajEAa0dOQJBAIpjnb4wqpsEh7VpmJqOdSdGxb1XXfFQ
sA0T1OQYqQnFppWwqrxIL+d9pZdiA1ITnNqyvUFBNETqDSOrUHwwb2cCQGArE+vu
ffPUWQ0j+fiK+covFG8NL7H+26NSGB5+Xsn9uwOGLj7K/YT6CbBtr9hJiuWjM1Al
0V4ltlTuu2mTMaw=
-----END PRIVATE KEY-----

@ -1,142 +0,0 @@
# Test code for the ACI modules
# 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 any pre-existing certificate
aci_aaa_user_certificate: &cert_absent
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") }}'
aaa_user: admin
certificate_name: admin
state: absent
# ADD USER CERTIFICATE
- name: Add user certificate (check_mode)
aci_aaa_user_certificate: &cert_present
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") }}'
aaa_user: admin
certificate_name: admin
certificate: "{{ lookup('file', 'pki/admin.crt') }}"
state: present
check_mode: yes
register: cm_add_cert
- name: Add user certificate (normal mode)
aci_aaa_user_certificate: *cert_present
register: nm_add_cert
- name: Add user certificate again (check mode)
aci_aaa_user_certificate: *cert_present
check_mode: yes
register: cm_add_cert_again
- name: Add user certificate again (normal mode)
aci_aaa_user_certificate: *cert_present
register: nm_add_cert_again
- name: Verify add_cert
assert:
that:
- cm_add_cert is changed
- nm_add_cert is change
- cm_add_cert_again is not changed
- nm_add_cert_again is not changed
# QUERY ALL USER CERTIFICATES
- name: Query all user certificates using signature-based authentication (check_mode)
aci_aaa_user_certificate: &cert_query
host: '{{ aci_hostname }}'
username: '{{ aci_username }}'
#password: '{{ aci_password }}'
private_key: '{{ role_path }}/pki/admin.key'
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") }}'
aaa_user: admin
state: query
check_mode: yes
register: cm_query_all_certs
- name: Query all user certificates using signature-based authentication (normal mode)
aci_aaa_user_certificate: *cert_query
register: nm_query_all_certs
- name: Verify query_all_certs
assert:
that:
- cm_query_all_certs is not changed
- nm_query_all_certs is not changed
# NOTE: Order of certs is not stable between calls
#- cm_query_all_certs == nm_query_all_certs
# QUERY OUR USER CERTIFICATE
- name: Query our certificate using signature-based authentication (check_mode)
aci_aaa_user_certificate:
<<: *cert_query
certificate_name: admin
check_mode: yes
register: cm_query_cert
- name: Query our certificate using signature-based authentication (normal mode)
aci_aaa_user_certificate:
<<: *cert_query
certificate_name: admin
register: nm_query_cert
- name: Verify query_cert
assert:
that:
- cm_query_cert is not changed
- nm_query_cert is not changed
- cm_query_cert == nm_query_cert
# REMOVE CERTIFICATE
- name: Remove certificate (check_mode)
aci_aaa_user_certificate: *cert_absent
check_mode: yes
register: cm_remove_cert
- name: Remove certificate (normal mode)
aci_aaa_user_certificate: *cert_absent
register: nm_remove_cert
- name: Remove certificate again (check_mode)
aci_aaa_user_certificate: *cert_absent
check_mode: yes
register: cm_remove_cert_again
- name: Remove certificate again (normal mode)
aci_aaa_user_certificate: *cert_absent
register: nm_remove_cert_again
- name: Verify remove_cert
assert:
that:
- cm_remove_cert is changed
- nm_remove_cert is changed
- cm_remove_cert_again is not changed
- nm_remove_cert_again is not changed

@ -1,2 +0,0 @@
# No ACI simulator yet, so not enabled
unsupported

@ -1,135 +0,0 @@
# Test code for the ACI modules
# Copyright: (c) 2017, Bruno Calogero <brunocalogero@hotmail.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
- name: Ensuring Interface Policy Leaf profile exists for kick off
aci_interface_policy_leaf_profile: &aci_interface_policy_leaf_profile_present
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
state: present
leaf_interface_profile: leafintprftest
register: leaf_profile_present
- name: Ensure Interface Access Port Selector exists for kick of
aci_access_port_to_interface_policy_leaf_profile: &aci_access_port_to_interface_policy_leaf_profile_present
<<: *aci_interface_policy_leaf_profile_present
access_port_selector: anstest_accessportselector
# TODO: Ensure that leaf Policy Group Exists (module missing) (infra:AccPortGrp)
- name: Bind an Access Port Block to an Interface Access Port Selector - check mode works
aci_access_port_block_to_access_port: &aci_access_port_block_to_access_port_present
<<: *aci_access_port_to_interface_policy_leaf_profile_present
leaf_port_blk: anstest_leafportblkname
leaf_port_blk_description: anstest_leafportblkdesc
fromPort: 13
toPort: 16
check_mode: yes
register: accessportblock_to_accessport_check_mode_present
- name: Bind an Access Port Block to an Interface Access Port Selector - creation works
aci_access_port_block_to_access_port:
<<: *aci_access_port_block_to_access_port_present
register: accessportblock_to_accessport_present
- name: Bind an Access Port Block to an Interface Access Port Selector - idempotency works
aci_access_port_block_to_access_port:
<<: *aci_access_port_block_to_access_port_present
register: accessportblock_to_accessport_idempotent
- name: Bind an Access Port Block to an Interface Access Port Selector - update works
aci_access_port_block_to_access_port:
<<: *aci_access_port_block_to_access_port_present
toPort: 15
register: accessportblock_to_accessport_update
# TODO: also test for errors
- name: present assertions
assert:
that:
- accessportblock_to_accessport_check_mode_present is changed
- accessportblock_to_accessport_present is changed
- accessportblock_to_accessport_present.previous == []
- 'accessportblock_to_accessport_present.sent == {"infraPortBlk": {"attributes": {"descr": "anstest_leafportblkdesc", "name": "anstest_leafportblkname", "fromPort": "13", "toPort": "16"}}}'
- accessportblock_to_accessport_idempotent is not changed
- accessportblock_to_accessport_idempotent.sent == {}
- accessportblock_to_accessport_update is changed
- 'accessportblock_to_accessport_update.sent == {"infraPortBlk": {"attributes": {"toPort": "15"}}}'
- name: Query Specific port block and access_port_selector binding
aci_access_port_block_to_access_port:
<<: *aci_access_port_block_to_access_port_present
state: query
register: binding_query
- name: present assertions
assert:
that:
- binding_query is not changed
- binding_query.current | length >= 1
- '"api/mo/uni/infra/accportprof-leafintprftest/hports-anstest_accessportselector-typ-range/portblk-anstest_leafportblkname.json" in binding_query.url'
- name: Remove binding of Access Port Block and Interface Access Port Selector - check mode
aci_access_port_block_to_access_port: &aci_access_port_block_to_access_port_absent
<<: *aci_access_port_block_to_access_port_present
state: absent
check_mode: yes
register: accessportblock_to_accessport_check_mode_absent
- name: Remove binding of Access Port Block and Interface Access Port Selector - delete works
aci_access_port_block_to_access_port:
<<: *aci_access_port_block_to_access_port_absent
register: accessportblock_to_accessport_absent
- name: Remove binding of Access Port Block and Interface Access Port Selector - idempotency works
aci_access_port_block_to_access_port:
<<: *aci_access_port_block_to_access_port_absent
register: accessportblock_to_accessport_absent_idempotent
- name: Remove binding of Access Port Block and Interface Access Port Selector - check mode
aci_access_port_block_to_access_port:
<<: *aci_access_port_to_interface_policy_leaf_profile_present
#leaf_port_blk: anstest_leafportblkname
state: absent
ignore_errors: yes
register: accessportblock_to_accessport_absent_missing_param
- name: absent assertions
assert:
that:
- accessportblock_to_accessport_check_mode_absent is changed
- accessportblock_to_accessport_check_mode_absent.previous != []
- accessportblock_to_accessport_absent is changed
- accessportblock_to_accessport_absent.previous == accessportblock_to_accessport_check_mode_absent.previous
- accessportblock_to_accessport_absent_idempotent is not changed
- accessportblock_to_accessport_absent_idempotent.previous == []
- accessportblock_to_accessport_absent_missing_param is failed
- 'accessportblock_to_accessport_absent_missing_param.msg == "state is absent but all of the following are missing: leaf_port_blk"'
- name: Remove binding of Access Port Block and Interface Access Port Selector - Clean up
aci_access_port_block_to_access_port:
<<: *aci_access_port_block_to_access_port_present
state: absent
- name: Remove Interface Access Port Selector - Cleanup
aci_access_port_to_interface_policy_leaf_profile:
<<: *aci_access_port_to_interface_policy_leaf_profile_present
state: absent
- name: Remove Interface policy leaf profile - Cleanup
aci_interface_policy_leaf_profile:
<<: *aci_interface_policy_leaf_profile_present
state: absent

@ -1,2 +0,0 @@
# No ACI simulator yet, so not enabled
unsupported

@ -1,135 +0,0 @@
# Test code for the ACI modules
# Copyright: (c) 2017, Bruno Calogero <brunocalogero@hotmail.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
- name: Ensuring bindings do not already exist
aci_access_port_to_interface_policy_leaf_profile:
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) }}'
leaf_interface_profile: leafintprftest
access_port_selector: anstest_accessportselector
state: absent
- name: Ensuring Interface Policy Leaf profile exists for kick off
aci_interface_policy_leaf_profile: &aci_interface_policy_leaf_profile_present
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
state: present
leaf_interface_profile: leafintprftest
register: leaf_profile_present
# TODO: Ensure that leaf Policy Group Exists (module missing) (infra:AccPortGrp)
- name: Bind an Interface Access Port Selector to an Interface Policy Leaf Profile with a Policy Group - check mode works
aci_access_port_to_interface_policy_leaf_profile: &aci_access_port_to_interface_policy_leaf_profile_present
<<: *aci_interface_policy_leaf_profile_present
access_port_selector: anstest_accessportselector
check_mode: yes
register: accessport_to_intf_check_mode_present
- name: Bind an Interface Access Port Selector to an Interface Policy Leaf Profile with a Policy Group - creation works
aci_access_port_to_interface_policy_leaf_profile:
<<: *aci_access_port_to_interface_policy_leaf_profile_present
register: accessport_to_intf_present
- name: Bind an Interface Access Port Selector to an Interface Policy Leaf Profile with a Policy Group - idempotency works
aci_access_port_to_interface_policy_leaf_profile:
<<: *aci_access_port_to_interface_policy_leaf_profile_present
register: accessport_to_intf_idempotent
- name: Bind an Interface Access Port Selector to an Interface Policy Leaf Profile with a Policy Group - update works
aci_access_port_to_interface_policy_leaf_profile:
<<: *aci_access_port_to_interface_policy_leaf_profile_present
policy_group: anstest_policygroupname
register: accessport_to_intf_update
# TODO: also test for errors
- name: present assertions
assert:
that:
- accessport_to_intf_check_mode_present is changed
- accessport_to_intf_present is changed
- accessport_to_intf_present.previous == []
- 'accessport_to_intf_present.sent == {"infraHPortS": {"attributes": {"name": "anstest_accessportselector"}}}'
- accessport_to_intf_idempotent is not changed
- accessport_to_intf_idempotent.sent == {}
- accessport_to_intf_update is changed
- 'accessport_to_intf_update.sent == {"infraHPortS": {"attributes": {},"children": [{"infraRsAccBaseGrp": {"attributes": {"tDn": "uni/infra/funcprof/accportgrp-anstest_policygroupname"}}}]}}'
- name: Query Specific access_port_selector and leaf_interface_profile binding
aci_access_port_to_interface_policy_leaf_profile:
<<: *aci_interface_policy_leaf_profile_present
access_port_selector: anstest_accessportselector # "{{ fake_var | default(omit) }}" ?
state: query
register: binding_query
- name: present assertions
assert:
that:
- binding_query is not changed
- binding_query.current | length >= 1
- '"api/mo/uni/infra/accportprof-leafintprftest/hports-anstest_accessportselector-typ-range.json" in binding_query.url'
- name: Remove binding of interface access port selector and Interface Policy Leaf Profile - check mode
aci_access_port_to_interface_policy_leaf_profile: &aci_access_port_to_interface_policy_leaf_profile_absent
<<: *aci_interface_policy_leaf_profile_present
access_port_selector: anstest_accessportselector
state: absent
check_mode: yes
register: accessport_to_intf_check_mode_absent
- name: Remove binding of interface access port selector and Interface Policy Leaf Profile - delete works
aci_access_port_to_interface_policy_leaf_profile:
<<: *aci_access_port_to_interface_policy_leaf_profile_absent
register: accessport_to_intf_absent
- name: Remove binding of interface access port selector and Interface Policy Leaf Profile - idempotency works
aci_access_port_to_interface_policy_leaf_profile:
<<: *aci_access_port_to_interface_policy_leaf_profile_absent
register: accessport_to_intf_absent_idempotent
- name: Remove binding of interface access port selector and Interface Policy Leaf Profile - check mode
aci_access_port_to_interface_policy_leaf_profile:
<<: *aci_interface_policy_leaf_profile_present
#access_port_selector: anstest_accessportselector
state: absent
ignore_errors: yes
register: accessport_to_intf_absent_missing_param
- name: absent assertions
assert:
that:
- accessport_to_intf_check_mode_absent is changed
- accessport_to_intf_check_mode_absent.previous != []
- accessport_to_intf_absent is changed
- accessport_to_intf_absent.previous == accessport_to_intf_check_mode_absent.previous
- accessport_to_intf_absent_idempotent is not changed
- accessport_to_intf_absent_idempotent.previous == []
- accessport_to_intf_absent_missing_param is failed
- 'accessport_to_intf_absent_missing_param.msg == "state is absent but all of the following are missing: access_port_selector"'
- name: Remove an interface access port selector associated with an Interface Policy Leaf Profile - Clean up
aci_access_port_to_interface_policy_leaf_profile:
<<: *aci_access_port_to_interface_policy_leaf_profile_absent
state: absent
- name: Remove Interface policy leaf profile - Cleanup
aci_interface_policy_leaf_profile:
<<: *aci_interface_policy_leaf_profile_present
state: absent

@ -1,2 +0,0 @@
# No ACI simulator yet, so not enabled
unsupported

@ -1,137 +0,0 @@
# Test code for the ACI modules
# Copyright: (c) 2017, Bruno Calogero <brunocalogero@hotmail.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
- name: Ensuring Interface Policy Leaf profile exists for kick off
aci_interface_policy_leaf_profile: &aci_interface_policy_leaf_profile_present
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
state: present
leaf_interface_profile: leafintprftest
register: leaf_profile_present
- name: Ensure Interface Access Port Selector exists for kick of
aci_access_port_to_interface_policy_leaf_profile: &aci_access_port_to_interface_policy_leaf_profile_present
<<: *aci_interface_policy_leaf_profile_present
access_port_selector: anstest_accessportselector
# TODO: Ensure that leaf Policy Group Exists (module missing) (infra:AccPortGrp)
- name: Bind an Access Sub Port Block to an Interface Access Port Selector - check mode works
aci_access_sub_port_block_to_access_port: &aci_access_sub_port_block_to_access_port_present
<<: *aci_access_port_to_interface_policy_leaf_profile_present
leaf_port_blk: anstest_leafportblkname
leaf_port_blk_description: anstest_leafportblkdesc
fromPort: 13
toPort: 13
fromSubPort: 1
toSubPort: 3
check_mode: yes
register: accesssubportblock_to_accessport_check_mode_present
- name: Bind an Access Sub Port Block to an Interface Access Port Selector - creation works
aci_access_sub_port_block_to_access_port:
<<: *aci_access_sub_port_block_to_access_port_present
register: accesssubportblock_to_accessport_present
- name: Bind an Access Sub Port Block to an Interface Access Port Selector - idempotency works
aci_access_sub_port_block_to_access_port:
<<: *aci_access_sub_port_block_to_access_port_present
register: accesssubportblock_to_accessport_idempotent
- name: Bind an Access Sub Port Block to an Interface Access Port Selector - update works
aci_access_sub_port_block_to_access_port:
<<: *aci_access_sub_port_block_to_access_port_present
toSubPort: 2
register: accesssubportblock_to_accessport_update
# TODO: also test for errors
- name: present assertions
assert:
that:
- accesssubportblock_to_accessport_check_mode_present is changed
- accesssubportblock_to_accessport_present is changed
- accesssubportblock_to_accessport_present.previous == []
- 'accesssubportblock_to_accessport_present.sent == {"infraSubPortBlk": {"attributes": {"descr": "anstest_leafportblkdesc", "name": "anstest_leafportblkname", "fromPort": "13", "toPort": "13", "fromSubPort": "1", "toSubPort": "3"}}}'
- accesssubportblock_to_accessport_idempotent is not changed
- accesssubportblock_to_accessport_idempotent.sent == {}
- accesssubportblock_to_accessport_update is changed
- 'accesssubportblock_to_accessport_update.sent == {"infraSubPortBlk": {"attributes": {"toSubPort": "2"}}}'
- name: Query Specific sub port block and access_port_selector binding
aci_access_sub_port_block_to_access_port:
<<: *aci_access_sub_port_block_to_access_port_present
state: query
register: binding_query
- name: present assertions
assert:
that:
- binding_query is not changed
- binding_query.current | length >= 1
- '"api/mo/uni/infra/accportprof-leafintprftest/hports-anstest_accessportselector-typ-range/subportblk-anstest_leafportblkname.json" in binding_query.url'
- name: Remove binding of Access Sub Port Block and Interface Access Port Selector - check mode
aci_access_sub_port_block_to_access_port: &aci_access_sub_port_block_to_access_port_absent
<<: *aci_access_sub_port_block_to_access_port_present
state: absent
check_mode: yes
register: accesssubportblock_to_accessport_check_mode_absent
- name: Remove binding of Access Sub Port Block and Interface Access Port Selector - delete works
aci_access_sub_port_block_to_access_port:
<<: *aci_access_sub_port_block_to_access_port_absent
register: accesssubportblock_to_accessport_absent
- name: Remove binding of Access Sub Port Block and Interface Access Port Selector - idempotency works
aci_access_sub_port_block_to_access_port:
<<: *aci_access_sub_port_block_to_access_port_absent
register: accesssubportblock_to_accessport_absent_idempotent
- name: Remove binding of Access Sub Port Block and Interface Access Port Selector - check mode
aci_access_sub_port_block_to_access_port:
<<: *aci_access_port_to_interface_policy_leaf_profile_present
#leaf_port_blk: anstest_leafportblkname
state: absent
ignore_errors: yes
register: accesssubportblock_to_accessport_absent_missing_param
- name: absent assertions
assert:
that:
- accesssubportblock_to_accessport_check_mode_absent is changed
- accesssubportblock_to_accessport_check_mode_absent.previous != []
- accesssubportblock_to_accessport_absent is changed
- accesssubportblock_to_accessport_absent.previous == accesssubportblock_to_accessport_check_mode_absent.previous
- accesssubportblock_to_accessport_absent_idempotent is not changed
- accesssubportblock_to_accessport_absent_idempotent.previous == []
- accesssubportblock_to_accessport_absent_missing_param is failed
- 'accesssubportblock_to_accessport_absent_missing_param.msg == "state is absent but all of the following are missing: leaf_port_blk"'
- name: Remove binding of Access Sub Port Block and Interface Access Port Selector - Clean up
aci_access_sub_port_block_to_access_port:
<<: *aci_access_sub_port_block_to_access_port_present
state: absent
- name: Remove Interface Access Port Selector - Cleanup
aci_access_port_to_interface_policy_leaf_profile:
<<: *aci_access_port_to_interface_policy_leaf_profile_present
state: absent
- name: Remove Interface policy leaf profile - Cleanup
aci_interface_policy_leaf_profile:
<<: *aci_interface_policy_leaf_profile_present
state: absent

@ -1,2 +0,0 @@
# No ACI simulator yet, so not enabled
unsupported

@ -1,272 +0,0 @@
# 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)
- 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 AEP
aci_aep: &aep_absent
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") }}'
aep: ansible_test
state: absent
# ADD AEP
- name: Add AEP (check_mode)
aci_aep: &aep_present
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") }}'
aep: ansible_test
state: present
check_mode: yes
register: cm_add_aep
- name: Add AEP (normal mode)
aci_aep: *aep_present
register: nm_add_aep
- name: Verify add_aep
assert:
that:
- cm_add_aep is changed
- nm_add_aep is changed
- nm_add_aep.previous == nm_add_aep.previous == cm_add_aep.current == []
- 'nm_add_aep.current == [{"infraAttEntityP": {"attributes": {"descr": "", "dn": "uni/infra/attentp-ansible_test", "name": "ansible_test", "nameAlias": "", "ownerKey": "", "ownerTag": ""}}}]'
- 'cm_add_aep.proposed == nm_add_aep.proposed == cm_add_aep.sent == nm_add_aep.sent == {"infraAttEntityP": {"attributes": {"name": "ansible_test"}}}'
- name: Add AEP again (check_mode)
aci_aep: *aep_present
check_mode: yes
register: cm_add_aep_again
- name: Add AEP again (normal mode)
aci_aep: *aep_present
register: nm_add_aep_again
- name: Verify add_aep_again
assert:
that:
- cm_add_aep_again is not changed
- nm_add_aep_again is not changed
- 'nm_add_aep_again.previous == nm_add_aep_again.previous == cm_add_aep_again.current == nm_add_aep_again.current == [{"infraAttEntityP": {"attributes": {"descr": "", "dn": "uni/infra/attentp-ansible_test", "name": "ansible_test", "nameAlias": "", "ownerKey": "", "ownerTag": ""}}}]'
- 'cm_add_aep_again.proposed == nm_add_aep_again.proposed == {"infraAttEntityP": {"attributes": {"name": "ansible_test"}}}'
- cm_add_aep_again.sent == nm_add_aep_again.sent == {}
# CHANGE AEP
- name: Change description of AEP (check_mode)
aci_aep:
<<: *aep_present
description: Ansible test AEP
check_mode: yes
register: cm_add_aep_descr
- name: Change description of AEP (normal mode)
aci_aep:
<<: *aep_present
description: Ansible test AEP
register: nm_add_aep_descr
- name: Verify add_aep_descr
assert:
that:
- cm_add_aep_descr is changed
- nm_add_aep_descr is changed
- 'cm_add_aep_descr.proposed == nm_add_aep_descr.proposed == {"infraAttEntityP": {"attributes": {"descr": "Ansible test AEP", "name": "ansible_test"}}}'
- 'cm_add_aep_descr.sent == nm_add_aep_descr.sent == {"infraAttEntityP": {"attributes": {"descr": "Ansible test AEP"}}}'
- 'cm_add_aep_descr.previous == nm_add_aep_descr.previous == cm_add_aep_descr.current == [{"infraAttEntityP": {"attributes": {"descr": "", "dn": "uni/infra/attentp-ansible_test", "name": "ansible_test", "nameAlias": "", "ownerKey": "", "ownerTag": ""}}}]'
- 'nm_add_aep_descr.current == [{"infraAttEntityP": {"attributes": {"descr": "Ansible test AEP", "dn": "uni/infra/attentp-ansible_test", "name": "ansible_test", "nameAlias": "", "ownerKey": "", "ownerTag": ""}}}]'
- name: Change description of AEP again (check_mode)
aci_aep:
<<: *aep_present
description: Ansible test AEP
check_mode: yes
register: cm_add_aep_descr_again
- name: Change description of AEP again (normal mode)
aci_aep:
<<: *aep_present
description: Ansible test AEP
register: nm_add_aep_descr_again
- name: Verify add_aep_descr_again
assert:
that:
- cm_add_aep_descr_again is not changed
- nm_add_aep_descr_again is not changed
- 'cm_add_aep_descr_again.proposed == nm_add_aep_descr_again.proposed == {"infraAttEntityP": {"attributes": {"descr": "Ansible test AEP", "name": "ansible_test"}}}'
- 'cm_add_aep_descr_again.sent == nm_add_aep_descr_again.sent == {}'
- 'cm_add_aep_descr_again.previous == nm_add_aep_descr_again.previous == cm_add_aep_descr_again.current == nm_add_aep_descr_again.current == [{"infraAttEntityP": {"attributes": {"descr": "Ansible test AEP", "dn": "uni/infra/attentp-ansible_test", "name": "ansible_test", "nameAlias": "", "ownerKey": "", "ownerTag": ""}}}]'
# ADD AEP AGAIN
- name: Add AEP again with no description (check_mode)
aci_aep: *aep_present
check_mode: yes
register: cm_add_aep_again_no_descr
- name: Add AEP again with no description (normal mode)
aci_aep: *aep_present
register: nm_add_aep_again_no_descr
- name: Verify add_aep_again_no_descr
assert:
that:
- cm_add_aep_again_no_descr is not changed
- nm_add_aep_again_no_descr is not changed
- 'cm_add_aep_again_no_descr.proposed == nm_add_aep_again_no_descr.proposed == {"infraAttEntityP": {"attributes": {"name": "ansible_test"}}}'
- cm_add_aep_again_no_descr.sent == nm_add_aep_again_no_descr.sent == {}
- 'cm_add_aep_again_no_descr.previous == nm_add_aep_again_no_descr.previous == cm_add_aep_again_no_descr.current == nm_add_aep_again_no_descr.current == [{"infraAttEntityP": {"attributes": {"descr": "Ansible test AEP", "dn": "uni/infra/attentp-ansible_test", "name": "ansible_test", "nameAlias": "", "ownerKey": "", "ownerTag": ""}}}]'
# QUERY ALL AEPS
- name: Query all AEPs (check_mode)
aci_aep: &aep_query
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") }}'
state: query
check_mode: yes
register: cm_query_all_aeps
- name: Query all AEPs (normal mode)
aci_aep: *aep_query
register: nm_query_all_aeps
- name: Verify query_all_aeps
assert:
that:
- cm_query_all_aeps is not changed
- nm_query_all_aeps is not changed
- cm_query_all_aeps == nm_query_all_aeps
- nm_query_all_aeps.current|length >= 1
# QUERY A AEP
- name: Query our AEP
aci_aep:
<<: *aep_query
aep: ansible_test
check_mode: yes
register: cm_query_aep
- name: Query our AEP
aci_aep:
<<: *aep_query
aep: ansible_test
register: nm_query_aep
- name: Verify query_aep
assert:
that:
- cm_query_aep is not changed
- nm_query_aep is not changed
- cm_query_aep == nm_query_aep
- nm_query_aep.current.0.infraAttEntityP.attributes.descr == "Ansible test AEP"
- nm_query_aep.current.0.infraAttEntityP.attributes.dn == "uni/infra/attentp-ansible_test"
- nm_query_aep.current.0.infraAttEntityP.attributes.name == "ansible_test"
# REMOVE AEP
- name: Remove AEP (check_mode)
aci_aep: *aep_absent
check_mode: yes
register: cm_remove_aep
- name: Remove AEP (normal mode)
aci_aep: *aep_absent
register: nm_remove_aep
- name: Verify remove_aep
assert:
that:
- cm_remove_aep is changed
- nm_remove_aep is changed
- cm_remove_aep.proposed == nm_remove_aep.proposed == {}
- cm_remove_aep.sent == nm_remove_aep.sent == {}
- 'cm_remove_aep.previous == nm_remove_aep.previous == cm_remove_aep.current == [{"infraAttEntityP": {"attributes": {"descr": "Ansible test AEP", "dn": "uni/infra/attentp-ansible_test", "name": "ansible_test", "nameAlias": "", "ownerKey": "", "ownerTag": ""}}}]'
- nm_remove_aep.current == []
- name: Remove AEP again (check_mode)
aci_aep: *aep_absent
check_mode: yes
register: cm_remove_aep_again
- name: Remove AEP again (normal mode)
aci_aep: *aep_absent
register: nm_remove_aep_again
- name: Verify remove_aep_again
assert:
that:
- cm_remove_aep_again is not changed
- nm_remove_aep_again is not changed
- cm_remove_aep_again.proposed == nm_remove_aep_again.proposed == {}
- cm_remove_aep_again.sent == nm_remove_aep_again.sent == {}
- cm_remove_aep_again.previous == nm_remove_aep_again.previous == cm_remove_aep_again.current == nm_remove_aep_again.current == []
# QUERY NON-EXISTING AEP
- name: Query non-existing AEP (check_mode)
aci_aep:
<<: *aep_query
aep: ansible_test
check_mode: yes
register: cm_query_non_aep
- name: Query non-existing AEP (normal mode)
aci_aep:
<<: *aep_query
aep: ansible_test
register: nm_query_non_aep
- name: Verify query_non_aep
assert:
that:
- cm_query_non_aep is not changed
- nm_query_non_aep is not changed
- cm_query_non_aep == nm_query_non_aep
- cm_query_non_aep.current == nm_query_non_aep.current == []
# PROVOKE ERRORS
- name: Error when required parameter is missing
aci_aep:
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") }}'
state: present
ignore_errors: yes
register: error_on_missing_required_param
- name: Verify error_on_missing_required_param
assert:
that:
- error_on_missing_required_param is failed
- 'error_on_missing_required_param.msg == "state is present but all of the following are missing: aep"'

@ -1,2 +0,0 @@
# No ACI simulator yet, so not enabled
unsupported

@ -1,210 +0,0 @@
# 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)
# CLEAN ENVIRONMENT
- name: Remove AEP to domain binding
aci_aep_to_domain: &binding_absent
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") }}'
aep: test_aep
domain: phys_dom
domain_type: phys
state: absent
- name: Create AEP
aci_aep:
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") }}'
aep: test_aep
description: Test AEP
state: present
- name: Create physical domain
aci_domain:
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") }}'
domain: phys_dom
domain_type: phys
state: present
# ADD BINDING
- name: Add AEP to domain binding (check_mode)
aci_aep_to_domain: &binding_present
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") }}'
aep: test_aep
domain: phys_dom
domain_type: phys
state: present
check_mode: yes
register: cm_add_binding
- name: Add AEP to domain binding (normal mode)
aci_aep_to_domain: *binding_present
register: nm_add_binding
- name: Verify add_binding
assert:
that:
- cm_add_binding is changed
- nm_add_binding is changed
- 'cm_add_binding.sent == nm_add_binding.sent == {"infraRsDomP": {"attributes": {"tDn": "uni/phys-phys_dom"}}}'
- 'cm_add_binding.proposed == nm_add_binding.proposed == {"infraRsDomP": {"attributes": {"tDn": "uni/phys-phys_dom"}}}'
- cm_add_binding.current == cm_add_binding.previous == nm_add_binding.previous == []
- 'nm_add_binding.current == [{"infraRsDomP": {"attributes": {"dn": "uni/infra/attentp-test_aep/rsdomP-[uni/phys-phys_dom]", "tDn": "uni/phys-phys_dom"}}}]'
- name: Add AEP to domain binding again (check_mode)
aci_aep_to_domain: *binding_present
check_mode: yes
register: cm_add_binding_again
- name: Add AEP to domain binding again (normal mode)
aci_aep_to_domain: *binding_present
register: nm_add_binding_again
- name: Verify add_binding_again
assert:
that:
- cm_add_binding_again is not changed
- nm_add_binding_again is not changed
# QUERY ALL BINDINGS
- name: Query all AEP to domain bindings (check_mode)
aci_aep_to_domain: &binding_query
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") }}'
state: query
check_mode: yes
register: cm_query_all_bindings
- name: Query all AEP to domain bindings (normal mode)
aci_aep_to_domain: *binding_query
register: nm_query_all_bindings
- name: Verify query_all_bindings
assert:
that:
- cm_query_all_bindings is not changed
- nm_query_all_bindings is not changed
- cm_query_all_bindings == nm_query_all_bindings
- nm_query_all_bindings.current|length >= 1
# QUERY A BINDING
- name: Query our AEP to domain binding (check_mode)
aci_aep_to_domain:
<<: *binding_query
aep: test_aep
domain: phys_dom
domain_type: phys
check_mode: yes
register: cm_query_binding
- name: Query our AEP to domain binding (normal mode)
aci_aep_to_domain:
<<: *binding_query
aep: test_aep
domain: phys_dom
domain_type: phys
register: nm_query_binding
- name: Verify query_binding
assert:
that:
- cm_query_binding is not changed
- nm_query_binding is not changed
- cm_query_binding == nm_query_binding
- nm_query_binding.current.0.infraRsDomP.attributes.dn == 'uni/infra/attentp-test_aep/rsdomP-[uni/phys-phys_dom]'
- nm_query_binding.current.0.infraRsDomP.attributes.tCl == 'physDomP'
- nm_query_binding.current.0.infraRsDomP.attributes.tDn == 'uni/phys-phys_dom'
# REMOVE BINDING
- name: Remove AEP to domain binding (check_mode)
aci_aep_to_domain: *binding_absent
check_mode: yes
register: cm_remove_binding
- name: Remove AEP to domain binding (normal mode)
aci_aep_to_domain: *binding_absent
register: nm_remove_binding
- name: Verify remove_binding
assert:
that:
- cm_remove_binding is changed
- nm_remove_binding is changed
- 'cm_remove_binding.current == cm_remove_binding.previous == nm_remove_binding.previous == [{"infraRsDomP": {"attributes": {"dn": "uni/infra/attentp-test_aep/rsdomP-[uni/phys-phys_dom]", "tDn": "uni/phys-phys_dom"}}}]'
- nm_remove_binding.current == []
- name: Remove AEP to domain binding again (check_mode)
aci_aep_to_domain: *binding_absent
check_mode: yes
register: cm_remove_binding_again
- name: Remove AEP to domain binding again (normal mode)
aci_aep_to_domain: *binding_absent
register: nm_remove_binding_again
- name: Verify remove_binding_again
assert:
that:
- cm_remove_binding_again is not changed
- nm_remove_binding_again is not changed
# QUERY NON-EXISTING BINDING
- name: Query non-existing AEP to domain binding (check_mode)
aci_aep_to_domain:
<<: *binding_query
aep: test_aep
domain: phys_dom
domain_type: phys
check_mode: yes
register: cm_query_non_binding
- name: Query non-existing AEP to domain binding (normal mode)
aci_aep_to_domain:
<<: *binding_query
aep: test_aep
domain: phys_dom
domain_type: phys
register: nm_query_non_binding
- name: Verify query_non_binding
assert:
that:
- cm_query_non_binding is not changed
- nm_query_non_binding is not changed
- cm_query_non_binding == nm_query_non_binding
- nm_query_non_binding.current == []

@ -1,2 +0,0 @@
# No ACI simulator yet, so not enabled
unsupported

@ -1,173 +0,0 @@
# Test code for the ACI modules
# Copyright: (c) 2017, Jacob McGill (@jmcgill298)
# 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
- name: ensure tenant exists for tests to kick off
aci_tenant: &aci_tenant_present
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
state: present
tenant: anstest
register: tenant_present
- name: ensure ap does not exist initially
aci_ap:
<<: *aci_tenant_present
ap: anstest
state: absent
- name: create ap - check mode works
aci_ap: &aci_ap_present
<<: *aci_tenant_present
ap: anstest
description: Ansible Test
check_mode: yes
register: ap_present_check_mode
- name: create ap - creation works
aci_ap:
<<: *aci_ap_present
register: ap_present
- name: create ap - extra for query
aci_ap:
<<: *aci_tenant_present
ap: anstest2
- name: create ap - idempotency works
aci_ap:
<<: *aci_ap_present
register: ap_present_idempotent
- name: update ap - update works
aci_ap:
<<: *aci_ap_present
description: Ansible Test Update
register: ap_present_update
- name: create ap - creation works
aci_ap:
<<: *aci_tenant_present
ignore_errors: yes
register: ap_present_missing_param
- name: present asserts
assert:
that:
- ap_present_check_mode is changed
- ap_present is changed
- ap_present.previous == []
- ap_present.sent == ap_present_check_mode.sent
- 'ap_present.sent == {"fvAp": {"attributes": {"descr": "Ansible Test", "name": "anstest"}}}'
- ap_present_idempotent is not changed
- ap_present_idempotent.previous != []
- ap_present_idempotent.sent == {}
- ap_present_update is changed
- 'ap_present_update.sent.fvAp.attributes == {"descr": "Ansible Test Update"}'
- ap_present_missing_param is failed
- 'ap_present_missing_param.msg == "state is present but all of the following are missing: ap"'
- name: get ap - query specific ap
aci_ap: &aci_ap_query
<<: *aci_ap_present
state: query
register: query_ap
- name: get all ap for tenant - query tenant aps
aci_ap:
<<: *aci_ap_query
ap: "{{ fakevar | default(omit) }}"
register: query_ap_tenant
- name: get all ap by name - query ap name
aci_ap:
<<: *aci_ap_query
tenant: "{{ fakevar | default(omit) }}"
register: query_ap_ap
- name: get all aps - query general
aci_ap:
<<: *aci_ap_query
tenant: "{{ fakevar | default(omit) }}"
ap: "{{ fakevar | default(omit) }}"
register: query_all
- name: query assertions
assert:
that:
- query_ap is not changed
- query_ap.current | length == 1
- query_ap.current.0.fvAp.attributes.name == "anstest"
- '"tn-anstest/ap-anstest.json" in query_ap.url'
- query_ap_tenant is not changed
- query_ap_tenant.current | length == 1
- query_ap_tenant.current.0.fvTenant.children | length == 2
- '"rsp-subtree-class=fvAp" in query_ap_tenant.filter_string'
- '"tn-anstest.json" in query_ap_tenant.url'
- query_ap_ap is not changed
- query_ap_ap.current != []
- query_ap_ap.current.0.fvAp is defined
- '"query-target-filter=eq(fvAp.name, \"anstest\")" in query_ap_ap.filter_string'
- '"class/fvAp.json" in query_ap_ap.url'
- query_all is not changed
- query_all.current | length > 1
- '"class/fvAp.json" in query_all.url'
- name: delete ap - check_mode works
aci_ap: &aci_ap_absent
<<: *aci_ap_present
state: absent
check_mode: yes
register: ap_delete_check_mode
- name: delete ap - delete works
aci_ap:
<<: *aci_ap_absent
register: ap_delete
- name: delete ap - delete idempotency works
aci_ap:
<<: *aci_ap_absent
register: ap_delete_idempotent
- name: delete ap - missing param error
aci_ap:
<<: *aci_ap_absent
tenant: "{{ fakevar | default(omit) }}"
ignore_errors: yes
register: ap_delete_missing_param
- name: delete ap remove ap used for query
aci_ap:
<<: *aci_ap_absent
ap: anstest2
- name: absent assertions
assert:
that:
- ap_delete_check_mode is changed
- ap_delete_check_mode.previous != []
- '"tn-anstest/ap-anstest.json" in ap_delete_check_mode.url'
- ap_delete is changed
- ap_delete.previous == ap_delete_check_mode.previous
- ap_delete_idempotent is not changed
- ap_delete_idempotent.previous == []
- ap_delete_missing_param is failed
- 'ap_delete_missing_param.msg == "state is absent but all of the following are missing: tenant"'
- name: delete tenant - cleanup before ending tests
aci_tenant:
<<: *aci_tenant_present
state: absent
when: tenant_present is changed

@ -1,2 +0,0 @@
# No ACI simulator yet, so not enabled
unsupported

@ -1,205 +0,0 @@
# Test code for the ACI modules
# Copyright: (c) 2017, Jacob McGill (@jmcgill298)
# 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
- name: ensure tenant exists for tests to kick off
aci_tenant: &aci_tenant_present
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
state: present
tenant: anstest
register: tenant_present
- name: ensure vrf exists for tests to kick off
aci_vrf: &aci_vrf_present
<<: *aci_tenant_present
vrf: anstest
register: vrf_present
- name: ensure bd anstest does not exist
aci_bd:
<<: *aci_tenant_present
bd: anstest
state: absent
- name: ensure bd anstest2 does not exist
aci_bd:
<<: *aci_tenant_present
bd: anstest2
state: absent
- name: create bd - check mode works
aci_bd: &aci_bd_present
<<: *aci_tenant_present
bd: anstest
description: Ansible Test
check_mode: yes
register: bd_present_check_mode
- name: create bd - creation works
aci_bd:
<<: *aci_bd_present
register: bd_present
- name: create bd again - idempotency works
aci_bd:
<<: *aci_bd_present
register: bd_present_idempotent
- name: update bd - update works
aci_bd:
<<: *aci_bd_present
vrf: anstest
description: Ansible Test Update
register: bd_update
- name: create another bd - check more params
aci_bd:
<<: *aci_bd_present
bd: anstest2
ip_learning: "no"
l2_unknown_unicast: flood
l3_unknown_multicast: opt-flood
multi_dest: drop
enable_routing: "no"
arp_flooding: "yes"
register: bd_present_2
- name: create bd without all necessary params - failure message works
aci_bd:
<<: *aci_bd_present
tenant: "{{ fake_var | default(omit) }}"
ignore_errors: yes
register: bd_present_missing_param
- name: present asserts
assert:
that:
- bd_present_check_mode is changed
- 'bd_present_check_mode.sent == {"fvBD": {"attributes": {"descr": "Ansible Test", "name": "anstest"}}}'
- bd_present is changed
- bd_present.sent == bd_present_check_mode.sent
- bd_present.previous == []
- bd_present_idempotent is not changed
- bd_present_idempotent.previous != []
- bd_update is changed
- bd_update.previous != []
- bd_update.sent != bd_update.proposed
- 'bd_update.sent == {"fvBD": {"attributes": {"descr": "Ansible Test Update"}, "children": [{"fvRsCtx": {"attributes": {"tnFvCtxName": "anstest"}}}]}}'
- 'bd_present_2.sent.fvBD.attributes == {"arpFlood": "yes", "descr": "Ansible Test", "ipLearning": "no", "multiDstPktAct": "drop", "name": "anstest2",
"unicastRoute": "no", "unkMacUcastAct": "flood", "unkMcastAct": "opt-flood"}'
- bd_present_missing_param is failed
- 'bd_present_missing_param.msg == "state is present but all of the following are missing: tenant"'
- name: get all bd
aci_bd: &aci_query
<<: *aci_tenant_present
state: query
tenant: "{{ fake_var | default(omit) }}"
register: query_all
- name: get all in tenant
aci_bd:
<<: *aci_query
tenant: anstest
register: query_tenant
- name: get all with name
aci_bd:
<<: *aci_query
bd: anstest
register: query_bd_bd
- name: get bd
aci_bd:
<<: *aci_bd_present
state: query
register: query_bd
- name: query asserts
assert:
that:
- query_all is not changed
- query_all.current | length > 1
- query_all.current.0.fvBD is defined
- '"rsp-subtree-class=fvRsBdToEpRet,fvRsCtx,fvRsIgmpsn,fvRsBDToNdP" in query_all.filter_string'
- '"class/fvBD.json" in query_all.url'
- query_tenant is not changed
- query_tenant.current | length == 1
- query_tenant.current.0.fvTenant.children | length == 2
- '"rsp-subtree-class=fvRsBdToEpRet,fvBD,fvRsCtx,fvRsIgmpsn,fvRsBDToNdP" in query_tenant.filter_string'
- '"tn-anstest.json" in query_tenant.url'
- query_bd_bd is not changed
- query_bd_bd.current != []
- '"query-target-filter=eq(fvBD.name, \"anstest\")" in query_bd_bd.filter_string'
- '"rsp-subtree-class=fvRsBdToEpRet,fvRsCtx,fvRsIgmpsn,fvRsBDToNdP" in query_bd_bd.filter_string'
- '"class/fvBD.json" in query_bd_bd.url'
- query_bd is not changed
- query_bd.current | length == 1
- query_bd.current.0.fvBD.attributes.name == "anstest"
- '"rsp-subtree-class=fvRsBdToEpRet,fvRsCtx,fvRsIgmpsn,fvRsBDToNdP" in query_bd.filter_string'
- '"tn-anstest/BD-anstest.json" in query_bd.url'
- name: delete bd - check mode works
aci_bd: &aci_bd_absent
<<: *aci_bd_present
state: absent
check_mode: yes
register: bd_absent_check_mode
- name: delete bd - delete works
aci_bd:
<<: *aci_bd_absent
register: bd_absent
- name: delete bd again - idempotency works
aci_bd:
<<: *aci_bd_absent
register: bd_absent_idempotent
- name: delete bd - cleanup
aci_bd:
<<: *aci_bd_absent
name: anstest2
- name: delete bd missing param - fails properly
aci_bd:
<<: *aci_bd_absent
bd: "{{ fakevar | default(omit) }}"
ignore_errors: yes
register: bd_absent_missing_param
- name: asserts for deletion task
assert:
that:
- bd_absent_check_mode is changed
- bd_absent_check_mode.proposed == {}
- bd_absent is changed
- bd_absent.previous != []
- bd_absent_idempotent is not changed
- bd_absent_idempotent.previous == []
- bd_absent_missing_param is failed
- 'bd_absent_missing_param.msg == "state is absent but all of the following are missing: bd"'
- name: delete vrf - cleanup before ending tests
aci_vrf:
<<: *aci_vrf_present
state: absent
when: vrf_present is changed
- name: delete tenant - cleanup before ending tests
aci_tenant:
<<: *aci_tenant_present
state: absent
when: tenant_present is changed

@ -1,2 +0,0 @@
# No ACI simulator yet, so not enabled
unsupported

@ -1,237 +0,0 @@
# Test code for the ACI modules
# Copyright: (c) 2017, Jacob McGill (@jmcgill298)
# 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
- name: ensure tenant exists for tests to kick off
aci_tenant: &aci_tenant_present
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
state: present
tenant: anstest
register: tenant_present
- name: ensure bd exists for tests to kick off
aci_bd: &aci_bd_present
<<: *aci_tenant_present
bd: anstest
register: bd_present
- name: ensure subnet does not exist for tests to kick off
aci_bd_subnet: &aci_subnet_absent
<<: *aci_bd_present
state: absent
gateway: 10.100.100.1
mask: 24
- name: ensure subnet does not exist for tests to kick off
aci_bd_subnet: &aci_subnet2_absent
<<: *aci_subnet_absent
gateway: 10.100.101.1
mask: 25
- name: create subnet - check mode works
aci_bd_subnet: &aci_subnet_present
<<: *aci_subnet_absent
state: present
subnet_name: anstest
descr: Ansible Test
check_mode: yes
register: create_check_mode
- name: create subnet - creation works
aci_bd_subnet:
<<: *aci_subnet_present
register: create_subnet
- name: create new subnet - creation works
aci_bd_subnet: &aci_subnet2_present
<<: *aci_subnet2_absent
state: present
descr: Ansible Test
scope: [private, shared]
route_profile: default
route_profile_l3_out: default
register: create_subnet2
- name: create subnet again - idempotency works
aci_bd_subnet:
<<: *aci_subnet2_present
register: create_idempotency
- name: modify subnet - update works
aci_bd_subnet:
<<: *aci_subnet_present
scope: [shared, public]
subnet_control: querier_ip
register: modify_subnet
- name: create subnet with bad scope - failure message works
aci_bd_subnet:
<<: *aci_subnet_present
scope: [private, public]
register: create_bad_scope
ignore_errors: yes
- name: create subnet without all necessary params - failure message works
aci_bd_subnet:
<<: *aci_subnet_present
bd: "{{ fake_var | default(omit) }}"
register: create_incomplete_data
ignore_errors: yes
- name: asserts for subnet creation tasks
assert:
that:
- create_check_mode is changed
- 'create_check_mode.sent == {"fvSubnet": {"attributes": {"descr": "Ansible Test", "ip": "10.100.100.1/24", "name": "anstest"}}}'
- create_subnet is changed
- 'create_subnet.sent == {"fvSubnet": {"attributes": {"descr": "Ansible Test", "ip": "10.100.100.1/24", "name": "anstest"}}}'
- create_subnet.previous == []
- create_subnet2 is changed
- create_subnet2.sent == create_subnet2.proposed
- create_subnet2.sent.fvSubnet.attributes.scope == "private,shared"
- 'create_subnet2.sent.fvSubnet.children.0.fvRsBDSubnetToProfile.attributes == {"tnL3extOutName": "default", "tnRtctrlProfileName": "default"}'
- create_idempotency is not changed
- create_idempotency.previous != []
- modify_subnet is changed
- modify_subnet.previous != []
- modify_subnet.sent != modify_subnet.proposed
- 'modify_subnet.sent == {"fvSubnet": {"attributes": {"ctrl": "querier", "scope": "public,shared"}}}'
- create_bad_scope is failed
- create_bad_scope.msg.startswith("Parameter 'scope' cannot be both 'private' and 'public'")
- create_incomplete_data is failed
- 'create_incomplete_data.msg == "state is present but all of the following are missing: bd"'
- name: get all subnets
aci_bd_subnet: &aci_query
<<: *aci_tenant_present
state: query
tenant: "{{ fake_var | default(omit) }}"
register: get_all
- name: get all in tenant
aci_bd_subnet:
<<: *aci_query
tenant: anstest
register: get_all_tenant
- name: get all in bd
aci_bd_subnet:
<<: *aci_query
bd: anstest
register: get_all_bd
- name: get all tenant and bd
aci_bd_subnet:
<<: *aci_bd_present
state: query
register: get_all_tenant_bd
- name: get subnet in tenant
aci_bd_subnet:
<<: *aci_subnet_present
state: query
bd: "{{ fake_var | default(omit) }}"
register: get_subnet_tenant
- name: get subnet in bd
aci_bd_subnet:
<<: *aci_subnet_present
state: query
tenant: "{{ fake_var | default(omit) }}"
register: get_subnet_bd
- name: get specific subnet
aci_bd_subnet:
<<: *aci_subnet_present
state: query
register: get_subnet
- name: get all subnets matching gateway
aci_bd_subnet:
<<: *aci_subnet_present
state: query
tenant: "{{ fake_var | default(omit) }}"
bd: "{{ fake_var | default(omit) }}"
register: get_subnets_gateway
- name: asserts for query tasks
assert:
that:
- get_all is not changed
- get_all.current | length > 1
- get_all_tenant is not changed
- '"tn-anstest.json" in get_all_tenant.url'
- get_all_bd is not changed
- '"query-target-filter=eq(fvBD.name, \"anstest\")" in get_all_bd.filter_string'
- '"class/fvBD.json" in get_all_bd.url'
- get_all_tenant_bd is not changed
- '"tn-anstest/BD-anstest.json" in get_all_tenant_bd.url'
- get_all_tenant_bd.current.0.fvBD.children | length > 1
- get_subnet_tenant is not changed
- '"rsp-subtree-filter=eq(fvSubnet.ip, \"10.100.100.1/24\")" in get_subnet_tenant.filter_string'
- '"tn-anstest.json" in get_subnet_tenant.url'
- get_subnet_bd is not changed
- '"query-target-filter=eq(fvBD.name, \"anstest\")"'
- '"rsp-subtree-filter=eq(fvSubnet.ip, \"10.100.100.1/24\")" in get_subnet_bd.filter_string'
- '"class/fvBD.json" in get_subnet_bd.url'
- get_subnet is not changed
- get_subnet.current | length == 1
- '"tn-anstest/BD-anstest/subnet-[10.100.100.1/24].json" in get_subnet.url'
- get_subnets_gateway is not changed
- '"query-target-filter=eq(fvSubnet.ip, \"10.100.100.1/24\")" in get_subnets_gateway.filter_string'
- '"class/fvSubnet.json" in get_subnets_gateway.url'
- name: delete subnet - check mode works
aci_bd_subnet:
<<: *aci_subnet_absent
check_mode: yes
register: delete_check_mode
- name: delete subnet - delete works
aci_bd_subnet:
<<: *aci_subnet_absent
register: delete_subnet
- name: delete subnet - cleanup
aci_bd_subnet:
<<: *aci_subnet2_absent
- name: delete subnet again - idempotency works
aci_bd_subnet:
<<: *aci_subnet2_absent
register: delete_idempotency
- name: asserts for deletion task
assert:
that:
- delete_check_mode is changed
- delete_check_mode.proposed == {}
- delete_subnet is changed
- delete_subnet.previous != []
- delete_subnet.method == "DELETE"
- delete_idempotency is not changed
- delete_idempotency.previous == []
- name: delete bd - cleanup before ending tests
aci_bd:
<<: *aci_bd_present
state: absent
when: bd_present is changed
- name: delete tenant - cleanup before ending tests
aci_tenant:
<<: *aci_tenant_present
state: absent
when: tenant_present is changed

@ -1,2 +0,0 @@
# No ACI simulator yet, so not enabled
unsupported

@ -1,98 +0,0 @@
# Test code for the ACI modules
# Copyright: (c) 2017, Jacob McGill (@jmcgill298)
# 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
- name: ensure tenant does not exist for tests to kick off
aci_tenant: &aci_tenant_absent
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
state: absent
tenant: anstest
- name: create a snapshot
aci_config_snapshot: &create_snapshot
<<: *aci_tenant_absent
state: present
tenant: "{{ fakevar | default(omit) }}"
export_policy: anstest
- name: create a tenant - use for rollback
aci_tenant: &aci_tenant
<<: *create_snapshot
export_policy: "{{ fakevar | default(omit) }}"
tenant: anstest
register: tenant_present
- name: create a new snapshot
aci_config_snapshot:
<<: *create_snapshot
- name: get snapshots
aci_config_snapshot:
<<: *create_snapshot
state: query
register: snapshots
- name: compare snapshots
aci_config_rollback: &preview_rollback
<<: *create_snapshot
state: preview
compare_export_policy: anstest
compare_snapshot: "{{ snapshots.current.0.configSnapshotCont.children[-1].configSnapshot.attributes.name }}"
snapshot: "{{ snapshots.current.0.configSnapshotCont.children[-2].configSnapshot.attributes.name }}"
register: rollback_preview
- name: rollback to snapshot
aci_config_rollback: &aci_rollback
<<: *create_snapshot
state: rollback
snapshot: "{{ snapshots.current.0.configSnapshotCont.children[-1].configSnapshot.attributes.name }}"
ignore_errors: yes
register: rollback_missing_param
- name: rollback to snapshot
aci_config_rollback:
<<: *aci_rollback
import_policy: anstest
import_type: replace
import_mode: atomic
register: rollback_rollback
- name: pause execution to let rollback take effect
pause:
seconds: 15
- name: ensure tenant doesn't exist after rollback
aci_tenant:
<<: *aci_tenant_absent
register: tenant_removed
- name: rollback assertions
assert:
that:
- rollback_preview is not changed
# FIXME: diff output not longer works ?
# - '"<fvTenant name=\"anstest\" rn=\"tn-anstest\" status=\"deleted\">" in rollback_preview.diff'
- '"snapshots.diff.xml" in rollback_preview.url'
- rollback_missing_param is failed
- 'rollback_missing_param.msg == "state is rollback but all of the following are missing: import_policy"'
- rollback_rollback is changed
# FIXME: fileName key is missing from 'sent' dictionary, but exists in 'proposed' dictionary
# - '"ce2_" in rollback_rollback.sent.configImportP.attributes.fileName'
# - '".tar.gz" in rollback_rollback.sent.configImportP.attributes.fileName'
- '"ce2_" in rollback_rollback.proposed.configImportP.attributes.fileName'
- '".tar.gz" in rollback_rollback.proposed.configImportP.attributes.fileName'
- '"fabric/configimp-anstest.json" in rollback_rollback.url'
- tenant_removed is not changed
- tenant_removed.previous == []

@ -1,2 +0,0 @@
# No ACI simulator yet, so not enabled
unsupported

@ -1,142 +0,0 @@
# Test code for the ACI modules
# 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
- name: create a snapshot - creation works
aci_config_snapshot: &create_snapshot
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
export_policy: anstest
max_count: 10
include_secure: no
format: json
description: ansible test
register: create
- name: update snapshot to include secure and use xml - update works
aci_config_snapshot:
<<: *create_snapshot
include_secure: yes
format: xml
register: create_update
- name: create a snapshot invalid max_count - error message
aci_config_snapshot:
<<: *create_snapshot
max_count: 11
ignore_errors: yes
register: invalid_max_count
- name: create a snapshot invalid max_count - error message
aci_config_snapshot:
<<: *create_snapshot
export_policy: "{{ fake_var | default(omit) }}"
ignore_errors: yes
register: missing_param
- name: present assertion tests
assert:
that:
- create is not failed
- create is changed
- create.sent.configExportP.attributes.adminSt == "triggered"
- create_update is not failed
- create_update is changed
- 'create_update.sent == {"configExportP": {"attributes": {"adminSt": "triggered", "format": "xml", "includeSecureFields": "yes"}}}'
- invalid_max_count is failed
- invalid_max_count.msg == "Parameter 'max_count' must be a number between 1 and 10"
- missing_param is failed
- 'missing_param.msg == "state is present but all of the following are missing: export_policy"'
- name: query with export_policy
aci_config_snapshot: &query_snapshot
<<: *create_snapshot
state: query
register: query_export
- name: generate snapshot name
set_fact:
test_snapshot: "{{ query_export.current.0.configSnapshotCont.children.0.configSnapshot.attributes.rn.strip('snapshot-') }}"
- name: query with export_policy and snapshot
aci_config_snapshot: &query_both
<<: *query_snapshot
snapshot: "{{ test_snapshot }}"
register: query_export_snapshot
- name: query with snapshot - module add run- to snapshot
aci_config_snapshot:
<<: *query_snapshot
export_policy: "{{ fake_var | default(omit) }}"
snapshot: "{{ test_snapshot.strip('run-') }}"
register: query_snapshot
- name: query no params
aci_config_snapshot:
<<: *query_snapshot
export_policy: "{{ fake_var | default(omit) }}"
register: query_all
- name: query assertion tests
assert:
that:
- query_export is not failed
- query_export is not changed
- '"snapshots-[uni/fabric/configexp-anstest].json" in query_export.url'
- query_export.current.0.configSnapshotCont.attributes.name == "anstest"
- query_export.current.0.configSnapshotCont.children | length > 1
- query_export_snapshot is not failed
- query_export_snapshot is not changed
- '"snapshots-[uni/fabric/configexp-anstest]/snapshot-{{ test_snapshot }}.json" in query_export_snapshot.url'
- query_export_snapshot.current | length == 1
- query_snapshot is not failed
- query_snapshot is not changed
- '"class/configSnapshot.json" in query_snapshot.url'
- '"configSnapshot.name, \"{{ test_snapshot }}\"" in query_snapshot.filter_string'
- query_all is not failed
- query_all is not changed
- '"class/configSnapshot.json" in query_all.url'
- query_all.current | length > 1
- name: delete works
aci_config_snapshot: &delete
<<: *query_both
state: absent
register: delete_snapshot
- name: delete works - idempotency
aci_config_snapshot:
<<: *delete
register: delete_idempotent
- name: delete missing param
aci_config_snapshot:
<<: *delete
snapshot: "{{ fake_var | default(omit) }}"
ignore_errors: yes
register: delete_missing_param
- name: absent assertion tests
assert:
that:
- delete_snapshot is not failed
- delete_snapshot is changed
- 'delete_snapshot.sent == {"configSnapshot": {"attributes": {"retire": "yes"}}}'
- delete_snapshot.previous != []
- delete_snapshot.previous.0.configSnapshot.attributes.name == test_snapshot
- delete_idempotent is not failed
- delete_idempotent is not changed
- delete_idempotent.previous == []
- delete_missing_param is failed
- 'delete_missing_param.msg == "state is absent but all of the following are missing: snapshot"'

@ -1,2 +0,0 @@
# No ACI simulator yet, so not enabled
unsupported

@ -1,163 +0,0 @@
# Test code for the ACI modules
# Copyright: (c) 2017, Jacob McGill (@jmcgill298)
# 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
- name: ensure tenant exists for tests to kick off
aci_tenant: &aci_tenant_present
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
tenant: anstest
state: present
register: tenant_present
- name: create contract - check mode works
aci_contract: &aci_contract_present
<<: *aci_tenant_present
contract: anstest
description: Ansible Test
check_mode: yes
register: present_check_mode
- name: create contract - creation works
aci_contract:
<<: *aci_contract_present
register: contract_present
- name: create contract - idempotency works
aci_contract:
<<: *aci_contract_present
register: present_idempotent
- name: update contract - update works
aci_contract:
<<: *aci_contract_present
scope: application-profile
register: present_update
- name: create contract - used for query
aci_contract:
<<: *aci_contract_present
contract: anstest2
- name: missing param - failure message works
aci_contract:
<<: *aci_tenant_present
ignore_errors: yes
register: present_missing_param
- name: present assertions
assert:
that:
- present_check_mode is changed
- present_check_mode.previous == []
- 'present_check_mode.sent == {"vzBrCP": {"attributes": {"name": "anstest", "descr": "Ansible Test"}}}'
- contract_present is changed
- contract_present.sent == present_check_mode.sent
- present_idempotent is not changed
- present_update is changed
- present_update.sent != present_update.proposed
- present_update.sent.vzBrCP.attributes.scope == "application-profile"
- present_missing_param is failed
- 'present_missing_param.msg == "state is present but all of the following are missing: contract"'
- name: query contract
aci_contract: &aci_contract_query
<<: *aci_contract_present
state: query
register: query_contract
- name: query all in tenant
aci_contract:
<<: *aci_contract_query
contract: "{{ fakevar | default(omit) }}"
register: query_tenant
- name: query all with name
aci_contract:
<<: *aci_contract_query
tenant: "{{ fakevar | default(omit) }}"
register: query_name
- name: query all
aci_contract:
<<: *aci_contract_query
tenant: "{{ fakevar | default(omit) }}"
contract: "{{ fakevar | default(omit) }}"
register: query_all
- name: query assertions
assert:
that:
- query_contract is not changed
- query_contract.current | length == 1
- '"tn-anstest/brc-anstest.json" in query_contract.url'
- query_tenant is not changed
- query_tenant.current | length == 1
- query_tenant.current.0.fvTenant.children | length > 1
- '"rsp-subtree-class=vzBrCP" in query_tenant.filter_string'
- '"tn-anstest.json" in query_tenant.url'
- query_name is not changed
- query_name.current != []
- '"query-target-filter=eq(vzBrCP.name, \"anstest\")" in query_name.filter_string'
- '"class/vzBrCP.json" in query_name.url'
- query_all is not changed
- query_all.current | length > 1
- '"class/vzBrCP.json" in query_all.url'
- name: delete contract - check mode works
aci_contract: &aci_contract_absent
<<: *aci_contract_present
state: absent
check_mode: yes
register: absent_check_mode
- name: delete contract - deletion works
aci_contract:
<<: *aci_contract_absent
register: contract_absent
- name: delete contract - idempotency works
aci_contract:
<<: *aci_contract_absent
register: absent_idempotent
- name: delete contract - cleanup second contract
aci_contract:
<<: *aci_contract_absent
contract: anstest2
- name: missing param - fail message works
aci_contract:
<<: *aci_contract_absent
tenant: "{{ fakevar | default(omit) }}"
ignore_errors: yes
register: absent_missing_param
- name: absent assertions
assert:
that:
- absent_check_mode is changed
- absent_check_mode.previous != []
- contract_absent is changed
- contract_absent.previous == absent_check_mode.previous
- absent_idempotent is not changed
- absent_idempotent.previous == []
- absent_missing_param is failed
- 'absent_missing_param.msg == "state is absent but all of the following are missing: tenant"'
- name: cleanup tenant
aci_tenant:
<<: *aci_tenant_present
state: absent
when: tenant_present is changed

@ -1,2 +0,0 @@
# No ACI simulator yet, so not enabled
unsupported

@ -1,241 +0,0 @@
# Test code for the ACI modules
# Copyright: (c) 2017, Jacob McGill (@jmcgill298)
# 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
- name: ensure tenant exists for tests to kick off
aci_tenant: &aci_tenant_present
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
state: present
tenant: anstest
register: tenant_present
- name: ensure contract exists for tests to kick off
aci_contract: &aci_contract_present
<<: *aci_tenant_present
contract: anstest
register: contract_present
- name: create subject - check mode works
aci_contract_subject: &aci_subject_present
<<: *aci_contract_present
subject: anstest
description: Ansible Test
check_mode: yes
register: subject_present_check_mode
- name: create subject - creation works
aci_contract_subject:
<<: *aci_subject_present
register: subject_present
- name: create subject - idempotency works
aci_contract_subject:
<<: *aci_subject_present
register: subject_present_idempotent
- name: update subject - update works
aci_contract_subject:
<<: *aci_subject_present
description: Ansible Test
reverse_filter: "yes"
provider_match: at_most_one
priority: level2
register: subject_update
- name: create subject - try additional params
aci_contract_subject: &aci_subject_present_2
<<: *aci_contract_present
subject: anstest2
reverse_filter: "no"
consumer_match: all
priority: level3
register: subject_present_2
- name: missing param - failure message works
aci_contract_subject:
<<: *aci_tenant_present
ignore_errors: yes
register: present_missing_param
- name: present assertions
assert:
that:
- subject_present_check_mode is changed
- 'subject_present_check_mode.sent == {"vzSubj": {"attributes": {"descr": "Ansible Test", "name": "anstest"}}}'
- subject_present is changed
- subject_present.previous == []
- subject_present.sent == subject_present_check_mode.sent
- subject_present_idempotent is not changed
- subject_present_idempotent.previous != []
- subject_update is changed
- subject_update.sent != subject_update.proposed
- 'subject_update.sent.vzSubj.attributes == {"prio": "level2", "provMatchT": "AtmostOne"}'
- subject_present_2 is changed
- 'subject_present_2.sent.vzSubj.attributes == {"consMatchT": "All", "name": "anstest2", "prio": "level3", "revFltPorts": "no"}'
- present_missing_param is failed
- 'present_missing_param.msg == "state is present but all of the following are missing: contract, subject"'
- name: query tenant contract subject
aci_contract_subject: &aci_query_subject
<<: *aci_subject_present
state: query
register: query_tenant_contract_subject
- name: query tenant contract
aci_contract_subject:
<<: *aci_query_subject
subject: "{{ fakevar | default(omit) }}"
register: query_tenant_contract
- name: query tenant subject
aci_contract_subject:
<<: *aci_query_subject
contract: "{{ fakevar | default(omit) }}"
register: query_tenant_subject
- name: query contract subject
aci_contract_subject:
<<: *aci_query_subject
tenant: "{{ fakevar | default(omit) }}"
register: query_contract_subject
- name: query tenant
aci_contract_subject:
<<: *aci_tenant_present
state: query
register: query_tenant
- name: query contract
aci_contract_subject:
<<: *aci_contract_present
state: query
tenant: "{{ fakevar | default(omit) }}"
register: query_contract
- name: query subject
aci_contract_subject:
<<: *aci_query_subject
tenant: "{{ fakevar | default(omit) }}"
contract: "{{ fakevar | default(omit) }}"
register: query_subject
- name: query all
aci_contract_subject:
<<: *aci_tenant_present
state: query
tenant: "{{ fakevar | default(omit) }}"
register: query_all
- name: query assertions
assert:
that:
- query_tenant_contract_subject is not changed
- query_tenant_contract_subject.current | length == 1
- query_tenant_contract_subject.current.0.vzSubj.attributes.name == "anstest"
- '"tn-anstest/brc-anstest/subj-anstest.json" in query_tenant_contract_subject.url'
- query_tenant_contract is not changed
- query_tenant_contract.current | length == 1
- query_tenant_contract.current.0.vzBrCP.attributes.name == "anstest"
- query_tenant_contract.current.0.vzBrCP.children | length == 2
- '"rsp-subtree-class=vzSubj" in query_tenant_contract.filter_string'
- '"tn-anstest/brc-anstest.json" in query_tenant_contract.url'
- query_tenant_subject is not changed
- query_tenant_subject.current | length == 1
- query_tenant_subject.current.0.fvTenant.attributes.name == "anstest"
- query_tenant_subject.current.0.fvTenant.children.0.vzBrCP.children | length == 1
- query_tenant_subject.current.0.fvTenant.children.0.vzBrCP.children.0.vzSubj.attributes.name == "anstest"
- '"rsp-subtree-filter=eq(vzSubj.name, \"anstest\")" in query_tenant_subject.filter_string'
- '"rsp-subtree-class=vzSubj" in query_tenant_subject.filter_string'
- '"tn-anstest.json" in query_tenant_subject.url'
- query_contract_subject is not changed
- query_contract_subject.current.0.vzBrCP.attributes.name == "anstest"
- query_contract_subject.current.0.vzBrCP.children | length == 1
- query_contract_subject.current.0.vzBrCP.children.0.vzSubj.attributes.name == "anstest"
- '"query-target-filter=eq(vzBrCP.name, \"anstest\")" in query_contract_subject.filter_string'
- '"rsp-subtree-filter=eq(vzSubj.name, \"anstest\")" in query_contract_subject.filter_string'
- '"rsp-subtree-class=vzSubj" in query_contract_subject.filter_string'
- '"class/vzBrCP.json" in query_contract_subject.url'
- query_tenant is not changed
- query_tenant.current | length == 1
- query_tenant.current.0.fvTenant.attributes.name == "anstest"
- '"rsp-subtree-class=vzBrCP,vzSubj" in query_tenant.filter_string'
- '"tn-anstest.json" in query_tenant.url'
- query_contract is not changed
- query_contract.current.0.vzBrCP.attributes.name == "anstest"
- '"query-target-filter=eq(vzBrCP.name, \"anstest\")" in query_contract.filter_string'
- '"rsp-subtree-class=vzSubj" in query_contract.filter_string'
- '"class/vzBrCP.json" in query_contract.url'
- query_subject is not changed
- query_subject.current.0.vzSubj.attributes.name == "anstest"
- '"query-target-filter=eq(vzSubj.name, \"anstest\")" in query_subject.filter_string'
- '"class/vzSubj.json" in query_subject.url'
- query_all is not changed
- query_all.current > 1
- query_all.current.0.vzSubj is defined
- '"class/vzSubj.json" in query_all.url'
- name: delete subject - check mode works
aci_contract_subject: &aci_subject_absent
<<: *aci_subject_present
state: absent
check_mode: yes
register: subject_absent_check_mode
- name: delete subject - deletion works
aci_contract_subject:
<<: *aci_subject_absent
register: subject_absent
- name: delete subject - idempotency works
aci_contract_subject:
<<: *aci_subject_absent
register: subject_absent_idempotent
- name: delete subject - cleanup
aci_contract_subject:
<<: *aci_subject_present_2
state: absent
- name: missing params - failure message works
aci_contract_subject:
<<: *aci_subject_absent
subject: "{{ fakevar | default(omit) }}"
ignore_errors: yes
register: absent_missing_param
- name: absent assertions
assert:
that:
- subject_absent_check_mode is changed
- subject_absent_check_mode.previous != []
- subject_absent_check_mode.proposed == {}
- subject_absent is changed
- subject_absent.previous == subject_absent_check_mode.previous
- subject_absent_idempotent is not changed
- subject_absent_idempotent.previous == []
- absent_missing_param is failed
- 'absent_missing_param.msg == "state is absent but all of the following are missing: subject"'
- name: cleanup contract
aci_contract:
<<: *aci_contract_present
state: absent
when: contract_present is changed
- name: cleanup tenant
aci_tenant:
<<: *aci_tenant_present
state: absent
when: tenant_present is changed

@ -1,2 +0,0 @@
# No ACI simulator yet, so not enabled
unsupported

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save