ansible: lineinfile для кількох рядків?


162

Так само є модуль lineinfileдля додавання одного рядка у файл, чи є спосіб додати кілька рядків?

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


Я розумію, ви не хочете користуватися template, але використання lineinfileє антипатерном . Це також сильний червоний прапор, який ви "не знаєте, що є у файлі", що призводить до значного ризику невідомих збоїв.
tedder42

39
Це не анти-модель. Сенс рядкового файлу полягає в підтримці декількох джерел, що управляють одним файлом, що іноді неминуче. Більшість файлів конфігурації мають фіксований формат і логіка, щоб уникнути конфліктів, зазвичай не надто суттєва.
Doug F

Я не знаю, що в переважній більшості файлів на моєму ПК; не означає, що я хочу їх занурити!
DylanYoung

Відповіді:


222

Ви можете використовувати цикл для цього. Ось приклад використання with_itemsциклу:

- name: Set some kernel parameters
  lineinfile:
    dest: /etc/sysctl.conf
    regexp: "{{ item.regexp }}"
    line: "{{ item.line }}"
  with_items:
    - { regexp: '^kernel.shmall', line: 'kernel.shmall = 2097152' }
    - { regexp: '^kernel.shmmax', line: 'kernel.shmmax = 134217728' }
    - { regexp: '^fs.file-max', line: 'fs.file-max = 65536' }

Переконайтеся , що ви маєте аргумент рядка = і регулярний вираз = в лапках . Я цього не зробив, і я продовжував отримувати msg: this module requires key=value arguments. Наведений приклад має таке правильне - я просто не слідував прикладу.
JDS

1
Чи можу я запитати, як зробити одну резервну копію до першої зміни? можливо item.backup? : D
tdihp

6
За це, ймовірно, проголосували до Ansible 2.0. Найкращою відповіддю тепер: stackoverflow.com/a/28306576/972128
kkurian

@kkurian Напевно, тільки якщо ви вставляєте, а не якщо ви замінюєте?
ndtreviv

7
@kkurian Рішення blockinfile не працюватиме, якщо вам потрібно, наприклад, додати деякі рядки до файлу json і не потрібно маркувати. У той час як ви можете встановити маркери на "", ansible blockinfile все одно буде шукати маркери, не знаходити жодних, і вставити блок ще раз. Таким чином, блок-файл без маркерів не є ідентичним, лінійний файл з циклом є.
абсурд

176

Ви можете спробувати використовувати blockinfileнатомість.

Можна зробити щось на кшталт

- blockinfile: |
    dest=/etc/network/interfaces backup=yes
    content="iface eth0 inet static
        address 192.168.0.1
        netmask 255.255.255.0"

8
blockinfileМодуль працює чудово кожен раз , коли я вирішив використовувати його. Я особливо люблю інтуїтивну поведінку insertafter/ insertbeforeваріантів.
Джей Тейлор

9
Відповідь з найвищим голосом була, ймовірно, перед Ansible 2.0, але це більш правильна відповідь зараз.
Віллем ван Кетвіч

11
Для блочного файлу потрібні маркери. Іноді це варіант не є.
закінчення

1
Чи можемо ми перезаписати вміст blockinfile?
pkaramol

1
Я думаю, що це правильний спосіб зробити це. docs.ansible.com/ansible/blockinfile_module.html
Пауло Віктор

20

Якщо вам потрібно налаштувати набір унікальних рядків властивості = значення, я рекомендую більш стислий цикл. Наприклад:

- name: Configure kernel parameters
  lineinfile:
    dest: /etc/sysctl.conf
    regexp: "^{{ item.property | regex_escape() }}="
    line: "{{ item.property }}={{ item.value }}"
  with_items:
    - { property: 'kernel.shmall', value: '2097152' }
    - { property: 'kernel.shmmax', value: '134217728' }
    - { property: 'fs.file-max', value: '65536' }

Використовуючи диктант, як запропонував Alix Axel, і додавши автоматичне видалення відповідних коментованих записів,

- name: Configure IPV4 Forwarding
  lineinfile:
    path: /etc/sysctl.conf
    regexp: "^#? *{{ item.key | regex_escape() }}="
    line: "{{ item.key }}={{ item.value }}"
  with_dict:
    'net.ipv4.ip_forward': 1

