#!/usr/bin/python # Copyright: (c) 2018, Pluribus Networks # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function __metaclass__ = type ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'} DOCUMENTATION = ''' --- module: pn_vrouter_bgp author: "Pluribus Networks (@rajaspachipulusu17)" short_description: CLI command to add/modify/remove vrouter-bgp description: - This module can be used to add Border Gateway Protocol neighbor to a vRouter modify Border Gateway Protocol neighbor to a vRouter and remove Border Gateway Protocol neighbor from a vRouter. options: pn_cliswitch: description: - Target switch to run the CLI on. required: false type: str state: description: - vrouter-bgp configuration command. required: false type: str choices: ['present', 'absent', 'update'] default: 'present' pn_neighbor: description: - IP address for BGP neighbor. required: true type: str pn_vrouter_name: description: - name of service config. required: true type: str pn_send_community: description: - send any community attribute to neighbor. required: false type: bool pn_weight: description: - default weight value between 0 and 65535 for the neighbor's routes. required: false pn_multi_protocol: description: - Multi-protocol features. required: false choices: ['ipv4-unicast', 'ipv6-unicast'] pn_prefix_list_in: description: - prefixes used for filtering. required: false type: str pn_route_reflector_client: description: - set as route reflector client. required: false type: bool pn_default_originate: description: - announce default routes to the neighbor or not. required: false type: bool pn_neighbor_holdtime: description: - BGP Holdtime (seconds). required: false type: str pn_connect_retry_interval: description: - BGP Connect retry interval (seconds). required: false type: str pn_advertisement_interval: description: - Minimum interval between sending BGP routing updates. required: false type: str pn_route_map_out: description: - route map out for nbr. required: false type: str pn_update_source: description: - IP address of BGP packets required for peering over loopback interface. required: false type: str pn_bfd: description: - BFD protocol support for fault detection. required: false type: bool default: False pn_next_hop_self: description: - BGP next hop is self or not. required: false type: bool pn_allowas_in: description: - Allow/reject routes with local AS in AS_PATH. required: false type: bool pn_neighbor_keepalive_interval: description: - BGP Keepalive interval (seconds). required: false type: str pn_max_prefix: description: - maximum number of prefixes. required: false type: str pn_bfd_multihop: description: - always use BFD multi-hop port for fault detection. required: false type: bool pn_interface: description: - Interface to reach the neighbor. required: false type: str pn_password: description: - password for MD5 BGP. required: false type: str pn_route_map_in: description: - route map in for nbr. required: false type: str pn_soft_reconfig_inbound: description: - soft reset to reconfigure inbound traffic. required: false type: bool pn_override_capability: description: - override capability. required: false type: bool pn_max_prefix_warn_only: description: - warn if the maximum number of prefixes is exceeded. required: false type: bool pn_ebgp_multihop: description: - value for external BGP from 1 to 255. required: false type: str pn_remote_as: description: - BGP remote AS from 1 to 4294967295. required: false type: str pn_prefix_list_out: description: - prefixes used for filtering outgoing packets. required: false type: str pn_no_route_map_out: description: - Remove egress route-map from BGP neighbor. required: false type: str pn_no_route_map_in: description: - Remove ingress route-map from BGP neighbor. required: false type: str ''' EXAMPLES = """ - name: "Add BGP to vRouter" pn_vrouter_bgp: state: 'present' pn_vrouter_name: 'sw01-vrouter' pn_neighbor: '105.104.104.1' pn_remote_as: 65000 pn_bfd: true - name: "Remove BGP to vRouter" pn_vrouter_bgp: state: 'absent' pn_vrouter_name: 'sw01-vrouter' pn_neighbor: '105.104.104.1' - name: "Modify BGP to vRouter" pn_vrouter_bgp: state: 'update' pn_vrouter_name: 'sw01-vrouter' pn_neighbor: '105.104.104.1' pn_remote_as: 65000 pn_bfd: false pn_allowas_in: true """ RETURN = """ command: description: the CLI command run on the target node. returned: always type: str stdout: description: set of responses from the vrouter-bgp command. returned: always type: list stderr: description: set of error responses from the vrouter-bgp command. returned: on error type: list changed: description: indicates whether the CLI caused changes on the target. returned: always type: bool """ from ansible.module_utils.basic import AnsibleModule from ansible_collections.community.general.plugins.module_utils.network.netvisor.pn_nvos import pn_cli, run_cli, booleanArgs from ansible_collections.community.general.plugins.module_utils.network.netvisor.netvisor import run_commands def is_valid(module, param_name, param_val, min_val, max_val): if int(param_val) < min_val or int(param_val) > max_val: module.fail_json( failed=True, msg='Valid %s range is %s to %s' % (param_name, min_val, max_val) ) def check_cli(module, cli): """ This method checks if vRouter exists on the target node. This method also checks for idempotency using the vrouter-bgp-show command. If the given vRouter exists, return VROUTER_EXISTS as True else False. If the given neighbor exists on the given vRouter, return NEIGHBOR_EXISTS as True else False. :param module: The Ansible module to fetch input parameters :param cli: The CLI string :return Booleans: VROUTER_EXISTS, NEIGHBOR_EXISTS """ vrouter_name = module.params['pn_vrouter_name'] neighbor = module.params['pn_neighbor'] # Check for vRouter check_vrouter = cli + ' vrouter-show format name no-show-headers' out = run_commands(module, check_vrouter)[1] if out: out = out.split() VROUTER_EXISTS = True if vrouter_name in out else False if neighbor: # Check for BGP neighbor show = cli + ' vrouter-bgp-show vrouter-name %s ' % vrouter_name show += 'format neighbor no-show-headers' out = run_commands(module, show)[1] if out and neighbor in out.split(): NEIGHBOR_EXISTS = True else: NEIGHBOR_EXISTS = False return VROUTER_EXISTS, NEIGHBOR_EXISTS def main(): """ This section is for arguments parsing """ state_map = dict( present='vrouter-bgp-add', absent='vrouter-bgp-remove', update='vrouter-bgp-modify' ) argument_spec = dict( pn_cliswitch=dict(required=False, type='str'), state=dict(required=False, type='str', choices=state_map.keys(), default='present'), pn_neighbor=dict(required=True, type='str'), pn_vrouter_name=dict(required=True, type='str'), pn_send_community=dict(required=False, type='bool'), pn_weight=dict(required=False, type='str'), pn_multi_protocol=dict(required=False, type='str', choices=['ipv4-unicast', 'ipv6-unicast']), pn_prefix_list_in=dict(required=False, type='str'), pn_route_reflector_client=dict(required=False, type='bool'), pn_default_originate=dict(required=False, type='bool'), pn_neighbor_holdtime=dict(required=False, type='str'), pn_connect_retry_interval=dict(required=False, type='str'), pn_advertisement_interval=dict(required=False, type='str'), pn_route_map_out=dict(required=False, type='str'), pn_update_source=dict(required=False, type='str'), pn_bfd=dict(required=False, type='bool', default=False), pn_next_hop_self=dict(required=False, type='bool'), pn_allowas_in=dict(required=False, type='bool'), pn_neighbor_keepalive_interval=dict(required=False, type='str'), pn_max_prefix=dict(required=False, type='str'), pn_bfd_multihop=dict(required=False, type='bool'), pn_interface=dict(required=False, type='str'), pn_password=dict(required=False, type='str', no_log=True), pn_route_map_in=dict(required=False, type='str'), pn_soft_reconfig_inbound=dict(required=False, type='bool'), pn_override_capability=dict(required=False, type='bool'), pn_max_prefix_warn_only=dict(required=False, type='bool'), pn_ebgp_multihop=dict(required=False, type='str'), pn_remote_as=dict(required=False, type='str'), pn_prefix_list_out=dict(required=False, type='str'), pn_no_route_map_out=dict(required=False, type='str'), pn_no_route_map_in=dict(required=False, type='str'), ) module = AnsibleModule( argument_spec=argument_spec, required_if=( ["state", "present", ["pn_vrouter_name", "pn_neighbor", "pn_remote_as"]], ["state", "absent", ["pn_vrouter_name", "pn_neighbor"]], ["state", "update", ["pn_vrouter_name", "pn_neighbor"]] ), required_one_of=[['pn_send_community', 'pn_weight', 'pn_multi_protocol', 'pn_prefix_list_in', 'pn_route_reflector_client', 'pn_default_originate', 'pn_neighbor_holdtime', 'pn_connect_retry_interval', 'pn_advertisement_interval', 'pn_route_map_out', 'pn_update_source', 'pn_bfd', 'pn_next_hop_self', 'pn_allowas_in', 'pn_neighbor_keepalive_interval', 'pn_max_prefix', 'pn_bfd_multihop', 'pn_interface', 'pn_password', 'pn_route_map_in', 'pn_soft_reconfig_inbound', 'pn_override_capability', 'pn_max_prefix_warn_only', 'pn_ebgp_multihop', 'pn_remote_as', 'pn_prefix_list_out', 'pn_no_route_map_out', 'pn_no_route_map_in']], ) # Accessing the arguments cliswitch = module.params['pn_cliswitch'] state = module.params['state'] neighbor = module.params['pn_neighbor'] vrouter_name = module.params['pn_vrouter_name'] send_community = module.params['pn_send_community'] weight = module.params['pn_weight'] multi_protocol = module.params['pn_multi_protocol'] prefix_list_in = module.params['pn_prefix_list_in'] route_reflector_client = module.params['pn_route_reflector_client'] default_originate = module.params['pn_default_originate'] neighbor_holdtime = module.params['pn_neighbor_holdtime'] connect_retry_interval = module.params['pn_connect_retry_interval'] advertisement_interval = module.params['pn_advertisement_interval'] route_map_out = module.params['pn_route_map_out'] update_source = module.params['pn_update_source'] bfd = module.params['pn_bfd'] next_hop_self = module.params['pn_next_hop_self'] allowas_in = module.params['pn_allowas_in'] neighbor_keepalive_interval = module.params['pn_neighbor_keepalive_interval'] max_prefix = module.params['pn_max_prefix'] bfd_multihop = module.params['pn_bfd_multihop'] interface = module.params['pn_interface'] password = module.params['pn_password'] route_map_in = module.params['pn_route_map_in'] soft_reconfig_inbound = module.params['pn_soft_reconfig_inbound'] override_capability = module.params['pn_override_capability'] max_prefix_warn_only = module.params['pn_max_prefix_warn_only'] ebgp_multihop = module.params['pn_ebgp_multihop'] remote_as = module.params['pn_remote_as'] prefix_list_out = module.params['pn_prefix_list_out'] no_route_map_out = module.params['pn_no_route_map_out'] no_route_map_in = module.params['pn_no_route_map_in'] command = state_map[state] if weight and weight != 'none': if int(weight) < 1 or int(weight) > 65535: module.fail_json( failed=True, msg='Valid weight range is 1 to 65535' ) # Building the CLI command string cli = pn_cli(module, cliswitch) VROUTER_EXISTS, NEIGHBOR_EXISTS = check_cli(module, cli) if state: if VROUTER_EXISTS is False: module.exit_json( skipped=True, msg='vRouter %s does not exist' % vrouter_name ) if command == 'vrouter-bgp-remove' or command == 'vrouter-bgp-modify': if NEIGHBOR_EXISTS is False: module.exit_json( skipped=True, msg='BGP neighbor with IP %s does not exist on %s' % (neighbor, vrouter_name) ) if command == 'vrouter-bgp-add': if NEIGHBOR_EXISTS is True: module.exit_json( skipped=True, msg='BGP neighbor with IP %s already exists on %s' % (neighbor, vrouter_name) ) cli += ' %s vrouter-name %s neighbor %s ' % (command, vrouter_name, neighbor) if command == 'vrouter-bgp-add' or command == 'vrouter-bgp-modify': if weight: cli += ' weight ' + weight if multi_protocol: cli += ' multi-protocol ' + multi_protocol if prefix_list_in: cli += ' prefix-list-in ' + prefix_list_in if neighbor_holdtime: is_valid(module, 'neighbor holdtime', neighbor_holdtime, '0', '65535') cli += ' neighbor-holdtime ' + neighbor_holdtime if connect_retry_interval: is_valid(module, 'connect retry interval', connect_retry_interval, '0', '65535') cli += ' connect-retry-interval ' + connect_retry_interval if advertisement_interval: is_valid(module, 'advertisement interval', advertisement_interval, '0', '65535') cli += ' advertisement-interval ' + advertisement_interval if route_map_out: cli += ' route-map-out ' + route_map_out if update_source: cli += ' update-source ' + update_source if neighbor_keepalive_interval: is_valid(module, 'neighbor keepalive interval', neighbor_keepalive_interval, '0', '65535') cli += ' neighbor-keepalive-interval ' + neighbor_keepalive_interval if max_prefix: cli += ' max-prefix ' + max_prefix if interface: cli += ' interface ' + interface if password: cli += ' password ' + password if route_map_in: cli += ' route-map-in ' + route_map_in if ebgp_multihop: is_valid(module, 'ebgp_multihop', ebgp_multihop, '1', '255') cli += ' ebgp-multihop ' + ebgp_multihop if remote_as: cli += ' remote-as ' + remote_as if prefix_list_out: cli += ' prefix-list-out ' + prefix_list_out cli += booleanArgs(send_community, 'send-community', 'no-send-community') cli += booleanArgs(route_reflector_client, 'route-reflector-client', 'no-route-reflector-client') cli += booleanArgs(default_originate, 'default-originate', 'no-default-originate') cli += booleanArgs(bfd, 'bfd', 'no-bfd') cli += booleanArgs(next_hop_self, 'next-hop-self', 'no-next-hop-self') cli += booleanArgs(allowas_in, 'allowas-in', 'no-allowas-in') cli += booleanArgs(bfd_multihop, 'bfd-multihop', 'no-bfd-multihop') cli += booleanArgs(soft_reconfig_inbound, 'soft-reconfig-inbound', 'no-soft-reconfig-inbound') cli += booleanArgs(override_capability, 'override-capability', 'no-override-capability') cli += booleanArgs(max_prefix_warn_only, 'max-prefix-warn-only', 'no-max-prefix-warn-only') if command == 'vrouter-bgp-modify': if no_route_map_out: cli += ' no-route-map-out ' + no_route_map_out if no_route_map_in: cli += ' no-route-map-in ' + no_route_map_in run_cli(module, cli, state_map) if __name__ == '__main__': main()