ansible filter_plugins插件实现jinja2自定义filter过滤器

简介:

前言:


   filter_plugins是什么? 这个单词拆解下,filter !  熟悉jinja2模板的人,到知道他是过滤器,可以在模板中以管道的方式用pyhton的代码处理字符串。 ansible模板调用的是jinja2,这个大家都知道 。 这个filter_plugins插件代码,就是为了更好的处理jinja2模板中的字符串和逻辑判断的。 先前,我和沈灿讨论一个模板的问题,实在蛋疼的要命,总是达不到我们要的数据,当时是做一个数据的统计和rabbitmq的配置,有些地方用jinja2模板自身的语法,处理起来实在是费劲, 用了多级{% set %}和各种length 。 其实一开始我就想用jinja2的filter,结果没看到相应的文档说明。 原来还计划着,在纠结下ansible template的代码,把jinja2的过滤器搞进去,要是不成功,自己外置一个api做处理。 看来,ansible那帮人,把能想到的东西都给做了。

    这两天又看了下文档,发现讲插件的list里面有个filter_plugins,然后看了下说明,果然是他 ! 


更多的有关ansible的文章,请移步到 http://xiaorui.cc


ansible支持jinja2中默认的内置过滤器用法的,这些是一部分 ! 具体的每个功能我就不详细说了,大家自己测测就知道用途了。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
abs(number)
绝对值
 
attr(obj, name)
属性
 
 
{{ my_variable|default( 'my_variable is not defined' ) }}
如果没有值,可以定义默认的
 
 
 
{%  for  item  in  mydict|dictsort %}
     sort  the dict by key,  case  insensitive
 
{%  for  item  in  mydict|dictsort( true ) %}
     sort  the dict by key,  case  sensitive
 
{%  for  item  in  mydict|dictsort( false 'value' ) %}
     sort  the dict by key,  case  insensitive, sorted
     normally and ordered by value.
escape(s)
安全的代码模式
 
 
first( seq )
第一个
 
float(value, default=0.0)
浮点型
 
forceescape(value)
强制html转义
 
 
indent(s, width=4, indentfirst=False)
 
 
{{ mytext|indent(2,  true ) }}
 
 
{{ [1, 2, 3]| join ( '|' ) }}
     -> 1|2|3
 
{{ [1, 2, 3]| join  }}
     -> 123
 
 
{{  users | join ( ', ' , attribute= 'username' ) }}
 
 
last( seq )
Return the last item of a sequence.
 
length(object)
Return the number of items of a sequence or mapping.
 
 
lower(s)
Convert a value to lowercase.
 
 
 
random( seq )
Return a random item from the sequence.
 
reject()
Filters a sequence of objects by appying a  test  to the object and rejecting the ones with the  test  succeeding.
 
Example usage:
 
{{ numbers|reject( "odd" ) }}
New  in  version 2.7.
 
rejectattr()
Filters a sequence of objects by appying a  test  to an attribute of an object or the attribute and rejecting the ones with the  test  succeeding.
 
{{  users |rejectattr( "is_active" ) }}
{{  users |rejectattr( "email" "none" ) }}
New  in  version 2.7.
 
replace(s, old, new, count=None)
 
 
{{  "Hello World" |replace( "Hello" "Goodbye" ) }}
     -> Goodbye World
 
{{  "aaaaargh" |replace( "a" "d'oh, " , 2) }}
     -> d 'oh, d' oh, aaargh
 
round(value, precision=0, method= 'common' )
 
 
{{ 42.55|round }}
     -> 43.0
{{ 42.55|round(1,  'floor' ) }}
     -> 42.5
Note that even  if  rounded to 0 precision, a float is returned. If you need a real integer, pipe it through int:
 
{{ 42.55|round|int }}
     -> 43
safe(value)
Mark the value as safe  which  means that  in  an environment with automatic escaping enabled this variable will not be escaped.
 
select ()
Filters a sequence of objects by appying a  test  to the object and only selecting the ones with the  test  succeeding.
 
Example usage:
 
{{ numbers| select ( "odd" ) }}
{{ numbers| select ( "odd" ) }}
New  in  version 2.7.
 
selectattr()
 
 
Example usage:
 
{{  users |selectattr( "is_active" ) }}
{{  users |selectattr( "email" "none" ) }}
 
{%  for  item  in  iterable| sort  %}
     ...
{% endfor %}
It is also possible to  sort  by an attribute ( for  example to  sort  by the  date  of an object) by specifying the attribute parameter:
 
{%  for  item  in  iterable| sort (attribute= 'date' ) %}
     ...
{% endfor %}
Changed  in  version 2.6: The attribute parameter was added.
 
string(object)
Make a string unicode  if  it isn’t already. That way a markup string is not converted back to unicode.
 
 
upper(s)
Convert a value to uppercase.
 
urlencode(value)
Escape strings  for  use  in  URLs (uses UTF-8 encoding). It accepts both dictionaries and regular strings as well as pairwise iterables.
 
wordcount(s)
个数


下面是实现自定义的jinja2 filter的代码。 里面已经实现了调用ansible的template的时候,有可能会用到的filter过滤器。

