netbox-community / netbox

The premier source of truth powering network automation. Open source under Apache 2. Try NetBox Cloud free: https://netboxlabs.com/free-netbox-cloud/
http://netboxlabs.com/oss/netbox/
Apache License 2.0
16.18k stars 2.59k forks source link

Custom validators unable to validate tag presence #12731

Closed stuntguy3000 closed 10 months ago

stuntguy3000 commented 1 year ago

NetBox version

v3.5.1

Python version

3.10

Steps to Reproduce

  1. Set the Custom Validators setting to validate tag requirements
    CUSTOM_VALIDATORS = {
        "ipam.ipaddress": [{"tags": {"required": True}}],
        "dcim.site": [{"tags": {"required": True}}],
        "dcim.region": [{"tags": {"required": True}}]
    }
  2. Create a new object defined in the list above with/without tags defined.

(This error is not exclusive to those object types)

Expected Behavior

I expected NetBox to validate if that particular object has tags set.

Observed Behavior

<class 'ValueError'>

IPAddress objects need to have a primary key value before you can access their tags.

Python version: 3.10.6
NetBox version: 3.5.1

I'm not sure if I'm asking too much from the Custom Validators here, or if another method to enforce the existence of Tags is available.

stuntguy3000 commented 1 year ago

I'm curious if this is actually fixable?

My understanding is that the Model is passed to the custom validator, but the tag information is lost as it sits as it is different from the other fields. Validators can't access the raw form data and the tags input is not passed along down this chain.

The only fix I can even see is to either hack together more custom validation specifically for tags, or to save the object BEFORE the tags are then validated - what could go wrong.

Have to leave this for someone more versed in Django, this isn't a simple fix :(

netopsab commented 1 year ago

Hi,

This is the only way I have found to catch tags (or other m2m fields) with CustomValidator :

from netbox.context import current_request
from extras.models import Tag

request = current_request.get()
tags = Tag.objects.filter(id__in=request.POST.getlist('tags')).values_list('name', flat=True)

Note : this is for the 'standard' edit form. For bulk edit (or import form), you have to dig with other fields (like add_tags, remove_tags) and check the view name before (with object request.resolver_match.view_name).

from extras.models import Tag

tags = set(instance.tags.names()).union(
    Tag.objects.filter(id__in=request.POST.getlist('add_tags')).values_list('name', flat=True)
).difference(
    Tag.objects.filter(id__in=request.POST.getlist('remove_tags')).values_list('name', flat=True)
)

Hope this can help you.

NB : for tracking, this issue occurs for all m2m fields (like tagged_vlans), not just tags.

github-actions[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. NetBox is governed by a small group of core maintainers which means not all opened issues may receive direct feedback. Do not attempt to circumvent this process by "bumping" the issue; doing so will result in its immediate closure and you may be barred from participating in any future discussions. Please see our contributing guide.

github-actions[bot] commented 1 year ago

This issue has been automatically closed due to lack of activity. In an effort to reduce noise, please do not comment any further. Note that the core maintainers may elect to reopen this issue at a later date if deemed necessary.

arthanson commented 1 year ago

@Urth stated he wanted to work on this.

Urth commented 1 year ago

yes, please assign it to me :+1: