Я пытаюсь достичь следующего. Предположим, у нас есть playbook , подобный следующему:
---
- hosts: local
tasks:
- ini_file:
path: test.ini
create: yes
section: "{{???}}"
option: "{{???}}"
value: "{{???}}"
loop: "{{inidict ...???}}"
vars:
inidict:
section1:
option1: value1
option2: value2
section2:
option1: value1
option2: value2
Вышеупомянутый playbook недействителен из-за строк с ???
в них.
Теперь моя цель - чтобы сопоставить этот dict с разделами / параметрами / значениями внутри файла INI и получить следующее содержимое INI:
[section1]
option1 = value1
option2 = value2
[section2]
option1 = value1
option2 = value2
К сожалению, это не удается, поскольку мне нужно как-то добавить вторичный уровень вложенности для цикла в ] перебирать разделы во внешнем цикле, а затем - параметры / значения во внутреннем.
Есть ли более элегантный или «ответственный» (из-за отсутствия термина Ansible, соответствующего pythonic) способ добиться этого, чем путем его обертывания уровень цикла в роли и итерация по именам разделов с использованием, скажем, include_role
, при передаче имени раздела и списка опций / значений в качестве переменной?
Я полагаю, что одной альтернативой могло бы быть «сглаживание» словарь таким образом, чтобы получилось что-то, что составляет (YAML):
vars:
inicontents:
- section: section1
key: option1
value: value1
- section: section1
key: option2
value: value2
- section: section2
key: option1
value: value1
- section: section2
key: option2
value: value2
Я просто хотел бы оставить его СУХИМ и аннулируйте дублирование имени раздела, когда ясно, что dict будет идеально соответствовать «модели данных» файла INI.
Я не знаю о способе сделать это с ansible по умолчанию кроме использования Вашей "приглушенной" версии. К счастью, Вы можете иметь лучший из обоих миров и записать Ваш собственный плагин фильтра для выравнивания dict для Вас. Просто добавьте что-то как следующее к filter_plugins
каталог в Вашем каталоге проекта или в ~/.ansible/plugins/filter_plugins
и назовите его чем-то как filters.py
:
class FilterModule(object):
def filters(self):
return { 'ini_dict_flatten': self.ini_dict_flatten }
def ini_dict_flatten(self, arg):
ret = []
for section, subdict in arg.items():
for key, value in subdict.items():
ret.append(dict(section=section,
key=key,
value=value))
return ret
После этого можно использовать новый фильтр в проекте как это:
- hosts: localhost
tasks:
- ini_file:
path: /tmp/test.ini
create: yes
section: "{{ item.section }}"
option: "{{ item.key }}"
value: "{{ item.value }}"
loop: "{{ inidict | ini_dict_flatten }}"
vars:
inidict:
section1:
option1: value1
option2: value2
section2:
option1: value1
option2: value2
иногда помогает, знаете ли Вы Python начиная с того способа, которым можно записать собственные плагины для ansible.
РЕДАКТИРОВАНИЕ: Я буду включать намного менее читаемый и не рекомендуемое решение также. Начиная с loop:
работы с json отформатированными строками и jinja2 применяются к строкам в ansible, прежде чем они будут обработаны, можно использовать логику Джинджи для создания "flattend" для Вас непосредственно в сборнике пьес. Это решение является намного более ужасным и менее допускающим повторное использование, чем запись Вашего собственного фильтра, но thecnically все еще работает.
- hosts: localhost
vars:
inidict:
section1:
option1: value1
option2: value2
section2:
option1: value1
option2: value2
tasks:
- ini_file:
path: /tmp/test.ini
create: yes
section: "{{ item.section }}"
option: "{{ item.key }}"
value: "{{ item.value }}"
loop: >-
[
{% for section, subdict in inidict.items() %}
{% for key, value in subdict.items() %}
{'section': '{{ section }}',
'key': '{{ key }}',
'value': '{{ value }}'}
{% if not loop.last %}
,
{% endif %}
{% endfor %}
{% if not loop.last %}
,
{% endif %}
{% endfor %}
]