GithubHelp home page GithubHelp logo

nautobot / nautobot-app-data-validation-engine Goto Github PK

View Code? Open in Web Editor NEW
15.0 10.0 5.0 7.68 MB

Data validation rules engine app to easily codify corporate data standards

Home Page: https://docs.nautobot.com/projects/data-validation/en/latest/

License: Other

Dockerfile 1.98% Python 94.66% HTML 2.95% Jinja 0.41%
nautobot-plugin nautobot hacktoberfest

nautobot-app-data-validation-engine's Introduction

Data Validation Engine



An App for Nautobot.

Overview

An app for Nautobot with a UI to build custom data validation rules for Source of Truth data.

The Data Validation Engine app offers a set of user definable rules which are used to enforce business constraints on the data in Nautobot. These rules are tied to particular models and each rule is meant to enforce one aspect of a business use case.

Supported rule types include:

  • Regular expression
  • Min/max value
  • Required fields
  • Unique values

Another feature within the app called Data Compliance can audit any object within Nautobot ad-hoc according to a set of rules that you can define programmatically or from the built-in data validation 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 all objects including pre-existing ones (such as all existing devices).

Dropdown

Screenshots

More screenshots can be found in the Using the App page in the documentation. Here's a quick overview of some of the app's added functionality:

Min/Max Rules

Min/Max List

Regular Expression Rules

Regex Rules List

Required Rules

Required Rules List

Unique Rules

Unique Rules List

Data Compliance

Data Compliance Results List

Try it out!

This App is installed in the Nautobot Community Sandbox found over at demo.nautobot.com!

For a full list of all the available always-on sandbox environments, head over to the main page on networktocode.com.

Documentation

Full web-based HTML documentation for this app can be found over on the Nautobot Docs website:

Contributing to the Docs

You can find all the Markdown source for the App documentation under the docs folder in this repository. For simple edits, a Markdown capable editor is sufficient - clone the repository and edit away.

If you need to view the fully generated documentation site, you can build it with mkdocs. A container hosting the docs will be started using the invoke commands (details in the Development Environment Guide) on http://localhost:8001. As your changes are saved, the live docs will be automatically reloaded.

Any PRs with fixes or improvements are very welcome!

Questions

