2013-05-05 39 views
38

Tôi muốn sao chép đệ quy qua thư mục hiển thị tất cả các tệp .j2 trong đó làm mẫu. Đối với điều này, tôi hiện đang sử dụng các dòng sau:ansible - xóa các tập tin không được quản lý khỏi thư mục?

- template: > 
      src=/src/conf.d/{{ item }} 
      dest=/dest/conf.d/{{ item|replace('.j2','') }} 
    with_lines: find /src/conf.d/ -type f -printf "%P\n" 

Bây giờ tôi đang tìm cách xóa các tệp không được quản lý khỏi thư mục này. Ví dụ: nếu tôi xóa tệp/mẫu khỏi /src/conf.d/ Tôi cũng muốn Ansible xóa nó khỏi /dest/conf.d/.

Có cách nào để thực hiện việc này không? Tôi đã thử không quan trọng với rsync --delete, nhưng ở đó tôi gặp sự cố với các mẫu bị xóa hậu tố .j2.

Trả lời

2

Có thể có một số cách để xử lý việc này, nhưng có thể hoàn toàn trống thư mục đích trong một nhiệm vụ trước bước mẫu không? Hoặc có thể thả các tập tin templated vào một thư mục tạm thời và sau đó xóa + đổi tên trong một bước tiếp theo?

+2

Hoàn toàn dọn sạch thư mục đích trước khi sao chép có nghĩa là vở kịch sẽ luôn 'thay đổi'. Ngay cả khi không có thay đổi nào được thực hiện cho thư mục nguồn. Khi đổi tên cục bộ tệp (ví dụ: rsync-> render-> rename-> rsync), luôn có sự cố mà ansible sẽ báo cáo thay đổi (đổi tên) khi thực sự không có thay đổi. –

+1

@keks 'changed_when: false' sẽ sửa lỗi – ffghfgh

+0

Nhưng bạn muốn biết khi nào/nếu tệp cấu hình đã thay đổi để khởi động trình xử lý – dalore

45

Tôi sẽ làm điều đó như thế này, giả định một biến được định nghĩa là 'managed_files' trên cùng là danh sách.

- shell: ls -1 /some/dir 
    register: contents 

- file: path=/some/dir/{{ item }} state=absent 
    with_items: contents.stdout_lines 
    when: item not in managed_files 
+0

Cảm ơn. Hoạt động tuyệt vời. Bây giờ, bất kỳ tư vấn về cách tôi sẽ loại bỏ các tập tin nếu managed_files của tôi không có tên tập tin phạm vi nhưng các tập tin của tôi làm gì? Có lẽ đây là một câu hỏi hoàn toàn khác. – Batandwa

+1

Nó thực sự hoạt động. Đã cứu tôi từ việc hoàn thiện tóc của tôi. – Bwire

+1

@Batandwa bạn có thể sử dụng bộ lọc jinja, như thế này: 'khi: mục | regex_replace ('^ (. *) \\. Ext $', '\\ 1') không nằm trong managed_files' – menghan

0

Rõ ràng điều này là không thể với ansible tại thời điểm này. Tôi đã có một cuộc trò chuyện với mdehaan trên IRC và nó sôi xuống để ansible không có một tài nguyên directed acyclic graph, làm cho những thứ như thế này rất khó.

Yêu cầu mdehaan ví dụ, ví dụ: uy quyền quản lý một thư mục sudoers.d ông đã đưa ra những điều này:

14:17 < mdehaan> Robe: http://pastebin.com/yrdCZB0y 
14:19 < Robe> mdehaan: HM 
14:19 < Robe> mdehaan: that actually looks relatively sane 
14:19 < mdehaan> thanks :) 
14:19 < Robe> the problem I'm seeing is that I'd have to gather the managed files myself 
14:19 < mdehaan> you would yes 
14:19 < mdehaan> ALMOST 
14:20 < mdehaan> you could do a fileglob and ... well, it would be a little gross 
[..] 
14:32 < mdehaan> eh, theoretical syntax, nm 
14:33 < mdehaan> I could do it by writing a lookup plugin that filtered a list 
14:34 < mdehaan> http://pastebin.com/rjF7QR24 
14:34 < mdehaan> if that plugin existed, for instance, and iterated across lists in A that were also in B 
1

Thông thường tôi không gỡ bỏ những file nhưng tôi thêm -unmanaged hậu tố tên của nó. Mẫu nhiệm vụ ansible:

- name: Get sources.list.d files 
    shell: grep -r --include=\*.list -L '^# Ansible' /etc/apt/sources.list.d || true 
    register: grep_unmanaged 
    changed_when: grep_unmanaged.stdout_lines 

