Можно ли отобразить несколько атрибутов с помощью Jinja/Ansible?

Я хотел бы построить вывод, который показывает ключ и значение переменной.

Следующее работает отлично...

# Format in Ansible

msg="{{ php_command_result.results | map(attribute='item') | join(', ') }}"

# Output
{'value': {'svn_tag': '20150703r1_6.36_homeland'}, 'key': 'ui'}, {'value': {'svn_tag': '20150702r1_6.36_homeland'}, 'key': 'api'}

Я хотел бы показать вместе key и svn_tag следующим образом:

Я могу отображать либо key, либо svn_tag, но получение их для совместного использования не работает.

msg="{{ php_command_result.results | map(attribute='item.key') | join(', ') }}"

# Output
ui, api

Однако, это то, что я хочу.

# Desired Output
api - 20150702r1_6.36_homeland
ui - 20150703r1_6.36_homeland

Ответ 1

Вы можете сделать это, используя следующие методы:

  • Создайте filter_plugin. Добавьте filter_plugins = <path to the folder> в ansible.cfg. Затем создайте файл: my_plugin.py:

    class FilterModule(object):
    ''' Custom filter '''
        def filters(self, my_arg):
           return <parse it here......>
    

Пример:

playbook.yml

---
- hosts: localhost
  gather_facts: no
  connection: local
  tasks:
    - set_fact: 
        php_command_result:
          results: {'value': {'svn_tag': '20150703r1_6.36_homeland'}, 'key': 'ui'}
    - debug: msg="Hey look what I got '{{ php_command_result.results | a }}'"

my_plugin.py

import json

class FilterModule(object):
    def filters(self):
      return {'a': a}

def a(a):
  r = '%s - %s' % (a['key'], a['value']['svn_tag'])
  return r
  1. Быстрый и простой подход: используйте python/php/shell или что вы предпочитаете с модулем shell. Что-то вроде этого:

    - name: Pars output
      shell: python -c "import json; json.loads('{{ php_command_result.results }}') ....
    

Ответ 2

Использование утверждений дзиндзя:

- set_fact:
    php_command_result:
      results: [{"value":{"svn_tag":"20150703r1_6.36_homeland"},"key":"ui"},{"value":{"svn_tag":"20150702r1_6.36_homeland"},"key":"api"}]

- debug:
    msg: "{% for result in php_command_result.results %}\
        {{ result.key }} - {{ result.value.svn_tag }} |
      {% endfor %}"

Выходы:

ok: [localhost] => {
    "msg": "ui - 20150703r1_6.36_homeland | api - 20150702r1_6.36_homeland | "
}

Если вы хотите получить результаты в отдельных строках:

- debug:
    msg: "{% set output = [] %}\
        {% for result in php_command_result.results %}\
          {{ output.append( result.key ~ ' - ' ~ result.value.svn_tag) }}\
        {% endfor %}\
      {{ output }}"

Выходы:

ok: [localhost] => {
    "msg": [
        "ui - 20150703r1_6.36_homeland", 
        "api - 20150702r1_6.36_homeland"
    ]
}

При желании любой из них может быть помещен в одну строку:

- debug:
    msg: "{% for result in php_command_result.results %}{{ result.key }} - {{ result.value.svn_tag }} | {% endfor %}"

- debug:
    msg: "{% set output = [] %}{% for result in php_command_result.results %}{{ output.append( result.key ~ ' - ' ~ result.value.svn_tag) }}{% endfor %}{{ output }}"

Ответ 3

Вот решение без пользовательского фильтра filter_plugin или командной строки. Однако для этого необходимо установить дополнительный факт в цикле with_items (php_fmt).

- hosts: localhost
  connection: local
  gather_facts: false 
  tasks:
    - set_fact: 
        php_command_result:
          results: '[{"value":{"svn_tag":"20150703r1_6.36_homeland"},"key":"ui"},{"value":{"svn_tag":"20150702r1_6.36_homeland"},"key":"api"}]'

    - set_fact:
        php_fmt: "{{ php_fmt|default([])|union([item.key+' -- '+item.value.svn_tag ]) }}"
      with_items: "{{ php_command_result.results }}"

    - debug: 
        msg: "{{php_fmt|join(',')}}"

Ответ 4

Вот еще один ответ с использованием filter_plugins, который я нашел очень простым в использовании.

Если кому-то это все еще нужно, вы можете использовать следующий код (поместите в playbooks/filter_plugins/mapattributes.py):

#!/usr/bin/env python
class FilterModule(object):
  def filters(self):
    return { 'mapattributes': self.mapattributes }

  def mapattributes(self, list_of_dicts, list_of_keys):
    l = []
    for di in list_of_dicts:
      newdi = { }
      for key in list_of_keys:
        newdi[key] = di[key]
      l.append(newdi)
    return l

И скажем, у вас есть этот список, от которого вам нужны только ключи:

    INTERFACES:
      - { name: GigabitEthernet1/0/24 , enabled: yes, state: up , description: FRONT }
      - { name: GigabitEthernet1/0/9  , enabled: yes, state: up , description: BACK  }

Давайте создадим другую переменную, фильтрующую только нужные key:values

    test: "{{ INTERFACES | mapattributes(['name', 'description']) }}"

Проверьте вывод

    - debug:
        var: test
ok: [R1] => {
    "test": [
        {
            "description": "FRONT",
            "name": "GigabitEthernet1/0/24"
        },
        {
            "description": "BACK",
            "name": "GigabitEthernet1/0/9"
        }
    ]
}

Это позволяет мне иметь большой словарь и выделять только те ключи, которые мне нужно передать ios_interface/aggregate

Спасибо Nee6ione, я нашел его на паллетах /jinja github issue