#ubuntu #dynamic #ansible #jq #inventory
#ubuntu #динамический #ansible #jq #инвентаризация
Вопрос:
Я пытаюсь создать базовый сценарий динамической инвентаризации для ansible на основе вывода JSON. Я новичок в jq, но я столкнулся с проблемой, когда динамическому скрипту на ansible версии v2.9.14 и 2.9.15 не нравится вывод, но если я отправляю вывод в файл, а затем запускаю Ansible против вывода в файле, ansible работает.
Вот что происходит:
вывод скрипта динамической инвентаризации:
{
"all": {
"hosts": {
"ip-172-31-39-30.eu-west-1.compute.internal": null,
"ip-172-31-44-224.eu-west-1.compute.internal": null,
"ip-172-31-42-6.eu-west-1.compute.internal": null,
"ip-172-31-32-68.eu-west-1.compute.internal": null,
}
}
}
Запуск Ansible и ошибка:
$ ansible -i ./dynamic1.sh all -m ping -u ubuntu
[WARNING]: * Failed to parse /home/ubuntu/dynamic1.sh with script plugin: failed to parse executable inventory script results from /home/ubuntu/dynamic1.sh:
Expecting property name enclosed in double quotes: line 8 column 5 (char 242)
[WARNING]: * Failed to parse /home/ubuntu/dynamic1.sh with ini plugin: /home/ubuntu/dynamic1.sh:2: Expected key=value host variable assignment, got: {
[WARNING]: Unable to parse /home/ubuntu/dynamic1.sh as an inventory source
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
Теперь, если я выведу динамический скрипт в файл, а затем снова запущу ansible, он сработает:
$ ./dynamic1.sh > output.json
$ cat output.json
{
"all": {
"hosts": {
"ip-172-31-39-30.eu-west-1.compute.internal": null,
"ip-172-31-44-224.eu-west-1.compute.internal": null,
"ip-172-31-42-6.eu-west-1.compute.internal": null,
"ip-172-31-32-68.eu-west-1.compute.internal": null,
}
}
}
$ ansible -i output.json all -m ping -u ubuntu
[DEPRECATION WARNING]: Distribution Ubuntu 16.04 on host ip-172-31-42-6.eu-west-1.compute.internal should use /usr/bin/python3, but is using /usr/bin/python for
backward compatibility with prior Ansible releases. A future Ansible release will default to using the discovered platform python for this host. See
https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more information. This feature will be removed in version 2.12. Deprecation
warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
ip-172-31-42-6.eu-west-1.compute.internal | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
ip-172-31-39-30.eu-west-1.compute.internal | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
ip-172-31-32-68.eu-west-1.compute.internal | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
ip-172-31-44-224.eu-west-1.compute.internal | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
Итак, это работает…
Это содержимое dynamic1.sh . Я знаю, что будут лучшие способы сделать это, но мне просто нужен список серверов на основе соответствующей переменной в выводе JSON, который может использовать ansible.
$ cat dynamic1.sh
#!/bin/bash
echo "{"
echo " "all": {"
echo " "hosts": {"
curl --silent -X GET https://url.com/api/servers -H "Authorization: Token $token" -H "Content-Type: text/json" -H "Accept:application/json" | jq -r '.Result.servers[] | select(.ansible_local.local.local_facts.instance_type | tostring | contains("t2.micro")) | (.ansible_fqdn "": null,")' | sed 's/^/"/g'
echo " }"
echo " }"
echo "}"
Может ли кто-нибудь помочь мне объяснить, почему ansible принимает файл, но не вывод скрипта?
Ответ №1:
В отличие от формата инвентаризации Ansible, плагин инвентаризации script.py ожидает, что атрибут hosts будет списком (например, hosts: [ host1, host2, host3 ]), а не словарем (например, hosts: { host, host2, host3 }).
Плагин инвентаризации yaml.py работает со словарями хостов
Инвентаризация JSON (или YAML, поскольку JSON является подмножеством YAML) работает нормально
shell> cat hosts.json
{
"all": {
"hosts": {
"ip-172-31-39-30.eu-west-1.compute.internal",
"ip-172-31-44-224.eu-west-1.compute.internal",
"ip-172-31-42-6.eu-west-1.compute.internal",
"ip-172-31-32-68.eu-west-1.compute.internal"
}
}
}
shell> ansible-inventory -i hosts.json --list -vvv
...
Parsed /scratch/tmp/hosts.json inventory source with yaml plugin
{
"_meta": {
"hostvars": {}
},
"all": {
"children": [
"ungrouped"
]
},
"ungrouped": {
"hosts": [
"ip-172-31-32-68.eu-west-1.compute.internal",
"ip-172-31-39-30.eu-west-1.compute.internal",
"ip-172-31-42-6.eu-west-1.compute.internal",
"ip-172-31-44-224.eu-west-1.compute.internal"
]
}
}
Но тот же файл, предоставленный скриптом, завершится ошибкой
shell> cat hosts.sh
#!/bin/bash
cat hosts.json
shell> ansible-inventory -i hosts.sh --list -vvv
...
Parsed /scratch/tmp/hosts.sh inventory source with script plugin
[ПРЕДУПРЕЖДЕНИЕ]: не удалось проанализировать / scratch/tmp/hosts.sh с помощью плагина script: вы
определили группу «все» с неверными данными для списка хостов: {‘hosts’: {‘ip-172-31-39-30.eu —
west-1.вычислить.внутренний’: Нет, ‘ip-172-31-44-224.eu-west-1.compute.internal’: Нет,
‘ip-172-31-42-6 .eu-west-1.вычислить.внутренний’: Нет, ‘ip-172-31-32-68.eu —
запад-1.вычисление.внутреннее’:Нет}}
…
{
"_meta": {
"hostvars": {}
},
"all": {
"children": [
"ungrouped"
]
}
}
Плагин инвентаризации script.py работает со списками хостов
Плагин инвентаризации script.py работает, как и ожидалось, когда атрибут hosts представляет собой список
shell> cat hosts.json
{
"all": {
"hosts": [
"ip-172-31-39-30.eu-west-1.compute.internal",
"ip-172-31-44-224.eu-west-1.compute.internal",
"ip-172-31-42-6.eu-west-1.compute.internal",
"ip-172-31-32-68.eu-west-1.compute.internal"
]
}
}
shell> ansible-inventory -i hosts.sh --list -vvv
...
Parsed /scratch/tmp/hosts.sh inventory source with script plugin
{
"_meta": {
...
},
"all": {
"children": [
"ungrouped"
]
},
"ungrouped": {
"hosts": [
"ip-172-31-32-68.eu-west-1.compute.internal",
"ip-172-31-39-30.eu-west-1.compute.internal",
"ip-172-31-42-6.eu-west-1.compute.internal",
"ip-172-31-44-224.eu-west-1.compute.internal"
]
}
}
Примечания
- Сценарий hosts.sh не реализован должным образом и служит только для целей этого примера. Цитирование из script.py:
описание: — Предоставленный источник должен быть исполняемым файлом, который возвращает Ansible inventory JSON — Источник должен принимать C(—list) и C(—host ) в качестве аргументов. C(—host) будет использоваться только в том случае, если отсутствует ключ C (_meta).
Комментарии:
1. Хороший Владимир. Я только что прочитал ваше объяснение, и мой скрипт динамической инвентаризации работает на основе того, что вы сказали. Спасибо, что нашли время объяснить это так, как мне удалось!