For any questions or comments, please check the FAQ first. Feel free to also swing by the Network to Code Slack (channel #nautobot), sign up here if you don't have an account.

nautobot-app-data-validation-engine's People

Contributors

chadell avatar cmsirbu avatar dependabot[bot] avatar dgarros avatar distantvoyager avatar gsnider2195 avatar itdependsnetworks avatar jedelman8 avatar lampwins avatar mzbroch avatar nautobot-bot avatar sdoiron0330 avatar snaselj avatar u1735067 avatar ubajze avatar whitej6 avatar zackt25 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nautobot-app-data-validation-engine's Issues

Plugin reports all possible data validators as in use

Environment

  • Python version:
  • Nautobot version: 2.0 (next from 2023-05-31)
  • nautobot-data-validation-engine version: branch next-2.0

Expected Behavior

Plugin shows only model defined through DataComplianceRule created in custom_validators.py

Observed Behavior

Plugin shows all models under Data Validators

Steps to Reproduce

  1. In plugin's custom_validators.py create following :
class DeviceDataComplianceRules(DataComplianceRule):
    model = "dcim.device"
    enforce = False

    # Checks if a device name contains any special characters other than a dash (-), underscore (_), or period (.) using regex
    def audit_device_name_chars(self):
        if not re.match("^[a-zA-Z0-9\-_.]+$", self.context["object"].name):
            raise ComplianceError({"name": "Device name contains unallowed special characters."})

    # Checks if a device is not assigned to a rack
    def audit_device_rack(self):
        if not self.context["object"].rack:
            raise ComplianceError({"rack": "Device should be assigned to a rack."})

    def audit(self):
        messages = {}
        for fn in [self.audit_device_name_chars, self.audit_device_rack]:
            try:
                fn()
            except ComplianceError as ex:
                messages.update(ex.message_dict)
        if messages:
            raise ComplianceError(messages)


custom_validators = list(CustomValidatorIterator()) + [DeviceDataComplianceRules]
  1. Navigate to Installed Plugins -> , click on details
Screenshot 2023-05-31 at 10 05 19

Update screenshots in documentation

Environment

  • Nautobot version: ^2.0.0
  • nautobot-data-validation-engine version: 3.1.0

Proposed Functionality

Update the app's screenshots with the recent Nautobot versions and UI.

Use Case

The screenshots in the documentation should match the updated Nautobot versions.

Invalid Validation Result

Environment

  • Python version: 3.9
  • Nautobot version: e85c2fa37e4d (v1.4.10)
  • nautobot-data-validation-engine version: 1.0.0

Steps to Reproduce

  1. Define the following Regular Expression Rule

    image

    Regular Expression: ^([ -~]+|[ ]*)$

  2. Open a Interface and enter this description: 1/0/17 Doorlock SREL Kolben Spänecontainer

  3. Save the changes

Expected Behavior

The validator should throw an error as verified with regex101

image

Observed Behavior

Input accepted

Blank values for unique validation fields are being flagged

Environment

  • Python version: 3.8
  • Nautobot version: 1.6.1b1
  • nautobot-data-validation-engine version: 2.1.0

Expected Behavior

If I edit an object that currently has a blank value or no entry for a field that contains a unique validation rule, I shouldn't receive a validation error.

Observed Behavior

A validation error is received for blank field values (obviously because there are other objects with blank values too).

Steps to Reproduce

  1. Create a unique validation rule for a content type's field, such as for dcim | device serial
  2. Ensure the existing data already contains objects with that field blank
  3. Try creating a new object (such as device) or editing one while still leaving that field blank
  4. A unique validation error will be returned
    image

ValidationError for rule URLs using names instead of UUIDs

Environment

  • Python version: 3.8
  • Nautobot version: 2.0 [ next-6756eb4-1686184941-py3.8 ]
  • nautobot-data-validation-engine version: 2.1.0 [ next-2.0 ]

Expected Behavior

Able to successfully view a rule object.

Observed Behavior

When trying to view a DVE rule (Min/Max, Regex, Required, Unique), a Validation Error is returned.

For example, when trying to click & view a Min/Max Rule called "Max VLAN ID", the following error is returned:

image

image

Steps to Reproduce

  1. Ensure your environment has a Min/Max, Regex, Required, or Unique Rule existing or create one.
  2. Try to view that rule object and the error is returned.

Full Traceback:

Environment:


Request Method: GET
Request URL: http://localhost:8080/plugins/nautobot-data-validation-engine/min-max-rules/max-vlan-id

Django Version: 3.2.18
Python Version: 3.8.17
Installed Applications:
['django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.humanize',
 'corsheaders',
 'django_filters',
 'django_jinja',
 'django_tables2',
 'django_prometheus',
 'social_django',
 'taggit',
 'timezone_field',
 'nautobot.core.apps.NautobotConstanceConfig',
 'nautobot.core',
 'django.contrib.admin',
 'django_celery_beat',
 'django_celery_results',
 'rest_framework',
 'db_file_storage',
 'nautobot.circuits',
 'nautobot.dcim',
 'nautobot.ipam',
 'nautobot.extras',
 'nautobot.tenancy',
 'nautobot.users',
 'nautobot.virtualization',
 'drf_spectacular',
 'drf_spectacular_sidecar',
 'graphene_django',
 'health_check',
 'health_check.storage',
 'django_extensions',
 'constance.backends.database',
 'django_ajax_tables',
 'debug_toolbar',
 'nautobot_data_validation_engine.NautobotDataValidationEngineConfig']
Installed Middleware:
['debug_toolbar.middleware.DebugToolbarMiddleware',
 'django_prometheus.middleware.PrometheusBeforeMiddleware',
 'corsheaders.middleware.CorsMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'django.middleware.security.SecurityMiddleware',
 'nautobot.core.middleware.ExceptionHandlingMiddleware',
 'nautobot.core.middleware.RemoteUserMiddleware',
 'nautobot.core.middleware.ExternalAuthMiddleware',
 'nautobot.core.middleware.ObjectChangeMiddleware',
 'django_prometheus.middleware.PrometheusAfterMiddleware']



Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/django/db/models/fields/__init__.py", line 2434, in to_python
    return uuid.UUID(**{input_form: value})
  File "/usr/local/lib/python3.8/uuid.py", line 171, in __init__
    raise ValueError('badly formed hexadecimal UUID string')

During handling of the above exception (badly formed hexadecimal UUID string), another exception occurred:
  File "/usr/local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.8/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/rest_framework/viewsets.py", line 125, in view
    return self.dispatch(request, *args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/nautobot/core/views/mixins.py", line 297, in dispatch
    return super().dispatch(request, *args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 509, in dispatch
    response = self.handle_exception(exc)
  File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
    raise exc
  File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/nautobot/core/views/mixins.py", line 585, in retrieve
    instance = self.get_object()
  File "/usr/local/lib/python3.8/site-packages/nautobot/core/views/mixins.py", line 453, in get_object
    obj = get_object_or_404(queryset, **filter_kwargs)
  File "/usr/local/lib/python3.8/site-packages/django/shortcuts.py", line 76, in get_object_or_404
    return queryset.get(*args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 424, in get
    clone = self._chain() if self.query.combinator else self.filter(*args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/nautobot/core/models/querysets.py", line 115, in filter
    return super().filter(*args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 941, in filter
    return self._filter_or_exclude(False, args, kwargs)
  File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 961, in _filter_or_exclude
    clone._filter_or_exclude_inplace(negate, args, kwargs)
  File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 968, in _filter_or_exclude_inplace
    self._query.add_q(Q(*args, **kwargs))
  File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/query.py", line 1416, in add_q
    clause, _ = self._add_q(q_object, self.used_aliases)
  File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/query.py", line 1435, in _add_q
    child_clause, needed_inner = self.build_filter(
  File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/query.py", line 1370, in build_filter
    condition = self.build_lookup(lookups, col, value)
  File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/query.py", line 1216, in build_lookup
    lookup = lookup_class(lhs, rhs)
  File "/usr/local/lib/python3.8/site-packages/django/db/models/lookups.py", line 25, in __init__
    self.rhs = self.get_prep_lookup()
  File "/usr/local/lib/python3.8/site-packages/django/db/models/lookups.py", line 77, in get_prep_lookup
    return self.lhs.output_field.get_prep_value(self.rhs)
  File "/usr/local/lib/python3.8/site-packages/django/db/models/fields/__init__.py", line 2418, in get_prep_value
    return self.to_python(value)
  File "/usr/local/lib/python3.8/site-packages/django/db/models/fields/__init__.py", line 2436, in to_python
    raise exceptions.ValidationError(

Exception Type: ValidationError at /plugins/nautobot-data-validation-engine/min-max-rules/max-vlan-id
Exception Value: ['“max-vlan-id” is not a valid UUID.']

Unique validation rule flags if unchanged when editing/saving

Environment

  • Python version: 3.8
  • Nautobot version: 1.6.1b1
  • nautobot-data-validation-engine version: 2.1.0

Expected Behavior

With a unique validation rule enabled, I can successfully edit an object while not modifying the unique validated field.

Observed Behavior

Unable to edit due to the unique validation rule being flagged for the validated field. Field value is still unique to that object, but when editing it's somehow being prevented from staying the same.

Steps to Reproduce

  1. Create a new unique validation rule such as for dcim | device serial field with a max value of 1
    image

  2. Create an object of the same content type as the unique rule, such as a new device. Enter a unique value in validated field, such as 123 for serial
    image

  3. Then, edit that object by modifying a field other than the unique validated one (leave that field value the same). For example, add a note to the device and then try updating/saving it.

  4. A validation error is returned for the unique validated field, despite not changing it. For example, when just trying to add a note to the device:
    image

Ability to provide filtering to validation rules

Environment

  • Nautobot version: 2.X.X
  • nautobot-data-validation-engine version: 3.X.X

Proposed Functionality

Currently, DVE's various validation rules are applied for all instances of a chosen content type. However, there are many times where validation rules might exist that are only relevant to a specific filtered subset of that grouping.

As a network automation engineer, I want the ability to apply validation rules to either all object instances of a certain content type or only a filtered subset, so that I can achieve differing validation rules that are not necessarily global.

  • Ability to provide a filter to a validation rule

    • Either on queryset
    • OR skip conditions

Use Case

Within Company X, we have two primary departments within our network org: Core and Access. I want to enforce naming standards for our network devices. However, the naming standards are not the same for Core and Access. Each department has their own set of rules defined for the devices that they manage.

When creating Regex Rules for the dcim | device content type's name field using DVE, rather than only being able to create rules that will apply to all device objects, I want to be able to create one rule with the naming standards for Core (i.e. devices whose role is Core) and another rule with the naming standards for Access (i.e. devices whose role is Access), where each rule only applies to the relevant department's devices (e.g. filtered by device role).

  • Device Type A has regex rule 1 whereas Device Type B has regex rule 2

Regex builder integrated into Regex Rule form

Environment

  • Nautobot version: 1.5.18
  • nautobot-data-validation-engine version: 2.0.0

Proposed Functionality

When adding a new regex validation rule, have some type of regex builder integrated into the form itself to help users to craft their intended regex.

Use Case

As a network engineer who is a novice with regular expressions, I want to be able to craft my desired regex within Nautobot when I am creating a regex validation rule without having to search online to figure out what I want to do.

Unit tests are failing

When the invoke unittest command is used, unit tests are failing.

This is the output from my local machine:

➜  nautobot-plugin-data-validation-engine git:(travis) poetry run invoke unittest
Creating nautobot_data_validation_engine_nautobot_run ... done
Wrapping model clean methods for custom validators failed because the ContentType table was not available or populated. This is normal during the execution of the migration command for the first time.
Creating test database for alias 'default'...

System check identified no issues (0 silenced).
.......................................FFFF...FF.............................................................................
======================================================================
FAIL: test_empty_field_values_raise_validation_error (nautobot_data_validation_engine.tests.test_custom_validators.MinMaxValidationRuleModelTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/source/nautobot_data_validation_engine/tests/test_custom_validators.py", line 89, in test_empty_field_values_raise_validation_error
    site.clean()
AssertionError: ValidationError not raised

======================================================================
FAIL: test_field_value_type_raise_validation_error (nautobot_data_validation_engine.tests.test_custom_validators.MinMaxValidationRuleModelTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/source/nautobot_data_validation_engine/tests/test_custom_validators.py", line 108, in test_field_value_type_raise_validation_error
    site.clean()
AssertionError: ValidationError not raised

======================================================================
FAIL: test_max_violation_raise_validation_error (nautobot_data_validation_engine.tests.test_custom_validators.MinMaxValidationRuleModelTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/source/nautobot_data_validation_engine/tests/test_custom_validators.py", line 146, in test_max_violation_raise_validation_error
    site.clean()
AssertionError: ValidationError not raised

======================================================================
FAIL: test_min_violation_raise_validation_error (nautobot_data_validation_engine.tests.test_custom_validators.MinMaxValidationRuleModelTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/source/nautobot_data_validation_engine/tests/test_custom_validators.py", line 127, in test_min_violation_raise_validation_error
    site.clean()
AssertionError: ValidationError not raised

======================================================================
FAIL: test_empty_field_values_coerced_to_empty_string (nautobot_data_validation_engine.tests.test_custom_validators.RegularExpressionValidationRuleModelTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/source/nautobot_data_validation_engine/tests/test_custom_validators.py", line 64, in test_empty_field_values_coerced_to_empty_string
    site.clean()
AssertionError: ValidationError not raised

======================================================================
FAIL: test_invalid_regex_matches_raise_validation_error (nautobot_data_validation_engine.tests.test_custom_validators.RegularExpressionValidationRuleModelTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/source/nautobot_data_validation_engine/tests/test_custom_validators.py", line 30, in test_invalid_regex_matches_raise_validation_error
    site.clean()
AssertionError: ValidationError not raised

----------------------------------------------------------------------
Ran 125 tests in 6.259s

FAILED (failures=6)
Destroying test database for alias 'default'...

The same result is also seen on Travis:
https://travis-ci.com/github/nautobot/nautobot-plugin-data-validation-engine/builds/228644947

Because of this, the invoke unittest command is currently disabled in .travis.yml. It should be re-enabled after unit tests are fixed.

Regex rule - Allow multiline regexes and inline comments

Environment

  • Python version: 3.8.5
  • Nautobot version: 1.0.0b2
  • nautobot-device-onboarding version: 1.0.0.dev0

Proposed Functionality

It would be great to allow users to define regexes spanning multiple lines.

When creating regex rule, a user is allowed to spread the rule over multiple lines. This is currently of limited use due to the new line character being inserted inside of the rule. E.g.

image

image

Use Case

Allowing users to define regex over multiple lines would increase the readability of complex regexes and would make maintenance easier.

Additionally, it would be great if we could enable re.VERBOSE flag, either implicitly or explicitly, for multiline regexes. This would allow end-users to use inline comments for complex multiline regexes.

For example:

(^\d{5,8}\w{3}$) # Asset version 1
|(^\d{3,4}$) # Asset version 2
|(^\w{5}$) # Asset version 3

I uploaded branch pr-re-verbose with a crude example of how that could be implemented.

        # Regex rules
        for rule in RegularExpressionValidationRule.objects.get_for_model(self.model):
            re_flags = re.UNICODE
            if rule.regular_expression.count("\n") > 1:
                re_flags |= re.VERBOSE

            if not re.match(rule.regular_expression, getattr(obj, rule.field), flags=re_flags):
                self.validation_error(
                    {rule.field: rule.error_message or f"Value does not conform to regex: {rule.regular_expression}"}
                )

Warning on OrderedDefaultRouter's APIRootView attribute

Environment

  • Python version: 3.11
  • Nautobot version: 2.2.2
  • nautobot-data-validation-engine version: 3.1.1

Expected Behavior

No warning messages

Observed Behavior

When the instance starts, or a nautobot-server command issued, a warning is shown:

$ nautobot-server health_check
15:54:45.342 WARNING nautobot.core.api.routers :
  Something has changed an OrderedDefaultRouter's APIRootView attribute to a custom class. Please verify that class DataValidationEngineRootView implements appropriate authentication controls.
DatabaseBackend          ... working
DefaultFileStorageHealthCheck ... working
MigrationsBackend        ... working
RedisBackend             ... working

Steps to Reproduce

  1. Install this app
  2. Run nautobot-server health_check

Security

Does the issue pointed by this error message have a security impact / are this app endpoints accessible without authentication?

The `lint` phase in `.travis.yml` should be updated

The following is the current configuration for the lint phase in .travis.yml:

    - stage: "lint"
      before_script:
        - "pip install --upgrade pip"
        - "pip install invoke poetry toml"
        - "poetry config virtualenvs.create false"
        - "poetry install --no-interaction"
        - "invoke build"
      script:
        - "invoke black"
        - "invoke bandit"
        # - "invoke pydocstyle"
        # - "invoke flake8"
        # - "invoke yamllint"
        # - "invoke pylint"

As you can see four commands are currently disabled. Make sure that these are executed without any errors and enable commands again.

Syncing DataCompliance rules from a Git Repo fails

Environment

  • Python version: 3.8
  • Nautobot version: 2.0 [ build: next-6756eb4-1686184941-py3.8 ]
  • nautobot-data-validation-engine version: 2.1.0 [ branch: next-2.0 ]

Expected Behavior

Able to successfully sync an external Git repository containing Data Compliance rules.

Observed Behavior

When adding a Git repository that has Data Compliance rules via Platform -> Git Repositories, the sync job fails with the error {'exc_type': 'AttributeError', 'exc_message': ("type object 'LogLevelChoices' has no attribute 'LOG_SUCCESS'",), 'exc_module': 'builtins'}. The Git Repository does get added, but any attempts to sync the repo fail.

image

image

image

Steps to Reproduce

  1. Go to Platform -> Git Repositories -> Add
  2. Enter the information from the screenshot above to add a Git Repository data source containing Data Compliance rules
  3. Click 'Create & Sync'

Show built-in data validation rules results under Data Compliance Report

Environment

  • Python version:
  • Nautobot version:
  • nautobot-data-validation-engine version:

Expected Behavior

Data Compliance Report shows values for built-in data validation rules (ie. regex)

This will support the natural workflow :
0. Create disabled data validation rules

  1. Understand data discrepancies : using disabled validation rules ensure inconsistencies are reported normally
  2. Enable data enforcement once data is reviewed and fixed

Observed Behavior

Built-in validation rules (ie. regex) does not show up under Data Compliance Report automatically

Steps to Reproduce

  1. Create bulit-in data validation rule
  2. Execute the data validation report

Running data validation a job fails

Environment

  • Python version:
  • Nautobot version: 2.0 (next from 2023-05-31)
  • nautobot-data-validation-engine version: branch next-2.0

Expected Behavior

Job runs successfully

Observed Behavior

Job fails with a traceback :

Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/celery/app/trace.py", line 451, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/celery/app/trace.py", line 734, in __protected_call__
    return self.run(*args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/nautobot/extras/jobs.py", line 1283, in run_job
    output = _run_job()
  File "/usr/local/lib/python3.8/site-packages/nautobot/extras/jobs.py", line 1209, in _run_job
    output = job.run(data=data, commit=commit)
  File "/usr/local/lib/python3.8/site-packages/nautobot_data_validation_engine/jobs.py", line 66, in run
    ins.clean()
  File "/usr/local/lib/python3.8/site-packages/nautobot_data_validation_engine/custom_validators.py", line 226, in clean
    self.compliance_result(message=f"{self.context['object']} is valid")
  File "/usr/local/lib/python3.8/site-packages/nautobot_data_validation_engine/custom_validators.py", line 259, in compliance_result
    result, _ = DataCompliance.objects.update_or_create(
  File "/usr/local/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 613, in update_or_create
    obj.save(using=self.db)
  File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 739, in save
    self.save_base(using=using, force_insert=force_insert,
  File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 787, in save_base
    post_save.send(
  File "/usr/local/lib/python3.8/site-packages/django/dispatch/dispatcher.py", line 180, in send
    return [
  File "/usr/local/lib/python3.8/site-packages/django/dispatch/dispatcher.py", line 181, in <listcomp>
    (receiver, receiver(signal=self, sender=sender, **named))
  File "/usr/local/lib/python3.8/site-packages/nautobot/extras/context_managers.py", line 81, in _curried
    return _curried_func(*args, *moreargs, **{**kwargs, **morekwargs})
  File "/usr/local/lib/python3.8/site-packages/nautobot/extras/signals.py", line 81, in _handle_changed_object
    objectchange = instance.to_objectchange(action)
  File "/usr/local/lib/python3.8/site-packages/nautobot/extras/models/change_logging.py", line 46, in to_objectchange
    object_data_v2=serialize_object_v2(self),
  File "/usr/local/lib/python3.8/site-packages/nautobot/core/models/utils.py", line 142, in serialize_object_v2
    data = serializer_class(obj, context={"request": None}).data
  File "/usr/local/lib/python3.8/site-packages/rest_framework/serializers.py", line 555, in data
    ret = super().data
  File "/usr/local/lib/python3.8/site-packages/rest_framework/serializers.py", line 253, in data
    self._data = self.to_representation(self.instance)
  File "/usr/local/lib/python3.8/site-packages/rest_framework/serializers.py", line 522, in to_representation
    ret[field.field_name] = field.to_representation(attribute)
  File "/usr/local/lib/python3.8/site-packages/rest_framework/fields.py", line 1187, in to_representation
    value = self.enforce_timezone(value)
  File "/usr/local/lib/python3.8/site-packages/rest_framework/fields.py", line 1135, in enforce_timezone
    if timezone.is_aware(value):
  File "/usr/local/lib/python3.8/site-packages/django/utils/timezone.py", line 220, in is_aware
    return value.utcoffset() is not None
AttributeError: 'datetime.date' object has no attribute 'utcoffset'

Steps to Reproduce

  1. Create device
  2. Create DataComplianceRule for device3.
import re
from nautobot_data_validation_engine.custom_validators import DataComplianceRule, ComplianceError, CustomValidatorIterator


class DeviceDataComplianceRules(DataComplianceRule):
    model = "dcim.device"
    enforce = False

    # Checks if a device name contains any special characters other than a dash (-), underscore (_), or period (.) using regex
    def audit_device_name_chars(self):
        if not re.match("^[a-zA-Z0-9\-_.]+$", self.context["object"].name):
            raise ComplianceError({"name": "Device name contains unallowed special characters."})

    # Checks if a device is not assigned to a rack
    def audit_device_rack(self):
        if not self.context["object"].rack:
            raise ComplianceError({"rack": "Device should be assigned to a rack."})

    def audit(self):
        messages = {}
        for fn in [self.audit_device_name_chars, self.audit_device_rack]:
            try:
                fn()
            except ComplianceError as ex:
                messages.update(ex.message_dict)
        if messages:
            raise ComplianceError(messages)


custom_validators = list(CustomValidatorIterator()) + [DeviceDataComplianceRules]
  1. Execute data compliance job

Only apply regex rules based on other fields

Environment

  • Nautobot version:
  • nautobot-data-validation-engine version:

Proposed Functionality

Only apply a regex rule to a field when the value of another field meets a certain criteria.

Use Case

  • I want all device names in site ABC to start with ABC, and all device names in site DEF start with DEF.
  • I want all device names with a role of leaf to start with ABC, and all device names with a role of spine to start with DEF.

Unique Fields

Environment

  • Nautobot version: 1.2
  • nautobot-data-validation-engine version: 1.0

Proposed Functionality

Allow easy enforcement of unique fields.

Use Case

While it makes sense for Nautobot to not enforce uniqueness on all fields, each organization may want to have some data unique, while not requiring a bespoke plugin. As an example, an organization may be able to safely enforce unique device names and it would be advantageous to them to do so.

`DataCompliance` jobs do not show in Jobs section

Environment

  • Python version: 3.8
  • Nautobot version: 2.0.0b1
  • nautobot-data-validation-engine version: 2.1.0 [ branch: next-2.0 ]

Expected Behavior

The two jobs for DataCompliance are showing as available options under Automation -> Jobs.

Observed Behavior

The two DataCompliance jobs (RunRegisteredDataComplianceRules & DeleteOrphanedDataComplianceData) are not showing within the Jobs section. It appears that they are not getting registered properly in Nautobot 2.0.

image

They do show up under Data Validation Engine details in the Installed Apps section:

image

But clicking on them shows this error:

image

Steps to Reproduce

  1. Navigate to Automation -> Jobs
  2. Navigate to Platform -> Installed Apps -> Data Validation Engine -> Click on one of the jobs

Fix "Publish to GitHub" CI task - bad credentials

Environment

  • nautobot-data-validation-engine version: 2.0.0

Expected Behavior

Publish to GitHub CI task completes successfully.

Observed Behavior

Publish to GitHub CI task fails with a bad credentials error.

README is out of date

The README looks like it is old it refers to requirements.txt and local_requirements which are no longer patterns in Nautobot

Update 'development' directory files to align with other Nautobot apps & docs

Environment

  • Nautobot version: 1.5.0+
  • nautobot-data-validation-engine version: 1.0.0+

Proposed Functionality

Add and update the files in the 'development' directory to align with other Nautobot apps. An example is https://github.com/nautobot/nautobot-plugin-welcome-wizard/tree/develop/development. This will bring the repo up-to-speed with the developer experience of other Nautobot apps and more closely follow developer docs.

Use Case

As an engineer wanting to develop for the Nautobot Data Validation Engine app, I want a simpler structure of the development files required to setup my dev environment and for them to coincide with the development guides, docs, and other Nautobot apps.

importlib-metadata 5.0.0 in lockfile prevents nautobot from starting on python 3.7

Environment

  • Python version: 3.7.12
  • Nautobot version: 1.2.0-1.3.10
  • nautobot-data-validation-engine version: develop branch

Steps to Reproduce

  1. clone develop branch
  2. invoke build
  3. invoke debug

Expected Behavior

Nautobot starts

Observed Behavior

Nautobot fails to start with traceback:

nautobot_data_validation_engine-nautobot-1  |   File "/usr/local/lib/python3.7/site-packages/nautobot/core/__init__.py", line 5, in <module>
nautobot_data_validation_engine-nautobot-1  |     from nautobot.core.celery import app as celery_app
nautobot_data_validation_engine-nautobot-1  |   File "/usr/local/lib/python3.7/site-packages/nautobot/core/celery/__init__.py", line 4, in <module>
nautobot_data_validation_engine-nautobot-1  |     from celery import Celery, shared_task
nautobot_data_validation_engine-nautobot-1  | ImportError: cannot import name 'Celery' from 'celery' (/usr/local/lib/python3.7/site-packages/celery/__init__.py)
nautobot_data_validation_engine-nautobot-1  |Waited 30s or more for the DB to become ready.

Related to celery issue celery/celery#7783

The poetry.lock file is using importlib-metadata version 5.0.0. There doesn't appear to be any dependency on this version and the workaround is to pin the version to <5.0.0. The nautobot dependency was changed from ~4.4 to ^4.4 in nautobot v1.4.0 which resolves the issue.

Incompatible with 1.1.0-beta.1

Environment

  • Python version: 3.6.14
  • Nautobot version: 1.1.0-beta.1
  • nautobot-device-onboarding version: 1.0.0

After installing the plugin and adding it to PLUGINS I am unable to start Nautobot:

Traceback (most recent call last):
  File "/usr/local/bin/nautobot-server", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.6/site-packages/nautobot/core/cli.py", line 62, in main
    initializer=_configure_settings,  # Called after defaults
  File "/usr/local/lib/python3.6/site-packages/nautobot/core/runner/runner.py", line 266, in run_app
    management.execute_from_command_line([runner_name, command] + command_args)
  File "/usr/local/lib/python3.6/site-packages/django/core/management/__init__.py", line 401, in execute_from_command_line
    utility.execute()
  File "/usr/local/lib/python3.6/site-packages/django/core/management/__init__.py", line 377, in execute
    django.setup()
  File "/usr/local/lib/python3.6/site-packages/django/__init__.py", line 24, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "/usr/local/lib/python3.6/site-packages/django/apps/registry.py", line 122, in populate
    app_config.ready()
  File "/usr/local/lib/python3.6/site-packages/nautobot/extras/plugins/__init__.py", line 101, in ready
    register_plugin_menu_items(self.verbose_name, menu_items)
  File "/usr/local/lib/python3.6/site-packages/nautobot/extras/plugins/__init__.py", line 380, in register_plugin_menu_items
    registry["nav_menu"]["tabs"]["Plugins"][list(registry["nav_menu"]["tabs"]["Plugins"])[-1]]["weight"]
TypeError: 'set' object is not subscriptable

Steps to Reproduce

  1. Install Nautobot 1.1.0b1
  2. Install data-validation-engine plugin
  3. Enable plugin in nautobot_config PLUGINS
  4. start Nautobot

Expected Behavior

Nautobot Starts

Observed Behavior

Nautobot Fails to start

Address and fix pylint recommendations

Environment

  • Python version: 3.10
  • Nautobot version: 1.5.14
  • nautobot-data-validation-engine version: 2.0.0

Steps to Reproduce

  1. Remove the pylint error types from pyproject.toml in the tool.pylint.messages_control for disable
  2. Run invoke tests or invoke pylint to run the tests
  3. Errors will be presented in the output with their location in the code

Expected Behavior

Pylint to run and complete with 10/10 score without having to disable and skip specific error types

Observed Behavior

Pylint runs but fails with a score of less than 10/10.

Address and resolve the pylint issues.

Validation Rules for a subset of objects

Environment

  • Nautobot version: 2.x.x
  • nautobot-data-validation-engine version: 3.x.x

Proposed Functionality

Currently, DVE's various validation rules are applied for all instances of a chosen content type. However, there are many times where validation rules might exist that are only relevant to a specific filtered subset of that grouping.

As a network automation engineer, I want the ability to apply validation rules to either all object instances of a certain content type or only a filtered subset, so that I can achieve differing validation rules that are not necessarily global.

Use Case

Within Company X, we have two primary departments within our network org: Core and Access. I want to enforce naming standards for our network devices. However, the naming standards are not the same for Core and Access. Each department has their own set of rules defined for the devices that they manage.

When creating Regex Rules for the dcim | device content type's name field using DVE, rather than only being able to create rules that will apply to all device objects, I want to be able to create one rule with the naming standards for Core (i.e. devices whose role is Core) and another rule with the naming standards for Access (i.e. devices whose role is Access), where each rule only applies to the relevant department's devices (e.g. filtered by device role).

Support of External Validation Services

Environment

  • Nautobot version:
  • nautobot-data-validation-engine version:

Proposed Functionality

Support External Validation Services

Use Case

As an organization that operates a micro service to validate names of devices, I wish to be able to have the validation plugin reach out to these services to complete validations.

Legacy templates need to extend `generic/object_detail.html`

Black test fails

Environment

  • Python version:
  • Nautobot version:
  • nautobot-data-validation-engine version: develop branch

Steps to Reproduce

  1. Run Black tests

Expected Behavior

Black tests should pass

Observed Behavior

Run poetry run invoke black
Traceback (most recent call last):
  File "/home/runner/.cache/pypoetry/virtualenvs/nautobot-data-validation-engine-HqbtailY-py3.9/bin/black", line 5, in <module>
    from black import patched_main
  File "/home/runner/.cache/pypoetry/virtualenvs/nautobot-data-validation-engine-HqbtailY-py3.9/lib/python3.9/site-packages/black/__init__.py", line 52, in <module>
    from typed_ast import ast3, ast27
  File "/home/runner/.cache/pypoetry/virtualenvs/nautobot-data-validation-engine-HqbtailY-py3.9/lib/python3.9/site-packages/typed_ast/ast3.py", line 40, in <module>
    from typed_ast import _ast3
ImportError: /home/runner/.cache/pypoetry/virtualenvs/nautobot-data-validation-engine-HqbtailY-py3.9/lib/python3.9/site-packages/typed_ast/_ast3.cpython-39-x[8](https://github.com/nautobot/nautobot-plugin-data-validation-engine/runs/7108413421?check_suite_focus=true#step:4:9)6_64-linux-gnu.so: undefined symbol: _PyUnicode_DecodeUnicodeEscape
Error: Process completed with exit code 1.

Mandatory Fields

Environment

  • Nautobot version: 1.1
  • nautobot-device-onboarding version: 1.0

Proposed Functionality

Allow easy enforcement of mandatory fields.

Use Case

While it makes sense for Nautobot to not enforce all fields, each organization may want to enforce some data, while not requiring a bespoke plugin. As an example, an MSP may want to enforce tenant or an organization may want to enforce manufacturer.

Enable Git Repository Sync

Environment

  • Nautobot version: 1.2.4
  • nautobot-data-validation-engine version: 1.0.0

Proposed Functionality

As in other plugins such as golden config I would like to be able to backup/restore my data validation rules to/from a git data source.

Use Case

Today I'm able to test config contexts/golden config and other features of Nautobot/Nautobot plugins by deploying the changes in git, testing in my dev environment, and if successful merging those (via the a PR process) to my production environment and I have a high level of confidence what I tested in dev is now in prod. With my Data validation rules I have to manually create them in dev, test them, and manually create them in prod. If these could be exported to git my workflow would be consistent.

Editing object with data validation no longer possible

Environment

  • Python version:
  • Nautobot version: 2.0 (next from 2023-05-31)
  • nautobot-data-validation-engine version: branch next-2.0

Expected Behavior

  1. Object can be edited if DataComplianceRule exist for given model

Observed Behavior

Object can't be edited once a DataComplianceRule created for model

Screenshot 2023-05-31 at 10 10 56

Steps to Reproduce

  1. Create device
  2. Create DataComplianceRule for device3.
import re
from nautobot_data_validation_engine.custom_validators import DataComplianceRule, ComplianceError, CustomValidatorIterator


class DeviceDataComplianceRules(DataComplianceRule):
    model = "dcim.device"
    enforce = False

    # Checks if a device name contains any special characters other than a dash (-), underscore (_), or period (.) using regex
    def audit_device_name_chars(self):
        if not re.match("^[a-zA-Z0-9\-_.]+$", self.context["object"].name):
            raise ComplianceError({"name": "Device name contains unallowed special characters."})

    # Checks if a device is not assigned to a rack
    def audit_device_rack(self):
        if not self.context["object"].rack:
            raise ComplianceError({"rack": "Device should be assigned to a rack."})

    def audit(self):
        messages = {}
        for fn in [self.audit_device_name_chars, self.audit_device_rack]:
            try:
                fn()
            except ComplianceError as ex:
                messages.update(ex.message_dict)
        if messages:
            raise ComplianceError(messages)


custom_validators = list(CustomValidatorIterator()) + [DeviceDataComplianceRules]
  1. Attempt to edit a device (change a description), hit save/next.

Error occurs:

<class 'AttributeError'>

'datetime.date' object has no attribute 'utcoffset'

Python version: 3.8.16
Nautobot version: 2.0.0a2

Update code structure to follow the cookiecutter-ntc template

Environment

  • Nautobot version: 1.5.0+
  • nautobot-data-validation-engine version: 2.0.0

Proposed Functionality

Update the Data Validation Engine app repository to align with other Nautobot apps. The structure should follow the cookiecutter-ntc template (https://github.com/networktocode-llc/cookiecutter-ntc). This will bring the repo up-to-speed and consistent with other Nautobot apps and more closely follow existing docs.

Use Case

As an engineer wanting to develop for the Nautobot Data Validation Engine app, I want a consistent structure of the app's repo/code and for it to coincide with the development guides, docs, and structure of other Nautobot apps.

Dynamic `Field` in rule forms

Environment

  • Nautobot version: 1.5.18
  • nautobot-data-validation-engine version: 2.0.0

Proposed Functionality

Make the Field field in the rule form dynamic (similar to the Content type field) so that a user can clearly see the various Field options available for the selected Content type.
image

Use Case

As a network engineer, I want to add a validation rule for the Asset Tag field for Devices without having to lookup the proper formatting of the Asset Tag field for the validation rule form to accept it. I want to see the available Field options for the selected Content type 'dcim | device' and be able to choose quickly from the form.

Uninstall docs need to have steps to remove models where the `slug` attribute was removed

Environment

  • Python version: 3.11
  • Nautobot version: 2.1.X
  • nautobot-data-validation-engine version: Latest

Expected Behavior

nautobot-server migrate nautobot_data_validation_engine zero

Observed Behavior

These tables need data cleared prior to uninstall (can have objects removed via UI, API, or ORM)
nautobot_data_validation_engine_minmaxvalidationrule
nautobot_data_validation_engine_regularexpressionvalidationrule

Steps to Reproduce

Support validating the set of tags on an object

Environment

  • Python version: 3.8.5
  • Nautobot version: 1.0.1
  • nautobot-plugin-data-validation-engine: 1.0.0-dev

Steps to Reproduce

  1. Create regex rule for Object allowing tags, e.g. ipam.VLAN
  2. Specify "tags" as the Field
  3. Specify simple regex e.g. "data" as Regular expression

Example rule used for testing:

image

Expected Behavior

One of two outcomes should happend:

  1. When new VLAN is created and tag matching regex is added new object should be created without errors.
  2. When new VLAN is created and added tag does NOT match regex a validation error should be raised.

Observed Behavior

TypeError is raised: "expected string or bytes-like object"

image

Full traceback:

Internal Server Error: /ipam/vlans/add/
Traceback (most recent call last):
  File "/opt/nautobot/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/opt/nautobot/lib/python3.8/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/opt/nautobot/lib/python3.8/site-packages/django/views/generic/base.py", line 70, in view
    return self.dispatch(request, *args, **kwargs)
  File "/opt/nautobot/lib/python3.8/site-packages/nautobot/core/views/generic.py", line 266, in dispatch
    return super().dispatch(request, *args, **kwargs)
  File "/opt/nautobot/lib/python3.8/site-packages/nautobot/utilities/views.py", line 94, in dispatch
    return super().dispatch(request, *args, **kwargs)
  File "/opt/nautobot/lib/python3.8/site-packages/django/views/generic/base.py", line 98, in dispatch
    return handler(request, *args, **kwargs)
  File "/opt/nautobot/lib/python3.8/site-packages/nautobot/core/views/generic.py", line 293, in post
    if form.is_valid():
  File "/opt/nautobot/lib/python3.8/site-packages/django/forms/forms.py", line 177, in is_valid
    return self.is_bound and not self.errors
  File "/opt/nautobot/lib/python3.8/site-packages/django/forms/forms.py", line 172, in errors
    self.full_clean()
  File "/opt/nautobot/lib/python3.8/site-packages/django/forms/forms.py", line 376, in full_clean
    self._post_clean()
  File "/opt/nautobot/lib/python3.8/site-packages/django/forms/models.py", line 405, in _post_clean
    self.instance.full_clean(exclude=exclude, validate_unique=False)
  File "/opt/nautobot/lib/python3.8/site-packages/django/db/models/base.py", line 1216, in full_clean
    self.clean()
  File "/opt/nautobot/lib/python3.8/site-packages/nautobot/extras/plugins/validators.py", line 34, in wrapper
    custom_validator(model_instance).clean()
  File "/opt/nautobot/lib/python3.8/site-packages/nautobot_data_validation_engine/custom_validators.py", line 35, in clean
    if not re.match(rule.regular_expression, getattr(obj, rule.field)):
  File "/usr/lib/python3.8/re.py", line 191, in match
    return _compile(pattern, flags).match(string)
TypeError: expected string or bytes-like object

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.