Назад | Перейти на главную страницу

Динамический инвентарь в формате yaml

Задний план

У меня есть домен, управляемый через Terraform, и он выводит IP-адрес сервера. Затем у меня есть сценарий, который выводит инвентарь YAML (результаты будут позже).

Проблема

Когда я бегу ansible-inventory --inventory inventory.sh --graph это всегда заканчивается

@all:
  |--@stage:
  |--@ungrouped:
  |  |--18.66.1.28

Если бы я ожидал, что машина будет в групповом этапе.

Я обнаружил, что статическая инвентаризация и инвентаризация в качестве вывода скрипта ведут себя по-разному.

Статический файл

Если вы сохраните его как статический файл и используете в качестве инвентаря, он будет работать.

all:
  hosts:
    18.66.1.28
  children:
    stage:
      hosts:
        18.66.1.28:

Вывод:

  @all:
  |--@stage:
  |  |--18.66.1.28
  |--@ungrouped:

Сценарий

но если вы укажете сценарий оболочки, как показано ниже, он не будет работать

#!/bin/bash

echo "all:
  hosts:
    18.66.1.28
  children:
    stage:
      hosts:
        18.66.1.28:"

Вывод:

 [WARNING]:  * Failed to parse /tmp/inventory.sh with script plugin: You defined a group 'all' with bad data for the host list:  {u'hosts':
u'18.66.1.28', u'children': {u'stage': {u'hosts': {u'18.66.1.28': None}}}}

 [WARNING]:  * Failed to parse /tmp/inventory.sh with ini plugin: /tmp/inventory.sh:3: Error parsing host definition 'echo "all:': No closing
quotation

 [WARNING]: Unable to parse /tmp/inventory.sh as an inventory source

 [WARNING]: No inventory was parsed, only implicit localhost is available

YAML выходы

Вариант 1

all:
  hosts:
    - 18.66.1.28
  children:
    stage:
      hosts:
        - 18.66.1.28:

Вариант 2

all:
  hosts:
    - 18.66.1.28
  children:
    stage:
      hosts:
        18.66.1.28:

Вариант 3

all:
  hosts:
    - 18.66.1.28
  children:
    stage:
      hosts:
        - 18.66.1.28

Короткий ответ

Не смотри на https://docs.ansible.com/ansible/2.6/user_guide/intro_inventory.html но в https://docs.ansible.com/ansible/2.6/dev_guide/developing_inventory.html.

Длинный ответ

Ansible использует как минимум три формата для инвентаризации. YAML, INI и JSON. Формат INI - это полностью отдельный формат со своей собственной структурой. YAML и JSON сами по себе позволяют создавать практически одинаковые структуры данных. Когда я смотрю на https://docs.ansible.com/ansible/2.6/user_guide/intro_inventory.html полный примеров YAML, используя JSON, я бы просто изменил нотацию, чтобы получить ту же структуру данных, что и в YAML. Дело в том, что плагин скрипта использует разные структуры данных, но позволяет использовать как формат YAML, так и JSON.

Примеры

Static inventory

Вход:

$ cat /tmp/inventory-static 
all:
  hosts:
    18.66.1.28
  children:
    stage:
      hosts:
        18.66.1.28:

Вывод

$ ansible-inventory --inventory /tmp/inventory-static --graph 
@all:
  |--@stage:
  |  |--18.66.1.28
  |--@ungrouped:

Это правильный формат и поведение в соответствии с https://docs.ansible.com/ansible/2.6/user_guide/intro_inventory.html .

Script

Вход:

$ cat /tmp/inventory.sh 
#!/bin/bash

echo "all:
  hosts:
    18.66.1.28
  children:
    stage:
      hosts:
        18.66.1.28:"

Вывод:

 $ ansible-inventory --inventory /tmp/inventory.sh --graph    
 [WARNING]:  * Failed to parse /tmp/inventory.sh with script plugin: You defined a group 'all' with bad data for the host list:  {u'hosts':
u'18.66.1.28', u'children': {u'stage': {u'hosts': {u'18.66.1.28': None}}}}

 [WARNING]:  * Failed to parse /tmp/inventory.sh with ini plugin: /tmp/inventory.sh:3: Error parsing host definition 'echo "all:': No closing
quotation

 [WARNING]: Unable to parse /tmp/inventory.sh as an inventory source

 [WARNING]: No inventory was parsed, only implicit localhost is available

Я не ожидал этого. Проблема в том, что плагин скрипта ожидает другую структуру данных. Давайте попробуем это со структурой данных из https://docs.ansible.com/ansible/2.6/dev_guide/developing_inventory.html.

Вход:

$ cat /tmp/inventory.sh                                  
#!/bin/bash
echo "stage:
  hosts:
    - 18.66.1.28”

Вывод

$ ansible-inventory --inventory /tmp/inventory.sh --graph
@all:
  |--@stage:
  |  |--18.66.1.28
  |--@ungrouped:

Да, это результат, которого я ожидал. Машина находится в правильной группе, и плагин приема ни на что не жалуется. Конечно, согласно «Динамическим источникам инвентаризации», сценарий должен делать немного больше, чем просто echo инвентарь, и он, вероятно, должен выводить JSON, это просто демонстрация того, как структурировать вывод инвентаризации скрипта.

Это заняло у меня довольно много времени, чтобы понять, поэтому я надеюсь, что написав это, я сохраню его для кого-то другого.

Перед именем хоста не должно быть тире (ваш вариант 1).

all:
  hosts:
    18.66.1.28
  children:
    stage:
      hosts:
        18.66.1.28:

$ ansible-inventory --inventory inventory --graph

@all:
  |--@stage:
  |  |--18.66.1.28
  |--@ungrouped:

Через тире вы должны увидеть множество предупреждений.

all:
  hosts:
    - 18.66.1.28
  children:
    stage:
      hosts:
        - 18.66.1.28:

$ ansible-inventory --inventory inventory --graph

 [WARNING]:  * Failed to parse inventory with yaml plugin:
 Invalid "hosts" entry for "all" group, requires a dictionary, found "<class 
 'ansible.parsing.yaml.objects.AnsibleSequence'>" instead.

 [WARNING]:  * Failed to parse inventory with ini plugin:
 inventory:3: Expected key=value host variable assignment, 
 got: 18.66.1.28

 [WARNING]: Unable to parse inventory as an inventory source

 [WARNING]: No inventory was parsed, only implicit localhost is available

...

Цитата из man ansible-inventory

-i, --inventory, --inventory-file
    specify inventory host path or comma separated host list.
    --inventory-file is deprecated

Если сценарий сначала создает файл, все в порядке.

$ ./inventory.sh> /tmp/my_inventory.yml && ansible-inventory --inventory /tmp/my_inventory.yml --graph

@all:
  |--@stage:
  |  |--18.66.1.28
  |--@ungrouped: