Skip to main content

Tools for parsing & diffing RouterOS configuration files. Can produce config file patches.

Project description

Diff and prettify RouterOS configuration files

PyPI license PyPI pyversions Tests

Installation

Install using your favourite Python package manager. For example:

pip install routeros-diff

Get a diff

The routeros_diff (alias ros_diff) command will take two RouterOS files and diff them:

routeros_diff old_config.rsc new_config.rsc

Or using Python:

from routeros_diff.parser import RouterOSConfig
old = RouterOSConfig.parse(old_config_string)
new = RouterOSConfig.parse(new_config_string)
print(old.diff(new))

Examples:

A simple example first:

# Old:
/routing ospf instance
add name=core router-id=100.127.0.1

# New:
/routing ospf instance
add name=core router-id=100.127.0.99

# Diff:
/routing ospf instance
set [ find name=core ] router-id=100.127.0.99

Here is a more complex example where we use custom IDs in order to maintain expression ordering (see 'Natural Keys & IDs' below for details):

# Old:
/ip firewall nat 
add chain=a comment="Example text [ ID:1 ]"
add chain=c comment="[ ID:3 ]"

# New:
/ip firewall nat 
add chain=a comment="Example text [ ID:1 ]"
add chain=b comment="[ ID:2 ]"
add chain=c comment="[ ID:3 ]"

# Diff:
/ip firewall nat 
add chain=b comment="[ ID:2 ]" place-before=[ find where comment~ID:3 ]

Usage & limitations

This aim is for this diffing process to work well within a limited range of conditions. The configuration format is an entire scripting language in itself, and so this library cannot sensibly hope to parse any arbitrary input. As a rule of thumb, this library should be able to diff anything produced by /export.

Sections and expressions

The following is NOT supported:

## NOT SUPPORTED, DONT DO THIS ##
/routing ospf instance add name=core router-id=100.127.0.1

Rather, this must be formatted as separate 'sections' and 'expressions' on different lines. For example:

/routing ospf instance 
add name=core router-id=100.127.0.1

The section in this example is /routing ospf instance, and the expression is add name=core router-id=100.127.0.1. Each section may contain multiple expressions (just like the output you see from /export).

Natural Keys & IDs

The parser will try to uniquely identify each expression. This allows the parser to be intelligent regarding additions, modifications, deletions, and ordering.

The parser refers to these unique identities as naturals keys & natural IDs. For example:

add name=core router-id=100.127.0.1

Here the natural key is name and the natural ID is core. The parser assumes name will be the natural key, but is configured to use other keys in some situations (see NATURAL_KEYS).

Additionally, you can choose to manually add your own IDs to expressions. This is done using comments. For example:

add chain=a comment="[ ID:1 ]"

These comment-based IDs take priority over whatever the parser may have otherwise used. If using comment IDs, you should make sure you set them for all expressions in that section.

This is especially useful for firewall rules. The order of firewall rules is important, and they have no obvious natural keys/IDs. Using comments IDs for your firewall rules allows the parser to intelligently maintain order. For example:

# Old:
/ip firewall nat 
add chain=a comment="Example text [ ID:1 ]"
add chain=c comment="[ ID:3 ]"

# New:
/ip firewall nat 
add chain=a comment="Example text [ ID:1 ]"
add chain=b comment="[ ID:2 ]"
add chain=c comment="[ ID:3 ]"

# Diff:
/ip firewall nat 
add chain=b comment="[ ID:2 ]" place-before=[ find where comment~ID:3 ]

Note that the parser uses place-before to correctly place the new firewall rule.

Without using comment IDs, the parse would have to drop and recreate all firewall rules. This would be non-ideal for reasons of both security and reliability.

Reporting errors

Seeing something strange in your diff output? Please report the error with the following information:

  • The input
  • The actual output
  • What you think the output should be instead

Please minimise the size of this data as much as possible. The smaller and more specific the example of the problem, the easier it will be for us to find a resolution.

Prettify

The routeros_prettify (alias ros_prettify) command will parse an existing configuration and re-print it in a standard format with common sections collapsed:

routeros_prettify old_config.rsc new_config.rsc

Or using Python:

from routeros_diff.parser import RouterOSConfig
config = RouterOSConfig.parse(config_string)
print(config)

Concepts

This is a section with a path of /ip address and two expressions:

/ip address
add address=1.2.3.4
add address=5.6.7.8

This is an expression with a command of add, and a key-value argument of address=1.2.3.4:

add address=1.2.3.4

Release process:

export VERSION=a.b.c

poetry version $VERSION
dephell convert
black setup.py

git add .
git commit -m "Releasing version $VERSION"

git tag "v$VERSION"
git branch "v$VERSION"
git push origin \
    refs/tags/"v$VERSION" \
    refs/heads/"v$VERSION" \
    main

# Wait for CI to pass

poetry publish --build

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

routeros-diff-0.1.1.tar.gz (19.2 kB view details)

Uploaded Source

Built Distribution

routeros_diff-0.1.1-py3-none-any.whl (20.7 kB view details)

Uploaded Python 3

File details

Details for the file routeros-diff-0.1.1.tar.gz.

File metadata

  • Download URL: routeros-diff-0.1.1.tar.gz
  • Upload date:
  • Size: 19.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.4 CPython/3.8.5 Darwin/20.3.0

File hashes

Hashes for routeros-diff-0.1.1.tar.gz
Algorithm Hash digest
SHA256 166828931ad47add2cab50300593d7a8813aac0b65874e30019980a8abd67c22
MD5 e45d5415dedfb087ce0b8da3daa1329f
BLAKE2b-256 8335b39be7eced3a1aa5fb9313d89c62e7220a4529019413caf88c90bf9ef9ac

See more details on using hashes here.

File details

Details for the file routeros_diff-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: routeros_diff-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 20.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.4 CPython/3.8.5 Darwin/20.3.0

File hashes

Hashes for routeros_diff-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0dfb0438ac16055a61e2b7b6c8afcd88d07c1d4821f7283743f0c10ff2afb5cc
MD5 8eb450ff816249f9ce1bdaef4cf57364
BLAKE2b-256 cb12f28716871bbd280d36b949468ec099dc0b6f9e0f6d9f9205678490753232

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page