原文: http://rfyiamcool.blog.51cto.com/1030776/1440686 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
#xiaorui.cc
 
import  base64
import  json
import  os.path
import  yaml
import  types
import  pipes
import  glob
import  re
import  operator as py_operator
from ansible  import  errors
from ansible.utils  import  md5s
from distutils.version  import  LooseVersion, StrictVersion
from random  import  SystemRandom
from jinja2.filters  import  environmentfilter
 
def to_nice_yaml(*a, **kw):
     '' 'Make verbose, human readable yaml' ''
     return  yaml.safe_dump(*a, indent=4, allow_unicode=True, default_flow_style=False, **kw)
 
def to_json(a, *args, **kw):
     '' ' Convert the value to JSON ' ''
     return  json.dumps(a, *args, **kw)
 
def to_nice_json(a, *args, **kw):
     '' 'Make verbose, human readable JSON' ''
     return  json.dumps(a, indent=4, sort_keys=True, *args, **kw)
 
def failed(*a, **kw):
     '' ' Test if task result yields failed ' ''
     item = a[0]
     if  type (item) != dict:
         raise errors.AnsibleFilterError( "|failed expects a dictionary" )
     rc = item.get( 'rc' ,0)
     failed = item.get( 'failed' ,False)
     if  rc != 0 or failed:
         return  True
     else :
         return  False
 
def success(*a, **kw):
     '' ' Test if task result yields success ' ''
     return  not failed(*a, **kw)
 
def changed(*a, **kw):
     '' ' Test if task result yields changed ' ''
     item = a[0]
     if  type (item) != dict:
         raise errors.AnsibleFilterError( "|changed expects a dictionary" )
     if  not  'changed'  in  item:
         changed = False
         if  ( 'results'  in  item     # some modules return a 'results' key
                 and  type (item[ 'results' ]) == list
                 and  type (item[ 'results' ][0]) == dict):
             for  result  in  item[ 'results' ]:
                 changed = changed or result.get( 'changed' , False)
     else :
         changed = item.get( 'changed' , False)
     return  changed
 
def skipped(*a, **kw):
     '' ' Test if task result yields skipped ' ''
     item = a[0]
     if  type (item) != dict:
         raise errors.AnsibleFilterError( "|skipped expects a dictionary" )
     skipped = item.get( 'skipped' , False)
     return  skipped
 
def mandatory(a):
     '' ' Make a variable mandatory ' ''
     try:
         a
     except NameError:
         raise errors.AnsibleFilterError( 'Mandatory variable not defined.' )
     else :
         return  a
 
def bool(a):
     '' ' return a bool for the arg ' ''
     if  a is None or  type (a) == bool:
         return  a
     if  type (a)  in  types.StringTypes:
         a = a.lower()
     if  in  [ 'yes' 'on' '1' 'true' , 1]:
         return  True
     else :
         return  False
 
def quote(a):
     '' ' return its argument quoted for shell usage ' ''
     return  pipes.quote(a)
 
def fileglob(pathname):
     '' ' return list of matched files for glob ' ''
     return  glob.glob(pathname)
 
def regex(value= '' , pattern= '' , ignorecase=False, match_type= 'search' ):
     '' ' Expose `re` as a boolean filter using the `search` method by default.
         This is likely only useful  for  `search` and `match`  which  already
         have their own filters.
     '' '
     if  ignorecase:
         flags = re.I
     else :
         flags = 0
     _re = re.compile(pattern, flags=flags)
     _bool = __builtins__.get( 'bool' )
     return  _bool(getattr(_re, match_type,  'search' )(value))
 
def match(value, pattern= '' , ignorecase=False):
     '' ' Perform a `re.match` returning a boolean ' ''
     return  regex(value, pattern, ignorecase,  'match' )
 
def search(value, pattern= '' , ignorecase=False):
     '' ' Perform a `re.search` returning a boolean ' ''
     return  regex(value, pattern, ignorecase,  'search' )
 
def regex_replace(value= '' , pattern= '' , replacement= '' , ignorecase=False):
     '' ' Perform a `re.sub` returning a string ' ''
 
     if  not isinstance(value, basestring):
         value = str(value)
 
     if  ignorecase:
         flags = re.I
     else :
         flags = 0
     _re = re.compile(pattern, flags=flags)
     return  _re.sub(replacement, value)
 
def unique(a):
     return  set (a)
 
def intersect(a, b):
     return  set (a).intersection(b)
 
def difference(a, b):
     return  set (a).difference(b)
 
def symmetric_difference(a, b):
     return  set (a).symmetric_difference(b)
 
def union(a, b):
     return  set (a).union(b)
 
def version_compare(value, version, operator= 'eq' , strict=False):
     '' ' Perform a version comparison on a value ' ''
     op_map = {
         '==' 'eq' '=' :   'eq' 'eq' 'eq' ,
         '<' :   'lt' 'lt' 'lt' ,
         '<=' 'le' 'le' 'le' ,
         '>' :   'gt' 'gt' 'gt' ,
         '>=' 'ge' 'ge' 'ge' ,
         '!=' 'ne' '<>' 'ne' 'ne' 'ne'
     }
 
     if  strict:
         Version = StrictVersion
     else :
         Version = LooseVersion
 
     if  operator  in  op_map:
         operator = op_map[operator]
     else :
         raise errors.AnsibleFilterError( 'Invalid operator type' )
 
     try:
         method = getattr(py_operator, operator)
         return  method(Version(str(value)), Version(str(version)))
     except Exception, e:
         raise errors.AnsibleFilterError( 'Version comparison: %s'  % e)
 