2
Якщо ви використовуєте with_dict, це було б більш стисло.
Алікс Аксель

18

Ось безшумна версія рішення, яке полягає у використанні with_items:

- name: add lines
  lineinfile: 
    dest: fruits.txt
    line: '{{ item }}'
  with_items:
    - 'Orange'
    - 'Apple'
    - 'Banana' 

Для кожного елемента, якщо предмет існує у фруктах.txt, не вживаються дії.

Якщо елемента не існує, він буде доданий до кінця файлу.

Простенька.


Це не можна поєднувати із вставкою.
відхилення

Якщо відсутня декілька рядків, я хотів би, щоб товар відображався в порядку. Як я можу бути впевнений у порядку, в якому елементи додаються?
МУЙ Бельгія

5

Це не ідеально, але вам дозволено кілька дзвінків lineinfile. Використовуючи це за допомогою insert_after, ви можете отримати бажаний результат:

- name: Set first line at EOF (1/3)
  lineinfile: dest=/path/to/file regexp="^string 1" line="string 1"
- name: Set second line after first (2/3)
  lineinfile: dest=/path/to/file regexp="^string 2" line="string 2" insertafter="^string 1"
- name: Set third line after second (3/3)
  lineinfile: dest=/path/to/file regexp="^string 3" line="string 3" insertafter="^string 2"

5
так, але це все одно один рядок. Якщо у мене є 15 рядків, я вважаю за краще додавати їх лише однією командою. Здається, це не можливо.
Майкл

1
Дякую. Здається, що це все-таки єдиний спосіб зробити кілька рядків із вставкою після / до.
timss

5

Я зміг це зробити, використовуючи \nпараметр рядка.

Це особливо корисно, якщо файл можна перевірити, а додавання одного рядка створює недійсний файл.

У моєму випадку я додавав AuthorizedKeysCommandта AuthorizedKeysCommandUserв sshd_config , використовуючи таку команду:

- lineinfile: dest=/etc/ssh/sshd_config line='AuthorizedKeysCommand /etc/ssh/ldap-keys\nAuthorizedKeysCommandUser nobody' validate='/usr/sbin/sshd -T -f %s'

Додавання лише однієї з опцій створює файл, який не дає змоги перевірити.


12
Це створить рядок додатковий раз при кожному запуску ігрової книги - це невірно визнає, що лінія вже існує. Принаймні, це так у мене в Ansible 1.7.1
David

1
Я повідомив про помилку , але хлопці з Ansible не мають інтересу виправити це.
закінчення

1
Існує новий модуль blockinfile, який зараз повинен бути кращим, ніж це рішення. ( docs.ansible.com/ansible/blockinfile_module.html )
Penz

1

Щоб додати кілька рядків, ви можете використовувати блок-файл:

- name: Add mappings to /etc/hosts
  blockinfile:
    path: /etc/hosts
    block: |
      '10.10.10.10  server.example.com'
      '10.10.10.11  server1.example.com'

Щоб додати один рядок, ви можете використовувати lininfile:

- name: server.example.com in /etc/hosts
  lineinfile:
    path: /etc/hosts
    line: '192.0.2.42 server.example.com server'
    state: present

1

Для додавання декількох рядків ви можете використовувати lineinfileмодуль з with_itemsтакож включенням змінної varsтут, щоб зробити його простішим :)

---
- hosts: localhost  #change Host group as par inventory
  gather_facts: no
  become: yes
  vars:
    test_server: "10.168.1.1"
    test_server_name: "test-server"
    file_dest: "/etc/test/test_agentd.conf"

  - name: configuring test.conf
    lineinfile:
      dest: "{{ item.dest }}"
      regexp: "{{ item.regexp }}"
      line: "{{ item.line }}"
    with_items:
      - { dest: '"{{ file_dest }}"', regexp: 'Server=', line: 'Server="{{test_server}}"' }
      - { dest: '"{{ file_dest }}"', regexp: 'ServerActive=', line: 'ServerActive="{{test_server}}"' }
      - { dest: '"{{ file_dest }}"', regexp: 'Hostname=', line: 'Hostname="{{test_server_name}}"' }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.