Ansible lineinfile не копирует последнюю строку на сервер

Я пытаюсь скопировать секретный файл настроек Python с сервера настроек в производственную среду. Поскольку настройки содержат пароли, я использую Ansible Vault.

Мой playbook выглядит так:

---
- hosts: production
  tasks:
  - include_vars: settings.yml
  - name: Set properties
    lineinfile:
      dest: ~/temp/deploy
      regexp: "{{ item.split('=')[0] }}\\s*="
      line: "{{ item }}"
    with_lines: echo "{{ config }}"

И мой settings.yml выглядит так:

config:  |
  ASD='DEF'
  PROGRAM='PROG'
  PASSWORD='MAGNUS123'
  TEMP='TEST'

Однако, когда я запускаю playbook, я получаю файл:

ASD='DEF'
PROGRAM='PROG'
PASSWORD='MAGNUS123'

Хотя Ansible утверждает, что последняя строка также скопирована:

changed: [ssh.pythonanywhere.com] => (item=ASD='DEF' )
changed: [ssh.pythonanywhere.com] => (item=PROGRAM='PROG')
changed: [ssh.pythonanywhere.com] => (item=PASSWORD='MAGNUS123')
changed: [ssh.pythonanywhere.com] => (item=TEMP='TEST')
changed: [ssh.pythonanywhere.com] => (item=)

Что я делаю не так, чтобы вызвать это?

Ansible версия:

ansible --version
ansible 2.4.1.0
  config file = None
  ansible python module location = /usr/local/lib/python3.6/site-packages/ansible
  executable location = /usr/local/bin/ansible
  python version = 3.6.2 (default, Jul 17 2017, 16:44:45) [GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.42)]

1 ответ

Решение

Вы делаете что-то совершенно ненужное (пропустите до конца), но давайте попробуем...

Что я делаю не так, чтобы вызвать это?

Если вы запустите следующее:

- shell: echo "{{ config }}" | hexdump
  register: echo

- debug:
    var: echo.stdout

Вы увидите, что вывод заканчивается на:

54 45 4d 50 3d 27 54 45 53 54 27 0a 0a

который TEMP='TEST' сопровождаемый двумя символами новой строки. Когда используется в with_lines цикл это вызовет две итерации - последняя с пустым значением, переданным item,

Теперь подумайте, что происходит с вашими аргументами, когда item пустой:

regexp становится \\s*= а также line пустой.

Другими словами, вы указываете Ansible заменить строку, содержащую = с пустой строкой.

Если отправной точкой является пустой файл, Ansible делает следующее:

  1. Добавляет ASD='DEF' линия.
  2. Добавляет PROGRAM='PROG' линия.
  3. Добавляет PASSWORD='MAGNUS123' линия.
  4. Добавляет TEMP='TEST' линия.
  5. Заменяет строку на = с пустой строкой (фактически это самая последняя строка).

И вот результат, который вы получите: три строки и одна пустая.


Вы также можете прийти к такому же выводу, просто используя debug модуль для отображения значений "{{ item.split('=')[0] }}\\s*=" а также {{ item }} который вы передаете lineinfile аргументы.


echo имеет -n аргумент (" Не печатать завершающий символ новой строки "), но по причине, выходящей за рамки моего текущего понимания, он не меняет результат (проверьте с помощью hexdump).

Однако если вы заменили echo с printf - свисающий 0x0a там нет, и вы получите ожидаемый результат (уточните у hexdump).


Все это, помимо того, что это хорошая головоломка, является еще одним аргументом против использования linefile модуль в Ansible.

использование copy (вы можете защитить весь файл с помощью Ansible Vault - см. decrypt аргумент) или template (вы можете иметь открытый шаблон и хранить значения переменных в защищенной от Vault форме). Определите желаемое состояние, не полагайтесь на текущее состояние. Период.

Другие вопросы по тегам