- name: Add '-unmanaged' suffix 
    shell: rename 's/$/-unmanaged/' {{ item }} 
    with_items: grep_unmanaged.stdout_lines 

GIẢI THÍCH

Grep lệnh sử dụng:

  • -r làm đệ quy tìm kiếm
  • --include=\*.list - chỉ mất file với phần mở rộng .list trong tìm kiếm đệ quy
  • -L '^# Ansible' - hiển thị tên tệp không có dòng bắt đầu bằng '# Ansible'
  • || true - điều này được sử dụng để bỏ qua lỗi. Ansible của ignore_errors cũng hoạt động nhưng trước khi bỏ qua các lỗi ansible sẽ hiển thị nó trong màu đỏ trong ansible-playbook chạy đó là không mong muốn (ít nhất là cho tôi).

Sau đó, tôi đăng ký đầu ra của lệnh grep dưới dạng biến. Khi grep hiển thị bất kỳ đầu ra nào tôi đặt nhiệm vụ này là đã thay đổi (dòng changed_when chịu trách nhiệm về điều này).

Trong tác vụ tiếp theo, tôi lặp lại đầu ra grep (tức là tên tệp được trả về bởi grep) và chạy lệnh đổi tên để thêm hậu tố cho mỗi tệp.

Đó là tất cả. Lần sau khi bạn chạy lệnh đầu tiên, nhiệm vụ phải có màu xanh lá cây và bỏ qua lần thứ hai.

+0

Cảm ơn! Đây là cách ưa thích của tôi để làm điều đó ngay bây giờ, bởi vì bình luận bình chọn hàng đầu không xử lý "công cụ không thay đổi" rất tốt. –

8

Chúng tôi làm điều này với các file nginx của chúng tôi, vì chúng tôi muốn họ được theo một thứ tự đặc biệt, đến từ các mẫu, nhưng loại bỏ những người không được quản lý công trình này:

