ansible: lineinfile für mehrere Zeilen?


166

Genauso wie es ein Modul gibt lineinfile, um eine Zeile in eine Datei einzufügen, gibt es eine Möglichkeit, mehrere Zeilen hinzuzufügen?

Ich möchte keine Vorlage verwenden, da Sie die gesamte Datei bereitstellen müssen. Ich möchte nur einer vorhandenen Datei etwas hinzufügen, ohne unbedingt zu wissen, was die Datei bereits enthält, sodass eine Vorlage keine Option ist.


Ich verstehe, dass Sie nicht verwenden möchten template, aber verwenden lineinfileist ein Antimuster . Es ist auch eine starke rote Fahne, dass Sie "nicht wissen, was in der Datei enthalten ist", was zu einem erheblichen Risiko unbekannter Fehler führt.
Tedder42

40
Es ist kein Anti-Muster. Der Punkt von lineinfile besteht darin, mehrere Quellen zu unterstützen, die dieselbe Datei verwalten, was manchmal unvermeidlich ist. Die meisten Konfigurationsdateien haben ein festes Format und die Logik zur Vermeidung von Konflikten ist normalerweise nicht zu umfangreich.
Doug F

Ich weiß nicht, was in den meisten Dateien auf meinem PC enthalten ist. heißt nicht, dass ich sie alle zerstören will!
DylanYoung

Antworten:


230

Sie können dazu eine Schleife verwenden. Hier ist ein Beispiel mit einer with_itemsSchleife:

- 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' }

Stellen Sie sicher, dass Sie das Argument line = und regexp = in Anführungszeichen haben . Ich tat es nicht und ich bekam es immer wieder msg: this module requires key=value arguments. Das gegebene Beispiel hat dies richtig - ich bin dem Beispiel einfach nicht gefolgt.
JDS

1
Darf ich fragen, wie vor der ersten Änderung eine einzelne Sicherung durchgeführt werden soll? vielleicht item.backup? : D
tdihp

6
Dies wurde wahrscheinlich vor Ansible 2.0 abgestimmt. Eine bessere Antwort ist jetzt: stackoverflow.com/a/28306576/972128
kkurian

@kkurian Sicher nur, wenn Sie einfügen, nicht, wenn Sie ersetzen?
ndtreviv

7
@kkurian Die Blockinfile-Lösung funktioniert nicht, wenn Sie z. B. einer json-Datei einige Zeilen hinzufügen müssen und keine Markierungen wünschen. Während Sie Markierungen auf "" setzen können, sucht ansible blockinfile weiterhin nach Markierungen, findet keine und fügt den Block erneut ein. Blockinfile ohne Marker ist also nicht idempotent, Lineinfile mit einer Schleife.
absurd

181

Sie können es blockinfilestattdessen versuchen .

Sie können so etwas tun

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

8
Das blockinfileModul hat jedes Mal wunderbar funktioniert, wenn ich es verwendet habe. Ich mag besonders das intuitive Verhalten der insertafter/ insertbeforeOptionen.
Jay Taylor

9
Die Antwort mit der höchsten Stimme war wahrscheinlich vor Ansible 2.0, aber dies ist jetzt die korrektere Antwort.
Willem van Ketwich

11
Blockinfile erfordert Marker. Dies ist manchmal keine Option.
Ceving

1
Können wir Inhalte mit überschreiben blockinfile?
Karamol

1
Es ist ein richtiger Weg, denke ich. docs.ansible.com/ansible/blockinfile_module.html
Paulo Victor

21

Wenn Sie eine Reihe eindeutiger Eigenschafts- / Wertzeilen konfigurieren müssen, empfehle ich eine präzisere Schleife. Zum Beispiel:

- 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' }

Verwenden Sie ein Diktat, wie von Alix Axel vorgeschlagen, und fügen Sie das automatische Entfernen übereinstimmender auskommentierter Einträge hinzu.

- 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
Wenn Sie with_dict verwenden, ist dies prägnanter.
Alix Axel

20

Hier ist eine rauschfreie Version der Lösung, die mit_items verwendet werden soll:

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

Wenn für jeden Artikel der Artikel in obst.txt vorhanden ist, wird keine Aktion ausgeführt.

Wenn das Element nicht vorhanden ist, wird es an das Ende der Datei angehängt.

Kinderleicht.


Dies kann nicht mit Insertafter kombiniert werden.
Ceving

Wenn mehrere Zeilen fehlen, möchte ich, dass der Artikel in einer Bestellung angezeigt wird. Wie kann ich sicher sein, in welcher Reihenfolge Artikel angehängt werden?
MUY Belgien

5

Es ist nicht ideal, aber Sie dürfen mehrere Anrufe tätigen lineinfile. Wenn Sie das mit verwenden insert_after, können Sie das gewünschte Ergebnis erzielen:

- 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
Ja, aber es ist immer noch eine Zeile nach der anderen. Wenn ich 15 Zeilen habe, würde ich sie lieber mit nur einem Befehl hinzufügen. Es scheint nicht möglich zu sein.
Michael

1
Vielen Dank. Es scheint, dass dies immer noch die einzige Möglichkeit ist, mehrere Zeilen mit Einfügen nach / vor zu erstellen.
Timss

5

Das konnte ich mit dem Zeilenparameter tun \n.

Es ist besonders nützlich, wenn die Datei validiert werden kann und das Hinzufügen einer einzelnen Zeile eine ungültige Datei erzeugt.

In meinem Fall war ich das Hinzufügen AuthorizedKeysCommandund AuthorizedKeysCommandUserzu sshd_config , mit dem folgenden Befehl:

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

Wenn Sie nur eine der Optionen hinzufügen, wird eine Datei generiert, deren Validierung fehlschlägt.


12
Dadurch wird die Zeile jedes Mal ein zusätzliches Mal erstellt, wenn das Playbook ausgeführt wird. Es wird nicht korrekt erkannt, dass die Zeile bereits vorhanden ist. Zumindest ist das bei Ansible 1.7.1
David

1
Ich habe einen Fehler gemeldet , aber die Ansible-Leute haben kein Interesse daran, ihn zu beheben.
Ceving

1
Es gibt ein neues Blockinfile-Modul, das jetzt besser sein sollte als diese Lösung. ( docs.ansible.com/ansible/blockinfile_module.html )
Penz

2

Um mehrere Zeilen hinzuzufügen, können Sie das lineinfileModul verwenden with_items, das varshier auch eine Variable enthält , um es einfach zu machen :)

---
- 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}}"' }

1

Um mehrere Zeilen hinzuzufügen, können Sie Blockdatei verwenden:

- 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'

Um eine Zeile hinzuzufügen, können Sie lininfile verwenden:

- name: server.example.com in /etc/hosts
  lineinfile:
    path: /etc/hosts
    line: '192.0.2.42 server.example.com server'
    state: present
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.