nautobot / pynautobot

Nautobot Python SDK
https://pynautobot.readthedocs.io/en/latest/index.html
Apache License 2.0
34 stars 29 forks source link

setting primary IP failes when IP assigments are removed and re-assigned #204

Open veritas-sot opened 3 weeks ago

veritas-sot commented 3 weeks ago

Environment:

nautobot 2.2.5 pynautobot: 2.2.0

Details:

When I remove all existing IP assignmets of an interface, then re-assign all IP addresses to the interface and set the primary IP of the device, the primary IP is NOT set. Using the rest API works well. This could be similar to issue 197!

The follwing code does not work, it deletes the primary IP of the device

# get device, interface and IP
device = nautobot.dcim.devices.get(name='lab.local')
interface = nautobot.dcim.interfaces.get(device_id=device.id, name='Loopback0')
ip_address = nautobot.ipam.ip_addresses.get(address='192.168.2.1')

# get list of assigments
id_list = nautobot.ipam.ip_address_to_interface.filter(interface=interface.id, ip_address=ip_address.id)

# remove assignments
for assignment in id_list:
    assignment.delete()

# re-assign
assigned = nautobot.ipam.ip_address_to_interface.create({'interface': interface.id, 'ip_address': ip_address.id} )

# save
save = device.save()
# set primary
success = device.primary_ip4 = ip_address
#save
device.save()

When I add the following line to the code

device = nautobot.dcim.devices.get(name='lab.local')

right before setting the primary IP, it works.

I was asked to open this issue (https://networktocode.slack.com/archives/C01NWPK6WHL/p1718816339526429)

joewesch commented 3 weeks ago

Using the rest API works well

Can you provide the REST API calls that work for you?

veritas-sot commented 3 weeks ago

sure. I have got a little "Layer" between my script and nautobot (authentication and some error handling, nothing more).

# delete assigmnets

for iface in interfaces:
    interface_id = iface.get('id')
    ip_addresses = []
    ip_to_interface = rest.get(url=f"api/ipam/ip-address-to-interface/?interface={interface_id}")
    if ip_to_interface.get('count') > 0:
        ip_to_interface_id = ip_to_interface.get('results')[0].get('id')
        ip_addresses.append(ip_to_interface.get('results')[0].get('ip_address').get('id'))
        response = rest.delete(url=f"api/ipam/ip-address-to-interface/{ip_to_interface_id}/")
        print(response.status_code)
        if response.status_code == 204:
            print(f"Removed assignment from Interface {interface_id}")
        else:
            print(f"Failed to remove assignment from Interface {interface_id}")
            print(response.content)

    # add assigmnents
    for ip in ip_addresses:
        data = {'interface': interface_id, 'ip_address': ip}
        response = rest.post(url="api/ipam/ip-address-to-interface/", json=data)
        if response.status_code == 201:
            print(f"Interface {interface_id} updated")
        else:
            print(f"Interface {interface_id} not update ({response.status_code})")
            print(response.content)

# get IP id
address = "192.168.0.1"
response = rest.get(url=f"api/ipam/ip-addresses/?address={address}", format="json")
if response.get('count') > 0:
    ip_id = response.get('results')[0].get('id')

# set primary IP address
data = {'id': device_id, 'primary_ip4': {'id': ip_id} }
response = rest.patch(url="api/dcim/devices/", json=[data])
if response.status_code == 200:
    print(f"Device {device_id} updated")
else:
    print(f"Device {device_id} not updated ({response.status_code})")
    print(response.content)
joewesch commented 1 week ago

I apologize for the delay in getting back to this.

I was unable to reproduce this error via pynautobot using the demo site (which is currently on 2.2.7) with the following code:

from pynautobot import api
url = "https://demo.nautobot.com/"
token = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
nautobot = api(url=url, token=token)

# get device, interface and IP
device = nautobot.dcim.devices.get(name='atl01-sdwan-02')
interface = nautobot.dcim.interfaces.get(device_id=device.id, name='Loopback0')
ip_address = nautobot.ipam.ip_addresses.get(address='192.0.2.1')

## REST OF YOUR ORIGINAL SNIPPET
....

When I remove all existing IP assignmets of an interface

Can you confirm your original code snippet is correct? Your snippet is only removing a single assignment since you are filtering the assignments by the interface and the IP ID's:

id_list = nautobot.ipam.ip_address_to_interface.filter(interface=interface.id, ip_address=ip_address.id)

Is this maybe a bug in your code or did you provide an incorrect snippet?