Cómo mover / renombrar un archivo usando una tarea Ansible en un sistema remoto

202

¿Cómo es posible mover / cambiar el nombre de un archivo / directorio utilizando un módulo Ansible en un sistema remoto? No quiero usar el comando / tareas de shell y no quiero copiar el archivo del sistema local al sistema remoto.

Christian Berendt
fuente
¿Por qué no quieres usar command / shell?
Nick Urban
44
Solo quería saber si hay una manera sin usar las tareas mencionadas. Parece que no hay otra manera en este momento.
Christian Berendt
1
¿Por qué quieres moverlo específicamente en lugar de copiarlo? Eso parece una acción única, en lugar de un tipo de paso idempotente para garantizar el estado del sistema.
Nick Urban
2
Tengo un archivo de configuración de muestra incluido en un paquete RPM y quiero mover este archivo de configuración de muestra.
Christian Berendt
1
Por el momento estoy usando un enlace simbólico para hacer referencia al archivo. Usar get_url no es una opción para mí porque el sistema no puede acceder a Internet.
Christian Berendt

Respuestas:

201

El módulo de archivo no copia archivos en el sistema remoto. El módulo src solo usa el parámetro src al crear un enlace simbólico a un archivo.

Si desea mover / cambiar el nombre de un archivo por completo en un sistema remoto, lo mejor es usar el módulo de comando para invocar el comando apropiado:

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

Si quieres ponerte elegante, primero puedes usar el módulo de estadísticas para verificar que 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
fuente
3
Sin usar el módulo de comando, su única opción sería escribir su propio módulo personalizado.
Bruce P
2
Etiquetado como respuesta correcta porque esta es la forma actual de copiar archivos remotos.
Christian Berendt
11
Con respecto a mirar antes de saltar: ¿hay alguna razón para no usar la removesopción para el commandmódulo (documentado aquí )? Parece que esa opción haría que Ansible verifique primero.
Jim Witschey
2
Ansible rastrea los cambios para notificar al controlador, lo que hace que esta solución sea subóptima.
Boh
3
No tiene que verificar manualmente la existencia del archivo si usa removes: /path/to/fooy creates: /path/to/bar. @Fonant ya mencionó esto como comentario en otra respuesta, pero como esta es la aceptada, quiero señalarlo nuevamente.
Michael Trojanek
218

Desde la versión 2.0 , en el módulo de copia puede usarremote_src parámetro.

Si Trueirá a la máquina remota / objetivo para el src.

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

Si desea mover el archivo, debe eliminar el archivo antiguo con el módulo de archivo

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

Desde la versión 2.8, el módulo de copia remote_src admite la copia recursiva.

Alex
fuente
29
Pequeña observación: "Actualmente, remote_src no admite la copia recursiva". tomado del módulo ansible doc. Entonces, si desea copiar de forma recursiva, aún necesita el módulo de shell / comando.
klaas
23
No entiendo. Copiar y luego eliminar no es lo mismo que mover. Por un lado, no es atómico. Por otro lado, es más lento, especialmente para archivos grandes. Soy nuevo en Ansible, pero esto me parece realmente extraño.
mlissner
19
@alex lo que digo es que no puede ser la forma correcta de hacer esto. Voy contra el viento en contra de 50 votos a favor, pero esto es una locura. Otro problema: los permisos y otros atributos no se mantienen. Otro: ¿Qué pasa si el archivo se cambia durante la copia ?
mlissner
2
@Hamish Downer y Mlissner. No dije que es la mejor solución para todas sus necesidades. También escribí que si quieres copiar muchos archivos no deberías usar el módulo de copia. Lea la pregunta "No quiero usar el comando / tareas de shell".
Alex
77
@Alex, esta es la segunda respuesta más votada en una pregunta sobre el movimiento idempotente de archivos. La pregunta no es sobre copiar. Hay muchos problemas con la copia en lugar de moverla, por lo tanto, esta respuesta es incorrecta. Por lo tanto, recibe un voto negativo. La etiqueta en SO es explicar los votos negativos. Como se señaló en otra parte, la mejor opción hasta ahora escommand: mv /path/to/foo /path/to/bar creates=/path/to/bar removes=/path/to/foo
Alec Wenzowski el
106

He encontrado útil la opción de creación en el módulo de comando. Qué tal esto:

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

Solía ​​hacer un enfoque de 2 tareas usando estadísticas como sugiere Bruce P. Ahora hago esto como una tarea con crea. Creo que esto es mucho más claro.

