I have a YAML Variable file for use with Ansible. I'm trying to build a python script to change specific variables within the YAML file.
YAML File accsw01.yml looks something like this:
interface_vars:
- {interface: Ethernet1/1, description: Test_interface_1, access_vlan: 10}
- {interface: Ethernet1/2, description: Test_interface_2, access_vlan: 20}
I use a while loop to find the right interface var in the YAML file:
interface = input("Enter interface: ")
yaml_file_printout = pprint.PrettyPrinter(indent=2)
with open("/ansible/inventories/test/host_vars/accsw01.yml", "r") as yaml_file:
yaml_read = yaml.load(yaml_file, Loader=yaml.FullLoader)
interface_count = 0
while True:
output_interface = yaml_read["interface_vars"][interface_count]["interface"]
if interface != output_interface:
interface_count += 1
elif interface == output_interface:
yaml_file_printout.pprint(yaml_read["interface_vars"][interface_count])
break
How can I get python to change say, the access_vlan on interface Ethernet1/2 while leaving the rest of the file intact?
I've tried:
Appending the file with PyYAML but that just sticks the block of new variables on top of the YAML file..
Changing the variables with ruamel.yaml, but although it changes the variables, it removes all formatting from the YAML file and does not display the variables as a dict
First of all you cannot normally append to a YAML file, you have to read the file into a data structure, change (append, remove) the data structure, and then dump it back.
Second, you should not leave a file open unnecessarily while you go and do
other things. After doing yaml.load()
(whether in ruamel.yaml or in
PyYAML) the data is read, so you should exit the with statement, by dedenting your code
Your program doesn't change the data read into yaml_read
, so I tried some explicit changes:
import sys
import pprint
import ruamel.yaml
yaml = ruamel.yaml.YAML()
# yaml.indent(mapping=4, sequence=4, offset=2)
yaml.preserve_quotes = True
yaml.default_flow_style=None
interface = 'Ethernet1/1'
yaml_file_printout = pprint.PrettyPrinter(indent=2)
with open("interface.yaml", "r") as yaml_file:
data = yaml.load(yaml_file)
interface_count = 0
while True:
output_interface = data["interface_vars"][interface_count]["interface"]
if interface != output_interface:
interface_count += 1
elif interface == output_interface:
yaml_file_printout.pprint(data["interface_vars"][interface_count])
break
print('------')
yaml.dump(data, sys.stdout)
print('------')
data['interface_vars'][1]['access_vlan'] = 30
data['interface_vars'].append(dict(interface='Ethernet1/3', description='Test_interface_3', access_vlan='5'))
yaml.dump(data, sys.stdout)
which gives:
{ 'access_vlan': 10,
'description': 'Test_interface_1',
'interface': 'Ethernet1/1'}
------
interface_vars:
- {interface: Ethernet1/1, description: Test_interface_1, access_vlan: 10}
- {interface: Ethernet1/2, description: Test_interface_2, access_vlan: 20}
------
interface_vars:
- {interface: Ethernet1/1, description: Test_interface_1, access_vlan: 10}
- {interface: Ethernet1/2, description: Test_interface_2, access_vlan: 30}
- {interface: Ethernet1/3, description: Test_interface_3, access_vlan: '5'}
Instead of globally making leaf nodes flow-style (using
yaml.default_flow_style = None
) you can also wrap the dict that is
appended in a ruamel.yaml.comments.CommentedMap()
type for finer
control over how the data is dumped (there are some details on how to
do that here)
Also note that the officially recommended
extension
for YAML files has been .yaml
for over 13 years now.