Examples

Runcible Simple

Runcible Simple is an example DB that shows how MergeDB can be used to generate Runcible network configurations.

The base mdb.yaml definition in the root directory has the following contents:

---
knockout: '~'
merge_rules:
  keyed_array:
    - path: []
      attribute: 'vlans'
      key: 'id'
    - path: []
      attribute: 'interfaces'
      key: 'name'

The knockout attribute allows layers to stop the inheritance of attributes and keys from higher layers.

We also have two keyed_array merge rules. These override the default simple_array_merge_nodup strategy for lists. We define these rules by specifying the path (In this case, there is no path, as they are top level keys), the attribute to match, and a key to inform the keyed_array strategy of which key to use to associate inherited items.

This example has two buildable declarations, switch1.yaml and switch2.yaml, both located in Cumulus_Switches.

# Cumulus_Switches/switch1.yaml
---
meta:
  device:
    ssh:
      hostname: 192.168.122.41
    default_management_protocol: ssh
    driver: cumulus
  system:
    hostname: switch1
# Cumulus_Switches/switch2.yaml
---
meta:
  device:
    ssh:
      hostname: 192.168.122.42
    default_management_protocol: ssh
    driver: cumulus
  system:
    hostname: switch2

These files only include content, in this case they define runcible layers.

This directory has a dir.yaml override as well:

# Cumulus_Switches/dir.yaml
---
build:
  - switch1.yaml
  - switch2.yaml
inherit:
  - Roles/ssh_creds.yaml
  - Roles/vlans.yaml
  - Roles/Switch_Classes/spine.yaml

This file does two things, firstly it specifies that switch1 and switch2 are to be built when mergedb runs. Secondly, it defines some inherited layers for both built items. Note that the path for the inherit attribute is relative to the root directory, not the current directory.

Note

inherit only applies to built configs in the current directory, it does not include any intermediate layers.

Now lets examine the other directories where the layers are stored. In all of the other directories, we have a blank dir.yaml file that simply lets MergeDB know that there is content it should index in those directories. Then we have several intermediate non-built declarations.

# Roles/ssh_creds.yaml
---
meta:
  device:
    ssh:
      username: cumulus
      password: CumulusLinux!

This file is just content, once again a runcible layer.

# Roles/vlans.yaml
---
vlans:
  {% for i in range(1,6) %}
  - id: {{ i }}
    name: vlan{{ i }}
  {% endfor %}
# Roles/Switch_Classes/spine.yaml
{% set vlans = [1,2,3,4,5]%}
---
interfaces:
  {% for i in range(1,3) %}
  - name: swp{{ i }}
    vlans: {{ vlans }}
    portfast: False
    mtu: 9000
  {% endfor %}
vlans:
  - id: 1
    name: changed_name

These files are also content, but they have some jinja2 templating, to reduce the amount of boilerplate inside the layer.

The spine.yaml is also in a subdirectory of roles, this doesn’t affect the behavior of Runcible at all, and is just to show that the user is able to define the directory structure that makes sense for the data that they are organizing.

The result of running mergedb examples/runcible_simple build on this database is:

switch1:
  interfaces:
  - mtu: 9000
    name: swp1
    portfast: false
    vlans:
    - 1
    - 2
    - 3
    - 4
    - 5
  - mtu: 9000
    name: swp2
    portfast: false
    vlans:
    - 1
    - 2
    - 3
    - 4
    - 5
  meta:
    device:
      default_management_protocol: ssh
      driver: cumulus
      ssh:
        hostname: 192.168.122.41
        password: CumulusLinux!
        username: cumulus
    system:
      hostname: switch1
  vlans:
  - id: 1
    name: changed_name
  - id: 2
    name: vlan2
  - id: 3
    name: vlan3
  - id: 4
    name: vlan4
  - id: 5
    name: vlan5
switch2:
  interfaces:
  - mtu: 9000
    name: swp1
    portfast: false
    vlans:
    - 1
    - 2
    - 3
    - 4
    - 5
  - mtu: 9000
    name: swp2
    portfast: false
    vlans:
    - 1
    - 2
    - 3
    - 4
    - 5
  meta:
    device:
      default_management_protocol: ssh
      driver: cumulus
      ssh:
        hostname: 192.168.122.42
        password: CumulusLinux!
        username: cumulus
    system:
      hostname: switch2
  vlans:
  - id: 1
    name: changed_name
  - id: 2
    name: vlan2
  - id: 3
    name: vlan3
  - id: 4
    name: vlan4
  - id: 5
    name: vlan5

One of the important things to note, is that due to the merge rules specified in mdb.yaml, the name of vlan1 was overridden by the contents of spine.yaml, but it’s entry was not duplicated as keyed_array_merge identified the duplicate via the key specified in the rule and merged them.