ansible: lineinfile cho một số dòng?


162

Cùng một cách có một mô-đun lineinfileđể thêm một dòng trong một tệp, có cách nào để thêm một vài dòng không?

Tôi không muốn sử dụng một mẫu vì bạn phải cung cấp toàn bộ tệp. Tôi chỉ muốn thêm một cái gì đó vào một tệp hiện có mà không nhất thiết phải biết những gì tệp đã chứa để một mẫu không phải là một tùy chọn.


Tôi hiểu rằng bạn không muốn sử dụng template, nhưng sử dụng lineinfilelà một antipotype . Đó cũng là một lá cờ đỏ mạnh mẽ mà bạn "không biết những gì trong tập tin", dẫn đến nguy cơ thất bại đáng kể.
tedder42

39
Nó không phải là một mô hình chống. Quan điểm của lineinfile là hỗ trợ nhiều nguồn quản lý cùng một tệp, điều này đôi khi không thể tránh khỏi. Hầu hết các tệp cấu hình có định dạng và logic cố định để tránh xung đột thường không quá lớn.
Doug F

Tôi không biết những gì trong phần lớn các tệp trên PC của tôi; không có nghĩa là tôi muốn nuke tất cả!
DylanYoung

Câu trả lời:


221

Bạn có thể sử dụng một vòng lặp để làm điều đó. Đây là một ví dụ sử dụng with_itemsvòng lặp:

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

HÃY ĐẢM BẢO bạn có đối số để line = và regapi = trong dấu ngoặc kép . Tôi đã không, và tôi tiếp tục nhận được msg: this module requires key=value arguments. Ví dụ đưa ra có đúng điều này - tôi chỉ không làm theo ví dụ.
JDS

1
Tôi có thể hỏi làm thế nào để thực hiện một bản sao lưu duy nhất trước khi thay đổi đầu tiên không? có thể item.backup? : D
tdihp

6
Điều này có lẽ đã được bình chọn trước Ansible 2.0. Một câu trả lời tốt hơn bây giờ là: stackoverflow.com/a/28306576/972128
kkurian

@kkurian Chắc chắn chỉ khi bạn chèn chứ không phải nếu bạn thay thế?
ndtreviv

7
@kkurian Giải pháp blockinfile sẽ không hoạt động nếu bạn muốn thêm một số dòng vào tệp json và không muốn bất kỳ điểm đánh dấu nào. Mặc dù bạn có thể đặt các điểm đánh dấu thành "", blockinfile ansible vẫn sẽ tìm kiếm các điểm đánh dấu, không tìm thấy bất kỳ điểm nào và chèn lại khối. Vì vậy, blockinfile không có markers không phải là idempotent, lineinfile với một vòng lặp là.
vô lý

176

Bạn có thể thử sử dụng blockinfilethay thế.

Bạn có thể làm một cái gì đó như

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

8
Các blockinfilemô-đun đã đề ra tuyệt vời mỗi khi tôi đã chọn để sử dụng nó. Tôi đặc biệt thích hành vi trực quan của insertafter/ insertbeforetùy chọn.
Jay Taylor

9
Câu trả lời được bình chọn cao nhất có lẽ là trước Ansible 2.0, nhưng đây là câu trả lời đúng hơn bây giờ.
Willem van Ketwich

11
Blockinfile yêu cầu đánh dấu. Điều này đôi khi không có tùy chọn.
ceving

1
Chúng tôi có thể ghi đè lên nội dung với blockinfile?
pkaramol

1
Đó là một cách đúng đắn để làm điều đó tôi nghĩ. docs.ansible.com/ansible/blockinfile_module.html
Paulo Victor

20

Nếu bạn cần định cấu hình một tập hợp các dòng property = value duy nhất, tôi khuyên bạn nên sử dụng một vòng lặp ngắn gọn hơn. Ví dụ:

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

Sử dụng một lệnh chính được đề xuất bởi Alix Axel và thêm tự động loại bỏ các mục đã nhận xét phù hợp,

- 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
Nếu bạn sử dụng with_dict thì sẽ ngắn gọn hơn.
Alix Axel

18

Đây là phiên bản không có tiếng ồn của giải pháp sử dụng with_items:

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

Đối với mỗi mục, nếu mục tồn tại trong fruit.txt, không có hành động nào được thực hiện.

Nếu mục không tồn tại, nó sẽ được thêm vào cuối tập tin.

Dễ như ăn bánh.


Điều này không thể được kết hợp với insertafter.
ceving

Nếu nhiều dòng bị thiếu, tôi muốn mục này xuất hiện theo thứ tự. Làm thế nào tôi có thể chắc chắn về thứ tự các mặt hàng được nối thêm?
MUY Bỉ

5

Điều đó không lý tưởng, nhưng bạn được phép nhiều cuộc gọi đến lineinfile. Sử dụng với insert_after, bạn có thể nhận được kết quả bạn muốn:

- 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
có nhưng nó vẫn là một dòng tại một thời điểm. Nếu tôi có 15 dòng, tôi muốn thêm chúng chỉ với một lệnh. Nó dường như không thể.
Michael

1
Cảm ơn. Có vẻ như đây vẫn là cách duy nhất để thực hiện nhiều dòng với chèn sau / trước.
timss

5

Tôi đã có thể làm điều đó bằng cách sử dụng \ntrong tham số dòng.

Nó đặc biệt hữu ích nếu tệp có thể được xác nhận và thêm một dòng sẽ tạo một tệp không hợp lệ.

Trong trường hợp của tôi, tôi đã thêm AuthorizedKeysCommandAuthorizedKeysCommandUservào sshd_config , bằng lệnh sau:

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

Chỉ thêm một trong các tùy chọn sẽ tạo một tệp không xác thực.


12
Điều này sẽ tạo ra dòng thêm một lần mỗi khi playbook được chạy - nó không nhận ra chính xác rằng dòng đã tồn tại. Ít nhất, đó là trường hợp của tôi trên Ansible 1.7.1
David

1
Tôi đã báo cáo một lỗi , nhưng những người Ansible không có hứng thú để sửa nó.
ceving

1
Có một mô-đun blockinfile mới nên tốt hơn giải pháp đó bây giờ. ( docs.ansible.com/ansible/blockinfile_module.html )
Penz

1

Để thêm nhiều dòng, bạn có thể sử dụng 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'

để thêm một dòng bạn có thể sử dụng lininfile:

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

1

Để thêm nhiều dòng, bạn có thể sử dụng lineinfilemô-đun với with_itemsbao gồm cả biến varsở đây để làm cho nó đơn giản :)

---
- 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}}"' }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.