Вопрос или проблема
переменные:
сервера:
- имя: centos
порт: 22
задачи:
- имя: Проверка удаленного порта
wait_for: host={{ item.name }} port={{ item.port }} timeout=1
ignore_errors: True
register: out
with_items: "{{ сервера }}"
- debug: var=out
- имя: Сохранить удаленный порт
shell: echo "{{ item.host }}" > /tmp/x_output.csv
args:
executable: /bin/bash
with_items: "{{ out.results }}"
ВЫВОД
ИГРА [все] **************************************************************************************************************************
ЗАДАЧА [Сбор фактов] **************************************************************************************************************
ок: [centos]
ЗАДАЧА [telnet : Проверка удаленного порта] ************************************************************************************************
ок: [centos] => (item={u'name': u'centos', u'port': u'22'})
ЗАДАЧА [telnet : debug] ***************************************************************************************************************
ок: [centos] => {
"out": {
"changed": false,
"msg": "Все элементы завершены",
"results": [
{
"_ansible_ignore_errors": true,
"_ansible_item_result": true,
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": false,
"elapsed": 0,
"failed": false,
"invocation": {
"module_args": {
"active_connection_states": [
"ESTABLISHED",
"FIN_WAIT1",
"FIN_WAIT2",
"SYN_RECV",
"SYN_SENT",
"TIME_WAIT"
],
"connect_timeout": 5,
"delay": 0,
"exclude_hosts": null,
"host": "centos",
"msg": null,
"path": null,
"port": 22,
"search_regex": null,
"sleep": 1,
"state": "started",
"timeout": 1
}
},
"item": {
"name": "centos",
"port": "22"
},
"path": null,
"port": 22,
"search_regex": null,
"state": "started"
}
]
}
}
ЗАДАЧА [telnet : Сохранить удаленный порт] ****************************************************************************************************
фатально: [centos]: FAILED! => {"msg": "Задача включает опцию с неопределенной переменной. Ошибка: 'dict object' не имеет атрибута 'host'\n\nОшибка, похоже, произошла в '/home/xxxxxx/ansible/tso-playbook/roles/telnet/tasks/main.yml': строка 17, столбец 3, но может быть\nв другом месте файла в зависимости от точной синтаксической проблемы.\n\nПроблемная строка выглядит следующим образом:\n\n\n- имя: Сохранить удаленный порт\n ^ здесь\n\nтип исключения: <class 'ansible.errors.AnsibleUndefinedVariable'>\nисключение: 'dict object' не имеет атрибута 'host'"}
для повтора используйте: --limit @/home/xxxxxxx/ansible/tso-playbook/telnet.retry
РЕЗЮМЕ ИГРЫ **************************************************************************************************************************
centos : ok=3 changed=0 unreachable=0 failed=1
Примечание: это мой первый раз, когда я публикую здесь, не знаю, как правильно исправить строку за строкой… Я просто хочу получить доступ к out.host, который ‘centos’ и сохранить его в csv файл, конечно, мне нужно сделать больше, но это первое, что мне нужно сделать, пожалуйста, помогите! Спасибо.
---
- имя: Сохранить удаленный порт
shell: echo {{ item.changed }} > /tmp/x_output.csv
args:
executable: /bin/bash
with_items: "{{ out.results }}"
Это единственное, на что я могу сослаться, item.changed, который “Ложь”, но все остальные я не могу.
Почему?
Как вы можете видеть в отладке, которую вы опубликовали, в отличие от ключа changed
, в элементах списка results
нет ключа host
.
Один есть внутри словаря invocation
, поэтому:
shell: echo "{{ item.invocation.module_args.host }}" > /tmp/x_output.csv
Хотя это значение, которое вы определили сами, а не возвращаемое значение.
Ответ или решение
Для данной задачи в Ansible вы хотите извлечь информацию о хосте и его порте, а затем сохранить эту информацию в CSV-файл. Ниже приведен исправленный пример кода, который соответствует вашим требованиям. В исправлении я учёл, что ключа host
в результатах нет, и вместо этого использовал invocation.module_args.host
для доступа к имени хоста.
---
- hosts: all
vars:
servers:
- name: centos
port: 22
tasks:
- name: Проверка доступности порта на удалённом хосте
wait_for:
host: "{{ item.name }}"
port: "{{ item.port }}"
timeout: 1
ignore_errors: true
register: out
with_items: "{{ servers }}"
- debug: var=out
- name: Сохранение информации о портах в CSV файл
lineinfile:
path: /tmp/x_output.csv
line: "{{ item.invocation.module_args.host }},{{ item.invocation.module_args.port }}"
create: yes
with_items: "{{ out.results }}"
when: item.failed is not defined or not item.failed
Объяснение внесенных изменений:
-
Использование
invocation.module_args.host
: Как уже упоминали в комментариях, для доступа к имени хоста нужно использовать полеinvocation.module_args.host
. Это позволит вам правильно извлечь имя хоста из результатов предыдущей задачи. -
Заменить
shell
наlineinfile
: Вместо использования командыshell
сecho
, я использовал модульlineinfile
, который обеспечивает более безопасное и удобное управление файлами. Это также позволяет избежать проблем с параллельным доступом к файлам. -
Условие с
when
: Добавлено условиеwhen
, чтобы избежать попыток сохранить информацию о портах, если запрос завершился неудачно. Оно проверяет, не был ли элемент в списке итоговfailed
.
Этот подход правильно сохраняет данные о порте и хосте в формате CSV, что должно удовлетворить ваши требования. Убедитесь, что у вас есть все необходимые права доступа для записи в файл /tmp/x_output.csv
на целевом хосте.