ansible: lineinfile untuk beberapa baris?

162

Cara yang sama ada modul lineinfileuntuk menambahkan satu baris dalam file, apakah ada cara untuk menambahkan beberapa baris?

Saya tidak ingin menggunakan templat karena Anda harus menyediakan seluruh file. Saya hanya ingin menambahkan sesuatu ke file yang sudah ada tanpa harus mengetahui file apa yang sudah berisi sehingga template bukan pilihan.

Michael
sumber
Saya mengerti Anda tidak ingin menggunakan template, tetapi menggunakan lineinfileadalah antipattern . Ini juga merupakan tanda merah yang kuat bahwa Anda "tidak tahu apa yang ada di file", yang mengarah pada risiko besar kegagalan yang tidak diketahui.
tedder42
39
Itu bukan anti-pola. Maksud lineinfile adalah untuk mendukung banyak sumber yang mengelola file yang sama, yang terkadang tidak dapat dihindari. Sebagian besar file konfigurasi memiliki format dan logika tetap untuk menghindari konflik biasanya tidak terlalu besar.
Doug F
Saya tidak tahu apa yang ada di sebagian besar file di PC saya; bukan berarti saya ingin nuke mereka semua!
DylanYoung

Jawaban:

222

Anda dapat menggunakan loop untuk melakukannya. Berikut ini contoh menggunakan with_itemsloop:

- 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' }
Ben Whaley
sumber
PASTIKAN Anda memiliki argumen untuk baris = dan regexp = dalam tanda kutip . Aku tidak, dan saya terus mendapatkan msg: this module requires key=value arguments. Contoh yang diberikan memang memiliki ini benar - Saya hanya tidak mengikuti contoh.
JDS
1
Bolehkah saya bertanya bagaimana cara melakukan backup tunggal sebelum perubahan pertama? mungkin item.backup? : D
tdihp
6
Ini mungkin dipilih sebelum Ansible 2.0. Jawaban yang lebih baik adalah sekarang: stackoverflow.com/a/28306576/972128
kkurian
@kkurian Tentunya hanya jika Anda memasukkan, bukan jika Anda mengganti?
ndtreviv
7
@kkurian Solusi blockinfile tidak akan berfungsi jika Anda misalnya perlu menambahkan beberapa baris ke file json dan tidak ingin ada marker. Meskipun Anda dapat mengatur marker ke "", blockinfile yang masih ada masih akan mencari marker, tidak menemukan apa pun, dan memasukkan blok lagi. Jadi, blockinfile tanpa spidol tidak idempoten, lineinfile dengan perulangan adalah
absurd
176

Anda dapat mencoba menggunakan blockinfilesebagai gantinya.

Anda dapat melakukan sesuatu seperti

- blockinfile: |
    dest=/etc/network/interfaces backup=yes
    content="iface eth0 inet static
        address 192.168.0.1
        netmask 255.255.255.0"
Soichi Hayashi
sumber
8
The blockinfilemodul telah berhasil keluar indah setiap kali saya telah memilih untuk menggunakannya. Aku terutama suka perilaku intuitif insertafter/ insertbeforepilihan.
Jay Taylor
9
Jawaban dengan suara tertinggi mungkin sebelum Ansible 2.0, tetapi ini adalah jawaban yang lebih benar sekarang.
Willem van Ketwich
11
Blockinfile membutuhkan spidol. Ini terkadang tidak ada pilihan.
ceving
1
Apakah kami dapat menimpa konten blockinfile?
pkaramol
1
Kurasa itu cara yang tepat untuk melakukannya. docs.ansible.com/ansible/blockinfile_module.html
Paulo Victor
20

Jika Anda perlu mengonfigurasi serangkaian garis properti = nilai unik, saya sarankan loop yang lebih ringkas. Sebagai contoh:

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

Menggunakan dikt seperti yang disarankan oleh Alix Axel dan menambahkan penghapusan otomatis dari entri komentar yang cocok,

- 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
Nicholas Sushkin
sumber
2
Jika Anda menggunakan with_dict akan lebih ringkas.
Alix Axel
18

Berikut ini adalah versi bebas dari solusi yang digunakan dengan with_items:

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

Untuk setiap item, jika item tersebut ada di fruits.txt tidak ada tindakan yang diambil.

Jika item tidak ada, maka akan ditambahkan ke akhir file.

Mudah marah.

Rick O'Shea
sumber
Ini tidak dapat digabungkan dengan insertafter.
ceving
Jika beberapa baris tidak ada, saya ingin item muncul dalam pesanan. Bagaimana saya bisa yakin dengan urutan item yang ditambahkan?
MUY Belgium
5

Ini tidak ideal, tetapi Anda diizinkan untuk melakukan beberapa panggilan lineinfile. Dengan itu insert_after, Anda bisa mendapatkan hasil yang diinginkan:

- 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"
Ramon de la Fuente
sumber
5
ya tapi itu masih satu baris pada satu waktu. Jika saya memiliki 15 baris, saya lebih suka menambahkannya dengan hanya satu perintah. Sepertinya tidak mungkin.
Michael
1
Terima kasih. Tampaknya ini masih satu-satunya cara untuk melakukan banyak baris dengan menyisipkan setelah / sebelumnya.
timss
5

Saya dapat melakukannya dengan menggunakan \nparameter baris.

Ini sangat berguna jika file tersebut dapat divalidasi, dan menambahkan satu baris menghasilkan file yang tidak valid.

Dalam kasus saya, saya menambahkan AuthorizedKeysCommanddan AuthorizedKeysCommandUserke sshd_config , dengan perintah berikut:

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

Menambahkan hanya satu opsi menghasilkan file yang gagal validasi.

Penz
sumber
12
Ini akan membuat garis waktu tambahan setiap kali playbook dijalankan - itu tidak benar mengenali bahwa garis sudah ada. Setidaknya, itulah yang terjadi pada saya pada Ansible 1.7.1
David
1
Saya melaporkan bug , tetapi orang-orang Ansible tidak tertarik untuk memperbaikinya.
ceving
1
Ada modul blockinfile baru yang seharusnya lebih baik daripada solusi itu sekarang. ( docs.ansible.com/ansible/blockinfile_module.html )
Penz
1

Untuk menambahkan beberapa baris, Anda dapat menggunakan blockfile:

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

untuk menambahkan satu baris, Anda dapat menggunakan lininfile:

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

Untuk menambahkan beberapa baris, Anda dapat menggunakan lineinfilemodul dengan with_itemsmenyertakan variabel di varssini untuk membuatnya lebih mudah :)

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