ansible-collections / cisco.nxos

Ansible Network Collection for Cisco NXOS
GNU General Public License v3.0
114 stars 105 forks source link

nxos.static_routes - if given prefix is not configured all routes in configuration get deleted - relative to VRF or global #864

Open a-l-e-x-b opened 1 month ago

a-l-e-x-b commented 1 month ago
SUMMARY

Executing the provided playbook below multiple times with the very same prefix will delete the prefix if found in configuration under global or VRF context. If given prefix is not found in configuration all the routes in configuration - relative to VRF or global configuration - get deleted.

ISSUE TYPE
COMPONENT NAME

cisco.nxos.nxos_static_routes

ANSIBLE VERSION

ansible [core 2.16.7] config file = None configured module search path = ['/home/user1/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /home/user1/python/ansible_nxos/lib/python3.10/site-packages/ansible ansible collection location = /home/user1/.ansible/collections:/usr/share/ansible/collections executable location = /home/user1/python/ansible_nxos/bin/ansible python version = 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] (/home/user1/python/ansible_nxos/bin/python3.10) jinja version = 3.1.4 libyaml = True

COLLECTION VERSION
$ ansible-galaxy collection list | grep nxos
# /home/user1/python/ansible_nxos/lib/python3.10/site-packages/ansible_collections
cisco.nxos                               8.1.0
CONFIGURATION
CONFIG_FILE() = None
OS / ENVIRONMENT

No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.4 LTS Release: 22.04 Codename: jammy

Target Device Cisco Nexus 9000:

Software BIOS: version 05.47 NXOS: version 9.3(11) BIOS compile time: 04/28/2022 NXOS image file is: bootflash:///nxos.9.3.11.bin NXOS compile time: 1/15/2023 12:00:00 [01/24/2023 09:38:35]

Hardware cisco Nexus9000 C9348GC-FXP Chassis Intel(R) Xeon(R) CPU D-1526 @ 1.80GHz with 24570088 kB of memory. Processor Board ID FDO22512SLF

STEPS TO REPRODUCE

Execute the playbook multiple times. On first run the specified prefix gets deleted as expected. On the next run all the routes in the VRF get deleted. With the very same prefix specified tough.

---
- name: Modify route
  gather_facts: no
  hosts: "all"
  connection: ansible.netcommon.network_cli
  vars:
    ansible_network_os: cisco.nxos.nxos
    ansible_network_cli_ssh_type: paramiko
    ansible_command_timeout: 3000
    ansible_connect_timeout: 3000
    ansible_ssh_host_key_checking : false
    ansible_paramiko_host_key_checking: false
    NW: "192.168.199.0/24"
    NH: "10.40.0.110"
    DESC: "default ansible description"
    AFI: "ipv4"
    VRF: "alex-test-vrf"

    ANSIBLE_STATE: "deleted"   
    #   
    DESC_CLEAN: "{{ DESC|replace(' ', '_')|lower }}"

  vars_prompt:
    - name: ansible_user
      prompt: What is your username?
      private: false
    - name: ansible_password
      prompt: What is your password?

  tasks:
    - name: Add/delete route {{ NW }}
      cisco.nxos.nxos_static_routes:
        config: 
        - vrf: "{{ VRF }}"
          address_families:
          - afi: "{{ AFI }}"
            routes:
            - dest: "{{ NW }}"
              next_hops:
              - forward_router_address: "{{ NH }}"
                route_name: "{{ DESC_CLEAN }}"

        state: "{{ ANSIBLE_STATE }}"
EXPECTED RESULTS

I expect the prefix to be deleted if prefix is present in the configuration. On subsequent executions if prefix is not present in configuration I expect nothing to happen. I do not expect that all routes relative to VRF or global config are deleted when explicit prefix is given. Behavior is the same if run with a VRF context or on global routing configuration.

ACTUAL RESULTS

If prefix is not given in the configuration all routes in respect to VRF or global routing configuration get deleted from configuration.

Initial state:

gcat50-testlab# sh run | section vrf
  limit-resource vrf minimum 2 maximum 4096
vrf context alex-test-vrf
  ip route 192.168.197.0/24 10.40.0.110 name default_ansible_description
  ip route 192.168.198.0/24 10.40.0.110 name default_ansible_description
  ip route 192.168.199.0/24 10.40.0.110 name default_ansible_description
vrf context management
  vrf member management
gcat50-testlab#

#
# Playbook-run:
#

(ansible_nxos) user1@mgmt-vm:~/docs/ansible/add_route_core$ ansible-playbook -vvv  add_route_core.yaml -i inventory/inventory.yml
ansible-playbook [core 2.16.7]
  config file = None
  configured module search path = ['/home/user1/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/user1/python/ansible_nxos/lib/python3.10/site-packages/ansible
  ansible collection location = /home/user1/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/user1/python/ansible_nxos/bin/ansible-playbook
  python version = 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] (/home/user1/python/ansible_nxos/bin/python3.10)
  jinja version = 3.1.4
  libyaml = True
No config file found; using defaults
host_list declined parsing /home/user1/docs/ansible/add_route_core/inventory/inventory.yml as it did not pass its verify_file() method
script declined parsing /home/user1/docs/ansible/add_route_core/inventory/inventory.yml as it did not pass its verify_file() method
Using inventory plugin 'ansible_collections.networktocode.nautobot.plugins.inventory.inventory' to process inventory source '/home/user1/docs/ansible/add_route_core/inventory/inventory.yml'
Fetching: https://ntbt.acme.org/api/docs/?format=openapi
Fetching: https://ntbt.acme.org/api/dcim/devices/?limit=0&tenant=acme_testlab&has_primary_ip=true&status=active&platform=cisco_nxos&exclude=config_context
Fetching: https://ntbt.acme.org/api/virtualization/virtual-machines/?limit=0&tenant=acme_testlab&exclude=config_context
Fetching: https://ntbt.acme.org/api/dcim/sites/?limit=0
Fetching: https://ntbt.acme.org/api/dcim/regions/?limit=0
Fetching: https://ntbt.acme.org/api/tenancy/tenants/?limit=0
Fetching: https://ntbt.acme.org/api/dcim/racks/?limit=0
Fetching: https://ntbt.acme.org/api/dcim/rack-groups/?limit=0
Fetching: https://ntbt.acme.org/api/dcim/device-roles/?limit=0
Fetching: https://ntbt.acme.org/api/dcim/platforms/?limit=0
Fetching: https://ntbt.acme.org/api/dcim/device-types/?limit=0
Fetching: https://ntbt.acme.org/api/dcim/manufacturers/?limit=0
Fetching: https://ntbt.acme.org/api/virtualization/clusters/?limit=0
Fetching: https://ntbt.acme.org/api/ipam/services/?limit=0
Parsed /home/user1/docs/ansible/add_route_core/inventory/inventory.yml inventory source with auto plugin
Skipping callback 'default', as we already have a stdout callback.
Skipping callback 'minimal', as we already have a stdout callback.
Skipping callback 'oneline', as we already have a stdout callback.

PLAYBOOK: add_route_core.yaml ********************************************************************************************************
1 plays in add_route_core.yaml
What is your username?: user1
What is your password?:

PLAY [Add route] *********************************************************************************************************************

TASK [Check if route is valid ipv4 network] ******************************************************************************************
task path: /home/user1/docs/ansible/add_route_core/add_route_core.yaml:41
ok: [gcat50-testlab] => {
    "ansible_facts": {
        "IS_NETWORK": true
    },
    "changed": false,
    "failed_when_result": false
}

TASK [Check if nexthop is valid ipv4 address] ****************************************************************************************
task path: /home/user1/docs/ansible/add_route_core/add_route_core.yaml:48
ok: [gcat50-testlab] => {
    "ansible_facts": {
        "IS_HOST": false
    },
    "changed": false,
    "failed_when_result": false
}

TASK [Print sanitized route description] *********************************************************************************************
task path: /home/user1/docs/ansible/add_route_core/add_route_core.yaml:68
ok: [gcat50-testlab] => {
    "DESC_CLEAN": "default_ansible_description"
}

TASK [Add route 192.168.199.0/24] ****************************************************************************************************
task path: /home/user1/docs/ansible/add_route_core/add_route_core.yaml:73
changed: [gcat50-testlab] => {
    "after": [
        {
            "address_families": [
                {
                    "afi": "ipv4",
                    "routes": [
                        {
                            "dest": "0.0.0.0/0",
                            "next_hops": [
                                {
                                    "forward_router_address": "10.40.254.1"
                                }
                            ]
                        },
                        {
                            "dest": "10.40.0.0/24",
                            "next_hops": [
                                {
                                    "forward_router_address": "10.40.0.140",
                                    "route_name": "erst_recht_nicht_vonANSiblE"
                                }
                            ]
                        }
                    ]
                }
            ]
        },
        {
            "address_families": [
                {
                    "afi": "ipv4",
                    "routes": [
                        {
                            "dest": "192.168.197.0/24",
                            "next_hops": [
                                {
                                    "forward_router_address": "10.40.0.110",
                                    "route_name": "default_ansible_description"
                                }
                            ]
                        },
                        {
                            "dest": "192.168.198.0/24",
                            "next_hops": [
                                {
                                    "forward_router_address": "10.40.0.110",
                                    "route_name": "default_ansible_description"
                                }
                            ]
                        }
                    ]
                }
            ],
            "vrf": "alex-test-vrf"
        }
    ],
    "before": [
        {
            "address_families": [
                {
                    "afi": "ipv4",
                    "routes": [
                        {
                            "dest": "0.0.0.0/0",
                            "next_hops": [
                                {
                                    "forward_router_address": "10.40.254.1"
                                }
                            ]
                        },
                        {
                            "dest": "10.40.0.0/24",
                            "next_hops": [
                                {
                                    "forward_router_address": "10.40.0.140",
                                    "route_name": "erst_recht_nicht_vonANSiblE"
                                }
                            ]
                        }
                    ]
                }
            ]
        },
        {
            "address_families": [
                {
                    "afi": "ipv4",
                    "routes": [
                        {
                            "dest": "192.168.197.0/24",
                            "next_hops": [
                                {
                                    "forward_router_address": "10.40.0.110",
                                    "route_name": "default_ansible_description"
                                }
                            ]
                        },
                        {
                            "dest": "192.168.198.0/24",
                            "next_hops": [
                                {
                                    "forward_router_address": "10.40.0.110",
                                    "route_name": "default_ansible_description"
                                }
                            ]
                        },
                        {
                            "dest": "192.168.199.0/24",
                            "next_hops": [
                                {
                                    "forward_router_address": "10.40.0.110",
                                    "route_name": "default_ansible_description"
                                }
                            ]
                        }
                    ]
                }
            ],
            "vrf": "alex-test-vrf"
        }
    ],
    "changed": true,
    "commands": [
        "vrf context alex-test-vrf",
        "no ip route 192.168.199.0/24 10.40.0.110 name default_ansible_description"
    ],
    "invocation": {
        "module_args": {
            "config": [
                {
                    "address_families": [
                        {
                            "afi": "ipv4",
                            "routes": [
                                {
                                    "dest": "192.168.199.0/24",
                                    "next_hops": [
                                        {
                                            "admin_distance": null,
                                            "dest_vrf": null,
                                            "forward_router_address": "10.40.0.110",
                                            "interface": null,
                                            "route_name": "default_ansible_description",
                                            "tag": null,
                                            "track": null
                                        }
                                    ]
                                }
                            ]
                        }
                    ],
                    "vrf": "alex-test-vrf"
                }
            ],
            "running_config": null,
            "state": "deleted"
        }
    }
}

PLAY RECAP ***************************************************************************************************************************
gcat50-testlab             : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

(ansible_nxos) user1@mgmt-vm:~/docs/ansible/add_route_core$

#
# END Playbook-run:
#

#
# After first playbook run: - as expected - Net 192.168.199.0/24 got deleted:
#

gcat50-testlab# sh run | section vrf
  limit-resource vrf minimum 2 maximum 4096
vrf context alex-test-vrf
  ip route 192.168.197.0/24 10.40.0.110 name default_ansible_description
  ip route 192.168.198.0/24 10.40.0.110 name default_ansible_description
vrf context management
  vrf member management
gcat50-testlab#

#
# Next Playbook run - deletes ale routes in the VRF :
#

(ansible_nxos) user1@mgmt-vm:~/docs/ansible/add_route_core$ ansible-playbook -vvv  add_route_core.yaml -i inventory/inventory.yml
ansible-playbook [core 2.16.7]
  config file = None
  configured module search path = ['/home/user1/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/user1/python/ansible_nxos/lib/python3.10/site-packages/ansible
  ansible collection location = /home/user1/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/user1/python/ansible_nxos/bin/ansible-playbook
  python version = 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] (/home/user1/python/ansible_nxos/bin/python3.10)
  jinja version = 3.1.4
  libyaml = True
No config file found; using defaults
host_list declined parsing /home/user1/docs/ansible/add_route_core/inventory/inventory.yml as it did not pass its verify_file() method
script declined parsing /home/user1/docs/ansible/add_route_core/inventory/inventory.yml as it did not pass its verify_file() method
Using inventory plugin 'ansible_collections.networktocode.nautobot.plugins.inventory.inventory' to process inventory source '/home/user1/docs/ansible/add_route_core/inventory/inventory.yml'
Fetching: https://ntbt.acme.org/api/docs/?format=openapi
Fetching: https://ntbt.acme.org/api/dcim/devices/?limit=0&tenant=acme_testlab&has_primary_ip=true&status=active&platform=cisco_nxos&exclude=config_context
Fetching: https://ntbt.acme.org/api/virtualization/virtual-machines/?limit=0&tenant=acme_testlab&exclude=config_context
Fetching: https://ntbt.acme.org/api/dcim/sites/?limit=0
Fetching: https://ntbt.acme.org/api/dcim/regions/?limit=0
Fetching: https://ntbt.acme.org/api/tenancy/tenants/?limit=0
Fetching: https://ntbt.acme.org/api/dcim/racks/?limit=0
Fetching: https://ntbt.acme.org/api/dcim/rack-groups/?limit=0
Fetching: https://ntbt.acme.org/api/dcim/device-roles/?limit=0
Fetching: https://ntbt.acme.org/api/dcim/platforms/?limit=0
Fetching: https://ntbt.acme.org/api/dcim/device-types/?limit=0
Fetching: https://ntbt.acme.org/api/dcim/manufacturers/?limit=0
Fetching: https://ntbt.acme.org/api/virtualization/clusters/?limit=0
Fetching: https://ntbt.acme.org/api/ipam/services/?limit=0
Parsed /home/user1/docs/ansible/add_route_core/inventory/inventory.yml inventory source with auto plugin
Skipping callback 'default', as we already have a stdout callback.
Skipping callback 'minimal', as we already have a stdout callback.
Skipping callback 'oneline', as we already have a stdout callback.

PLAYBOOK: add_route_core.yaml ********************************************************************************************************
1 plays in add_route_core.yaml
What is your username?: user1
What is your password?:

PLAY [Add route] *********************************************************************************************************************

TASK [Check if route is valid ipv4 network] ******************************************************************************************
task path: /home/user1/docs/ansible/add_route_core/add_route_core.yaml:41
ok: [gcat50-testlab] => {
    "ansible_facts": {
        "IS_NETWORK": true
    },
    "changed": false,
    "failed_when_result": false
}

TASK [Check if nexthop is valid ipv4 address] ****************************************************************************************
task path: /home/user1/docs/ansible/add_route_core/add_route_core.yaml:48
ok: [gcat50-testlab] => {
    "ansible_facts": {
        "IS_HOST": false
    },
    "changed": false,
    "failed_when_result": false
}

TASK [Print sanitized route description] *********************************************************************************************
task path: /home/user1/docs/ansible/add_route_core/add_route_core.yaml:68
ok: [gcat50-testlab] => {
    "DESC_CLEAN": "default_ansible_description"
}

TASK [Add route 192.168.199.0/24] ****************************************************************************************************
task path: /home/user1/docs/ansible/add_route_core/add_route_core.yaml:73
changed: [gcat50-testlab] => {
    "after": [
        {
            "address_families": [
                {
                    "afi": "ipv4",
                    "routes": [
                        {
                            "dest": "0.0.0.0/0",
                            "next_hops": [
                                {
                                    "forward_router_address": "10.40.254.1"
                                }
                            ]
                        },
                        {
                            "dest": "10.40.0.0/24",
                            "next_hops": [
                                {
                                    "forward_router_address": "10.40.0.140",
                                    "route_name": "erst_recht_nicht_vonANSiblE"
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    ],
    "before": [
        {
            "address_families": [
                {
                    "afi": "ipv4",
                    "routes": [
                        {
                            "dest": "0.0.0.0/0",
                            "next_hops": [
                                {
                                    "forward_router_address": "10.40.254.1"
                                }
                            ]
                        },
                        {
                            "dest": "10.40.0.0/24",
                            "next_hops": [
                                {
                                    "forward_router_address": "10.40.0.140",
                                    "route_name": "erst_recht_nicht_vonANSiblE"
                                }
                            ]
                        }
                    ]
                }
            ]
        },
        {
            "address_families": [
                {
                    "afi": "ipv4",
                    "routes": [
                        {
                            "dest": "192.168.197.0/24",
                            "next_hops": [
                                {
                                    "forward_router_address": "10.40.0.110",
                                    "route_name": "default_ansible_description"
                                }
                            ]
                        },
                        {
                            "dest": "192.168.198.0/24",
                            "next_hops": [
                                {
                                    "forward_router_address": "10.40.0.110",
                                    "route_name": "default_ansible_description"
                                }
                            ]
                        }
                    ]
                }
            ],
            "vrf": "alex-test-vrf"
        }
    ],
    "changed": true,
    "commands": [
        "vrf context alex-test-vrf",
        "no ip route 192.168.197.0/24 10.40.0.110 name default_ansible_description",
        "no ip route 192.168.198.0/24 10.40.0.110 name default_ansible_description"
    ],
    "invocation": {
        "module_args": {
            "config": [
                {
                    "address_families": [
                        {
                            "afi": "ipv4",
                            "routes": [
                                {
                                    "dest": "192.168.199.0/24",
                                    "next_hops": [
                                        {
                                            "admin_distance": null,
                                            "dest_vrf": null,
                                            "forward_router_address": "10.40.0.110",
                                            "interface": null,
                                            "route_name": "default_ansible_description",
                                            "tag": null,
                                            "track": null
                                        }
                                    ]
                                }
                            ]
                        }
                    ],
                    "vrf": "alex-test-vrf"
                }
            ],
            "running_config": null,
            "state": "deleted"
        }
    }
}

PLAY RECAP ***************************************************************************************************************************
gcat50-testlab             : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

(ansible_nxos) user1@mgmt-vm:~/docs/ansible/add_route_core$

#
# After the playbook run no routes are present anymore in the VRF:
#
gcat50-testlab# sh run | section vrf
  limit-resource vrf minimum 2 maximum 4096
vrf context alex-test-vrf
vrf context management
  vrf member management
gcat50-testlab#