Scripts are not increasing counter for device components like power ports and inventory items #8924

Closed
opened 2025-12-29 20:42:54 +01:00 by adam · 7 comments
Owner

Originally created by @cichutkiii on GitHub (Dec 6, 2023).

NetBox version

v3.6.4

Python version

3.8

Steps to Reproduce

  1. create 1 random items for power ports and inventory items.
  2. run script which will create items in inventory items and power ports
  3. delete manually items

Expected Behavior

counter should count newly added items by script

Observed Behavior

counter is not working while running script
And while removing items I'm getting to the situation when I have counter below 0

image

Originally created by @cichutkiii on GitHub (Dec 6, 2023). ### NetBox version v3.6.4 ### Python version 3.8 ### Steps to Reproduce 1. create 1 random items for power ports and inventory items. 2. run script which will create items in inventory items and power ports 3. delete manually items ### Expected Behavior counter should count newly added items by script ### Observed Behavior counter is not working while running script And while removing items I'm getting to the situation when I have counter below 0 ![image](https://github.com/netbox-community/netbox/assets/823614/ae6146ee-9796-4687-bf72-9ac6e59708b2)
adam added the type: bug label 2025-12-29 20:42:54 +01:00
adam closed this issue 2025-12-29 20:42:54 +01:00
Author
Owner

@jeremystretch commented on GitHub (Dec 6, 2023):

  1. run script which will create items in inventory items and power ports

Please share the script that someone else can run locally to reproduce the reported behavior.

@jeremystretch commented on GitHub (Dec 6, 2023): > 2. run script which will create items in inventory items and power ports Please share the script that someone else can run locally to reproduce the reported behavior.
Author
Owner

@cichutkiii commented on GitHub (Dec 6, 2023):

Sure, Jeremy
I made some testing and debugging and found out that this is happening because I'm updating device after creating inv items.
When the update is before creation of inv item, then this will not occur.

from django.utils.text import slugify

from dcim.choices import DeviceStatusChoices, SiteStatusChoices
from dcim.models import Device, Interface,InventoryItem,Rack, InventoryItemRole, PowerPort
from dcim.models import Manufacturer,Site,DeviceType,DeviceRole
from ipam.models import IPAddress
from extras.scripts import *
from pathlib import Path
from django.forms import PasswordInput
import ansible_runner
import json
import datetime

class UpdateDataScript(Script):

    class Meta:
        name = "Update device"
        description = "Update device with basic information"
    
    device = ObjectVar(
        model=Device,
        required=False
    )
    IP = StringVar(
        description="ip to connect to device",
        required=True
    )
    login = StringVar(
        description="Login to device",
        required=False
    )

    password = StringVar(
        widget=PasswordInput,
        required=False)
        
    hostname = BooleanVar(
        description="Check if you want to update hostname in Netbox"
        )
    serial = BooleanVar(
        description="Check if you want to update serial number in Netbox"
        )
    gln = BooleanVar(
        
        description="Check if device is in GLN"
        )
    
    
    def run(self, data, commit):
        device = data['device']
        
        DEFAULT_USER = data['login']
        DEFAULT_PASS = data['password']

        inv_role = InventoryItemRole.objects.get(name='Ethernet Card')
        inv_item = InventoryItem(
           name = "nane",
           label = "label",
           device_id = device.id,
           serial = "serial",
           role = inv_role,
           
        )
        self.log_success("adding new inventory item")
        inv_item.full_clean()
        inv_item.save()
        inv_item = InventoryItem(
           name = "nane2",
           label = "labe2l",
           device_id = device.id,
           serial = "seri2al",
           role = inv_role,
           
        )
        self.log_success("adding new inventory item")
        inv_item.full_clean()
        inv_item.save()
        inv_item = InventoryItem(
           name = "nane44",
           label = "label44",
           device_id = device.id,
           serial = "serial44",
           role = inv_role,
           
        )
        self.log_success("adding new inventory item")
        inv_item.full_clean()
        inv_item.save()
        device.asset_tag = "test"
        device.full_clean()
        device.save()

