-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #135 from netdevops/v3-docs
V3 docs
- Loading branch information
Showing
14 changed files
with
1,453 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
# Config View | ||
|
||
A Config View is an abstraction layer for network device configurations. It provides a structured, Pythonic way to interact with and extract information from raw configuration data. Config Views are especially useful for standardizing how configuration elements are accessed across different platforms and devices. | ||
|
||
The framework uses a combination of abstract base classes (e.g., `ConfigViewInterfaceBase`, `HConfigViewBase`) and platform-specific implementations (e.g., `ConfigViewInterfaceCiscoIOS`, `HConfigViewCiscoIOS`) to provide a unified interface for interacting with configurations while accounting for the unique syntax and semantics of each vendor or platform. | ||
|
||
## Why Use Config Views? | ||
|
||
1. **Vendor Abstraction:** Network devices from different vendors (Cisco, Arista, Juniper, etc.) have varied configuration formats. Config Views standardize access, making it easier to work across platforms. | ||
|
||
2. **Simplified Interface:** Accessing configuration data becomes more intuitive through Python properties and methods rather than manually parsing text. | ||
|
||
3. **Extensibility:** Easily extendable to support new platforms or devices by implementing platform-specific subclasses. | ||
|
||
4. **Error Reduction:** Encapsulates parsing logic, reducing the risk of errors due to configuration syntax differences. | ||
|
||
## Available Config Views | ||
|
||
| **Property/Method** | **Type** | **Description** | | ||
|-----------------------------|--------------------------------|------------------------------------------------------------------------------| | ||
| `bundle_interface_views` | `Iterable` | Yields interfaces configured as bundles. | | ||
| `config` | `HConfig` | Root configuration object. | | ||
| `dot1q_mode_from_vlans` | `Callable` | Determines 802.1Q mode based on VLANs and tagging. | | ||
| `hostname` | `Optional[str]` | Retrieves the device hostname. | | ||
| `interface_names_mentioned` | `frozenset[str]` | Set of all interface names mentioned. | | ||
| `interface_view_by_name` | `Callable` | Returns view of a specific interface by name. | | ||
| `interface_views` | `Iterable` | Yields all interface views. | | ||
| `interfaces` | `Iterable[HConfigChild]` | Yields raw configuration objects for all interfaces. | | ||
| `interfaces_names` | `Iterable[str]` | Yields the names of all interfaces. | | ||
| `ipv4_default_gw` | `Optional[IPv4Address]` | Retrieves the IPv4 default gateway. | | ||
| `location` | `str` | Returns the SNMP location. | | ||
| `module_numbers` | `Iterable[int]` | Yields module numbers from interfaces. | | ||
| `stack_members` | `Iterable[StackMember]` | Yields stack members configured on the device. | | ||
| `vlan_ids` | `frozenset[int]` | Set of VLAN IDs configured. | | ||
| `vlans` | `Iterable[Vlan]` | Yields VLAN objects, including ID and name. | | ||
|
||
## Example: Cisco IOS Config View | ||
|
||
### Step 1: Parse Configuration | ||
|
||
Assume we have a Cisco IOS configuration file as a string. | ||
|
||
```python | ||
from hier_config import Platform, get_hconfig | ||
|
||
|
||
raw_config = """ | ||
hostname router1 | ||
interface GigabitEthernet0/1 | ||
description Uplink to Switch | ||
switchport access vlan 10 | ||
ip address 192.168.1.1 255.255.255.0 | ||
shutdown | ||
! | ||
vlan 10 | ||
name DATA | ||
""" | ||
|
||
hconfig = get_hconfig(Platform.CISCO_IOS, raw_config) | ||
``` | ||
|
||
### Step 2: Create Config View | ||
|
||
```python | ||
from hier_config.platforms.cisco_ios.view import HConfigViewCiscoIOS | ||
|
||
|
||
config_view = HConfigViewCiscoIOS(hconfig) | ||
``` | ||
|
||
### Step 3: Access Configuration Details | ||
|
||
Access properties to interact with the configuration programmatically: | ||
|
||
```python | ||
# Get the hostname | ||
print(config_view.hostname) # Output: router1 | ||
|
||
# List all interface names | ||
print(list(config_view.interfaces_names)) # Output: ['GigabitEthernet0/1'] | ||
|
||
# Check if an interface is enabled | ||
for interface_view in config_view.interface_views: | ||
print(interface_view.name, "Enabled:", interface_view.enabled) | ||
|
||
# Get all VLANs | ||
for vlan in config_view.vlans: | ||
print(f"VLAN {vlan.id}: {vlan.name}") | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
# Creating Custom Workflows | ||
|
||
Certain scenarios demand remediation strategies that go beyond the standard negation and idempotency workflows Hier Config is designed to handle. To address these edge cases, Hier Config allows for custom remediation workflows that integrate seamlessly with the existing remediation process. | ||
|
||
---- | ||
|
||
## Building a Remediation Workflow | ||
|
||
1. Importing Modules and Loading Configurations | ||
|
||
Start by importing the necessary modules and loading the running and intended configurations for comparison. | ||
|
||
```python | ||
from hier_config import WorkflowRemediation, get_hconfig, Platform | ||
from hier_config.utils import load_device_config | ||
``` | ||
|
||
Load the configurations from files: | ||
|
||
```python | ||
running_config = load_device_config("./tests/fixtures/running_config_acl.conf") | ||
generated_config = load_device_config("./tests/fixtures/generated_config_acl.conf") | ||
``` | ||
|
||
These configurations represent the current and desired states of the device. | ||
|
||
---- | ||
|
||
2. Initializing the Workflow Remediation Object: | ||
|
||
Initialize the WorkflowRemediation object for a Cisco IOS platform: | ||
|
||
|
||
```python | ||
wfr = WorkflowRemediation( | ||
running_config=get_hconfig(Platform.CISCO_IOS, running_config), | ||
generated_config=get_hconfig(Platform.CISCO_IOS, generated_config) | ||
) | ||
``` | ||
This object manages the remediation workflow between the running and generated configurations. | ||
|
||
---- | ||
|
||
## Extracting and Analyzing Remediation Sections | ||
|
||
### Example: Access-List Custom Remediation | ||
|
||
**Current (Running) Configuration** | ||
|
||
```python | ||
print(wfr.running_config.get_child(startswith="ip access-list")) | ||
``` | ||
|
||
Output: | ||
|
||
``` | ||
ip access-list extended TEST | ||
12 permit ip 10.0.0.0 0.0.0.7 any | ||
exit | ||
``` | ||
|
||
**Intended (Generated) Configuration** | ||
|
||
```python | ||
print(wfr.generated_config.get_child(startswith="ip access-list")) | ||
``` | ||
|
||
Output: | ||
|
||
``` | ||
ip access-list extended TEST | ||
10 permit ip 10.0.1.0 0.0.0.255 any | ||
20 permit ip 10.0.0.0 0.0.0.7 any | ||
exit | ||
``` | ||
|
||
**Default Remediation Configuration** | ||
|
||
```python | ||
print(wfr.remediation_config.get_child(startswith="ip access-list")) | ||
``` | ||
|
||
Output: | ||
|
||
``` | ||
ip access-list extended TEST | ||
no 12 permit ip 10.0.0.0 0.0.0.7 any | ||
10 permit ip 10.0.1.0 0.0.0.255 any | ||
20 permit ip 10.0.0.0 0.0.0.7 any | ||
exit | ||
``` | ||
|
||
#### Issues with the Default Remediation: | ||
|
||
1. **Invalid Command:** `no 12 permit ip 10.0.0.0 0.0.0.7 any` is invalid in Cisco IOS. The valid command is `no 12`. | ||
2. **Risk of Lockout:** Removing a line currently matched by traffic could cause a connectivity outage. | ||
3. **Unnecessary Changes:** `permit ip 10.0.0.0 0.0.0.7 any` is a valid line aside from sequence numbers. In large ACLs, this might be unnecessary to delete and re-add. | ||
|
||
---- | ||
|
||
#### Goals for Safe Access-List Remediation | ||
|
||
To avoid outages during production changes: | ||
|
||
1. **Resequence the ACL:** Adjust sequence numbers using the ip access-list resequence command. | ||
* For demonstration, resequence to align 12 to 20. | ||
2. **Temporary Allow-All:** Add a temporary rule (1 permit ip any any) to prevent lockouts. | ||
2. **Cleanup:** Remove the temporary rule (no 1) after applying the changes. | ||
|
||
---- | ||
|
||
## Building the Custom Remediation | ||
|
||
1. Create a Custom `HConfig` Object | ||
|
||
```python | ||
from hier_config import HConfig | ||
|
||
custom_remediation = HConfig(wfr.running_config.driver) | ||
``` | ||
|
||
2. Add Resequencing and Extract ACL Remediation | ||
|
||
```python | ||
custom_remediation.add_child("ip access-list resequence TEST 10 10") | ||
custom_remediation.add_child("ip access-list extended TEST") | ||
remediation = wfr.remediation_config.get_child(equals="ip access-list extended TEST") | ||
``` | ||
|
||
3. Build the Custom ACL Remediation | ||
|
||
```python | ||
acl = custom_remediation.get_child(equals="ip access-list extended TEST") | ||
acl.add_child("1 permit ip any any") # Temporary allow-all | ||
|
||
for line in remediation.all_children(): | ||
if line.text.startswith("no "): | ||
# Adjust invalid sequence negation | ||
parts = line.text.split() | ||
rounded_number = round(int(parts[1]), -1) | ||
acl.add_child(f"{parts[0]} {rounded_number}") | ||
else: | ||
acl.add_child(line.text) | ||
|
||
acl.add_child("no 1") # Cleanup temporary rule | ||
``` | ||
|
||
### Output of Custom Remediation | ||
|
||
```python | ||
print(custom_remediation) | ||
``` | ||
|
||
Output: | ||
|
||
``` | ||
ip access-list resequence TEST 10 10 | ||
ip access-list extended TEST | ||
1 permit ip any any | ||
no 10 | ||
10 permit ip 10.0.1.0 0.0.0.255 any | ||
20 permit ip 10.0.0.0 0.0.0.7 any | ||
no 1 | ||
exit | ||
``` | ||
|
||
## Applying the Custom Remediation | ||
|
||
### Remove Invalid Remediation | ||
|
||
```python | ||
invalid_remediation = wfr.remediation_config.get_child(equals="ip access-list extended TEST") | ||
wfr.remediation_config.delete_child(invalid_remediation) | ||
``` | ||
|
||
### Add Custom Remediation | ||
|
||
```python | ||
wfr.remediation_config.merge(custom_remediation) | ||
``` | ||
|
||
### Output of Updated Remediation | ||
|
||
```python | ||
print(wfr.remediation_config) | ||
``` | ||
|
||
Output: | ||
|
||
``` | ||
vlan 3 | ||
name switch_mgmt_10.0.3.0/24 | ||
exit | ||
vlan 4 | ||
name switch_mgmt_10.0.4.0/24 | ||
exit | ||
interface Vlan2 | ||
mtu 9000 | ||
ip access-group TEST in | ||
no shutdown | ||
exit | ||
interface Vlan3 | ||
description switch_mgmt_10.0.3.0/24 | ||
ip address 10.0.3.1 255.255.0.0 | ||
exit | ||
interface Vlan4 | ||
mtu 9000 | ||
description switch_mgmt_10.0.4.0/24 | ||
ip address 10.0.4.1 255.255.0.0 | ||
ip access-group TEST in | ||
no shutdown | ||
exit | ||
ip access-list resequence TEST 10 10 | ||
ip access-list extended TEST | ||
1 permit ip any any | ||
no 10 | ||
10 permit ip 10.0.1.0 0.0.0.255 any | ||
20 permit ip 10.0.0.0 0.0.0.7 any | ||
no 1 | ||
exit | ||
``` |
Oops, something went wrong.