开源中文网

您的位置: 首页 > Linux内核 > 正文

ansible 自定义filter_plugins的用法

来源: 网络整理  作者: 佚名

ansible playbook 一个非常强大的功能就是允许我们自定义filter_plugins,这个filter_plugin是什么呢?
就是我们一般看到的
{{item|max}}
其实,后边的这个 max就是一个函数,我们可以定义自己的函数,例如:

|-- filter_plugins
|   |-- zhiming_filter.py
|   `-- zhiming_filter.pyc
`-- main.yml
目录结构就是我们在我们的playbook下创建filter_plugins文件夹,然后写一个python文件,里边定义一些方法:
例如我的:

#!/usr/bin/env python
# coding=utf-8
'''
Created on Apr 13, 2016
@author: zhizhang
'''
import re

class FilterModule(object):
    @staticmethod
    def get_ebs_id(data):
        patten = re.compile(r'xiaoming-[a-zA-Z0-9]{8}')
        if patten.search(data):
            return patten.search(data).group()
        return None
    def filters(self):
        ''' returns a mapping of filters to methods '''
        return {
            "get_ebs_id": self.get_ebs_id,
}

这个函数的功能事,例如我们有一串字符串
xiaoming-s7d7f7s7-we32sdfa-asdfasdf
我们只想取到xiaoming-s7d7f7s7
我们直接在playbook中使用我的方法就可以了,例如
– debug: msg=” the id infof is {{abc|get_ebs_id}}”
然后就可以了
例子,ilter_plugins插件实现jinja2模板filter过滤器
ansible支持jinja2中默认的内置过滤器用法的,这些是一部分 ! 具体的每个功能我就不详细说了,大家自己测测就知道用途了。
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过滤器。

#111cn.net
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 a 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,
    }
模板的代码,这里只是做个测试而已。模板里面的变量不是从外面引入的,是我自己设的变量。

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

Tags:
相关文章列表:
关于开源中文网 - 联系我们 - 广告服务 - 网站地图 - 版权声明