From df78df5d9056552dd6e8628e76f291479afaab57 Mon Sep 17 00:00:00 2001 From: Dag Wieers Date: Thu, 22 Feb 2018 00:36:47 +0100 Subject: [PATCH] Apply all devel ACI changes missing from stable-2.5 (#36553) --- lib/ansible/module_utils/network/aci/aci.py | 60 ++-- .../modules/network/aci/aci_aaa_user.py | 16 +- .../network/aci/aci_aaa_user_certificate.py | 17 +- ...s_port_to_interface_policy_leaf_profile.py | 18 +- lib/ansible/modules/network/aci/aci_aep.py | 14 +- .../modules/network/aci/aci_aep_to_domain.py | 56 +++- lib/ansible/modules/network/aci/aci_ap.py | 16 +- lib/ansible/modules/network/aci/aci_bd.py | 13 +- .../modules/network/aci/aci_bd_subnet.py | 21 +- .../modules/network/aci/aci_bd_to_l3out.py | 15 +- .../network/aci/aci_config_rollback.py | 14 +- .../network/aci/aci_config_snapshot.py | 11 +- .../modules/network/aci/aci_contract.py | 63 ++-- .../network/aci/aci_contract_subject.py | 15 +- .../aci/aci_contract_subject_to_filter.py | 69 ++-- lib/ansible/modules/network/aci/aci_domain.py | 20 +- .../network/aci/aci_domain_to_encap_pool.py | 310 ------------------ .../network/aci/aci_domain_to_vlan_pool.py | 25 +- .../modules/network/aci/aci_encap_pool.py | 3 +- .../network/aci/aci_encap_pool_range.py | 17 +- lib/ansible/modules/network/aci/aci_epg.py | 15 +- .../network/aci/aci_epg_monitoring_policy.py | 11 +- .../network/aci/aci_epg_to_contract.py | 63 +++- .../modules/network/aci/aci_epg_to_domain.py | 68 +++- .../modules/network/aci/aci_fabric_node.py | 134 +++++++- lib/ansible/modules/network/aci/aci_filter.py | 11 +- .../modules/network/aci/aci_filter_entry.py | 15 +- .../network/aci/aci_firmware_source.py | 40 ++- .../network/aci/aci_interface_policy_fc.py | 8 +- .../network/aci/aci_interface_policy_l2.py | 8 +- .../aci_interface_policy_leaf_policy_group.py | 210 ++++++------ .../aci/aci_interface_policy_leaf_profile.py | 4 +- .../network/aci/aci_interface_policy_lldp.py | 10 +- .../network/aci/aci_interface_policy_mcp.py | 4 +- .../aci/aci_interface_policy_port_channel.py | 4 +- .../aci/aci_interface_policy_port_security.py | 4 +- ..._selector_to_switch_policy_leaf_profile.py | 27 +- .../network/aci/aci_l3out_route_tag_policy.py | 9 +- lib/ansible/modules/network/aci/aci_rest.py | 81 +++-- .../network/aci/aci_static_binding_to_epg.py | 185 ++++++++--- .../network/aci/aci_switch_leaf_selector.py | 39 +-- .../aci/aci_switch_policy_leaf_profile.py | 26 +- .../aci_switch_policy_vpc_protection_group.py | 143 ++++++-- .../modules/network/aci/aci_taboo_contract.py | 33 +- lib/ansible/modules/network/aci/aci_tenant.py | 6 +- .../aci/aci_tenant_action_rule_profile.py | 16 +- .../aci/aci_tenant_ep_retention_policy.py | 11 +- .../network/aci/aci_tenant_span_dst_group.py | 15 +- .../network/aci/aci_tenant_span_src_group.py | 25 +- .../aci_tenant_span_src_group_to_dst_group.py | 29 +- .../modules/network/aci/aci_vlan_pool.py | 8 +- .../network/aci/aci_vlan_pool_encap_block.py | 17 +- lib/ansible/modules/network/aci/aci_vrf.py | 10 +- .../tasks/main.yml | 2 +- .../targets/aci_aep_to_domain/tasks/main.yml | 30 +- .../integration/targets/aci_ap/tasks/main.yml | 2 +- .../integration/targets/aci_bd/tasks/main.yml | 2 +- .../targets/aci_bd_subnet/tasks/main.yml | 2 +- .../aci_config_rollback/tasks/main.yml | 2 +- .../aci_config_snapshot/tasks/main.yml | 2 +- .../targets/aci_contract/tasks/main.yml | 2 +- .../aci_contract_subject/tasks/main.yml | 2 +- .../tasks/main.yml | 2 +- .../targets/aci_domain/tasks/fc.yml | 42 ++- .../targets/aci_domain/tasks/l2dom.yml | 42 ++- .../targets/aci_domain/tasks/l3dom.yml | 42 ++- .../targets/aci_domain/tasks/main.yml | 2 +- .../targets/aci_domain/tasks/phys.yml | 42 ++- .../targets/aci_domain/tasks/vmm-vmware.yml | 50 ++- .../targets/aci_domain_to_encap_pool/aliases | 0 .../aci_domain_to_encap_pool/tasks/main.yml | 18 - .../aci_domain_to_encap_pool/tasks/vlan.yml | 215 ------------ .../aci_domain_to_encap_pool/tasks/vsan.yml | 215 ------------ .../aci_domain_to_encap_pool/tasks/vxlan.yml | 215 ------------ .../aci_domain_to_vlan_pool/tasks/main.yml | 49 ++- .../targets/aci_encap_pool/tasks/main.yml | 2 +- .../targets/aci_encap_pool/tasks/vxlan.yml | 14 +- .../aci_encap_pool_range/tasks/main.yml | 2 +- .../targets/aci_epg/tasks/main.yml | 2 +- .../aci_epg_to_contract/tasks/main.yml | 4 +- .../targets/aci_epg_to_domain/tasks/main.yml | 2 +- .../targets/aci_filter/tasks/main.yml | 2 +- .../targets/aci_filter_entry/tasks/main.yml | 2 +- .../tasks/main.yml | 8 +- .../tasks/main.yml | 2 +- .../tasks/main.yml | 2 +- .../targets/aci_rest/tasks/json_inline.yml | 7 +- .../targets/aci_rest/tasks/json_string.yml | 6 +- .../targets/aci_rest/tasks/main.yml | 10 +- .../targets/aci_rest/tasks/xml_string.yml | 6 +- .../targets/aci_rest/tasks/yaml_inline.yml | 6 +- .../targets/aci_rest/tasks/yaml_string.yml | 6 +- .../tasks/main.yml | 2 +- .../aci_switch_leaf_selector/tasks/main.yml | 2 +- .../targets/aci_taboo_contract/tasks/main.yml | 2 +- .../targets/aci_tenant/tasks/main.yml | 2 +- .../targets/aci_vlan_pool/tasks/dynamic.yml | 2 +- .../targets/aci_vlan_pool/tasks/static.yml | 2 +- .../targets/aci_vrf/tasks/main.yml | 2 +- 99 files changed, 1328 insertions(+), 1831 deletions(-) delete mode 100644 lib/ansible/modules/network/aci/aci_domain_to_encap_pool.py delete mode 100644 test/integration/targets/aci_domain_to_encap_pool/aliases delete mode 100644 test/integration/targets/aci_domain_to_encap_pool/tasks/main.yml delete mode 100644 test/integration/targets/aci_domain_to_encap_pool/tasks/vlan.yml delete mode 100644 test/integration/targets/aci_domain_to_encap_pool/tasks/vsan.yml delete mode 100644 test/integration/targets/aci_domain_to_encap_pool/tasks/vxlan.yml diff --git a/lib/ansible/module_utils/network/aci/aci.py b/lib/ansible/module_utils/network/aci/aci.py index ef7211c2278..4aa3d8173a2 100644 --- a/lib/ansible/module_utils/network/aci/aci.py +++ b/lib/ansible/module_utils/network/aci/aci.py @@ -300,7 +300,6 @@ class ACIModule(object): except Exception as e: # Expose RAW output for troubleshooting self.error = dict(code=-1, text="Unable to parse output as JSON, see 'raw' output. %s" % e) - # self.error = dict(code=str(self.status), text="Request failed: %s (see 'raw' output)" % self.response) self.result['raw'] = rawoutput return @@ -324,7 +323,6 @@ class ACIModule(object): except Exception as e: # Expose RAW output for troubleshooting self.error = dict(code=-1, text="Unable to parse output as XML, see 'raw' output. %s" % e) - # self.error = dict(code=str(self.status), text="Request failed: %s (see 'raw' output)" % self.response) self.result['raw'] = rawoutput return @@ -750,7 +748,8 @@ class ACIModule(object): """ update_config = {child_class: {'attributes': {}}} for key, value in proposed_child.items(): - if value != existing_child[key]: + existing_field = existing_child.get(key) + if value != existing_field: update_config[child_class]['attributes'][key] = value if not update_config[child_class]['attributes']: @@ -928,36 +927,40 @@ class ACIModule(object): self.result['changed'] = True self.method = 'POST' - def exit_json(self): + def exit_json(self, **kwargs): - if self.params['state'] in ('absent', 'present'): - if self.params['output_level'] in ('debug', 'info'): - self.result['previous'] = self.existing + if 'state' in self.params: + if self.params['state'] in ('absent', 'present'): + if self.params['output_level'] in ('debug', 'info'): + self.result['previous'] = self.existing # Return the gory details when we need it if self.params['output_level'] == 'debug': - self.result['filter_string'] = self.filter_string + if 'state' in self.params: + self.result['filter_string'] = self.filter_string self.result['method'] = self.method # self.result['path'] = self.path # Adding 'path' in result causes state: absent in output self.result['response'] = self.response self.result['status'] = self.status self.result['url'] = self.url - self.original = self.existing - if self.params['state'] in ('absent', 'present'): - self.get_existing() + if 'state' in self.params: + self.original = self.existing + if self.params['state'] in ('absent', 'present'): + self.get_existing() # if self.module._diff and self.original != self.existing: # self.result['diff'] = dict( # before=json.dumps(self.original, sort_keys=True, indent=4), # after=json.dumps(self.existing, sort_keys=True, indent=4), # ) - self.result['current'] = self.existing + self.result['current'] = self.existing - if self.params['output_level'] in ('debug', 'info'): - self.result['sent'] = self.config - self.result['proposed'] = self.proposed + if self.params['output_level'] in ('debug', 'info'): + self.result['sent'] = self.config + self.result['proposed'] = self.proposed + self.result.update(**kwargs) self.module.exit_json(**self.result) def fail_json(self, msg, **kwargs): @@ -966,22 +969,31 @@ class ACIModule(object): if self.error['code'] is not None and self.error['text'] is not None: self.result['error'] = self.error - if self.params['state'] in ('absent', 'present'): - if self.params['output_level'] in ('debug', 'info'): - self.result['previous'] = self.existing - # Return the gory details when we need it - if self.params['output_level'] == 'debug': - if self.imdata is not None: - self.result['imdata'] = self.imdata - self.result['totalCount'] = self.totalCount + if 'state' in self.params: + if self.params['state'] in ('absent', 'present'): + if self.params['output_level'] in ('debug', 'info'): + self.result['previous'] = self.existing + + # Return the gory details when we need it + if self.params['output_level'] == 'debug': + if self.imdata is not None: + self.result['imdata'] = self.imdata + self.result['totalCount'] = self.totalCount + if self.params['output_level'] == 'debug': if self.url is not None: - self.result['filter_string'] = self.filter_string + if 'state' in self.params: + self.result['filter_string'] = self.filter_string self.result['method'] = self.method # self.result['path'] = self.path # Adding 'path' in result causes state: absent in output self.result['response'] = self.response self.result['status'] = self.status self.result['url'] = self.url + if 'state' in self.params: + if self.params['output_level'] in ('debug', 'info'): + self.result['sent'] = self.config + self.result['proposed'] = self.proposed + self.result.update(**kwargs) self.module.fail_json(msg=msg, **self.result) diff --git a/lib/ansible/modules/network/aci/aci_aaa_user.py b/lib/ansible/modules/network/aci/aci_aaa_user.py index 3061cbefa16..adde79c6911 100644 --- a/lib/ansible/modules/network/aci/aci_aaa_user.py +++ b/lib/ansible/modules/network/aci/aci_aaa_user.py @@ -17,15 +17,16 @@ module: aci_aaa_user short_description: Manage AAA users (aaa:User) description: - Manage AAA users. -- More information from the internal APIC class I(aaa:User) at - U(https://developer.cisco.com/docs/apic-mim-ref/). -author: -- Dag Wieers (@dagwieers) 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. + of the APIC REST API. The vendor has been informed. + More information in :ref:`the ACI documentation `. +- More information from the internal APIC class I(aaa:User) at + U(https://developer.cisco.com/docs/apic-mim-ref/). +author: +- Dag Wieers (@dagwieers) requirements: - python-dateutil version_added: '2.5' @@ -246,7 +247,7 @@ def main(): 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', required=True, aliases=['name']), + aaa_user=dict(type='str', required=True, aliases=['name']), # Not required for querying all objects clear_password_history=dict(type='bool'), description=dict(type='str', aliases=['descr']), email=dict(type='str'), @@ -306,7 +307,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module params with null values aci.payload( aci_class='aaaUser', class_config=dict( @@ -325,10 +325,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='aaaUser') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_aaa_user_certificate.py b/lib/ansible/modules/network/aci/aci_aaa_user_certificate.py index bc0f822ca21..f82fcf2a4a1 100644 --- a/lib/ansible/modules/network/aci/aci_aaa_user_certificate.py +++ b/lib/ansible/modules/network/aci/aci_aaa_user_certificate.py @@ -16,15 +16,15 @@ DOCUMENTATION = r''' module: aci_aaa_user_certificate short_description: Manage AAA user certificates (aaa:UserCert) description: -- Manage AAA user and appuser certificates. +- Manage AAA user certificates. +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. - More information from the internal APIC class I(aaa:UserCert) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Dag Wieers (@dagwieers) version_added: '2.5' -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. options: aaa_user: description: @@ -212,10 +212,10 @@ ACI_MAPPING = dict( def main(): argument_spec = aci_argument_spec() argument_spec.update( - aaa_user=dict(type='str', required=True), + aaa_user=dict(type='str', required=True), # Not required for querying all objects 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']), + certificate=dict(type='str', aliases=['cert_data', 'certificate_data']), # Not required for querying all objects + certificate_name=dict(type='str', aliases=['cert_name']), # Not required for querying all objects state=dict(type='str', default='present', choices=['absent', 'present', 'query']), ) @@ -252,7 +252,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module params with null values aci.payload( aci_class='aaaUserCert', class_config=dict( @@ -261,10 +260,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='aaaUserCert') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_access_port_to_interface_policy_leaf_profile.py b/lib/ansible/modules/network/aci/aci_access_port_to_interface_policy_leaf_profile.py index df5dc461dd2..834b576a09d 100644 --- a/lib/ansible/modules/network/aci/aci_access_port_to_interface_policy_leaf_profile.py +++ b/lib/ansible/modules/network/aci/aci_access_port_to_interface_policy_leaf_profile.py @@ -17,6 +17,7 @@ module: aci_access_port_to_interface_policy_leaf_profile short_description: Manage Fabric interface policy leaf profile interface selectors on Cisco ACI fabrics (infra:HPortS, infra:RsAccBaseGrp, infra:PortBlk) description: - Manage Fabric interface policy leaf profile interface selectors on Cisco ACI fabrics. +notes: - More information from the internal APIC class I(infra:HPortS, infra:RsAccBaseGrp, infra:PortBlk) at U(https://developer.cisco.com/media/mim-ref). author: @@ -36,7 +37,6 @@ options: description: description: - The description to assign to the C(access_port_selector) - required: no leaf_port_blk: description: - The name of the Fabric access policy leaf interface profile access port block. @@ -59,7 +59,6 @@ options: policy_group: description: - The name of the fabric access policy group to be associated with the leaf interface profile interface selector. - required: no aliases: [ policy_group_name ] state: description: @@ -227,8 +226,8 @@ 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']), - 'access_port_selector': dict(type='str', aliases=['name', 'access_port_selector_name']), + '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(typ='str'), 'leaf_port_blk': dict(type='str', aliases=['leaf_port_blk_name']), 'leaf_port_blk_description': dict(type='str'), @@ -277,7 +276,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='infraHPortS', class_config=dict( @@ -292,23 +290,21 @@ def main(): name=leaf_port_blk, fromPort=from_, toPort=to_, - ) - ) + ), + ), ), dict( infraRsAccBaseGrp=dict( attributes=dict( tDn='uni/infra/funcprof/accportgrp-{0}'.format(policy_group), - ) - ) + ), + ), ), ], ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='infraHPortS') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_aep.py b/lib/ansible/modules/network/aci/aci_aep.py index f251fc5fe6a..399886fe9d6 100644 --- a/lib/ansible/modules/network/aci/aci_aep.py +++ b/lib/ansible/modules/network/aci/aci_aep.py @@ -17,13 +17,12 @@ short_description: Manage attachable Access Entity Profile (AEP) on Cisco ACI fa description: - Connect to external virtual and physical domains by using attachable Access Entity Profiles (AEP) on Cisco ACI fabrics. +notes: - More information from the internal APIC classes I(infra:AttEntityP) and I(infra:ProvAcc) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Swetha Chunduri (@schunduri) version_added: '2.4' -requirements: -- ACI Fabric 1.0(3f)+ options: aep: description: @@ -70,19 +69,19 @@ EXAMPLES = r''' aep: ACI-AEP state: absent -- name: Query an AEP +- name: Query all AEPs aci_aep: host: apic username: admin password: SomeSecretPassword - aep: ACI-AEP state: query -- name: Query all AEPs +- name: Query a specific AEP aci_aep: host: apic username: admin password: SomeSecretPassword + aep: ACI-AEP state: query ''' @@ -198,7 +197,7 @@ from ansible.module_utils.basic import AnsibleModule def main(): argument_spec = aci_argument_spec() argument_spec.update( - aep=dict(type='str', aliases=['name', 'aep_name']), # not required for querying all AEPs + 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']), @@ -237,7 +236,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='infraAttEntityP', class_config=dict( @@ -247,10 +245,8 @@ def main(): child_configs=child_configs, ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='infraAttEntityP') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_aep_to_domain.py b/lib/ansible/modules/network/aci/aci_aep_to_domain.py index 3b1c269bdfd..c4785a31ce8 100755 --- a/lib/ansible/modules/network/aci/aci_aep_to_domain.py +++ b/lib/ansible/modules/network/aci/aci_aep_to_domain.py @@ -17,14 +17,14 @@ module: aci_aep_to_domain short_description: Bind AEPs to Physical or Virtual Domains on Cisco ACI fabrics (infra:RsDomP) description: - Bind AEPs to Physical or Virtual Domains on Cisco ACI fabrics. +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. - More information from the internal APIC class I(infra:RsDomP) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Dag Wieers (@dagwieers) version_added: '2.5' -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. options: aep: description: @@ -54,7 +54,44 @@ options: extends_documentation_fragment: aci ''' -EXAMPLES = r''' # ''' +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 + +- 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 + +- 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 + +- name: Query all AEP to domain bindings + aci_aep_to_domain: &binding_query + host: apic + username: admin + password: SomeSecretPassword + state: query +''' RETURN = r''' current: @@ -178,9 +215,9 @@ VM_PROVIDER_MAPPING = dict( def main(): argument_spec = aci_argument_spec() argument_spec.update( - aep=dict(type='str', aliases=['aep_name']), - domain=dict(type='str', aliases=['domain_name', 'domain_profile']), - domain_type=dict(type='str', choices=['fc', 'l2dom', 'l3dom', 'phys', 'vmm'], aliases=['type']), + 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']), ) @@ -194,7 +231,7 @@ def main(): ['state', 'present', ['aep', 'domain', 'domain_type']], ], required_together=[ - ['domain', 'domain_type'] + ['domain', 'domain_type'], ], ) @@ -241,16 +278,13 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module params with null values aci.payload( aci_class='infraRsDomP', class_config=dict(tDn=domain_mo), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='infraRsDomP') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_ap.py b/lib/ansible/modules/network/aci/aci_ap.py index 1b5488bb715..e2a4b2c6547 100644 --- a/lib/ansible/modules/network/aci/aci_ap.py +++ b/lib/ansible/modules/network/aci/aci_ap.py @@ -16,15 +16,15 @@ module: aci_ap short_description: Manage top level Application Profile (AP) objects on Cisco ACI fabrics (fv:Ap) description: - Manage top level Application Profile (AP) objects on Cisco ACI fabrics +notes: +- This module does not manage EPGs, see M(aci_epg) to do this. +- The C(tenant) used must exist before using this module in your playbook. + The M(aci_tenant) module can be used for this. - More information from the internal APIC class I(fv:Ap) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Swetha Chunduri (@schunduri) version_added: '2.4' -notes: -- This module does not manage EPGs, see M(aci_epg) to do this. -- The C(tenant) used must exist before using this module in your playbook. - The M(aci_tenant) module can be used for this. options: tenant: description: @@ -198,8 +198,8 @@ from ansible.module_utils.basic import AnsibleModule def main(): argument_spec = aci_argument_spec() argument_spec.update( - tenant=dict(type='str', aliases=['tenant_name']), # tenant not required for querying all APs - ap=dict(type='str', aliases=['app_profile', 'app_profile_name', 'name']), + 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'], required=False), state=dict(type='str', default='present', choices=['absent', 'present', 'query']), method=dict(type='str', choices=['delete', 'get', 'post'], aliases=['action'], removed_in_version='2.6'), # Deprecated starting from v2.6 @@ -215,7 +215,6 @@ def main(): ], ) - # tenant = module.params['tenant'] ap = module.params['ap'] description = module.params['description'] state = module.params['state'] @@ -240,7 +239,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='fvAp', class_config=dict( @@ -249,10 +247,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='fvAp') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_bd.py b/lib/ansible/modules/network/aci/aci_bd.py index 36c6d76d5b7..46d44735157 100644 --- a/lib/ansible/modules/network/aci/aci_bd.py +++ b/lib/ansible/modules/network/aci/aci_bd.py @@ -16,14 +16,14 @@ module: aci_bd short_description: Manage Bridge Domains (BD) on Cisco ACI Fabrics (fv:BD) description: - Manages Bridge Domains (BD) on Cisco ACI Fabrics. +notes: +- The C(tenant) used must exist before using this module in your playbook. + The M(aci_tenant) module can be used for this. - More information from the internal APIC class I(fv:BD) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Jacob McGill (@jmcgill298) version_added: '2.4' -notes: -- The C(tenant) used must exist before using this module in your playbook. - The M(aci_tenant) module can be used for this. options: arp_flooding: description: @@ -319,7 +319,7 @@ def main(): argument_spec = aci_argument_spec() argument_spec.update( arp_flooding=dict(type='bool'), - bd=dict(type='str', aliases=['bd_name', 'name']), + 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'), @@ -337,7 +337,7 @@ def main(): mac_address=dict(type='str', aliases=['mac']), multi_dest=dict(choices=['bd-flood', 'drop', 'encap-flood']), state=dict(choices=['absent', 'present', 'query'], type='str', default='present'), - tenant=dict(type='str', aliases=['tenant_name']), + tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects vrf=dict(type='str', aliases=['vrf_name']), gateway_ip=dict(type='str', removed_in_version='2.4'), # Deprecated starting from v2.4 scope=dict(type='str', removed_in_version='2.4'), # Deprecated starting from v2.4 @@ -409,7 +409,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module params with null values aci.payload( aci_class='fvBD', class_config=dict( @@ -436,10 +435,8 @@ def main(): ], ) - # generate config diff which will be used as POST request body aci.get_diff(aci_class='fvBD') - # submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_bd_subnet.py b/lib/ansible/modules/network/aci/aci_bd_subnet.py index 29f6d17c2db..1675040810a 100644 --- a/lib/ansible/modules/network/aci/aci_bd_subnet.py +++ b/lib/ansible/modules/network/aci/aci_bd_subnet.py @@ -16,16 +16,16 @@ module: aci_bd_subnet short_description: Manage Subnets on Cisco ACI fabrics (fv:Subnet) description: - Manage Subnets on Cisco ACI fabrics. -- More information from the internal APIC class I(fv:Subnet) at - U(https://developer.cisco.com/docs/apic-mim-ref/). -author: -- Jacob McGill (@jmcgill298) -version_added: '2.4' 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. +- More information from the internal APIC class I(fv:Subnet) at + U(https://developer.cisco.com/docs/apic-mim-ref/). +author: +- Jacob McGill (@jmcgill298) +version_added: '2.4' options: bd: description: @@ -316,11 +316,11 @@ from ansible.module_utils.basic import AnsibleModule, SEQUENCETYPE def main(): argument_spec = aci_argument_spec() argument_spec.update( - bd=dict(type='str', aliases=['bd_name']), + 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']), - mask=dict(type='int', aliases=['subnet_mask']), + 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'), @@ -329,7 +329,7 @@ def main(): 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']), + tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects method=dict(type='str', choices=['delete', 'get', 'post'], aliases=['action'], removed_in_version='2.6'), # Deprecated starting from v2.6 protocol=dict(type='str', removed_in_version='2.6'), # Deprecated in v2.6 ) @@ -398,7 +398,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module params with null values aci.payload( aci_class='fvSubnet', class_config=dict( @@ -416,10 +415,8 @@ def main(): ], ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='fvSubnet') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_bd_to_l3out.py b/lib/ansible/modules/network/aci/aci_bd_to_l3out.py index 6f20227d2ce..0de89fe16dd 100644 --- a/lib/ansible/modules/network/aci/aci_bd_to_l3out.py +++ b/lib/ansible/modules/network/aci/aci_bd_to_l3out.py @@ -16,14 +16,14 @@ module: aci_bd_to_l3out short_description: Bind Bridge Domain to L3 Out on Cisco ACI fabrics (fv:RsBDToOut) description: - Bind Bridge Domain to L3 Out on Cisco ACI fabrics. +notes: +- The C(bd) and C(l3out) parameters should exist before using this module. + The M(aci_bd) and M(aci_l3out) can be used for these. - More information from the internal APIC class I(fv:RsBDToOut) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Jacob McGill (@jmcgill298) version_added: '2.4' -notes: -- The C(bd) and C(l3out) parameters should exist before using this module. - The M(aci_bd) and M(aci_l3out) can be used for these. options: bd: description: @@ -162,10 +162,10 @@ from ansible.module_utils.basic import AnsibleModule def main(): argument_spec = aci_argument_spec() argument_spec.update( - bd=dict(type='str', aliases=['bd_name', 'bridge_domain']), - l3out=dict(type='str'), + 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 state=dict(type='str', default='present', choices=['absent', 'present', 'query']), - tenant=dict(type='str', aliases=['tenant_name']), + tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects method=dict(type='str', choices=['delete', 'get', 'post'], aliases=['action'], removed_in_version='2.6'), # Deprecated starting from v2.6 protocol=dict(type='str', removed_in_version='2.6'), # Deprecated in v2.6 ) @@ -210,16 +210,13 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module params with null values aci.payload( aci_class='fvRsBDToOut', class_config=dict(tnL3extOutName=l3out), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='fvRsBDToOut') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_config_rollback.py b/lib/ansible/modules/network/aci/aci_config_rollback.py index 4bbd9a63952..2774e698a22 100644 --- a/lib/ansible/modules/network/aci/aci_config_rollback.py +++ b/lib/ansible/modules/network/aci/aci_config_rollback.py @@ -17,6 +17,7 @@ short_description: Provides rollback and rollback preview functionality for Cisc description: - Provides rollback and rollback preview functionality for Cisco ACI fabric. - Config Rollbacks are done using snapshots C(aci_snapshot) with the configImportP class. +notes: - More information from the internal APIC class I(config:ImportP) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: @@ -97,9 +98,9 @@ EXAMPLES = r''' password: SomeSecretPassword state: preview export_policy: config_backup - snapshot: 'run-2017-08-28T06-24-01' + snapshot: run-2017-08-28T06-24-01 compare_export_policy: config_backup - compare_snapshot: 'run-2017-08-27T23-43-56' + compare_snapshot: run-2017-08-27T23-43-56 - name: Rollback Configuration aci_config_rollback: @@ -109,7 +110,7 @@ EXAMPLES = r''' state: rollback import_policy: rollback_config export_policy: config_backup - snapshot: 'run-2017-08-28T06-24-01' + snapshot: run-2017-08-28T06-24-01 - name: Rollback Configuration aci_config_rollback: @@ -119,8 +120,8 @@ EXAMPLES = r''' state: rollback import_policy: rollback_config export_policy: config_backup - snapshot: 'run-2017-08-28T06-24-01' - description: 'Rollback 8-27 changes' + snapshot: run-2017-08-28T06-24-01 + description: Rollback 8-27 changes import_mode: atomic import_type: replace fail_on_decrypt: yes @@ -241,7 +242,6 @@ def main(): aci.get_existing() - # Filter out module parameters with null values aci.payload( aci_class='configImportP', class_config=dict( @@ -256,10 +256,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='configImportP') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'preview': diff --git a/lib/ansible/modules/network/aci/aci_config_snapshot.py b/lib/ansible/modules/network/aci/aci_config_snapshot.py index 676989d2624..81b8950829c 100644 --- a/lib/ansible/modules/network/aci/aci_config_snapshot.py +++ b/lib/ansible/modules/network/aci/aci_config_snapshot.py @@ -18,15 +18,15 @@ 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. +notes: +- The APIC does not provide a mechanism for naming the snapshots. +- 'Snapshot files use the following naming structure: ce_---
T::.+:.' +- 'Snapshot objects use the following naming structure: run---
T--.' - More information from the internal APIC classes I(config:Snapshot) and I(config:ExportP) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Jacob McGill (@jmcgill298) version_added: '2.4' -notes: -- The APIC does not provide a mechanism for naming the snapshots. -- 'Snapshot files use the following naming structure: ce_---
T::.+:.' -- 'Snapshot objects use the following naming structure: run---
T--.' options: description: description: @@ -215,7 +215,7 @@ def main(): argument_spec = aci_argument_spec() argument_spec.update( description=dict(type='str', aliases=['descr']), - export_policy=dict(type='str', aliases=['name']), + 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'), @@ -261,7 +261,6 @@ def main(): aci.get_existing() - # Filter out module params with null values aci.payload( aci_class='configExportP', class_config=dict( diff --git a/lib/ansible/modules/network/aci/aci_contract.py b/lib/ansible/modules/network/aci/aci_contract.py index 2cbe9c121b5..373a0faa29e 100644 --- a/lib/ansible/modules/network/aci/aci_contract.py +++ b/lib/ansible/modules/network/aci/aci_contract.py @@ -16,16 +16,16 @@ module: aci_contract short_description: Manage contract resources on Cisco ACI fabrics (vz:BrCP) description: - Manage Contract resources on Cisco ACI fabrics. -- More information from the internal APIC class I(vz:BrCP) at - U(https://developer.cisco.com/docs/apic-mim-ref/). -author: -- Dag Wieers (@dagwieers) -version_added: '2.4' 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. +- More information from the internal APIC class I(vz:BrCP) at + U(https://developer.cisco.com/docs/apic-mim-ref/). +author: +- Dag Wieers (@dagwieers) +version_added: '2.4' options: contract: description: @@ -66,18 +66,42 @@ options: extends_documentation_fragment: aci ''' -# FIXME: Add more, better examples EXAMPLES = r''' -- aci_contract: - host: '{{ inventory_hostname }}' - username: '{{ username }}' - password: '{{ password }}' - contract: '{{ contract }}' - description: '{{ descr }}' - tenant: '{{ tenant }}' - scope: '{{ scope }}' - priority: '{{ priority }}' - target: '{{ target }}' +- 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 + +- name: Remove an existing contract + aci_contract: + host: apic + username: admin + password: SomeSecretPassword + tenant: production + contract: web_to_db + state: absent + +- name: Query a specific contract + aci_contract: + host: apic + username: admin + password: SomeSecretPassword + tenant: production + contract: web_to_db + state: query + +- name: Query all contracts + aci_contract: + host: apic + username: admin + password: SomeSecretPassword + state: query ''' RETURN = r''' @@ -210,8 +234,8 @@ def main(): argument_spec=argument_spec, supports_check_mode=True, required_if=[ - ['state', 'absent', ['tenant', 'contract']], - ['state', 'present', ['tenant', 'contract']], + ['state', 'absent', ['contract', 'tenant']], + ['state', 'present', ['contract', 'tenant']], ], ) @@ -242,7 +266,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='vzBrCP', class_config=dict( @@ -254,10 +277,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='vzBrCP') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_contract_subject.py b/lib/ansible/modules/network/aci/aci_contract_subject.py index a731a4e3a90..49362b3ef51 100755 --- a/lib/ansible/modules/network/aci/aci_contract_subject.py +++ b/lib/ansible/modules/network/aci/aci_contract_subject.py @@ -16,14 +16,14 @@ module: aci_contract_subject short_description: Manage initial Contract Subjects on Cisco ACI fabrics (vz:Subj) description: - Manage initial Contract Subjects on Cisco ACI fabrics. +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. - More information from the internal APIC class I(vz:Subj) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Swetha Chunduri (@schunduri) version_added: '2.4' -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. options: tenant: description: @@ -240,9 +240,9 @@ MATCH_MAPPING = dict(all='All', at_least_one='AtleastOne', at_most_one='AtmostOn def main(): argument_spec = aci_argument_spec() argument_spec.update( - contract=dict(type='str', aliases=['contract_name']), - subject=dict(type='str', aliases=['contract_subject', 'name', 'subject_name']), - tenant=dict(type='str', aliases=['tenant_name']), + 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']), @@ -311,7 +311,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='vzSubj', class_config=dict( @@ -325,10 +324,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='vzSubj') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_contract_subject_to_filter.py b/lib/ansible/modules/network/aci/aci_contract_subject_to_filter.py index 84e3cfd21fc..b6c98b97f9c 100644 --- a/lib/ansible/modules/network/aci/aci_contract_subject_to_filter.py +++ b/lib/ansible/modules/network/aci/aci_contract_subject_to_filter.py @@ -16,16 +16,14 @@ module: aci_contract_subject_to_filter short_description: Bind Contract Subjects to Filters on Cisco ACI fabrics (vz:RsSubjFiltAtt) description: - Bind Contract Subjects to Filters on Cisco ACI fabrics. +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. - More information from the internal APIC class I(vz:RsSubjFiltAtt) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Jacob McGill (@jmcgill298) version_added: '2.4' -requirements: -- ACI Fabric 1.0(3f)+ -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. options: contract: description: @@ -60,17 +58,51 @@ options: extends_documentation_fragment: aci ''' -# FIXME: Add more, better examples EXAMPLES = r''' -- aci_subject_filter_binding: - host: '{{ inventory_hostname }}' - username: '{{ username }}' - password: '{{ password }}' - tenant: '{{ tenant }}' - contract: '{{ contract }}' - subject: '{{ subject }}' +- name: Add a new contract subject to filer binding + aci_subject_filter_binding: + host: apic + username: admin + password: SomeSecretPassword + tenant: production + contract: web_to_db + subject: test filter: '{{ filter }}' log: '{{ log }}' + state: present + +- name: Remove an existing contract subject to filter binding + aci_subject_filter_binding: + host: apic + username: admin + password: SomeSecretPassword + tenant: production + contract: web_to_db + subject: test + filter: '{{ filter }}' + log: '{{ log }}' + state: present + +- name: Query a specific contract subject to filter binding + aci_subject_filter_binding: + host: apic + username: admin + password: SomeSecretPassword + tenant: production + contract: web_to_db + subject: test + filter: '{{ filter }}' + state: query + +- name: Query all contract subject to filter bindings + aci_subject_filter_binding: + host: apic + username: admin + password: SomeSecretPassword + tenant: production + contract: web_to_db + subject: test + state: query ''' RETURN = r''' @@ -185,11 +217,11 @@ from ansible.module_utils.basic import AnsibleModule def main(): argument_spec = aci_argument_spec() argument_spec.update( - contract=dict(type='str', aliases=['contract_name']), - filter=dict(type='str', aliases=['filter_name']), + 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 log=dict(tyep='str', choices=['log', 'none'], aliases=['directive']), - subject=dict(type='str', aliases=['contract_subject', 'subject_name']), - tenant=dict(type='str', aliases=['tenant_name']), + 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 state=dict(type='str', default='present', choices=['absent', 'present', 'query']), method=dict(type='str', choices=['delete', 'get', 'post'], aliases=['action'], removed_in_version='2.6'), # Deprecated starting from v2.6 protocol=dict(type='str', removed_in_version='2.6'), # Deprecated in v2.6 @@ -249,7 +281,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='vzRsSubjFiltAtt', class_config=dict( @@ -258,10 +289,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='vzRsSubjFiltAtt') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_domain.py b/lib/ansible/modules/network/aci/aci_domain.py index f1db1543be6..3c597d96060 100644 --- a/lib/ansible/modules/network/aci/aci_domain.py +++ b/lib/ansible/modules/network/aci/aci_domain.py @@ -16,6 +16,7 @@ module: aci_domain short_description: Manage physical, virtual, bridged, routed or FC domain profiles (*:DomP) description: - Manage physical, virtual, bridged, routed or FC domain profiles. +notes: - More information from the internal APIC classes I(phys:DomP), I(vmm:DomP), I(l2ext:DomP), I(l3ext:DomP), I(fc:DomP) at U(https://developer.cisco.com/docs/apic-mim-ref/). @@ -259,8 +260,8 @@ def main(): 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']), - domain=dict(type='str', aliases=['domain_name', 'domain_profile', 'name']), - domain_type=dict(type='str', choices=['fc', 'l2dom', 'l3dom', 'phys', 'vmm'], aliases=['type']), + domain=dict(type='str', aliases=['domain_name', 'domain_profile', 'name']), # Not required for querying all objects + domain_type=dict(type='str', required=True, choices=['fc', 'l2dom', 'l3dom', 'phys', 'vmm'], aliases=['type']), # Not required for querying all objects encap_mode=dict(type='str', choices=['unknown', 'vlan', 'vxlan']), multicast_address=dict(type='str'), state=dict(type='str', default='present', choices=['absent', 'present', 'query']), @@ -291,13 +292,13 @@ def main(): if domain_type != 'vmm': if vm_provider is not None: - module.fail_json(msg="Domain type '{0}' cannot have a 'vm_provider'".format(domain_type)) + 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 an 'encap_mode'".format(domain_type)) + 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 a 'multicast_address'".format(domain_type)) + 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 a 'vswitch'".format(domain_type)) + 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") @@ -324,6 +325,10 @@ def main(): 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 = ACIModule(module) aci.construct_url( root_class=dict( @@ -337,7 +342,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class=domain_class, class_config=dict( @@ -349,10 +353,8 @@ def main(): ), ) - # 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': diff --git a/lib/ansible/modules/network/aci/aci_domain_to_encap_pool.py b/lib/ansible/modules/network/aci/aci_domain_to_encap_pool.py deleted file mode 100644 index 2e1817a8fb3..00000000000 --- a/lib/ansible/modules/network/aci/aci_domain_to_encap_pool.py +++ /dev/null @@ -1,310 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2017, Dag Wieers -# 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_domain_to_encap_pool -short_description: Bind Domain to Encap Pools on Cisco ACI fabrics (infra:RsVlanNs) -description: -- Bind Domain to Encap Pools on Cisco ACI fabrics. -- More information from the internal APIC class I(infra:RsVlanNs) at - U(https://developer.cisco.com/docs/apic-mim-ref/). -author: -- Dag Wieers (@dagwieers) -version_added: '2.5' -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. -options: - domain: - description: - - Name of the domain being associated with the Encap Pool. - aliases: [ domain_name, domain_profile ] - domain_type: - description: - - Determines if the Domain is physical (phys) or virtual (vmm). - choices: [ fc, l2dom, l3dom, phys, vmm ] - pool: - description: - - The name of the pool. - aliases: [ pool_name ] - pool_allocation_mode: - description: - - The method used for allocating encaps to resources. - - Only vlan and vsan support allocation modes. - choices: [ dynamic, static] - aliases: [ allocation_mode, mode ] - pool_type: - description: - - The encap type of C(pool). - required: yes - choices: [ vlan, vsan, vxsan ] - state: - description: - - Use C(present) or C(absent) for adding or removing. - - Use C(query) for listing an object or multiple objects. - 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. - choices: [ cloudfoundry, kubernetes, microsoft, openshift, openstack, redhat, vmware ] -extends_documentation_fragment: aci -''' - -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: string - sample: '' -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: string - sample: ?rsp-prop-include=config-only -method: - description: The HTTP method used for the request to the APIC - returned: failure or debug - type: string - sample: POST -response: - description: The HTTP response from the APIC - returned: failure or debug - type: string - 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: string - 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 - -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-', - child_class='infraRsVlanNs', - ), - vxlan=dict( - aci_mo='uni/infra/vxlanns-', - child_class='vmmRsVxlanNs', - ), - vsan=dict( - aci_mo='uni/infra/vsanns-', - child_class='fcRsVsanNs', - ), -) - - -def main(): - argument_spec = aci_argument_spec() - argument_spec.update( - domain=dict(type='str', aliases=['domain_name', 'domain_profile']), - domain_type=dict(type='str', choices=['fc', 'l2dom', 'l3dom', 'phys', 'vmm']), - pool=dict(type='str', aliases=['pool_name']), - pool_allocation_mode=dict(type='str', aliases=['allocation_mode', 'mode'], choices=['dynamic', 'static']), - pool_type=dict(type='str', required=True, choices=['vlan', 'vsan', 'vxlan']), - 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['domain'] - domain_type = module.params['domain_type'] - pool = module.params['pool'] - pool_allocation_mode = module.params['pool_allocation_mode'] - pool_type = module.params['pool_type'] - vm_provider = module.params['vm_provider'] - state = module.params['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) - - pool_mo = POOL_MAPPING[pool_type]["aci_mo"] + 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, - filter_target='eq({0}.name, "{1}")'.format(domain_class, domain), - module_object=domain_mo, - ), - 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() diff --git a/lib/ansible/modules/network/aci/aci_domain_to_vlan_pool.py b/lib/ansible/modules/network/aci/aci_domain_to_vlan_pool.py index 3ebdb71cf3b..5a81623108a 100755 --- a/lib/ansible/modules/network/aci/aci_domain_to_vlan_pool.py +++ b/lib/ansible/modules/network/aci/aci_domain_to_vlan_pool.py @@ -17,14 +17,14 @@ module: aci_domain_to_vlan_pool short_description: Bind Domain to VLAN Pools on Cisco ACI fabrics (infra:RsVlanNs) description: - Bind Domain to VLAN Pools on Cisco ACI fabrics. +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. - More information from the internal APIC class I(infra:RsVlanNs) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Dag Wieers (@dagwieers) version_added: '2.5' -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. options: domain: description: @@ -122,6 +122,7 @@ EXAMPLES = r''' host: apic username: admin password: SomeSecretPassword + domain_type: phys state: query ''' @@ -234,7 +235,10 @@ from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec from ansible.module_utils.basic import AnsibleModule VM_PROVIDER_MAPPING = dict( + cloudfoundry='CloudFoundry', + kubernetes='Kubernetes', microsoft='Microsoft', + openshift='OpenShift', openstack='OpenStack', redhat='Redhat', vmware='VMware', @@ -244,9 +248,9 @@ VM_PROVIDER_MAPPING = dict( def main(): argument_spec = aci_argument_spec() argument_spec.update( - domain=dict(type='str', aliases=['domain_name', 'domain_profile']), - domain_type=dict(type='str', choices=['fc', 'l2dom', 'l3dom', 'phys', 'vmm']), - pool=dict(type='str', aliases=['pool_name', 'vlan_pool']), + domain=dict(type='str', aliases=['domain_name', 'domain_profile']), # Not required for querying all objects + domain_type=dict(type='str', required=True, choices=['fc', 'l2dom', 'l3dom', 'phys', 'vmm']), # 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']), @@ -300,7 +304,11 @@ def main(): domain_mo = 'uni/vmmp-{0}/dom-{1}'.format(VM_PROVIDER_MAPPING[vm_provider], domain) domain_rn = 'dom-{0}'.format(domain) - aci_mo = 'uni/infra/vlanns-' + pool_name + # 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( @@ -316,7 +324,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module params with null values aci.payload( aci_class=domain_class, class_config=dict(name=domain), @@ -325,10 +332,8 @@ def main(): ] ) - # 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': diff --git a/lib/ansible/modules/network/aci/aci_encap_pool.py b/lib/ansible/modules/network/aci/aci_encap_pool.py index f80f6aca44f..d5767291430 100644 --- a/lib/ansible/modules/network/aci/aci_encap_pool.py +++ b/lib/ansible/modules/network/aci/aci_encap_pool.py @@ -16,6 +16,7 @@ module: aci_encap_pool short_description: Manage encap pools on Cisco ACI fabrics (fvns:VlanInstP, fvns:VxlanInstP, fvns:VsanInstP) description: - Manage vlan, vxlan, and vsan pools on Cisco ACI fabrics. +notes: - More information from the internal APIC class I(fvns:VlanInstP), I(fvns:VxlanInstP), and I(fvns:VsanInstP) at U(https://developer.cisco.com/docs/apic-mim-ref/). @@ -218,7 +219,7 @@ def main(): argument_spec = aci_argument_spec() argument_spec.update( description=dict(type='str', aliases=['descr']), - pool=dict(type='str', aliases=['name', 'pool_name']), + 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']), pool_type=dict(type='str', aliases=['type'], choices=['vlan', 'vxlan', 'vsan'], required=True), state=dict(type='str', default='present', choices=['absent', 'present', 'query']), diff --git a/lib/ansible/modules/network/aci/aci_encap_pool_range.py b/lib/ansible/modules/network/aci/aci_encap_pool_range.py index b6749d8dd68..be22da83655 100644 --- a/lib/ansible/modules/network/aci/aci_encap_pool_range.py +++ b/lib/ansible/modules/network/aci/aci_encap_pool_range.py @@ -16,13 +16,13 @@ module: aci_encap_pool_range short_description: Manage encap ranges assigned to pools on Cisco ACI fabrics (fvns:EncapBlk, fvns:VsanEncapBlk) description: - Manage vlan, vxlan, and vsan ranges that are assigned to pools on Cisco ACI fabrics. +notes: +- The C(pool) must exist in order to add or delete a range. - More information from the internal APIC class I(fvns:EncapBlk) and I(fvns:VsanEncapBlk) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Jacob McGill (@jmcgill298) version_added: '2.5' -requirements: -- The C(pool) must exist in order to add or delete a range. options: allocation_mode: description: @@ -252,12 +252,12 @@ def main(): argument_spec.update( allocation_mode=dict(type='str', aliases=['mode'], choices=['dynamic', 'inherit', 'static']), description=dict(type='str', aliases=['descr']), - pool=dict(type='str', aliases=['pool_name']), + 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']), pool_type=dict(type='str', aliases=['type'], choices=['vlan', 'vxlan', 'vsan'], required=True), - range_end=dict(type='int', aliases=['end']), - range_name=dict(type='str', aliases=["name", "range"]), - range_start=dict(type='int', aliases=["start"]), + 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']), ) @@ -383,7 +383,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class=aci_range_class, class_config={ @@ -392,13 +391,11 @@ def main(): "from": encap_start, "name": range_name, "to": encap_end, - } + }, ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class=aci_range_class) - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_epg.py b/lib/ansible/modules/network/aci/aci_epg.py index 6017010a1b1..57e5037eaae 100644 --- a/lib/ansible/modules/network/aci/aci_epg.py +++ b/lib/ansible/modules/network/aci/aci_epg.py @@ -16,14 +16,14 @@ module: aci_epg short_description: Manage End Point Groups (EPG) on Cisco ACI fabrics (fv:AEPg) description: - Manage End Point Groups (EPG) on Cisco ACI fabrics. +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. - More information from the internal APIC class I(fv:AEPg) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Swetha Chunduri (@schunduri) version_added: '2.4' -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. options: tenant: description: @@ -270,10 +270,10 @@ from ansible.module_utils.basic import AnsibleModule def main(): argument_spec = aci_argument_spec() argument_spec.update( - epg=dict(type='str', aliases=['name', 'epg_name']), + epg=dict(type='str', aliases=['name', 'epg_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']), - tenant=dict(type='str', aliases=['tenant_name']), + 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']), @@ -331,7 +331,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='fvAEPg', class_config=dict( @@ -347,10 +346,8 @@ def main(): ], ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='fvAEPg') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_epg_monitoring_policy.py b/lib/ansible/modules/network/aci/aci_epg_monitoring_policy.py index 722bb4906d3..6ad0edbc00b 100644 --- a/lib/ansible/modules/network/aci/aci_epg_monitoring_policy.py +++ b/lib/ansible/modules/network/aci/aci_epg_monitoring_policy.py @@ -16,16 +16,14 @@ module: aci_epg_monitoring_policy short_description: Manage monitoring policies on Cisco ACI fabrics (mon:EPGPol) description: - Manage monitoring policies on Cisco ACI fabrics. +notes: +- The C(tenant) used must exist before using this module in your playbook. + The M(aci_tenant) module can be used for this. - More information from the internal APIC class I(mon:EPGPol) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Dag Wieers (@dagwieers) version_added: '2.4' -requirements: -- ACI Fabric 1.0(3f)+ -notes: -- The C(tenant) used must exist before using this module in your playbook. - The M(aci_tenant) module can be used for this. options: monitoring_policy: description: @@ -214,7 +212,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='monEPGPol', class_config=dict( @@ -223,10 +220,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='monEPGPol') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_epg_to_contract.py b/lib/ansible/modules/network/aci/aci_epg_to_contract.py index 5396de0f084..b2e3428c3f2 100644 --- a/lib/ansible/modules/network/aci/aci_epg_to_contract.py +++ b/lib/ansible/modules/network/aci/aci_epg_to_contract.py @@ -16,14 +16,14 @@ module: aci_epg_to_contract short_description: Bind EPGs to Contracts on Cisco ACI fabrics (fv:RsCons and 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. - More information from the internal APIC classes I(fv:RsCons) and I(fv:RsProv) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Jacob McGill (@jmcgill298) version_added: '2.4' -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. options: ap: description: @@ -67,7 +67,51 @@ options: extends_documentation_fragment: aci ''' -EXAMPLES = r''' # ''' +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 + +- 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 + +- 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 + +- name: Query all provider contract to EPG bindings + aci_epg_to_contract: + host: apic + username: admin + password: SomeSecretPassword + contract_type: provider + state: query +''' RETURN = r''' current: @@ -184,14 +228,14 @@ PROVIDER_MATCH_MAPPING = {"all": "All", "at_least_one": "AtleastOne", "at_most_o def main(): argument_spec = aci_argument_spec() argument_spec.update( - ap=dict(type='str', aliases=['app_profile', 'app_profile_name']), - epg=dict(type='str', aliases=['epg_name']), - contract=dict(type='str', aliases=['contract_name']), + 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 contract_type=dict(type='str', required=True, choices=['consumer', 'provider']), 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']), + tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects method=dict(type='str', choices=['delete', 'get', 'post'], aliases=['action'], removed_in_version='2.6'), # Deprecated starting from v2.6 protocol=dict(type='str', removed_in_version='2.6'), # Deprecated in v2.6 ) @@ -253,7 +297,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class=aci_class, class_config=dict( @@ -263,10 +306,8 @@ def main(): ), ) - # 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': diff --git a/lib/ansible/modules/network/aci/aci_epg_to_domain.py b/lib/ansible/modules/network/aci/aci_epg_to_domain.py index 8d7e4dbf58e..095aa3c99a9 100644 --- a/lib/ansible/modules/network/aci/aci_epg_to_domain.py +++ b/lib/ansible/modules/network/aci/aci_epg_to_domain.py @@ -16,17 +16,17 @@ module: aci_epg_to_domain short_description: Bind EPGs to Domains on Cisco ACI fabrics (fv:RsDomAtt) description: - Bind EPGs to Physical and Virtual Domains on Cisco ACI fabrics. -- More information from the internal APIC class I(fv:RsDomAtt) at - U(https://developer.cisco.com/docs/apic-mim-ref/). -author: -- Jacob McGill (@jmcgill298) -version_added: '2.4' 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. +- More information from the internal APIC class I(fv:RsDomAtt) at + U(https://developer.cisco.com/docs/apic-mim-ref/). +author: +- Jacob McGill (@jmcgill298) +version_added: '2.4' options: allow_useg: description: @@ -103,7 +103,50 @@ options: extends_documentation_fragment: aci ''' -EXAMPLES = r''' # ''' +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 + +- 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 + +- 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 + +- name: Query all domain to EPG bindings + aci_epg_to_domain: + host: apic + username: admin + password: SomeSecretPassword + state: query +''' RETURN = r''' current: @@ -228,18 +271,18 @@ 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']), + ap=dict(type='str', aliases=['app_profile', 'app_profile_name']), # Not required for querying all objects deploy_immediacy=dict(type='str', choices=['immediate', 'on-demand']), - domain=dict(type='str', aliases=['domain_name', 'domain_profile']), - domain_type=dict(type='str', choices=['phys', 'vmm'], aliases=['type']), + domain=dict(type='str', aliases=['domain_name', 'domain_profile']), # Not required for querying all objects + domain_type=dict(type='str', choices=['phys', 'vmm'], aliases=['type']), # Not required for querying all objects encap=dict(type='int'), encap_mode=dict(type='str', choices=['auto', 'vlan', 'vxlan']), - epg=dict(type='str', aliases=['name', 'epg_name']), + epg=dict(type='str', aliases=['name', 'epg_name']), # Not required for querying all objects netflow=dict(type='raw'), # Turn into a boolean in v2.9 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']), + 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']), method=dict(type='str', choices=['delete', 'get', 'post'], aliases=['action'], removed_in_version='2.6'), # Deprecated starting from v2.6 protocol=dict(type='str', removed_in_version='2.6'), # Deprecated in v2.6 @@ -323,7 +366,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='fvRsDomAtt', class_config=dict( @@ -337,10 +379,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='fvRsDomAtt') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_fabric_node.py b/lib/ansible/modules/network/aci/aci_fabric_node.py index a462c2ce789..bdaa0561485 100644 --- a/lib/ansible/modules/network/aci/aci_fabric_node.py +++ b/lib/ansible/modules/network/aci/aci_fabric_node.py @@ -17,6 +17,7 @@ module: aci_fabric_node short_description: Add a new Fabric Node Member on Cisco ACI fabrics (fabric:NodeIdentP) description: - Add a new Fabric Node Member on Cisco ACI fabrics. +notes: - More information from the internal APIC class I(fabric:NodeIdentP) at U(https://developer.cisco.com/site/aci/docs/apis/apic-mim-ref/). author: @@ -36,7 +37,7 @@ options: switch: description: - Switch Name for the new Fabric Node Member. - aliases: [ switch_name ] + aliases: [ name, switch_name ] description: description: - Description for the new Fabric Node Member. @@ -71,7 +72,108 @@ 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: string + sample: '' +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: string + sample: '?rsp-prop-include=config-only' +method: + description: The HTTP method used for the request to the APIC + returned: failure or debug + type: string + sample: POST +response: + description: The HTTP response from the APIC + returned: failure or debug + type: string + 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: string + sample: https://10.11.12.13/api/mo/uni/tn-production.json ''' from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec @@ -84,12 +186,12 @@ from ansible.module_utils.basic import AnsibleModule def main(): argument_spec = aci_argument_spec() argument_spec.update( - pod_id=dict(type='int'), - serial=dict(type='str', aliases=['serial_number']), - node_id=dict(type='int'), - switch=dict(type='str', aliases=['switch_name']), 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']), ) @@ -97,8 +199,8 @@ def main(): argument_spec=argument_spec, supports_check_mode=True, required_if=[ - ['state', 'absent', ['serial', 'node_id']], - ['state', 'present', ['serial', 'node_id']], + ['state', 'absent', ['node_id', 'serial']], + ['state', 'present', ['node_id', 'serial']], ], ) @@ -123,31 +225,27 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='fabricNodeIdentP', class_config=dict( - dn='uni/controller/nodeidentpol/nodep-{0}'.format(serial), - podId=pod_id, - serial=serial, - nodeId=node_id, + descr=description, name=switch, - role=role, + nodeId=node_id, + podId=pod_id, rn='nodep-{0}'.format(serial), - descr=description, + role=role, + serial=serial, ) ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='fabricNodeIdentP') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': aci.delete_config() - module.exit_json(**aci.result) + aci.exit_json(**aci.result) if __name__ == "__main__": diff --git a/lib/ansible/modules/network/aci/aci_filter.py b/lib/ansible/modules/network/aci/aci_filter.py index 2949e47b930..8d868c15eba 100644 --- a/lib/ansible/modules/network/aci/aci_filter.py +++ b/lib/ansible/modules/network/aci/aci_filter.py @@ -16,15 +16,15 @@ module: aci_filter short_description: Manages top level filter objects on Cisco ACI fabrics (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. +notes: +- The C(tenant) used must exist before using this module in your playbook. + The M(aci_tenant) module can be used for this. - More information from the internal APIC class I(vz:Filter) at U(https://developer.cisco.com/docs/apic-mim-ref/). -- This modules does not manage filter entries, see M(aci_filter_entry) for this functionality. author: - Dag Wieers (@dagwieers) version_added: '2.4' -notes: -- The C(tenant) used must exist before using this module in your playbook. - The M(aci_tenant) module can be used for this. options: filter: description: @@ -240,7 +240,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='vzFilter', class_config=dict( @@ -249,10 +248,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='vzFilter') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_filter_entry.py b/lib/ansible/modules/network/aci/aci_filter_entry.py index e81f25448bc..1d106ec7402 100644 --- a/lib/ansible/modules/network/aci/aci_filter_entry.py +++ b/lib/ansible/modules/network/aci/aci_filter_entry.py @@ -16,14 +16,14 @@ module: aci_filter_entry short_description: Manage filter entries on Cisco ACI fabrics (vz:Entry) description: - Manage filter entries for a filter on Cisco ACI fabrics. +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. - More information from the internal APIC class I(vz:Entry) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Jacob McGill (@jmcgill298) version_added: '2.4' -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. options: arp_flag: description: @@ -247,15 +247,15 @@ def main(): 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']), + 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']), + 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']), + tenant=dict(type="str", aliases=['tenant_name']), # Not required for querying all objects ) module = AnsibleModule( @@ -327,7 +327,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module params with null values aci.payload( aci_class='vzEntry', class_config=dict( @@ -344,10 +343,8 @@ def main(): ), ) - # generate config diff which will be used as POST request body aci.get_diff(aci_class='vzEntry') - # submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_firmware_source.py b/lib/ansible/modules/network/aci/aci_firmware_source.py index 1d0ce73bd43..56ff67c464b 100644 --- a/lib/ansible/modules/network/aci/aci_firmware_source.py +++ b/lib/ansible/modules/network/aci/aci_firmware_source.py @@ -17,11 +17,12 @@ module: aci_firmware_source short_description: Manage firmware image sources on Cisco ACI fabrics (firmware:OSource) description: - Manage firmware image sources on Cisco ACI fabrics. -- More information from the internal APIC class I(firmware:OSource) at - U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Dag Wieers (@dagwieers) version_added: '2.5' +notes: +- More information from the internal APIC class I(firmware:OSource) at + U(https://developer.cisco.com/docs/apic-mim-ref/). options: source: description: @@ -58,35 +59,35 @@ extends_documentation_fragment: aci EXAMPLES = r''' - name: Add firmware source aci_firmware_source: - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' + host: apic + username: admin + password: SomeSecretPassword source: aci-msft-pkg-3.1.1i.zip - url: foobar.cisco.com/download/cisco/aci/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 - name: Remove firmware source aci_firmware_source: - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' + host: apic + username: admin + password: SomeSecretPassword source: aci-msft-pkg-3.1.1i.zip state: absent -- name: Query all firmware sources +- name: Query a specific firmware source aci_firmware_source: - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' + host: apic + username: admin + password: SomeSecretPassword + source: aci-msft-pkg-3.1.1i.zip state: query -- name: Query a specific firmware source +- name: Query all firmware sources aci_firmware_source: - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - source: aci-msft-pkg-3.1.1i.zip + host: apic + username: admin + password: SomeSecretPassword state: query ''' @@ -241,7 +242,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='firmwareOSource', class_config=dict( @@ -254,10 +254,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='firmwareOSource') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_interface_policy_fc.py b/lib/ansible/modules/network/aci/aci_interface_policy_fc.py index 7b963a81a3e..46ff1b0c945 100644 --- a/lib/ansible/modules/network/aci/aci_interface_policy_fc.py +++ b/lib/ansible/modules/network/aci/aci_interface_policy_fc.py @@ -16,11 +16,12 @@ module: aci_interface_policy_fc short_description: Manage Fibre Channel interface policies on Cisco ACI fabrics (fc:IfPol) description: - Manage ACI Fiber Channel interface policies on Cisco ACI fabrics. -- More information from the internal APIC class I(fc:IfPol) at - U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Dag Wieers (@dagwieers) version_added: '2.4' +notes: +- More information from the internal APIC class I(fc:IfPol) at + U(https://developer.cisco.com/docs/apic-mim-ref/). options: fc_policy: description: @@ -203,7 +204,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='fcIfPol', class_config=dict( @@ -213,10 +213,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='fcIfPol') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_interface_policy_l2.py b/lib/ansible/modules/network/aci/aci_interface_policy_l2.py index 5649ce385ed..c264d9b58c2 100644 --- a/lib/ansible/modules/network/aci/aci_interface_policy_l2.py +++ b/lib/ansible/modules/network/aci/aci_interface_policy_l2.py @@ -16,11 +16,12 @@ module: aci_interface_policy_l2 short_description: Manage Layer 2 interface policies on Cisco ACI fabrics (l2:IfPol) description: - Manage Layer 2 interface policies on Cisco ACI fabrics. -- More information from the internal APIC class I(l2:IfPol) at - U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Dag Wieers (@dagwieers) version_added: '2.4' +notes: +- More information from the internal APIC class I(l2:IfPol) at + U(https://developer.cisco.com/docs/apic-mim-ref/). options: l2_policy: description: @@ -222,7 +223,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='l2IfPol', class_config=dict( @@ -233,10 +233,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='l2IfPol') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_interface_policy_leaf_policy_group.py b/lib/ansible/modules/network/aci/aci_interface_policy_leaf_policy_group.py index ce130718505..3ac7f55e195 100644 --- a/lib/ansible/modules/network/aci/aci_interface_policy_leaf_policy_group.py +++ b/lib/ansible/modules/network/aci/aci_interface_policy_leaf_policy_group.py @@ -17,14 +17,14 @@ module: aci_interface_policy_leaf_policy_group short_description: Add Fabric Interface Policy Leaf Policy Groups on Cisco ACI fabrics. description: - Add Fabric Interface Policy Leaf Policy Groups on Cisco ACI fabrics. +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. - More information from the internal APIC class I(infra:AccBndlGrp), I(infra:AccPortGrp) at U(https://developer.cisco.com/site/aci/docs/apis/apic-mim-ref/). author: - Bruno Calogero (@brunocalogero) version_added: '2.5' -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. options: policy_group: description: @@ -37,7 +37,11 @@ options: 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) aliases: [ lag_type_name ] + choices: [ leaf, link, node ] link_level_policy: description: - Choice of link_level_policy to be used as part of the leaf policy group to be created. @@ -111,12 +115,13 @@ options: extends_documentation_fragment: aci ''' +# FIXME: Add query examples EXAMPLES = r''' -- name: creating a Port Channel (PC) Interface Policy Group +- name: Create a Port Channel (PC) Interface Policy Group aci_interface_policy_leaf_policy_group: host: apic - username: yourusername - password: yourpassword + username: admin + password: SomeSecretPassword policy_group: policygroupname description: policygroupname description lag_type: link @@ -124,39 +129,39 @@ EXAMPLES = r''' fibre_channel_interface_policy: whateverfcpolicy state: present -- name: creating a Virtual Port Channel (VPC) Interface Policy Group (no description) +- name: Create a Virtual Port Channel (VPC) Interface Policy Group (no description) aci_interface_policy_leaf_policy_group: host: apic - username: yourusername - password: yourpassword + username: admin + password: SomeSecretPassword policy_group: policygroupname lag_type: node link_level_policy: whateverlinklevelpolicy fibre_channel_interface_policy: whateverfcpolicy state: present -- name: creating a Leaf Access Port Policy Group (no description) +- name: Create a Leaf Access Port Policy Group (no description) aci_interface_policy_leaf_policy_group: host: apic - username: yourusername - password: yourpassword + username: admin + password: SomeSecretPassword policy_group: policygroupname lag_type: leaf link_level_policy: whateverlinklevelpolicy fibre_channel_interface_policy: whateverfcpolicy state: present -- name: deleting an Interface policy Leaf Policy Group +- name: Delete an Interface policy Leaf Policy Group aci_interface_policy_leaf_policy_group: host: apic - username: yourusername - password: yourpassword + username: admin + password: SomeSecretPassword policy_group: policygroupname lag_type: type_name state: absent ''' -RETURN = ''' +RETURN = r''' current: description: The existing configuration from the APIC after the module has finished returned: success @@ -268,11 +273,11 @@ from ansible.module_utils.basic import AnsibleModule def main(): argument_spec = aci_argument_spec() argument_spec.update({ - 'policy_group': dict(type='str', aliases=['name', 'policy_group_name']), + 'policy_group': dict(type='str', aliases=['name', 'policy_group_name']), # Not required for querying all objects 'description': dict(type='str', aliases=['descr']), - # NOTE: Since this module needs to include both infra:AccBndlGrp (for PC andVPC) and infra:AccPortGrp (for leaf access port policy group): + # 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', aliases=['lag_type_name']), + 'lag_type': dict(type='str', aliases=['lag_type_name'], choices=['leaf', 'link', 'node']), # Not required for querying all objects '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']), @@ -289,16 +294,16 @@ def main(): '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']) + 'state': dict(type='str', default='present', choices=['absent', 'present', 'query']), }) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, required_if=[ - ['state', 'absent', ['policy_group', 'lag_type']], - ['state', 'present', ['policy_group', 'lag_type']] - ] + ['state', 'absent', ['lag_type', 'policy_group']], + ['state', 'present', ['lag_type', 'policy_group']], + ], ) policy_group = module.params['policy_group'] @@ -321,9 +326,6 @@ def main(): port_security_policy = module.params['port_security_policy'] aep = module.params['aep'] state = module.params['state'] - aci_class_name = '' - dn_name = '' - class_config_dict = {} if lag_type == 'leaf': aci_class_name = 'infraAccPortGrp' @@ -331,7 +333,6 @@ def main(): class_config_dict = dict( name=policy_group, descr=description, - dn='uni/infra/funcprof/{0}-{1}'.format(dn_name, policy_group) ) elif lag_type == 'link' or lag_type == 'node': aci_class_name = 'infraAccBndlGrp' @@ -340,7 +341,6 @@ def main(): name=policy_group, descr=description, lagT=lag_type, - dn='uni/infra/funcprof/{0}-{1}'.format(dn_name, policy_group) ) aci = ACIModule(module) @@ -349,144 +349,152 @@ def main(): aci_class=aci_class_name, aci_rn='infra/funcprof/{0}-{1}'.format(dn_name, policy_group), filter_target='eq({0}.name, "{1}")'.format(aci_class_name, policy_group), - module_object=policy_group + module_object=policy_group, ), child_classes=[ - 'infraRsMonIfInfraPol', 'infraRsLldpIfPol', 'infraRsFcIfPol', - 'infraRsLacpPol', 'infraRsL2PortSecurityPol', 'infraRsHIfPol', - 'infraRsQosPfcIfPol', 'infraRsStpIfPol', 'infraRsQosIngressDppIfPol', - 'infraRsStormctrlIfPol', 'infraRsQosEgressDppIfPol', 'infraRsQosSdIfPol', - 'infraRsAttEntP', 'infraRsMcpIfPol', 'infraRsCdpIfPol', 'infraRsL2IfPol' - ] + 'infraRsAttEntP', + 'infraRsCdpIfPol', + 'infraRsFcIfPol', + 'infraRsHIfPol', + 'infraRsL2IfPol', + 'infraRsL2PortSecurityPol', + 'infraRsLacpPol', + 'infraRsLldpIfPol', + 'infraRsMcpIfPol', + 'infraRsMonIfInfraPol', + 'infraRsQosEgressDppIfPol', + 'infraRsQosIngressDppIfPol', + 'infraRsQosPfcIfPol', + 'infraRsQosSdIfPol', + 'infraRsStormctrlIfPol', + 'infraRsStpIfPol', + ], ) aci.get_existing() if state == 'present': - # Filter out module params with null values aci.payload( aci_class=aci_class_name, class_config=class_config_dict, child_configs=[ dict( - infraRsMonIfInfraPol=dict( + infraRsAttEntP=dict( attributes=dict( - tnMonInfraPolName=monitoring_policy - ) - ) + tDn='uni/infra/attentp-{0}'.format(aep), + ), + ), ), dict( - infraRsLldpIfPol=dict( + infraRsCdpIfPol=dict( attributes=dict( - tnLldpIfPolName=lldp_policy - ) - ) + tnCdpIfPolName=cdp_policy, + ), + ), ), dict( infraRsFcIfPol=dict( attributes=dict( - tnFcIfPolName=fibre_channel_interface_policy - ) - ) + tnFcIfPolName=fibre_channel_interface_policy, + ), + ), ), dict( - infraRsLacpPol=dict( + infraRsHIfPol=dict( attributes=dict( - tnLacpLagPolName=port_channel_policy - ) - ) + tnFabricHIfPolName=link_level_policy, + ), + ), ), dict( - infraRsL2PortSecurityPol=dict( + infraRsL2IfPol=dict( attributes=dict( - tnL2PortSecurityPolName=port_security_policy - ) - ) + tnL2IfPolName=l2_interface_policy, + ), + ), ), dict( - infraRsHIfPol=dict( + infraRsL2PortSecurityPol=dict( attributes=dict( - tnFabricHIfPolName=link_level_policy - ) - ) + tnL2PortSecurityPolName=port_security_policy, + ), + ), ), dict( - infraRsQosPfcIfPol=dict( + infraRsLacpPol=dict( attributes=dict( - tnQosPfcIfPolName=priority_flow_control_policy - ) - ) + tnLacpLagPolName=port_channel_policy, + ), + ), ), dict( - infraRsStpIfPol=dict( + infraRsLldpIfPol=dict( attributes=dict( - tnStpIfPolName=stp_interface_policy - ) - ) + tnLldpIfPolName=lldp_policy, + ), + ), ), dict( - infraRsQosIngressDppIfPol=dict( + infraRsMcpIfPol=dict( attributes=dict( - tnQosDppPolName=ingress_data_plane_policing_policy - ) - ) + tnMcpIfPolName=mcp_policy, + ), + ), ), dict( - infraRsStormctrlIfPol=dict( + infraRsMonIfInfraPol=dict( attributes=dict( - tnStormctrlIfPolName=storm_control_interface_policy - ) - ) + tnMonInfraPolName=monitoring_policy, + ), + ), ), dict( infraRsQosEgressDppIfPol=dict( attributes=dict( - tnQosDppPolName=egress_data_plane_policing_policy - ) - ) + tnQosDppPolName=egress_data_plane_policing_policy, + ), + ), ), dict( - infraRsQosSdIfPol=dict( + infraRsQosIngressDppIfPol=dict( attributes=dict( - tnQosSdIfPolName=slow_drain_policy - ) - ) + tnQosDppPolName=ingress_data_plane_policing_policy, + ), + ), ), dict( - infraRsMcpIfPol=dict( + infraRsQosPfcIfPol=dict( attributes=dict( - tnMcpIfPolName=mcp_policy - ) - ) + tnQosPfcIfPolName=priority_flow_control_policy, + ), + ), ), dict( - infraRsCdpIfPol=dict( + infraRsQosSdIfPol=dict( attributes=dict( - tnCdpIfPolName=cdp_policy - ) - ) + tnQosSdIfPolName=slow_drain_policy, + ), + ), ), dict( - infraRsL2IfPol=dict( + infraRsStormctrlIfPol=dict( attributes=dict( - tnL2IfPolName=l2_interface_policy - ) - ) + tnStormctrlIfPolName=storm_control_interface_policy, + ), + ), ), dict( - infraRsAttEntP=dict( + infraRsStpIfPol=dict( attributes=dict( - tDn='uni/infra/attentp-{0}'.format(aep) - ) - ) - ) + tnStpIfPolName=stp_interface_policy, + ), + ), + ), ], ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class=aci_class_name) - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_interface_policy_leaf_profile.py b/lib/ansible/modules/network/aci/aci_interface_policy_leaf_profile.py index 83f8c875d76..a63f6b29122 100644 --- a/lib/ansible/modules/network/aci/aci_interface_policy_leaf_profile.py +++ b/lib/ansible/modules/network/aci/aci_interface_policy_leaf_profile.py @@ -17,6 +17,7 @@ module: aci_interface_policy_leaf_profile short_description: Manage Fabric interface policy leaf profiles on Cisco ACI fabrics (infra:AccPortP) description: - Manage Fabric interface policy leaf profiles on Cisco ACI fabrics. +notes: - More information from the internal APIC class I(infra:AccPortP) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: @@ -217,7 +218,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='infraAccPortP', class_config=dict( @@ -226,10 +226,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='infraAccPortP') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_interface_policy_lldp.py b/lib/ansible/modules/network/aci/aci_interface_policy_lldp.py index f49c931689d..9f20b50dd72 100644 --- a/lib/ansible/modules/network/aci/aci_interface_policy_lldp.py +++ b/lib/ansible/modules/network/aci/aci_interface_policy_lldp.py @@ -16,6 +16,7 @@ module: aci_interface_policy_lldp short_description: Manage LLDP interface policies on Cisco ACI fabrics (lldp:IfPol) description: - Manage LLDP interface policies on Cisco ACI fabrics. +notes: - More information from the internal APIC class I(lldp:IfPol) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: @@ -33,13 +34,13 @@ options: aliases: [ descr ] receive_state: description: - - Enable or disable Receive state (FIXME!) + - Enable or disable Receive state. required: yes choices: [ disabled, enabled ] default: enabled transmit_state: description: - - Enable or Disable Transmit state (FIXME!) + - Enable or Disable Transmit state. required: false choices: [ disabled, enabled ] default: enabled @@ -176,7 +177,7 @@ from ansible.module_utils.basic import AnsibleModule def main(): argument_spec = aci_argument_spec() argument_spec.update( - lldp_policy=dict(type='str', require=False, aliases=['name']), + lldp_policy=dict(type='str', require=False, aliases=['name']), # Not required for querying all objects description=dict(type='str', aliases=['descr']), receive_state=dict(type='raw'), # Turn into a boolean in v2.9 transmit_state=dict(type='raw'), # Turn into a boolean in v2.9 @@ -214,7 +215,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='lldpIfPol', class_config=dict( @@ -225,10 +225,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='lldpIfPol') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_interface_policy_mcp.py b/lib/ansible/modules/network/aci/aci_interface_policy_mcp.py index 352df42a939..710f90f60d0 100644 --- a/lib/ansible/modules/network/aci/aci_interface_policy_mcp.py +++ b/lib/ansible/modules/network/aci/aci_interface_policy_mcp.py @@ -16,6 +16,7 @@ module: aci_interface_policy_mcp short_description: Manage MCP interface policies on Cisco ACI fabrics (mcp:IfPol) description: - Manage MCP interface policies on Cisco ACI fabrics. +notes: - More information from the internal APIC class I(mcp:IfPol) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: @@ -204,7 +205,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='mcpIfPol', class_config=dict( @@ -214,10 +214,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='mcpIfPol') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_interface_policy_port_channel.py b/lib/ansible/modules/network/aci/aci_interface_policy_port_channel.py index a262262be7e..e1b47122b8b 100644 --- a/lib/ansible/modules/network/aci/aci_interface_policy_port_channel.py +++ b/lib/ansible/modules/network/aci/aci_interface_policy_port_channel.py @@ -16,6 +16,7 @@ module: aci_interface_policy_port_channel short_description: Manage port channel interface policies on Cisco ACI fabrics (lacp:LagPol) description: - Manage port channel interface policies on Cisco ACI fabrics. +notes: - More information from the internal APIC class I(lacp:LagPol) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: @@ -288,7 +289,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='lacpLagPol', class_config=dict( @@ -301,10 +301,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='lacpLagPol') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_interface_policy_port_security.py b/lib/ansible/modules/network/aci/aci_interface_policy_port_security.py index 2a2f0f956dc..402649852d5 100644 --- a/lib/ansible/modules/network/aci/aci_interface_policy_port_security.py +++ b/lib/ansible/modules/network/aci/aci_interface_policy_port_security.py @@ -16,6 +16,7 @@ module: aci_interface_policy_port_security short_description: Manage port security on Cisco ACI fabrics (l2:PortSecurityPol) description: - Manage port security on Cisco ACI fabrics. +notes: - More information from the internal APIC class I(l2:PortSecurityPol) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: @@ -204,7 +205,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='l2PortSecurityPol', class_config=dict( @@ -214,10 +214,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='l2PortSecurityPol') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_interface_selector_to_switch_policy_leaf_profile.py b/lib/ansible/modules/network/aci/aci_interface_selector_to_switch_policy_leaf_profile.py index 8aad5dfbc84..c1bb36c3eb9 100644 --- a/lib/ansible/modules/network/aci/aci_interface_selector_to_switch_policy_leaf_profile.py +++ b/lib/ansible/modules/network/aci/aci_interface_selector_to_switch_policy_leaf_profile.py @@ -17,15 +17,13 @@ module: aci_interface_selector_to_switch_policy_leaf_profile short_description: Associates an Interface Selector Profile to a Switch Policy Leaf Profile (infra:RsAccPortP) description: - Associates an Interface Profile (Selector) to a Switch Policy Leaf Profile on Cisco ACI fabrics. +notes: +- This module requires an existing leaf profile, the module M(aci_switch_policy_leaf_profile) can be used for this. - More information from the internal APIC class I(infra:RsAccPortP) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Bruno Calogero (@brunocalogero) version_added: '2.5' -notes: -- This module can be used with M(aci_switch_policy_leaf_profile). - One first creates a leaf profile (infra:NodeP), - Finally, associates an interface profile using the provided interface selector profile (infra:RsAccPortP) options: leaf_profile: description: @@ -48,8 +46,8 @@ 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: someusername - password: somepassword + username: admin + password: SomeSecretPassword leaf_profile: sw_name interface_selector: interface_profile_name state: present @@ -57,8 +55,8 @@ EXAMPLES = r''' - name: Remove an interface selector profile associated with a switch policy leaf profile aci_interface_selector_to_switch_policy_leaf_profile: host: apic - username: someusername - password: somepassword + username: admin + password: SomeSecretPassword leaf_profile: sw_name interface_selector: interface_profile_name state: absent @@ -66,8 +64,8 @@ EXAMPLES = r''' - name: Query an interface selector profile associated with a switch policy leaf profile aci_interface_selector_to_switch_policy_leaf_profile: host: apic - username: someusername - password: somepassword + username: admin + password: SomeSecretPassword leaf_profile: sw_name interface_selector: interface_profile_name state: query @@ -185,8 +183,8 @@ from ansible.module_utils.basic import AnsibleModule def main(): argument_spec = aci_argument_spec() argument_spec.update( - leaf_profile=dict(type='str', aliases=['leaf_profile_name']), - interface_selector=dict(type='str', aliases=['name', 'interface_selector_name', 'interface_profile_name']), + 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']) ) @@ -226,16 +224,13 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module params with null values aci.payload( aci_class='infraRsAccPortP', - class_config=dict(tDn=interface_selector_tDn) + class_config=dict(tDn=interface_selector_tDn), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='infraRsAccPortP') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_l3out_route_tag_policy.py b/lib/ansible/modules/network/aci/aci_l3out_route_tag_policy.py index ee7ad13a071..9b5f979ff87 100644 --- a/lib/ansible/modules/network/aci/aci_l3out_route_tag_policy.py +++ b/lib/ansible/modules/network/aci/aci_l3out_route_tag_policy.py @@ -16,14 +16,14 @@ module: aci_l3out_route_tag_policy short_description: Manage route tag policies on Cisco ACI fabrics (l3ext:RouteTagPol) description: - Manage route tag policies on Cisco ACI fabrics. +notes: +- The C(tenant) used must exist before using this module in your playbook. + The M(aci_tenant) module can be used for this. - More information from the internal APIC class I(l3ext:RouteTagPol) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Dag Wieers (@dagwieers) version_added: '2.4' -notes: -- The C(tenant) used must exist before using this module in your playbook. - The M(aci_tenant) module can be used for this. options: rtp: description: @@ -219,7 +219,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='l3extRouteTagPol', class_config=dict( @@ -228,10 +227,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='l3extRouteTagPol') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_rest.py b/lib/ansible/modules/network/aci/aci_rest.py index 9c16e1114a7..f64a94049d6 100644 --- a/lib/ansible/modules/network/aci/aci_rest.py +++ b/lib/ansible/modules/network/aci/aci_rest.py @@ -1,6 +1,7 @@ #!/usr/bin/python # -*- coding: utf-8 -*- +# Copyright: (c) 2017, Dag Wieers (@dagwieers) # 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 @@ -16,6 +17,15 @@ 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. +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 `. +- 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 `. +- XML payloads require the C(lxml) and C(xmljson) python libraries. For JSON payloads nothing special is needed. - More information regarding the Cisco APIC REST API is available from U(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: @@ -25,7 +35,6 @@ requirements: - lxml (when using XML payload) - xmljson >= 0.1.8 (when using XML payload) - python 2.7+ (when using xmljson) -extends_documentation_fragment: aci options: method: description: @@ -52,21 +61,14 @@ options: - Name of the absolute path of the filname that includes the body of the http request being sent to the ACI fabric. aliases: [ config_file ] -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 at U(https://github.com/ansible/community/wiki/Network:-ACI-Documentation#known-issues) -- Certain payloads (or 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. - More information at U(https://github.com/ansible/community/wiki/Network:-ACI-Documentation#known-issues) -- XML payloads require the C(lxml) and C(xmljson) python libraries. For JSON payloads nothing special is needed. +extends_documentation_fragment: aci ''' EXAMPLES = r''' - name: Add a tenant using certifcate authentication aci_rest: - host: '{{ inventory_hostname }}' - username: '{{ aci_username }}' + host: apic + username: admin private_key: pki/admin.key method: post path: /api/mo/uni.xml @@ -75,8 +77,8 @@ EXAMPLES = r''' - name: Add a tenant using inline YAML aci_rest: - host: '{{ inventory_hostname }}' - username: '{{ aci_username }}' + host: apic + username: admin private_key: pki/admin.key validate_certs: no path: /api/mo/uni.json @@ -90,8 +92,8 @@ EXAMPLES = r''' - name: Add a tenant using a JSON string aci_rest: - host: '{{ inventory_hostname }}' - username: '{{ aci_username }}' + host: apic + username: admin private_key: pki/admin.key validate_certs: no path: /api/mo/uni.json @@ -109,8 +111,8 @@ EXAMPLES = r''' - name: Add a tenant using an XML string aci_rest: - host: '{{ inventory_hostname }}' - username: '{{ aci_username }}' + host: apic + username: admin private_key: pki/{{ aci_username}}.key validate_certs: no path: /api/mo/uni.xml @@ -120,17 +122,17 @@ EXAMPLES = r''' - name: Get tenants using password authentication aci_rest: - host: '{{ inventory_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' + host: apic + username: admin + password: SomeSecretPassword method: get path: /api/node/class/fvTenant.json delegate_to: localhost - name: Configure contracts aci_rest: - host: '{{ inventory_hostname }}' - username: '{{ aci_username }}' + host: apic + username: admin private_key: pki/admin.key method: post path: /api/mo/uni.xml @@ -139,8 +141,8 @@ EXAMPLES = r''' - name: Register leaves and spines aci_rest: - host: '{{ inventory_hostname }}' - username: '{{ aci_username }}' + host: apic + username: admin private_key: pki/admin.key validate_certs: no method: post @@ -155,8 +157,8 @@ EXAMPLES = r''' - name: Wait for all controllers to become ready aci_rest: - host: '{{ inventory_hostname }}' - username: '{{ aci_username }}' + 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") @@ -285,7 +287,7 @@ class ACIRESTModule(ACIModule): return False - def response_any(self, rawoutput, rest_type='xml'): + def response_type(self, rawoutput, rest_type='xml'): ''' Handle APIC response output ''' if rest_type == 'json': @@ -313,8 +315,8 @@ def main(): mutually_exclusive=[['content', 'src']], ) - path = module.params['path'] content = module.params['content'] + path = module.params['path'] src = module.params['src'] # Report missing file @@ -380,39 +382,36 @@ def main(): if aci.params['private_key'] is not None: aci.cert_auth(path=path, payload=payload) + aci.method = aci.params['method'].upper() + # Perform request resp, info = fetch_url(module, aci.url, data=payload, headers=aci.headers, - method=aci.params['method'].upper(), + method=aci.method, timeout=aci.params['timeout'], use_proxy=aci.params['use_proxy']) - if aci.params['output_level'] == 'debug': - aci.result['filter_string'] = aci.filter_string - aci.result['method'] = aci.params['method'].upper() - # aci.result['path'] = aci.path # Adding 'path' in result causes state: absent in output - aci.result['response'] = info['msg'] - aci.result['status'] = info['status'] - aci.result['url'] = aci.url + aci.response = info['msg'] + aci.status = info['status'] # Report failure if info['status'] != 200: try: # APIC error - aci.response(info['body'], rest_type) - aci.fail_json(msg='Request failed: %(code)s %(text)s' % aci.error) + aci.response_type(info['body'], rest_type) + aci.fail_json(msg='APIC Error %(code)s: %(text)s' % aci.error) except KeyError: # Connection error - aci.fail_json(msg='Request connection failed for %(url)s. %(msg)s' % info) + aci.fail_json(msg='Connection failed for %(url)s. %(msg)s' % info) - aci.response_any(resp.read(), rest_type) + aci.response_type(resp.read(), rest_type) aci.result['imdata'] = aci.imdata aci.result['totalCount'] = aci.totalCount # Report success - module.exit_json(**aci.result) + aci.exit_json(**aci.result) if __name__ == '__main__': diff --git a/lib/ansible/modules/network/aci/aci_static_binding_to_epg.py b/lib/ansible/modules/network/aci/aci_static_binding_to_epg.py index a8d2dc2ea29..2cd8683bd63 100644 --- a/lib/ansible/modules/network/aci/aci_static_binding_to_epg.py +++ b/lib/ansible/modules/network/aci/aci_static_binding_to_epg.py @@ -17,14 +17,14 @@ module: aci_static_binding_to_epg short_description: Bind static paths to EPGs on Cisco ACI fabrics (fv:RsPathAtt) description: - Bind static paths to EPGs on Cisco ACI fabrics. +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. - More information from the internal APIC classes I(fv:RsPathAtt) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Bruno Calogero (@brunocalogero) version_added: '2.5' -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. options: tenant: description: @@ -59,27 +59,31 @@ options: 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 the mode to C(trunk). - choices: [ access, trunk, 802.1p ] + choices: [ 802.1p, access, native, regular, tagged, trunk, untagged ] default: trunk - aliases: [ mode, interface_mode_name ] + aliases: [ interface_mode_name, mode ] interface_type: description: - The type of interface for the static EPG deployement. - The APIC defaults the C(interface_type) to C(switch_port). - choices: [ switch_port, vpc, port_channel, fex ] + choices: [ fex, port_channel, switch_port, vpc ] default: switch_port - pod: + pod_id: description: - The pod number part of the tDn. - - C(pod) is usually an integer below 10. - aliases: [ pod_number ] + - C(pod_id) is usually an integer below 10. + 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. - aliases: [ paths, leaves, nodes, switches ] + - The C(leafs) value is usually something like '101' or '101-102' depending on C(connection_type). + aliases: [ leaves, nodes, paths, switches ] interface: description: - The C(interface) string value part of the tDn. @@ -109,16 +113,117 @@ EXAMPLES = r''' epg: accessport_epg1 encap_id: 222 deploy_immediacy: lazy - interface_mode: access + interface_mode: untagged interface_type: switch_port - pod: 1 + pod_id: 1 leafs: 101 interface: '1/7' 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: string + sample: '' +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: string + sample: ?rsp-prop-include=config-only +method: + description: The HTTP method used for the request to the APIC + returned: failure or debug + type: string + sample: POST +response: + description: The HTTP response from the APIC + returned: failure or debug + type: string + 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: string + sample: https://10.11.12.13/api/mo/uni/tn-production.json ''' from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec @@ -130,21 +235,18 @@ from ansible.module_utils.basic import AnsibleModule def main(): argument_spec = aci_argument_spec() argument_spec.update( - tenant=dict(type='str', aliases=['tenant_name']), - ap=dict(type='str', aliases=['app_profile', 'app_profile_name']), - epg=dict(type='str', aliases=['epg_name']), + 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 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=['access', 'tagged', '802.1p'], aliases=['mode', 'interface_mode_name']), - interface_type=dict(type='str', choices=['switch_port', 'vpc', 'port_channel', 'fex'], required=True), - # NOTE: C(pod) is usually an integer below 10. - pod=dict(type='int', aliases=['pod_number']), - # NOTE: C(leafs) is usually something like '101' or '101-102' depending on C(connection_type). - leafs=dict(type='list', aliases=['paths', 'leaves', 'nodes', 'switches']), - # NOTE: C(interface) is usually a policy group like: "test-IntPolGrp" or an interface of the following format: "1/7" depending on C(interface_type). + 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']), interface=dict(type='str'), - # NOTE: C(extpaths) is only used if C(interface_type) is C(fex), it is usually something like '1011'(int) extpaths=dict(type='int'), state=dict(type='str', default='present', choices=['absent', 'present', 'query']), ) @@ -153,9 +255,9 @@ def main(): argument_spec=argument_spec, supports_check_mode=True, required_if=[ - ['state', 'absent', ['tenant', 'ap', 'epg', 'interface_type', 'pod', 'leafs', 'interface']], - ['state', 'present', ['tenant', 'ap', 'epg', 'encap_id', 'interface_type', 'pod', 'leafs', 'interface']], ['interface_type', 'fex', ['extpaths']], + ['state', 'absent', ['ap', 'epg', 'interface', 'leafs', 'pod_id', 'tenant']], + ['state', 'present', ['ap', 'encap_id', 'epg', 'interface', 'leafs', 'pod_id', 'tenant']], ], ) @@ -167,7 +269,7 @@ def main(): deploy_immediacy = module.params['deploy_immediacy'] interface_mode = module.params['interface_mode'] interface_type = module.params['interface_type'] - pod = module.params['pod'] + pod_id = module.params['pod_id'] # Users are likely to use integers for leaf IDs, which would raise an exception when using the join method leafs = [str(leaf) for leaf in module.params['leafs']] if leafs is not None: @@ -201,18 +303,26 @@ def main(): else: module.fail_json(msg='Valid VLAN assigments are from 1 to 4096') + INTERFACE_MODE_MAPPING = { + '802.1p': 'native', + 'access': 'untagged', + 'native': 'native', + 'regular': 'regular', + 'tagged': 'regular', + 'trunk': 'regular', + 'untagged': 'untagged', + } + INTERFACE_TYPE_MAPPING = dict( - # NOTE: C(interface) can be a policy group like: 'test-IntPolGrp' or of following format: '1/7', C(leafs) can only be something like '101' - switch_port='topology/pod-{0}/paths-{1}/pathep-[eth{2}]'.format(pod, leafs, interface), - # NOTE: C(interface) can be a policy group like: 'test-IntPolGrp' or of following format: '1/7', C(leafs) can only be something like '101' - port_channel='topology/pod-{0}/paths-{1}/pathep-[eth{2}]'.format(pod, leafs, interface), - # NOTE: C(interface) can be a policy group like: 'test-IntPolGrp', C(leafs) can be something like '101-102' - vpc='topology/pod-{0}/protpaths-{1}/pathep-[{2}]'.format(pod, leafs, interface), - # NOTE: C(interface) can be of the following format: '1/7', C(leafs) can only be like '101', C(extpaths) can only be like '1011' - fex='topology/pod-{0}/paths-{1}/extpaths-{2}/pathep-[eth{3}]'.format(pod, leafs, extpaths, interface), + fex='topology/pod-{0}/paths-{1}/extpaths-{2}/pathep-[eth{3}]'.format(pod_id, leafs, extpaths, interface), + port_channel='topology/pod-{0}/paths-{1}/pathep-[eth{2}]'.format(pod_id, leafs, interface), + switch_port='topology/pod-{0}/paths-{1}/pathep-[eth{2}]'.format(pod_id, leafs, interface), + vpc='topology/pod-{0}/protpaths-{1}/pathep-[{2}]'.format(pod_id, leafs, interface), ) static_path = INTERFACE_TYPE_MAPPING[interface_type] + if interface_mode is not None: + interface_mode = INTERFACE_MODE_MAPPING[interface_mode] aci = ACIModule(module) aci.construct_url( @@ -245,7 +355,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='fvRsPathAtt', class_config=dict( @@ -257,16 +366,14 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='fvRsPathAtt') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': aci.delete_config() - module.exit_json(**aci.result) + aci.exit_json() if __name__ == "__main__": diff --git a/lib/ansible/modules/network/aci/aci_switch_leaf_selector.py b/lib/ansible/modules/network/aci/aci_switch_leaf_selector.py index ec1e9964a0a..7d410c178ce 100644 --- a/lib/ansible/modules/network/aci/aci_switch_leaf_selector.py +++ b/lib/ansible/modules/network/aci/aci_switch_leaf_selector.py @@ -17,14 +17,14 @@ module: aci_switch_leaf_selector short_description: Add a leaf Selector with Node Block Range and Policy Group to a Switch Policy Leaf Profile on Cisco ACI fabrics description: - Add a leaf Selector with Node Block range and Policy Group to a Switch Policy Leaf Profile on Cisco ACI fabrics. +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), - More information from the internal APIC class I(infra:LeafS), I(infra:NodeBlk), I(infra:RsAccNodePGrp) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Bruno Calogero (@brunocalogero) version_added: '2.5' -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), options: description: description: @@ -69,8 +69,8 @@ EXAMPLES = r''' - name: adding a switch policy leaf profile selector associated Node Block range (w/ policy group) aci_switch_leaf_selector: host: apic - username: someusername - password: somepassword + username: admin + password: SomeSecretPassword leaf_profile: sw_name leaf: leaf_selector_name leaf_node_blk: node_blk_name @@ -82,8 +82,8 @@ EXAMPLES = r''' - name: adding a switch policy leaf profile selector associated Node Block range (w/o policy group) aci_switch_leaf_selector: host: apic - username: someusername - password: somepassword + username: admin + password: SomeSecretPassword leaf_profile: sw_name leaf: leaf_selector_name leaf_node_blk: node_blk_name @@ -94,8 +94,8 @@ EXAMPLES = r''' - name: Removing a switch policy leaf profile selector aci_switch_leaf_selector: host: apic - username: someusername - password: somepassword + username: admin + password: SomeSecretPassword leaf_profile: sw_name leaf: leaf_selector_name state: absent @@ -103,8 +103,8 @@ EXAMPLES = r''' - name: Querying a switch policy leaf profile selector aci_switch_leaf_selector: host: apic - username: someusername - password: somepassword + username: admin + password: SomeSecretPassword leaf_profile: sw_name leaf: leaf_selector_name state: query @@ -223,8 +223,8 @@ def main(): argument_spec = aci_argument_spec() argument_spec.update({ 'description': dict(type='str'), - 'leaf_profile': dict(type='str', aliases=['leaf_profile_name']), - 'leaf': dict(type='str', aliases=['name', 'leaf_name', 'leaf_profile_leaf_name', 'leaf_selector_name']), + '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'), 'from': dict(type='int', aliases=['node_blk_range_from', 'from_range', 'range_from']), @@ -268,14 +268,13 @@ def main(): module_object=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'] + child_classes=['infraNodeBlk', 'infraRsAccNodePGrp'], ) aci.get_existing() if state == 'present': - # Filter out module params with null values aci.payload( aci_class='infraLeafS', class_config=dict( @@ -290,23 +289,21 @@ def main(): name=leaf_node_blk, from_=from_, to_=to_, - ) - ) + ), + ), ), dict( infraRsAccNodePGrp=dict( attributes=dict( tDn='uni/infra/funcprof/accnodepgrp-{0}'.format(policy_group), - ) - ) + ), + ), ), ], ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='infraLeafS') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_switch_policy_leaf_profile.py b/lib/ansible/modules/network/aci/aci_switch_policy_leaf_profile.py index bb34cbe7789..882c425314a 100644 --- a/lib/ansible/modules/network/aci/aci_switch_policy_leaf_profile.py +++ b/lib/ansible/modules/network/aci/aci_switch_policy_leaf_profile.py @@ -17,6 +17,7 @@ module: aci_switch_policy_leaf_profile short_description: Create switch policy leaf profiles on Cisco ACI fabrics (infra:NodeP) description: - Create switch policy leaf profiles on Cisco ACI fabrics. +notes: - More information from the internal APIC class I(infra:NodeP) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: @@ -26,7 +27,7 @@ options: leaf_profile: description: - The name of the Leaf Profile. - aliases: [ name, leaf_profile_name ] + aliases: [ leaf_profile_name, name ] description: description: - Description for the Leaf Profile. @@ -44,8 +45,8 @@ EXAMPLES = r''' - name: creating a Leaf Profile with description aci_switch_policy_leaf_profile: host: apic - username: someusername - password: somepassword + username: admin + password: SomeSecretPassword leaf_profile: sw_name description: sw_description state: present @@ -53,16 +54,16 @@ EXAMPLES = r''' - name: Deleting a Leaf Profile aci_switch_policy_leaf_profile: host: apic - username: someusername - password: somepassword + username: admin + password: SomeSecretPassword leaf_profile: sw_name state: absent - name: Query a Leaf Profile aci_switch_policy_leaf_profile: host: apic - username: someusername - password: somepassword + username: admin + password: SomeSecretPassword leaf_profile: sw_name state: query ''' @@ -179,7 +180,7 @@ from ansible.module_utils.basic import AnsibleModule def main(): argument_spec = aci_argument_spec() argument_spec.update( - leaf_profile=dict(type='str', aliases=['name', 'leaf_profile_name']), + 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']), ) @@ -203,26 +204,23 @@ def main(): aci_class='infraNodeP', aci_rn='infra/nprof-{0}'.format(leaf_profile), filter_target='eq(infraNodeP.name, "{0}")'.format(leaf_profile), - module_object=leaf_profile - ) + module_object=leaf_profile, + ), ) aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='infraNodeP', class_config=dict( name=leaf_profile, descr=description, - ) + ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='infraNodeP') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_switch_policy_vpc_protection_group.py b/lib/ansible/modules/network/aci/aci_switch_policy_vpc_protection_group.py index 4fd2c015c4b..081da4e0193 100644 --- a/lib/ansible/modules/network/aci/aci_switch_policy_vpc_protection_group.py +++ b/lib/ansible/modules/network/aci/aci_switch_policy_vpc_protection_group.py @@ -17,6 +17,7 @@ module: aci_switch_policy_vpc_protection_group short_description: Create switch policy Explicit vPC Protection Group on Cisco ACI fabrics (fabric:ExplicitGEp, fabric:NodePEp). description: - Create switch policy Explicit vPC Protection Group on Cisco ACI fabrics. +notes: - More information from the internal APIC class I(fabric:ExplicitGEp) and I(fabric:NodePEp) at U(https://developer.cisco.com/site/aci/docs/apis/apic-mim-ref/). author: @@ -37,7 +38,6 @@ options: description: - The vPC domain policy to be associated with the Explicit vPC Protection Group. aliases: [ vpc_domain_policy_name ] - required: no switch_1_id: description: - The ID of the first Leaf Switch for the Explicit vPC Protection Group. @@ -58,9 +58,9 @@ extends_documentation_fragment: aci EXAMPLES = r''' - name: Add Explicit vPC Protection Group aci_switch_policy_vpc_protection_group: - host: "{{ aci_hostname }}" - username: "{{ aci_username }}" - password: "{{ aci_password }}" + host: apic + username: admin + password: SomeSecretPassword protection_group: protectiongroupname protection_group_id: 6 vpc_domain_policy: vpcdomainpolicyname @@ -70,15 +70,116 @@ EXAMPLES = r''' - name: Remove Explicit vPC Protection Group aci_switch_policy_vpc_protection_group: - host: "{{ aci_hostname }}" - username: "{{ aci_username }}" - password: "{{ aci_password }}" + host: apic + username: admin + password: SomeSecretPassword protection_group: protectiongroupname 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: string + sample: '' +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: string + sample: ?rsp-prop-include=config-only +method: + description: The HTTP method used for the request to the APIC + returned: failure or debug + type: string + sample: POST +response: + description: The HTTP response from the APIC + returned: failure or debug + type: string + 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: string + sample: https://10.11.12.13/api/mo/uni/tn-production.json ''' from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec @@ -88,7 +189,7 @@ from ansible.module_utils.basic import AnsibleModule def main(): argument_spec = aci_argument_spec() argument_spec.update( - protection_group=dict(type='str', aliases=['name', 'protection_group_name']), + 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'), @@ -118,19 +219,17 @@ def main(): aci_class='fabricExplicitGEp', aci_rn='fabric/protpol/expgep-{0}'.format(protection_group), filter_target='eq(fabricExplicitGEp.name, "{0}")'.format(protection_group), - module_object=protection_group + module_object=protection_group, ), - child_classes=['fabricNodePEp', 'fabricNodePEp', 'fabricRsVpcInstPol'] + child_classes=['fabricNodePEp', 'fabricNodePEp', 'fabricRsVpcInstPol'], ) aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='fabricExplicitGEp', class_config=dict( - dn='uni/fabric/protpol/expgep-{0}'.format(protection_group), name=protection_group, id=protection_group_id, rn='expgep-{0}'.format(protection_group), @@ -139,35 +238,31 @@ def main(): dict( fabricNodePEp=dict( attributes=dict( - dn='uni/fabric/protpol/expgep-{0}/nodepep-{1}'.format(protection_group, switch_1_id), id='{0}'.format(switch_1_id), rn='nodepep-{0}'.format(switch_1_id), - ) - ) + ), + ), ), dict( fabricNodePEp=dict( attributes=dict( - dn='uni/fabric/protpol/expgep-{0}/nodepep-{1}'.format(protection_group, switch_2_id), id='{0}'.format(switch_2_id), rn='nodepep-{0}'.format(switch_2_id), - ) - ) + ), + ), ), dict( fabricRsVpcInstPol=dict( attributes=dict( tnVpcInstPolName=vpc_domain_policy, - ) - ) + ), + ), ), - ] + ], ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='fabricExplicitGEp') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_taboo_contract.py b/lib/ansible/modules/network/aci/aci_taboo_contract.py index 6cbabd6c64a..02db78c5856 100644 --- a/lib/ansible/modules/network/aci/aci_taboo_contract.py +++ b/lib/ansible/modules/network/aci/aci_taboo_contract.py @@ -17,14 +17,14 @@ module: aci_taboo_contract short_description: Manage taboo contracts on Cisco ACI fabrics (vz:BrCP) description: - Manage taboo contracts on Cisco ACI fabrics. +notes: +- The C(tenant) used must exist before using this module in your playbook. + The M(aci_tenant) module can be used for this. - More information from the internal APIC class I(vz:BrCP) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Dag Wieers (@dagwieers) version_added: '2.4' -notes: -- The C(tenant) used must exist before using this module in your playbook. - The M(aci_tenant) module can be used for this. options: taboo_contract: description: @@ -58,34 +58,34 @@ extends_documentation_fragment: aci EXAMPLES = r''' - name: Add taboo contract aci_taboo_contract: - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' + host: apic + username: admin + password: SomeSecretPassword tenant: ansible_test taboo_contract: taboo_contract_test state: present - name: Remove taboo contract aci_taboo_contract: - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' + host: apic + username: admin + password: SomeSecretPassword tenant: ansible_test taboo_contract: taboo_contract_test state: absent - name: Query all taboo contracts aci_taboo_contract: - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' + host: apic + username: admin + password: SomeSecretPassword state: query - name: Query a specific taboo contract aci_taboo_contract: - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' + host: apic + username: admin + password: SomeSecretPassword tenant: ansible_test taboo_contract: taboo_contract_test state: query @@ -246,7 +246,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='vzTaboo', class_config=dict( @@ -256,10 +255,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='vzTaboo') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_tenant.py b/lib/ansible/modules/network/aci/aci_tenant.py index 8428de946d6..2efcfae6e76 100644 --- a/lib/ansible/modules/network/aci/aci_tenant.py +++ b/lib/ansible/modules/network/aci/aci_tenant.py @@ -16,6 +16,7 @@ module: aci_tenant short_description: Manage tenants on Cisco ACI fabrics (fv:Tenant) description: - Manage tenants on Cisco ACI fabrics. +notes: - More information from the internal APIC class I(fv:Tenant) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: @@ -202,9 +203,9 @@ def main(): ], ) - tenant = module.params['tenant'] description = module.params['description'] state = module.params['state'] + tenant = module.params['tenant'] aci = ACIModule(module) aci.construct_url( @@ -218,7 +219,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='fvTenant', class_config=dict( @@ -227,10 +227,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='fvTenant') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_tenant_action_rule_profile.py b/lib/ansible/modules/network/aci/aci_tenant_action_rule_profile.py index da47a836534..1877ab9f689 100644 --- a/lib/ansible/modules/network/aci/aci_tenant_action_rule_profile.py +++ b/lib/ansible/modules/network/aci/aci_tenant_action_rule_profile.py @@ -16,14 +16,14 @@ module: aci_tenant_action_rule_profile short_description: Manage action rule profiles on Cisco ACI fabrics (rtctrl:AttrP) description: - Manage action rule profiles on Cisco ACI fabrics. +notes: +- The C(tenant) used must exist before using this module in your playbook. + The M(aci_tenant) module can be used for this. - More information from the internal APIC class I(rtctrl:AttrP) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Dag Wieers (@dagwieers) version_added: '2.4' -notes: -- The C(tenant) used must exist before using this module in your playbook. - The M(aci_tenant) module can be used for this. options: action_rule: description: @@ -49,9 +49,9 @@ extends_documentation_fragment: aci # FIXME: Add more, better examples EXAMPLES = r''' - aci_tenant_action_rule_profile: - host: '{{ inventory_hostname }}' - username: '{{ username }}' - password: '{{ password }}' + host: apic + username: admin + password: SomeSecretPassword action_rule: '{{ action_rule }}' description: '{{ descr }}' tenant: '{{ tenant }}' @@ -210,20 +210,16 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='rtctrlAttrP', class_config=dict( name=action_rule, descr=description, ), - ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='rtctrlAttrP') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_tenant_ep_retention_policy.py b/lib/ansible/modules/network/aci/aci_tenant_ep_retention_policy.py index 8f832835a5d..3e5cf7ef113 100755 --- a/lib/ansible/modules/network/aci/aci_tenant_ep_retention_policy.py +++ b/lib/ansible/modules/network/aci/aci_tenant_ep_retention_policy.py @@ -16,14 +16,14 @@ module: aci_tenant_ep_retention_policy short_description: Manage End Point (EP) retention protocol policies on Cisco ACI fabrics (fv:EpRetPol) description: - Manage End Point (EP) retention protocol policies on Cisco ACI fabrics. +notes: +- The C(tenant) used must exist before using this module in your playbook. + The M(aci_tenant) module can be used for this. - More information from the internal APIC class I(fv:EpRetPol) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Swetha Chunduri (@schunduri) version_added: '2.4' -notes: -- The C(tenant) used must exist before using this module in your playbook. - The M(aci_tenant) module can be used for this. options: tenant: description: @@ -231,7 +231,7 @@ 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 EPRs + tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects epr_policy=dict(type='str', aliases=['epr_name', 'name']), bounce_age=dict(type='int'), bounce_trigger=dict(type='str', choices=['coop', 'flood']), @@ -304,7 +304,6 @@ def main(): aci.get_existing() if state == 'present': - # filter out module parameters with null values aci.payload( aci_class='fvEpRetPol', class_config=dict( @@ -319,10 +318,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='fvEpRetPol') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_tenant_span_dst_group.py b/lib/ansible/modules/network/aci/aci_tenant_span_dst_group.py index 7f23e5570fb..e05e1e4ff03 100644 --- a/lib/ansible/modules/network/aci/aci_tenant_span_dst_group.py +++ b/lib/ansible/modules/network/aci/aci_tenant_span_dst_group.py @@ -16,14 +16,14 @@ module: aci_tenant_span_dst_group short_description: Manage SPAN destination groups on Cisco ACI fabrics (span:DestGrp) description: - Manage SPAN destination groups on Cisco ACI fabrics. +notes: +- The C(tenant) used must exist before using this module in your playbook. + The M(aci_tenant) module can be used for this. - More information from the internal APIC class I(span:DestGrp) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Dag Wieers (@dagwieers) version_added: '2.4' -notes: -- The C(tenant) used must exist before using this module in your playbook. - The M(aci_tenant) module can be used for this. options: dst_group: description: @@ -51,9 +51,9 @@ extends_documentation_fragment: aci # FIXME: Add more, better examples EXAMPLES = r''' - aci_tenant_span_dst_group: - host: '{{ inventory_hostname }}' - username: '{{ username }}' - password: '{{ password }}' + host: apic + username: admin + password: SomeSecretPassword dst_group: '{{ dst_group }}' description: '{{ descr }}' tenant: '{{ tenant }}' @@ -212,7 +212,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='spanDestGrp', class_config=dict( @@ -221,10 +220,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='spanDestGrp') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_tenant_span_src_group.py b/lib/ansible/modules/network/aci/aci_tenant_span_src_group.py index 25f3108c98f..d6560313b79 100755 --- a/lib/ansible/modules/network/aci/aci_tenant_span_src_group.py +++ b/lib/ansible/modules/network/aci/aci_tenant_span_src_group.py @@ -16,14 +16,14 @@ module: aci_tenant_span_src_group short_description: Manage SPAN source groups on Cisco ACI fabrics (span:SrcGrp) description: - Manage SPAN source groups on Cisco ACI fabrics. +notes: +- The C(tenant) used must exist before using this module in your playbook. + The M(aci_tenant) module can be used for this. - More information from the internal APIC class I(span:SrcGrp) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Jacob McGill (@jmcgill298) version_added: '2.4' -notes: -- The C(tenant) used must exist before using this module in your playbook. - The M(aci_tenant) module can be used for this. options: admin_state: description: @@ -56,14 +56,14 @@ extends_documentation_fragment: aci EXAMPLES = r''' - aci_tenant_span_src_group: - host:"{{ inventory_hostname }}" - username:"{{ username }}" - password:"{{ password }}" - tenant:"{{ tenant }}" - src_group:"{{ src_group }}" - dst_group:"{{ dst_group }}" - admin_state:"{{ admin_state }}" - description:"{{ description }}" + host: apic + username: admin + password: SomeSecretPassword + tenant: production + src_group: "{{ src_group }}" + dst_group: "{{ dst_group }}" + admin_state: "{{ admin_state }}" + description: "{{ description }}" ''' RETURN = r''' @@ -225,7 +225,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='spanSrcGrp', class_config=dict( @@ -236,10 +235,8 @@ def main(): child_configs=[{'spanSpanLbl': {'attributes': {'name': dst_group}}}], ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='spanSrcGrp') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_tenant_span_src_group_to_dst_group.py b/lib/ansible/modules/network/aci/aci_tenant_span_src_group_to_dst_group.py index fb8c82503b6..2688754e2ee 100755 --- a/lib/ansible/modules/network/aci/aci_tenant_span_src_group_to_dst_group.py +++ b/lib/ansible/modules/network/aci/aci_tenant_span_src_group_to_dst_group.py @@ -16,14 +16,14 @@ module: aci_tenant_span_src_group_to_dst_group short_description: Manage SPAN source group to destination group bindings on Cisco ACI fabrics (span:SpanLbl) description: - Manage SPAN source groups' associated destinaton group on Cisco ACI fabrics. +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. - More information from the internal APIC class I(span:SrcGrp) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Jacob McGill (@jmcgill298) version_added: '2.4' -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. options: description: description: @@ -50,13 +50,13 @@ extends_documentation_fragment: aci EXAMPLES = r''' - aci_tenant_span_src_group_to_dst_group: - host:"{{ inventory_hostname }}" - username:"{{ username }}" - password:"{{ password }}" - tenant:"{{ tenant }}" - src_group:"{{ src_group }}" - dst_group:"{{ dst_group }}" - description:"{{ description }}" + host: apic + username: admin + password: SomeSecretPassword + tenant: production + src_group: "{{ src_group }}" + dst_group: "{{ dst_group }}" + description: "{{ description }}" ''' RETURN = r''' @@ -172,10 +172,10 @@ def main(): argument_spec = aci_argument_spec() argument_spec.update( description=dict(type='str', aliases=['descr']), - dst_group=dict(type='str'), - src_group=dict(type='str'), + dst_group=dict(type='str'), # Not required for querying all objects + src_group=dict(type='str'), # Not required for querying all objects state=dict(type='str', default='present', choices=['absent', 'present', 'query']), - tenant=dict(type='str', aliases=['tenant_name']), + tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects method=dict(type='str', choices=['delete', 'get', 'post'], aliases=['action'], removed_in_version='2.6'), # Deprecated starting from v2.6 protocol=dict(type='str', removed_in_version='2.6'), # Deprecated in v2.6 ) @@ -220,7 +220,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='spanSpanLbl', class_config=dict( @@ -229,10 +228,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='spanSpanLbl') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_vlan_pool.py b/lib/ansible/modules/network/aci/aci_vlan_pool.py index fdecbb7217b..79526ae1c64 100644 --- a/lib/ansible/modules/network/aci/aci_vlan_pool.py +++ b/lib/ansible/modules/network/aci/aci_vlan_pool.py @@ -18,6 +18,7 @@ module: aci_vlan_pool short_description: Manage VLAN pools on Cisco ACI fabrics (fvns:VlanInstP) description: - Manage VLAN pools on Cisco ACI fabrics. +notes: - More information from the internal APIC class I(fvns:VlanInstP) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: @@ -197,7 +198,7 @@ def main(): argument_spec = aci_argument_spec() argument_spec.update( description=dict(type='str', aliases=['descr']), - pool=dict(type='str', aliases=['name', 'pool_name']), + 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']), ) @@ -238,20 +239,17 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='fvnsVlanInstP', class_config=dict( allocMode=pool_allocation_mode, descr=description, name=pool, - ) + ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='fvnsVlanInstP') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_vlan_pool_encap_block.py b/lib/ansible/modules/network/aci/aci_vlan_pool_encap_block.py index d7f6b701283..730d6e76f11 100644 --- a/lib/ansible/modules/network/aci/aci_vlan_pool_encap_block.py +++ b/lib/ansible/modules/network/aci/aci_vlan_pool_encap_block.py @@ -18,14 +18,14 @@ module: aci_vlan_pool_encap_block short_description: Manage encap blocks assigned to VLAN pools on Cisco ACI fabrics (fvns:EncapBlk) description: - Manage VLAN encap blocks that are assigned to VLAN pools on Cisco ACI fabrics. +notes: +- The C(pool) must exist in order to add or delete a encap block. - More information from the internal APIC class I(fvns:EncapBlk) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Jacob McGill (@jmcgill298) - Dag Wieers (@dagwieers) version_added: '2.5' -requirements: -- The C(pool) must exist in order to add or delete a encap block. options: allocation_mode: description: @@ -227,11 +227,11 @@ def main(): argument_spec.update( allocation_mode=dict(type='str', aliases=['mode'], choices=['dynamic', 'inherit', 'static']), description=dict(type='str', aliases=['descr']), - pool=dict(type='str', aliases=['pool_name']), + 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']), - block_name=dict(type='str', aliases=['name']), - block_end=dict(type='int', aliases=['end']), - block_start=dict(type='int', aliases=["start"]), + 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 state=dict(type='str', default='present', choices=['absent', 'present', 'query']), ) @@ -327,7 +327,6 @@ def main(): aci.get_existing() if state == 'present': - # Filter out module parameters with null values aci.payload( aci_class='fvnsEncapBlk', class_config={ @@ -336,13 +335,11 @@ def main(): "from": encap_start, "name": block_name, "to": encap_end, - } + }, ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='fvnsEncapBlk') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/lib/ansible/modules/network/aci/aci_vrf.py b/lib/ansible/modules/network/aci/aci_vrf.py index d2a2afc3f2b..c7bec9bc224 100644 --- a/lib/ansible/modules/network/aci/aci_vrf.py +++ b/lib/ansible/modules/network/aci/aci_vrf.py @@ -17,14 +17,14 @@ short_description: Manage VRF (private networks aka. contexts) on Cisco ACI fabr description: - Manage VRF (private networks aka. contexts) on Cisco ACI fabrics. - Each context is a private network associated to a tenant, i.e. VRF. +notes: +- The C(tenant) used must exist before using this module in your playbook. + The M(aci_tenant) module can be used for this. - More information from the internal APIC class I(fv:Ctx) at U(https://developer.cisco.com/docs/apic-mim-ref/). author: - Jacob McGill (@jmcgill298) version_added: '2.4' -notes: -- The C(tenant) used must exist before using this module in your playbook. - The M(aci_tenant) module can be used for this. options: tenant: description: @@ -247,10 +247,10 @@ def main(): module_object=vrf, ), ) + aci.get_existing() if state == 'present': - # Filter out module params with null values aci.payload( aci_class='fvCtx', class_config=dict( @@ -261,10 +261,8 @@ def main(): ), ) - # Generate config diff which will be used as POST request body aci.get_diff(aci_class='fvCtx') - # Submit changes if module not in check_mode and the proposed is different than existing aci.post_config() elif state == 'absent': diff --git a/test/integration/targets/aci_access_port_to_interface_policy_leaf_profile/tasks/main.yml b/test/integration/targets/aci_access_port_to_interface_policy_leaf_profile/tasks/main.yml index 34ebe08d83b..b88c45f8099 100644 --- a/test/integration/targets/aci_access_port_to_interface_policy_leaf_profile/tasks/main.yml +++ b/test/integration/targets/aci_access_port_to_interface_policy_leaf_profile/tasks/main.yml @@ -1,5 +1,5 @@ # Test code for the ACI modules -# Copyright 2017, Bruno Calogero +# Copyright: (c) 2017, Bruno Calogero # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) diff --git a/test/integration/targets/aci_aep_to_domain/tasks/main.yml b/test/integration/targets/aci_aep_to_domain/tasks/main.yml index d1d011e8593..29a43507d89 100644 --- a/test/integration/targets/aci_aep_to_domain/tasks/main.yml +++ b/test/integration/targets/aci_aep_to_domain/tasks/main.yml @@ -1,5 +1,5 @@ # Test code for the ACI modules -# Copyright 2018, Dag Wieers (@dagwieers) +# Copyright: (c) 2018, Dag Wieers (@dagwieers) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) @@ -65,6 +65,15 @@ aci_aep_to_domain: *binding_present register: nm_add_binding +- name: Verify add_binding + assert: + that: + - cm_add_binding.changed == nm_add_binding.changed == true + - '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 @@ -74,15 +83,10 @@ aci_aep_to_domain: *binding_present register: nm_add_binding_again -- name: Verify add_binding +- name: Verify add_binding_again assert: that: - - cm_add_binding.changed == nm_add_binding.changed == true - cm_add_binding_again.changed == nm_add_binding_again.changed == false - - '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"}}}]' # QUERY ALL BINDINGS @@ -148,6 +152,13 @@ aci_aep_to_domain: *binding_absent register: nm_remove_binding +- name: Verify remove_binding + assert: + that: + - cm_remove_binding.changed == nm_remove_binding.changed == true + - '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 @@ -157,13 +168,10 @@ aci_aep_to_domain: *binding_absent register: nm_remove_binding_again -- name: Verify remove_binding +- name: Verify remove_binding_again assert: that: - - cm_remove_binding.changed == nm_remove_binding.changed == true - cm_remove_binding_again.changed == nm_remove_binding_again.changed == false - - '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 == [] # QUERY NON-EXISTING BINDING diff --git a/test/integration/targets/aci_ap/tasks/main.yml b/test/integration/targets/aci_ap/tasks/main.yml index 73d1b27b0a9..6d3da16fd4d 100644 --- a/test/integration/targets/aci_ap/tasks/main.yml +++ b/test/integration/targets/aci_ap/tasks/main.yml @@ -1,5 +1,5 @@ # Test code for the ACI modules -# Copyright 2017, Jacob McGill +# Copyright: (c) 2017, Dag Wieers (@dagwieers) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) diff --git a/test/integration/targets/aci_contract/tasks/main.yml b/test/integration/targets/aci_contract/tasks/main.yml index dbb14e024bb..32519135c8c 100644 --- a/test/integration/targets/aci_contract/tasks/main.yml +++ b/test/integration/targets/aci_contract/tasks/main.yml @@ -1,5 +1,5 @@ # Test code for the ACI modules -# Copyright 2017, Jacob McGill +# Copyright: (c) 2018, Dag Wieers (@dagwieers) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) @@ -39,6 +39,15 @@ aci_domain: *domain_present register: nm_add_domain +- name: Verify add_domain + assert: + that: + - cm_add_domain.changed == nm_add_domain.changed == true + - 'cm_add_domain.sent == nm_add_domain.sent == {"fcDomP": {"attributes": {"name": "fc_dom"}}}' + - 'cm_add_domain.proposed == nm_add_domain.proposed == {"fcDomP": {"attributes": {"name": "fc_dom"}}}' + - cm_add_domain.current == cm_add_domain.previous == nm_add_domain.previous == [] + - 'nm_add_domain.current == [{"fcDomP": {"attributes": {"dn": "uni/fc-fc_dom", "name": "fc_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}}}]' + - name: Add FC domain again (check_mode) aci_domain: *domain_present check_mode: yes @@ -48,15 +57,10 @@ aci_domain: *domain_present register: nm_add_domain_again -- name: Verify add_domain +- name: Verify add_domain_again assert: that: - - cm_add_domain.changed == nm_add_domain.changed == true - cm_add_domain_again.changed == nm_add_domain_again.changed == false - - 'cm_add_domain.sent == nm_add_domain.sent == {"fcDomP": {"attributes": {"name": "fc_dom"}}}' - - 'cm_add_domain.proposed == nm_add_domain.proposed == {"fcDomP": {"attributes": {"name": "fc_dom"}}}' - - cm_add_domain.current == cm_add_domain.previous == nm_add_domain.previous == [] - - 'nm_add_domain.current == [{"fcDomP": {"attributes": {"dn": "uni/fc-fc_dom", "name": "fc_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}}}]' # QUERY ALL DOMAINS @@ -82,8 +86,8 @@ assert: that: - cm_query_all_domains.changed == nm_query_all_domains.changed == false - # NOTE: Order of domains is not stable between calls - #- cm_query_all_domains == nm_query_all_domains + - cm_query_all_domains == nm_query_all_domains + - nm_query_all_domains.current|length >= 1 # QUERY A DOMAIN @@ -119,6 +123,13 @@ aci_domain: *domain_absent register: nm_remove_domain +- name: Verify remove_domain + assert: + that: + - cm_remove_domain.changed == nm_remove_domain.changed == true + - 'cm_remove_domain.current == cm_remove_domain.previous == nm_remove_domain.previous == [{"fcDomP": {"attributes": {"dn": "uni/fc-fc_dom", "name": "fc_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}}}]' + - nm_remove_domain.current == [] + - name: Remove FC domain again (check_mode) aci_domain: *domain_absent check_mode: yes @@ -128,23 +139,24 @@ aci_domain: *domain_absent register: nm_remove_domain_again -- name: Verify remove_domain +- name: Verify remove_domain_again assert: that: - - cm_remove_domain.changed == nm_remove_domain.changed == true - cm_remove_domain_again.changed == nm_remove_domain_again.changed == false - - 'cm_remove_domain.current == cm_remove_domain.previous == nm_remove_domain.previous == [{"fcDomP": {"attributes": {"dn": "uni/fc-fc_dom", "name": "fc_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}}}]' - - nm_remove_domain.current == [] # QUERY NON-EXISTING DOMAIN - name: Query non-existing FC domain (check_mode) - aci_domain: *domain_query + aci_domain: + <<: *domain_query + domain: fc_dom check_mode: yes register: cm_query_non_domain - name: Query non-existing FC domain (normal mode) - aci_domain: *domain_query + aci_domain: + <<: *domain_query + domain: fc_dom register: nm_query_non_domain - name: Verify query_non_domain diff --git a/test/integration/targets/aci_domain/tasks/l2dom.yml b/test/integration/targets/aci_domain/tasks/l2dom.yml index 4fa16076baf..7bec569e598 100644 --- a/test/integration/targets/aci_domain/tasks/l2dom.yml +++ b/test/integration/targets/aci_domain/tasks/l2dom.yml @@ -1,5 +1,5 @@ # Test code for the ACI modules -# Copyright 2018, Dag Wieers (@dagwieers) +# Copyright: (c) 2018, Dag Wieers (@dagwieers) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) @@ -39,6 +39,15 @@ aci_domain: *domain_present register: nm_add_domain +- name: Verify add_domain + assert: + that: + - cm_add_domain.changed == nm_add_domain.changed == true + - 'cm_add_domain.sent == nm_add_domain.sent == {"l2extDomP": {"attributes": {"name": "l2_dom"}}}' + - 'cm_add_domain.proposed == nm_add_domain.proposed == {"l2extDomP": {"attributes": {"name": "l2_dom"}}}' + - cm_add_domain.current == cm_add_domain.previous == nm_add_domain.previous == [] + - 'nm_add_domain.current == [{"l2extDomP": {"attributes": {"dn": "uni/l2dom-l2_dom", "name": "l2_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}}}]' + - name: Add L2 domain again (check_mode) aci_domain: *domain_present check_mode: yes @@ -48,15 +57,10 @@ aci_domain: *domain_present register: nm_add_domain_again -- name: Verify add_domain +- name: Verify add_domain_again assert: that: - - cm_add_domain.changed == nm_add_domain.changed == true - cm_add_domain_again.changed == nm_add_domain_again.changed == false - - 'cm_add_domain.sent == nm_add_domain.sent == {"l2extDomP": {"attributes": {"name": "l2_dom"}}}' - - 'cm_add_domain.proposed == nm_add_domain.proposed == {"l2extDomP": {"attributes": {"name": "l2_dom"}}}' - - cm_add_domain.current == cm_add_domain.previous == nm_add_domain.previous == [] - - 'nm_add_domain.current == [{"l2extDomP": {"attributes": {"dn": "uni/l2dom-l2_dom", "name": "l2_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}}}]' # QUERY ALL DOMAINS @@ -82,8 +86,8 @@ assert: that: - cm_query_all_domains.changed == nm_query_all_domains.changed == false - # NOTE: Order of domains is not stable between calls - #- cm_query_all_domains == nm_query_all_domains + - cm_query_all_domains == nm_query_all_domains + - nm_query_all_domains.current|length >= 1 # QUERY A DOMAIN @@ -119,6 +123,13 @@ aci_domain: *domain_absent register: nm_remove_domain +- name: Verify remove_domain + assert: + that: + - cm_remove_domain.changed == nm_remove_domain.changed == true + - 'cm_remove_domain.current == cm_remove_domain.previous == nm_remove_domain.previous == [{"l2extDomP": {"attributes": {"dn": "uni/l2dom-l2_dom", "name": "l2_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}}}]' + - nm_remove_domain.current == [] + - name: Remove L2 domain again (check_mode) aci_domain: *domain_absent check_mode: yes @@ -128,23 +139,24 @@ aci_domain: *domain_absent register: nm_remove_domain_again -- name: Verify remove_domain +- name: Verify remove_domain_again assert: that: - - cm_remove_domain.changed == nm_remove_domain.changed == true - cm_remove_domain_again.changed == nm_remove_domain_again.changed == false - - 'cm_remove_domain.current == cm_remove_domain.previous == nm_remove_domain.previous == [{"l2extDomP": {"attributes": {"dn": "uni/l2dom-l2_dom", "name": "l2_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}}}]' - - nm_remove_domain.current == [] # QUERY NON-EXISTING DOMAIN - name: Query non-existing L2 domain (check_mode) - aci_domain: *domain_query + aci_domain: + <<: *domain_query + domain: l2_dom check_mode: yes register: cm_query_non_domain - name: Query non-existing L2 domain (normal mode) - aci_domain: *domain_query + aci_domain: + <<: *domain_query + domain: l2_dom register: nm_query_non_domain - name: Verify query_non_domain diff --git a/test/integration/targets/aci_domain/tasks/l3dom.yml b/test/integration/targets/aci_domain/tasks/l3dom.yml index 5b76bd37170..26aa694db9a 100644 --- a/test/integration/targets/aci_domain/tasks/l3dom.yml +++ b/test/integration/targets/aci_domain/tasks/l3dom.yml @@ -1,5 +1,5 @@ # Test code for the ACI modules -# Copyright 2018, Dag Wieers (@dagwieers) +# Copyright: (c) 2018, Dag Wieers (@dagwieers) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) @@ -39,6 +39,15 @@ aci_domain: *domain_present register: nm_add_domain +- name: Verify add_domain + assert: + that: + - cm_add_domain.changed == nm_add_domain.changed == true + - 'cm_add_domain.sent == nm_add_domain.sent == {"l3extDomP": {"attributes": {"name": "l3_dom"}}}' + - 'cm_add_domain.proposed == nm_add_domain.proposed == {"l3extDomP": {"attributes": {"name": "l3_dom"}}}' + - cm_add_domain.current == cm_add_domain.previous == nm_add_domain.previous == [] + - 'nm_add_domain.current == [{"l3extDomP": {"attributes": {"dn": "uni/l3dom-l3_dom", "name": "l3_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}}}]' + - name: Add L3 domain again (check_mode) aci_domain: *domain_present check_mode: yes @@ -48,15 +57,10 @@ aci_domain: *domain_present register: nm_add_domain_again -- name: Verify add_domain +- name: Verify add_domain_again assert: that: - - cm_add_domain.changed == nm_add_domain.changed == true - cm_add_domain_again.changed == nm_add_domain_again.changed == false - - 'cm_add_domain.sent == nm_add_domain.sent == {"l3extDomP": {"attributes": {"name": "l3_dom"}}}' - - 'cm_add_domain.proposed == nm_add_domain.proposed == {"l3extDomP": {"attributes": {"name": "l3_dom"}}}' - - cm_add_domain.current == cm_add_domain.previous == nm_add_domain.previous == [] - - 'nm_add_domain.current == [{"l3extDomP": {"attributes": {"dn": "uni/l3dom-l3_dom", "name": "l3_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}}}]' # QUERY ALL DOMAINS @@ -82,8 +86,8 @@ assert: that: - cm_query_all_domains.changed == nm_query_all_domains.changed == false - # NOTE: Order of domains is not stable between calls - #- cm_query_all_domains == nm_query_all_domains + - cm_query_all_domains == nm_query_all_domains + - nm_query_all_domains.current|length >= 1 # QUERY A DOMAIN @@ -119,6 +123,13 @@ aci_domain: *domain_absent register: nm_remove_domain +- name: Verify remove_domain + assert: + that: + - cm_remove_domain.changed == nm_remove_domain.changed == true + - 'cm_remove_domain.current == cm_remove_domain.previous == nm_remove_domain.previous == [{"l3extDomP": {"attributes": {"dn": "uni/l3dom-l3_dom", "name": "l3_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}}}]' + - nm_remove_domain.current == [] + - name: Remove L3 domain again (check_mode) aci_domain: *domain_absent check_mode: yes @@ -128,23 +139,24 @@ aci_domain: *domain_absent register: nm_remove_domain_again -- name: Verify remove_domain +- name: Verify remove_domain_again assert: that: - - cm_remove_domain.changed == nm_remove_domain.changed == true - cm_remove_domain_again.changed == nm_remove_domain_again.changed == false - - 'cm_remove_domain.current == cm_remove_domain.previous == nm_remove_domain.previous == [{"l3extDomP": {"attributes": {"dn": "uni/l3dom-l3_dom", "name": "l3_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}}}]' - - nm_remove_domain.current == [] # QUERY NON-EXISTING DOMAIN - name: Query non-existing L3 domain (check_mode) - aci_domain: *domain_query + aci_domain: + <<: *domain_query + domain: l3_dom check_mode: yes register: cm_query_non_domain - name: Query non-existing L3 domain (normal mode) - aci_domain: *domain_query + aci_domain: + <<: *domain_query + domain: l3_dom register: nm_query_non_domain - name: Verify query_non_domain diff --git a/test/integration/targets/aci_domain/tasks/main.yml b/test/integration/targets/aci_domain/tasks/main.yml index 2bc4ddeee8c..5a0585ef328 100644 --- a/test/integration/targets/aci_domain/tasks/main.yml +++ b/test/integration/targets/aci_domain/tasks/main.yml @@ -1,5 +1,5 @@ # Test code for the ACI modules -# Copyright 2018, Dag Wieers (@dagwieers) +# Copyright: (c) 2018, Dag Wieers (@dagwieers) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) diff --git a/test/integration/targets/aci_domain/tasks/phys.yml b/test/integration/targets/aci_domain/tasks/phys.yml index 01637cb8a9b..6a8f6d77510 100644 --- a/test/integration/targets/aci_domain/tasks/phys.yml +++ b/test/integration/targets/aci_domain/tasks/phys.yml @@ -1,5 +1,5 @@ # Test code for the ACI modules -# Copyright 2018, Dag Wieers (@dagwieers) +# Copyright: (c) 2018, Dag Wieers (@dagwieers) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) @@ -39,6 +39,15 @@ aci_domain: *domain_present register: nm_add_domain +- name: Verify add_domain + assert: + that: + - cm_add_domain.changed == nm_add_domain.changed == true + - 'cm_add_domain.sent == nm_add_domain.sent == {"physDomP": {"attributes": {"name": "phys_dom"}}}' + - 'cm_add_domain.proposed == nm_add_domain.proposed == {"physDomP": {"attributes": {"name": "phys_dom"}}}' + - cm_add_domain.current == cm_add_domain.previous == nm_add_domain.previous == [] + - 'nm_add_domain.current == [{"physDomP": {"attributes": {"dn": "uni/phys-phys_dom", "name": "phys_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}}}]' + - name: Add physical domain again (check_mode) aci_domain: *domain_present check_mode: yes @@ -48,15 +57,10 @@ aci_domain: *domain_present register: nm_add_domain_again -- name: Verify add_domain +- name: Verify add_domain_again assert: that: - - cm_add_domain.changed == nm_add_domain.changed == true - cm_add_domain_again.changed == nm_add_domain_again.changed == false - - 'cm_add_domain.sent == nm_add_domain.sent == {"physDomP": {"attributes": {"name": "phys_dom"}}}' - - 'cm_add_domain.proposed == nm_add_domain.proposed == {"physDomP": {"attributes": {"name": "phys_dom"}}}' - - cm_add_domain.current == cm_add_domain.previous == nm_add_domain.previous == [] - - 'nm_add_domain.current == [{"physDomP": {"attributes": {"dn": "uni/phys-phys_dom", "name": "phys_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}}}]' # QUERY ALL DOMAINS @@ -82,8 +86,8 @@ assert: that: - cm_query_all_domains.changed == nm_query_all_domains.changed == false - # NOTE: Order of domains is not stable between calls - #- cm_query_all_domains == nm_query_all_domains + - cm_query_all_domains == nm_query_all_domains + - nm_query_all_domains.current|length >= 1 # QUERY A DOMAIN @@ -119,6 +123,13 @@ aci_domain: *domain_absent register: nm_remove_domain +- name: Verify remove_domain + assert: + that: + - cm_remove_domain.changed == nm_remove_domain.changed == true + - 'cm_remove_domain.current == cm_remove_domain.previous == nm_remove_domain.previous == [{"physDomP": {"attributes": {"dn": "uni/phys-phys_dom", "name": "phys_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}}}]' + - nm_remove_domain.current == [] + - name: Remove physical domain again (check_mode) aci_domain: *domain_absent check_mode: yes @@ -128,23 +139,24 @@ aci_domain: *domain_absent register: nm_remove_domain_again -- name: Verify remove_domain +- name: Verify remove_domain_again assert: that: - - cm_remove_domain.changed == nm_remove_domain.changed == true - cm_remove_domain_again.changed == nm_remove_domain_again.changed == false - - 'cm_remove_domain.current == cm_remove_domain.previous == nm_remove_domain.previous == [{"physDomP": {"attributes": {"dn": "uni/phys-phys_dom", "name": "phys_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}}}]' - - nm_remove_domain.current == [] # QUERY NON-EXISTING DOMAIN - name: Query non-existing physical domain (check_mode) - aci_domain: *domain_query + aci_domain: + <<: *domain_query + domain: phys_dom check_mode: yes register: cm_query_non_domain - name: Query non-existing physical domain (normal mode) - aci_domain: *domain_query + aci_domain: + <<: *domain_query + domain: phys_dom register: nm_query_non_domain - name: Verify query_non_domain diff --git a/test/integration/targets/aci_domain/tasks/vmm-vmware.yml b/test/integration/targets/aci_domain/tasks/vmm-vmware.yml index dab1c8444f9..a539ead6605 100644 --- a/test/integration/targets/aci_domain/tasks/vmm-vmware.yml +++ b/test/integration/targets/aci_domain/tasks/vmm-vmware.yml @@ -1,5 +1,5 @@ # Test code for the ACI modules -# Copyright 2018, Dag Wieers (@dagwieers) +# Copyright: (c) 2018, Dag Wieers (@dagwieers) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) @@ -41,6 +41,16 @@ aci_domain: *domain_present register: nm_add_domain +- name: Verify add_domain + assert: + that: + - cm_add_domain.changed == nm_add_domain.changed == true + - 'cm_add_domain.sent == nm_add_domain.sent == {"vmmDomP": {"attributes": {"name": "vmm_dom"}}}' + - 'cm_add_domain.proposed == nm_add_domain.proposed == {"vmmDomP": {"attributes": {"name": "vmm_dom"}}}' + - cm_add_domain.current == cm_add_domain.previous == nm_add_domain.previous == [] + - nm_add_domain.current.0.vmmDomP.attributes.dn == 'uni/vmmp-VMware/dom-vmm_dom' + - nm_add_domain.current.0.vmmDomP.attributes.name == 'vmm_dom' + - name: Add VMM domain again (check_mode) aci_domain: *domain_present check_mode: yes @@ -50,16 +60,10 @@ aci_domain: *domain_present register: nm_add_domain_again -- name: Verify add_domain +- name: Verify add_domain_again assert: that: - - cm_add_domain.changed == nm_add_domain.changed == true - cm_add_domain_again.changed == nm_add_domain_again.changed == false - - 'cm_add_domain.sent == nm_add_domain.sent == {"vmmDomP": {"attributes": {"name": "vmm_dom"}}}' - - 'cm_add_domain.proposed == nm_add_domain.proposed == {"vmmDomP": {"attributes": {"name": "vmm_dom"}}}' - - cm_add_domain.current == cm_add_domain.previous == nm_add_domain.previous == [] - - nm_add_domain.current.0.vmmDomP.attributes.dn == 'uni/vmmp-VMware/dom-vmm_dom' - - nm_add_domain.current.0.vmmDomP.attributes.name == 'vmm_dom' # QUERY ALL DOMAINS @@ -86,8 +90,8 @@ assert: that: - cm_query_all_domains.changed == nm_query_all_domains.changed == false - # NOTE: Order of domains is not stable between calls - #- cm_query_all_domains == nm_query_all_domains + - cm_query_all_domains == nm_query_all_domains + - nm_query_all_domains.current|length >= 1 # QUERY A DOMAIN @@ -125,6 +129,15 @@ aci_domain: *domain_absent register: nm_remove_domain +- name: Verify remove_domain + assert: + that: + - cm_remove_domain.changed == nm_remove_domain.changed == true + - cm_remove_domain.current == cm_remove_domain.previous == nm_remove_domain.previous + - nm_remove_domain.previous.0.vmmDomP.attributes.dn == 'uni/vmmp-VMware/dom-vmm_dom' + - nm_remove_domain.previous.0.vmmDomP.attributes.name == 'vmm_dom' + - nm_remove_domain.current == [] + - name: Remove VMM domain again (check_mode) aci_domain: *domain_absent check_mode: yes @@ -134,25 +147,26 @@ aci_domain: *domain_absent register: nm_remove_domain_again -- name: Verify remove_domain +- name: Verify remove_domain_again assert: that: - - cm_remove_domain.changed == nm_remove_domain.changed == true - cm_remove_domain_again.changed == nm_remove_domain_again.changed == false - - cm_remove_domain.current == cm_remove_domain.previous == nm_remove_domain.previous - - nm_remove_domain.previous.0.vmmDomP.attributes.dn == 'uni/vmmp-VMware/dom-vmm_dom' - - nm_remove_domain.previous.0.vmmDomP.attributes.name == 'vmm_dom' - - nm_remove_domain.current == [] # QUERY NON-EXISTING DOMAIN - name: Query non-existing VMM domain (check_mode) - aci_domain: *domain_query + aci_domain: + <<: *domain_query + domain: vmm_dom + vm_provider: vmware check_mode: yes register: cm_query_non_domain - name: Query non-existing VMM domain (normal mode) - aci_domain: *domain_query + aci_domain: + <<: *domain_query + domain: vmm_dom + vm_provider: vmware register: nm_query_non_domain - name: Verify query_non_domain diff --git a/test/integration/targets/aci_domain_to_encap_pool/aliases b/test/integration/targets/aci_domain_to_encap_pool/aliases deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test/integration/targets/aci_domain_to_encap_pool/tasks/main.yml b/test/integration/targets/aci_domain_to_encap_pool/tasks/main.yml deleted file mode 100644 index 0c4a148cc16..00000000000 --- a/test/integration/targets/aci_domain_to_encap_pool/tasks/main.yml +++ /dev/null @@ -1,18 +0,0 @@ -# Test code for the ACI modules -# Copyright: (c) 2018, Dag Wieers (@dagwieers) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- name: Test that we have an ACI APIC host, ACI username and ACI password - fail: - msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' - when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined - -- include_tasks: vlan.yml - when: vlan is not defined or vlan - -- include_tasks: vsan.yml - when: vsan is not defined or vsan - -- include_tasks: vxlan.yml - when: vxlan is not defined or vxlan diff --git a/test/integration/targets/aci_domain_to_encap_pool/tasks/vlan.yml b/test/integration/targets/aci_domain_to_encap_pool/tasks/vlan.yml deleted file mode 100644 index bd60329cd05..00000000000 --- a/test/integration/targets/aci_domain_to_encap_pool/tasks/vlan.yml +++ /dev/null @@ -1,215 +0,0 @@ -# Test code for the ACI modules -# Copyright: (c) 2018, Dag Wieers (@dagwieers) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - - -# CLEAN ENVIRONMENT -- name: Remove domain to VLAN pool binding - aci_domain_to_encap_pool: &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: info - domain: phys_dom - domain_type: phys - pool: test_pool - pool_type: vlan - pool_allocation_mode: dynamic - state: absent - -- name: Remove 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) }}' - domain: phys_dom - domain_type: phys - state: absent - -- name: Create VLAN pool - aci_encap_pool: - 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) }}' - pool: test_pool - pool_type: vlan - pool_allocation_mode: dynamic - description: Test VLAN pool - state: present - - -# ADD BINDING -- name: Add domain to VLAN pool binding (check_mode) - aci_domain_to_encap_pool: &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: info - domain: phys_dom - domain_type: phys - pool: test_pool - pool_type: vlan - pool_allocation_mode: dynamic - state: present - check_mode: yes - register: cm_add_binding - -- name: Add domain to VLAN pool binding (normal mode) - aci_domain_to_encap_pool: *binding_present - register: nm_add_binding - -- name: Verify add_binding - assert: - that: - - cm_add_binding.changed == nm_add_binding.changed == true - - 'cm_add_binding.sent == nm_add_binding.sent == {"physDomP": {"attributes": {"name": "phys_dom"}, "children": [{"infraRsVlanNs": {"attributes": {"tDn": "uni/infra/vlanns-[test_pool]-dynamic"}}}]}}' - - 'cm_add_binding.proposed == nm_add_binding.proposed == {"physDomP": {"attributes": {"name": "phys_dom"}, "children": [{"infraRsVlanNs": {"attributes": {"tDn": "uni/infra/vlanns-[test_pool]-dynamic"}}}]}}' - - cm_add_binding.current == cm_add_binding.previous == nm_add_binding.previous == [] - - 'nm_add_binding.current == [{"physDomP": {"attributes": {"dn": "uni/phys-phys_dom", "name": "phys_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}, "children": [{"infraRsVlanNs": {"attributes": {"tDn": "uni/infra/vlanns-[test_pool]-dynamic"}}}]}}]' - -- name: Add domain to VLAN pool binding again (check_mode) - aci_domain_to_encap_pool: *binding_present - check_mode: yes - register: cm_add_binding_again - -- name: Add domain to VLAN pool binding again (normal mode) - aci_domain_to_encap_pool: *binding_present - register: nm_add_binding_again - -- name: Verify add_binding_again - assert: - that: - - cm_add_binding_again.changed == nm_add_binding_again.changed == false - - -# QUERY ALL BINDINGS -- name: Query all domain to VLAN pool bindings (check_mode) - aci_domain_to_encap_pool: &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: info - domain_type: phys - pool_type: vlan - pool_allocation_mode: dynamic - state: query - check_mode: yes - register: cm_query_all_bindings - -- name: Query all domain to VLAN pool bindings (normal mode) - aci_domain_to_encap_pool: *binding_query - register: nm_query_all_bindings - -- name: Verify query_all_bindings - assert: - that: - - cm_query_all_bindings.changed == nm_query_all_bindings.changed == false - - cm_query_all_bindings == nm_query_all_bindings - - nm_query_all_bindings.current|length >= 1 - - -# QUERY A BINDING -- name: Query our domain to VLAN pool binding (check_mode) - aci_domain_to_encap_pool: - <<: *binding_query - domain: phys_dom - pool: test_pool - pool_type: vlan - pool_allocation_mode: dynamic - check_mode: yes - register: cm_query_binding - -- name: Query our domain to VLAN pool binding (normal mode) - aci_domain_to_encap_pool: - <<: *binding_query - domain: phys_dom - pool: test_pool - pool_type: vlan - pool_allocation_mode: dynamic - register: nm_query_binding - -- name: Verify query_binding - assert: - that: - - cm_query_binding.changed == nm_query_binding.changed == false - - cm_query_binding == nm_query_binding - - nm_query_binding.current.0.physDomP.attributes.dn == 'uni/phys-phys_dom' - - nm_query_binding.current.0.physDomP.attributes.name == 'phys_dom' - - nm_query_binding.current.0.physDomP.children.0.infraRsVlanNs.attributes.tCl == 'fvnsVlanInstP' - - nm_query_binding.current.0.physDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' - - -# REMOVE BINDING -- name: Remove domain to VLAN pool binding (check_mode) - aci_domain_to_encap_pool: *binding_absent - check_mode: yes - register: cm_remove_binding - -- name: Remove domain to VLAN pool binding (normal mode) - aci_domain_to_encap_pool: *binding_absent - register: nm_remove_binding - -- name: Verify remove_binding - assert: - that: - - cm_remove_binding.changed == nm_remove_binding.changed == true - - 'cm_remove_binding.current == cm_remove_binding.previous == nm_remove_binding.previous == [{"physDomP": {"attributes": {"dn": "uni/phys-phys_dom", "name": "phys_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}, "children": [{"infraRsVlanNs": {"attributes": {"tDn": "uni/infra/vlanns-[test_pool]-dynamic"}}}]}}]' - - nm_remove_binding.current == [] - -- name: Remove domain to VLAN pool binding again (check_mode) - aci_domain_to_encap_pool: *binding_absent - check_mode: yes - register: cm_remove_binding_again - -- name: Remove domain to VLAN pool binding again (normal mode) - aci_domain_to_encap_pool: *binding_absent - register: nm_remove_binding_again - -- name: Verify remove_binding_again - assert: - that: - - cm_remove_binding_again.changed == nm_remove_binding_again.changed == false - - -# QUERY NON-EXISTING BINDING -- name: Query non-existing domain to VLAN pool binding (check_mode) - aci_domain_to_encap_pool: - <<: *binding_query - domain: phys_dom - pool: test_pool - pool_type: vlan - pool_allocation_mode: dynamic - check_mode: yes - register: cm_query_non_binding - -- name: Query non-existing domain to VLAN pool binding (normal mode) - aci_domain_to_encap_pool: - <<: *binding_query - domain: phys_dom - pool: test_pool - pool_type: vlan - pool_allocation_mode: dynamic - register: nm_query_non_binding - -- name: Verify query_non_binding - assert: - that: - - cm_query_non_binding.changed == nm_query_non_binding.changed == false - - cm_query_non_binding == nm_query_non_binding - - nm_query_non_binding.current == [] diff --git a/test/integration/targets/aci_domain_to_encap_pool/tasks/vsan.yml b/test/integration/targets/aci_domain_to_encap_pool/tasks/vsan.yml deleted file mode 100644 index 2474b7635a2..00000000000 --- a/test/integration/targets/aci_domain_to_encap_pool/tasks/vsan.yml +++ /dev/null @@ -1,215 +0,0 @@ -# Test code for the ACI modules -# Copyright: (c) 2018, Dag Wieers (@dagwieers) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - - -# CLEAN ENVIRONMENT -- name: Remove domain to VSAN pool binding - aci_domain_to_encap_pool: &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: info - domain: phys_dom - domain_type: phys - pool: test_pool - pool_type: vsan - pool_allocation_mode: static - state: absent - -- name: Remove 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) }}' - domain: phys_dom - domain_type: phys - state: absent - -- name: Create VSAN pool - aci_encap_pool: - 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) }}' - pool: test_pool - pool_type: vsan - pool_allocation_mode: static - description: Test VSAN pool - state: present - - -# ADD BINDING -- name: Add domain to VSAN pool binding (check_mode) - aci_domain_to_encap_pool: &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: info - domain: phys_dom - domain_type: phys - pool: test_pool - pool_type: vsan - pool_allocation_mode: static - state: present - check_mode: yes - register: cm_add_binding - -- name: Add domain to VSAN pool binding (normal mode) - aci_domain_to_encap_pool: *binding_present - register: nm_add_binding - -- name: Verify add_binding - assert: - that: - - cm_add_binding.changed == nm_add_binding.changed == true - - 'cm_add_binding.sent == nm_add_binding.sent == {"physDomP": {"attributes": {"name": "phys_dom"}, "children": [{"infraRsVlanNs": {"attributes": {"tDn": "uni/infra/vsanns-[test_pool]-static"}}}]}}' - - 'cm_add_binding.proposed == nm_add_binding.proposed == {"physDomP": {"attributes": {"name": "phys_dom"}, "children": [{"infraRsVlanNs": {"attributes": {"tDn": "uni/infra/vsanns-[test_pool]-static"}}}]}}' - - cm_add_binding.current == cm_add_binding.previous == nm_add_binding.previous == [] - - 'nm_add_binding.current == [{"physDomP": {"attributes": {"dn": "uni/phys-phys_dom", "name": "phys_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}, "children": [{"infraRsVlanNs": {"attributes": {"tDn": "uni/infra/vsanns-[test_pool]-static"}}}]}}]' - -- name: Add domain to VSAN pool binding again (check_mode) - aci_domain_to_encap_pool: *binding_present - check_mode: yes - register: cm_add_binding_again - -- name: Add domain to VSAN pool binding again (normal mode) - aci_domain_to_encap_pool: *binding_present - register: nm_add_binding_again - -- name: Verify add_binding_again - assert: - that: - - cm_add_binding_again.changed == nm_add_binding_again.changed == false - - -# QUERY ALL BINDINGS -- name: Query all domain to VSAN pool bindings (check_mode) - aci_domain_to_encap_pool: &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: info - domain_type: phys - pool_type: vsan - pool_allocation_mode: static - state: query - check_mode: yes - register: cm_query_all_bindings - -- name: Query all domain to VSAN pool bindings (normal mode) - aci_domain_to_encap_pool: *binding_query - register: nm_query_all_bindings - -- name: Verify query_all_bindings - assert: - that: - - cm_query_all_bindings.changed == nm_query_all_bindings.changed == false - - cm_query_all_bindings == nm_query_all_bindings - - nm_query_all_bindings.current|length >= 1 - - -# QUERY A BINDING -- name: Query our domain to VSAN pool binding (check_mode) - aci_domain_to_encap_pool: - <<: *binding_query - domain: phys_dom - pool: test_pool - pool_type: vsan - pool_allocation_mode: static - check_mode: yes - register: cm_query_binding - -- name: Query our domain to VSAN pool binding (normal mode) - aci_domain_to_encap_pool: - <<: *binding_query - domain: phys_dom - pool: test_pool - pool_type: vsan - pool_allocation_mode: static - register: nm_query_binding - -- name: Verify query_binding - assert: - that: - - cm_query_binding.changed == nm_query_binding.changed == false - - cm_query_binding == nm_query_binding - - nm_query_binding.current.0.physDomP.attributes.dn == 'uni/phys-phys_dom' - - nm_query_binding.current.0.physDomP.attributes.name == 'phys_dom' - - nm_query_binding.current.0.physDomP.children.0.infraRsVlanNs.attributes.tCl == 'fvnsVlanInstP' - - nm_query_binding.current.0.physDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vsanns-[test_pool]-static' - - -# REMOVE BINDING -- name: Remove domain to VSAN pool binding (check_mode) - aci_domain_to_encap_pool: *binding_absent - check_mode: yes - register: cm_remove_binding - -- name: Remove domain to VSAN pool binding (normal mode) - aci_domain_to_encap_pool: *binding_absent - register: nm_remove_binding - -- name: Verify remove_binding - assert: - that: - - cm_remove_binding.changed == nm_remove_binding.changed == true - - 'cm_remove_binding.current == cm_remove_binding.previous == nm_remove_binding.previous == [{"physDomP": {"attributes": {"dn": "uni/phys-phys_dom", "name": "phys_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}, "children": [{"infraRsVlanNs": {"attributes": {"tDn": "uni/infra/vsanns-[test_pool]-static"}}}]}}]' - - nm_remove_binding.current == [] - -- name: Remove domain to VSAN pool binding again (check_mode) - aci_domain_to_encap_pool: *binding_absent - check_mode: yes - register: cm_remove_binding_again - -- name: Remove domain to VSAN pool binding again (normal mode) - aci_domain_to_encap_pool: *binding_absent - register: nm_remove_binding_again - -- name: Verify remove_binding_again - assert: - that: - - cm_remove_binding_again.changed == nm_remove_binding_again.changed == false - - -# QUERY NON-EXISTING BINDING -- name: Query non-existing domain to VSAN pool binding (check_mode) - aci_domain_to_encap_pool: - <<: *binding_query - domain: phys_dom - pool: test_pool - pool_type: vsan - pool_allocation_mode: static - check_mode: yes - register: cm_query_non_binding - -- name: Query non-existing domain to VSAN pool binding (normal mode) - aci_domain_to_encap_pool: - <<: *binding_query - domain: phys_dom - pool: test_pool - pool_type: vsan - pool_allocation_mode: static - register: nm_query_non_binding - -- name: Verify query_non_binding - assert: - that: - - cm_query_non_binding.changed == nm_query_non_binding.changed == false - - cm_query_non_binding == nm_query_non_binding - - nm_query_non_binding.current == [] diff --git a/test/integration/targets/aci_domain_to_encap_pool/tasks/vxlan.yml b/test/integration/targets/aci_domain_to_encap_pool/tasks/vxlan.yml deleted file mode 100644 index 9db7e366757..00000000000 --- a/test/integration/targets/aci_domain_to_encap_pool/tasks/vxlan.yml +++ /dev/null @@ -1,215 +0,0 @@ -# Test code for the ACI modules -# Copyright: (c) 2018, Dag Wieers (@dagwieers) - -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - - -# CLEAN ENVIRONMENT -- name: Remove domain to VXLAN pool binding - aci_domain_to_encap_pool: &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: info - domain: vmm_dom - domain_type: vmm - vm_provider: vmware - pool: test_pool - pool_type: vxlan - state: absent - -- name: Remove VMM 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) }}' - domain: vmm_dom - domain_type: vmm - vm_provider: vmware - state: absent - -- name: Create VXLAN pool - aci_encap_pool: - 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) }}' - pool: test_pool - pool_type: vxlan - description: Test VXLAN pool - state: present - - -# ADD BINDING -- name: Add domain to VXLAN pool binding (check_mode) - aci_domain_to_encap_pool: &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: info - domain: vmm_dom - domain_type: vmm - vm_provider: vmware - pool: test_pool - pool_type: vxlan - state: present - check_mode: yes - register: cm_add_binding - -- name: Add domain to VXLAN pool binding (normal mode) - aci_domain_to_encap_pool: *binding_present - register: nm_add_binding - -- name: Verify add_binding - assert: - that: - - cm_add_binding.changed == nm_add_binding.changed == true - - 'cm_add_binding.sent == nm_add_binding.sent == {"vmmDomP": {"attributes": {"name": "vmm_dom"}, "children": [{"infraRsVlanNs": {"attributes": {"tDn": "uni/infra/vxlanns-[test_pool]-dynamic"}}}]}}' - - 'cm_add_binding.proposed == nm_add_binding.proposed == {"vmmDomP": {"attributes": {"name": "vmm_dom"}, "children": [{"infraRsVlanNs": {"attributes": {"tDn": "uni/infra/vxlanns-[test_pool]-dynamic"}}}]}}' - - cm_add_binding.current == cm_add_binding.previous == nm_add_binding.previous == [] - - 'nm_add_binding.current == [{"vmmDomP": {"attributes": {"dn": "uni/vmm-vmm_dom", "name": "vmm_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}, "children": [{"infraRsVlanNs": {"attributes": {"tDn": "uni/infra/vxlanns-[test_pool]-dynamic"}}}]}}]' - -- name: Add domain to VXLAN pool binding again (check_mode) - aci_domain_to_encap_pool: *binding_present - check_mode: yes - register: cm_add_binding_again - -- name: Add domain to VXLAN pool binding again (normal mode) - aci_domain_to_encap_pool: *binding_present - register: nm_add_binding_again - -- name: Verify add_binding_again - assert: - that: - - cm_add_binding_again.changed == nm_add_binding_again.changed == false - - -# QUERY ALL BINDINGS -- name: Query all domain to VXLAN pool bindings (check_mode) - aci_domain_to_encap_pool: &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: info - domain_type: vmm - vm_provider: vmware - pool_type: vxlan - state: query - check_mode: yes - register: cm_query_all_bindings - -- name: Query all domain to VXLAN pool bindings (normal mode) - aci_domain_to_encap_pool: *binding_query - register: nm_query_all_bindings - -- name: Verify query_all_bindings - assert: - that: - - cm_query_all_bindings.changed == nm_query_all_bindings.changed == false - - cm_query_all_bindings == nm_query_all_bindings - - nm_query_all_bindings.current|length >= 1 - - -# QUERY A BINDING -- name: Query our domain to VXLAN pool binding (check_mode) - aci_domain_to_encap_pool: - <<: *binding_query - domain: vmm_dom - vm_provider: vmware - pool: test_pool - pool_type: vxlan - check_mode: yes - register: cm_query_binding - -- name: Query our domain to VXLAN pool binding (normal mode) - aci_domain_to_encap_pool: - <<: *binding_query - domain: vmm_dom - vm_provider: vmware - pool: test_pool - pool_type: vxlan - register: nm_query_binding - -- name: Verify query_binding - assert: - that: - - cm_query_binding.changed == nm_query_binding.changed == false - - cm_query_binding == nm_query_binding - - nm_query_binding.current.0.vmmDomP.attributes.dn == 'uni/vmm-vmm_dom' - - nm_query_binding.current.0.vmmDomP.attributes.name == 'vmm_dom' - - nm_query_binding.current.0.vmmDomP.children.0.infraRsVlanNs.attributes.tCl == 'fvnsVlanInstP' - - nm_query_binding.current.0.vmmDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vxlanns-[test_pool]-dynamic' - - -# REMOVE BINDING -- name: Remove domain to VXLAN pool binding (check_mode) - aci_domain_to_encap_pool: *binding_absent - check_mode: yes - register: cm_remove_binding - -- name: Remove domain to VXLAN pool binding (normal mode) - aci_domain_to_encap_pool: *binding_absent - register: nm_remove_binding - -- name: Verify remove_binding - assert: - that: - - cm_remove_binding.changed == nm_remove_binding.changed == true - - 'cm_remove_binding.current == cm_remove_binding.previous == nm_remove_binding.previous == [{"vmmDomP": {"attributes": {"dn": "uni/vmm-vmm_dom", "name": "vmm_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}, "children": [{"infraRsVlanNs": {"attributes": {"tDn": "uni/infra/vxlanns-[test_pool]-dynamic"}}}]}}]' - - nm_remove_binding.current == [] - -- name: Remove domain to VXLAN pool binding again (check_mode) - aci_domain_to_encap_pool: *binding_absent - check_mode: yes - register: cm_remove_binding_again - -- name: Remove domain to VXLAN pool binding again (normal mode) - aci_domain_to_encap_pool: *binding_absent - register: nm_remove_binding_again - -- name: Verify remove_binding_again - assert: - that: - - cm_remove_binding_again.changed == nm_remove_binding_again.changed == false - - -# QUERY NON-EXISTING BINDING -- name: Query non-existing domain to VXLAN pool binding (check_mode) - aci_domain_to_encap_pool: - <<: *binding_query - domain: vmm_dom - vm_provider: vmware - pool: test_pool - pool_type: vxlan - check_mode: yes - register: cm_query_non_binding - -- name: Query non-existing domain to VXLAN pool binding (normal mode) - aci_domain_to_encap_pool: - <<: *binding_query - domain: vmm_dom - vm_provider: vmware - pool: test_pool - pool_type: vxlan - register: nm_query_non_binding - -- name: Verify query_non_binding - assert: - that: - - cm_query_non_binding.changed == nm_query_non_binding.changed == false - - cm_query_non_binding == nm_query_non_binding - - nm_query_non_binding.current == [] diff --git a/test/integration/targets/aci_domain_to_vlan_pool/tasks/main.yml b/test/integration/targets/aci_domain_to_vlan_pool/tasks/main.yml index 95f2b5bbdd4..2cbb936f42f 100644 --- a/test/integration/targets/aci_domain_to_vlan_pool/tasks/main.yml +++ b/test/integration/targets/aci_domain_to_vlan_pool/tasks/main.yml @@ -1,5 +1,5 @@ # Test code for the ACI modules -# Copyright 2018, Dag Wieers (@dagwieers) +# Copyright: (c) 2018, Dag Wieers (@dagwieers) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) @@ -68,6 +68,15 @@ aci_domain_to_vlan_pool: *binding_present register: nm_add_binding +- name: Verify add_binding + assert: + that: + - cm_add_binding.changed == nm_add_binding.changed == true + - 'cm_add_binding.sent == nm_add_binding.sent == {"physDomP": {"attributes": {"name": "phys_dom"}, "children": [{"infraRsVlanNs": {"attributes": {"tDn": "uni/infra/vlanns-[test_pool]-dynamic"}}}]}}' + - 'cm_add_binding.proposed == nm_add_binding.proposed == {"physDomP": {"attributes": {"name": "phys_dom"}, "children": [{"infraRsVlanNs": {"attributes": {"tDn": "uni/infra/vlanns-[test_pool]-dynamic"}}}]}}' + - cm_add_binding.current == cm_add_binding.previous == nm_add_binding.previous == [] + - 'nm_add_binding.current == [{"physDomP": {"attributes": {"dn": "uni/phys-phys_dom", "name": "phys_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}, "children": [{"infraRsVlanNs": {"attributes": {"tDn": "uni/infra/vlanns-[test_pool]-dynamic"}}}]}}]' + - name: Add domain to VLAN pool binding again (check_mode) aci_domain_to_vlan_pool: *binding_present check_mode: yes @@ -77,15 +86,10 @@ aci_domain_to_vlan_pool: *binding_present register: nm_add_binding_again -- name: Verify add_binding +- name: Verify add_binding_again assert: that: - - cm_add_binding.changed == nm_add_binding.changed == true - cm_add_binding_again.changed == nm_add_binding_again.changed == false - - 'cm_add_binding.sent == nm_add_binding.sent == {"physDomP": {"attributes": {"name": "phys_dom"}, "children": [{"infraRsVlanNs": {"attributes": {"tDn": "uni/infra/vlanns-[test_pool]-dynamic"}}}]}}' - - 'cm_add_binding.proposed == nm_add_binding.proposed == {"physDomP": {"attributes": {"name": "phys_dom"}, "children": [{"infraRsVlanNs": {"attributes": {"tDn": "uni/infra/vlanns-[test_pool]-dynamic"}}}]}}' - - cm_add_binding.current == cm_add_binding.previous == nm_add_binding.previous == [] - - 'nm_add_binding.current == [{"physDomP": {"attributes": {"dn": "uni/phys-phys_dom", "name": "phys_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}, "children": [{"infraRsVlanNs": {"attributes": {"tDn": "uni/infra/vlanns-[test_pool]-dynamic"}}}]}}]' # QUERY ALL BINDINGS @@ -99,7 +103,6 @@ use_proxy: '{{ aci_use_proxy | default(true) }}' output_level: info domain_type: phys - pool: test_pool pool_allocation_mode: dynamic state: query check_mode: yes @@ -113,8 +116,8 @@ assert: that: - cm_query_all_bindings.changed == nm_query_all_bindings.changed == false - # NOTE: Order of bindings is not stable between calls - #- cm_query_all_bindings == nm_query_all_bindings + - cm_query_all_bindings == nm_query_all_bindings + - nm_query_all_bindings.current|length >= 1 # QUERY A BINDING @@ -131,6 +134,8 @@ aci_domain_to_vlan_pool: <<: *binding_query domain: phys_dom + pool: test_pool + pool_allocation_mode: dynamic register: nm_query_binding - name: Verify query_binding @@ -154,6 +159,13 @@ aci_domain_to_vlan_pool: *binding_absent register: nm_remove_binding +- name: Verify remove_binding + assert: + that: + - cm_remove_binding.changed == nm_remove_binding.changed == true + - 'cm_remove_binding.current == cm_remove_binding.previous == nm_remove_binding.previous == [{"physDomP": {"attributes": {"dn": "uni/phys-phys_dom", "name": "phys_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}, "children": [{"infraRsVlanNs": {"attributes": {"tDn": "uni/infra/vlanns-[test_pool]-dynamic"}}}]}}]' + - nm_remove_binding.current == [] + - name: Remove domain to VLAN pool binding again (check_mode) aci_domain_to_vlan_pool: *binding_absent check_mode: yes @@ -163,23 +175,28 @@ aci_domain_to_vlan_pool: *binding_absent register: nm_remove_binding_again -- name: Verify remove_binding +- name: Verify remove_binding_again assert: that: - - cm_remove_binding.changed == nm_remove_binding.changed == true - cm_remove_binding_again.changed == nm_remove_binding_again.changed == false - - 'cm_remove_binding.current == cm_remove_binding.previous == nm_remove_binding.previous == [{"physDomP": {"attributes": {"dn": "uni/phys-phys_dom", "name": "phys_dom", "nameAlias": "", "ownerKey": "", "ownerTag": ""}, "children": [{"infraRsVlanNs": {"attributes": {"tDn": "uni/infra/vlanns-[test_pool]-dynamic"}}}]}}]' - - nm_remove_binding.current == [] # QUERY NON-EXISTING BINDING - name: Query non-existing domain to VLAN pool binding (check_mode) - aci_domain_to_vlan_pool: *binding_query + aci_domain_to_vlan_pool: + <<: *binding_query + domain: phys_dom + pool: test_pool + pool_allocation_mode: dynamic check_mode: yes register: cm_query_non_binding - name: Query non-existing domain to VLAN pool binding (normal mode) - aci_domain_to_vlan_pool: *binding_query + aci_domain_to_vlan_pool: + <<: *binding_query + domain: phys_dom + pool: test_pool + pool_allocation_mode: dynamic register: nm_query_non_binding - name: Verify query_non_binding diff --git a/test/integration/targets/aci_encap_pool/tasks/main.yml b/test/integration/targets/aci_encap_pool/tasks/main.yml index e158bc0c4de..971b42bfebe 100644 --- a/test/integration/targets/aci_encap_pool/tasks/main.yml +++ b/test/integration/targets/aci_encap_pool/tasks/main.yml @@ -1,5 +1,5 @@ # Test code for the ACI modules -# Copyright 2017, Jacob McGill +# Copyright: (c) 2017, Dag Wieers (@dagwieers) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) diff --git a/test/integration/targets/aci_filter/tasks/main.yml b/test/integration/targets/aci_filter/tasks/main.yml index 73060e5de73..22599ed8f3f 100644 --- a/test/integration/targets/aci_filter/tasks/main.yml +++ b/test/integration/targets/aci_filter/tasks/main.yml @@ -1,5 +1,5 @@ # Test code for the ACI modules -# Copyright 2017, Dag Wieers +# Copyright: (c) 2017, Dag Wieers (@dagwieers) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) diff --git a/test/integration/targets/aci_filter_entry/tasks/main.yml b/test/integration/targets/aci_filter_entry/tasks/main.yml index 9eb8deb7e42..d54a7a41c93 100644 --- a/test/integration/targets/aci_filter_entry/tasks/main.yml +++ b/test/integration/targets/aci_filter_entry/tasks/main.yml @@ -1,5 +1,5 @@ # Test code for the ACI modules -# Copyright 2017, Jacob McGill +# Copyright: (c) 2017, Bruno Calogero # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) @@ -90,7 +90,7 @@ - intf_policy_leaf_polgrp_check_mode_present.changed == true - intf_policy_leaf_polgrp_present.changed == true - intf_policy_leaf_polgrp_present.previous == [] - - 'intf_policy_leaf_polgrp_present.sent == {"infraAccBndlGrp": {"attributes": {"dn": "uni/infra/funcprof/accbundle-policygroupname","lagT": "link","name": "policygroupname"},"children": [{"infraRsFcIfPol": {"attributes": {"tnFcIfPolName": "fiberchannelpolicy"}}},{"infraRsHIfPol": {"attributes": {"tnFabricHIfPolName": "linklevelpolicy"}}},{"infraRsAttEntP": {"attributes": {"tDn": "uni/infra/attentp-None"}}}]}}' + - 'intf_policy_leaf_polgrp_present.sent == {"infraAccBndlGrp": {"attributes": {"lagT": "link","name": "policygroupname"},"children": [{"infraRsFcIfPol": {"attributes": {"tnFcIfPolName": "fiberchannelpolicy"}}},{"infraRsHIfPol": {"attributes": {"tnFabricHIfPolName": "linklevelpolicy"}}},{"infraRsAttEntP": {"attributes": {"tDn": "uni/infra/attentp-None"}}}]}}' - intf_policy_leaf_polgrp_idempotent.changed == false - intf_policy_leaf_polgrp_idempotent.sent == {} - intf_policy_leaf_polgrp_update.changed == true @@ -209,7 +209,7 @@ - intf_policy_leaf_polgrp_check_mode_present.changed == true - intf_policy_leaf_polgrp_present.changed == true - intf_policy_leaf_polgrp_present.previous == [] - - 'intf_policy_leaf_polgrp_present.sent == {"infraAccBndlGrp": {"attributes": {"dn": "uni/infra/funcprof/accbundle-policygroupname","lagT": "node","name": "policygroupname"},"children": [{"infraRsFcIfPol": {"attributes": {"tnFcIfPolName": "fiberchannelpolicy"}}},{"infraRsHIfPol": {"attributes": {"tnFabricHIfPolName": "linklevelpolicy"}}},{"infraRsAttEntP": {"attributes": {"tDn": "uni/infra/attentp-None"}}}]}}' + - 'intf_policy_leaf_polgrp_present.sent == {"infraAccBndlGrp": {"attributes": {"lagT": "node","name": "policygroupname"},"children": [{"infraRsFcIfPol": {"attributes": {"tnFcIfPolName": "fiberchannelpolicy"}}},{"infraRsHIfPol": {"attributes": {"tnFabricHIfPolName": "linklevelpolicy"}}},{"infraRsAttEntP": {"attributes": {"tDn": "uni/infra/attentp-None"}}}]}}' - intf_policy_leaf_polgrp_idempotent.changed == false - intf_policy_leaf_polgrp_idempotent.sent == {} - intf_policy_leaf_polgrp_update.changed == true @@ -336,7 +336,7 @@ - intf_policy_leaf_polgrp_check_mode_present.changed == true - intf_policy_leaf_polgrp_present.changed == true - intf_policy_leaf_polgrp_present.previous == [] - - 'intf_policy_leaf_polgrp_present.sent == {"infraAccPortGrp": {"attributes": {"dn": "uni/infra/funcprof/accportgrp-policygroupname","name": "policygroupname"},"children": [{"infraRsFcIfPol": {"attributes": {"tnFcIfPolName": "fiberchannelpolicy"}}},{"infraRsHIfPol": {"attributes": {"tnFabricHIfPolName": "linklevelpolicy"}}},{"infraRsAttEntP": {"attributes": {"tDn": "uni/infra/attentp-None"}}}]}}' + - 'intf_policy_leaf_polgrp_present.sent == {"infraAccPortGrp": {"attributes": {"name": "policygroupname"},"children": [{"infraRsFcIfPol": {"attributes": {"tnFcIfPolName": "fiberchannelpolicy"}}},{"infraRsHIfPol": {"attributes": {"tnFabricHIfPolName": "linklevelpolicy"}}},{"infraRsAttEntP": {"attributes": {"tDn": "uni/infra/attentp-None"}}}]}}' - intf_policy_leaf_polgrp_idempotent.changed == false - intf_policy_leaf_polgrp_idempotent.sent == {} - intf_policy_leaf_polgrp_update.changed == true diff --git a/test/integration/targets/aci_interface_policy_leaf_profile/tasks/main.yml b/test/integration/targets/aci_interface_policy_leaf_profile/tasks/main.yml index ef252ec1b4b..3536375fece 100644 --- a/test/integration/targets/aci_interface_policy_leaf_profile/tasks/main.yml +++ b/test/integration/targets/aci_interface_policy_leaf_profile/tasks/main.yml @@ -1,5 +1,5 @@ # Test code for the ACI modules -# Copyright 2017, Bruno Calogero +# Copyright: (c) 2017, Bruno Calogero # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) diff --git a/test/integration/targets/aci_interface_selector_to_switch_policy_leaf_profile/tasks/main.yml b/test/integration/targets/aci_interface_selector_to_switch_policy_leaf_profile/tasks/main.yml index d70980cd509..08bab2006e0 100644 --- a/test/integration/targets/aci_interface_selector_to_switch_policy_leaf_profile/tasks/main.yml +++ b/test/integration/targets/aci_interface_selector_to_switch_policy_leaf_profile/tasks/main.yml @@ -1,5 +1,5 @@ # Test code for the ACI modules -# Copyright 2017, Bruno Calogero +# Copyright: (c) 2017, Bruno Calogero # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) diff --git a/test/integration/targets/aci_rest/tasks/json_inline.yml b/test/integration/targets/aci_rest/tasks/json_inline.yml index fec7f4f290f..86c48d43a39 100644 --- a/test/integration/targets/aci_rest/tasks/json_inline.yml +++ b/test/integration/targets/aci_rest/tasks/json_inline.yml @@ -1,12 +1,8 @@ # Test code for the ACI modules -# Copyright 2017, Dag Wieers +# Copyright: (c) 2017, Dag Wieers (@dagwieers) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -- name: Test that we have an ACI APIC host, ACI username and ACI password - fail: - msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' - when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined # CLEAN ENVIRONMENT - name: Remove tenant @@ -19,7 +15,6 @@ use_proxy: '{{ aci_use_proxy | default(true) }}' path: /api/mo/uni/tn-[ansible_test].json method: delete - delegate_to: localhost # ADD TENANT - name: Add tenant (normal mode) diff --git a/test/integration/targets/aci_rest/tasks/json_string.yml b/test/integration/targets/aci_rest/tasks/json_string.yml index 2c7e5622fa9..a05f53bddbb 100644 --- a/test/integration/targets/aci_rest/tasks/json_string.yml +++ b/test/integration/targets/aci_rest/tasks/json_string.yml @@ -1,12 +1,8 @@ # Test code for the ACI modules -# Copyright 2017, Dag Wieers +# Copyright: (c) 2017, Dag Wieers (@dagwieers) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -- name: Test that we have an ACI APIC host, ACI username and ACI password - fail: - msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' - when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined # CLEAN ENVIRONMENT - name: Remove tenant diff --git a/test/integration/targets/aci_rest/tasks/main.yml b/test/integration/targets/aci_rest/tasks/main.yml index 940b66760fc..c7f7f20e9d2 100644 --- a/test/integration/targets/aci_rest/tasks/main.yml +++ b/test/integration/targets/aci_rest/tasks/main.yml @@ -1,8 +1,13 @@ # Test code for the ACI modules -# Copyright 2017, Dag Wieers +# Copyright: (c) 2017, Dag Wieers (@dagwieers) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + - include_tasks: yaml_inline.yml tags: yaml_inline @@ -17,3 +22,6 @@ - include_tasks: xml_string.yml tags: xml_string + +- include_tasks: error_handling.yml + tags: error_handling diff --git a/test/integration/targets/aci_rest/tasks/xml_string.yml b/test/integration/targets/aci_rest/tasks/xml_string.yml index b2c304e5e17..de31f5dd32e 100644 --- a/test/integration/targets/aci_rest/tasks/xml_string.yml +++ b/test/integration/targets/aci_rest/tasks/xml_string.yml @@ -1,12 +1,8 @@ # Test code for the ACI modules -# Copyright 2017, Dag Wieers +# Copyright: (c) 2017, Dag Wieers (@dagwieers) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -- name: Test that we have an ACI APIC host, ACI username and ACI password - fail: - msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' - when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined # CLEAN ENVIRONMENT - name: Remove tenant diff --git a/test/integration/targets/aci_rest/tasks/yaml_inline.yml b/test/integration/targets/aci_rest/tasks/yaml_inline.yml index 96ae3b6aba6..a8fbf8801dc 100644 --- a/test/integration/targets/aci_rest/tasks/yaml_inline.yml +++ b/test/integration/targets/aci_rest/tasks/yaml_inline.yml @@ -1,12 +1,8 @@ # Test code for the ACI modules -# Copyright 2017, Dag Wieers +# Copyright: (c) 2017, Dag Wieers (@dagwieers) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -- name: Test that we have an ACI APIC host, ACI username and ACI password - fail: - msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' - when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined # CLEAN ENVIRONMENT - name: Remove tenant diff --git a/test/integration/targets/aci_rest/tasks/yaml_string.yml b/test/integration/targets/aci_rest/tasks/yaml_string.yml index ceaa4f72713..ca67eb5f4c2 100644 --- a/test/integration/targets/aci_rest/tasks/yaml_string.yml +++ b/test/integration/targets/aci_rest/tasks/yaml_string.yml @@ -1,12 +1,8 @@ # Test code for the ACI modules -# Copyright 2017, Dag Wieers +# Copyright: (c) 2017, Dag Wieers (@dagwieers) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -- name: Test that we have an ACI APIC host, ACI username and ACI password - fail: - msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' - when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined # CLEAN ENVIRONMENT - name: Remove tenant diff --git a/test/integration/targets/aci_switch_leaf_policy_profile/tasks/main.yml b/test/integration/targets/aci_switch_leaf_policy_profile/tasks/main.yml index bb4f60ef1ca..274064503ea 100644 --- a/test/integration/targets/aci_switch_leaf_policy_profile/tasks/main.yml +++ b/test/integration/targets/aci_switch_leaf_policy_profile/tasks/main.yml @@ -1,5 +1,5 @@ # Test code for the ACI modules -# Copyright 2017, Bruno Calogero +# Copyright: (c) 2017, Bruno Calogero # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) diff --git a/test/integration/targets/aci_switch_leaf_selector/tasks/main.yml b/test/integration/targets/aci_switch_leaf_selector/tasks/main.yml index 5ab82ecb037..176e94bbac9 100644 --- a/test/integration/targets/aci_switch_leaf_selector/tasks/main.yml +++ b/test/integration/targets/aci_switch_leaf_selector/tasks/main.yml @@ -1,5 +1,5 @@ # Test code for the ACI modules -# Copyright 2017, Bruno Calogero +# Copyright: (c) 2017, Bruno Calogero # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) diff --git a/test/integration/targets/aci_taboo_contract/tasks/main.yml b/test/integration/targets/aci_taboo_contract/tasks/main.yml index e78fd69106b..d01e05911e4 100644 --- a/test/integration/targets/aci_taboo_contract/tasks/main.yml +++ b/test/integration/targets/aci_taboo_contract/tasks/main.yml @@ -268,7 +268,7 @@ ignore_errors: yes register: error_on_missing_required_param -- name: Assertion test - present +- name: Verify error_on_missing_required_param assert: that: - error_on_missing_required_param.failed == true diff --git a/test/integration/targets/aci_tenant/tasks/main.yml b/test/integration/targets/aci_tenant/tasks/main.yml index 9087513efed..83de6ced485 100644 --- a/test/integration/targets/aci_tenant/tasks/main.yml +++ b/test/integration/targets/aci_tenant/tasks/main.yml @@ -1,5 +1,5 @@ # Test code for the ACI modules -# Copyright 2017, Dag Wieers +# Copyright: (c) 2017, Dag Wieers (@dagwieers) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) diff --git a/test/integration/targets/aci_vlan_pool/tasks/dynamic.yml b/test/integration/targets/aci_vlan_pool/tasks/dynamic.yml index 86887cf2588..d17907ddb53 100644 --- a/test/integration/targets/aci_vlan_pool/tasks/dynamic.yml +++ b/test/integration/targets/aci_vlan_pool/tasks/dynamic.yml @@ -258,7 +258,7 @@ ignore_errors: yes register: error_on_missing_required_param -- name: Assertion test - present +- name: Verify error_on_missing_required_param assert: that: - error_on_missing_required_param.failed == true diff --git a/test/integration/targets/aci_vlan_pool/tasks/static.yml b/test/integration/targets/aci_vlan_pool/tasks/static.yml index f9fa1c08bdf..809073d7741 100644 --- a/test/integration/targets/aci_vlan_pool/tasks/static.yml +++ b/test/integration/targets/aci_vlan_pool/tasks/static.yml @@ -258,7 +258,7 @@ ignore_errors: yes register: error_on_missing_required_param -- name: Assertion test - present +- name: Verify error_on_missing_required_param assert: that: - error_on_missing_required_param.failed == true diff --git a/test/integration/targets/aci_vrf/tasks/main.yml b/test/integration/targets/aci_vrf/tasks/main.yml index 88c6d03f636..aa1c73b1709 100644 --- a/test/integration/targets/aci_vrf/tasks/main.yml +++ b/test/integration/targets/aci_vrf/tasks/main.yml @@ -1,5 +1,5 @@ # Test code for the ACI modules -# Copyright 2017, Jacob McGill