Como mover / renomear um arquivo usando uma tarefa Ansible em um sistema remoto

202

Como é possível mover / renomear um arquivo / diretório usando um módulo Ansible em um sistema remoto? Não quero usar as tarefas de comando / shell e não quero copiar o arquivo do sistema local para o sistema remoto.

Christian Berendt
fonte
Por que você não deseja usar o comando / shell?
Nick Urban.
4
Só queria saber se existe uma maneira sem usar as tarefas mencionadas. Parece que não há outra maneira no momento.
Christian Berendt
1
Por que você deseja movê-lo especificamente em vez de copiá-lo? Parece uma ação pontual, em vez de uma etapa idempotente de garantir o estado do sistema.
Nick Urban.
2
Eu tenho um arquivo de configuração de amostra incluído em um pacote RPM e desejo mover esse arquivo de configuração de exemplo.
Christian Berendt
1
No momento, estou usando um link simbólico para fazer referência ao arquivo. Usar get_url não é uma opção para mim, porque o sistema não pode acessar a Internet.
Christian Berendt

Respostas:

201

O módulo de arquivo não copia arquivos no sistema remoto. O parâmetro src é usado apenas pelo módulo de arquivo ao criar um link simbólico para um arquivo.

Se você deseja mover / renomear um arquivo inteiramente em um sistema remoto, sua melhor aposta é usar o módulo de comando para chamar o comando apropriado:

- name: Move foo to bar
  command: mv /path/to/foo /path/to/bar

Se você quiser ser extravagante, poderá primeiro usar o módulo stat para verificar se o foo realmente existe:

- name: stat foo
  stat: path=/path/to/foo
  register: foo_stat

- name: Move foo to bar
  command: mv /path/to/foo /path/to/bar
  when: foo_stat.stat.exists
Bruce P
fonte
3
Sem usar o módulo de comando, sua única outra opção seria escrever seu próprio módulo personalizado.
Bruce P
2
Marcado como resposta correta, porque esta é a maneira atual de copiar arquivos remotos.
Christian Berendt
11
Em relação à observação antes de saltar: existe algum motivo para não usar a removesopção do commandmódulo (documentada aqui )? Parece que essa opção faria o Ansible checar primeiro.
21715 Jim Jimitsitsy
2
O Ansible rastreia as alterações para notificar o manipulador, o que torna essa solução abaixo do ideal.
boh
3
Você não precisa verificar manualmente a existência do arquivo se usar removes: /path/to/fooe creates: /path/to/bar. A @Fonant já mencionou isso como comentário em outra resposta, mas como essa é a aceita, quero apontar novamente.
Michael Trojanek
218

A partir da versão 2.0 , no módulo de cópia, você pode usar o remote_srcparâmetro

Se Truefor para a máquina remota / de destino do src.

- name: Copy files from foo to bar
  copy: remote_src=True src=/path/to/foo dest=/path/to/bar

Se você deseja mover o arquivo, é necessário excluir o arquivo antigo com o módulo de arquivo

- name: Remove old files foo
  file: path=/path/to/foo state=absent

A partir da versão 2.8, o módulo de cópia remote_src suporta cópia recursiva.

Alex
fonte
29
Pequena observação: "Atualmente o remote_src não suporta cópia recursiva." extraído do módulo ansible doc. Portanto, se você deseja copiar recursivamente, ainda precisa do módulo shell / comando.
Klaas
23
Eu não entendo Copiar e excluir não é o mesmo que mover. Por um lado, não é atômico. Por outro, é mais lento, especialmente para arquivos grandes. Sou novo no Ansible, mas isso me parece muito estranho.
mlissner
19
@ alex o que estou dizendo é que não pode ser o caminho certo para fazer isso. Eu estou indo contra o vento contra 50 votos positivos, mas isso é loucura. Outro problema: permissões e outros atributos não são mantidos. Outro: E se o arquivo for alterado durante a cópia ?
mlissner
2
@Hamish Downer e mlissner. Eu não disse que é a melhor solução para todas as suas necessidades. Também escrevi que, se você deseja copiar muitos arquivos, não deve usar o módulo de cópia. Leia a pergunta "Não quero usar as tarefas de comando / shell".
Alex
7
@ Alex, esta é a segunda resposta mais votada em uma pergunta sobre a movimentação de arquivos com idempotência. A questão não é sobre cópia. Existem muitos problemas com a cópia em vez de mover, portanto, esta resposta está incorreta. Por isso, recebe um voto negativo. A etiqueta no SO é explicar votos negativos. Como observado em outro lugar, a melhor opção até agora é:command: mv /path/to/foo /path/to/bar creates=/path/to/bar removes=/path/to/foo
Alec Wenzowski 29/11
106

Eu encontrei a opção de criação no módulo de comando útil. Que tal agora:

- name: Move foo to bar
  command: creates="path/to/bar" mv /path/to/foo /path/to/bar

Eu costumava fazer uma abordagem de duas tarefas usando estatísticas, como sugere Bruce P. Agora eu faço isso como uma tarefa com cria. Eu acho que isso é muito mais claro.

Tom Ekberg
fonte
60
Ou, ainda melhor: command: mv /path/to/foo /path/to/bar creates=/path/to/bar removes=/path/to/foo
Fonant 07/04
8

Outra opção que funcionou bem para mim é usar o módulo de sincronização . Em seguida, remova o diretório original usando o módulo de arquivo.

Aqui está um exemplo dos documentos:

- synchronize:
    src: /first/absolute/path
    dest: /second/absolute/path
    archive: yes
  delegate_to: "{{ inventory_hostname }}"
