#ansible
#ansible
Вопрос:
Использование blockinfile: который использует with_items из внешнего файла. Когда я запускаю playbook, я вижу, что все обрабатываемые элементы, но в результирующем конечном файле обновляется только последний элемент.
Извиняюсь, немного новичок в этом, поэтому может отсутствовать что-то очевидное.
Пробовал различные перестановки
У меня есть внешний файл конфигурации yaml со следующим содержимым, который включен как include_vars:
файл реквизитов yaml:
ds_props:
- prop: dataSource.initialSize=8
- prop: dataSource.maxActive=50
- prop: dataSource.maxIdle=20
- prop: dataSource.minIdle=5
- prop: dataSource.maxWait=1000
Задачи Ansible:
- name: update DS settings
blockinfile:
path: /app.properties
insertafter: "##### Data Source Properties"
block: |
"{{ item.prop }}"
with_items: "{{ ds_props }}"
Ожидаемый:
##### Data Source Properties #####
# BEGIN ANSIBLE MANAGED BLOCK
dataSource.initialSize=8
dataSource.maxActive=50
dataSource.maxIdle=20
dataSource.minIdle=5
dataSource.maxWait=1000
# END ANSIBLE MANAGED BLOCK
Актуально:
##### Data Source Properties #####
# BEGIN ANSIBLE MANAGED BLOCK
dataSource.maxWait=1000
# END ANSIBLE MANAGED BLOCK
Комментарии:
1. Потрясающе. Спасибо за подробный ответ.
Ответ №1:
blockinfile
использует marker
для отслеживания блоков, которыми он управляет в файле. По умолчанию этот маркер является ANSIBLE MANAGED BLOCK
.
Что происходит в вашем случае, поскольку вы используете маркер по умолчанию, так это то, что блок создается после строки «##### Свойства источника данных» для первого элемента, а затем редактируется для следующих элементов.
Одним из решений было бы изменить маркер для каждого элемента. Другой вариант — использовать lineinfile, как сообщает @Larsk
Я бы предпочел в этом случае создать полный блок сразу:
- name: update DS settings
blockinfile:
path: /app.properties
insertafter: "##### Data Source Properties"
marker: "Custom ds props - ansible managed"
block: "{{ ds_props | json_query('[].prop') | join('n') }}"
Если вы намерены выполнять более сложные действия с вашим конфигурационным файлом, следуйте совету @ Larsk и используйте шаблон.
Ответ №2:
blockinfile
работает точно так, как задумано: он добавляет блок текста в целевой файл и удаляет соответствующий блок перед добавлением измененной версии. Таким образом, для каждой итерации вашего цикла blockinfile
удаляется блок, добавленный предыдущей итерацией, и добавляется новый.
Учитывая, что вы добавляете отдельные строки в файл, а не блок, вам, вероятно, лучше использовать lineinfile
модуль, как в:
---
- hosts: localhost
gather_facts: false
vars:
ds_props:
- prop: dataSource.initialSize=8
- prop: dataSource.maxActive=50
- prop: dataSource.maxIdle=20
- prop: dataSource.minIdle=5
- prop: dataSource.maxWait=1000
tasks:
- name: update DS settings using lineinfile
lineinfile:
path: /app.properties-line
line: "{{ item.prop }}"
insertafter: "##### Data Source Properties"
with_items: "{{ ds_props }}"
Хотя это работает, это все еще проблематично: если вы измените значение одного из своих свойств, в результате в файле будет несколько записей. Например, если бы мы изменили dataSource.maxWait
с 1000
на 2000
, мы бы получили:
dataSource.maxWait=1000
dataSource.maxWait=2000
Мы можем защитить от этого, используя regexp
опцию для lineinfile
модуля, например:
- name: update DS settings using lineinfile
lineinfile:
path: /app.properties-line
line: "{{ item.prop }}"
insertafter: "##### Data Source Properties"
regexp: "{{ item.prop.split('=')[0] }}"
with_items: "{{ ds_props }}"
Это приведет к тому, что модуль удалит все существующие строки для конкретного свойства перед добавлением нового.
Кстати, возможно, вам захочется немного реструктурировать свои данные, используя словарь, а не список строк «ключ = значение», например:
---
- hosts: localhost
gather_facts: false
vars:
ds_props:
dataSource.initialSize: 8
dataSource.maxActive: 50
dataSource.maxIdle: 20
dataSource.minIdle: 5
dataSource.maxWait: 1000
tasks:
- name: update DS settings using lineinfile
lineinfile:
path: /app.properties-line
line: "{{ item.key }}={{ item.value }}"
insertafter: "##### Data Source Properties"
regexp: "{{ item.key }}"
with_items: "{{ ds_props|dict2items }}"
И, наконец, вместо использования lineinfile
или blockinfile
, вы можете рассмотреть возможность использования template
модуля ansible для создания вашего /app.properties
файла, а не пытаться редактировать его.