Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ✨Add jinja settings support for golden config plugin #527

Merged
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion development/nautobot_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import os
import sys

from django.utils.module_loading import import_string

from nautobot.core.settings import * # noqa: F403
from nautobot.core.settings_funcs import parse_redis_connection
from nautobot.core.settings_funcs import is_truthy, parse_redis_connection


#
Expand Down Expand Up @@ -174,6 +176,11 @@
"enable_postprocessing": is_truthy(os.environ.get("ENABLE_POSTPROCESSING", True)),
"postprocessing_callables": os.environ.get("POSTPROCESSING_CALLABLES", []),
"postprocessing_subscribed": os.environ.get("POSTPROCESSING_SUBSCRIBED", []),
"jinja_env": {
"undefined": import_string("jinja2.StrictUndefined"),
"jinja_env_trim_blocks": is_truthy(os.getenv("NAUTOBOT_JINJA_ENV_TRIM_BLOCKS", True)),
"jinja_env_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.).
Expand Down
18 changes: 16 additions & 2 deletions docs/admin/admin_install.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ PLUGINS_CONFIG = {
"postprocessing_callables": [],
"postprocessing_subscribed": [],
"platform_slug_map": None,
"jinja_env_trim_blocks": True,
"jinja_env_lstrip_blocks": False,
itdependsnetworks marked this conversation as resolved.
Show resolved Hide resolved
# "get_custom_compliance": "my.custom_compliance.func"
},
}
Expand Down Expand Up @@ -93,17 +95,29 @@ 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_postprocessing | True | False | A boolean to represent whether or not to generate intended configurations to push, with extra processing such as secrets rendering. |
| enable_postprocessing | True | False | A boolean to represent whether or not to generate intended configurations to push, with extra processing such as secrets rendering. |
| 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`. |
| 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`. |
| sot_agg_transposer | "mypkg.transposer" | None | A string representation of a function that can post-process the graphQL data. |
| per_feature_bar_width | 0.15 | 0.15 | The width of the table bar within the overview report |
| per_feature_width | 13 | 13 | The width in inches that the overview table can be. |
| per_feature_height | 4 | 4 | The height in inches that the overview table can be. |
| jinja_env | {"jinja_env_lstrip_blocks": False} | See Note Below | A dictionary of Jinja2 Environment options compatible with Jinja2.SandboxEnvironment() |

!!! note
Over time the compliance report will become more dynamic, but for now allow users to configure the `per_*` configs in a way that fits best for them.

!!! note
Review [`nautobot_plugin_nornir`](https://docs.nautobot.com/projects/plugin-nornir/en/latest/user/app_feature_dispatcher/) for Nornir and dispatcher configuration options.

!!! note
Defaults for Jinja2 environment settings (`jinja_env`) are as follows:

```python
jinja_env = {
"undefined": import_string("jinja2.StrictUndefined"),
"jinja_env_trim_blocks": True,
"jinja_env_lstrip_blocks": False,
}
```
itdependsnetworks marked this conversation as resolved.
Show resolved Hide resolved
6 changes: 6 additions & 0 deletions nautobot_golden_config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

__version__ = metadata.version(__name__)

from jinja2 import StrictUndefined
from django.db.models.signals import post_migrate
from nautobot.extras.plugins import PluginConfig

Expand Down Expand Up @@ -36,6 +37,11 @@ class GoldenConfig(PluginConfig):
"per_feature_width": 13,
"per_feature_height": 4,
"get_custom_compliance": None,
"jinja_env": {
"undefined": StrictUndefined,
"jinja_env_trim_blocks": True,
"jinja_env_lstrip_blocks": False,
},
}

def ready(self):
Expand Down
10 changes: 9 additions & 1 deletion nautobot_golden_config/nornir_plays/config_intended.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from nornir.core.task import Result, Task

from django.template import engines
from jinja2.sandbox import SandboxedEnvironment

from nornir_nautobot.exceptions import NornirNautobotException
from nornir_nautobot.plugins.tasks.dispatcher import dispatcher
Expand All @@ -18,6 +19,7 @@
from nautobot_plugin_nornir.constants import NORNIR_SETTINGS
from nautobot_plugin_nornir.utils import get_dispatcher

from nautobot_golden_config.utilities.constant import PLUGIN_CFG
from nautobot_golden_config.utilities.db_management import close_threaded_db_connections
from nautobot_golden_config.models import GoldenConfigSetting, GoldenConfig
from nautobot_golden_config.utilities.helper import (
Expand All @@ -32,7 +34,12 @@
InventoryPluginRegister.register("nautobot-inventory", NautobotORMInventory)
LOGGER = logging.getLogger(__name__)

jinja_env = engines["jinja"].env
# Use a custom Jinja2 environment instead of Django's to avoid HTML escaping
JINJA_ENV = PLUGIN_CFG["jinja_env"]
jinja_env = SandboxedEnvironment(**JINJA_ENV)

# Retrieve filters from the Django jinja template engine
jinja_env.filters = engines["jinja"].env.filters
itdependsnetworks marked this conversation as resolved.
Show resolved Hide resolved


@close_threaded_db_connections
Expand Down Expand Up @@ -85,6 +92,7 @@ def run_template( # pylint: disable=too-many-arguments
output_file_location=output_file_location,
default_drivers_mapping=get_dispatcher(),
jinja_filters=jinja_env.filters,
jinja_env=jinja_env,
itdependsnetworks marked this conversation as resolved.
Show resolved Hide resolved
)[1].result["config"]
intended_obj.intended_last_success_date = task.host.defaults.data["now"]
intended_obj.intended_config = generated_config
Expand Down