Ansible: Como excluir arquivos e pastas dentro de um diretório?

152

O código abaixo exclui apenas o primeiro arquivo que ele obtém dentro do diretório da web. Desejo remover todos os arquivos e pastas dentro do diretório da web e retê-lo. Como eu posso fazer isso?

  - name: remove web dir contents
     file: path='/home/mydata/web/{{ item }}' state=absent
     with_fileglob:
       - /home/mydata/web/*

Nota: Tentei rm -rfusar o comando e o shell, mas eles não funcionam. Talvez eu esteja usando-os incorretamente.

Qualquer ajuda na direção certa será apreciada.

Estou usando o ansible 2.1.0.0

Abbas
fonte
Parece um bug.
ceving 27/10/16

Respostas:

132

O código abaixo excluirá todo o conteúdo de artifact_path

- name: Clean artifact path
  file:
    state: absent
    path: "{{ artifact_path }}/"

Nota : isso também excluirá o diretório.

Mohan Kumar P
fonte
3
aspas não são necessárias. Este é apenas o meu código de trabalho. artifact_path é como / app / my_app / work / #
Mohan Kumar P
83
O OP (e eu) deseja uma solução que exclua o conteúdo da pasta, MAS NÃO a própria pasta. Esta solução exclui o conteúdo e a própria pasta.
estocástica
19
Como isso foi aprovado? Isso exclui o diretório também.
Deppfx
17
Alguém teve o código acima falhar neles com artifact_path sendo nulo? Isto parece que poderia ser suscetível a um desses grandes rm -rf /momentos da história
ted-K42
2
@ ted-K42 eu faria algo como isso apenas para ser seguro:when: artifact_path is defined and artifact_path != ""
bmaupin
69

Usando o módulo shell ( também idempotente ):

- shell: /bin/rm -rf /home/mydata/web/*

Solução mais limpa se você não se importa com a data de criação e o proprietário / permissões:

- file: path=/home/mydata/web state=absent
- file: path=/home/mydata/web state=directory
olaV
fonte
7
Funciona, mas não removeu arquivos começando com. como .htaccess
Abbas
A Shell também trabalhou para mim. Exatamente a mesma tarefa, mas trocado shelldentro para commande ele funciona
SomethingOn
4
Os curingas não funcionam com o comando, pois exigem um shell para expansão
JamesP
1
Observe que isso pode alterar suas permissões / proprietário, a menos que você defina explicitamente durante o momento da criação.
NeverEndingQueue
Usando o shell, você receberá um aviso de uso do módulo de arquivo com state = ausente em vez de shell rm. Para evitá-lo basta adicionar args: avisar: false
Rodrigo
60

Remova o diretório (basicamente uma cópia de https://stackoverflow.com/a/38201611/1695680 ), o Ansible faz essa operação rmtreesob o capô.

- name: remove files and directories
  file:
    state: "{{ item }}"
    path: "/srv/deleteme/"
    owner: 1000  # set your owner, group, and mode accordingly
    group: 1000
    mode: '0777'
  with_items:
    - absent
    - directory

Se você não tiver o luxo de remover o diretório inteiro e recriá-lo, poderá procurar arquivos (e diretórios) e excluí-los um a um. O que vai demorar um pouco. Você provavelmente quer ter certeza de que tem[ssh_connection]\npipelining = True seu ansible.cfg ativado.

- block:
  - name: 'collect files'
    find:
      paths: "/srv/deleteme/"
      hidden: True
      recurse: True
      # file_type: any  # Added in ansible 2.3
    register: collected_files

  - name: 'collect directories'
    find:
      paths: "/srv/deleteme/"
      hidden: True
      recurse: True
      file_type: directory
    register: collected_directories

  - name: remove collected files and directories
    file:
      path: "{{ item.path }}"
      state: absent
    with_items: >
      {{
        collected_files.files
        + collected_directories.files
      }}
ThorSummoner
fonte
6
A primeira tarefa é a solução mais elegante que eu já vi. Observe os comentários em outro lugar que há uma solicitação de recurso de longa duração a ser adicionadastate=empty
William Turrell 23/03
24

Eu realmente não gostei da solução rm, também o ansible fornece avisos sobre o uso de rm. Então, aqui está como fazê-lo sem a necessidade de rm e sem avisos ansíveis.

- hosts: all
  tasks:
  - name: Ansible delete file glob
    find:
      paths: /etc/Ansible
      patterns: "*.txt"
    register: files_to_delete

  - name: Ansible remove file glob
    file:
      path: "{{ item.path }}"
      state: absent
    with_items: "{{ files_to_delete.files }}"

fonte: http://www.mydailytutorials.com/ansible-delete-multiple-files-directories-ansible/

Cris
fonte
ainda a melhor solução para a pergunta !!
Vsegar 6/06
18

tente o comando abaixo, ele deve funcionar

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

- file: path=/some/dir/{{ item }} state=absent
  with_items: {{ contents.stdout_lines }}
Ganesan Srinivasan
fonte
3
você perdeu para escapar corretamente da última linha com {{,}} para obterwith_items: "{{ contents.stdout_lines }}"
Valerio Crini 29/17/17
É perigoso usar ls'output para obter nomes de arquivos porque não imprime corretamente nomes de arquivos com caracteres especiais, como novas linhas.
bfontaine
5

Criou uma implementação geral rehauled e à prova de falhas a partir de todos os comentários e sugestões:

# collect stats about the dir
- name: check directory exists
  stat:
    path: '{{ directory_path }}'
  register: dir_to_delete

# delete directory if condition is true
- name: purge {{directory_path}}
  file:
    state: absent
    path: '{{ directory_path  }}'
  when: dir_to_delete.stat.exists and dir_to_delete.stat.isdir

# create directory if deleted (or if it didn't exist at all)
- name: create directory again
  file:
    state: directory
    path: '{{ directory_path }}'
  when: dir_to_delete is defined or dir_to_delete.stat.exist == False
Markus
fonte
Eu acho que você está perdendo o registerpara plugin_dir_deleted, certo?
Bob Vork
obrigado por apontar isso. Eu tive este pedaço de código retirado de um dos meus playbooks e tornou mais genérica em termos de nomenclatura, mas se esqueça de substituir dois nomes de variáveis
Markus
1
Coisas boas, mas acho que o estado na última tarefa precisa ser definido como "diretório" em vez de "presente".
Andrew Allaire
1
Você deve usar seu resultado stat para preservar as permissões: owner from pw_name, group from gr_name e mode from mode.
DylanYoung
tentei, owner: dir_to_delete.stat.pw_name, group: dir_to_delete.stat.gr_name mode: dir_to_delete.stat.modemas ele falha em mim com a minha versão atual do Ansible :(
Markus
3

Usando o arquivo glob também funcionará. Há algum erro de sintaxe no código que você postou. Eu modifiquei e testei isso deve funcionar.

- name: remove web dir contents
  file:
    path: "{{ item }}"
    state: absent
  with_fileglob:
    - "/home/mydata/web/*"
Deepali Mittal
fonte
7
with_fileglobfunciona apenas na máquina local, não na remota; não é verdade?
Stepan Vavra
Verdadeiro .. with_fileglob é apenas para local #
Deepali Mittal
Além disso, isso não exclui diretórios, apenas os arquivos são excluídos.
precisa saber é o seguinte
2

Enquanto o Ansible ainda está debatendo para implementar state = empty https://github.com/ansible/ansible-modules-core/issues/902

my_folder: "/home/mydata/web/"
empty_path: "/tmp/empty"


- name: "Create empty folder for wiping."
  file:
    path: "{{ empty_path }}" 
    state: directory

- name: "Wipe clean {{ my_folder }} with empty folder hack."
  synchronize:
    mode: push

    #note the backslash here
    src: "{{ empty_path }}/" 

    dest: "{{ nl_code_path }}"
    recursive: yes
    delete: yes
  delegate_to: "{{ inventory_hostname }}"

Observe, porém, com a sincronização, você poderá sincronizar seus arquivos (com exclusão) corretamente de qualquer maneira.

Marcin
fonte
2

Isso é o que eu proponho:

- name: Get directory listing
  find:
    path: "{{ directory }}" 
    file_type: any
    hidden: yes
  register: directory_content_result

- name: Remove directory content
  file:
    path: "{{ item.path }}" 
    state: absent
  with_items: "{{ directory_content_result.files }}" 
  loop_control:
    label: "{{ item.path }}" 

Primeiro, estamos recebendo a listagem de diretórios com find, definindo

  • file_typepara anynão perdermos diretórios e links aninhados
  • hiddenpara yes, para não pularmos arquivos ocultos
  • Além disso, não defina recursecomo yes, pois não é apenas desnecessário, mas pode aumentar o tempo de execução.

Então, passamos por essa lista com o filemódulo. Sua saída é um pouco detalhada, por loop_control.labelisso nos ajudará a limitar a saída (encontrei este conselho aqui ).


Mas achei a solução anterior um pouco lenta, pois itera pelo conteúdo, então fui com:

- name: Get directory stats
  stat:
    path: "{{ directory }}"
  register: directory_stat

- name: Delete directory
  file:
    path: "{{ directory }}"
    state: absent

- name: Create directory
  file:
    path: "{{ directory }}"
    state: directory
    owner: "{{ directory_stat.stat.pw_name }}"
    group: "{{ directory_stat.stat.gr_name }}"
    mode: "{{ directory_stat.stat.mode }}"
  • obter propriedades do diretório com o stat
  • excluir diretório
  • recrie o diretório com as mesmas propriedades.

Isso foi o suficiente para mim, mas você pode adicionar attributestambém, se quiser.

Alexander
fonte
1

Há um problema em aberto com relação a isso.

Por enquanto, a solução funciona para mim: crie uma pasta vazia localmente e sincronize-a com a remota.

Aqui está um exemplo de manual:

- name: "Empty directory"
  hosts: *
  tasks:
    - name: "Create an empty directory (locally)"
      local_action:
        module: file
        state: directory
        path: "/tmp/empty"

    - name: Empty remote directory
      synchronize:
        src: /tmp/empty/
        dest: /home/mydata/web/
        delete: yes
        recursive: yes
w1100n
fonte
1

Eu escrevi um módulo ansible personalizado para limpar arquivos com base em vários filtros, como idade, carimbo de data e hora, padrões glob, etc.

Também é compatível com versões antigas ansible. Pode ser encontrado aqui .

Aqui está um exemplo:

- cleanup_files:
  path_pattern: /tmp/*.log
  state: absent
  excludes:
    - foo*
    - bar*
Rahul
fonte
0

Quero ter certeza de que o comando find exclua apenas tudo dentro do diretório e deixe o diretório intacto, porque no meu caso, o diretório é um sistema de arquivos. O sistema irá gerar um erro ao tentar excluir um sistema de arquivos, mas essa não é uma boa opção. Estou usando a opção de shell, porque essa é a única opção de trabalho que encontrei até agora para esta pergunta.

O que eu fiz:

Edite o arquivo hosts para inserir algumas variáveis:

[all:vars]
COGNOS_HOME=/tmp/cognos
find=/bin/find

E crie um manual:

- hosts: all
  tasks:
  - name: Ansible remove files
    shell: "{{ find }} {{ COGNOS_HOME }} -xdev -mindepth 1 -delete"

Isso excluirá todos os arquivos e diretórios no diretório / sistema de arquivos variáveis ​​COGNOS_HOME. A opção "-mindepth 1" garante que o diretório atual não seja tocado.

Tjerk Maij
fonte
0

Apenas um pequeno modelo de copiar e colar mais limpo da resposta do ThorSummoners, se você estiver usando Ansible> = 2.3 (distinção entre arquivos e diretórios não é mais necessária).

- name: Collect all fs items inside dir
  find:
    path: "{{ target_directory_path }}"
    hidden: true
    file_type: any
  changed_when: false
  register: collected_fsitems
- name: Remove all fs items inside dir
  file:
    path: "{{ item.path }}"
    state: absent
  with_items: "{{ collected_fsitems.files }}"
  when: collected_fsitems.matched|int != 0
Enno Gröper
fonte
-1

Supondo que você esteja sempre no Linux, tente o findcmd.

- name: Clean everything inside {{ item }}
  shell: test -d {{ item }} && find {{ item }} -path '{{ item }}/*' -prune -exec rm -rf {} \;
  with_items: [/home/mydata/web]

Isso deve apagar arquivos / pastas / ocultos em /home/mydata/web

Sherzod Odinaev
fonte
1
Pode funcionar, mas o uso do módulo shell sempre deve ser o último recurso.
Chris
-1
先 删除 对应 的 目录 , 然后 在 创建 该 目录 , 使用 的 是 嵌套.
  - name: delete old data and clean cache
    file:
      path: "{{ item[0] }}" 
      state: "{{ item[1] }}"
    with_nested:
      - [ "/data/server/{{ app_name }}/webapps/", "/data/server/{{ app_name }}/work/" ]
      - [ "absent", "directory" ]
    ignore_errors: yes
lanni654321
fonte
-4

Este é o meu exemplo.

  1. Instalar repositório
  2. Instale o pacote rsyslog
  3. pare rsyslog
  4. exclua todos os arquivos dentro de / var / log / rsyslog /
  5. iniciar o rsyslog

    - hosts: all
      tasks:
        - name: Install rsyslog-v8 yum repo
          template:
            src: files/rsyslog.repo
            dest: /etc/yum.repos.d/rsyslog.repo
    
        - name: Install rsyslog-v8 package
          yum:
            name: rsyslog
            state: latest
    
        - name: Stop rsyslog
          systemd:
            name: rsyslog
            state: stopped
    
        - name: cleann up /var/spool/rsyslog
          shell: /bin/rm -rf /var/spool/rsyslog/*
    
        - name: Start rsyslog
          systemd:
            name: rsyslog
            state: started
    
Satish
fonte
-6

Abaixo funcionou para mim,

- name: Ansible delete html directory
  file:
   path: /var/www/html
   state: directory
Sakharam Thorat
fonte
Isso apenas confirmará que o diretório existe. Ele será criado se não o fizer, mas não fará nada além de informar OK, se o fizer.
Chris