# loop through the nginx sites array and create a conf for each file in order 
    # file will be name 01_file.conf, 02_file.conf etc 
    - name: nginx_sites conf 
    template: > 
     src=templates/nginx/{{ item.1.template }} 
     dest={{ nginx_conf_dir }}/{{ '%02d' % item.0 }}_{{ item.1.conf_name|default(item.1.template) }} 
     owner={{ user }} 
     group={{ group }} 
     mode=0660 
    with_indexed_items: nginx_sites 
    notify: 
     - restart nginx 
    register: nginx_sites_confs 

    # flatten and map the results into simple list 
    # unchanged files have attribute dest, changed have attribute path 
    - set_fact: 
     nginx_confs: "{{ nginx_sites_confs.results|selectattr('dest', 'string')|map(attribute='dest')|list + nginx_sites_confs.results|selectattr('path', 'string')|map(attribute='path')|select|list }}" 
    when: nginx_sites 

    # get contents of conf dir 
    - shell: ls -1 {{ nginx_conf_dir }}/*.conf 
    register: contents 
    when: nginx_sites 

    # so we can delete the ones we don't manage 
    - name: empty old confs 
    file: path="{{ item }}" state=absent 
    with_items: contents.stdout_lines 
    when: nginx_sites and item not in nginx_confs 

Bí quyết (như bạn có thể nhìn thấy) là mẫu đó và with_items có các thuộc tính khác nhau trong kết quả đăng ký. Sau đó, bạn biến chúng thành một danh sách các tập tin bạn quản lý và sau đó nhận được một danh sách các thư mục và loại bỏ những người không có trong danh sách đó.

Có thể được thực hiện với ít mã hơn nếu bạn đã có danh sách tệp. Nhưng trong trường hợp này, tôi đang tạo danh sách được lập chỉ mục, vì vậy cần phải tạo danh sách cũng như với bản đồ.

+2

Điều này rất hay - được bỏ phiếu. Mặc dù vậy, tôi đã vật lộn với nó: nếu bạn không chỉ định ký tự đại diện, nó sẽ so sánh đường dẫn đầy đủ và tên tệp chỉ với tên tệp để nó xóa mọi thứ. Thay vì 'ls -l' thử' tìm {{nginx_conf_dir}} -type f' thay vì trong trường hợp đó – Erfan

5

Tôi muốn chia sẻ kinh nghiệm của mình với trường hợp này.

Ansible from 2.2 đã có vòng lặp with_filetree cung cấp cách đơn giản để tải lên thư mục, liên kết, tệp tĩnh và thậm chí (!) Mẫu. Đó là cách tốt nhất để giữ cho thư mục cấu hình của tôi được đồng bộ hóa.

- name: etc config - Create directories 
    file: 
    path: "{{ nginx_conf_dir }}/{{ item.path }}" 
    state: directory 
    mode: 0755 
    with_filetree: etc/nginx 
    when: item.state == 'directory' 

- name: etc config - Creating configuration files from templates 
    template: 
    src: "{{ item.src }}" 
    dest: "{{ nginx_conf_dir }}/{{ item.path | regex_replace('\\.j2$', '') }}" 
    mode: 0644 
    with_filetree: etc/nginx 
    when: 
    - item.state == "file" 
    - item.path | match('.+\.j2$') | bool 

- name: etc config - Creating staic configuration files 
    copy: 
    src: "{{ item.src }}" 
    dest: "{{ nginx_conf_dir }}/{{ item.path }}" 
    mode: 0644 
    with_filetree: etc/nginx 
    when: 
    - item.state == "file" 
    - not (item.path | match('.+\.j2$') | bool) 

- name: etc config - Recreate symlinks 
    file: 
    src: "{{ item.src }}" 
    dest: "{{ nginx_conf_dir }}/{{ item.path }}" 
    state: link 
    force: yes 
    mode: "{{ item.mode }}" 
    with_filetree: etc/nginx 
    when: item.state == "link" 

Tiếp theo, chúng tôi có thể muốn xóa các tệp không sử dụng khỏi thư mục cấu hình. Thật đơn giản. Chúng tôi thu thập danh sách các tệp và tệp được tải lên tồn tại trên máy chủ từ xa, tiếp theo xóa sự khác biệt.

Nhưng chúng tôi có thể muốn có các tệp không được quản lý trong thư mục cấu hình. Tôi đã sử dụng chức năng -prune của find để tránh xóa các thư mục có tệp không được quản lý.

PS _ (Y) _ chắc chắn sau khi tôi đã xóa một số tập tin không được quản lý

- name: etc config - Gathering managed files 
    set_fact: 
    __managed_file_path: "{{ nginx_conf_dir }}/{{ item.path | regex_replace('\\.j2$', '') }}" 
    with_filetree: etc/nginx 
    register: __managed_files 

- name: etc config - Convert managed files to list 
    set_fact: managed_files="{{ __managed_files.results | map(attribute='ansible_facts.__managed_file_path') | list }}" 

- name: etc config - Gathering exist files (excluding .ansible_keep-content dirs) 
    shell: find /etc/nginx -mindepth 1 -type d -exec test -e '{}/.ansible_keep-content' \; -prune -o -print 
    register: exist_files 
    changed_when: False 

- name: etc config - Delete unmanaged files 
    file: path="{{ item }}" state=absent 
    with_items: "{{ exist_files.stdout_lines }}" 
    when: 
    - item not in managed_files 
+0

Điều này rất thông minh và cần có nhiều phiếu bầu hơn !!! –

1

Đây là điều mà tôi đã đưa ra:

 
- template: src=/source/directory{{ item }}.j2 dest=/target/directory/{{ item }} 
    register: template_results 
    with_items: 
    - a_list.txt 
    - of_all.txt 
    - templates.txt 
- set_fact: 
    managed_files: "{{ template_results.results|selectattr('invocation', 'defined')|map(attribute='invocation.module_args.dest')|list }}" 

- debug: 
    var: managed_files 
    verbosity: 0 

- find: 
    paths: "/target/directory/" 
    patterns: "*.txt" 
    register: all_files 
- set_fact: 
    files_to_delete: "{{ all_files.files|map(attribute='path')|difference(managed_files) }}" 

- debug: 
    var: all_files 
    verbosity: 0 
- debug: 
    var: files_to_delete 
    verbosity: 0 

- file: path={{ item }} state=absent 
    with_items: "{{ files_to_delete }}" 
  • này tạo ra các mẫu (tuy nhiên cách mà bạn muốn) và ghi lại kết quả trong 'template_results'
  • Kết quả bị xé để lấy danh sách đơn giản về "số phận" của từng mẫu. Các mẫu bị bỏ qua (do điều kiện khi không hiển thị) không có thuộc tính "yêu cầu", do đó chúng được lọc ra.
  • "tìm" sau đó được sử dụng để lấy danh sách tất cả các tệp sẽ bị thiếu trừ khi được ghi cụ thể.
  • điều này sau đó bị xén để lấy danh sách các tệp thô hiện tại và sau đó các tệp "được cho là có" được xóa.
  • Còn lại "files_to_delete" sau đó sẽ bị xóa.

Ưu điểm: Bạn tránh nhiều mục 'bỏ qua' hiển thị trong khi xóa.

Nhược điểm: Bạn sẽ cần ghép nối từng template_results.results nếu bạn muốn thực hiện nhiều tác vụ mẫu trước khi thực hiện tìm/xóa.

Các vấn đề liên quan