在 Jinja 2 中使用正则表达式来编写 ansible 剧本

using regex in jinja 2 for ansible playbooks

嗨,我是 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" 的值,我想评估使用哪些证书。 也就是说,如果域包含 "thinking" 关键字,则使用这些证书,如果它包含 "sleeping" 关键字,则使用该证书。

但没有找到任何支持此功能的 jinja2 过滤器。 请帮助 me.I 找到一些 python 代码并确定可以工作但是如何在 jinja2 模板中使用 python?

据我所知,Jinja2 和 Ansible 中都没有内置过滤器 extra filters,但是自己制作也没什么大不了的:

certs = {'.*thinking.*': 'akash', '.*sleeping.*': 'akashthakur'}
def map_regex(value, mapping=certs):
    for k, v in mapping.items():
        if re.match(k, value):
            return v 

然后你需要添加一个 filter plugin 到 Ansible,这样它就会在模板中使用上面的函数(如果你将过滤器命名为 ssl_cert 就像 {{server|ssl_cert}} )。

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

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

1. Jinja2 没有任何用于查找子字符串或正则表达式的过滤器,因此唯一的解决方案是创建自定义过滤器。我按照以下步骤解决了我的问题。

2. 在我的剧本的根目录中,我创建了一个目录 "filter_plugins" 并在 python 中编写了一个自定义模块并将文件放在该目录中。 python 文件的名称可以是任何名称。我的 python 代码如下所示:

 __author__ = 'akthakur'
class FilterModule(object):
    ''' Custom filters are loaded by FilterModule objects '''

    def filters(self):
        ''' Filter Module objects return a dict mapping filter names to filter functions. '''
        return {
            'substr': self.substr,
        }

        ''' def substr(self, check,checkin):
        return value1+value2'''
    def substr(self,check,checkin):
         if check in checkin:
            return True
         else:
            return False

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 %}

因此不需要您的子字符串正则表达式过滤器。但是,如果您想要更高级的正则表达式匹配,那么 are 实际上可以在 ansible 中使用过滤器 - 请参阅 http://docs.ansible.com/playbooks_filters.html#other-useful-filters 中的正则表达式过滤器 - 有趣的是,上面的匹配语法几乎完全相同对。

+1 for 不过,它以地图的形式提供了一个不错的选择。

Ansible>1.6

中有一个 "regex_replace" 过滤器可用

Other Useful Filters 向下滚动,您会看到:

New in version 1.6.

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

# 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 2.1 中有一些(当前)未记录的过滤器可以满足您的需要:
Ansible plugins/filter.core.py

regex_search 过滤器将对字符串执行正则表达式并 return 结果匹配。与此类似的东西可以工作并包含在 Ansible 角色中:

{% set server = 'www.thinkingmonster.com' %}
{% if regexp_search(server, 'thinking') %}
   do something...
{% endif %}

还有一个 regex_findall 过滤器执行 Python findall 搜索而不是正则表达式。

Review the original pull request for further information

这有点难看,但从 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. 提示,我找到了一种在模板条件中添加正则表达式的方法:

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