Вопрос или проблема
Я хотел передать плейбук в ansible-playbook 2.4.2.0 из stdin на RHEL 7.5. Я нашел этот пост, который казался многообещающим, но у меня не работает:
$ cat ~/simple-ansible-playbook.yaml | ansible-playbook -i ~/inventory.yaml /dev/stdin
ERROR! Не удается получить содержимое файла
Не удалось найти или получить доступ к '/dev/stdin'
$
Я отслеживал сообщение до /usr/lib/python2.7/site-packages/ansible/parsing/dataloader.py
:
if not self.path_exists(b_file_name) or not self.is_file(b_file_name):
raise AnsibleFileNotFound("Не удается получить содержимое файла", file_name=file_name)
os.path.isfile()
возвращает False
для /dev/stdin
, который является символьной ссылкой на специальный файл:
$ ls -l /dev/stdin
lrwxrwxrwx. 1 root root 15 Nov 11 13:11 /dev/stdin -> /proc/self/fd/0
$ ls -Ll /dev/stdin
crw--w----. 1 stack tty 136, 3 Feb 15 07:45 /dev/stdin
Кто-нибудь имеет идеи, как это заставить работать? Я не понимаю, почему это, казалось, работало для указанного поста, но у меня не получается.
Обновление
Я думаю, я лучше это понимаю. Исходный пост использовал here document, который оболочка, очевидно, возвращает в обычный файл. В моем методе данные находятся в канале. Я не осознавал, что оболочка ведет себя по-другому в этом отношении: я полагал, что here document также приведет к каналу. Так что, по крайней мере, я узнал что-то новое о разнице, но, похоже, я не могу сделать то, что я хочу, если только ansible-playbook
не изменится.
Я понял, что мне придется взять себя в руки и поместить плейбук во временный обычный файл, а не передавать его через stdin.
Исходный пост использовал here document, который оболочка, очевидно, возвращает в обычный файл
Версия с каналом работает прекрасно на современной версии ansible (я просто использовал heredoc, чтобы сделать ответ более кратким):
$ printf -- '- hosts: all\n tasks:\n - debug: msg=hello\n' | \
ansible-playbook -c local -i localhost, /dev/stdin
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
TASK [debug] *******************************************************************
ok: [localhost] =>
msg: hello
PLAY RECAP *********************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0
$ ls -l /dev/stdin
lrwxrwxrwx 1 root root 15 Feb 15 16:44 /dev/stdin -> /proc/self/fd/0
$ ansible --version
ansible 2.7.7
config file = None
configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/lib/python2.7/dist-packages/ansible
executable location = /usr/local/bin/ansible
python version = 2.7.15rc1 (default, Nov 12 2018, 14:31:15) [GCC 7.3.0]
Итак, решение вашей проблемы – обновиться до современной версии ansible.
Тем не менее, я не хотел, чтобы все было мрачно, поэтому существует обходной путь, если вы настаиваете на передаче данных в ansible через канал: обманите и сериализуйте поток в файл с помощью tee
:
$ printf -- '- hosts: all\n tasks:\n - debug: msg=hello\n' | \
tee being-on-old-software-is-dangerous.yml | \
ansible-playbook -c local -i localhost, being-on-old-software-is-dangerous.yml
Ответ или решение
Решение проблемы: "Не удается получить содержимое файла" при попытке передачи playbook в ansible-playbook через stdin
Ошибка "Unable to retrieve file contents" возникает при использовании более старой версии Ansible (в вашем случае 2.4.2.0), когда вы пытаетесь передать playbook через стандартный ввод. Решение данной проблемы требует понимания того, как Ansible обрабатывает входные данные и использование правильного подхода.
Причина проблемы
Как вы правильно заметили, Ansible в версии 2.4.2.0 не поддерживает обработку входных данных через /dev/stdin
. При выполнении команды Ansible проверяет, существует ли файл, передаваемый в качестве аргумента, и на самом деле /dev/stdin
не является обычным файлом, а представляет собой специальный файл (символическую ссылку) на текущий дескриптор файла. Это вызывает сбой в функции проверки существования файла, что приводит к ошибке.
Сравнение с более новыми версиями Ansible
Новые версии Ansible, такие как 2.7.x и выше, обрабатывают этот сценарий корректно. Вы можете передавать playbook через конвейер, и Ansible сможет прочитать его из стандартного ввода без проблем.
Пример работы с новым Ansible:
$ printf -- '- hosts: all\n tasks:\n - debug: msg=hello\n' | ansible-playbook -c local -i localhost, /dev/stdin
Решение для старой версии Ansible
Если вы не можете обновить Ansible, существуют обходные пути:
-
Использование временного файла: Вы можете создать временный файл и записать в него содержимое вашего playbook, после чего передать его в ansible-playbook. Например:
$ cat ~/simple-ansible-playbook.yaml > /tmp/temp_playbook.yaml && ansible-playbook -i ~/inventory.yaml /tmp/temp_playbook.yaml
-
Использование утилиты
tee
: Если вы хотите оставаться в рамках цепочек команд, можно использоватьtee
для создания временного файла в рамках командной цепочки:$ printf -- '- hosts: all\n tasks:\n - debug: msg=hello\n' | tee /tmp/playbook.yml | ansible-playbook -i localhost, /tmp/playbook.yml
Важность обновления
Понимание различий в поведении версий Ansible является важным аспектом поддержания инфраструктуры. Если есть возможность обновить Ansible до более свежей версии, это настоятельно рекомендуется, поскольку новые версии не только добавляют поддержку новых функций, но и исправляют ранее существующие ошибки и недоработки.
Заключение
Хотя использование stdin оказывается невозможным с Ansible 2.4.2.0, существуют простые обходные пути, такие как создание временных файлов или использование утилиты tee
. Тем не менее, лучшим решением будет обновление вашего Ansible до более новой версии, что предотвратит возникновение подобных проблем в будущем и обеспечит доступ к улучшенным возможностям платформы.