Repository: netbox-community/netbox
Pull request: 17614 Disallow removal of virtual chassis from device if set as master
### Fixes: #17614 

Raise error if removing the virtual chassis from a device if it is set as master.  We could auto-remove it from master on the virtual-chassis, but it seems like in other places we disallow the removal so keeping it consistent.

Problem statement:
Virtual Chassis still has master after member removed
### Deployment Type

Self-hosted

### NetBox Version

v4.1.1

### Python Version

3.12

### Steps to Reproduce

1. Create new virtual chassis
2. Create new device and assign to virtual chassis
3. Assign device as master of virtual chassis
4. Edit the device and clear the virtual chassis
5. View the virtual chassis and confirm the member is gone but the master remains

### Expected Behavior

Other pages seem to prevent the member being from being removed while it is the master, so assumedly this behaviour should be consistent from the device edit page.

### Observed Behavior

Master exists in virtual chassis without it being a member.

Hints from issue discussion:

Commit message: 17614 Disallow removal of virtual chassis from device if set as master

Patch to review:
diff --git a/netbox/dcim/models/devices.py b/netbox/dcim/models/devices.py
index a2b78957e40..554c8390b19 100644
--- a/netbox/dcim/models/devices.py
+++ b/netbox/dcim/models/devices.py
@@ -983,6 +983,13 @@ def clean(self):
                 'vc_position': _("A device assigned to a virtual chassis must have its position defined.")
             })
 
+        if hasattr(self, 'vc_master_for') and self.vc_master_for and self.vc_master_for != self.virtual_chassis:
+            raise ValidationError({
+                'virtual_chassis': _("Cannot change to a different virtual chassis when assigned as a master. Remove it as the master of {master} first.").format(
+                    master=self.vc_master_for
+                )
+            })
+
     def _instantiate_components(self, queryset, bulk_create=True):
         """
         Instantiate components for the device from the specified component templates.


Code review comments:
diff_hunk: @@ -983,6 +983,13 @@ def clean(self):
                 'vc_position': _("A device assigned to a virtual chassis must have its position defined.")
             })
 
+        if hasattr(self, 'vc_master_for') and self.vc_master_for and self.vc_master_for != self.virtual_chassis:
+            raise ValidationError({
+                'virtual_chassis': _("Cannot change to a different virtual chassis when assigned as a master. Remove it as the master of {master} first.").format(
path: netbox/dcim/models/devices.py
text: @user1:
Can we tweak the error message to avoid confusing the user? (We're not necessarily moving the device to a _different_ virtual chassis; we may just be removing it.) Something like "Device cannot be removed from virtual chassis {virtual_chassis} because it is currently designated as its master."