Handling YAML with Python
YAML (YAML Ain’t Markup Language) is a human-readable data format widely used for configuration files and data serialization. For network engineers, YAML can be a powerful tool for managing network device configurations across multiple vendors. In Python, you can leverage the PyYAML library to read, write, update, and convert YAML files—making it ideal for automation tasks.
1. Installing PyYAML
Before working with YAML in Python, install the PyYAML package:
1
pip install pyyaml
Once installed, you can start using it in your Python scripts.
2. Reading YAML Files for Network Configurations
For network automation, you might have a YAML file that includes configuration details for devices from different vendors. The following example shows a sample YAML file with configuration details for Cisco, Juniper, and Arista devices.
Example YAML File (network_config.yaml):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
cisco:
hostname: "CiscoRouter1"
interfaces:
- name: GigabitEthernet0/1
ip_address: "192.168.1.1/24"
- name: GigabitEthernet0/2
ip_address: "192.168.2.1/24"
juniper:
hostname: "JuniperSwitch1"
interfaces:
- name: ge-0/0/1
ip_address: "10.0.0.1/24"
- name: ge-0/0/2
ip_address: "10.0.1.1/24"
arista:
hostname: "AristaSwitch1"
interfaces:
- name: Ethernet1
ip_address: "172.16.0.1/24"
- name: Ethernet2
ip_address: "172.16.1.1/24"
Python Code to Read the YAML File:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import yaml
# Load the network configuration YAML file
with open("network_config.yaml", "r") as file:
network_config = yaml.safe_load(file)
# Print the parsed YAML data
print(network_config)
# Example: Accessing Cisco device details
print(f"Cisco Hostname: {network_config['cisco']['hostname']}")
print("Cisco Interfaces:")
for intf in network_config['cisco']['interfaces']:
print(f" - {intf['name']}: {intf['ip_address']}")
🔹 Tip: Use
yaml.safe_load()to safely parse YAML without risking arbitrary code execution.
3. Writing YAML Files for Device Configurations
You can also create or update network configurations by writing Python dictionaries into YAML files. This is particularly useful when generating configuration scripts dynamically.
Python Code to Write a Network Configuration:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import yaml
# Example network configuration data
network_data = {
"cisco": {
"hostname": "CiscoRouter2",
"interfaces": [
{"name": "GigabitEthernet0/1", "ip_address": "192.168.10.1/24"},
{"name": "GigabitEthernet0/2", "ip_address": "192.168.20.1/24"}
]
},
"juniper": {
"hostname": "JuniperSwitch2",
"interfaces": [
{"name": "ge-0/0/1", "ip_address": "10.1.0.1/24"}
]
}
}
# Write network configuration data to YAML file
with open("new_network_config.yaml", "w") as file:
yaml.dump(network_data, file, default_flow_style=False)
print("Network YAML file created successfully!")
🔹 Note: Setting
default_flow_style=Falseformats the YAML in a more readable structure, which is especially helpful for manual reviews.
4. Updating Network Device YAML Files
To update a device configuration, first read the YAML file, modify the necessary fields, and write it back.
Python Code to Update a YAML File:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import yaml
# Read the existing YAML file
with open("network_config.yaml", "r") as file:
network_config = yaml.safe_load(file)
# Update the Juniper device configuration
network_config["juniper"]["hostname"] = "JuniperSwitchUpdated"
network_config["juniper"]["interfaces"][0]["ip_address"] = "10.1.1.1/24"
# Write the updated configuration back to the file
with open("network_config.yaml", "w") as file:
yaml.dump(network_config, file, default_flow_style=False)
print("Network YAML file updated successfully!")
🔹 Tip: Always backup your configuration files before making updates to prevent accidental data loss.
5. Handling Complex YAML Structures
YAML supports advanced features like nested lists, dictionaries, and references, which can be useful for handling redundant configurations across multiple devices.
Example Complex YAML (complex_network.yaml):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
defaults: &defaults
timeout: 30
retries: 3
cisco:
<<: *defaults
hostname: "CiscoRouter3"
interfaces:
- name: GigabitEthernet0/1
ip_address: "192.168.100.1/24"
juniper:
<<: *defaults
hostname: "JuniperSwitch3"
interfaces:
- name: ge-0/0/1
ip_address: "10.2.0.1/24"
Python Code to Handle Complex YAML:
1
2
3
4
5
6
import yaml
with open("complex_network.yaml", "r") as file:
complex_config = yaml.safe_load(file)
print(complex_config)
🔹 Note: YAML references (using
&defaultsand*defaults) help you avoid repetition and ensure consistent default values across device configurations.
6. Converting YAML to JSON for API Integrations
In many network automation platforms, you might need to convert YAML configurations to JSON, which is widely used in REST APIs.
Python Code for YAML to JSON Conversion:
1
2
3
4
5
6
7
8
9
10
11
import yaml
import json
# Load the YAML configuration file
with open("network_config.yaml", "r") as file:
yaml_data = yaml.safe_load(file)
# Convert YAML data to JSON
json_data = json.dumps(yaml_data, indent=4)
print(json_data)
🔹 Example Output (JSON Format): The output will include your network device configurations in JSON, which can be easily integrated with network management APIs.
7. Error Handling in YAML Processing
When automating network configurations, robust error handling is crucial. Use exception handling to catch issues like missing files or syntax errors in YAML.
Example Code with Exception Handling:
1
2
3
4
5
6
7
8
9
10
import yaml
try:
with open("network_config.yaml", "r") as file:
data = yaml.safe_load(file)
print("YAML file loaded successfully!")
except FileNotFoundError:
print("Error: YAML file not found.")
except yaml.YAMLError as e:
print(f"YAML Parsing Error: {e}")
🔹 Tip: Always handle
yaml.YAMLErrorto catch parsing issues which could lead to misconfigurations on network devices.
8. Preserving Order with OrderedDict
In network configurations, the order of parameters can be significant. If you need to maintain the order of YAML keys (especially for devices that expect a specific order), use OrderedDict.
Example Code for Ordered YAML Data:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import yaml
from collections import OrderedDict
def ordered_yaml_load(stream, Loader=yaml.SafeLoader):
class OrderedLoader(Loader):
pass
def construct_mapping(loader, node):
return OrderedDict(loader.construct_pairs(node))
OrderedLoader.add_constructor(
yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
construct_mapping
)
return yaml.load(stream, OrderedLoader)
with open("network_config.yaml", "r") as file:
ordered_config = ordered_yaml_load(file)
print(ordered_config)
🔹 Note: Maintaining key order can be critical when automating configuration tasks that rely on specific sequencing.