Tom Ekberg
fuente
6060
O, mejor aún: command: mv /path/to/foo /path/to/bar creates=/path/to/bar removes=/path/to/foo
Fonant
8

Otra opción que me ha funcionado bien es usar el módulo de sincronización . Luego, elimine el directorio original utilizando el módulo de archivo.

Aquí hay un ejemplo de los documentos:

- synchronize:
    src: /first/absolute/path
    dest: /second/absolute/path
    archive: yes
  delegate_to: "{{ inventory_hostname }}"
Andrew Becker
fuente
Esto no funciona localmente en todos los casos porque destse accede a través de SSH incluso si el directorio está en la misma máquina.
Karl Richter
5

Otra forma de lograr esto es usar filecon state: hard.

Este es un ejemplo que puse a trabajar:

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

Sin embargo, solo se probó en localhost (OSX), pero también debería funcionar en Linux. No puedo decir para Windows.

Tenga en cuenta que se necesitan rutas absolutas. De lo contrario, no me dejaría crear el enlace. Además, no puede cruzar los sistemas de archivos, por lo que puede fallar el trabajo con cualquier medio montado.

El enlace duro es muy similar al movimiento, si luego elimina el archivo fuente:

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

Otro beneficio es que los cambios persisten cuando estás en medio de una jugada. Entonces, si alguien cambia la fuente, cualquier cambio se refleja en el archivo de destino.

Puede verificar el número de enlaces a un archivo a través de ls -l. El número de enlaces duros se muestra junto al modo (por ejemplo, rwxr-xr-x 2, cuando un archivo tiene 2 enlaces).

martinczerwi
fuente
2
Desafortunadamente, esto no funcionará para un directorio, ya que los enlaces duros no están permitidos para directorios (((
Drew
1
Esta respuesta supone que el sistema de destino, específicamente que src y dest están en la misma partición. Esto puede no ser cierto y, por lo tanto, esta respuesta no debe usarse.
mikky
4

Bruce no estaba intentando establecer el destino para verificar si se movía o no el archivo si ya estaba allí; se estaba asegurando de que el archivo a mover realmente existiera antes de intentar el mv.

Si su interés, como el de Tom, es moverse solo si el archivo aún no existe, creo que aún deberíamos integrar el cheque de Bruce en la mezcla:

- 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
fuente
3

Así es como lo hice funcionar para mí:

  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

el libro de jugadas anterior verificará si existe el archivo abc.xts antes de mover el archivo a la carpeta tmp.

eduprado
fuente
3
No es necesario usar when: stat_result.stat.exists == True. Solo usar when: stat_result.stat.existses lo suficientemente bueno.
kuttumiah
Normalmente uso el == Trueporque siempre estoy haciendo algo cuando no se encuentra el archivo o == False.
eduprado
Según la página de documentación oficial de lastat exists propiedad del módulo , se devuelve un booleanvalor. Entonces, si solo coloca when: stat_result.stat.existseso, satisfará la condición si el archivo está presente, que también es idéntico when: stat_result.stat.exists == Truepero con más textos y verificación condicional innecesaria.
kuttumiah
0

Esto puede parecer excesivo, pero si desea evitar usar el módulo de comando (lo cual hago, porque usar el comando no es idempotente) puede usar una combinación de copiar y desarchivar.

  1. Use tar para archivar los archivos que necesitará. Si piensas con anticipación, esto realmente tiene sentido. Es posible que desee una serie de archivos en un directorio dado. Cree ese directorio con todos los archivos y archívelos en un tar.
  2. Usa el módulo de desarchivar. Cuando lo haga, junto con el destino: y la palabra clave remote_src: puede comenzar a copiar todos sus archivos en una carpeta temporal para comenzar y luego desempaquetarlos exactamente donde desee.
Mark Chassy
fuente
No hay idempotencia en el archivo con alquitrán
visit1985
0

Puedes hacerlo por -

Uso del comando ad hoc

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

O usted si quiere hacerlo usando el libro de jugadas

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

Sé que es un tema de AÑOS , pero me sentí frustrado y creé un papel para que yo hiciera exactamente esto para una lista arbitraria de archivos. Extienda como mejor le parezca:

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

Tenga en cuenta que la vinculación física es preferible a copiar aquí, ya que inherentemente conserva la propiedad y los permisos (además de no consumir más espacio en disco para una segunda copia del archivo).

Orlach
fuente
0

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

Para cambiar el nombre, use el comando rename o ren en su lugar

Vitalia
fuente