跳转到主要内容

用于解析和比较RouterOS配置文件的工具。可以生成配置文件补丁。

项目描述

为您的Mikrotik路由器创建配置补丁

PyPI license PyPI pyversions Tests

安装

使用您喜欢的Python包管理器进行安装。例如

pip install routeros-diff

获取差异

routeros_diff(别名ros_diff)命令将取两个RouterOS文件并进行比较

routeros_diff old_config.rsc new_config.rsc

或者使用Python

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

示例

首先是一个简单的示例

# 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

下面是一个更复杂的示例,我们使用自定义ID以保持表达式顺序(有关详细信息,请参阅下面的“自然键和ID”)

# Old:
/ip firewall nat 
add chain=a comment="Example text [ ID:block-smtp ]"
add chain=c comment="[ ID:block-smb ]"

# New:
/ip firewall nat 
add chain=a comment="Example text [ ID:block-smtp ]"
add chain=b comment="[ ID:block-nfs ]"
add chain=c comment="[ ID:block-smb ]"

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

使用和限制

本过程的目的是在有限范围内运行良好。配置格式本身就是一个完整的脚本语言,因此这个库无法合理地希望解析任何任意输入。作为一般规则,这个库应该能够比较由/export产生的任何内容。

高级使用

RouterOSConfig.parse还接受一个可选的第二个参数,如下所示

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

# Produced using: /export verbose
old_verbose = RouterOSConfig.parse(old_verbose_config_string)

print(new.diff(old, old_verbose))

提供old_verbose可以使比较算法在产生的比较中更智能。当提供old_verbose时,算法可以自动避免设置它知道未更改的某些值。这仅适用于以下情况:a)新的配置将参数设置回其默认值,b)旧的配置已经将参数设置为相同的值。

虽然这个特性不是生成有效比较所必需的,但它确实使生成没有不必要的表达式的比较变得更容易。换句话说,如果您想确保两个功能上相等的配置产生一个空比较,请使用此方法。

章节和表达式

以下内容不支持

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

相反,必须将它们格式化为不同的行上的单独的'章节'和'表达式'。例如

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

本例中的章节是 /routing ospf instance,表达式是 add name=core router-id=100.127.0.1。每个章节可以包含多个表达式(就像您从 /export 看到的输出一样)。

自然键与ID

解析器会尝试唯一地标识每个表达式。这使得解析器在添加、修改、删除和排序方面更加智能。

解析器将这些唯一标识称为自然键和自然ID。例如

add name=core router-id=100.127.0.1

在这里,自然键是 name,自然ID是 core。解析器假定 name 将是自然键,但在某些情况下配置为使用其他键。

此外,您可以选择手动将您自己的ID添加到表达式中。这是通过注释实现的。例如

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

这些基于注释的ID将优先于解析器可能使用的任何其他ID。如果您使用注释ID,请确保您为该章节中的所有表达式设置了它们。

这对于防火墙规则特别有用。防火墙规则的顺序很重要,它们没有明显的自然键/ID。使用注释ID对您的防火墙规则进行注释可以让解析器智能地维护顺序。例如

# Old:
/ip firewall nat 
add chain=a comment="Example text [ ID:block-smtp ]"
add chain=c comment="[ ID:block-smb ]"

# New:
/ip firewall nat 
add chain=a comment="Example text [ ID:block-smtp ]"
add chain=b comment="[ ID:block-nfs ]"
add chain=c comment="[ ID:block-smb ]"

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

请注意,解析器使用 place-before 正确放置新的防火墙规则。

如果不使用注释ID,解析器将不得不删除并重新创建所有防火墙规则。 这在安全性和可靠性方面都不是理想的选择。

报告错误

在您的diff输出中看到了奇怪的内容?请提供以下信息报告错误

  • 输入
  • 实际输出
  • 您认为的输出应该是

请尽可能缩小这些数据的大小。问题示例越小、越具体,我们找到解决方案就越容易。

美化

routeros_prettify(别名 ros_prettify)命令将解析现有配置,并以标准格式重新打印它,其中常见章节已折叠

routeros_prettify old_config.rsc new_config.rsc

或者使用Python

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

您还可以按照以下方式生成配置的语法高亮HTML版本(查看示例CSS

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

设置

您可以通过两种方式之一自定义设置。

最简单的方法是将设置传递给 RouterOSConfig.parse() 方法

RouterOSConfig.parse(s=my_config, settings=dict(
    # Natural keys for each section name.
    # 'name' will be used if none is found below
    # (and only if the 'name' value is available)
    natural_keys={
        "/ip address": "address", 
        ...
    },
    
    # Don't perform deletions in these sections
    no_deletions={
        "/interface ethernet", 
        ...
    },
    
    # Don't perform creations in these sections
    no_creations={
        "/interface ethernet",
        ...
    },
    
    # Ordering is important in these sections. Ensure 
    # entities maintain their order. Natural keys/ids must be 
    # present in sections listed here
    expression_order_important={
        "/ip firewall*", 
        ...
    },
))

请注意,可以使用 '*' 通配符指定章节路径。例如,/ip firewall*

或者,您可以通过扩展此类并重写其方法来自定义此类。如果需要,您可以在此处实现更复杂的逻辑。在这种情况下,您可以将自定义类传递给解析器,如下所示

RouterOSConfig.parse(my_config, settings=MyCustomSettings())

概念

这是一个路径为 /ip address章节,包含两个表达式

/ip address
add address=1.2.3.4
add address=5.6.7.8

这是一个具有 add 命令的 表达式,键值参数为 address=1.2.3.4

add address=1.2.3.4

发布流程

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

项目详情


下载文件

下载您平台上的文件。如果您不确定选择哪个,请了解更多关于 安装软件包 的信息。

源代码分发

routeros-diff-0.5.3.tar.gz (19.9 kB 查看哈希值)

上传时间

构建版本

routeros_diff-0.5.3-py3-none-any.whl (20.8 kB 查看哈希值)

上传时间 Python 3

由以下支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面