@environmentfilter
def rand(environment, end, start=None, step=None):
     r = SystemRandom()
     if  isinstance(end, (int, long)):
         if  not start:
             start = 0
         if  not step:
             step = 1
         return  r.randrange(start, end, step)
     elif  hasattr(end,  '__iter__' ):
         if  start or step:
             raise errors.AnsibleFilterError( 'start and step can only be used with integer values' )
         return  r.choice(end)
     else :
         raise errors.AnsibleFilterError( 'random can only be used on sequences and integers' )
 
class FilterModule(object):
     '' ' Ansible core jinja2 filters ' ''
 
     def filters(self):
         return  {
             # base 64
             'b64decode' : base64.b64decode,
             'b64encode' : base64.b64encode,
 
             # json
             'to_json' : to_json,
             'to_nice_json' : to_nice_json,
             'from_json' : json.loads,
 
             # yaml
             'to_yaml' : yaml.safe_dump,
             'to_nice_yaml' : to_nice_yaml,
             'from_yaml' : yaml.safe_load,
 
             # path
             'basename' : os.path. basename ,
             'dirname' : os.path. dirname ,
             'expanduser' : os.path.expanduser,
             'realpath' : os.path.realpath,
             'relpath' : os.path.relpath,
 
             # failure testing
             'failed'   : failed,
             'success'  : success,
 
             # changed testing
             'changed'  : changed,
 
             # skip testing
             'skipped'  : skipped,
 
             # variable existence
             'mandatory' : mandatory,
 
             # value as boolean
             'bool' : bool,
 
             # quote string for shell usage
             'quote' : quote,
 
             # md5 hex digest of string
             'md5' : md5s,
 
             # file glob
             'fileglob' : fileglob,
 
             # regex
             'match' : match,
             'search' : search,
             'regex' : regex,
             'regex_replace' : regex_replace,
 
             # list
             'unique'  : unique,
             'intersect' : intersect,
             'difference' : difference,
             'symmetric_difference' : symmetric_difference,
             'union' : union,
 
             # version comparison
             'version_compare' : version_compare,
 
             # random numbers
             'random' : rand,
         }



模板的代码,这里只是做个测试而已。模板里面的变量不是从外面引入的,是我自己设的变量。


原文: http://rfyiamcool.blog.51cto.com/1030776/1440686 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
this is ceshi
{%  set  list1 = [1,2,3,4,5,6,7,8,9,10] %}
 
{%  for  in  list1 %}
     {{ i  }}
{% endfor %}
{{ list1|to_nice_yaml }}
 
{%  set  list2 = [ 'k_1' , 'k_2' , 'k_3' ] %}
 
to_replace .....
 
{%  for  in  list2 %}
     {{ i|to_replace  }}
{% endfor %}


wKioL1PL7xnAJwxpAAMl37ayClo826.jpg


这里是结果,可以看到咱们搞的那两个过滤器成功执行了。 

wKioL1PL7yOyvBxdAAJylh0LJAQ496.jpg

原文: http://rfyiamcool.blog.51cto.com/1030776/1440686 


ansible有个filter_plugins插件利器,在使用jinja2模板渲染数据的时候,就更加的方便了 !!!







 本文转自 rfyiamcool 51CTO博客,原文链接:http://blog.51cto.com/rfyiamcool/1440686 ,如需转载请自行联系原作者

相关文章
|
运维 Kubernetes 网络安全
Ansible自动化运维工具之主机管理与自定义配置文件(2)
Ansible自动化运维工具之主机管理与自定义配置文件(2)
147 0
|
Shell 项目管理
ansible之when条件语法、处理任务失败、jinja2模板和项目管理
ansible之when条件语法、处理任务失败、jinja2模板和项目管理
135 0
|
运维 负载均衡 应用服务中间件
【运维知识进阶篇】Ansible Jinja2模板详解
【运维知识进阶篇】Ansible Jinja2模板详解
319 0
Ansible 自定义变量与 role 默认变量的合并方法
如果你遇到 failed to combine variables, expected dicts but got a &#39;NoneType&#39; and a &#39;dict&#39; 这样的报错,你可以看看本文。
328 0
|
26天前
|
运维 应用服务中间件 Linux
自动化运维的利器:Ansible在配置管理中的应用
【10月更文挑战第39天】本文旨在通过深入浅出的方式,向读者展示如何利用Ansible这一强大的自动化工具来优化日常的运维工作。我们将从基础概念讲起,逐步深入到实战操作,不仅涵盖Ansible的核心功能,还会分享一些高级技巧和最佳实践。无论你是初学者还是有经验的运维人员,这篇文章都会为你提供有价值的信息,帮助你提升工作效率。