@cichutkiii commented on GitHub (Dec 6, 2023): Sure, Jeremy I made some testing and debugging and found out that this is happening because I'm updating device after creating inv items. When the update is before creation of inv item, then this will not occur. ``` from django.utils.text import slugify from dcim.choices import DeviceStatusChoices, SiteStatusChoices from dcim.models import Device, Interface,InventoryItem,Rack, InventoryItemRole, PowerPort from dcim.models import Manufacturer,Site,DeviceType,DeviceRole from ipam.models import IPAddress from extras.scripts import * from pathlib import Path from django.forms import PasswordInput import ansible_runner import json import datetime class UpdateDataScript(Script): class Meta: name = "Update device" description = "Update device with basic information" device = ObjectVar( model=Device, required=False ) IP = StringVar( description="ip to connect to device", required=True ) login = StringVar( description="Login to device", required=False ) password = StringVar( widget=PasswordInput, required=False) hostname = BooleanVar( description="Check if you want to update hostname in Netbox" ) serial = BooleanVar( description="Check if you want to update serial number in Netbox" ) gln = BooleanVar( description="Check if device is in GLN" ) def run(self, data, commit): device = data['device'] DEFAULT_USER = data['login'] DEFAULT_PASS = data['password'] inv_role = InventoryItemRole.objects.get(name='Ethernet Card') inv_item = InventoryItem( name = "nane", label = "label", device_id = device.id, serial = "serial", role = inv_role, ) self.log_success("adding new inventory item") inv_item.full_clean() inv_item.save() inv_item = InventoryItem( name = "nane2", label = "labe2l", device_id = device.id, serial = "seri2al", role = inv_role, ) self.log_success("adding new inventory item") inv_item.full_clean() inv_item.save() inv_item = InventoryItem( name = "nane44", label = "label44", device_id = device.id, serial = "serial44", role = inv_role, ) self.log_success("adding new inventory item") inv_item.full_clean() inv_item.save() device.asset_tag = "test" device.full_clean() device.save() ```
Author
Owner

@jeremystretch commented on GitHub (Dec 26, 2023):

I'm not able to reproduce the reported behavior on NetBox v3.6.7. It has likely been addressed in the latest release by #14081. Please try upgrading, and ask that this issue be re-opened if you find that the bug persists.

@jeremystretch commented on GitHub (Dec 26, 2023): I'm not able to reproduce the reported behavior on NetBox v3.6.7. It has likely been addressed in the latest release by #14081. Please try upgrading, and ask that this issue be re-opened if you find that the bug persists.
Author
Owner

@rizlas commented on GitHub (Dec 28, 2023):

The bug persists. I just upgraded to v3.6.8 and inventory items count still wrong. I'm also updating via scripts.

def create_inventory_item(component: dict, parent: InventoryItem = None):
    nb_item, _ = InventoryItem.objects.get_or_create(
        device=self.device_object,
        name=component["name"],
    )

    self.obj_snapshot(nb_item)

    nb_item.description = component["description"]
    nb_item.part_id = component["part_number"]
    nb_item.serial = component["serial_number"]

    if parent:
        nb_item.parent = parent

    nb_item.tags.add(self.inventory_common_tag)

    nb_item.full_clean()
    nb_item.save()

    return nb_item

Even if I remove all the inventory items before creation, counter remains wrong.

InventoryItem.objects.filter(device=self.device_object).delete()

@rizlas commented on GitHub (Dec 28, 2023): The bug persists. I just upgraded to v3.6.8 and inventory items count still wrong. I'm also updating via scripts. ``` def create_inventory_item(component: dict, parent: InventoryItem = None): nb_item, _ = InventoryItem.objects.get_or_create( device=self.device_object, name=component["name"], ) self.obj_snapshot(nb_item) nb_item.description = component["description"] nb_item.part_id = component["part_number"] nb_item.serial = component["serial_number"] if parent: nb_item.parent = parent nb_item.tags.add(self.inventory_common_tag) nb_item.full_clean() nb_item.save() return nb_item ``` Even if I remove all the inventory items before creation, counter remains wrong. `InventoryItem.objects.filter(device=self.device_object).delete()`
Author
Owner

@kkthxbye-code commented on GitHub (Dec 28, 2023):

@rizlas - The issue is, at least in @cichutkiii example, that the device is saved after the inventoryitem is added.

