From 2fddd0071681b830c67ae343a8cf61515c149b5f Mon Sep 17 00:00:00 2001 From: Ken Celenza Date: Sun, 1 Oct 2023 19:29:21 -0400 Subject: [PATCH 1/2] See #575 for commits, update to 2.0.0 (#575) * Update version statements * Replace broken imports * Swap Region/Site to Location * Fix/skip test cases * Change filters for 2.x * Remove scope property * Remove code around csv import/export per 2.x changes * Change some platform slug uses to network_driver * Remove remaining references to slugs in core models * Switch tag filter to tags * Remove custom get_absolute_url method * Remove management command, move to new dispatcher method, fix job logging and signature * Cookie initialy baked by NetworkToCode Cookie Drift Manager Tool (#583) * chore: Move docs changes to separate pr #584 * fix: Update poetry lock * fix: Pylint * fix: PR comments * fix: Job invocation * Jmcgill/2.x jobs rebase (#595) * Start jobs migration * todos updates (#598) * Move to new dispatcher, move compliant to device tab, update locations/tags filters/forms, * remove platform mapping. * Remove slugs added by Config Remediation work (#602) * Logging updates, active tab fix, add default_deploy_status, * Migrate config compliance and golden config views to viewsets, upgrade diff2html, remove job inclusion check, migrate gc views away from device model * General cleanup from linters (#615) * Revert list view actions to views, fix logging, dispatcher, call jobs by name, fix JS failures catching, run lock * Re-lock, and use hyperlinked_object * fix GoldenConfigSettingForm * downgrade django-pivot to 1.8.1 * Fix failing notes_url test (#625) * bump version, remove slugify, remove commit from config deploy, simplify serialzer, * Fix some more tests for 2.0 (#631) * Update git, logger bug, update processor * logger updates, add to request object, linter * audit linkable retrieve links, link configs vs show them * fix status link * Fix execute menu, extra context in GC overview, expanded to support RC4 * update gitrepo flow, switch to core get_app_settings_or_config, update test * Invert Completed logic * Rename network_driver_mapper to network_driver_mappings (#639) * Add logic to warn when GoldenConfig is out of sync (#629) * Add Job to sync GoldenConfig * update & clean up processor logic, fix reference to .url * fix datasources yaml key to network_driver but backwards to _slug * fix js issue where was too greedy in selection, add copy button * fix filtering on configplans * Add back constance code and clean up json view code (#642) * version update and remove json/yaml toggle * fix api that populates filterform for plan and deploy results * Start on migration/release docs, make booleans more consistent, add error codes framework, move to SearchFilter objects, clean up imports, add copy button to compliance retrieve view, * Migration docs updates, 2.0 release notes, remove dispatcher references * add custom dispatcher docs, update secrets docs, add constance docs, add error code links to other repos * update dependencies, fix or skip tests, minor doc updates --------- Co-authored-by: Jacob McGill Co-authored-by: Jacob McGill <9847006+jmcgill298@users.noreply.github.com> Co-authored-by: Jan Snasel Co-authored-by: bakebot Co-authored-by: Hanlin Miao Co-authored-by: Gary Snider <75227981+gsnider2195@users.noreply.github.com> Co-authored-by: Bryan Culver Co-authored-by: mzb Co-authored-by: John Anderson Co-authored-by: Jeff Kala --- .bandit.yml | 2 +- .cookiecutter.json | 33 + .dockerignore | 27 + .flake8 | 6 + .github/CODEOWNERS | 2 +- .github/ISSUE_TEMPLATE/bug_report.md | 16 +- .github/ISSUE_TEMPLATE/feature_request.md | 4 +- .../pull_request_template.md | 10 + .github/workflows/ci.yml | 38 +- .github/workflows/rebake.yaml | 34 + .github/workflows/upstream_testing.yml | 6 +- .gitignore | 26 +- .readthedocs.yaml | 2 +- .yamllint.yml | 5 +- LICENSE | 2 +- README.md | 3 + development/Dockerfile | 33 +- development/creds.example.env | 40 + development/development.env | 2 - development/docker-compose.base.yml | 4 +- development/docker-compose.dev.yml | 22 + development/docker-compose.mysql.yml | 8 +- development/docker-compose.postgres.yml | 4 +- development/nautobot_config.py | 116 +- docs/admin/admin_install.md | 32 +- docs/admin/compatibility_matrix.md | 3 +- docs/admin/migrating_to_v2.md | 202 + docs/admin/release_notes/version_1.4.md | 66 +- docs/admin/release_notes/version_1.5.md | 16 +- docs/admin/release_notes/version_2.0.md | 49 + docs/admin/troubleshooting/E3001.md | 19 + docs/admin/troubleshooting/E3002.md | 19 + docs/admin/troubleshooting/E3003.md | 19 + docs/admin/troubleshooting/E3004.md | 19 + docs/admin/troubleshooting/E3005.md | 19 + docs/admin/troubleshooting/E3006.md | 19 + docs/admin/troubleshooting/E3007.md | 19 + docs/admin/troubleshooting/E3008.md | 19 + docs/admin/troubleshooting/E3009.md | 19 + docs/admin/troubleshooting/E3010.md | 19 + docs/admin/troubleshooting/E3011.md | 19 + docs/admin/troubleshooting/E3012.md | 19 + docs/admin/troubleshooting/E3013.md | 19 + docs/admin/troubleshooting/E3014.md | 19 + docs/admin/troubleshooting/E3015.md | 19 + docs/admin/troubleshooting/E3016.md | 19 + docs/admin/troubleshooting/E3017.md | 19 + docs/admin/troubleshooting/E3018.md | 19 + docs/admin/troubleshooting/E3019.md | 19 + docs/admin/troubleshooting/E3020.md | 19 + docs/admin/troubleshooting/E3021.md | 19 + docs/admin/troubleshooting/E3022.md | 19 + docs/admin/troubleshooting/E3023.md | 19 + docs/admin/troubleshooting/E3024.md | 19 + docs/admin/troubleshooting/E3025.md | 19 + docs/admin/troubleshooting/E3026.md | 19 + docs/admin/troubleshooting/index.md | 13 + docs/dev/dev_adr.md | 2 +- docs/dev/dev_environment.md | 14 +- docs/images/backup-git-step2.png | Bin 69722 -> 44937 bytes docs/images/secret-step1.png | Bin 0 -> 383810 bytes docs/images/secret-step2.png | Bin 0 -> 340453 bytes docs/user/app_faq.md | 31 +- docs/user/app_feature_backup.md | 4 +- docs/user/app_feature_compliance.md | 6 +- docs/user/app_feature_compliancecustom.md | 4 +- .../user/app_feature_config_postprocessing.md | 26 +- docs/user/app_feature_sotagg.md | 27 +- docs/user/app_getting_started.md | 85 +- docs/user/app_use_cases.md | 98 +- .../troubleshoot_dispatchers.md | 25 +- invoke.example.yml | 2 +- invoke.mysql.yml | 2 +- mkdocs.yml | 30 + nautobot_golden_config/__init__.py | 29 +- nautobot_golden_config/api/serializers.py | 96 +- nautobot_golden_config/api/urls.py | 2 +- nautobot_golden_config/api/views.py | 41 +- nautobot_golden_config/choices.py | 2 +- nautobot_golden_config/datasources.py | 47 +- nautobot_golden_config/filters.py | 417 +- nautobot_golden_config/forms.py | 457 +- nautobot_golden_config/jobs.py | 243 +- .../management/commands/run_config_backup.py | 22 - .../commands/run_config_compliance.py | 22 - .../commands/run_generate_config.py | 22 - .../0020_convert_dynamicgroup_part_2.py | 1 - .../0028_auto_20230916_1712_part1.py | 43 + .../0028_auto_20230916_1712_part2.py | 204 + .../0029_alter_configplan_unique_together.py | 17 + .../0030_alter_goldenconfig_device.py | 19 + nautobot_golden_config/models.py | 256 +- nautobot_golden_config/navigation.py | 7 +- .../nornir_plays/__init__.py | 0 .../nornir_plays/config_backup.py | 86 +- .../nornir_plays/config_compliance.py | 91 +- .../nornir_plays/config_deployment.py | 121 +- .../nornir_plays/config_intended.py | 59 +- .../nornir_plays/processor.py | 49 +- nautobot_golden_config/signals.py | 18 +- .../diff2html-3.4.13/diff2html.min.css | 1 - .../diff2html-3.4.13/diff2html.min.js | 1 - .../diff2html-3.4.43/diff2html.min.css | 1 + .../diff2html-3.4.43/diff2html.min.js | 1 + nautobot_golden_config/static/run_job.js | 180 +- nautobot_golden_config/tables.py | 55 +- nautobot_golden_config/template_content.py | 42 +- .../compliance_report.html | 40 - .../compliancerule_retrieve.html | 4 +- .../configcompliance.html | 115 - .../configcompliance_details.html | 54 - .../configcompliance_detailsmodal.html | 37 - ...t.html => configcompliance_devicetab.html} | 50 +- .../configcompliance_list.html | 15 + ...rt.html => configcompliance_overview.html} | 36 +- .../configcompliance_retrieve.html | 93 + .../configplan_create.html | 14 +- .../configplan_list.html | 9 +- .../configplan_retrieve.html | 16 +- .../configremove_retrieve.html | 2 +- .../configreplace_retrieve.html | 2 +- .../content_template.html | 11 +- .../nautobot_golden_config/dff2html_base.html | 4 - .../goldenconfig_details.html | 6 + .../goldenconfig_detailsmodal.html | 67 + .../goldenconfig_list.html | 42 +- .../goldenconfig_retrieve.html | 54 + .../goldenconfigsetting_retrieve.html | 18 +- .../include/span_button.html | 5 + .../job_result_modal.html | 4 +- .../nautobot_golden_config/manytomany.html | 6 - .../remediationsetting_retrieve.html | 2 +- nautobot_golden_config/tests/conftest.py | 241 +- .../forms/test_golden_config_settings.py | 8 +- nautobot_golden_config/tests/test_api.py | 203 +- nautobot_golden_config/tests/test_basic.py | 1 - .../tests/test_datasources.py | 18 +- nautobot_golden_config/tests/test_filters.py | 226 +- nautobot_golden_config/tests/test_graphql.py | 51 +- nautobot_golden_config/tests/test_helpers.py | 39 +- nautobot_golden_config/tests/test_models.py | 43 +- .../test_config_compliance.py | 8 +- .../tests/test_utilities/test_config_plan.py | 1 - .../tests/test_utilities/test_git.py | 83 +- .../tests/test_utilities/test_graphql.py | 2 +- .../tests/test_utilities/test_helpers.py | 65 +- .../tests/test_utilities/test_utils.py | 28 - nautobot_golden_config/tests/test_views.py | 84 +- nautobot_golden_config/urls.py | 32 +- .../utilities/config_plan.py | 9 +- .../utilities/config_postprocessing.py | 18 +- nautobot_golden_config/utilities/constant.py | 1 + nautobot_golden_config/utilities/git.py | 65 +- nautobot_golden_config/utilities/graphql.py | 3 +- nautobot_golden_config/utilities/helper.py | 111 +- nautobot_golden_config/utilities/logger.py | 47 + .../utilities/management.py | 87 - nautobot_golden_config/utilities/mat_plot.py | 144 + nautobot_golden_config/utilities/utils.py | 37 +- nautobot_golden_config/views.py | 1035 +-- poetry.lock | 5542 +++++++++-------- pyproject.toml | 47 +- tasks.py | 337 +- 163 files changed, 7533 insertions(+), 6117 deletions(-) create mode 100644 .cookiecutter.json create mode 100644 .dockerignore create mode 100644 .github/PULL_REQUEST_TEMPLATE/pull_request_template.md create mode 100644 .github/workflows/rebake.yaml create mode 100644 docs/admin/migrating_to_v2.md create mode 100755 docs/admin/release_notes/version_2.0.md create mode 100644 docs/admin/troubleshooting/E3001.md create mode 100644 docs/admin/troubleshooting/E3002.md create mode 100644 docs/admin/troubleshooting/E3003.md create mode 100644 docs/admin/troubleshooting/E3004.md create mode 100644 docs/admin/troubleshooting/E3005.md create mode 100644 docs/admin/troubleshooting/E3006.md create mode 100644 docs/admin/troubleshooting/E3007.md create mode 100644 docs/admin/troubleshooting/E3008.md create mode 100644 docs/admin/troubleshooting/E3009.md create mode 100644 docs/admin/troubleshooting/E3010.md create mode 100644 docs/admin/troubleshooting/E3011.md create mode 100644 docs/admin/troubleshooting/E3012.md create mode 100644 docs/admin/troubleshooting/E3013.md create mode 100644 docs/admin/troubleshooting/E3014.md create mode 100644 docs/admin/troubleshooting/E3015.md create mode 100644 docs/admin/troubleshooting/E3016.md create mode 100644 docs/admin/troubleshooting/E3017.md create mode 100644 docs/admin/troubleshooting/E3018.md create mode 100644 docs/admin/troubleshooting/E3019.md create mode 100644 docs/admin/troubleshooting/E3020.md create mode 100644 docs/admin/troubleshooting/E3021.md create mode 100644 docs/admin/troubleshooting/E3022.md create mode 100644 docs/admin/troubleshooting/E3023.md create mode 100644 docs/admin/troubleshooting/E3024.md create mode 100644 docs/admin/troubleshooting/E3025.md create mode 100644 docs/admin/troubleshooting/E3026.md create mode 100644 docs/admin/troubleshooting/index.md create mode 100644 docs/images/secret-step1.png create mode 100644 docs/images/secret-step2.png delete mode 100644 nautobot_golden_config/management/commands/run_config_backup.py delete mode 100644 nautobot_golden_config/management/commands/run_config_compliance.py delete mode 100644 nautobot_golden_config/management/commands/run_generate_config.py create mode 100644 nautobot_golden_config/migrations/0028_auto_20230916_1712_part1.py create mode 100644 nautobot_golden_config/migrations/0028_auto_20230916_1712_part2.py create mode 100644 nautobot_golden_config/migrations/0029_alter_configplan_unique_together.py create mode 100644 nautobot_golden_config/migrations/0030_alter_goldenconfig_device.py create mode 100644 nautobot_golden_config/nornir_plays/__init__.py delete mode 100644 nautobot_golden_config/static/nautobot_golden_config/diff2html-3.4.13/diff2html.min.css delete mode 100644 nautobot_golden_config/static/nautobot_golden_config/diff2html-3.4.13/diff2html.min.js create mode 100644 nautobot_golden_config/static/nautobot_golden_config/diff2html-3.4.43/diff2html.min.css create mode 100644 nautobot_golden_config/static/nautobot_golden_config/diff2html-3.4.43/diff2html.min.js delete mode 100644 nautobot_golden_config/templates/nautobot_golden_config/compliance_report.html delete mode 100644 nautobot_golden_config/templates/nautobot_golden_config/configcompliance.html delete mode 100644 nautobot_golden_config/templates/nautobot_golden_config/configcompliance_details.html delete mode 100644 nautobot_golden_config/templates/nautobot_golden_config/configcompliance_detailsmodal.html rename nautobot_golden_config/templates/nautobot_golden_config/{compliance_device_report.html => configcompliance_devicetab.html} (86%) create mode 100644 nautobot_golden_config/templates/nautobot_golden_config/configcompliance_list.html rename nautobot_golden_config/templates/nautobot_golden_config/{compliance_overview_report.html => configcompliance_overview.html} (76%) create mode 100644 nautobot_golden_config/templates/nautobot_golden_config/configcompliance_retrieve.html delete mode 100644 nautobot_golden_config/templates/nautobot_golden_config/dff2html_base.html create mode 100644 nautobot_golden_config/templates/nautobot_golden_config/goldenconfig_details.html create mode 100644 nautobot_golden_config/templates/nautobot_golden_config/goldenconfig_detailsmodal.html create mode 100644 nautobot_golden_config/templates/nautobot_golden_config/goldenconfig_retrieve.html create mode 100644 nautobot_golden_config/templates/nautobot_golden_config/include/span_button.html delete mode 100644 nautobot_golden_config/templates/nautobot_golden_config/manytomany.html delete mode 100644 nautobot_golden_config/tests/test_utilities/test_utils.py create mode 100644 nautobot_golden_config/utilities/logger.py delete mode 100644 nautobot_golden_config/utilities/management.py create mode 100644 nautobot_golden_config/utilities/mat_plot.py diff --git a/.bandit.yml b/.bandit.yml index 16ab010a..78140801 100644 --- a/.bandit.yml +++ b/.bandit.yml @@ -2,6 +2,6 @@ # No need to check for security issues in the test scripts! exclude_dirs: - "./nautobot_golden_config/tests/" - + - "./.venv/" skips: - "B404" diff --git a/.cookiecutter.json b/.cookiecutter.json new file mode 100644 index 00000000..ea65bfeb --- /dev/null +++ b/.cookiecutter.json @@ -0,0 +1,33 @@ +{ + "cookiecutter": { + "codeowner_github_usernames": "@itdependsnetworks @jeffkala @nkallergis", + "full_name": "Network to Code, LLC", + "email": "opensource@networktocode.com", + "github_org": "nautobot", + "plugin_name": "nautobot_golden_config", + "verbose_name": "Golden Config", + "plugin_slug": "nautobot-golden-config", + "project_slug": "nautobot-plugin-golden-config", + "repo_url": "https://github.com/nautobot/nautobot-plugin-golden-config", + "base_url": "golden-config", + "min_nautobot_version": "1.4.0", + "max_nautobot_version": "1.9999", + "nautobot_version": "latest", + "camel_name": "NautobotGoldenConfig", + "project_short_description": "A plugin for configuration on nautobot", + "version": "1.0.0", + "model_class_name": "None", + "open_source_license": "Apache-2.0", + "docs_base_url": "https://docs.nautobot.com", + "docs_app_url": "https://docs.nautobot.com/projects/golden-config/en/latest", + "_drift_manager": { + "template": "https://github.com/nautobot/cookiecutter-nautobot-app.git", + "template_dir": "nautobot-app", + "template_ref": "develop", + "cookie_dir": "", + "branch_prefix": "drift-manager", + "pull_request_strategy": "create", + "post_actions": [] + } + } +} diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..2270f496 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,27 @@ +# Docker related +development/Dockerfile +development/docker-compose*.yml +development/*.env +*.env +environments/ + +# Python +**/*.pyc +**/*.pyo +**/__pycache__/ +**/.pytest_cache/ +**/.venv/ + + +# Other +docs/_build +FAQ.md +.git/ +.gitignore +.github +tasks.py +LICENSE +**/*.log +**/.vscode/ +invoke*.yml +tasks.py diff --git a/.flake8 b/.flake8 index e3ba27d5..888023fd 100644 --- a/.flake8 +++ b/.flake8 @@ -2,3 +2,9 @@ # E501: Line length is enforced by Black, so flake8 doesn't need to check it # W503: Black disagrees with this rule, as does PEP 8; Black wins ignore = E501, W503 +exclude = + migrations, + __pycache__, + manage.py, + settings.py, + .venv diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 30cca39a..d1982711 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,2 +1,2 @@ -# Default owners for all files in this repository +# Default owner(s) of all files in this repository * @itdependsnetworks @jeffkala @nkallergis diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 8f26fcbf..cbb194ae 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -5,9 +5,16 @@ about: Report a reproducible bug in the current release of nautobot-golden-confi ### Environment * Python version: -* Nautobot version: +* Nautobot version: * nautobot-golden-config version: + +### Expected Behavior + + + +### Observed Behavior + -### Expected Behavior - - - -### Observed Behavior diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 924a52ad..a8d54617 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,11 +1,11 @@ --- name: ✨ Feature Request about: Propose a new feature or enhancement + --- ### Environment -* Python version: -* Nautobot version: +* Nautobot version: * nautobot-golden-config version: Start safe to modify section -# Uncomment the line below if you are apt-installing any package. -# RUN apt update -# RUN apt install libldap2-dev +# Uncomment the lines below if you are apt-installing any package. +# RUN apt-get -y update && apt-get -y install \ +# libldap2-dev \ +# && rm -rf /var/lib/apt/lists/* # --> Stop safe to modify section # ------------------------------------------------------------------------------------- -# Install Nautobot Plugin +# Install Nautobot App # ------------------------------------------------------------------------------------- # !!! USE CAUTION WHEN MODIFYING LINES BELOW @@ -54,7 +53,7 @@ WORKDIR /source COPY . /source # Get container's installed Nautobot version as a forced constraint -# NAUTOBOT_VER may be a branch name and not a published release therefore we need to get the installed version +# NAUTOBOT_VER may be a branch name and not a published release therefor we need to get the installed version # so pip can use it to recognize local constraints. RUN pip show nautobot | grep "^Version: " | sed -e 's/Version: /nautobot==/' > constraints.txt @@ -68,7 +67,7 @@ RUN poetry export -f requirements.txt --with dev --without-hashes --output poetr RUN sort poetry_freeze_base.txt poetry_freeze_all.txt | uniq -u > poetry_freeze_dev.txt # Install all local project as editable, constrained on Nautobot version, to get any additional -# direct dependencies of the plugin +# direct dependencies of the app RUN pip install -c constraints.txt -e . # Install any dev dependencies frozen from Poetry diff --git a/development/creds.example.env b/development/creds.example.env index 26e24fad..554d4223 100644 --- a/development/creds.example.env +++ b/development/creds.example.env @@ -25,3 +25,43 @@ MYSQL_PASSWORD=${NAUTOBOT_DB_PASSWORD} # NAUTOBOT_DB_HOST=localhost # NAUTOBOT_REDIS_HOST=localhost # NAUTOBOT_CONFIG=development/nautobot_config.py + +# Use this for token and user vars + +# NAUTOBOT_GOLDEN_CONFIG_GIT_TOKEN= +# NAUTOBOT_GOLDEN_CONFIG_GIT_USERNAME= + +# Use this for token creation + +# from nautobot.extras.models.secrets import Secret, SecretsGroup, SecretsGroupAssociation +# from nautobot.extras.choices import SecretsGroupAccessTypeChoices, SecretsGroupSecretTypeChoices + +# secrets_group = SecretsGroup(name="Secrets Group 1") +# secrets_group.validated_save() + +# environment_secret = Secret.objects.create( +# name="Environment Variable Token", +# provider="environment-variable", +# parameters={"variable": "NAUTOBOT_GOLDEN_CONFIG_GIT_TOKEN"}, +# ) + +# SecretsGroupAssociation.objects.create( +# secrets_group=secrets_group, +# secret=environment_secret, +# access_type=SecretsGroupAccessTypeChoices.TYPE_HTTP, +# secret_type=SecretsGroupSecretTypeChoices.TYPE_TOKEN, +# ) + +# backup_repository=GitRepository.objects.filter(provided_contents__contains="nautobot_golden_config.backupconfigs").first() +# intended_repository=GitRepository.objects.filter(provided_contents__contains="nautobot_golden_config.intendedconfigs").first() +# jinja_repository=GitRepository.objects.filter(provided_contents__contains="nautobot_golden_config.jinjatemplate").first() + +# if not backup_repository.secrets_group is not None: +# backup_repository.secrets_group = secrets_group +# backup_repository.validated_save() +# if not intended_repository.secrets_group is not None: +# intended_repository.secrets_group = secrets_group +# intended_repository.validated_save() +# if not jinja_repository.secrets_group is not None: +# jinja_repository.secrets_group = secrets_group +# jinja_repository.validated_save() \ No newline at end of file diff --git a/development/development.env b/development/development.env index b6023644..abdb88f8 100644 --- a/development/development.env +++ b/development/development.env @@ -7,8 +7,6 @@ NAUTOBOT_BANNER_TOP="Local" NAUTOBOT_CHANGELOG_RETENTION=0 NAUTOBOT_DEBUG=True -NAUTOBOT_DJANGO_EXTENSIONS_ENABLED=True -NAUTOBOT_DJANGO_TOOLBAR_ENABLED=True NAUTOBOT_LOG_LEVEL=DEBUG NAUTOBOT_METRICS_ENABLED=True NAUTOBOT_NAPALM_TIMEOUT=5 diff --git a/development/docker-compose.base.yml b/development/docker-compose.base.yml index 26356204..6a0a4c72 100644 --- a/development/docker-compose.base.yml +++ b/development/docker-compose.base.yml @@ -22,13 +22,13 @@ services: db: condition: "service_healthy" <<: - - *nautobot-build - *nautobot-base + - *nautobot-build worker: entrypoint: - "sh" - "-c" # this is to evaluate the $NAUTOBOT_LOG_LEVEL from the env - - "nautobot-server celery worker -l $$NAUTOBOT_LOG_LEVEL" ## $$ because of docker-compose + - "nautobot-server celery worker -l $$NAUTOBOT_LOG_LEVEL --events" ## $$ because of docker-compose depends_on: - "nautobot" healthcheck: diff --git a/development/docker-compose.dev.yml b/development/docker-compose.dev.yml index 5987d5fb..2fee99b9 100644 --- a/development/docker-compose.dev.yml +++ b/development/docker-compose.dev.yml @@ -12,6 +12,15 @@ services: volumes: - "./nautobot_config.py:/opt/nautobot/nautobot_config.py" - "../:/source" + # Helper method to mount on top of the python implementations, assuming you are using py3.11 and + # have all of your projects in the same directory. Uncomment out as required. + # - "../../netutils/netutils:/usr/local/lib/python3.11/site-packages/netutils" + # - "../../nornir-nautobot/nornir_nautobot:/usr/local/lib/python3.11/site-packages/nornir_nautobot" + # - "../../nautobot-plugin-nornir/nautobot_plugin_nornir:/usr/local/lib/python3.11/site-packages/nautobot_plugin_nornir" + # - "../../nautobot/nautobot:/usr/local/lib/python3.11/site-packages/nautobot" + + healthcheck: + test: ["CMD", "true"] # Due to layering, disable: true won't work. Instead, change the test docs: entrypoint: "mkdocs serve -v -a 0.0.0.0:8080" ports: @@ -23,9 +32,22 @@ services: disable: true tty: true worker: + entrypoint: + - "sh" + - "-c" # this is to evaluate the $NAUTOBOT_LOG_LEVEL from the env + - "watchmedo auto-restart --directory './' --pattern '*.py' --recursive -- nautobot-server celery worker -l $$NAUTOBOT_LOG_LEVEL --events" ## $$ because of docker-compose + # - "watchmedo auto-restart --directory './' --directory '/usr/local/lib/python3.11/site-packages/' --pattern '*.py' --recursive -- nautobot-server celery worker -l $$NAUTOBOT_LOG_LEVEL --events" ## $$ because of docker-compose volumes: - "./nautobot_config.py:/opt/nautobot/nautobot_config.py" - "../:/source" + # Helper method to mount on top of the python implementations, assuming you are using py3.11 and + # have all of your projects in the same directory. Uncomment out as required. + # - "../../netutils/netutils:/usr/local/lib/python3.11/site-packages/netutils" + # - "../../nornir-nautobot/nornir_nautobot:/usr/local/lib/python3.11/site-packages/nornir_nautobot" + # - "../../nautobot-plugin-nornir/nautobot_plugin_nornir:/usr/local/lib/python3.11/site-packages/nautobot_plugin_nornir" + # - "../../nautobot/nautobot:/usr/local/lib/python3.11/site-packages/nautobot" + healthcheck: + test: ["CMD", "true"] # Due to layering, disable: true won't work. Instead, change the test # To expose postgres or redis to the host uncomment the following # postgres: # ports: diff --git a/development/docker-compose.mysql.yml b/development/docker-compose.mysql.yml index c7fa6a1f..062ada94 100644 --- a/development/docker-compose.mysql.yml +++ b/development/docker-compose.mysql.yml @@ -20,6 +20,7 @@ services: image: "mysql:8" command: - "--default-authentication-plugin=mysql_native_password" + - "--max_connections=1000" env_file: - "development.env" - "creds.env" @@ -27,7 +28,12 @@ services: volumes: - "mysql_data:/var/lib/mysql" healthcheck: - test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] + test: + - "CMD" + - "mysqladmin" + - "ping" + - "-h" + - "localhost" timeout: "20s" retries: 10 volumes: diff --git a/development/docker-compose.postgres.yml b/development/docker-compose.postgres.yml index 55afdb70..12d1de31 100644 --- a/development/docker-compose.postgres.yml +++ b/development/docker-compose.postgres.yml @@ -7,11 +7,13 @@ services: - "NAUTOBOT_DB_ENGINE=django.db.backends.postgresql" db: image: "postgres:13-alpine" + command: + - "-c" + - "max_connections=200" env_file: - "development.env" - "creds.env" volumes: - # - "./nautobot.sql:/tmp/nautobot.sql" - "postgres_data:/var/lib/postgresql/data" healthcheck: test: "pg_isready --username=$$POSTGRES_USER --dbname=$$POSTGRES_DB" diff --git a/development/nautobot_config.py b/development/nautobot_config.py index 937052fb..bd962a65 100644 --- a/development/nautobot_config.py +++ b/development/nautobot_config.py @@ -1,11 +1,25 @@ """Nautobot development configuration file.""" -# pylint: disable=invalid-envvar-default import os import sys -from nautobot.core.settings import * # noqa: F403 +from nautobot.core.settings import * # noqa: F403 # pylint: disable=wildcard-import,unused-wildcard-import from nautobot.core.settings_funcs import is_truthy, parse_redis_connection +# +# Debug +# + +DEBUG = is_truthy(os.getenv("NAUTOBOT_DEBUG", False)) +_TESTING = len(sys.argv) > 1 and sys.argv[1] == "test" + +if DEBUG and not _TESTING: + DEBUG_TOOLBAR_CONFIG = {"SHOW_TOOLBAR_CALLBACK": lambda _request: True} + + if "debug_toolbar" not in INSTALLED_APPS: # noqa: F405 + INSTALLED_APPS.append("debug_toolbar") # noqa: F405 + if "debug_toolbar.middleware.DebugToolbarMiddleware" not in MIDDLEWARE: # noqa: F405 + MIDDLEWARE.insert(0, "debug_toolbar.middleware.DebugToolbarMiddleware") # noqa: F405 + # # Misc. settings # @@ -13,6 +27,9 @@ ALLOWED_HOSTS = os.getenv("NAUTOBOT_ALLOWED_HOSTS", "").split(" ") SECRET_KEY = os.getenv("NAUTOBOT_SECRET_KEY", "") +# +# Database +# nautobot_db_engine = os.getenv("NAUTOBOT_DB_ENGINE", "django.db.backends.postgresql") default_db_settings = { @@ -42,18 +59,28 @@ DATABASES["default"]["OPTIONS"] = {"charset": "utf8mb4"} # -# Debug +# Redis # -DEBUG = True +# The django-redis cache is used to establish concurrent locks using Redis. +CACHES = { + "default": { + "BACKEND": "django_redis.cache.RedisCache", + "LOCATION": parse_redis_connection(redis_database=0), + "TIMEOUT": 300, + "OPTIONS": { + "CLIENT_CLASS": "django_redis.client.DefaultClient", + }, + } +} -# Django Debug Toolbar -DEBUG_TOOLBAR_CONFIG = {"SHOW_TOOLBAR_CALLBACK": lambda _request: DEBUG and not TESTING} +# Redis Cacheops +CACHEOPS_REDIS = parse_redis_connection(redis_database=1) -if DEBUG and "debug_toolbar" not in INSTALLED_APPS: # noqa: F405 - INSTALLED_APPS.append("debug_toolbar") # noqa: F405 -if DEBUG and "debug_toolbar.middleware.DebugToolbarMiddleware" not in MIDDLEWARE: # noqa: F405 - MIDDLEWARE.insert(0, "debug_toolbar.middleware.DebugToolbarMiddleware") # noqa: F405 +# +# Celery settings are not defined here because they can be overloaded with +# environment variables. By default they use `CACHES["default"]["LOCATION"]`. +# # # Logging @@ -61,10 +88,8 @@ LOG_LEVEL = "DEBUG" if DEBUG else "INFO" -TESTING = len(sys.argv) > 1 and sys.argv[1] == "test" - # Verbose logging during normal development operation, but quiet logging during unit test execution -if not TESTING: +if not _TESTING: LOGGING = { "version": 1, "disable_existing_loggers": False, @@ -98,40 +123,10 @@ }, }, } -else: - LOGGING = {} # -# Redis -# - -# The django-redis cache is used to establish concurrent locks using Redis. The -# django-rq settings will use the same instance/database by default. +# Apps # -# This "default" server is now used by RQ_QUEUES. -# >> See: nautobot.core.settings.RQ_QUEUES -CACHES = { - "default": { - "BACKEND": "django_redis.cache.RedisCache", - "LOCATION": parse_redis_connection(redis_database=0), - "TIMEOUT": 300, - "OPTIONS": { - "CLIENT_CLASS": "django_redis.client.DefaultClient", - }, - } -} - -# RQ_QUEUES is not set here because it just uses the default that gets imported -# up top via `from nautobot.core.settings import *`. - -# Redis Cacheops -CACHEOPS_REDIS = parse_redis_connection(redis_database=1) - -# -# Celery settings are not defined here because they can be overloaded with -# environment variables. By default they use `CACHES["default"]["LOCATION"]`. -# - # Enable installed plugins. Add the name of each plugin to the list. PLUGINS = ["nautobot_plugin_nornir", "nautobot_golden_config"] @@ -149,17 +144,6 @@ }, }, }, - # dispatcher_mapping may be necessary if you get an error `Cannot import "". Is the library installed?` - # when you run a backup job, and is the name of the platform applied to the device. - # to the Nornir driver names ("arista_eos", "cisco_ios", etc.). - # "dispatcher_mapping": { - # "eos": "nornir_nautobot.plugins.tasks.dispatcher.arista_eos.NautobotNornirDriver", - # "arbitrary_platform_name": "nornir_nautobot.plugins.tasks.dispatcher.arista_eos.NautobotNornirDriver", - # "ios": "nornir_nautobot.plugins.tasks.dispatcher.cisco_ios.NautobotNornirDriver", - # "iosxe": "nornir_nautobot.plugins.tasks.dispatcher.cisco_ios.NautobotNornirDriver", - # "junos": "nornir_nautobot.plugins.tasks.dispatcher.juniper_junos.NautobotNornirDriver", - # "nxos": "nornir_nautobot.plugins.tasks.dispatcher.cisco_nxos.NautobotNornirDriver", - # }, }, "nautobot_golden_config": { "per_feature_bar_width": float(os.environ.get("PER_FEATURE_BAR_WIDTH", 0.15)), @@ -180,21 +164,21 @@ "trim_blocks": is_truthy(os.getenv("NAUTOBOT_JINJA_ENV_TRIM_BLOCKS", True)), "lstrip_blocks": is_truthy(os.getenv("NAUTOBOT_JINJA_ENV_LSTRIP_BLOCKS", False)), }, - # The platform_slug_map maps an arbitrary platform slug to its corresponding parser. - # Use this if the platform slug names in your Nautobot instance don't correspond exactly - # to the Nornir driver names ("arista_eos", "cisco_ios", etc.). - # Each key should == the slug of the Nautobot platform object. - # "platform_slug_map": { - # "eos": "arista_eos", - # "ios": "cisco_ios", - # "iosxe": "cisco_ios", - # "junos": "juniper_junos", - # "nxos": "cisco_nxos", - # }, # "get_custom_compliance": "my.custom_compliance.func", + # "default_deploy_status": "Not Approved", + # + # + # custom_dispatcher is not required for preferring a framework such as netmiko or napalm. + # Instead, this is only required if you are truly "rolling your own" dispatcher, potentially + # to accommodate OS's not currently supported or to add your own business logic. + # "custom_dispatcher": { + # "arista_eos": "my_custom.dispatcher.NornirDriver", + # "arbitrary_platform_name": "my_custom.dispatcher.OtherNornirDriver", + # }, }, } +# TODO:Verify this is still needed # Modify django_jinja Environment for test cases django_jinja_config = None for template in TEMPLATES: # noqa: F405 diff --git a/docs/admin/admin_install.md b/docs/admin/admin_install.md index 3b2205d6..df2653d7 100644 --- a/docs/admin/admin_install.md +++ b/docs/admin/admin_install.md @@ -60,12 +60,12 @@ PLUGINS_CONFIG = { "sot_agg_transposer": None, "postprocessing_callables": [], "postprocessing_subscribed": [], - "platform_slug_map": None, "jinja_env": { "undefined": "jinja2.StrictUndefined", "trim_blocks": True, "lstrip_blocks": False, }, + # "default_deploy_status": "Not Approved", # "get_custom_compliance": "my.custom_compliance.func" }, } @@ -100,9 +100,10 @@ The plugin behavior can be controlled with the following list of settings. | enable_compliance | True | True | A boolean to represent whether or not to run the compliance process within the plugin. | | enable_intended | True | True | A boolean to represent whether or not to generate intended configurations within the plugin. | | enable_sotagg | True | True | A boolean to represent whether or not to provide a GraphQL query per device to allow the intended configuration to provide data variables to the plugin. | -| enable_plan | True | True | A boolean to represent whether or not to allow the config plan job to run. | -| enable_deploy | True | True | A boolean to represent whether or not to be able to deploy configs to network devices. | +| enable_plan | True | True | A boolean to represent whether or not to allow the config plan job to run. | +| enable_deploy | True | True | A boolean to represent whether or not to be able to deploy configs to network devices. | | enable_postprocessing | True | False | A boolean to represent whether or not to generate intended configurations to push, with extra processing such as secrets rendering. | +| default_deploy_status | "Not Approved" | "Not Approved" | A string that will be the name of the status you want as the default when create new config plans, you MUST create the status yourself before starting the app. | | postprocessing_callables | ['mypackage.myfunction'] | [] | A list of function paths, in dotted format, that are appended to the available methods for post-processing the intended configuration, for instance, the `render_secrets`. | | postprocessing_subscribed | ['mypackage.myfunction'] | [] | A list of function paths, that should exist as postprocessing_callables, that defines the order of application of during the post-processing process. | | platform_slug_map | {"cisco_wlc": "cisco_aireos"} | None | A dictionary in which the key is the platform slug and the value is what netutils uses in any "network_os" parameter within `netutils.config.compliance.parser_map`. | @@ -128,3 +129,28 @@ The plugin behavior can be controlled with the following list of settings. "lstrip_blocks": False, } ``` + +## Custom Dispatcher + +Please note, that this should only be used in rare circumstances not covered in the previous constance settings, when you are truly "rolling your own" dispatcher. Previously, the `dispatcher_mapping` covered use cases that are now more easily handled. The only two use cases that should be required are. + +- Provide support for network drivers not currently supported. +- Provide some custom business logic you need. + +That being said, if you do fall into one of those use cases, you can set the dispatcher as followed: + +```python +PLUGINS_CONFIG = { + "nautobot_plugin_nornir": { + }, + "nautobot_golden_config": { + "custom_dispatcher": { + "arista_eos": "my_custom.dispatcher.NornirDriver", + "arbitrary_platform_name": "my_custom.dispatcher.OtherNornirDriver", + }, + + }, +} +``` + +The format for defining these methods is via the dotted string format that will be imported by Django. For example, the Netmiko Cisco IOS dispatcher is defined as `nornir_nautobot.plugins.tasks.dispatcher.cisco_ios.NetmikoCiscoIos`. You also must hand any installation of the packaging and assurance that the value you provide is importable in the environment you run it on. \ No newline at end of file diff --git a/docs/admin/compatibility_matrix.md b/docs/admin/compatibility_matrix.md index 2063d9fc..8a3e2e55 100644 --- a/docs/admin/compatibility_matrix.md +++ b/docs/admin/compatibility_matrix.md @@ -2,7 +2,7 @@ Changes to the support of upstream Nautobot releases will be announced 1 minor or major version ahead. -The **deprecation policy** will be announced within the [release notes](../release_notes), and updated in the table below. There will be a `stable-.` branch that will be minimally maintained. Any security enhancements or major bugs in that branch will be supported for a limited time. +The **deprecation policy** will be announced within the [release notes](./release_notes/index.md), and updated in the table below. There will be a `stable-.` branch that will be minimally maintained. Any security enhancements or major bugs in that branch will be supported for a limited time. While that last supported version will not be strictly enforced via the `max_version` setting, any issues with an updated Nautobot supported version in a minor release will require raising a bug and fixing it in Nautobot core, with no fixes expected in this plugin. This allows the Golden Config plugin the ability to quickly take advantage of the latest features in Nautobot. @@ -17,3 +17,4 @@ While that last supported version will not be strictly enforced via the `max_ver | 1.4.X | 1.5.3 | 1.5.99 [Official] | | 1.5.X | 1.6.1 | 1.6.99 [Official] | | 1.6.X | 1.6.1 | 1.6.99 [Official] | +| 2.0.x | 2.0.0 | TBD | diff --git a/docs/admin/migrating_to_v2.md b/docs/admin/migrating_to_v2.md new file mode 100644 index 00000000..5aa4baaa --- /dev/null +++ b/docs/admin/migrating_to_v2.md @@ -0,0 +1,202 @@ +# Migrating to v2 + +While not a replacement of the [Nautobot Migration guide](https://docs.nautobot.com/projects/core/en/stable/development/apps/migration/from-v1/) these migration steps specifically for Golden Config are pretty straight forward, here is a quick overview with details information below. + +1. Ensure `Platform.network_driver` is set on every `Platform` object you have, in most circumstances running `nautobot-server populate_platform_network_driver` will take care of it. +2. Remove any reference to `slug` as well as to the models `Region`, `Site`, `DeviceRole`, or `RackRole` in your **Dynamic Group** definition, in most circumstances running `nautobot-server audit_dynamic_groups` will guide you to what needs to change. +3. Remove any reference to `slug` (or change to network_driver) as well as to the models `Region`, `Site`, `DeviceRole`, or `RackRole` in your **GraphQL** definition and reflect those changes in your Jinja files. +4. Remove any reference to `slug` as well as to the models `Region`, `Site`, `DeviceRole`, or `RackRole` in your **Golden Config Setting** definition in all of `Backup Path`, `Intended Path`, and `Template Path`. +5. Remove any `dispatcher_mapping` settings you have in your `nautobot_config.py` settings, see Golden Config for alternative options. +6. Update your Git Repositories to use Nautobot Secrets. + +!!! warning + Before you start, please note the `nautobot-server populate_platform_network_driver` command **must be ran in Nautobot 1.6.2 -> 1.6.X** as it will not work once on Nautobot 2.0. + +These steps may range from no change (though unlikely) to large amount of change with your environment in order to successfully upgrade Golden Config. To help guide you, there is a detailed explanation and question to ask yourself if these changes will effect you or not. + +**Providing Context** + +There are 3 primary pieces of information that will effect most of the changes that will need to be made, here is a recap of them. + +- In Nautobot 2.0.0, all the `Region` and `Site` related data models are being migrated to use `Location`. +- The `ipam.Role`, `dcim.RackRole`, and `dcim.DeviceRole` models have been removed and replaced by a single `extras.Role` model. This means that any references to the removed models in the code now use the `extras.Role` model instead. +- Slugs were used to identify unique objects in the database for various models in Nautobot v1.x and they are now replaced by Natural Keys or can often get the same effect adding the `|slugify` filter to your data. + +## Platform Network Driver + +!!! tip + You can safely skip this section if you already have your `Platform.network_driver` set and were not using either `platform_slug_map` nor `dispatcher_mapping` settings. + +The `Platform.slug` has been replace by Nautobot's `Platform.network_driver`. The nice thing about this feature is it provides mappings to all of the major network library (or frameworks) such as Netmiko and NAPALM to properly map between the slightly different names each library provides, such as `cisco_ios` vs `ios`. However, that means that you must now provide the network_driver on the the Platform object. + +While still on the a Nautobot 1.6 instance, run the command `nautobot-server populate_platform_network_driver`, this will help map all of your `Platform.slug`'s to `Platform.network_driver`. If there are any Platform's missed, you must update the Platform definitions that will be used by Golden Config. + +If previously you have leveraged the `platform_slug_map` you likely only have to assign the `network_driver` to your multiple current platforms. In the unlikely chance that you have a requirement to override the default network_driver_mappings, you can do so with the [NETWORK_DRIVERS](https://docs.nautobot.com/projects/core/en/stable/user-guide/administration/configuration/optional-settings/?h=network_driver#network_drivers) settings via UI with the [constance settings](../user/app_getting_started.md#constance-settings). + +If previously you have leveraged the `dispatcher_mapping` to use your preferred network library or framework such as Netmiko or NAPALM, you can how use the [constance settings](../user/app_getting_started.md#constance-settings) via the UI. + +!!! info + If you were using the `dispatcher_mapping` for other reasons, see the section below for Custom Dispatcher. + +## Dynamic Group + +!!! tip + You can safely skip this section if your Dynamic Groups did not use slugs or one of the removed models or you Dynamic Groups are currently in the required state. + +In an effort to guide you along, you are highly encouraged to leverage the `nautobot-server audit_dynamic_groups` as [documented](https://docs.nautobot.com/projects/core/en/v2.0.0/user-guide/administration/tools/nautobot-server/#audit_dynamic_groups). You will know you have completed this step, when the scope of devices in your Dynamic Group match your expectations. + +## GraphQL + +!!! tip + You can safely skip this section if your GraphQL did not use slugs or one of the removed models or your saved GraphQL currently renders to the appropriate state. + +As mentioned, any reference to slug or to one of the removed models will need to be updated to reflect Nautobot 2.0 standards, in this example we will review what would need to change. + +``` +query ($device_id: ID!) { + device(id: $device_id) { + hostname: name + tenant { + name + slug <----- Remove slug + } + tags { + name + slug <----- Remove slug + } + device_role { <----- Change to role vs device_role + name + } + platform { + name + slug <----- change to network_driver and potentially add network_driver_mappings + } + site { + name + slug <----- Remove slug + } + } +} +``` + +The new query would end up being: + +``` +query ($device_id: ID!) { + device(id: $device_id) { + hostname: name + tenant { + name + } + tags { + name + } + role { + name + } + platform { + name + network_driver + } + site { + name + slug + } + } +} +``` + +Additionally, your Jinja 2 templates will need to be updated to reflect the new updates to the data. Fortunately, if you have accepted the default that `SlugField` returns, this may be as simple as adding as the `| slugify` Jinja filter to the name equivalent. Let's take a quick look at a few examples of Jinja file change you may need to make: + +_Using slugify_ + +```jinja +snmp-server location {{ site.slug }} <---- old way of doing it +snmp-server location {{ site.name | slugify }} <---- new way of doing it +``` +_Update model_ + +```jinja +{% if device_role.name == 'spine' %} <---- old way of doing it +{% if role.name == 'spine' %} <---- new way of doing it +``` + +_Use network_driver_ + +```jinja +{% if platform.slug == 'cisco_ios' %} <---- old way of doing it +{% if platform.network_driver == 'cisco_ios' %} <---- new way of doing it +``` + +## Golden Config Settings + +!!! tip + You can safely skip this section if you are not using slug or one of the Models in your `Backup Path`, `Intended Path`, and `Template Path` settings. + +Similar to the the jinja examples above, you must ensure that the slug and legacy models are not referenced, using the previous recommendations and comparing to the current recommendations we can see how to make these changes. + +_Path for backup and intended_ + +```jinja +{{obj.site.slug}}/{{obj.name}} <---- old way of doing it +{{obj.location.name|slugify}}/{{obj.name}} <---- new way of doing it +``` + +_Path for templates_ + +```jinja +{{obj.platform.slug}}.j2 +{{obj.platform.network_driver}}.j2 <---- old way of doing it +{{obj.location.name|slugify}}/{{obj.name}} <---- new way of doing it +``` + +## Custom Dispatcher + +!!! tip + You can safely skip this section if you have not been using `dispatcher_mapping` settings. + +If you have previously used the `dispatcher_mapping` settings to prefer the framework (such as netmiko or napalm), please see the Platform Network Driver section above. If you were truly "rolling your own dispatcher", then it is simply a matter of updating your settings. + +The `custom_dispatcher` settings are Golden Config settings (and **NOT** Nautobot Plugin Nornir settings), and the key name is `custom_dispatcher`. For your protection, the application will not start if you have either `dispatcher_mapping` or `custom_dispatcher` in Nautobot Plugin Nornir. + +Previous relevant Settings: + +```python +PLUGINS_CONFIG = { + "nautobot_plugin_nornir": { + "dispatcher_mapping": { + "arista_eos": "my_custom.dispatcher.NornirDriver", + "arbitrary_platform_name": "my_custom.dispatcher.OtherNornirDriver", + }, + }, + "nautobot_golden_config": { + }, +} +``` + +Current relevant Settings: + +```python +PLUGINS_CONFIG = { + "nautobot_plugin_nornir": { + }, + "nautobot_golden_config": { + "custom_dispatcher": { # <---- Nested under nautobot_golden_config + "arista_eos": "my_custom.dispatcher.NornirDriver", + "arbitrary_platform_name": "my_custom.dispatcher.OtherNornirDriver", + }, + + }, +} +``` + +You can also see information within the [custom dispatcher docs](../admin/admin_install.md#custom-dispatcher). + +## Secrets + +!!! tip + You can safely skip this section if you have already been using Nautobot Secrets vs Git Repository Token. + +Nautobot initially had the ability to store some secrets, this was deprecated when [Secrets framework](https://docs.nautobot.com/projects/core/en/stable/user-guide/platform-functionality/secret/) was added in Nautobot 1.2. The feature to directly store Secrets in the database has been removed in 2.0. + +The documentation has been updated in docs covering [secret groups](../user/app_use_cases.md#create-secret-groups). \ No newline at end of file diff --git a/docs/admin/release_notes/version_1.4.md b/docs/admin/release_notes/version_1.4.md index 06251351..d03fc888 100755 --- a/docs/admin/release_notes/version_1.4.md +++ b/docs/admin/release_notes/version_1.4.md @@ -6,55 +6,55 @@ ### Changed -- [519](https://github.com/nautobot/nautobot-plugin-golden-config/pull/519) - docs-only: large fixes and template troubleshooting section. +- [#519](https://github.com/nautobot/nautobot-plugin-golden-config/pull/519) - docs-only: large fixes and template troubleshooting section. ### Fixed -- [492](https://github.com/nautobot/nautobot-plugin-golden-config/pull/492) - Fix count of in scope devices on settings detail view. -- [498](https://github.com/nautobot/nautobot-plugin-golden-config/pull/498) - Fix deepdiff dependency. -- [501](https://github.com/nautobot/nautobot-plugin-golden-config/pull/501) - Update docs for adding CustomField data with datasources. -- [503](https://github.com/nautobot/nautobot-plugin-golden-config/pull/503) - Switch from deprecated FilterSet to new FilterSetMixin. -- [504](https://github.com/nautobot/nautobot-plugin-golden-config/pull/504) - Fix extend queryfilter to export. -- [511](https://github.com/nautobot/nautobot-plugin-golden-config/pull/511) - Fix `log_failure` function missing argument. -- [523](https://github.com/nautobot/nautobot-plugin-golden-config/pull/523) - Fix docs site by pinning dev dependencies. -- [530](https://github.com/nautobot/nautobot-plugin-golden-config/pull/530) - Fix, removing ConfigCompliance model import from 0005 migration. +- [#492](https://github.com/nautobot/nautobot-plugin-golden-config/pull/492) - Fix count of in scope devices on settings detail view. +- [#498](https://github.com/nautobot/nautobot-plugin-golden-config/pull/498) - Fix deepdiff dependency. +- [#501](https://github.com/nautobot/nautobot-plugin-golden-config/pull/501) - Update docs for adding CustomField data with datasources. +- [#503](https://github.com/nautobot/nautobot-plugin-golden-config/pull/503) - Switch from deprecated FilterSet to new FilterSetMixin. +- [#504](https://github.com/nautobot/nautobot-plugin-golden-config/pull/504) - Fix extend queryfilter to export. +- [#511](https://github.com/nautobot/nautobot-plugin-golden-config/pull/511) - Fix `log_failure` function missing argument. +- [#523](https://github.com/nautobot/nautobot-plugin-golden-config/pull/523) - Fix docs site by pinning dev dependencies. +- [#530](https://github.com/nautobot/nautobot-plugin-golden-config/pull/530) - Fix, removing ConfigCompliance model import from 0005 migration. ## v1.4.1 - 2023-05 ### Fixed -- [488](https://github.com/nautobot/nautobot-plugin-golden-config/pull/488) - Fix Golden Config Settings Buttons. +- [#488](https://github.com/nautobot/nautobot-plugin-golden-config/pull/488) - Fix Golden Config Settings Buttons. ## v1.4.0 - 2023-05 ### Added -- [445](https://github.com/nautobot/nautobot-plugin-golden-config/pull/445) - Add validation for Settings sot_agg_query. -- [449](https://github.com/nautobot/nautobot-plugin-golden-config/pull/449) - Allows for custom kwargs to `get_secret_by_secret_group_slug`. -- [470](https://github.com/nautobot/nautobot-plugin-golden-config/pull/470) - Enhance UI settings detail object view. -- [473](https://github.com/nautobot/nautobot-plugin-golden-config/pull/473) - Add status selection field to job filtering. -- [480](https://github.com/nautobot/nautobot-plugin-golden-config/pull/480) - Add compliance summary to default tenant view. +- [#445](https://github.com/nautobot/nautobot-plugin-golden-config/pull/445) - Add validation for Settings sot_agg_query. +- [#449](https://github.com/nautobot/nautobot-plugin-golden-config/pull/449) - Allows for custom kwargs to `get_secret_by_secret_group_slug`. +- [#470](https://github.com/nautobot/nautobot-plugin-golden-config/pull/470) - Enhance UI settings detail object view. +- [#473](https://github.com/nautobot/nautobot-plugin-golden-config/pull/473) - Add status selection field to job filtering. +- [#480](https://github.com/nautobot/nautobot-plugin-golden-config/pull/480) - Add compliance summary to default tenant view. ### Changed -- [414](https://github.com/nautobot/nautobot-plugin-golden-config/pull/414) - Update application description for UI. -- [407](https://github.com/nautobot/nautobot-plugin-golden-config/pull/407) - Update branching policy in contributing docs. -- [417](https://github.com/nautobot/nautobot-plugin-golden-config/pull/417) - Changed extends base.html to extends generic/object_detail.html. -- [434](https://github.com/nautobot/nautobot-plugin-golden-config/pull/434) - Upgrade deepdiff dependency to 6.2.0. -- [451](https://github.com/nautobot/nautobot-plugin-golden-config/pull/451) - Tune Dependabot. -- [459](https://github.com/nautobot/nautobot-plugin-golden-config/pull/459) - Update tasks.py to meet current standards. -- [464](https://github.com/nautobot/nautobot-plugin-golden-config/pull/464) - Update ordering on compliance views. -- [471](https://github.com/nautobot/nautobot-plugin-golden-config/pull/471) - Migrate to using NautobotUIViewset and other initial 2.x prep work. -- [481](https://github.com/nautobot/nautobot-plugin-golden-config/pull/481) - Update filtersets for rack-group to extend proper TreeNode parent. +- [#414](https://github.com/nautobot/nautobot-plugin-golden-config/pull/414) - Update application description for UI. +- [#407](https://github.com/nautobot/nautobot-plugin-golden-config/pull/407) - Update branching policy in contributing docs. +- [#417](https://github.com/nautobot/nautobot-plugin-golden-config/pull/417) - Changed extends base.html to extends generic/object_detail.html. +- [#434](https://github.com/nautobot/nautobot-plugin-golden-config/pull/434) - Upgrade deepdiff dependency to 6.2.0. +- [#451](https://github.com/nautobot/nautobot-plugin-golden-config/pull/451) - Tune Dependabot. +- [#459](https://github.com/nautobot/nautobot-plugin-golden-config/pull/459) - Update tasks.py to meet current standards. +- [#464](https://github.com/nautobot/nautobot-plugin-golden-config/pull/464) - Update ordering on compliance views. +- [#471](https://github.com/nautobot/nautobot-plugin-golden-config/pull/471) - Migrate to using NautobotUIViewset and other initial 2.x prep work. +- [#481](https://github.com/nautobot/nautobot-plugin-golden-config/pull/481) - Update filtersets for rack-group to extend proper TreeNode parent. ### Fixed -- [436](https://github.com/nautobot/nautobot-plugin-golden-config/pull/436) - Update FAQ for how compliance works. -- [444](https://github.com/nautobot/nautobot-plugin-golden-config/pull/444) - `app_faq.md` references incorrect `Cisco IOS XR` platform slug. -- [446](https://github.com/nautobot/nautobot-plugin-golden-config/pull/446) - Fix mysql not working in github actions. -- [450](https://github.com/nautobot/nautobot-plugin-golden-config/pull/450) - Make ConfigReplace export match import. -- [456](https://github.com/nautobot/nautobot-plugin-golden-config/pull/456) - Fix postprocessing to use Sandbox Jinja2 environment. -- [461](https://github.com/nautobot/nautobot-plugin-golden-config/pull/461) - Moves dependabot config to proper location. -- [463](https://github.com/nautobot/nautobot-plugin-golden-config/pull/463) - Fix Json render in compliance reporting template. -- [468](https://github.com/nautobot/nautobot-plugin-golden-config/pull/468) - Fix GoldenConfig list view and csv export. -- [474](https://github.com/nautobot/nautobot-plugin-golden-config/pull/474) - Docs update: Fix multiple typos. +- [#436](https://github.com/nautobot/nautobot-plugin-golden-config/pull/436) - Update FAQ for how compliance works. +- [#444](https://github.com/nautobot/nautobot-plugin-golden-config/pull/444) - `app_faq.md` references incorrect `Cisco IOS XR` platform slug. +- [#446](https://github.com/nautobot/nautobot-plugin-golden-config/pull/446) - Fix mysql not working in github actions. +- [#450](https://github.com/nautobot/nautobot-plugin-golden-config/pull/450) - Make ConfigReplace export match import. +- [#456](https://github.com/nautobot/nautobot-plugin-golden-config/pull/456) - Fix postprocessing to use Sandbox Jinja2 environment. +- [#461](https://github.com/nautobot/nautobot-plugin-golden-config/pull/461) - Moves dependabot config to proper location. +- [#463](https://github.com/nautobot/nautobot-plugin-golden-config/pull/463) - Fix Json render in compliance reporting template. +- [#468](https://github.com/nautobot/nautobot-plugin-golden-config/pull/468) - Fix GoldenConfig list view and csv export. +- [#474](https://github.com/nautobot/nautobot-plugin-golden-config/pull/474) - Docs update: Fix multiple typos. diff --git a/docs/admin/release_notes/version_1.5.md b/docs/admin/release_notes/version_1.5.md index 7d4be037..46e0d40f 100755 --- a/docs/admin/release_notes/version_1.5.md +++ b/docs/admin/release_notes/version_1.5.md @@ -11,17 +11,17 @@ ### Added -- [455](https://github.com/nautobot/nautobot-plugin-golden-config/pull/455) - Add metrics for Golden Config plugin. -- [485](https://github.com/nautobot/nautobot-plugin-golden-config/pull/485) - Custom compliance for CLI and JSON rules. -- [487](https://github.com/nautobot/nautobot-plugin-golden-config/pull/487) - Implement native JSON support. -- [527](https://github.com/nautobot/nautobot-plugin-golden-config/pull/527) - Add the ability to update Jinja environment setting from nautobot_config. -- [558](https://github.com/nautobot/nautobot-plugin-golden-config/pull/558) - Updated Filters for various models, including adding an experimental `_isnull` on DateTime objects. +- [#455](https://github.com/nautobot/nautobot-plugin-golden-config/pull/455) - Add metrics for Golden Config plugin. +- [#485](https://github.com/nautobot/nautobot-plugin-golden-config/pull/485) - Custom compliance for CLI and JSON rules. +- [#487](https://github.com/nautobot/nautobot-plugin-golden-config/pull/487) - Implement native JSON support. +- [#527](https://github.com/nautobot/nautobot-plugin-golden-config/pull/527) - Add the ability to update Jinja environment setting from nautobot_config. +- [#558](https://github.com/nautobot/nautobot-plugin-golden-config/pull/558) - Updated Filters for various models, including adding an experimental `_isnull` on DateTime objects. ### Changed -- [485](https://github.com/nautobot/nautobot-plugin-golden-config/pull/485) - Changed the behavior of custom compliance to a boolean vs toggle between cli, json, and custom. +- [#485](https://github.com/nautobot/nautobot-plugin-golden-config/pull/485) - Changed the behavior of custom compliance to a boolean vs toggle between cli, json, and custom. ### Fixed -- [505](https://github.com/nautobot/nautobot-plugin-golden-config/pull/505) - fixes imports and choice definitions in the compliance nornir play. -- [513](https://github.com/nautobot/nautobot-plugin-golden-config/pull/513) - Fixed issue with native JSON support with `get_config_element` function. +- [#505](https://github.com/nautobot/nautobot-plugin-golden-config/pull/505) - fixes imports and choice definitions in the compliance nornir play. +- [#513](https://github.com/nautobot/nautobot-plugin-golden-config/pull/513) - Fixed issue with native JSON support with `get_config_element` function. diff --git a/docs/admin/release_notes/version_2.0.md b/docs/admin/release_notes/version_2.0.md new file mode 100755 index 00000000..b3f2da3d --- /dev/null +++ b/docs/admin/release_notes/version_2.0.md @@ -0,0 +1,49 @@ +# v2.0 Release Notes + +- Updated `nautobot` to `2.0.0` and made associated changes. +- Integrated all relevant sections with `Platform.network_driver`. +- Added a standard way to provide error codes. +- Changed Config Compliance view to be based on model, not dynamic group and provide a `message` when they have drifted. +- Added constance settings (`DEFAULT_FRAMEWORK`, `GET_CONFIG_FRAMEWORK`, `MERGE_CONFIG_FRAMEWORK`, and `REPLACE_CONFIG_FRAMEWORK`) and customer_dispatcher to remove dispatcher_mapping. +- Moved config compliance view to be a tab within device instead of a dedicated page. +- Removed management command in favor of Nautobot Core's. + +!!! note + Please see [migrating guide](../migrating_to_v2.md) for details on migration. + +## v2.0.0 - 2023-09 + +### Changed + +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Updated `nautobot` to `2.0.0` and made associated changes. +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Changed dispatcher_mapping to custom_dispatcher and constance settings. +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Changed Config Compliance view to be based on model, not dynamic group and provide a `message` when they have drifted. +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Changed the location of the config compliance view to be a tab on device objects. +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Changed the linking on Configuration Overview to point to the detailed object to align with Nautobot standards. +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Inverted Config Plan logic to not show Completed Config Plans by default and have a button to see them. +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Change logic to always include jobs, regardless of which features are in use. +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Changed several of the URL locations of views, based on migration to viewsets and overall simplification of code. +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Changed models to better reflect actual state, such as not to allow nullable on characters and one-to-one from config compliance to device model. +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Changed any date/time reference to be django's `make_aware`. +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Changed Nornir Processor logic on failures to be recursive lookups. +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Updated diff2html to 3.4.43. +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Changed booleans to be consistent with Nautobot UI. +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Pinned django-pivot to 1.8.1 as that returns a queryset. +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Various cleanup updates such as moving to viewsets, hyperlinked_text, moving matplot code, using Nautobot provided Git capabilities, updating development environment to NTC standards, etc. + +### Added + +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Introduced constance settings for DEFAULT_FRAMEWORK, GET_CONFIG_FRAMEWORK, MERGE_CONFIG_FRAMEWORK, and REPLACE_CONFIG_FRAMEWORK. +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Added error code framework. +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Added a setting for default_deploy_status to allow that to be configurable. +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Added a job to sync dynamic group and config compliance model. +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Added a custom logger capability to be able to handle stdout as well as nautobot job logs. +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Added copy buttons in several locations to allow for getting configurations easier. +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Added datasources yaml key to use network_driver but still backwards compatible to _slug. + +### Removed + +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Remove the already deprecated "Scope" in favor of dynamic groups. +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Removed references to git repository tokens. +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Removed management command to run jobs in favor of Nautobot Core's usage. +- [#575](https://github.com/nautobot/nautobot-plugin-golden-config/pull/575) - Removed platform_slug_map in favor of constance settings. \ No newline at end of file diff --git a/docs/admin/troubleshooting/E3001.md b/docs/admin/troubleshooting/E3001.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3001.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3002.md b/docs/admin/troubleshooting/E3002.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3002.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3003.md b/docs/admin/troubleshooting/E3003.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3003.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3004.md b/docs/admin/troubleshooting/E3004.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3004.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3005.md b/docs/admin/troubleshooting/E3005.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3005.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3006.md b/docs/admin/troubleshooting/E3006.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3006.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3007.md b/docs/admin/troubleshooting/E3007.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3007.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3008.md b/docs/admin/troubleshooting/E3008.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3008.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3009.md b/docs/admin/troubleshooting/E3009.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3009.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3010.md b/docs/admin/troubleshooting/E3010.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3010.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3011.md b/docs/admin/troubleshooting/E3011.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3011.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3012.md b/docs/admin/troubleshooting/E3012.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3012.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3013.md b/docs/admin/troubleshooting/E3013.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3013.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3014.md b/docs/admin/troubleshooting/E3014.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3014.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3015.md b/docs/admin/troubleshooting/E3015.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3015.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3016.md b/docs/admin/troubleshooting/E3016.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3016.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3017.md b/docs/admin/troubleshooting/E3017.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3017.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3018.md b/docs/admin/troubleshooting/E3018.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3018.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3019.md b/docs/admin/troubleshooting/E3019.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3019.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3020.md b/docs/admin/troubleshooting/E3020.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3020.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3021.md b/docs/admin/troubleshooting/E3021.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3021.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3022.md b/docs/admin/troubleshooting/E3022.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3022.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3023.md b/docs/admin/troubleshooting/E3023.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3023.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3024.md b/docs/admin/troubleshooting/E3024.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3024.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3025.md b/docs/admin/troubleshooting/E3025.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3025.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/E3026.md b/docs/admin/troubleshooting/E3026.md new file mode 100644 index 00000000..985793eb --- /dev/null +++ b/docs/admin/troubleshooting/E3026.md @@ -0,0 +1,19 @@ +# E30XX Details + +## Message emitted: + +`E30XX: Details coming soon` + +## Description: + +Description that is coming soon. + +## Troubleshooting: + +Troubleshooting that is coming soon. + +## Recommendation: + +Recommendation that is coming soon. + + diff --git a/docs/admin/troubleshooting/index.md b/docs/admin/troubleshooting/index.md new file mode 100644 index 00000000..6a5d8382 --- /dev/null +++ b/docs/admin/troubleshooting/index.md @@ -0,0 +1,13 @@ +# Troubleshooting Overview + +In an effort to help with troubleshooting, each expected error, will now emit an error ID, in the format of `E3XXX`, such as `E3003: There is currently no CLI-config parser support for platform network_driver `{obj.platform.network_driver}`, preemptively failed.`. The idea will be to define the error, the error message and some recommended troubleshooting steps or even potentially some fixes. + +This is an ongoing effort, but the foundation has been built. + +Within the Nautobot ecosystem, you may see various errors, they are distributed between 3 libraries as followed. + +| Error Range | Plugin Docs | +| ----------- | ----------- | +| E1001-E1999 | [Nornir Nautobot](https://docs.nautobot.com/projects/nornir-nautobot/en/latest/task/troubleshooting/) | +| E2001-E2999 | [Nautobot Plugin Nornir](https://docs.nautobot.com/projects/plugin-nornir/en/latest/admin/troubleshooting/) | +| E3001-E3999 | [Nautobot Golden Config](https://docs.nautobot.com/projects/golden-config/en/latest/admin/troubleshooting/) | \ No newline at end of file diff --git a/docs/dev/dev_adr.md b/docs/dev/dev_adr.md index a8591a0b..1d08962f 100644 --- a/docs/dev/dev_adr.md +++ b/docs/dev/dev_adr.md @@ -88,7 +88,7 @@ There is a function mapper for the diff logic. This allows for the diff logic to ## Dynamic Group -There was originally a `scope` associated with the project, this was changed to a Dynamic Group to make use of the features within Core. There is backwards compatibility for the time being. +There was originally a `scope` associated with the project, this was changed to a Dynamic Group to make use of the features within Core. There is backwards compatibility until version 2.0.0. ## Management Commands diff --git a/docs/dev/dev_environment.md b/docs/dev/dev_environment.md index e2c8a06a..f5ce31a8 100644 --- a/docs/dev/dev_environment.md +++ b/docs/dev/dev_environment.md @@ -15,7 +15,7 @@ The [Invoke](http://www.pyinvoke.org/) library is used to provide some helper co - `nautobot_ver`: the version of Nautobot to use as a base for any built docker containers (default: latest) - `project_name`: the default docker compose project name (default: `nautobot_golden_config`) -- `python_ver`: the version of Python to use as a base for any built docker containers (default: 3.8) +- `python_ver`: the version of Python to use as a base for any built docker containers (default: 3.11) - `local`: a boolean flag indicating if invoke tasks should be run on the host or inside the docker containers (default: False, commands will be run in docker containers) - `compose_dir`: the full path to a directory containing the project compose files - `compose_files`: a list of compose files applied in order (see [Multiple Compose files](https://docs.docker.com/compose/extends/#multiple-compose-files) for more information) @@ -187,7 +187,7 @@ The first thing you need to do is build the necessary Docker image for Nautobot #14 exporting layers #14 exporting layers 1.2s done #14 writing image sha256:2d524bc1665327faa0d34001b0a9d2ccf450612bf8feeb969312e96a2d3e3503 done -#14 naming to docker.io/nautobot-golden-config/nautobot:latest-py3.7 done +#14 naming to docker.io/nautobot-golden-config/nautobot:latest-py3.11 done ``` ### Invoke - Starting the Development Environment @@ -218,9 +218,9 @@ This will start all of the Docker containers used for hosting Nautobot. You shou ```bash ➜ docker ps ****CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -ee90fbfabd77 nautobot-golden-config/nautobot:latest-py3.7 "nautobot-server rqw…" 16 seconds ago Up 13 seconds nautobot_golden_config_worker_1 -b8adb781d013 nautobot-golden-config/nautobot:latest-py3.7 "/docker-entrypoint.…" 20 seconds ago Up 15 seconds 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp nautobot_golden_config_nautobot_1 -d64ebd60675d nautobot-golden-config/nautobot:latest-py3.7 "mkdocs serve -v -a …" 25 seconds ago Up 18 seconds 0.0.0.0:8001->8080/tcp, :::8001->8080/tcp nautobot_golden_config_docs_1 +ee90fbfabd77 nautobot-golden-config/nautobot:latest-py3.11 "nautobot-server rqw…" 16 seconds ago Up 13 seconds nautobot_golden_config_worker_1 +b8adb781d013 nautobot-golden-config/nautobot:latest-py3.11 "/docker-entrypoint.…" 20 seconds ago Up 15 seconds 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp nautobot_golden_config_nautobot_1 +d64ebd60675d nautobot-golden-config/nautobot:latest-py3.11 "mkdocs serve -v -a …" 25 seconds ago Up 18 seconds 0.0.0.0:8001->8080/tcp, :::8001->8080/tcp nautobot_golden_config_docs_1 e72d63129b36 postgres:13-alpine "docker-entrypoint.s…" 25 seconds ago Up 19 seconds 0.0.0.0:5432->5432/tcp, :::5432->5432/tcp nautobot_golden_config_postgres_1 96c6ff66997c redis:6-alpine "docker-entrypoint.s…" 25 seconds ago Up 21 seconds 0.0.0.0:6379->6379/tcp, :::6379->6379/tcp nautobot_golden_config_redis_1 ``` @@ -399,7 +399,7 @@ namespace.configure( { "nautobot_golden_config": { ... - "python_ver": "3.7", + "python_ver": "3.11", ... } } @@ -418,7 +418,7 @@ namespace.configure( { "nautobot_golden_config": { ... - "nautobot_ver": "1.0.2", + "nautobot_ver": "2.0.0", ... } } diff --git a/docs/images/backup-git-step2.png b/docs/images/backup-git-step2.png index bf4b4563dfb884ea7d50ba8c0c19fac232fc6a74..29955d43f54a22ebc2b7b845f2ffe8421008deb4 100644 GIT binary patch literal 44937 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 literal 69722 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