From 3ee92b404f5521212f9de36d6469c5a4e8577a9d Mon Sep 17 00:00:00 2001 From: lukebates123 Date: Mon, 8 May 2023 21:46:59 -0500 Subject: [PATCH] add bgp ansible --- canu/ansible/ansible.cfg | 4 ++ canu/ansible/filter_plugins/nutils.py | 6 ++ canu/ansible/plays/bgp_config.yaml | 82 ++++++++++++++++++++++++ canu/ansible/templates/bgp.j2 | 89 +++++++++++++++++++++++++++ 4 files changed, 181 insertions(+) create mode 100644 canu/ansible/ansible.cfg create mode 100644 canu/ansible/filter_plugins/nutils.py create mode 100644 canu/ansible/plays/bgp_config.yaml create mode 100644 canu/ansible/templates/bgp.j2 diff --git a/canu/ansible/ansible.cfg b/canu/ansible/ansible.cfg new file mode 100644 index 000000000..e93c634b4 --- /dev/null +++ b/canu/ansible/ansible.cfg @@ -0,0 +1,4 @@ +[defaults] + +filter_plugins = filter_plugins +host_key_checking = false \ No newline at end of file diff --git a/canu/ansible/filter_plugins/nutils.py b/canu/ansible/filter_plugins/nutils.py new file mode 100644 index 000000000..f80adbf48 --- /dev/null +++ b/canu/ansible/filter_plugins/nutils.py @@ -0,0 +1,6 @@ +from netutils.utils import jinja2_convenience_function + + +class FilterModule(object): + def filters(self): + return jinja2_convenience_function() diff --git a/canu/ansible/plays/bgp_config.yaml b/canu/ansible/plays/bgp_config.yaml new file mode 100644 index 000000000..70ba08f50 --- /dev/null +++ b/canu/ansible/plays/bgp_config.yaml @@ -0,0 +1,82 @@ +--- +- name: Configure BGP + hosts: spine + collections: + - arubanetworks.aoscx + gather_facts: true + + vars: + sls_json: "{{ lookup('file', 'sls_input_file.json') | from_json }}" + hostname: "{{ inventory_hostname }}" + bgp_max_paths: 32 + bgp_keepalive_timer: 1 + bgp_hold_timer: 3 + ebgp_admin_distance: 20 + ibgp_admin_distance: 70 + bgp_config_file: "{{ playbook_dir }}/bgp_config_{{ inventory_hostname }}.cfg" + bgp_template: "{{ playbook_dir }}/bgp_ansible.j2" + backup_path: "{{ playbook_dir }}" + ansible_connection: network_cli + + tasks: + - name: Set BGP ASNs + set_fact: + bgp_cmn: "{{ sls_json.Networks.CMN.ExtraProperties.MyASN | default(None) }}" + bgp_chn: "{{ sls_json.Networks.CHN.ExtraProperties.MyASN | default(None) }}" + bgp_nmn: "{{ sls_json.Networks.NMN.ExtraProperties.MyASN | default(None) }}" + bgp_switch: "{{ sls_json.Networks.NMN.ExtraProperties.PeerASN | default(None) }}" + + - name: Set IP addresses + set_fact: + nmn_ips: "{{ sls_json.Networks.NMN.ExtraProperties.Subnets | json_query(jmesquery) | default(None) }}" + hmn_ips: "{{ sls_json.Networks.HMN.ExtraProperties.Subnets | json_query(jmesquery) | default(None) }}" + nmn_lb_ips: "{{ sls_json.Networks.NMN.ExtraProperties.Subnets | json_query(jmesquery) | default(None) }}" + hmn_lb_ips: "{{ sls_json.Networks.HMN.ExtraProperties.Subnets | json_query(jmesquery) | default(None) }}" + can_ips: "{{ sls_json.Networks.CAN.ExtraProperties.Subnets | json_query(jmesquery) | default(None) }}" + cmn_ips: "{{ sls_json.Networks.CMN.ExtraProperties.Subnets | json_query(jmesquery) | default(None) }}" + chn_ips: "{{ sls_json.Networks.CHN.ExtraProperties.Subnets | json_query(jmesquery) | default(None) }}" + vars: + jmesquery: "[].IPReservations[].{Name: Name, IPAddress: IPAddress}" + + - name: Set Subnets + set_fact: + can_subnet: "{{ sls_json.Networks.CAN.ExtraProperties.CIDR | default(None) }}" + cmn_subnet: "{{ sls_json.Networks.CMN.ExtraProperties.CIDR | default(None) }}" + chn_subnet: "{{ sls_json.Networks.CHN.ExtraProperties.CIDR | default(None) }}" + hmnlb_subnet: "{{ sls_json.Networks.HMNLB.ExtraProperties.CIDR | default(None) }}" + nmnlb_subnet: "{{ sls_json.Networks.NMNLB.ExtraProperties.CIDR | default(None) }}" + + - name: Set TFTP IPs + set_fact: + hmnlb_tftp_ip: "{{ sls_json.Networks.HMNLB.ExtraProperties.Subnets | json_query(jmesquery) | default(None) }}" + nmnlb_tftp_ip: "{{ sls_json.Networks.NMNLB.ExtraProperties.Subnets | json_query(jmesquery) | default(None) }}" + vars: + jmesquery: "[].IPReservations[?Name=='cray-tftp'].IPAddress[] | [0]" + + - name: Generate BGP config + ansible.builtin.template: + src: "{{ bgp_template }}" + dest: "{{ bgp_config_file }}" + lstrip_blocks: yes + + - name: Enable auto-confirm + aoscx_command: + commands: + - auto-confirm + + - name: Configure BGP + aoscx_config: + backup: True + src: "{{ bgp_config_file }}" + save_when: changed + backup_options: + filename: "{{hostname}}_backup.cfg" + dir_path: "{{ backup_path }}" + register: bgp + + - name: Clear BGP Sessions + aoscx_command: + commands: + - clear bgp vrf Customer * + - clear bgp * + when: bgp.changed diff --git a/canu/ansible/templates/bgp.j2 b/canu/ansible/templates/bgp.j2 new file mode 100644 index 000000000..5d13af67a --- /dev/null +++ b/canu/ansible/templates/bgp.j2 @@ -0,0 +1,89 @@ +ip prefix-list pl-cmn seq 10 permit {{ cmn_subnet }} ge {{ cmn_subnet | ipaddress_network("prefixlen") }} +{% if can_subnet != '' %} +ip prefix-list pl-can seq 10 permit {{ can_subnet}} ge {{ can_subnet | ipaddress_network("prefixlen") }} +{% endif %} +ip prefix-list pl-hmn seq 10 permit {{ hmnlb_subnet }} ge {{ hmnlb_subnet | ipaddress_network("prefixlen") }} +ip prefix-list pl-nmn seq 10 permit {{ nmnlb_subnet }} ge {{ nmnlb_subnet | ipaddress_network("prefixlen") }} +{% set seq_num = 10 %} +ip prefix-list tftp seq {{ seq_num }} permit {{ nmnlb_tftp_ip | ipaddress_address("exploded") }}/32 ge 32 le 32 +{% set seq_num = seq_num + 10 %} +ip prefix-list tftp seq {{ seq_num }} permit {{ hmnlb_tftp_ip | ipaddress_address("exploded") }}/32 ge 32 le 32 + +{% for host in nmn_ips if "ncn-w" in host.Name %} +{% set sequence = namespace(value=10) %} +{% set localpref = namespace(value=1000) %} +{% for tftp_host in nmn_ips if tftp_host.Name in ["ncn-w001", "ncn-w002", "ncn-w003"] %} +route-map {{ host.Name }} permit seq {{ sequence.value }}{% set sequence.value = sequence.value + 10 %} + + match ip address prefix-list tftp + match ip next-hop {{ tftp_host.IPAddress | ipaddress_address("exploded") }} + set local-preference {{ localpref.value }}{% set localpref.value = localpref.value + 100 %} + +{% endfor %} + +route-map {{ host.Name }} permit seq {{ sequence.value }} + match ip address prefix-list pl-hmn + {% for hmn_entry in hmn_ips if host.Name == hmn_entry.Name %} + set ip next-hop {{ hmn_entry.IPAddress | ipaddress_address("exploded") }} + {% endfor %} + +{% set sequence.value = sequence.value + 10 %}route-map {{ host.Name }} permit seq {{ sequence.value }} + match ip address prefix-list pl-nmn + {% for nmn_entry in nmn_ips if host.Name == nmn_entry.Name %} + set ip next-hop {{ nmn_entry.IPAddress | ipaddress_address("exploded") }} + {% endfor %} +{% set sequence = namespace(value=10) %} +{% if can_subnet != '' %} +route-map {{ host.Name }}-Customer permit seq {{ sequence.value }} + set local-preference 1100 + {% for can_entry in can_ips if name == can_entry.Name %} + set ip next-hop {{ can_entry.IPAddress | ipaddress_address("exploded") }} +{% endfor %} +{% endif %} +{% if can_subnet == '' %} + {% set sequence.value = sequence.value + 10 %} +{% endif %} +route-map {{ host.Name }}-Customer permit seq {{ sequence.value }} + match ip address prefix-list pl-cmn + +{% endfor %} +router bgp {{ bgp_switch }} + bgp router-id {{ ansible_host }} + maximum-paths {{ bgp_max_paths }} + timers bgp {{ bgp_keepalive_timer }} {{ bgp_hold_timer }} + distance bgp {{ ebgp_admin_distance }} {{ ibgp_admin_distance }} + {% for host in nmn_ips if "spine" in host.Name and host.Name != hostname %} + neighbor {{ host.IPAddress | ipaddress_address("exploded") }} remote-as {{ bgp_switch }} + {% endfor %} + {% for host in nmn_ips if "ncn-w" in host.Name %} + neighbor {{ host.IPAddress | ipaddress_address("exploded") }} remote-as {{ bgp_nmn }} + neighbor {{ host.IPAddress | ipaddress_address("exploded") }} passive + {% endfor %} + address-family ipv4 unicast + {% for host in nmn_ips if "spine" in host.Name and host.Name != hostname or "ncn-w" in host.Name %} + neighbor {{ host.IPAddress | ipaddress_address("exploded") }} activate + {% if "ncn-w" in host.Name %} + neighbor {{ host.IPAddress | ipaddress_address("exploded") }} route-map {{ host.Name }} in + {% endif %} + {% endfor %} + exit-address-family + vrf Customer + bgp router-id {{ ansible_host }} + maximum-paths {{ bgp_max_paths }} + timers bgp {{ bgp_keepalive_timer }} {{ bgp_hold_timer }} + distance bgp {{ ebgp_admin_distance }} {{ ibgp_admin_distance }} + {% for host in cmn_ips if "spine" in host.Name and host.Name != hostname %} + neighbor {{ host.IPAddress | ipaddress_address("exploded") }} remote-as {{ bgp_switch }} + {% endfor %} + {% for host in cmn_ips if "ncn-w" in host.Name %} + neighbor {{ host.IPAddress | ipaddress_address("exploded") }} remote-as {{ bgp_cmn }} + neighbor {{ host.IPAddress | ipaddress_address("exploded") }} passive + {% endfor %} + address-family ipv4 unicast + {% for host in cmn_ips if "spine" in host.Name and host.Name != hostname or "ncn-w" in host.Name %} + neighbor {{ host.IPAddress | ipaddress_address("exploded") }} activate + {% if "ncn-w" in host.Name %} + neighbor {{ host.IPAddress | ipaddress_address("exploded") }} route-map {{ host.Name }}-Customer in + {% endif %} + {% endfor %} + exit-address-family \ No newline at end of file