From 429af9002753f5e16708b130719db8800a62621a Mon Sep 17 00:00:00 2001 From: Jacob McGill Date: Wed, 22 Nov 2017 10:07:39 -0500 Subject: [PATCH] Aci build url (#33017) * ACI Buid URL: Refactor how ACI modules dynamically build proper URL. * Remove MIM URl from update * fix missing comma --- lib/ansible/module_utils/aci.py | 156 ++++++++--------- lib/ansible/modules/network/aci/aci_aep.py | 9 +- lib/ansible/modules/network/aci/aci_ap.py | 17 +- lib/ansible/modules/network/aci/aci_bd.py | 18 +- .../modules/network/aci/aci_bd_subnet.py | 158 +++++++++++++++--- .../modules/network/aci/aci_bd_to_l3out.py | 30 +++- .../network/aci/aci_config_rollback.py | 10 +- .../network/aci/aci_config_snapshot.py | 36 ++-- .../modules/network/aci/aci_contract.py | 17 +- .../network/aci/aci_contract_subject.py | 30 +++- .../aci/aci_contract_subject_to_filter.py | 34 +++- lib/ansible/modules/network/aci/aci_epg.py | 25 ++- .../network/aci/aci_epg_monitoring_policy.py | 17 +- .../network/aci/aci_epg_to_contract.py | 46 +++-- .../modules/network/aci/aci_epg_to_domain.py | 42 ++++- lib/ansible/modules/network/aci/aci_filter.py | 17 +- .../modules/network/aci/aci_filter_entry.py | 24 ++- .../modules/network/aci/aci_intf_policy_fc.py | 10 +- .../modules/network/aci/aci_intf_policy_l2.py | 10 +- .../network/aci/aci_intf_policy_lldp.py | 10 +- .../network/aci/aci_intf_policy_mcp.py | 10 +- .../aci/aci_intf_policy_port_channel.py | 10 +- .../aci/aci_intf_policy_port_security.py | 10 +- .../network/aci/aci_l3out_route_tag_policy.py | 17 +- .../modules/network/aci/aci_taboo_contract.py | 17 +- lib/ansible/modules/network/aci/aci_tenant.py | 9 +- .../aci/aci_tenant_action_rule_profile.py | 17 +- .../aci/aci_tenant_ep_retention_policy.py | 17 +- .../network/aci/aci_tenant_span_dst_group.py | 23 ++- .../network/aci/aci_tenant_span_src_group.py | 24 ++- .../aci_tenant_span_src_group_to_dst_group.py | 31 +++- lib/ansible/modules/network/aci/aci_vrf.py | 16 +- 32 files changed, 732 insertions(+), 185 deletions(-) diff --git a/lib/ansible/module_utils/aci.py b/lib/ansible/module_utils/aci.py index bffb357e8c..f0a88836af 100644 --- a/lib/ansible/module_utils/aci.py +++ b/lib/ansible/module_utils/aci.py @@ -61,6 +61,7 @@ aci_argument_spec = dict( validate_certs=dict(type='bool', default=True), ) +''' URL_MAPPING = dict( action_rule=dict(aci_class='rtctrlAttrP', mo='attr-', key='name'), aep=dict(aci_class='infraAttEntityP', mo='infra/attentp-', key='name'), @@ -97,6 +98,7 @@ URL_MAPPING = dict( tenant_span_src_grp_dst_grp=dict(aci_class='spanSpanLbl', mo='spanlbl-', key='name'), vrf=dict(aci_class='fvCtx', mo='ctx-', key='name'), ) +''' def aci_response_error(result): @@ -284,16 +286,16 @@ class ACIModule(object): """ This method is used to retrieve the appropriate URL path and filter_string to make the request to the APIC. - :param root_class: Type str. - The top-level class naming parameter per the modules (EX: tenant). - :param sublass_1: Type str. - The second-level class naming parameter per the modules (EX: bd). - :param sublass_2: Type str. - The third-level class naming parameter per the modules (EX: gateway). - :param sublass_3: Type str. - The fourth-level class naming parameter per the modules. - :param child_classes: Type tuple. - The list of child classes that the module supports along with the object. + :param root_class: The top-level class dictionary containing aci_class, aci_rn, filter_target, and module_object keys. + :param sublass_1: The second-level class dictionary containing aci_class, aci_rn, filter_target, and module_object keys. + :param sublass_2: The third-level class dictionary containing aci_class, aci_rn, filter_target, and module_object keys. + :param sublass_3: The fourth-level class dictionary containing aci_class, aci_rn, filter_target, and module_object keys. + :param child_classes: The list of child classes that the module supports along with the object. + :type root_class: dict + :type subclass_1: dict + :type subclass_2: dict + :type subclass_3: dict + :type child_classes: list :return: The path and filter_string needed to build the full URL. """ if child_classes is None: @@ -314,18 +316,16 @@ class ACIModule(object): self.result['url'] = '{}://{}/{}'.format(self.module.params['protocol'], self.module.params['hostname'], path) self.result['filter_string'] = filter_string - def _construct_url_1(self, obj_class, child_includes): + def _construct_url_1(self, obj, child_includes): """ This method is used by get_url when the object is the top-level class. """ - obj = self.module.params.get(obj_class) - obj_dict = URL_MAPPING[obj_class] - obj_class = obj_dict['aci_class'] - obj_mo = obj_dict['mo'] + obj_class = obj['aci_class'] + obj_rn = obj['aci_rn'] # State is present or absent if self.module.params['state'] != 'query': - path = 'api/mo/uni/{}[{}].json'.format(obj_mo, obj) + path = 'api/mo/uni/{}.json'.format(obj_rn) filter_string = '?rsp-prop-include=config-only' + child_includes # Query for all objects of the module's class elif obj is None: @@ -333,7 +333,7 @@ class ACIModule(object): filter_string = '' # Query for a specific object in the module's class else: - path = 'api/mo/uni/{}[{}].json'.format(obj_mo, obj) + path = 'api/mo/uni/{}.json'.format(obj_rn) filter_string = '' # Append child_includes to filter_string if filter string is empty @@ -342,19 +342,16 @@ class ACIModule(object): return path, filter_string - def _construct_url_2(self, parent_class, obj_class, child_includes): + def _construct_url_2(self, parent, obj, child_includes): """ This method is used by get_url when the object is the second-level class. """ - parent = self.module.params.get(parent_class) - parent_dict = URL_MAPPING[parent_class] - parent_class = parent_dict['aci_class'] - parent_mo = parent_dict['mo'] - obj = self.module.params.get(obj_class) - obj_dict = URL_MAPPING[obj_class] - obj_class = obj_dict['aci_class'] - obj_mo = obj_dict['mo'] - obj_key = obj_dict['key'] + parent_rn = parent['aci_rn'] + parent_obj = parent['module_object'] + obj_class = obj['aci_class'] + obj_rn = obj['aci_rn'] + obj_filter = obj['filter_target'] + obj = obj['module_object'] if not child_includes: self_child_includes = '?rsp-subtree=full&rsp-subtree-class=' + obj_class @@ -363,26 +360,26 @@ class ACIModule(object): # State is present or absent if self.module.params['state'] != 'query': - path = 'api/mo/uni/{}[{}]/{}[{}].json'.format(parent_mo, parent, obj_mo, obj) + path = 'api/mo/uni/{}/{}.json'.format(parent_rn, obj_rn) filter_string = '?rsp-prop-include=config-only' + child_includes # Query for all objects of the module's class - elif obj is None and parent is None: + elif obj is None and parent_obj is None: path = 'api/class/{}.json'.format(obj_class) filter_string = '' # Queries when parent object is provided - elif parent is not None: + elif parent_obj is not None: # Query for specific object in the module's class if obj is not None: - path = 'api/mo/uni/{}[{}]/{}[{}].json'.format(parent_mo, parent, obj_mo, obj) + path = 'api/mo/uni/{}/{}.json'.format(parent_rn, obj_rn) filter_string = '' # Query for all object's of the module's class that belong to a specific parent object else: - path = 'api/mo/uni/{}[{}].json'.format(parent_mo, parent) + path = 'api/mo/uni/{}.json'.format(parent_rn) filter_string = self_child_includes # Query for all objects of the module's class that match the provided ID value else: path = 'api/class/{}.json'.format(obj_class) - filter_string = '?query-target-filter=eq({}.{}, \"{}\")'.format(obj_class, obj_key, obj) + child_includes + filter_string = '?query-target-filter=eq{}'.format(obj_filter) + child_includes # Append child_includes to filter_string if filter string is empty if child_includes is not None and filter_string == '': @@ -390,24 +387,20 @@ class ACIModule(object): return path, filter_string - def _construct_url_3(self, root_class, parent_class, obj_class, child_includes): + def _construct_url_3(self, root, parent, obj, child_includes): """ This method is used by get_url when the object is the third-level class. """ - root = self.module.params.get(root_class) - root_dict = URL_MAPPING[root_class] - root_class = root_dict['aci_class'] - root_mo = root_dict['mo'] - parent = self.module.params.get(parent_class) - parent_dict = URL_MAPPING[parent_class] - parent_class = parent_dict['aci_class'] - parent_mo = parent_dict['mo'] - parent_key = parent_dict['key'] - obj = self.module.params.get(obj_class) - obj_dict = URL_MAPPING[obj_class] - obj_class = obj_dict['aci_class'] - obj_mo = obj_dict['mo'] - obj_key = obj_dict['key'] + root_rn = root['aci_rn'] + root_obj = root['module_object'] + parent_class = parent['aci_class'] + parent_rn = parent['aci_rn'] + parent_filter = parent['filter_target'] + parent_obj = parent['module_object'] + obj_class = obj['aci_class'] + obj_rn = obj['aci_rn'] + obj_filter = obj['filter_target'] + obj = obj['module_object'] if not child_includes: self_child_includes = '&rsp-subtree=full&rsp-subtree-class=' + obj_class @@ -421,49 +414,49 @@ class ACIModule(object): # State is ablsent or present if self.module.params['state'] != 'query': - path = 'api/mo/uni/{}[{}]/{}[{}]/{}[{}].json'.format(root_mo, root, parent_mo, parent, obj_mo, obj) + path = 'api/mo/uni/{}/{}/{}.json'.format(root_rn, parent_rn, obj_rn) filter_string = '?rsp-prop-include=config-only' + child_includes # Query for all objects of the module's class - elif obj is None and parent is None and root is None: + elif obj is None and parent_obj is None and root_obj is None: path = 'api/class/{}.json'.format(obj_class) filter_string = '' # Queries when root object is provided - elif root is not None: + elif root_obj is not None: # Queries when parent object is provided - if parent is not None: + if parent_obj is not None: # Query for a specific object of the module's class if obj is not None: - path = 'api/mo/uni/{}[{}]/{}[{}]/{}[{}].json'.format(root_mo, root, parent_mo, parent, obj_mo, obj) + path = 'api/mo/uni/{}/{}/{}.json'.format(root_rn, parent_rn, obj_rn) filter_string = '' # Query for all objects of the module's class that belong to a specific parent object else: - path = 'api/mo/uni/{}[{}]/{}[{}].json'.format(root_mo, root, parent_mo, parent) + path = 'api/mo/uni/{}/{}.json'.format(root_rn, parent_rn) filter_string = self_child_includes.replace('&', '?', 1) # Query for all objects of the module's class that match the provided ID value and belong to a specefic root object elif obj is not None: - path = 'api/mo/uni/{}[{}].json'.format(root_mo, root) - filter_string = '?rsp-subtree-filter=eq({}.{}, \"{}\"){}'.format(obj_class, obj_key, obj, self_child_includes) + path = 'api/mo/uni/{}.json'.format(root_rn) + filter_string = '?rsp-subtree-filter=eq{}{}'.format(obj_filter, self_child_includes) # Query for all objects of the module's class that belong to a specific root object else: - path = 'api/mo/uni/{}[{}].json'.format(root_mo, root) + path = 'api/mo/uni/{}.json'.format(root_rn) filter_string = '?' + parent_self_child_includes # Queries when parent object is provided but root object is not provided - elif parent is not None: + elif parent_obj is not None: # Query for all objects of the module's class that belong to any parent class # matching the provided ID values for both object and parent object if obj is not None: path = 'api/class/{}.json'.format(parent_class) - filter_string = '?query-target-filter=eq({}.{}, \"{}\"){}&rsp-subtree-filter=eq({}.{}, \"{}\")'.format( - parent_class, parent_key, parent, self_child_includes, obj_class, obj_key, obj) + filter_string = '?query-target-filter=eq{}{}&rsp-subtree-filter=eq{}'.format( + parent_filter, self_child_includes, obj_filter) # Query for all objects of the module's class that belong to any parent class # matching the provided ID value for the parent object else: path = 'api/class/{}.json'.format(parent_class) - filter_string = '?query-target-filter=eq({}.{}, \"{}\"){}'.format(parent_class, parent_key, parent, self_child_includes) + filter_string = '?query-target-filter=eq{}{}'.format(parent_filter, self_child_includes) # Query for all objects of the module's class matching the provided ID value of the object else: path = 'api/class/{}.json'.format(obj_class) - filter_string = '?query-target-filter=eq({}.{}, \"{}\")'.format(obj_class, obj_key, obj) + child_includes + filter_string = '?query-target-filter=eq{}'.format(obj_filter) + child_includes # append child_includes to filter_string if filter string is empty if child_includes is not None and filter_string == '': @@ -471,33 +464,30 @@ class ACIModule(object): return path, filter_string - def _construct_url_4(self, root_class, sec_class, parent_class, obj_class, child_includes): + def _construct_url_4(self, root, sec, parent, obj, child_includes): """ This method is used by get_url when the object is the third-level class. """ - root = self.module.params.get(root_class) - root_dict = URL_MAPPING[root_class] - root_class = root_dict['aci_class'] - root_mo = root_dict['mo'] - sec = self.module.params.get(sec_class) - sec_dict = URL_MAPPING[sec_class] - sec_class = sec_dict['aci_class'] - sec_mo = sec_dict['mo'] - # sec_key = sec_dict['key'] - parent = self.module.params.get(parent_class) - parent_dict = URL_MAPPING[parent_class] - parent_class = parent_dict['aci_class'] - parent_mo = parent_dict['mo'] - # parent_key = parent_dict['key'] - obj = self.module.params.get(obj_class) - obj_dict = URL_MAPPING[obj_class] - obj_class = obj_dict['aci_class'] - obj_mo = obj_dict['mo'] - # obj_key = obj_dict['key'] + # root_class = root['aci_class'] + root_rn = root['aci_rn'] + # root_filter = root['filter_target'] + # root_obj = root['module_object'] + # sec_class = sec['aci_class'] + sec_rn = sec['aci_rn'] + # sec_filter = sec['filter_target'] + # sec_obj = sec['module_object'] + # parent_class = parent['aci_class'] + parent_rn = parent['aci_rn'] + # parent_filter = parent['filter_target'] + # parent_obj = parent['module_object'] + obj_class = obj['aci_class'] + obj_rn = obj['aci_rn'] + # obj_filter = obj['filter_target'] + # obj = obj['module_object'] # State is ablsent or present if self.module.params['state'] != 'query': - path = 'api/mo/uni/{}[{}]/{}[{}]/{}[{}]/{}[{}].json'.format(root_mo, root, sec_mo, sec, parent_mo, parent, obj_mo, obj) + path = 'api/mo/uni/{}/{}/{}/{}.json'.format(root_rn, sec_rn, parent_rn, obj_rn) filter_string = '?rsp-prop-include=config-only' + child_includes else: path = 'api/class/{}.json'.format(obj_class) diff --git a/lib/ansible/modules/network/aci/aci_aep.py b/lib/ansible/modules/network/aci/aci_aep.py index a0c2aca044..7bc9bb6cc2 100644 --- a/lib/ansible/modules/network/aci/aci_aep.py +++ b/lib/ansible/modules/network/aci/aci_aep.py @@ -108,7 +108,14 @@ def main(): state = module.params['state'] aci = ACIModule(module) - aci.construct_url(root_class="aep") + aci.construct_url( + root_class=dict( + aci_class='infraAttEntityP', + aci_rn='infra/attentp-{}'.format(aep), + filter_target='(infraAttEntityP.name, "{}")'.format(aep), + module_object=aep, + ), + ) aci.get_existing() if state == 'present': diff --git a/lib/ansible/modules/network/aci/aci_ap.py b/lib/ansible/modules/network/aci/aci_ap.py index 0f5cfa8a9e..c45146cdbe 100644 --- a/lib/ansible/modules/network/aci/aci_ap.py +++ b/lib/ansible/modules/network/aci/aci_ap.py @@ -120,9 +120,24 @@ def main(): ap = module.params['ap'] description = module.params['description'] state = module.params['state'] + tenant = module.params['tenant'] aci = ACIModule(module) - aci.construct_url(root_class='tenant', subclass_1='ap') + aci.construct_url( + root_class=dict( + aci_class='fvTenant', + aci_rn='tn-{}'.format(tenant), + filter_target='(fvTenant.name, "{}")'.format(tenant), + module_object=tenant, + ), + subclass_1=dict( + aci_class='fvAp', + aci_rn='ap-{}'.format(ap), + filter_target='(fvAp.name, "{}")'.format(ap), + module_object=ap, + ), + ) + aci.get_existing() if state == 'present': diff --git a/lib/ansible/modules/network/aci/aci_bd.py b/lib/ansible/modules/network/aci/aci_bd.py index fb1614a2ce..f53fe1486d 100644 --- a/lib/ansible/modules/network/aci/aci_bd.py +++ b/lib/ansible/modules/network/aci/aci_bd.py @@ -270,6 +270,7 @@ def main(): limit_ip_learn = module.params['limit_ip_learn'] multi_dest = module.params['multi_dest'] state = module.params['state'] + tenant = module.params['tenant'] vrf = module.params['vrf'] # Give warning when fvSubnet parameters are passed as those have been moved to the aci_subnet module @@ -278,7 +279,22 @@ def main(): The new modules still supports 'gateway_ip' and 'subnet_mask' along with more features"] aci = ACIModule(module) - aci.construct_url(root_class="tenant", subclass_1="bd", child_classes=['fvRsCtx', 'fvRsIgmpsn', 'fvRsBDToNdP', 'fvRsBdToEpRet']) + aci.construct_url( + root_class=dict( + aci_class='fvTenant', + aci_rn='tn-{}'.format(tenant), + filter_target='(fvTenant.name, "{}")'.format(tenant), + module_object=tenant, + ), + subclass_1=dict( + aci_class='fvBD', + aci_rn='BD-{}'.format(bd), + filter_target='(fvBD.name, "{}")'.format(bd), + module_object=bd, + ), + child_classes=['fvRsCtx', 'fvRsIgmpsn', 'fvRsBDToNdP', 'fvRsBdToEpRet'], + ) + aci.get_existing() if state == 'present': diff --git a/lib/ansible/modules/network/aci/aci_bd_subnet.py b/lib/ansible/modules/network/aci/aci_bd_subnet.py index 79871493dd..647dace1fb 100644 --- a/lib/ansible/modules/network/aci/aci_bd_subnet.py +++ b/lib/ansible/modules/network/aci/aci_bd_subnet.py @@ -71,20 +71,26 @@ options: - The L3 Out that contains the assocated Route Profile. scope: description: - - Determines if scope of the Subnet. - - The private option only allows communication with hosts in the same VRF. - - The public option allows the Subnet to be advertised outside of the ACI Fabric, and allows communication with + - Determines the scope of the Subnet. + - The C(private) option only allows communication with hosts in the same VRF. + - The C(public) option allows the Subnet to be advertised outside of the ACI Fabric, and allows communication with hosts in other VRFs. - The shared option limits communication to hosts in either the same VRF or the shared VRF. + - The value is a list of options, C(private) and C(public) are mutually exclusive, but both can be used with C(shared). - The APIC defaults new Subnets to C(private). - choices: [ private, public, shared ] + choices: + - private + - public + - shared + - [ private, shared ] + - [ public, shared ] default: private subnet_control: description: - Determines the Subnet's Control State. - - The querier_ip option is used to treat the gateway_ip as an IGMP querier source IP. - - The nd_ra option is used to treate the gateway_ip address as a Neighbor Discovery Router Advertisement Prefix. - - The no_gw option is used to remove default gateway functionality from the gateway address. + - The C(querier_ip) option is used to treat the gateway_ip as an IGMP querier source IP. + - The C(nd_ra) option is used to treate the gateway_ip address as a Neighbor Discovery Router Advertisement Prefix. + - The C(no_gw) option is used to remove default gateway functionality from the gateway address. - The APIC defaults new Subnets to C(nd_ra). choices: [ nd_ra, no_gw, querier_ip, unspecified ] default: nd_ra @@ -98,7 +104,97 @@ options: aliases: [ tenant_name ] ''' -EXAMPLES = r''' # ''' +EXAMPLES = r''' +- name: create a tenant + aci_tenant: + hostname: apic + username: admin + password: SomeSecretPassword + tenant: production + +- name: create a bridge domain + aci_bd: + hostname: apic + username: admin + password: SomeSecretPassword + tenant: production + bd: database + +- name: create a subnet + aci_bd_subnet: + hostname: apic + username: admin + password: SomeSecretPassword + tenant: production + bd: database + gateway: 10.1.1.1 + mask: 24 + +- name: create a subnet with options + aci_bd_subnet: + hostname: apic + username: admin + password: SomeSecretPassword + tenant: production + bd: database + subnet_name: sql + gateway: 10.1.2.1 + mask: 23 + description: SQL Servers + scope: public + route_profile_l3_out: corp + route_profile: corp_route_profile + +- name: update a subnets scope to private and shared + aci_bd_subnet: + hostname: apic + username: admin + password: SomeSecretPassword + tenant: production + bd: database + gateway: 10.1.1.1 + mask: 24 + scope: [private, shared] + +- name: get all subnets + aci_bd_subnet: + hostname: apic + username: admin + password: SomeSecretPassword + state: query + +- name: get all subnets of specific gateway in specified tenant + aci_bd_subnet: + hostname: apic + username: admin + password: SomeSecretPassword + state: query + tenant: production + gateway: 10.1.1.1 + mask: 24 + +- name: get specific subnet + aci_bd_subnet: + hostname: apic + username: admin + password: SomeSecretPassword + state: query + tenant: production + bd: database + gateway: 10.1.1.1 + mask: 24 + +- name: delete a subnet + aci_bd_subnet: + hostname: apic + username: admin + password: SomeSecretPassword + state: absent + tenant: production + bd: database + gateway: 10.1.1.1 + mask: 24 +''' RETURN = r''' # ''' @@ -122,7 +218,10 @@ def main(): preferred=dict(type='str', choices=['no', 'yes']), route_profile=dict(type='str'), route_profile_l3_out=dict(type='str'), - scope=dict(type='str', choices=['private', 'public', 'shared']), + scope=dict( + type='list', + choices=[['private'], ['public'], ['shared'], ['private', 'shared'], ['shared', 'private'], ['public', 'shared'], ['shared', 'public']], + ), 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']), @@ -141,32 +240,56 @@ def main(): description = module.params['description'] enable_vip = module.params['enable_vip'] + tenant = module.params['tenant'] + bd = module.params['bd'] gateway = module.params['gateway'] mask = module.params['mask'] if mask is not None and mask not in range(0, 129): # TODO: split checkes between IPv4 and IPv6 Addresses module.fail_json(msg='Valid Subnet Masks are 0 to 32 for IPv4 Addresses and 0 to 128 for IPv6 addresses') + if gateway is not None: + gateway = '{}/{}'.format(gateway, str(mask)) subnet_name = module.params['subnet_name'] nd_prefix_policy = module.params['nd_prefix_policy'] preferred = module.params['preferred'] route_profile = module.params['route_profile'] route_profile_l3_out = module.params['route_profile_l3_out'] scope = module.params['scope'] + if scope: + if len(scope) == 1: + scope = scope[0] + elif 'public' in scope: + scope = 'public,shared' + else: + scope = 'private,shared' state = module.params['state'] subnet_control = module.params['subnet_control'] if subnet_control: subnet_control = SUBNET_CONTROL_MAPPING[subnet_control] - # Construct gateway_addr and add to module.params for constructing URL - if gateway is not None and mask is not None: - gateway_addr = '{}/{}'.format(gateway, str(mask)) - module.params['gateway_addr'] = gateway_addr - aci = ACIModule(module) aci.construct_url( - root_class='tenant', subclass_1='bd', subclass_2='gateway_addr', + root_class=dict( + aci_class='fvTenant', + aci_rn='tn-{}'.format(tenant), + filter_target='(fvTenant.name, \"{}\")'.format(tenant), + module_object=tenant, + ), + subclass_1=dict( + aci_class='fvBD', + aci_rn='BD-{}'.format(bd), + filter_target='(fvBD.name, \"{}\")'.format(bd), + module_object=bd, + ), + subclass_2=dict( + aci_class='fvSubnet', + aci_rn='subnet-[{}]'.format(gateway), + filter_target='(fvSubnet.ip, \"{}\")'.format(gateway), + module_object=gateway, + ), child_classes=['fvRsBDSubnetToProfile', 'fvRsNdPfxPol'], ) + aci.get_existing() if state == 'present': @@ -176,7 +299,7 @@ def main(): class_config=dict( ctrl=subnet_control, descr=description, - ip=gateway_addr, + ip=gateway, name=subnet_name, preferred=preferred, scope=scope, @@ -197,9 +320,6 @@ def main(): elif state == 'absent': aci.delete_config() - # Remove gateway_addr used to form URL from module.params - module.params.pop("gateway_addr", None) - module.exit_json(**aci.result) 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 9f71a3c23a..963d267f0b 100644 --- a/lib/ansible/modules/network/aci/aci_bd_to_l3out.py +++ b/lib/ansible/modules/network/aci/aci_bd_to_l3out.py @@ -79,14 +79,33 @@ def main(): ], ) + bd = module.params['bd'] l3out = module.params['l3out'] state = module.params['state'] - - # Add bd_l3out key to module.params for building the URL - module.params['bd_l3out'] = l3out + tenant = module.params['tenant'] aci = ACIModule(module) - aci.construct_url(root_class='tenant', subclass_1='bd', subclass_2='bd_l3out') + aci.construct_url( + root_class=dict( + aci_class='fvTenant', + aci_rn='tn-{}'.format(tenant), + filter_target='(fvTenant.name, "{}")'.format(tenant), + module_object=tenant, + ), + subclass_1=dict( + aci_class='fvBD', + aci_rn='BD-{}'.format(bd), + filter_target='(fvBD.name, "{}")'.format(bd), + module_object=bd, + ), + subclass_2=dict( + aci_class='fvRsBDToOut', + aci_rn='rsBDToOut-{}'.format(l3out), + filter_target='(fvRsBDToOut.tnL3extOutName, "{}")'.format(l3out), + module_object=l3out, + ), + ) + aci.get_existing() if state == 'present': @@ -105,9 +124,6 @@ def main(): elif state == 'absent': aci.delete_config() - # Remove bd_l3out key used for URL building from module.params - module.params.pop('bd_l3out') - module.exit_json(**aci.result) diff --git a/lib/ansible/modules/network/aci/aci_config_rollback.py b/lib/ansible/modules/network/aci/aci_config_rollback.py index 093b7867a5..a5bbea1f8f 100644 --- a/lib/ansible/modules/network/aci/aci_config_rollback.py +++ b/lib/ansible/modules/network/aci/aci_config_rollback.py @@ -196,7 +196,15 @@ def main(): filename = 'ce2_{0}-{1}'.format(export_policy, snapshot) - aci.construct_url(root_class="import_policy") + aci.construct_url( + root_class=dict( + aci_class='configImportP', + aci_rn='fabric/configimp-{}'.format(import_policy), + filter_target='(configImportP.name, "{}")'.format(import_policy), + module_object=import_policy, + ), + ) + aci.get_existing() # Filter out module parameters with null values diff --git a/lib/ansible/modules/network/aci/aci_config_snapshot.py b/lib/ansible/modules/network/aci/aci_config_snapshot.py index db81de3efc..2125911bf1 100644 --- a/lib/ansible/modules/network/aci/aci_config_snapshot.py +++ b/lib/ansible/modules/network/aci/aci_config_snapshot.py @@ -147,13 +147,20 @@ def main(): snapshot = module.params['snapshot'] if snapshot is not None and not snapshot.startswith('run-'): snapshot = 'run-' + snapshot - module.params['snapshot'] = snapshot state = module.params['state'] aci = ACIModule(module) if state == 'present': - aci.construct_url(root_class='export_policy') + aci.construct_url( + root_class=dict( + aci_class='configExportP', + aci_rn='fabric/configexp-{}'.format(export_policy), + filter_target='(configExportP.name, "{}")'.format(export_policy), + module_object=export_policy, + ), + ) + aci.get_existing() # Filter out module params with null values @@ -176,13 +183,25 @@ def main(): aci.post_config() else: - # Add snapshot_container to module.params to build URL + # Prefix the proper url to export_policy if export_policy is not None: - module.params['snapshot_container'] = 'uni/fabric/configexp-{}'.format(module.params['export_policy']) - else: - module.params['snapshot_container'] = None + export_policy = 'uni/fabric/configexp-{}'.format(export_policy) + + aci.construct_url( + root_class=dict( + aci_class='configSnapshotCont', + aci_rn='backupst/snapshots-[{}]'.format(export_policy), + filter_target='(configSnapshotCont.name, "{}")'.format(export_policy), + module_object=export_policy, + ), + subclass_1=dict( + aci_class='configSnapshot', + aci_rn='snapshot-{}'.format(snapshot), + filter_target='(configSnapshot.name, "{}")'.format(snapshot), + module_object=snapshot, + ), + ) - aci.construct_url(root_class='snapshot_container', subclass_1='snapshot') aci.get_existing() if state == 'absent': @@ -201,9 +220,6 @@ def main(): # Mark Snapshot for Deletion aci.post_config() - # Remove snapshot used to build URL from module.params - module.params.pop('snapshot_container') - module.exit_json(**aci.result) diff --git a/lib/ansible/modules/network/aci/aci_contract.py b/lib/ansible/modules/network/aci/aci_contract.py index f23bf69ce8..365a49f5c1 100644 --- a/lib/ansible/modules/network/aci/aci_contract.py +++ b/lib/ansible/modules/network/aci/aci_contract.py @@ -123,9 +123,24 @@ def main(): priority = module.params['priority'] dscp = module.params['dscp'] state = module.params['state'] + tenant = module.params['tenant'] aci = ACIModule(module) - aci.construct_url(root_class='tenant', subclass_1='contract') + aci.construct_url( + root_class=dict( + aci_class='fvTenant', + aci_rn='tn-{}'.format(tenant), + filter_target='(fvTenant.name, "{}")'.format(tenant), + module_object=tenant, + ), + subclass_1=dict( + aci_class='vzBrCP', + aci_rn='brc-{}'.format(contract), + filter_target='(vzBrCP.name, "{}")'.format(contract), + module_object=contract, + ), + ) + aci.get_existing() if state == 'present': diff --git a/lib/ansible/modules/network/aci/aci_contract_subject.py b/lib/ansible/modules/network/aci/aci_contract_subject.py index 2c5748e8c1..905d771a56 100755 --- a/lib/ansible/modules/network/aci/aci_contract_subject.py +++ b/lib/ansible/modules/network/aci/aci_contract_subject.py @@ -136,6 +136,8 @@ RETURN = r''' from ansible.module_utils.aci import ACIModule, aci_argument_spec from ansible.module_utils.basic import AnsibleModule +MATCH_MAPPING = dict(all='All', at_least_one='AtleastOne', at_most_one='AtmostOne', none='None') + def main(): argument_spec = aci_argument_spec @@ -167,19 +169,45 @@ def main(): subject = module.params['subject'] priority = module.params['priority'] reverse_filter = module.params['reverse_filter'] + contract = module.params['contract'] dscp = module.params['dscp'] description = module.params['description'] filter_name = module.params['filter'] directive = module.params['directive'] consumer_match = module.params['consumer_match'] + if consumer_match is not None: + consumer_match = MATCH_MAPPING[consumer_match] provider_match = module.params['provider_match'] + if provider_match is not None: + provider_match = MATCH_MAPPING[provider_match] state = module.params['state'] + tenant = module.params['tenant'] if directive is not None or filter_name is not None: module.fail_json(msg='Managing Contract Subjects to Filter bindings has been moved to M(aci_subject_bind_filter)') aci = ACIModule(module) - aci.construct_url(root_class='tenant', subclass_1='contract', subclass_2='subject') + aci.construct_url( + root_class=dict( + aci_class='fvTenant', + aci_rn='tn-{}'.format(tenant), + filter_target='(fvTenant.name, "{}")'.format(tenant), + module_object=tenant, + ), + subclass_1=dict( + aci_class='vzBrCP', + aci_rn='brc-{}'.format(contract), + filter_target='(vzBrCP.name, "{}")'.format(contract), + module_object=contract, + ), + subclass_2=dict( + aci_class='vzSubj', + aci_rn='subj-{}'.format(subject), + filter_target='(vzSubj.name, "{}")'.format(subject), + module_object=subject, + ), + ) + aci.get_existing() if state == 'present': 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 50f8196544..85c3d71a1a 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 @@ -103,11 +103,11 @@ def main(): ], ) - # contract = module.params['contract'] + contract = module.params['contract'] filter_name = module.params['filter'] log = module.params['log'] - # subject = module.params['subject'] - # tenant = module.params['tenant'] + subject = module.params['subject'] + tenant = module.params['tenant'] state = module.params['state'] # Add subject_filter key to modul.params for building the URL @@ -118,7 +118,33 @@ def main(): log = '' aci = ACIModule(module) - aci.construct_url(root_class='tenant', subclass_1='contract', subclass_2='subject', subclass_3='subject_filter') + aci.construct_url( + root_class=dict( + aci_class='fvTenant', + aci_rn='tn-{}'.format(tenant), + filter_target='(fvTenant.name, "{}")'.format(tenant), + module_object=tenant, + ), + subclass_1=dict( + aci_class='vzBrCP', + aci_rn='brc-{}'.format(contract), + filter_target='(vzBrCP.name, "{}")'.format(contract), + module_object=contract, + ), + subclass_2=dict( + aci_class='vzSubj', + aci_rn='subj-{}'.format(subject), + filter_target='(vzSubj.name, "{}")'.format(subject), + module_object=subject, + ), + subclass_3=dict( + aci_class='vzRsSubjFiltAtt', + aci_rn='rssubjFiltAtt-{}'.format(filter_name), + filter_target='(vzRsSubjFiltAtt.tnVzFilterName, "{}")'.format(filter_name), + module_object=filter_name, + ), + ) + aci.get_existing() if state == 'present': diff --git a/lib/ansible/modules/network/aci/aci_epg.py b/lib/ansible/modules/network/aci/aci_epg.py index 21cf27a189..8e2126660b 100644 --- a/lib/ansible/modules/network/aci/aci_epg.py +++ b/lib/ansible/modules/network/aci/aci_epg.py @@ -193,9 +193,32 @@ def main(): intra_epg_isolation = module.params['intra_epg_isolation'] fwd_control = module.params['fwd_control'] state = module.params['state'] + tenant = module.params['tenant'] + ap = module.params['ap'] aci = ACIModule(module) - aci.construct_url(root_class="tenant", subclass_1="ap", subclass_2="epg", child_classes=['fvRsBd']) + aci.construct_url( + root_class=dict( + aci_class='fvTenant', + aci_rn='tn-{}'.format(tenant), + filter_target='(fvTenant.name, "{}")'.format(tenant), + module_object=tenant, + ), + subclass_1=dict( + aci_class='fvAp', + aci_rn='ap-{}'.format(ap), + filter_target='(fvAp.name, "{}")'.format(ap), + module_object=ap, + ), + subclass_2=dict( + aci_class='fvAEPg', + aci_rn='epg-{}'.format(epg), + filter_target='(fvAEPg.name, "{}")'.format(epg), + module_object=epg, + ), + child_classes=['fvRsBd'], + ) + aci.get_existing() if state == 'present': 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 91d4b6d7a5..110963b37f 100644 --- a/lib/ansible/modules/network/aci/aci_epg_monitoring_policy.py +++ b/lib/ansible/modules/network/aci/aci_epg_monitoring_policy.py @@ -93,9 +93,24 @@ def main(): monitoring_policy = module.params['monitoring_policy'] description = module.params['description'] state = module.params['state'] + tenant = module.params['tenant'] aci = ACIModule(module) - aci.construct_url(root_class='tenant', subclass_1='monitoring_policy') + aci.construct_url( + root_class=dict( + aci_class='fvTenant', + aci_rn='tn-{}'.format(tenant), + filter_target='(fvTenant.name, "{}")'.format(tenant), + module_object=tenant, + ), + subclass_1=dict( + aci_class='monEPGPol', + aci_rn='monepg-{}'.format(monitoring_policy), + filter_target='(monEPGPol.name, "{}")'.format(monitoring_policy), + module_object=monitoring_policy, + ), + ) + aci.get_existing() if state == 'present': 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 99507f14ef..08a858f8fc 100644 --- a/lib/ansible/modules/network/aci/aci_epg_to_contract.py +++ b/lib/ansible/modules/network/aci/aci_epg_to_contract.py @@ -79,7 +79,7 @@ RETURN = r''' # ''' from ansible.module_utils.aci import ACIModule, aci_argument_spec from ansible.module_utils.basic import AnsibleModule -ACI_CLASS_MAPPING = {"consumer": "fvRsCons", "provider": "fvRsProv"} +ACI_CLASS_MAPPING = {"consumer": {"class": "fvRsCons", "rn": "rscons-"}, "provider": {"class": "fvRsProv", "rn": "rsprov-"}} PROVIDER_MATCH_MAPPING = {"all": "All", "at_least_one": "AtleastOne", "at_most_one": "AtmostOne", "none": "None"} @@ -106,22 +106,51 @@ def main(): ], ) + ap = module.params['ap'] contract = module.params['contract'] contract_type = module.params['contract_type'] - aci_class = ACI_CLASS_MAPPING[contract_type] + epg = module.params['epg'] priority = module.params['priority'] provider_match = module.params['provider_match'] + if provider_match is not None: + provider_match = PROVIDER_MATCH_MAPPING[provider_match] state = module.params['state'] + tenant = module.params['tenant'] + + aci_class = ACI_CLASS_MAPPING[contract_type]["class"] + aci_rn = ACI_CLASS_MAPPING[contract_type]["rn"] if contract_type == "consumer" and provider_match is not None: module.fail_json(msg="the 'provider_match' is only configurable for Provided Contracts") - # Construct contract_class key and add to module.params for building URL - contract_class = 'epg_' + contract_type - module.params[contract_class] = contract - aci = ACIModule(module) - aci.construct_url(root_class='tenant', subclass_1='ap', subclass_2='epg', subclass_3=contract_class) + aci.construct_url( + root_class=dict( + aci_class='fvTenant', + aci_rn='tn-{}'.format(tenant), + filter_target='(fvTenant.name, "{}")'.format(tenant), + module_object=tenant, + ), + subclass_1=dict( + aci_class='fvAp', + aci_rn='ap-{}'.format(ap), + filter_target='(fvAp.name, "{}")'.format(ap), + module_object=ap, + ), + subclass_2=dict( + aci_class='fvAEPg', + aci_rn='epg-{}'.format(epg), + filter_target='(fvAEPg.name, "{}")'.format(epg), + module_object=epg, + ), + subclass_3=dict( + aci_class=aci_class, + aci_rn='{}{}'.format(aci_rn, contract), + filter_target='({}.tnVzBrCPName, "{}'.format(aci_class, contract), + module_object=contract, + ), + ) + aci.get_existing() if state == 'present': @@ -144,9 +173,6 @@ def main(): elif state == 'absent': aci.delete_config() - # Remove contract_class that is used to build URL from module.params - module.params.pop(contract_class) - module.exit_json(**aci.result) 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 e7ad960c2a..3459348f2d 100644 --- a/lib/ansible/modules/network/aci/aci_epg_to_domain.py +++ b/lib/ansible/modules/network/aci/aci_epg_to_domain.py @@ -143,6 +143,7 @@ def main(): ) allow_useg = module.params['allow_useg'] + ap = module.params['ap'] deploy_immediacy = module.params['deploy_immediacy'] domain = module.params['domain'] domain_type = module.params['domain_type'] @@ -154,6 +155,7 @@ def main(): else: module.fail_json(msg='Valid VLAN assigments are from 1 to 4096') encap_mode = module.params['encap_mode'] + epg = module.params['epg'] netflow = module.params['netflow'] primary_encap = module.params['primary_encap'] if primary_encap is not None: @@ -163,18 +165,47 @@ def main(): module.fail_json(msg='Valid VLAN assigments are from 1 to 4096') resolution_immediacy = module.params['resolution_immediacy'] state = module.params['state'] + tenant = module.params['tenant'] if domain_type == 'phys' and vm_provider is not None: module.fail_json(msg="Domain type 'phys' cannot have a 'vm_provider'") - # Compile the full domain and add it to module.params for URL building + # Compile the full domain for URL building if domain_type == 'vmm': - module.params["epg_domain"] = VM_PROVIDER_MAPPING[vm_provider] + domain + epg_domain = '{}{}'.format(VM_PROVIDER_MAPPING[vm_provider], domain) elif domain_type is not None: - module.params["epg_domain"] = 'uni/phys-' + domain + epg_domain = 'uni/phys-{}'.format(domain) + else: + epg_domain = None aci = ACIModule(module) - aci.construct_url(root_class="tenant", subclass_1="ap", subclass_2="epg", subclass_3="epg_domain") + aci.construct_url( + root_class=dict( + aci_class='fvTenant', + aci_rn='tn-{}'.format(tenant), + filter_target='(fvTenant.name, "{}")'.format(tenant), + module_object=tenant, + ), + subclass_1=dict( + aci_class='fvAp', + aci_rn='ap-{}'.format(ap), + filter_target='(fvAp.name, "{}")'.format(ap), + module_object=ap, + ), + subclass_2=dict( + aci_class='fvAEPg', + aci_rn='epg-{}'.format(epg), + filter_target='(fvTenant.name, "{}")'.format(epg), + module_object=epg, + ), + subclass_3=dict( + aci_class='fvRsDomAtt', + aci_rn='rsdomAtt-[{}]'.format(epg_domain), + filter_target='(fvRsDomAtt.tDn, "{}")'.format(epg_domain), + module_object=epg_domain, + ), + ) + aci.get_existing() if state == 'present': @@ -201,9 +232,6 @@ def main(): elif state == 'absent': aci.delete_config() - # Pop the epg_domain key that was added for URL building - module.params.pop("epg_domain") - module.exit_json(**aci.result) diff --git a/lib/ansible/modules/network/aci/aci_filter.py b/lib/ansible/modules/network/aci/aci_filter.py index 08f5a590aa..bb040c0e07 100644 --- a/lib/ansible/modules/network/aci/aci_filter.py +++ b/lib/ansible/modules/network/aci/aci_filter.py @@ -121,9 +121,24 @@ def main(): filter_name = module.params['filter'] description = module.params['description'] state = module.params['state'] + tenant = module.params['tenant'] aci = ACIModule(module) - aci.construct_url(root_class="tenant", subclass_1="filter") + aci.construct_url( + root_class=dict( + aci_class='fvTenant', + aci_rn='tn-{}'.format(tenant), + filter_target='(fvTenant.name, "{}")'.format(tenant), + module_object=tenant, + ), + subclass_1=dict( + aci_class='vzFilter', + aci_rn='flt-{}'.format(filter_name), + filter_target='(vzFilter.name, "{}")'.format(filter_name), + module_object=filter_name, + ), + ) + aci.get_existing() if state == 'present': diff --git a/lib/ansible/modules/network/aci/aci_filter_entry.py b/lib/ansible/modules/network/aci/aci_filter_entry.py index 876b012d5a..bb165f90c0 100644 --- a/lib/ansible/modules/network/aci/aci_filter_entry.py +++ b/lib/ansible/modules/network/aci/aci_filter_entry.py @@ -184,6 +184,7 @@ def main(): dst_start = FILTER_PORT_MAPPING[dst_start] entry = module.params['entry'] ether_type = module.params['ether_type'] + filter_name = module.params['filter'] icmp_msg_type = module.params['icmp_msg_type'] if icmp_msg_type is not None: icmp_msg_type = ICMP_MAPPING[icmp_msg_type] @@ -193,6 +194,7 @@ def main(): ip_protocol = module.params['ip_protocol'] state = module.params['state'] stateful = module.params['stateful'] + tenant = module.params['tenant'] # validate that dst_port is not passed with dst_start or dst_end if dst_port is not None and (dst_end is not None or dst_start is not None): @@ -202,7 +204,27 @@ def main(): dst_start = dst_port aci = ACIModule(module) - aci.construct_url(root_class='tenant', subclass_1='filter', subclass_2='entry') + aci.construct_url( + root_class=dict( + aci_class='fvTenant', + aci_rn='tn-{}'.format(tenant), + filter_target='(fvTenant.name, "{}")'.format(tenant), + module_object=tenant, + ), + subclass_1=dict( + aci_class='vzFilter', + aci_rn='flt-{}'.format(filter_name), + filter_target='(vzFilter.name, "{}")'.format(filter_name), + module_object=filter_name, + ), + subclass_2=dict( + aci_class='vzEntry', + aci_rn='e-{}'.format(entry), + filter_target='(vzEntry.name, "{}")'.format(entry), + module_object=entry + ), + ) + aci.get_existing() if state == 'present': diff --git a/lib/ansible/modules/network/aci/aci_intf_policy_fc.py b/lib/ansible/modules/network/aci/aci_intf_policy_fc.py index a85d14e78c..bb346d3fde 100644 --- a/lib/ansible/modules/network/aci/aci_intf_policy_fc.py +++ b/lib/ansible/modules/network/aci/aci_intf_policy_fc.py @@ -93,7 +93,15 @@ def main(): state = module.params['state'] aci = ACIModule(module) - aci.construct_url(root_class='fc_policy') + aci.construct_url( + root_class=dict( + aci_class='fcIfPol', + aci_rn='infra/fcIfPol-{}'.format(fc_policy), + filter_target='(fcIfPol.name, "{}")'.format(fc_policy), + module_object=fc_policy, + ), + ) + aci.get_existing() if state == 'present': diff --git a/lib/ansible/modules/network/aci/aci_intf_policy_l2.py b/lib/ansible/modules/network/aci/aci_intf_policy_l2.py index c20b84910d..9744a7e499 100644 --- a/lib/ansible/modules/network/aci/aci_intf_policy_l2.py +++ b/lib/ansible/modules/network/aci/aci_intf_policy_l2.py @@ -111,7 +111,15 @@ def main(): state = module.params['state'] aci = ACIModule(module) - aci.construct_url(root_class='l2_policy') + aci.construct_url( + root_class=dict( + aci_class='l2IfPol', + aci_rn='infra/l2IfP-{}'.format(l2_policy), + filter_target='(l2IfPol.name, "{}")'.format(l2_policy), + module_object=l2_policy, + ), + ) + aci.get_existing() if state == 'present': diff --git a/lib/ansible/modules/network/aci/aci_intf_policy_lldp.py b/lib/ansible/modules/network/aci/aci_intf_policy_lldp.py index 2b7937f67f..b95c75e84e 100644 --- a/lib/ansible/modules/network/aci/aci_intf_policy_lldp.py +++ b/lib/ansible/modules/network/aci/aci_intf_policy_lldp.py @@ -102,7 +102,15 @@ def main(): state = module.params['state'] aci = ACIModule(module) - aci.construct_url(root_class='lldp_policy') + aci.construct_url( + root_class=dict( + aci_class='lldpIfPol', + aci_rn='infra/lldpIfP-{}'.format(lldp_policy), + filter_target='(lldpIfPol.name, "{}")'.format(lldp_policy), + module_object=lldp_policy, + ), + ) + aci.get_existing() if state == 'present': diff --git a/lib/ansible/modules/network/aci/aci_intf_policy_mcp.py b/lib/ansible/modules/network/aci/aci_intf_policy_mcp.py index ff50b5a314..70c5ce9c9d 100644 --- a/lib/ansible/modules/network/aci/aci_intf_policy_mcp.py +++ b/lib/ansible/modules/network/aci/aci_intf_policy_mcp.py @@ -93,7 +93,15 @@ def main(): state = module.params['state'] aci = ACIModule(module) - aci.construct_url(root_class='mcp') + aci.construct_url( + root_class=dict( + aci_class='mcpIfPol', + aci_rn='infra/mcpIfP-{}'.format(mcp), + filter_target='(mcpIfPol.name, "{}")'.format(mcp), + module_object=mcp, + ), + ) + aci.get_existing() if state == 'present': diff --git a/lib/ansible/modules/network/aci/aci_intf_policy_port_channel.py b/lib/ansible/modules/network/aci/aci_intf_policy_port_channel.py index 6750c49db4..eaac35b467 100644 --- a/lib/ansible/modules/network/aci/aci_intf_policy_port_channel.py +++ b/lib/ansible/modules/network/aci/aci_intf_policy_port_channel.py @@ -178,7 +178,15 @@ def main(): ctrl = ",".join(ctrl) aci = ACIModule(module) - aci.construct_url(root_class='port_channel') + aci.construct_url( + root_class=dict( + aci_class='lacpLagPol', + aci_rn='infra/lacplagp-{}'.format(port_channel), + filter_target='(lacpLagPol.name, "{}")'.format(port_channel), + module_object=port_channel, + ), + ) + aci.get_existing() if state == 'present': diff --git a/lib/ansible/modules/network/aci/aci_intf_policy_port_security.py b/lib/ansible/modules/network/aci/aci_intf_policy_port_security.py index 8cbf386cbb..db94331304 100644 --- a/lib/ansible/modules/network/aci/aci_intf_policy_port_security.py +++ b/lib/ansible/modules/network/aci/aci_intf_policy_port_security.py @@ -94,7 +94,15 @@ def main(): state = module.params['state'] aci = ACIModule(module) - aci.construct_url(root_class='port_security') + aci.construct_url( + root_class=dict( + aci_class='l2PortSecurityPol', + aci_rn='infra/portsecurityP-{}'.format(port_security), + filter_target='(l2PortSecurityPol.name, "{}")'.format(port_security), + module_object=port_security, + ), + ) + aci.get_existing() if state == 'present': 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 65ed32d778..e4b6583c58 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 @@ -100,9 +100,24 @@ def main(): description = module.params['description'] tag = module.params['tag'] state = module.params['state'] + tenant = module.params['tenant'] aci = ACIModule(module) - aci.construct_url(root_class='tenant', subclass_1='rtp') + aci.construct_url( + root_class=dict( + aci_class='fvTenant', + aci_rn='tn-{}'.format(tenant), + filter_target='(fvTenant.name, "{}")'.format(tenant), + module_object=tenant, + ), + subclass_1=dict( + aci_class='l3extRouteTagPol', + aci_rn='rttag-{}'.format(rtp), + filter_target='(l3extRouteTagPol.name, "{}")'.format(rtp), + module_object=rtp, + ), + ) + aci.get_existing() if state == 'present': diff --git a/lib/ansible/modules/network/aci/aci_taboo_contract.py b/lib/ansible/modules/network/aci/aci_taboo_contract.py index f29a05177f..9254ea8a9e 100644 --- a/lib/ansible/modules/network/aci/aci_taboo_contract.py +++ b/lib/ansible/modules/network/aci/aci_taboo_contract.py @@ -101,9 +101,24 @@ def main(): description = module.params['description'] scope = module.params['scope'] state = module.params['state'] + tenant = module.params['tenant'] aci = ACIModule(module) - aci.construct_url(root_class='tenant', subclass_1='taboo_contract') + aci.construct_url( + root_class=dict( + aci_class='fvTenant', + aci_rn='tn-{}'.format(tenant), + filter_target='(fvTenant.name, "{}")'.format(tenant), + module_object=tenant, + ), + subclass_1=dict( + aci_class='vzTaboo', + aci_rn='taboo-{}'.format(taboo_contract), + filter_target='(vzTaboo.name, "{}")'.format(taboo_contract), + module_object=taboo_contract, + ), + ) + aci.get_existing() if state == 'present': diff --git a/lib/ansible/modules/network/aci/aci_tenant.py b/lib/ansible/modules/network/aci/aci_tenant.py index 0941af3ef2..93da05803b 100644 --- a/lib/ansible/modules/network/aci/aci_tenant.py +++ b/lib/ansible/modules/network/aci/aci_tenant.py @@ -109,7 +109,14 @@ def main(): state = module.params['state'] aci = ACIModule(module) - aci.construct_url(root_class="tenant") + aci.construct_url( + root_class=dict( + aci_class='fvTenant', + aci_rn='tn-{}'.format(tenant), + filter_target='(fvTenant.name, "{}")'.format(tenant), + module_object=tenant, + ), + ) aci.get_existing() if state == 'present': 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 e85bd2ae5b..7e3ef9ec67 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 @@ -91,9 +91,24 @@ def main(): action_rule = module.params['action_rule'] description = module.params['description'] state = module.params['state'] + tenant = module.params['tenant'] aci = ACIModule(module) - aci.construct_url(root_class='tenant', subclass_1='action_rule') + aci.construct_url( + root_class=dict( + aci_class='fvTenant', + aci_rn='tn-{}'.format(tenant), + filter_target='(fvTenant.name, "{}")'.format(tenant), + module_object=tenant, + ), + subclass_1=dict( + aci_class='rtctrlAttrP', + aci_rn='attr-{}'.format(action_rule), + filter_target='(rtctrlAttrP.name, "{}")'.format(action_rule), + module_object=action_rule, + ), + ) + aci.get_existing() if state == 'present': 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 2a52b051e4..afbfbcca1b 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 @@ -185,9 +185,24 @@ def main(): if remote_ep_interval == 0: remote_ep_interval = "infinite" state = module.params['state'] + tenant = module.params['tenant'] aci = ACIModule(module) - aci.construct_url(root_class='tenant', subclass_1='epr_policy') + aci.construct_url( + root_class=dict( + aci_class='fvTenant', + aci_rn='tn-{}'.format(tenant), + filter_target='(fvTenant.name, "{}")'.format(tenant), + module_object=tenant, + ), + subclass_1=dict( + aci_class='fvEpRetPol', + aci_rn='epRPol-{}'.format(epr_policy), + filter_target='(fvEpRetPol.name, "{}")'.format(epr_policy), + module_object=epr_policy, + ), + ) + aci.get_existing() if state == 'present': 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 57ab7de9d0..0a4788dd9f 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 @@ -93,12 +93,24 @@ def main(): dst_group = module.params['dst_group'] description = module.params['description'] state = module.params['state'] - - # Add tenant_span_dst_grp to module.params for URL building - module.params['tenant_span_dst_grp'] = dst_group + tenant = module.params['tenant'] aci = ACIModule(module) - aci.construct_url(root_class='tenant', subclass_1='tenant_span_dst_grp') + aci.construct_url( + root_class=dict( + aci_class='fvTenant', + aci_rn='tn-{}'.format(tenant), + filter_target='(fvTenant.name, "{}")'.format(tenant), + module_object=tenant, + ), + subclass_1=dict( + aci_class='spanDestGrp', + aci_rn='destgrp-{}'.format(dst_group), + filter_target='(spanDestGrp.name, "{}")'.format(dst_group), + module_object=dst_group, + ), + ) + aci.get_existing() if state == 'present': @@ -120,9 +132,6 @@ def main(): elif state == 'absent': aci.delete_config() - # Remove tenant_span_dst_grp that was used to build URL from module.params - module.params.pop('tenant_span_dst_grp') - module.exit_json(**aci.result) 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 8f4b95336f..1a328d9930 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 @@ -104,12 +104,25 @@ def main(): dst_group = module.params['dst_group'] src_group = module.params['src_group'] state = module.params['state'] - - # Add tenant_span_dst_grp to module.params for URL building - module.params['tenant_span_src_grp'] = src_group + tenant = module.params['tenant'] aci = ACIModule(module) - aci.construct_url(root_class='tenant', subclass_1='tenant_span_src_grp', child_classes=['spanSpanLbl']) + aci.construct_url( + root_class=dict( + aci_class='fvTenant', + aci_rn='tn-{}'.format(tenant), + filter_target='(fvTenant.name, "{}")'.format(tenant), + module_object=tenant, + ), + subclass_1=dict( + aci_class='spanSrcGrp', + aci_rn='srcgrp-{}'.format(src_group), + filter_target='(spanSrcGrp.name, "{}")'.format(src_group), + module_object=src_group, + ), + child_classes=['spanSpanLbl'], + ) + aci.get_existing() if state == 'present': @@ -133,9 +146,6 @@ def main(): elif state == 'absent': aci.delete_config() - # Remove tenant_span_src_grp that was used to build URL from module.params - module.params.pop('tenant_span_src_grp') - module.exit_json(**aci.result) 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 49a708dd5f..2574f610b4 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 @@ -95,13 +95,30 @@ def main(): dst_group = module.params['dst_group'] src_group = module.params['src_group'] state = module.params['state'] - - # Add tenant_span_src_grp and tenant_span_src_grp_dst_grp to module.params for URL building - module.params['tenant_span_src_grp'] = src_group - module.params['tenant_span_src_grp_dst_grp'] = dst_group + tenant = module.params['tenant'] aci = ACIModule(module) - aci.construct_url(root_class='tenant', subclass_1='tenant_span_src_grp', subclass_2='tenant_span_src_grp_dst_grp') + aci.construct_url( + root_class=dict( + aci_class='fvTenant', + aci_rn='tn-{}'.format(tenant), + filter_target='(fvTenant.name, "{}")'.format(tenant), + module_object=tenant, + ), + subclass_1=dict( + aci_class='spanSrcGrp', + aci_rn='srcgrp-{}'.format(src_group), + filter_target='(spanSrcGrp.name, "{}")'.format(src_group), + module_object=src_group, + ), + subclass_2=dict( + aci_class='spanSpanLbl', + aci_rn='spanlbl-{}'.format(dst_group), + filter_target='(spanSpanLbl.name, "{}")'.format(dst_group), + module_object=dst_group, + ), + ) + aci.get_existing() if state == 'present': @@ -123,10 +140,6 @@ def main(): elif state == 'absent': aci.delete_config() - # Remove tenant_span_src_grp and tenant_span_src_grp_dst_grp that was used to build URL from module.params - module.params.pop('tenant_span_src_grp') - module.params.pop('tenant_span_src_grp_dst_grp') - module.exit_json(**aci.result) diff --git a/lib/ansible/modules/network/aci/aci_vrf.py b/lib/ansible/modules/network/aci/aci_vrf.py index 36c2ac0042..dec63295ac 100644 --- a/lib/ansible/modules/network/aci/aci_vrf.py +++ b/lib/ansible/modules/network/aci/aci_vrf.py @@ -128,10 +128,24 @@ def main(): policy_control_direction = module.params['policy_control_direction'] policy_control_preference = module.params['policy_control_preference'] state = module.params['state'] + tenant = module.params['tenant'] vrf = module.params['vrf'] aci = ACIModule(module) - aci.construct_url(root_class="tenant", subclass_1="vrf") + aci.construct_url( + root_class=dict( + aci_class='fvTenant', + aci_rn='tn-{}'.format(tenant), + filter_target='(fvTenant.name, "{}")'.format(tenant), + module_object=tenant, + ), + subclass_1=dict( + aci_class='fvCtx', + aci_rn='ctx-{}'.format(vrf), + filter_target='(fvCtx.name, "{}")'.format(vrf), + module_object=vrf, + ), + ) aci.get_existing() if state == 'present':