ansible: lineinfile สำหรับหลายบรรทัด?


162

เช่นเดียวกับที่มีโมดูลlineinfileสำหรับเพิ่มหนึ่งบรรทัดในไฟล์มีวิธีเพิ่มหลายบรรทัดหรือไม่?

ฉันไม่ต้องการใช้เทมเพลตเพราะคุณต้องเตรียมไฟล์ทั้งหมด ฉันต้องการเพิ่มบางสิ่งลงในไฟล์ที่มีอยู่โดยไม่จำเป็นต้องรู้ว่าไฟล์มีอยู่แล้วดังนั้นเทมเพลตจึงไม่ใช่ตัวเลือก


เราเข้าใจว่าคุณไม่ต้องการที่จะใช้งานtemplateแต่ใช้lineinfileเป็นantipattern นอกจากนี้ยังมีการตั้งค่าสถานะสีแดงที่แข็งแกร่งที่คุณ "ไม่ทราบว่ามีอะไรในไฟล์" ซึ่งนำไปสู่ความเสี่ยงที่สำคัญของความล้มเหลวที่ไม่รู้จัก
tedder42

39
มันไม่ใช่รูปแบบการต่อต้าน จุดของ lineinfile คือการรองรับหลายแหล่งที่จัดการไฟล์เดียวกันซึ่งบางครั้งก็หลีกเลี่ยงไม่ได้ ไฟล์กำหนดค่าส่วนใหญ่มีรูปแบบคงที่และตรรกะเพื่อหลีกเลี่ยงความขัดแย้งมักจะไม่มากเกินไป
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' }

ให้แน่ใจว่าคุณมีการโต้แย้งกับสาย = และ = regexp ในเครื่องหมายคำพูด msg: this module requires key=value argumentsฉันไม่ได้และฉันเก็บรับ ตัวอย่างที่ให้มามีความถูกต้อง - ฉันแค่ไม่ได้ทำตามตัวอย่าง
JDS

1
ฉันขอถามวิธีการสำรองข้อมูลเดียวก่อนการเปลี่ยนแปลงครั้งแรกได้หรือไม่ อาจจะเป็นรายการสำรองข้อมูล? : D
tdihp

6
นี่อาจจะถูกโหวตก่อน Ansible 2.0 คำตอบที่ดีกว่าคือตอนนี้: stackoverflow.com/a/28306576/972128
kkurian

@kkurian แน่นอนว่าเฉพาะเมื่อคุณกำลังแทรกไม่ใช่ถ้าคุณกำลังเปลี่ยน?
ndtreviv

7
@kkurian โซลูชัน blockinfile จะไม่ทำงานหากคุณต้องการเพิ่มบางบรรทัดในไฟล์ json และไม่ต้องการเครื่องหมายใด ๆ ในขณะที่คุณสามารถตั้งค่าตัวทำเครื่องหมายเป็น "", บล็อกที่กรองได้จะยังคงมองหาเครื่องหมายไม่พบใด ๆ และใส่บล็อกอีกครั้ง ดังนั้น blockinfile ที่ไม่มีเครื่องหมายไม่ใช่ idempotent, lineinfile ที่มีลูปคือ
ไร้สาระ

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ตัวเลือก
Jay Taylor

9
คำตอบที่ได้รับการโหวตมากที่สุดน่าจะเป็นก่อน Ansible 2.0 แต่ตอนนี้เป็นคำตอบที่ถูกต้องมากกว่านี้
Willem van Ketwich

11
Blockinfile จำเป็นต้องมีเครื่องหมาย บางครั้งไม่มีตัวเลือก
ceving

1
เราสามารถเขียนทับเนื้อหาด้วยได้blockinfileหรือไม่?
pkaramol

1
ฉันคิดว่ามันเป็นวิธีที่ถูกต้อง docs.ansible.com/ansible/blockinfile_module.html
Paulo Victor

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

ใช้ dict ตามที่ 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 มันจะกระชับมากขึ้น
Alix Axel

18

นี่คือโซลูชันที่ปราศจากเสียงรบกวนซึ่งจะใช้ with_items:

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

สำหรับแต่ละรายการหากมีรายการอยู่ใน fruits.txt จะไม่มีการดำเนินการใด ๆ

หากไม่มีรายการรายการนั้นจะถูกผนวกเข้าที่ท้ายไฟล์

ง่าย peasy


สิ่งนี้ไม่สามารถใช้ร่วมกับส่วนแทรกได้ภายหลัง
ceving

หากไม่มีหลายบรรทัดฉันต้องการให้รายการปรากฏในการสั่งซื้อ ฉันจะมั่นใจได้อย่างไรว่ามีการเรียงลำดับรายการใดต่อท้าย
MUY เบลเยี่ยม

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 บรรทัดฉันต้องการเพิ่มให้กับคำสั่งเดียวเท่านั้น ดูเหมือนจะเป็นไปไม่ได้
Michael

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 ไม่สนใจที่จะแก้ไข
ceving

1
มีโมดูล blockinfile ใหม่ที่ควรจะดีกว่าโซลูชันในตอนนี้ ( docs.ansible.com/ansible/blockinfile_module.html )
Penz

1

ในการเพิ่มหลายบรรทัดคุณสามารถใช้ 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'

เพื่อเพิ่มหนึ่งบรรทัดคุณสามารถใช้ 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}}"' }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.