How to resolve internal variables with python yaml?

Viewed 5638

I have a file test.yml :

---
Servers:
  Server1:
    location: "Earth"
    network: {ip: "0.0.0.0", mac: "00:00:00:00:00:00"}
    inbound: "{{ Configs.Earth.allowed_connections }}"

  Server2:
    location: "Earth"
    network: {ip: "0.0.0.1", mac: "00:00:00:00:00:02"}
    inbound: "{{ Configs.Earth.allowed_connections }}"

  Server3:
    location: "Moon"
    network: {ip: "0.0.0.2", mac: "00:00:00:00:00:02"}

  Server4:
    location: "Mars"
    network: {ip: "0.0.0.3", mac: "00:00:00:00:00:03"}
    inbound: "{{ Configs.Mars.allowed_connections }}"

Configs:
  Earth:
    allowed_connections:
      - 99.99.99.99
      - 99.99.99.98
      - 99.99.99.97

  Mars:
    allowed_connections:
      - 88.99.99.99
      - 88.99.99.98
      - 88.99.99.97

I'd like to resolve the inbound variables when I load the yml file with python. Is there a way to do this natively? Or will I need to write a function that searches for any variables containing "{{ }}" and then reset them.

The solution needs to allow for varying depths that the variables could be located at.

I have no issues loading the file with yaml.load it's the variable resolution I'm struggling with

3 Answers

you can use Jinja template module here please see below example:

import yaml
from jinja2 import Environment

jsonobj = yaml.full_load(your_yaml_stream)
print jsonobj
print Environment().from_string(your_yaml_stream).render(jsonobj)

Output generated will be:

Servers:
  Server1:
    location: "Earth"
    network: {ip: "0.0.0.0", mac: "00:00:00:00:00:00"}
    inbound: "['99.99.99.99', '99.99.99.98', '99.99.99.97']"

  Server2:
    location: "Earth"
    network: {ip: "0.0.0.1", mac: "00:00:00:00:00:02"}
    inbound: "['99.99.99.99', '99.99.99.98', '99.99.99.97']"

  Server3:
    location: "Moon"
    network: {ip: "0.0.0.2", mac: "00:00:00:00:00:02"}

  Server4:
    location: "Mars"
    network: {ip: "0.0.0.3", mac: "00:00:00:00:00:03"}
    inbound: "['88.99.99.99', '88.99.99.98', '88.99.99.97']"

Configs:
  Earth:
    allowed_connections:
      - 99.99.99.99
      - 99.99.99.98
      - 99.99.99.97

  Mars:
    allowed_connections:
      - 88.99.99.99
      - 88.99.99.98
      - 88.99.99.97

You can use anchors/aliases for this.

Eg for a reduced version of your example

>>> import yaml
>>> doc = """
Configs: 
  Mars: 
    allowed_connections: &mars # Mark this as an anchor
      - 88.99.99.99 
      - 88.99.99.98 
      - 88.99.99.97 
Servers: 
  Server: 
    location: "Mars" 
    network: {ip: "0.0.0.3", mac: "00:00:00:00:00:03"} 
    inbound: *mars  # references the anchor here
"""
>>> from pprint import pprint # just for formatting
>>> pprint(yaml.load(doc))
{'Configs': {'Mars': {'allowed_connections': ['88.99.99.99',
                                              '88.99.99.98',
                                              '88.99.99.97']}},
 'Servers': {'Server': {'inbound': ['88.99.99.99',
                                    '88.99.99.98',
                                    '88.99.99.97'],
                        'location': 'Mars',
                        'network': {'ip': '0.0.0.3',
                                    'mac': '00:00:00:00:00:03'}}}}

Note that the config section has to be before the server section so that it can be referenced.

More examples here.

You can use regex for your function: ("(.*?)") It will find all words under quotes. You will just have to check if there is "Configs.Mars.allowed_connections" in the string.

Check this exemple of regex

Related