Andrew Becker
fonte
Isso não funciona localmente em todos os casos, porque desté acessado através do SSH, mesmo que o diretório esteja na mesma máquina.
Karl Richter
5

Outra maneira de conseguir isso é usando filecom state: hard.

Este é um exemplo que eu tenho que trabalhar:

- name: Link source file to another destination
  file:
    src: /path/to/source/file
    path: /target/path/of/file
    state: hard

Apenas testado no localhost (OSX), mas deve funcionar também no Linux. Eu não posso dizer para o Windows.

Observe que caminhos absolutos são necessários. Senão, não me deixaria criar o link. Além disso, você não pode atravessar sistemas de arquivos; portanto, o trabalho com qualquer mídia montada pode falhar.

O hardlink é muito semelhante ao movimento, se você remover o arquivo de origem depois:

- name: Remove old file
  file:
    path: /path/to/source/file
    state: absent

Outro benefício é que as mudanças persistem quando você está no meio de uma peça. Portanto, se alguém alterar a fonte, qualquer alteração será refletida no arquivo de destino.

Você pode verificar o número de links para um arquivo via ls -l. O número de links físicos é mostrado próximo ao modo (por exemplo, rwxr-xr-x 2, quando um arquivo possui 2 links).

martinczerwi
fonte
2
Infelizmente, isso não vai funcionar para um diretório, como hard links não são permitidos para os diretórios (((
de Drew
1
Esta resposta faz uma suposição sobre o sistema de destino, especificamente que src e dest estão na mesma partição. Isso pode não ser verdade e, portanto, esta resposta não deve ser usada.
Mikky 24/04/19
4

Bruce não estava tentando determinar o destino para verificar se movia ou não o arquivo, se ele já estava lá; ele estava se certificando de que o arquivo a ser movido realmente existia antes de tentar o mv.

Se o seu interesse, como o de Tom, é apenas mudar se o arquivo ainda não existir, acho que ainda devemos integrar o cheque de Bruce na mistura:

- name: stat foo
  stat: path=/path/to/foo
  register: foo_stat

- name: Move foo to bar
  command: creates="path/to/bar" mv /path/to/foo /path/to/bar
  when: foo_stat.stat.exists
gkedge
fonte
3

Foi assim que consegui trabalhar para mim:

  Tasks:
  - name: checking if the file 1 exists
     stat:      
      path: /path/to/foo abc.xts
     register: stat_result

  - name: moving file 1
    command: mv /path/to/foo abc.xts /tmp
    when: stat_result.stat.exists == True

o manual acima, verificará se o arquivo abc.xts existe antes de mover o arquivo para a pasta tmp.

eduprado
fonte
3
Não há necessidade de usar when: stat_result.stat.exists == True. Apenas usar when: stat_result.stat.existsé bom o suficiente.
Kurtumiah #
Eu normalmente uso o == Trueporque estou sempre fazendo algo quando o arquivo não é encontrado ou == False.
Eduprado 6/08/19
De acordo com a página da documentação oficial dastat exists propriedade do módulo , retorna um booleanvalor. Portanto, se você colocar apenas when: stat_result.stat.existsisso, satisfará a condição se o arquivo estiver presente, o que também é idêntico, when: stat_result.stat.exists == Truemas com mais textos e verificação condicional desnecessária.
precisa saber é
0

Isso pode parecer um exagero, mas se você quiser evitar o uso do módulo de comando (o que eu faço, porque ele não é idempotente), você pode usar uma combinação de copiar e desarquivar.

  1. Use tar para arquivar os arquivos necessários. Se você pensa no futuro, isso realmente faz sentido. Você pode querer uma série de arquivos em um determinado diretório. Crie esse diretório com todos os arquivos e arquive-os em um tar.
  2. Use o módulo desarquivar. Ao fazer isso, junto com o destino: e remote_src: keyword, você pode copiar todos os seus arquivos para uma pasta temporária para começar e depois descompactá-los exatamente onde quiser.
Mark Chassy
fonte
Não há idempotência no arquivamento com tar
visit1985
0

Você pode fazer isso por -

Usando o comando ad hoc

ansible all -m command -a" mv /path/to/foo /path/to/bar"

Ou você, se você quiser fazê-lo usando o playbook

- name: Move File foo to destination bar
  command: mv /path/to/foo /path/to/bar
Dev pokhariya
fonte
0

Sei que é um tópico antigo de ANOS , mas fiquei frustrado e criei uma função para fazer exatamente isso em uma lista arbitrária de arquivos. Estenda como achar melhor:

main.yml

- name: created destination directory
  file:
    path: /path/to/directory
    state: directory
    mode: '0750'
- include_tasks: move.yml
  loop:
    - file1
    - file2
    - file3

move.yml

- name: stat the file
  stat:
    path: {{ item }}
  register: my_file

- name: hard link the file into directory
  file:
    src: /original/path/to/{{ item }}
    dest: /path/to/directory/{{ item }}
    state: hard
  when: my_file.stat.exists

- name: Delete the original file
  file:
    path: /original/path/to/{{ item }}
    state: absent
  when: my_file.stat.exists

Observe que a vinculação física é preferível à cópia aqui, pois preserva inerentemente a propriedade e as permissões (além de não consumir mais espaço em disco para uma segunda cópia do arquivo).

Orlach
fonte
0

No Windows: - name: Move old folder to backup win_command: "cmd.exe /c move /Y {{ sourcePath }} {{ destinationFolderPath }}"

Para renomear, use o comando rename ou ren

Vitaly
fonte