ansible 自訂filter_plugins的用法

來源:互聯網
上載者:User

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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.