Drivers in Hier Config
Drivers represent a modern approach to handling operating system-specific options within Hier Config. Prior to version 3, Hier Config utilized options or hconfig_options, which were defined as dictionaries, to specify OS-specific parameters. Starting with version 3, these options have been replaced by drivers, which are implemented as Pydantic models and loaded as Python classes, offering improved structure and validation.
Note: Many of the options available in the Hier Config version 3 driver format are similar to those in the version 2 options format. However, some options have been removed because they are no longer used in version 3, or their names have been updated for consistency or clarity.
What is a Driver?
A driver in Hier Config defines a structured and systematic approach to managing operating system-specific configurations for network devices. It acts as a framework that encapsulates the rules, transformations, and behaviors required to process and normalize device configurations.
Drivers provide a consistent way to handle configurations by applying a set of specialized logic, including:
-
Negation Handling: Ensures commands are properly negated or reset according to the operating system's syntax and behavior, maintaining consistency in enabling or disabling features.
-
Sectional Exiting Rules: Defines how to navigate in and out of hierarchical configuration sections, ensuring commands are logically grouped and the configuration maintains its structural integrity.
-
Command Ordering: Establishes the sequence in which commands should be applied based on dependencies or importance, preventing conflicts or misconfigurations during deployment.
-
Line Substitutions: Cleans up unnecessary or temporary data in configurations, such as metadata, system-generated comments, or obsolete commands, resulting in a streamlined and standardized output.
-
Idempotency Management: Identifies and enforces commands that should not be duplicated, ensuring repeated application of the configuration does not lead to redundant or conflicting entries.
-
Post-Processing Callbacks: Performs additional adjustments or enhancements after the initial configuration is processed, such as refining access control lists or applying custom transformations specific to the device's operating system.
By defining these rules and behaviors in a reusable way, a driver enables Hier Config to adapt seamlessly to different operating systems while maintaining a consistent interface for configuration management. This abstraction allows users to work with configurations in a predictable and efficient manner, regardless of the underlying system-specific requirements.
Built-In Drivers in Hier Config
The following drivers are included in Hier Config:
- ARISTA_EOS
- CISCO_IOS
- CISCO_XR
- CISCO_NXOS
- FORTINET_FORTIOS
- GENERIC
- HP_COMWARE5
- HP_PROCURVE
- HUAWEI_VRP
- JUNIPER_JUNOS
- NOKIA_SRL
- VYOS
To activate a driver, use the get_hconfig_driver utility provided by Hier Config:
from hier_config import get_hconfig_driver, Platform
# Example: Activating the CISCO_IOS driver
driver = get_hconfig_driver(Platform.CISCO_IOS)
Cisco IOS Driver
Cisco IOS is hier_config's primary reference platform and the most thoroughly tested driver. The CISCO_IOS driver ships with a comprehensive set of rules covering common IOS configuration patterns:
- Idempotent commands:
hostname,ip address,ip access-group,description,banner, and many others are treated as last-write-wins — applying the same command twice leaves only the final value in place. - Negation: standard
nonegation prefix. Several commands (such aslogging console) useNegationDefaultWithRuleoverrides to emit a specific reset form. - Sectional exiting: BGP
peer-policyandpeer-sessionblocks requireexit-peer-policyandexit-peer-sessionclosure tokens. - Per-line substitutions: strips
Building configuration…banners and timestamp headers. - VLAN id list splitting: IOS can render unnamed VLANs collapsed onto a single comma/range line (e.g.
vlan 69,381,vlan 10-12), depending on how the VLANs were created — named VLANs always get their own block, and the grouping shifts as VLANs are named or unnamed. When such a collapsed line is present, a post-load callback splits it into onevlan <id>block each so the VLANs diff block-to-block against an intended config that lists them separately — avoiding a destructiveno vlan 69,381.
Platform enum: Platform.CISCO_IOS
from hier_config import Platform, get_hconfig_driver
driver = get_hconfig_driver(Platform.CISCO_IOS)
Arista EOS Driver
Arista EOS uses a Cisco IOS-like hierarchical CLI, so the ARISTA_EOS driver closely mirrors CISCO_IOS:
- BGP peer-policy and peer-session blocks require
exit-peer-policyandexit-peer-sessionclosure tokens (same as IOS). - Broad idempotency rules cover the most common EOS configuration patterns.
- Negation prefix:
no(default).
Platform enum: Platform.ARISTA_EOS
from hier_config import Platform, get_hconfig_driver
driver = get_hconfig_driver(Platform.ARISTA_EOS)
Cisco IOS XR Driver
Cisco IOS XR uses a commit-based configuration model with several syntax differences from classic IOS:
- Sectional overwrite no-negate:
prefix-set,route-policy, and similar blocks are replaced wholesale rather than line-by-line, because IOS XR does not support partial modification of these objects. - Indent adjust:
templateblocks use a different indentation depth; the driver adjusts the tree depth betweentemplateandend-templatemarkers. - Sectional exiting: route-policy blocks close with
end-policy; prefix-set and community-set blocks close withend-set; template blocks close withend-template; group blocks close withend-group. Allend-*exit text is rendered at the parent indentation level (exit_text_parent_level=True). - ACL sequence numbers are preserved for correct ordered access-list handling.
Platform enum: Platform.CISCO_XR
from hier_config import Platform, get_hconfig_driver
driver = get_hconfig_driver(Platform.CISCO_XR)
Cisco NX-OS Driver
Cisco NX-OS is similar to IOS in CLI structure but has NX-OS-specific idempotency requirements:
- TCAM region idempotency:
hardware access-list tcam regioncommands are treated as last-write-wins. - Some BGP commands use different negation forms; the driver includes
NegationDefaultWithRuleentries for affected commands. - Negation prefix:
no(default).
Platform enum: Platform.CISCO_NXOS
from hier_config import Platform, get_hconfig_driver
driver = get_hconfig_driver(Platform.CISCO_NXOS)
VyOS Driver
VyOS uses set and delete command syntax rather than the no-prefix convention.
Experimental: VyOS support has not been tested extensively in production environments. Use with caution.
- Declaration prefix:
set(prepended to each positive command). - Negation prefix:
delete(replacesno).
Platform enum: Platform.VYOS
from hier_config import Platform, get_hconfig_driver
driver = get_hconfig_driver(Platform.VYOS)
Nokia SRL (Service Router Linux) Driver
Nokia SR Linux uses set and delete command syntax, similar to VyOS and JunOS. The driver converts hierarchical SRL configuration (from info output) into flat set/delete commands via a preprocessor.
Experimental: Nokia SRL support has not been tested extensively in production environments. Use with caution.
- Declaration prefix:
set(prepended to each positive command). - Negation prefix:
delete(replacesno).
Platform enum: Platform.NOKIA_SRL
from hier_config import Platform, get_hconfig_driver
driver = get_hconfig_driver(Platform.NOKIA_SRL)
Remediation example:
from hier_config import WorkflowRemediation, get_hconfig, Platform
running = get_hconfig(Platform.NOKIA_SRL, running_text)
intended = get_hconfig(Platform.NOKIA_SRL, intended_text)
workflow = WorkflowRemediation(running, intended)
for line in workflow.remediation_config.all_children_sorted():
print(line.cisco_style_text())
Generic Driver
The GENERIC driver contains no platform-specific rules. It is useful as a starting point for custom drivers or for platforms that follow standard Cisco-style syntax with few special cases.
Platform enum: Platform.GENERIC
from hier_config import Platform, get_hconfig_driver
driver = get_hconfig_driver(Platform.GENERIC)
See Creating a Custom Driver for how to build on top of the generic driver.
Juniper JunOS Driver
Juniper JunOS uses set and delete command syntax for its hierarchical configuration.
Experimental: JunOS support has not been tested extensively in production environments. Use with caution.
- Declaration prefix:
set(prepended to each positive command). - Negation prefix:
delete(replacesno).
For a worked example see JunOS Style Syntax Remediation.
Platform enum: Platform.JUNIPER_JUNOS
from hier_config import Platform, get_hconfig_driver
driver = get_hconfig_driver(Platform.JUNIPER_JUNOS)
HP ProCurve (Aruba AOSS) Driver
HP ProCurve switches (sold as Aruba switches after the HP/Aruba merger) use a Cisco-style hierarchical CLI with no as the negation prefix. The HP_PROCURVE driver adds several post-load normalisation callbacks that simplify diffing:
- VLAN membership — moves
untagged/taggeddirectives out ofvlan <id>blocks and into per-interface blocks, matching the mental model that operators typically use when writing intended configs. - Port-access range expansion — expands compact port ranges like
aaa port-access authenticator 1/15-1/20,1/26-1/40into individual interface lines so that hier_config can apply idempotency rules per port. - Device-profile tagged-VLAN splitting — splits comma-separated VLAN lists in
device-profileblocks into one command per VLAN.
The driver also extends idempotency and negation-with logic to handle ProCurve-specific command patterns such as aaa port-access, radius-server, and tacacs-server with variable-length key fields.
Platform enum: Platform.HP_PROCURVE
Activate the driver:
from hier_config import Platform, get_hconfig_driver
driver = get_hconfig_driver(Platform.HP_PROCURVE)
Remediation example:
from hier_config import WorkflowRemediation, get_hconfig, Platform
running = get_hconfig(Platform.HP_PROCURVE, running_text)
intended = get_hconfig(Platform.HP_PROCURVE, intended_text)
workflow = WorkflowRemediation(running, intended)
for line in workflow.remediation_config.all_children_sorted():
print(line.cisco_style_text())
HP Comware5 Driver
HP Comware5 (and the compatible H3C platform) uses undo as the negation prefix rather than no. The HP_COMWARE5 driver overrides negation_prefix accordingly. No additional platform-specific rules are configured by default; extend the driver if your environment requires them (see Customising Existing Drivers).
Platform enum: Platform.HP_COMWARE5
Activate the driver:
from hier_config import Platform, get_hconfig_driver
driver = get_hconfig_driver(Platform.HP_COMWARE5)
Remediation example:
from hier_config import WorkflowRemediation, get_hconfig, Platform
running = get_hconfig(Platform.HP_COMWARE5, running_text)
intended = get_hconfig(Platform.HP_COMWARE5, intended_text)
workflow = WorkflowRemediation(running, intended)
for line in workflow.remediation_config.all_children_sorted():
print(line.cisco_style_text())
Huawei VRP Driver
Huawei VRP (Versatile Routing Platform) uses undo as the negation prefix rather than no. The HUAWEI_VRP driver customises negation handling for several command families:
- Negation prefix:
undo(replacesno). - Smart negation:
descriptionandaliascommands are negated without their argument;remarkcommands strip the remark text;snmp-agent communitycommands truncate to the community name. - Sectional exiting: section exit text
exitis translated toquitas VRP requires. - Per-line substitutions: strips
#and!comment lines during parsing.
Platform enum: Platform.HUAWEI_VRP
from hier_config import Platform, get_hconfig_driver
driver = get_hconfig_driver(Platform.HUAWEI_VRP)
Remediation example:
from hier_config import WorkflowRemediation, get_hconfig, Platform
running = get_hconfig(Platform.HUAWEI_VRP, running_text)
intended = get_hconfig(Platform.HUAWEI_VRP, intended_text)
workflow = WorkflowRemediation(running, intended)
for line in workflow.remediation_config.all_children_sorted():
print(line.cisco_style_text())
Fortinet FortiOS Driver
Fortinet firewalls model their CLI around config and edit blocks that are
terminated with next and end. The FORTINET_FORTIOS driver captures those
patterns and makes sure remediation output keeps the indentation and closure
FortiOS expects. Highlights include:
- Preserves the
set/unsetpairing by swapping declarations and negations automatically when hier_config determines a change is required. - Treats sibling
configblocks as duplicates when appropriate so that multiple objects such as policies or firewall addresses can be compared in a stable order. - Normalizes bare
nextandendtokens into indented versions to match the format FortiOS emits on the device. - Overrides idempotency matching to require that the same object name exists on both sides before a command is considered already present.
Activate the driver with the standard helper:
from hier_config import Platform, get_hconfig_driver
driver = get_hconfig_driver(Platform.FORTINET_FORTIOS)
Structure of Each Section and How Rules Are Built
In Hier Config, the rules within a driver are organized into sections, each targeting a specific aspect of device configuration processing. These sections use Pydantic models to define the behavior and ensure consistency. Here's a breakdown of each section and its associated models:
1. Negation Rules
Purpose: Define how to negate commands or reset them to a default state.
- Models:
-
NegationDefaultWithRule:match_rules: A tuple ofMatchRuleobjects defining the conditions under which the rule applies.use: The text to use as the negation command.
-
NegationDefaultWhenRule:match_rules: A tuple ofMatchRuleobjects for matching conditions where negation is default.
2. Sectional Exiting
Purpose: Manage hierarchical configuration sections by defining commands for properly exiting each section.
- Models:
SectionalExitingRule:match_rules: A tuple ofMatchRuleobjects defining the section's boundaries.exit_text: The command used to exit the section.exit_text_parent_level: A boolean (defaultFalse). WhenTrue, the exit text is rendered at the parent's indentation level rather than the section's own level (e.g., IOS XRend-policyappears unindented).
3. Ordering
Purpose: Assign weights to commands to control the order of operations during configuration application.
- Models:
OrderingRule:match_rules: A tuple ofMatchRuleobjects defining the commands to be ordered.weight: An integer determining the order (lower weights are processed earlier).
4. Per-Line Substitutions
Purpose: Modify or clean up specific lines in the configuration.
- Models:
-
PerLineSubRule:search: A string or regex to search for.replace: The replacement text.
-
FullTextSubRule:- Similar to
PerLineSubRule, but applies to the entire text rather than individual lines.
- Similar to
5. Idempotent Commands
Purpose: Ensure commands are not repeated unnecessarily in the configuration.
- Models:
-
IdempotentCommandsRule:match_rules: A tuple ofMatchRuleobjects defining idempotent commands.
-
IdempotentCommandsAvoidRule:match_rules: Specifies commands that should be avoided during idempotency checks.
6. Post-Processing Callbacks
Purpose: Apply additional transformations after initial configuration processing.
- Implementation:
- A list of functions or methods called after the driver rules are applied, enabling custom logic specific to the platform.
7. Tagging and Overwriting
Purpose: Apply tags to configuration lines or define overwriting behavior for specific sections.
- Models:
-
TagRule:match_rules: A tuple ofMatchRuleobjects defining the lines to tag.apply_tags: A frozenset of tags to apply.
-
SectionalOverwriteRule:match_rules: Defines sections that can be overwritten.
-
SectionalOverwriteNoNegateRule:- Similar to
SectionalOverwriteRule, but prevents negation.
- Similar to
8. Indentation Adjustments
Purpose: Define start and end points for adjusting indentation within configurations.
- Models:
IndentAdjustRule:start_expression: Regex or text marking the start of an adjustment.end_expression: Regex or text marking the end of an adjustment.
9. Match Rules
Purpose: Provide a flexible way to define conditions for matching configuration lines.
- Models:
MatchRule:equals: Matches lines that are exactly equal.startswith: Matches lines that start with the specified text or tuple of text.endswith: Matches lines that end with the specified text or tuple of text.contains: Matches lines that contain the specified text or tuple of text.re_search: Matches lines using a regular expression.
10. Instance Metadata
Purpose: Manage metadata for configuration instances, such as tags and comments.
- Models:
Instance:id: A unique positive integer identifier.comments: A frozenset of comments.tags: A frozenset of tags.
11. Dumping Configuration
Purpose: Represent and handle the output of processed configuration lines.
- Models:
-
DumpLine:depth: Indicates the hierarchy level of the line.text: The configuration text.tags: A frozenset of tags associated with the line.comments: A frozenset of comments associated with the line.new_in_config: A boolean indicating if the line is new.
-
Dump:lines: A tuple ofDumpLineobjects representing the processed configuration.
General Rule-Building Patterns
- Define Matching Conditions:
-
Use
MatchRuleto specify conditions for each rule, ensuring flexible and precise control over which configuration lines a rule applies to. -
Apply Context-Specific Logic:
-
Use specialized models like
SectionalExitingRuleorIdempotentCommandsRuleto tailor behavior to hierarchical or idempotency-related scenarios. -
Maintain Immutability:
- All models use Pydantic’s immutability and validation to enforce the integrity of rules and configurations.
This structure ensures that drivers are modular, extensible, and capable of handling diverse configuration scenarios across different platforms.
Customizing Existing Drivers
This guide provides two examples of how to extend the rules for a Cisco IOS driver in Hier Config. The first example involves subclassing the driver to customize and add rules. The second example demonstrates extending the driver rules dynamically after the driver has already been instantiated.
Example 1: Subclassing the Driver to Extend Rules
In this approach, you create a new class that subclasses the base Cisco IOS driver and overrides its _instantiate_rules method to customize the rules.
from hier_config.models import (
MatchRule,
NegationDefaultWithRule,
SectionalExitingRule,
OrderingRule,
PerLineSubRule,
IdempotentCommandsRule,
)
from hier_config.platforms.cisco_ios.driver import HConfigDriverCiscoIOS
class ExtendedHConfigDriverCiscoIOS(HConfigDriverCiscoIOS):
@staticmethod
def _instantiate_rules():
# Start with the base rules
base_rules = HConfigDriverCiscoIOS._instantiate_rules()
# Extend negation rules
base_rules.negate_with.append(
NegationDefaultWithRule(
match_rules=(MatchRule(startswith="ip route "),),
use="no ip route"
)
)
# Extend sectional exiting rules
base_rules.sectional_exiting.append(
SectionalExitingRule(
match_rules=(
MatchRule(startswith="policy-map"),
MatchRule(startswith="class"),
),
exit_text="exit",
)
)
# Add additional ordering rules
base_rules.ordering.append(
OrderingRule(
match_rules=(
MatchRule(startswith="access-list"),
MatchRule(startswith="permit "),
),
weight=50,
)
)
# Add new per-line substitutions
base_rules.per_line_sub.append(
PerLineSubRule(
search="^!.*Generated by system.*$", replace=""
)
)
# Add new idempotent commands
base_rules.idempotent_commands.append(
IdempotentCommandsRule(
match_rules=(
MatchRule(startswith="interface "),
MatchRule(startswith="speed "),
)
)
)
return base_rules
Using the Subclassed Driver
from hier_config import Platform
# Example function to activate the extended driver
def get_extended_hconfig_driver(platform: Platform):
if platform == Platform.CISCO_IOS:
return ExtendedHConfigDriverCiscoIOS()
raise ValueError(f"Unsupported platform: {platform}")
# Activate the extended driver
driver = get_extended_hconfig_driver(Platform.CISCO_IOS)
Example 2: Dynamically Extending Rules for an Instantiated Driver
If you already have the driver instantiated, you can modify its rules dynamically by directly appending to the appropriate sections.
from hier_config import get_hconfig_driver, Platform
from hier_config.models import (
MatchRule,
NegationDefaultWithRule,
SectionalExitingRule,
OrderingRule,
PerLineSubRule,
IdempotentCommandsRule,
)
# Instantiate the driver
driver = get_hconfig_driver(Platform.CISCO_IOS)
# Dynamically extend negation rules
driver.rules.negate_with.append(
NegationDefaultWithRule(
match_rules=(MatchRule(startswith="ip route "),),
use="no ip route"
)
)
# Dynamically extend sectional exiting rules
driver.rules.sectional_exiting.append(
SectionalExitingRule(
match_rules=(
MatchRule(startswith="policy-map"),
MatchRule(startswith="class"),
),
exit_text="exit",
)
)
# Add additional ordering rules dynamically
driver.rules.ordering.append(
OrderingRule(
match_rules=(
MatchRule(startswith="access-list"),
MatchRule(startswith="permit "),
),
weight=50,
)
)
# Add new per-line substitutions dynamically
driver.rules.per_line_sub.append(
PerLineSubRule(
search="^!.*Generated by system.*$", replace=""
)
)
# Add new idempotent commands dynamically
driver.rules.idempotent_commands.append(
IdempotentCommandsRule(
match_rules=(
MatchRule(startswith="interface "),
MatchRule(startswith="speed "),
)
)
)
Explanation
- Dynamic Rule Extension: You directly modify the driver.rules attributes to append new rules dynamically.
- Flexibility: This approach is useful when the driver is instantiated by external code, and subclassing is not feasible.
Both approaches allow you to extend the functionality of the Cisco IOS driver:
- Subclassing: Recommended for reusable, modular extensions where the driver logic can be encapsulated in a new class.
- Dynamic Modification: Useful when the driver is instantiated dynamically, and you need to modify the rules at runtime.
Example 3: Adding Unused Object Detection
Unused object detection is not enabled in any driver by default — it must be explicitly configured. This ensures no unintended side-effects for users who are not expecting it.
You can add unused object rules dynamically or via load_hconfig_v2_options:
Dynamic Extension
from hier_config import get_hconfig, get_hconfig_driver, Platform
from hier_config.models import MatchRule, ReferenceLocation, UnusedObjectRule
driver = get_hconfig_driver(Platform.CISCO_XR)
# Detect unused IPv4 ACLs
driver.rules.unused_objects.append(
UnusedObjectRule(
match_rules=(MatchRule(startswith="ipv4 access-list "),),
name_re=r"^ipv4 access-list (?P<name>\S+)",
reference_locations=(
ReferenceLocation(
match_rules=(MatchRule(startswith="interface "),),
reference_re=r"\bipv4 access-group {name}\b",
),
),
)
)
config = get_hconfig(driver, running_config_text)
for unused in config.unused_objects():
print(f"Unused: {unused.text}")
Via load_hconfig_v2_options
from hier_config import get_hconfig, Platform
from hier_config.utils import load_hconfig_v2_options
options = {
"unused_objects": [
{
"lineage": [{"startswith": "ipv4 access-list "}],
"name_re": r"^ipv4 access-list (?P<name>\S+)",
"reference_locations": [
{
"lineage": [{"startswith": "interface "}],
"reference_re": r"\bipv4 access-group {name}\b",
},
],
},
],
}
driver = load_hconfig_v2_options(options, Platform.CISCO_XR)
config = get_hconfig(driver, running_config_text)
for unused in config.unused_objects():
print(f"Unused: {unused.text}")
Each UnusedObjectRule requires:
match_rules— locates the object definition (e.g.,startswith="ipv4 access-list ")name_re— regex with a(?P<name>...)capture group to extract the object namereference_locations— a tuple ofReferenceLocationentries, each specifying where to search and what regex pattern (with{name}placeholder) to match
Example 4: Adding Negation Substitution
Some platforms require negation commands to be truncated or transformed. Use NegationSubRule for regex-based negation transformations:
from hier_config import get_hconfig_driver, Platform
from hier_config.models import MatchRule, NegationSubRule
driver = get_hconfig_driver(Platform.CISCO_NXOS)
# Truncate SNMP user negation after the username
driver.rules.negation_sub.append(
NegationSubRule(
match_rules=(MatchRule(startswith="snmp-server user "),),
search=r"(no snmp-server user \S+).*",
replace=r"\1",
)
)
Creating a Custom Driver
This guide walks you through the process of creating a custom driver using the HConfigDriverBase class from the hier_config.platforms.driver_base module. Custom drivers allow you to define operating system-specific rules and behaviors for managing device configurations.
Overview of HConfigDriverBase
The HConfigDriverBase class provides a foundation for defining driver-specific rules and behaviors. It encapsulates configuration rules and methods for handling idempotency, negation, and more. You will extend this class to create a new driver.
Key Components:
HConfigDriverRules: A collection of rules for handling configuration logic.- Methods to Override: Define custom behavior by overriding the
_instantiate_rulesmethod. - Properties: Adjust behavior for negation and declaration prefixes.
Steps to Create a Custom Driver
Step 1: Subclass HConfigDriverBase
Begin by subclassing HConfigDriverBase to define a new driver.
from hier_config.platforms.driver_base import HConfigDriverBase, HConfigDriverRules
from hier_config.models import (
MatchRule,
NegationDefaultWithRule,
SectionalExitingRule,
OrderingRule,
PerLineSubRule,
IdempotentCommandsRule,
)
class CustomHConfigDriver(HConfigDriverBase):
"""Custom driver for a specific operating system."""
@staticmethod
def _instantiate_rules() -> HConfigDriverRules:
"""Define the rules for this custom driver."""
return HConfigDriverRules(
negate_with=[
NegationDefaultWithRule(
match_rules=(MatchRule(startswith="ip route "),),
use="no ip route"
)
],
sectional_exiting=[
SectionalExitingRule(
match_rules=(
MatchRule(startswith="policy-map"),
MatchRule(startswith="class"),
),
exit_text="exit"
)
],
ordering=[
OrderingRule(
match_rules=(MatchRule(startswith="interface"),),
weight=10
)
],
per_line_sub=[
PerLineSubRule(
search="^!.*Generated by system.*$",
replace=""
)
],
idempotent_commands=[
IdempotentCommandsRule(
match_rules=(MatchRule(startswith="interface"),)
)
],
)
Step 2: Customize Negation or Declaration Prefixes (Optional)
Override the negation_prefix or declaration_prefix properties to customize their behavior.
@property
def negation_prefix(self) -> str:
"""Customize the negation prefix."""
return "disable "
@property
def declaration_prefix(self) -> str:
"""Customize the declaration prefix."""
return "enable "
Step 3: Use the Custom Driver
This section describes how to use the custom driver by extending the get_hconfig_driver function and adding a new platform to the Platform model. It also covers how to load the driver into Hier Config and utilize it for remediation workflows.
1. Extend get_hconfig_driver to Include the Custom Driver
First, modify the get_hconfig_driver function to include the new custom driver:
from hier_config.platforms.driver_base import HConfigDriverBase
from hier_config import get_hconfig_driver
from .custom_driver import CustomHConfigDriver # Import your custom driver
from hier_config.models import Platform
def get_custom_hconfig_driver(platform: Union[CustomPlatform,Platform]) -> HConfigDriverBase:
"""Create base options on an OS level."""
if platform == CustomPlatform.CUSTOM_DRIVER:
return CustomHConfigDriver()
return get_hconfig_driver(platform)
2. Create a custom Platform to Include the Custom Driver
from enum import Enum, auto
class CustomPlatform(str, Enum):
CUSTOM_PLATFORM = auto()
3. Load the Driver into HConfig
from .custom_platform import CustomPlatform
from hier_config import get_hconfig
from hier_config.utils import read_text_from_file
# Load running and intended configurations from files
running_config_text = read_text_from_file("./tests/fixtures/running_config.conf")
generated_config_text = read_text_from_file("./tests/fixtures/remediation_config.conf")
# Create HConfig objects for running and intended configurations
running_config = get_hconfig(CustomPlatform.CUSTOM_DRIVER, running_config_text)
generated_config = get_hconfig(CustomPlatform.CUSTOM_DRIVER, generated_config_text)
4. Instantiate a WorkflowRemediation
from hier_config import WorkflowRemediation
# Instantiate the remediation workflow
workflow = WorkflowRemediation(running_config, generated_config)
Key Methods in HConfigDriverBase
idempotent_for:- Matches configurations against idempotent rules to prevent duplication.
def idempotent_for(
self,
config: HConfigChild,
other_children: Iterable[HConfigChild],
) -> Optional[HConfigChild]:
...
negate_with:- Provides a negation command based on rules.
def negate_with(self, config: HConfigChild) -> Optional[str]:
...
swap_negation:- Toggles the negation of a command.
def swap_negation(self, child: HConfigChild) -> HConfigChild:
...
- Properties:
negation_prefix: Default is"no ".declaration_prefix: Default is"".
Example Rule Definitions
Negation Rules
Define commands that require specific negation handling:
negate_with=[
NegationDefaultWithRule(
match_rules=(MatchRule(startswith="ip route "),),
use="no ip route"
)
]
Sectional Exiting
Define how to exit specific configuration sections:
sectional_exiting=[
SectionalExitingRule(
match_rules=(
MatchRule(startswith="policy-map"),
MatchRule(startswith="class"),
),
exit_text="exit",
),
SectionalExitingRule(
match_rules=(MatchRule(startswith="route-policy"),),
exit_text="end-policy",
exit_text_parent_level=True, # render at parent indentation
),
]
Command Ordering
Set the execution order of specific commands:
ordering=[
OrderingRule(
match_rules=(MatchRule(startswith="interface"),),
weight=10
)
]
Per-Line Substitution
Clean up unwanted lines in the configuration:
per_line_sub=[
PerLineSubRule(
search="^!.*Generated by system.*$",
replace=""
)
]