YAML Refresher
Some salient points about YAML:
YAML stands for Yet Another Markup Language.
Just like JSON and XML it helps to solve the problem that we face with transfer/storage of program data like python dictionaries and other pythonic objects.
YAML provides us one more way to serialize data.
Serialization: Whenever we must store/transfer data which will either be processed by our own computers program at a later stage or will be transferred to another computer where it will be processed by a program on that computer, we have to use some kind of formatted way to store this data to make it understandable by a programming language. This process is called Serialization.
YAML becomes an even better choice when humans are involved in the process because YAML provides us with a much more human readable/easily editable way to create and use data.
Because of the above reason it has become an important part of the automation tools like Ansible and Salt Stack.
Let’s create some YAML documents and learn more about its specifics.
The file extension for YAML files can be both ‘.yml’ or ‘.yaml’
1. Let’s store a few ip addresses in the file as a list.
YAML File: Yaml_file_1.yml
---
# Three hyphens at the top are mandatory and are used to signify the start of a YAML file.
- 1.1.1.1 # The space after the hyphen is mandatory and proper spacing is very important in YAML file.
- 2.2.2.2 # Another thing to notice here is that these ip addss' are being input as strings but I did not have to use any quotes("")
- 192.168.25.11
- 192.168.25.12
Let’s now work with this file in python.
Library to work with yaml in python: pyyaml
It can installed using the command: pip install pyyaml
Python Script: Yaml_read_1.py
import yaml
yaml_file = r'Yaml_file_1.yml'
with open(yaml_file) as f:
output = yaml.safe_load(f)
print(output)
print(type(output))
Output:
['1.1.1.1', '2.2.2.2', '192.168.25.11', '192.168.25.12']
<class 'list'>
We just created a list in yaml.
2. Now, let’s learn how to create a dictionary in yaml.
YAML File: Yaml_file_2.yml
---
rtr1: 1.1.1.1 # We used a ': '(colon + space) in between the key and value pair just like we do in python dictionary.
rtr2: 2.2.2.2
rtr3: 192.168.25.11
Let’s now work with this file in python.
import yaml
yaml_file = r'C:\Users\admin\5_day_program\DAY2\Yaml_file_2.yml'
with open(yaml_file) as f:
output = yaml.safe_load(f)
print(output)
print(type(output))
# For Dictionary
print(output['rtr1'])
print(output['rtr2'])
Output:
{'rtr1': '1.1.1.1', 'rtr2': '2.2.2.2', 'rtr3': '192.168.25.11'} # We see that the key and values are of string type and we did not have to use any kind of quotes in the YAML file to acheive that.
<class 'dict'>
1.1.1.1
2.2.2.2
3. There are certain cases where we might have to use quotes to define a string.
YAML File: Yaml_file_3.yml
---
rtr1: 1.1.1.1
rtr2: 2.2.2.2
rtr3: We can have longer strings like these.
rtr4: "We can write longer strings with quotes as well and result will look the same."
rtr5: "{If we have special characters like these, it becomes mandatory to use quotes.}"
[! NOTE]: Omitted the Python script as nothing signifact changed there except the file name.
Output:
{'rtr1': '1.1.1.1', 'rtr2': '2.2.2.2', 'rtr3': 'We can have longer strings like these.', 'rtr4': 'We can write longer strings with quotes as well and result will look the same.', 'rtr5': '{If we have special characters like these, it becomes mandatory to use quotes.}'}
<class 'dict'>
4. There are also multiple ways we can define boolean values.
YAML File: Yaml_file_4.yml
---
rtr1: 1.1.1.1
rtr2: 2.2.2.2
rtr3: True
rtr4: False
rtr5: true # Also Boolean True
rtr6: false # Also Boolean False
rtr7: yes # Also Boolean True
rtr8: no # Also Boolean False
rtr9: on # Also Boolean True
rtr10: off # Also Boolean False
Output:
{'rtr1': '1.1.1.1', 'rtr2': '2.2.2.2', 'rtr3': True, 'rtr4': False, 'rtr5': True, 'rtr6': False, 'rtr7': True, 'rtr8': False, 'rtr9': True, 'rtr10': False}
<class 'dict'>
5. How to create <key: value> pairs where the value itself is a dictionary.
YAML File: Yaml_file_5.yml
---
rtr1:
device_type: cisco_ios # The two space indentation at the front is mandatory to indicate that all the data at that level of indentation belongs/corresponds to the value of the key(rtr1).
host: 1.1.1.1
username: admin
password: admin
rtr2:
device_type: juniper_junos
host: 2.2.2.2
username: admin
password: admin
Output:
{'rtr1': {'device_type': 'cisco_ios', 'host': '1.1.1.1', 'username': 'admin', 'password': 'admin'},
'rtr2': {'device_type': 'juniper_junos', 'host': '2.2.2.2', 'username': 'admin', 'password': 'admin'}}
<class 'dict'>
6. Let’s look at even further levels of indentation.
YAML File: Yaml_file_6.yml
---
rtr1:
device_type: cisco_ios
host: 1.1.1.1
username: admin
password: admin
neighbors: # We put the list elements at a further level of indentation.
- 192.168.25.11
- 192.168.25.12 # Expanded way to insert a list.
- 192.168.26.13
rtr2:
device_type: juniper_junos
host: 2.2.2.2
username: admin
password: admin
neighbors: [192.168.24.11, 192.168.24.12, 192.168.25.13] # Compressed way to insert a list.
rtr3: {host: 3.3.3.3} # Compressed way to insert a dictionary.
Output:
{'rtr1': {'device_type': 'cisco_ios', 'host': '1.1.1.1', 'username': 'admin', 'password': 'admin', 'neighbors': ['192.168.25.11', '192.168.25.12', '192.168.26.13']}, 'rtr2': {'device_type': 'juniper_junos', 'host': '2.2.2.2', 'username': 'admin', 'password': 'admin', 'neighbors': ['192.168.24.11', '192.168.24.12', '192.168.25.13']}, 'rtr3': {'host': '3.3.3.3'}}
<class 'dict'>
# Pretty printing the above data.
{'rtr1': {'device_type': 'cisco_ios',
'host': '1.1.1.1',
'neighbors': ['192.168.25.11', '192.168.25.12', '192.168.26.13'],
'password': 'admin',
'username': 'admin'},
'rtr2': {'device_type': 'juniper_junos',
'host': '2.2.2.2',
'neighbors': ['192.168.24.11', '192.168.24.12', '192.168.25.13'],
'password': 'admin',
'username': 'admin'},
'rtr3': {'host': '3.3.3.3'}}
Using Python to create YAML documents from pythonic data objects.
Python Script: Yaml_write_1.py
import yaml
device_detail_dict = {
'rtr1': {
'device_type': 'cisco_ios',
'host': '1.1.1.1',
'neighbors': ['192.168.25.11', '192.168.25.12', '192.168.26.13'],
'password': 'admin',
'username': 'admin'},
'rtr2': {
'device_type': 'juniper_junos',
'host': '2.2.2.2',
'neighbors': ['192.168.24.11', '192.168.24.12', '192.168.25.13'],
'password': 'admin',
'username': 'admin'},
'rtr3': {'host': '3.3.3.3'}
}
output_file = 'Yaml_output.yml'
with open(output_file, 'w') as f:
# With default_flow_style equal to True
output = yaml.dump(device_detail_dict, f, default_flow_style=True)
Output in file(Yaml_output.yml):
{rtr1: {device_type: cisco_ios, host: 1.1.1.1, neighbors: [192.168.25.11, 192.168.25.12,
192.168.26.13], password: admin, username: admin}, rtr2: {device_type: juniper_junos,
host: 2.2.2.2, neighbors: [192.168.24.11, 192.168.24.12, 192.168.25.13], password: admin,
username: admin}, rtr3: {host: 3.3.3.3}}
# With default_flow_style equal to False
output = yaml.dump(device_detail_dict, f, default_flow_style=False)
Output in file(Yaml_output.yml):
rtr1:
device_type: cisco_ios
host: 1.1.1.1
neighbors:
- 192.168.25.11
- 192.168.25.12
- 192.168.26.13
password: admin
username: admin
rtr2:
device_type: juniper_junos
host: 2.2.2.2
neighbors:
- 192.168.24.11
- 192.168.24.12
- 192.168.25.13
password: admin
username: admin
rtr3:
host: 3.3.3.3
Another additional option that YAML provides that is lacking in JSON files is the ability to add comments.
We can put a ‘#’ Anywhere in the file and add a comment after that.
