Navigating Configuration Post-processing¶
Note
The current implementation only renders the configuration for pushing and does not update the configuration on the target devices.
The intended configuration job doesn't produce a final configuration artifact (see below for reasons). The intended configuration represents the "intended" running configuration, as it generates what is expected to be in the final running configuration. While this approach works well for the "compliance" feature, it is less effective for creating a configuration artifact that is ready to be pushed to devices.
Challenges when using the running configuration as the intended configuration:
- Since the intended configuration is stored in both the database and an external Git repository, it should not contain any secrets.
- The format of the running configuration may differ from the configuration that needs to be pushed. Examples include:
- SNMPv3 configurations, which do not appear in the running configuration
- VTP configurations that are entirely absent from the running configuration
- Implicit configurations, such as "no shutdown" commands on interfaces
- Configurations necessary to achieve the intended state may need to be ordered carefully to prevent outages.
As the Golden Config application evolves into a comprehensive configuration management solution, it requires an advanced feature to generate a configuration artifact that is in the final format expected by your device, based on the intended configuration.
This is achieved through the get_config_postprocessing()
function defined in nautobot_golden_config.utilities.config_postprocessing
. This method processes the configurations generated by the Golden Config intended configuration feature, along with the HTTP request. It returns the intended configuration that is ready to be pushed.
From a user perspective, you can retrieve this configuration using two methods:
- UI: In the
Device
detail view, if the feature is enabled, a new row appears under "Configuration Types." Clicking the icon renders the new configuration on the fly (synchronously). See the figure below for reference. - REST API: You can request the processed intended configuration at the path
/api/plugins/golden-config/config-postprocessing/{device_id}
. The return payload will contain a "config" key with the rendered configuration.
Customizing Configuration Processing¶
There are two ways to customize the default behavior of the get_config_postprocessing
method:
postprocessing_callables
: A list of available methods for processing the intended configuration. It includes some default methods, such asrender_secrets
, but can be extended via configuration options (see the next section). These methods are defined using a dotted string format that Django imports. For example,render_secrets
is defined as"nautobot_golden_config.utilities.config_postprocessing.render_secrets"
.postprocessing_subscribed
: A list of method names (strings) that define the order in which methods are executed. The methods must exist in thepostprocessing_callables
list. This list can be customized through configuration options and could eventually accept HTTP query parameters for further customization.
Default Processors¶
Render Secrets¶
The render_secrets
function performs an additional Jinja rendering on the intended configuration, providing custom Jinja filters:
get_secret_by_secret_group_name
: As the name implies, this filter returns the value of a secret group for a given secret type based on itsname
.
Note
Standard Django or Netutils filters are not available in this Jinja environment. Only encrypt_<vendor>_type5
and encrypt_<vendor>_type7
filters can be used in conjunction with the get_secret
filters.
Since this rendering occurs after the initial generation of the intended configuration, the {% raw %}
Jinja syntax must be used to prevent premature processing.
- For example, an original template might look like this:
{% raw %}ppp pap sent-username {{ secrets_group["name"] | get_secret_by_secret_group_name("username") }}{% endraw %}
- It produces an intended configuration like this:
ppp pap sent-username {{ secrets_group["name"] | get_secret_by_secret_group_name("username") }}
- After applying
render_secrets
, it becomes:ppp pap sent-username my_username
.
Note that the get_secret
filters accept arguments. In the example, the secret_group
name is passed along with the type of secret. You can customize the signature for additional options.
Note
To render secrets, the user requesting the configuration via UI or API must have read permissions for Secrets Groups, Golden Config, and the specific Device object.
Render Secrets Example¶
Here is an example of rendering secrets for a Device
, using the default Secrets Group
ForeignKey (FK) and custom relationships, in this case at the Location
level.
GraphQL Query¶
query ($device_id: ID!) {
device(id: $device_id) {
secrets_group {
name
}
location {
rel_my_secret_relationship_for_location {
name
}
}
}
}
Jinja Template¶
Using the default secrets_group
FK in Device
:
{% raw %}{{ secrets_group["name"] | get_secret_by_secret_group_name("password") | default('no password') }}{% endraw %}
Using the custom relationship at the Location
level:
{% raw %}{{ location["rel_my_secret_relationship_for_location"][0]["name"] | get_secret_by_secret_group_name("password") | default('no password') }}{% endraw %}
This will render the secret of type "password" for the corresponding SecretGroup
.
Managing Errors¶
The rendering process may encounter issues, which are managed and properly explained to guide corrective actions: