Skip to content

Commit 94fb817

Browse files
author
Johan van den Dorpe
committed
Update documention and tests for custom field attributes
1 parent 92ab979 commit 94fb817

File tree

3 files changed

+44
-9
lines changed

3 files changed

+44
-9
lines changed

changes/205.fixed

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added support for validating custom fields by referencing them as cf_<custom_field_name> in ComplianceError exceptions

docs/user/app_data_compliance.md

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
## Overview
44

5-
The Data Compliance feature audits any object within Nautobot according to a set of rules that you can define programmatically or from the built-in data validation rules (e.g. Min/Max, Regex, Required, or Unique rules). Rather than only checking for adherence to specified rules during the *creation or modification* of objects, Data Compliance will run a job that produces compliance statuses across *existing* objects (such as all pre-existing devices).
5+
The Data Compliance feature audits any object within Nautobot according to a set of rules that you can define programmatically or from the built-in data validation rules (e.g. Min/Max, Regex, Required, or Unique rules). Rather than only checking for adherence to specified rules during the *creation or modification* of objects, Data Compliance will run a job that produces compliance statuses across *existing* objects (such as all pre-existing devices).
66

7-
This is ideal for implementing some kind of business logic or standardization requirement into Nautobot after data is already populated within the platform. Data Compliance will allow you to identify valid or invalid existing objects based on your specified data compliance and validation rules. Additionally, Data Compliance enables the ability to implement more complex rules using the full power of programming logic, in addition to the built-in data validation ones.
7+
This is ideal for implementing some kind of business logic or standardization requirement into Nautobot after data is already populated within the platform. Data Compliance will allow you to identify valid or invalid existing objects based on your specified data compliance and validation rules. Additionally, Data Compliance enables the ability to implement more complex rules using the full power of programming logic, in addition to the built-in data validation ones.
88

99
### `DataComplianceRule` Class
1010

@@ -15,9 +15,12 @@ The `DataComplianceRule` class takes advantage of the `CustomValidator` workflow
1515
Any `DataComplianceRule` class can have a `name` defined to provide a friendly name to be shown within in the UI. The `enforce` attribute can also be set to decide whether or not the `ComplianceError` caught in the `audit` method is raised again to the `clean` method, acting like a `ValidationError` wherever the original `full_clean` was called. Setting `enforce` to `True` changes the `DataComplianceRule` from a passive validation of data to an active enforcement of the logic within it.
1616

1717
> **Note:** Individual rules implemented using the `DataComplianceRule` class are re-ran and re-validated when the target object is modified and saved, in addition to run ad-hoc using the `RunRegisteredDataComplianceRules` job. However, `DataCompliance` objects that are created by the job for the built-in validation rules when using the `Run built-in validation rules?` option will not update nor be re-validated until the job is explicitly ran once again.
18-
>
18+
>
1919
> For example, if a user fixes an object attribute that was incompliant with a built-in rule and then navigates to its `Data Compliance` tab, the object will still show as invalid for that built-in rule. This will remain the case until the job is ran again with the `Run built-in validation rules?` option checked.
2020
21+
!!! note
22+
When raising a ComplianceError, the attribute must exist on the object. To raise errors for custom fields, use cf_custom_field_name as the attribute name.
23+
2124
## How to Use
2225

2326
### Step 1. Create Data Compliance Rules
@@ -52,7 +55,7 @@ class DesiredClassName(DataComplianceRule):
5255
# Your logic to determine if this function has succeeded or failed
5356
if "undesired_value" in self.context["object"].desired_attribute:
5457
raise ComplianceError({"desired_attribute": "Desired message why it's invalid."})
55-
58+
5659
def audit(self):
5760
messages = {}
5861
for fn in [self.audit_desired_name_one, self.audit_desired_name_two]: # Add audit functions here
@@ -88,7 +91,7 @@ class DesiredClassName(DataComplianceRule):
8891
# Your logic to determine if this function has succeeded or failed
8992
if "undesired_value" in self.context["object"].desired_attribute:
9093
raise ComplianceError({"desired_attribute": "Desired message why it's invalid."})
91-
94+
9295
def audit(self):
9396
messages = {}
9497
for fn in [self.audit_desired_name_one, self.audit_desired_name_two]: # Add audit functions here
@@ -136,12 +139,12 @@ from nautobot_data_validation_engine.custom_validators import DataComplianceRule
136139
class DeviceDataComplianceRules(DataComplianceRule):
137140
model = "dcim.device"
138141
enforce = False
139-
142+
140143
# Checks if a device name contains any special characters other than a dash (-), underscore (_), or period (.) using regex
141144
def audit_device_name_chars(self):
142145
if not re.match("^[a-zA-Z0-9\-_.]+$", self.context["object"].name):
143146
raise ComplianceError({"name": "Device name contains unallowed special characters."})
144-
147+
145148
def audit(self):
146149
messages = {}
147150
for fn in [self.audit_device_name_chars]:
@@ -155,12 +158,12 @@ class DeviceDataComplianceRules(DataComplianceRule):
155158
class RackDeviceComplianceRules(DataComplianceRule):
156159
model = "dcim.device"
157160
enforce = False
158-
161+
159162
# Checks if a device is not assigned to a rack
160163
def audit_device_rack(self):
161164
if not self.context["object"].rack:
162165
raise ComplianceError({"rack": "Device should be assigned to a rack."})
163-
166+
164167
def audit(self):
165168
messages = {}
166169
for fn in [self.audit_device_rack]:

nautobot_data_validation_engine/tests/test_data_compliance_rules.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,34 @@ def test_validate_replaces_results(self):
7878
len(DataCompliance.objects.filter(compliance_class_name=TestFailedDataComplianceRule.__name__)),
7979
5,
8080
)
81+
82+
def test_custom_field_attribute_value(self):
83+
# Simulate a Location with a custom field value
84+
self.s.cf = {"foo": "bar"}
85+
# Patch DataComplianceRule.context to include our instance
86+
rule = TestPassedDataComplianceRule(self.s)
87+
rule.context = {"object": self.s}
88+
89+
# Call _create_data_compliance_object with a custom field attribute
90+
obj = rule._create_data_compliance_object(attribute="cf_foo", valid=True, message="msg")
91+
self.assertEqual(obj.validated_attribute, "cf_foo")
92+
self.assertEqual(obj.validated_attribute_value, "bar")
93+
94+
def test_custom_field_attribute_value_missing(self):
95+
# Simulate a Location with no custom field value
96+
self.s.cf = {}
97+
rule = TestPassedDataComplianceRule(self.s)
98+
rule.context = {"object": self.s}
99+
100+
obj = rule._create_data_compliance_object(attribute="cf_missing", valid=True, message="msg")
101+
self.assertEqual(obj.validated_attribute, "cf_missing")
102+
self.assertIsNone(obj.validated_attribute_value)
103+
104+
def test_regular_attribute_value(self):
105+
# Test with a regular attribute
106+
rule = TestPassedDataComplianceRule(self.s)
107+
rule.context = {"object": self.s}
108+
109+
obj = rule._create_data_compliance_object(attribute="name", valid=True, message="msg")
110+
self.assertEqual(obj.validated_attribute, "name")
111+
self.assertEqual(obj.validated_attribute_value, self.s.name)

0 commit comments

Comments
 (0)