ansible-collections/cisco.nxos

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

a-l-e-x-b opened this issue · 0 comments

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
  • Bug Report
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#