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

Ansible: добавляйте строки с сохранением изменений

Я ищу способ изменить файл конфигурации с сохранением локальных изменений. Формат файла конфигурации похож на этот:

entry1: This is a local
entry2: modification.
entry3:

Файл состоит из переменного количества ключей (запись1, запись2, запись3 и, возможно, более поздняя запись4 и т. Д. - может быть до 100, а в будущем, возможно, даже до 2000 или около того), которые должны быть настроены Ansible. , за которыми следуют дополнительные параметры, которые другая программа добавит в файл конфигурации.

Я хочу, чтобы Ansible мог добавлять новые ключи в файл, сохраняя при этом любые существующие локальные модификации.

Самым естественным вариантом кажется lineinfile, но, к сожалению, он дает мне только возможность либо сохранение локальных изменений (используя backref = yes), или добавление новых ключей (backref = yes не добавит новых строк).

Есть ли хороший способ выполнить то, что мне нужно?

Я могу изменить существующие записи с включенными lineinfile и backref:

- lineinfile:
  path: myfile.conf
  regexp: "^{{ item }}: (.*)"
  backref: yes
  line: "{{ item }}: \1"
  with_items:
    - entry1
    - entry2
    - entry3
    - entry4

Но это не добавит entry4 в мой файл.

Или я могу использовать backref: no

- lineinfile:
  path: myfile.conf
  regexp: "^{{ item }}: (.*)"
  backref: no
  line: "{{ item }}:"
  with_items:
    - entry1
    - entry2
    - entry3
    - entry4

Но это приведет к сбою локальных изменений для entry1, entry2 и entry3.

Или я мог бы изменить регулярное выражение:

- lineinfile:
  path: myfile.conf
  regexp: "^"
  backref: no
  line: "{{ item }}:"
  with_items:
    - entry1
    - entry2
    - entry3
    - entry4

Но это, конечно, добавит каждый ключ при каждом запуске.

Я также рассмотрел возможность использования шаблона (но не нашел простого способа использовать его для управления существующим файлом).

Конечно, я могу написать свой собственный модуль Python, но должен ли быть более простой способ сделать это?

Если вы изменяете хорошо известные файлы конфигурации, вы можете использовать Augeas с этим доступным плагином augeas: https://github.com/paluh/ansible-augeas

Это один из примеров использования augeas:

- name: Force password on sudo group
  action: augeas path=/files/etc/sudoers/spec[user=\"sudo\"]/host_group/command/tag value=PASSWD

Другой вариант - использовать команду lineinfile, чтобы убедиться, что нужная строка доступна в файле: http://docs.ansible.com/ansible/latest/lineinfile_module.html

пример:

- lineinfile:
    path: /etc/selinux/config
    regexp: '^SELINUX='
    line: 'SELINUX=enforcing'

Я нашел способ как это сделать. Хитрость заключается в том, чтобы сначала использовать grep, чтобы найти только недостающие записи.

grep выдаст ошибку, если файл не существует, поэтому сначала я создаю файл:

copy: dest: myfile.conf content: "" force: no # set mode, owner, group to taste

Теперь используйте grep, чтобы найти только недостающие элементы. Grep вернет 0, если запись уже существует, или 1, если ее нет. Обычно код возврата 1 означает отказ Ansible. failed_when: True меняет это. Поскольку это только получение информации и ничего не меняет, он никогда не должен сообщать как "измененный", поэтому также необходимо установить changed_when.

command: 'grep "^{{ item }}" myfile.conf' with_items: - entry1 - entry2 - entry3 - entry4 failed_when: False changed_when: False register: grep_output

Grep произведет вывод в зарегистрированную переменную grep_output. При использовании в цикле grep_output будет содержать массив с именем results, который содержит один хэш для каждого элемента из цикла. В этом массиве мы находим всю необходимую информацию: код возврата (называемый rc) и исходный элемент из цикла (называемый элементом).

Теперь мы можем добавить только недостающие записи, проверив rc. Я не уверен, требуется ли здесь регулярное выражение.

lineinfile: path: myfile.conf regexp: "^{{ item.item }} *(.*)" insertafter: EOF line: '{{ item.item }}' state: present when: "item.rc > 0" with_items: "{{ grep_output.results }}"

 lineinfile: path: myfile.conf regexp: "^{{ item }}: (.*)" backref: no line: "{{ item }}:" with_items: - entry1 - entry2 - entry3 - entry4