So a script like this (simplified from the earlier example) will make the count bug:

inv_role = InventoryItemRole.objects.get(name='Ethernet Card')
inv_item = InventoryItem(
   name = "nane",
   label = "label",
   device_id = device.id,
   serial = "serial",
   role = inv_role,
)

inv_item.full_clean()
inv_item.save()

# Everything is fine here

device.asset_tag = "test"
device.full_clean()

# This device is stale, as when the above inventory item was created, the device _inventory_item_count (or whatever it's called) was modified by netbox.
device.save() 

Instead the end would have to be:

device.refresh_from_db() # Get the non-stale device
device.asset_tag = "test"
device.full_clean()
device.save() 

I guess another option would be to use the update_fields argument to the save call, to omit updating the count fields.

This is not a bug in netbox, however it is bad practice and not intuitive to modify fields on other objects in a non-obvious way like it was done when the cached item counts were added. I wouldn't count on it changing, so you have to update your scripts.

@kkthxbye-code commented on GitHub (Dec 28, 2023): @rizlas - The issue is, at least in @cichutkiii example, that the device is saved after the inventoryitem is added. So a script like this (simplified from the earlier example) will make the count bug: ``` inv_role = InventoryItemRole.objects.get(name='Ethernet Card') inv_item = InventoryItem( name = "nane", label = "label", device_id = device.id, serial = "serial", role = inv_role, ) inv_item.full_clean() inv_item.save() # Everything is fine here device.asset_tag = "test" device.full_clean() # This device is stale, as when the above inventory item was created, the device _inventory_item_count (or whatever it's called) was modified by netbox. device.save() ``` Instead the end would have to be: ``` device.refresh_from_db() # Get the non-stale device device.asset_tag = "test" device.full_clean() device.save() ``` I guess another option would be to use the `update_fields` argument to the save call, to omit updating the count fields. This is not a bug in netbox, however it is bad practice and not intuitive to modify fields on other objects in a non-obvious way like it was done when the cached item counts were added. I wouldn't count on it changing, so you have to update your scripts.
Author
Owner

@rizlas commented on GitHub (Dec 28, 2023):

I wasn't aware of refresh_from_db. Fine to me, make sense. But, I just tested your suggestion and the counter it still wrong.

This was my approach before testing your solution:

  • Device creation, update his attributes and save
  • Create other netbox objects (e.g. inventory items) referencing the entire device object (e.g. device=self.device_object)

After your suggestion:

  • Device creation, update his attributes
  • Create other netbox objects (e.g. inventory items) referencing the entire device object (e.g. device=self.device_object)
  • Saving the object this way:
self.device_object.refresh_from_db()
self.device_object.full_clean()
self.device_object.save()

Nothing changed

@rizlas commented on GitHub (Dec 28, 2023): I wasn't aware of [refresh_from_db](https://docs.djangoproject.com/en/5.0/ref/models/instances/#refreshing-objects-from-database). Fine to me, make sense. But, I just tested your suggestion and the counter it still wrong. This was my approach before testing your solution: - Device creation, update his attributes and save - Create other netbox objects (e.g. inventory items) referencing the entire device object (e.g. device=self.device_object) After your suggestion: - Device creation, update his attributes - Create other netbox objects (e.g. inventory items) referencing the entire device object (e.g. device=self.device_object) - Saving the object this way: ``` self.device_object.refresh_from_db() self.device_object.full_clean() self.device_object.save() ``` Nothing changed
Author
Owner

@rizlas commented on GitHub (Dec 28, 2023):

Thats my situation, as you can see I've inventory items but no "Inventory Items" tab.

image psd

If I add an item manually the tab appear.

immagine

Only deleting the entire device object seems to fix the problem.

@rizlas commented on GitHub (Dec 28, 2023): Thats my situation, as you can see I've inventory items but no "Inventory Items" tab. ![image psd](https://github.com/netbox-community/netbox/assets/8522635/737ce9dd-ce81-4bb8-ac72-943d236f7e5d) If I add an item manually the tab appear. ![immagine](https://github.com/netbox-community/netbox/assets/8522635/8bf35211-eeb3-4a2f-9fcd-166046661d23) Only deleting the entire device object seems to fix the problem.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#8924