mirror of https://github.com/ansible/ansible.git
Migrated to cisco.aci
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…
Reference in New Issue