Специальная команда Ansible фильтрует вывод JSON по ключу или свойству

#json #ansible #ansible-ad-hoc

#json #ansible #специальная команда ansible

Вопрос:

Я хотел бы отфильтровать вывод JSON специальных команд ansible — например, захватить длинный список «фактов» для нескольких хостов и показать только один, который может иметь глубину в несколько уровней, например ansible_lsb.description , чтобы я мог быстро сравнить, какие версии программного обеспечения они запускают, проверить точное время или часовые пояса, что угодно.

Это работает:

 ansible myserver -m setup -a 'filter=ansible_lsb'
myserver | SUCCESS => {
    "ansible_facts": {
        "ansible_lsb": {
            "codename": "wheezy",
            "description": "Debian GNU/Linux 7.11 (wheezy)",
            "id": "Debian",
            "major_release": "7",
            "release": "7.11"
        }
    },
    "changed": false
}
  

Однако, как указано в документах модуля установки, «параметр filter фильтрует только подраздел первого уровня ниже ansible_facts», поэтому это не удается:

 ansible myserver -m setup -a 'filter=ansible_lsb.description'
myserver | SUCCESS => {
    "ansible_facts": {},
    "changed": false
}
  

(хотя для справки, вы можете использовать точечную нотацию в других местах, например, в задаче, когда она условна)

Есть ли способ фильтровать ключи JSON перед отображением вывода?

Ответ №1:

Стандартный setup модуль может применять фильтр только к фактам «верхнего уровня».

Чтобы достичь желаемого, вы можете создать плагин action с setup именем для применения пользовательских фильтров.

Рабочий пример ./action_plugins/setup.py :

 from ansible.plugins.action import ActionBase

class ActionModule(ActionBase):

    def run(self, tmp=None, task_vars=None):

        def lookup(obj, path):
            return reduce(dict.get, path.split('.'), obj)

        result = super(ActionModule, self).run(tmp, task_vars)

        myfilter = self._task.args.get('myfilter', None)

        module_args = self._task.args.copy()
        if myfilter:
            module_args.pop('myfilter')

        module_return = self._execute_module(module_name='setup', module_args=module_args, task_vars=task_vars, tmp=tmp)

        if not module_return.get('failed') and myfilter:
            return {"changed":False, myfilter:lookup(module_return['ansible_facts'], myfilter)}
        else:
            return module_return
  

Она вызывает исходный параметр удаления setup модуля myfilter , затем фильтрует результат с помощью простой реализации reduce, если задача не выполнена с ошибкой и установлен myfilter. Функция поиска очень проста, поэтому она не будет работать со списками, только с объектами.

Результат:

 $ ansible myserver -m setup -a "myfilter=ansible_lsb.description"
myserver | SUCCESS => {
    "ansible_lsb.description": "Ubuntu 12.04.4 LTS",
    "changed": false
}