netboxlabs / netbox-branching

Official NetBox Labs plugin that implements git-like branching functionality for NetBox
http://netboxlabs.com
Other
57 stars 1 forks source link

Inconsistent behaviour of models in custom scripts with branching #156

Open RedLine89 opened 6 days ago

RedLine89 commented 6 days ago

Plugin Version

0.5.1

NetBox Version

4.1.4

Python Version

3.12.3

Steps to Reproduce

  1. Add the following custom script:
    
    from extras.scripts import *

from dcim.choices import DeviceStatusChoices from dcim.models import Device, DeviceRole, DeviceType, Site, ModuleType, ModuleBay, Module

class NewBranchScript(Script):

class Meta:
    name = "Bug_1"
    description = "Bug_1"
    commit_default = False

device_name = StringVar(
    description="Name of the device"
)
router_model = ObjectVar(
    description="Router model",
    model=DeviceType
)
site_name = ObjectVar(
    description="Name of the new site",
    model=Site
)

def run(self, data, commit):

    # Create routers
    router_role = DeviceRole.objects.get(name='SE')
    router = Device(
        device_type=data['router_model'],
        name=data['device_name'],
        site=data['site_name'],
        status=DeviceStatusChoices.STATUS_PLANNED,
        role=router_role
    )
    router.save()

    self.log_success(f"Created new router: {router}")

    mda_input = {
                'mda': [
                        {
                            'equipped-ports': '12',
                            'equipped-type': 'me12-100gb-qsfp28',
                            'mda-slot': '1'
                        },
                        {
                            'equipped-ports': '18',
                            'equipped-type': 'me16-25gb-sfp28+2-100gb-qsfp28',
                            'mda-slot': '2'
                        }
                    ]
    }

    # Creating new MDAs
    for mda in mda_input['mda']:

        if mda['equipped-type'] != 'unassigned':

            self.log_debug(f"Searching for module type: {mda['equipped-type']}")
            module_type = ModuleType.objects.get(model=mda['equipped-type'])
            self.log_info(f"Module type found: {module_type}")

            if module_type:
                new_module=Module(
                    device=router,
                    module_bay=ModuleBay.objects.get(device_id=router.id, position=f'1/{mda['mda-slot']}'),
                    module_type=module_type
                )
                new_module.save()

    return True
2. Run this script on `Main` branch without committing (default in this script);
3. Everything works as expected;
4. Create new branch `test_1`
5. Activate new branch `test_1`
6. Run the same script while branch `test_1` is active
7. Observe the following failure in the log. `Device` was created fine while `ModuleBay` was not able to fetch bay for this device - apparently `ModuleBay` is not branch aware.
    {
        "message": "An exception occurred: `DoesNotExist: ModuleBay matching query does not exist.`\n```\nTraceback (most recent call last):\n  File \"/opt/netbox/netbox/extras/jobs.py\", line 45, in run_script\n    script.output = script.run(data, commit)\n                    ^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/opt/netbox/netbox/scripts/bug_1.py\", line 81, in run\n    module_bay=ModuleBay.objects.get(device_id=router.id, position=f'1/{mda['mda-slot']}'),\n               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/opt/netbox/venv/lib/python3.12/site-packages/django/db/models/manager.py\", line 87, in manager_method\n    return getattr(self.get_queryset(), name)(*args, **kwargs)\n           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/opt/netbox/venv/lib/python3.12/site-packages/django/db/models/query.py\", line 649, in get\n    raise self.model.DoesNotExist(\ndcim.models.device_components.ModuleBay.DoesNotExist: ModuleBay matching query does not exist.\n\n```",
        "obj": null,
        "status": "failure",
        "time": "2024-10-17T21:20:41.887854+00:00",
        "url": null
    }
8. Note that `Device` with a given name gets actually committed/created on the branch `test_1`, while `commit_default = False` and unselected in the UI. And even though script logs this in the end:
    {
        "message": "Database changes have been reverted due to error.",
        "obj": null,
        "status": "info",
        "time": "2024-10-17T21:20:41.888004+00:00",
        "url": null
    }
9. Attempting to delete the new `Device` on the branch `test_1` via UI throw the following error in the browser:

Server Error There was a problem with your request. Please contact an administrator.

The complete exception is provided below:

<class 'dcim.models.device_components.ModuleBay.DoesNotExist'>

ModuleBay matching query does not exist.

Python version: 3.12.3 NetBox version: 4.1.4 Plugins: netbox_branching: 0.5.1 netbox_topology_views: 4.1.0 If further assistance is required, please post to the NetBox discussion forum on GitHub.

Home Page


10. The only way to "undo" this is to deactivate `test_1` branch and delete it.

### Expected Behavior

1. Create/get of each model should happen on active branch. Not sure why some models like `Device` get implicitly created on an active branch, while fetching bays from this device happens at `Main` branch (I suspect).
2. Saving `Device` model should have been reverted due to `commit_default = False`
3. Deleting new `Device` via UI should not cause `Server Error`.
4. If custom scripts are not supposed to work with branching plugin or if there is a different way to write custom scripts for branching, providing instructions on how to do it would be greatly appreciated.

### Observed Behavior

Explained in reproduce steps.
arthanson commented 5 days ago

@RedLine89 can you please fix the script and upload a sample that can be run? For example:

RedLine89 commented 5 days ago

thank you for checking @arthanson Apologies for extra imports - cleaned it up. But the script has been working for me as-is (on the main branch) though.

Could you please elaborate on "module_bay=ModuleBay.objects has an error because of the quotes". I don't get see any errors in IDE and NetBox executes it all right on the main branch.

Let me know if anything else is required.

arthanson commented 5 days ago

@RedLine89 at the f'1/{mda['mda-slot']}' part - there are single quotes inside single quotes so it parses it incorrectly, changing the outer or inner quotes to double (") would fix it.

arthanson commented 5 days ago

However, I think I know what the issue is in any case from working on a separate issue so this may be a moot point.

RedLine89 commented 2 days ago

Thank you for looking into this @arthanson In regards of my last question though. How scripts are supposed to work with branching? Is banrching implicit for them and they will make modification for an active branch? or scripts need to be written using branching objects?

In other words, should this example script be modified to make changes at active branch?