Python 在Jinja2中使用正则表达式生成ansible剧本

Python 在Jinja2中使用正则表达式生成ansible剧本,python,regex,jinja2,ansible,ansible-playbook,Python,Regex,Jinja2,Ansible,Ansible Playbook,您好,我是jinja2的新手,尝试使用正则表达式,如下所示 {% if ansible_hostname == 'uat' %} {% set server = 'thinkingmonster.com' %} {% else %} {% set server = 'define yourself' %} {% endif %} {% if {{ server }} match('*thinking*') %} {% set ssl_certificate = 'akash'

您好,我是jinja2的新手,尝试使用正则表达式,如下所示

{% if ansible_hostname == 'uat' %}
   {% set server = 'thinkingmonster.com' %}

{% else %}
   {% set server = 'define yourself' %}
{% endif %}

{% if {{ server }} match('*thinking*') %}
  {% set ssl_certificate = 'akash' %}

{% elif {{ server }} match( '*sleeping*')%}
   {% set ssl_certificate = 'akashthakur' %}
{% endif %}
根据“server”的值,我想评估使用哪些证书。 ie若域包含“thinking”关键字,则使用这些证书;若域包含“sleeping”关键字,则使用该证书

但没有发现任何jinja2过滤器支持这一点。
请帮帮我。我找到了一些python代码,并确信它们可以工作,但如何在jinja2模板中使用python?

据我所知,jinja2中也没有内置过滤器,Ansible中也没有,但创建自己的过滤器没什么大不了的:

certs = {'.*thinking.*': 'akash', '.*sleeping.*': 'akashthakur'}
def map_regex(value, mapping=certs):
    for k, v in mapping.items():
        if re.match(k, value):
            return v 
然后,您需要向Ansible添加一个,以便它在模板中使用上面的函数(如
{{server | ssl_cert}}
如果您命名过滤器
ssl_cert


也就是说,传递给模板并在模板中显式使用的普通旧函数或普通旧字典可能更适合这项工作。

因此,在谷歌搜索了很长一段时间后,在一些博客的帮助下,这里是我问题的最终解决方案:-

1。Jinja2没有任何用于查找子字符串或regexp的筛选器,因此唯一的解决方案是创建自定义筛选器。我按照以下步骤来解决问题

2。在我的playbook的根目录中,我创建了一个目录“filter\u plugins”,并用python编写了一个自定义模块,并将文件放在这个目录中。python文件的名称可以是任何内容。我的python代码如下所示:

\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
类FilterModule(对象):
''自定义筛选器由FilterModule对象''加载'
def过滤器(自):
''过滤器模块对象返回将过滤器名称映射到过滤器函数的dict。''
返回{
“substr”:self.substr,
}
''def substr(自我、签入、签入):
返回值1+2''
def substr(自我、签入、签入):
如果签入签入:
返回真值
其他:
返回错误
3。创建此文件后,我们全新的过滤器“substr”即可使用,并可在模板内使用,如下所示:

{% if 5==5 %}
 {% set server = 'www.thinkingmonster.com' %}
{% endif %}
{% if 'thinking' | substr(server) %}
   {% set ssl_cert = 'abc.crt'%}
{% endif %}

Jinja2可以很容易地通过简单的“in”比较进行substr检查,例如

{% set server = 'www.thinkingmonster.com' %}
{% if 'thinking' in server %}
   do something...
{% endif %}
因此不需要子字符串正则表达式过滤器。然而,如果您想要更高级的正则表达式匹配,那么ansible中实际上有可用的过滤器-请参阅中的正则表达式过滤器-有趣的是,您上面的匹配语法几乎完全正确

+1尽管如此,它以映射的形式提供了一个很好的替代方案。

Ansible>1.6中提供了一个“regex\u replace”过滤器

向下滚动,您将看到以下内容:

版本1.6中的新功能

要使用正则表达式替换字符串中的文本,请使用“正则表达式替换”筛选器:

# convert "ansible" to "able"
{{ 'ansible' | regex_replace('^a.*i(.*)$', 'a\\1') }}

# convert "foobar" to "bar"
{{ 'foobar' | regex_replace('^f.*o(.*)$', '\\1') }}

# convert "localhost:80" to "localhost, 80" using named groups
{{ 'localhost:80' | regex_replace('^(?P<host>.+):(?P<port>\\d+)$', '\\g<host>, \\g<port>') }}
#将“ansible”转换为“able”
{{'ansible'| regex_replace('^a.*i(.*)$','a\\1')}
#将“foobar”转换为“bar”
{{'foobar'| regex_replace('^f.*o(.*)','\\1')}
#使用命名组将“localhost:80”转换为“localhost,80”
{{'localhost:80'| regex_replace('^(?P.+):(?P\\d+$,'\\g,\\g')}
话虽如此,正则表达式对于找到这个特定问题的解决方案来说是一种过分的手段。

Ansible 2.1中有一些(目前)未记录的过滤器,它们可以满足您的需要:

regex\u搜索过滤器将对字符串执行正则表达式并返回结果匹配。类似于此的内容将起作用,并包含在Ansible角色中:

{% set server = 'www.thinkingmonster.com' %}
{% if regexp_search(server, 'thinking') %}
   do something...
{% endif %}
还有一个regex_findall过滤器,它执行Python findall搜索而不是regex


这相当难看,但它从1.6版开始工作

{% if server|regex_replace('.*thinking.*','matched') == 'matched' %}
  {% set ssl_certificate = 'akash' %}

{% elif server|regex_replace('.*sleeping.*','matched') == 'matched' %}
   {% set ssl_certificate = 'akashthakur' %}
{% endif %}

感谢Steve E.hint,我找到了一种在模板条件下添加正则表达式的方法:

{% if server | regex_search('thinking') %}
....
{% endif %}

只是为了确保我理解正确:您想要一个筛选器,根据它匹配的正则表达式映射一个值吗?@bereal是的,这就是我想要的。但是不能这样做{%if{{server}}match('thinking')%%{%set ssl_certificate='akash'}如果serve的值包含thinking关键字,那么ssl_证书的值应该是'akash',为什么jinja2没有用于检查子字符串的筛选器。这就解决了我的问题。有什么原因不能只将服务器名称映射到ssl证书吗?当尝试将此技术与Ansible 2.2结合使用时,我得到
AnsibleUndefinedVariable:'regex_search'是未定义
我的坏消息。我使用的是Ansible 2.1,2.2regex_搜索在Ansible 2.2.1.0上发布了“'regex_搜索'未定义”。我在使用Ansible 2.3.1.0的
regex_搜索
regex_搜索
中都得到了未定义的错误。请注意,这个答案非常过时,Ansible now中有regex过滤器:尽管这对于这个问题来说有些过分,但还是感谢您回答这个问题——因为我来这里是为了一个不同的问题问同一个问题!;)