Comment déplacer / renommer un fichier à l'aide d'une tâche Ansible sur un système distant

202

Comment déplacer / renommer un fichier / répertoire à l'aide d'un module Ansible sur un système distant? Je ne veux pas utiliser les tâches de commande / shell et je ne veux pas copier le fichier du système local vers le système distant.

Christian Berendt
la source
Pourquoi ne voulez-vous pas utiliser la commande / shell?
Nick Urban
4
Je voulais juste savoir s'il y avait un moyen sans utiliser les tâches mentionnées. Il semble qu'il n'y ait pas d'autre moyen pour le moment.
Christian Berendt
1
Pourquoi voulez-vous le déplacer spécifiquement au lieu de le copier? Cela ressemble à une action ponctuelle, plutôt qu'à une étape idempotente assurant l'état du système.
Nick Urban
2
J'ai un exemple de fichier de configuration inclus dans un package RPM et je souhaite déplacer cet exemple de fichier de configuration.
Christian Berendt
1
Pour le moment, j'utilise un lien symbolique pour référencer le fichier. Utiliser get_url n'est pas une option pour moi car le système ne peut pas accéder à Internet.
Christian Berendt

Réponses:

201

Le module de fichiers ne copie pas les fichiers sur le système distant. Le paramètre src n'est utilisé que par le module de fichiers lors de la création d'un lien symbolique vers un fichier.

Si vous souhaitez déplacer / renommer un fichier entièrement sur un système distant, le mieux est d'utiliser le module de commande pour appeler simplement la commande appropriée:

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

Si vous voulez devenir sophistiqué, vous pouvez d'abord utiliser le module stat pour vérifier que foo existe réellement:

- 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
la source
3
Sans utiliser le module de commande, votre seul autre choix serait d'écrire votre propre module personnalisé.
Bruce P
2
Marqué comme réponse correcte, car il s'agit de la méthode actuelle pour copier des fichiers distants.
Christian Berendt
11
Concernant la recherche avant de sauter: y a-t-il une raison pour ne pas utiliser l' removesoption du commandmodule (documentée ici )? Il semble que cette option ferait d'abord vérifier Ansible.
Jim Witschey
2
Ansible suit les modifications pour notifier le gestionnaire, ce qui rend cette solution sous-optimale.
boh
3
Vous n'avez pas besoin de vérifier manuellement l'existence du fichier si vous utilisez removes: /path/to/fooet creates: /path/to/bar. @Fonant a déjà mentionné cela comme un commentaire sur une autre réponse, mais comme c'est la réponse acceptée, je tiens à le souligner à nouveau.
Michael Trojanek
218

À partir de la version 2.0 , dans le module de copie, vous pouvez utiliser le remote_srcparamètre.

S'il Trueira à la machine distante / cible pour le src.

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

Si vous souhaitez déplacer un fichier, vous devez supprimer l'ancien fichier avec le module de fichiers

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

À partir de la version 2.8, le module de copie remote_src prend en charge la copie récursive.

Alex
la source
29
Petite remarque: "Actuellement, remote_src ne prend pas en charge la copie récursive." extrait du module ansible doc. Donc, si vous voulez copier récursivement, vous avez toujours besoin du module shell / commande.
klaas
23
Je ne comprends pas. Copier puis supprimer n'est pas la même chose que déplacer. D'une part, ce n'est pas atomique. Pour un autre, c'est plus lent, surtout pour les gros fichiers. Je suis nouveau chez Ansible, mais cela me semble vraiment bizarre.
mlissner
19
@alex ce que je dis, c'est que ce n'est pas la bonne façon de faire ça. Je vais contre le vent contre 50 votes positifs, mais c'est fou. Autre problème: les autorisations et autres attributs ne sont pas conservés. Un autre: que faire si le fichier est modifié pendant la copie ?
mlissner
2
@Hamish Downer et mlissner. Je n'ai pas dit que c'était la meilleure solution pour tous vos besoins. J'ai également écrit que si vous souhaitez copier de nombreux fichiers, vous ne devez pas utiliser le module de copie. Lisez la question "Je ne veux pas utiliser les tâches de commande / shell".
Alex
7
@Alex est la deuxième réponse la plus votée à une question sur le déplacement des fichiers de manière idempotente. La question n'est pas de copier. Il y a beaucoup de problèmes avec la copie au lieu de déplacer donc cette réponse est incorrecte. Il obtient donc un downvote. L'étiquette sur SO est d'expliquer les votes négatifs. Comme indiqué ailleurs, la meilleure option jusqu'à présent est decommand: mv /path/to/foo /path/to/bar creates=/path/to/bar removes=/path/to/foo
Alec Wenzowski
106

J'ai trouvé l'option create dans le module de commande utile. Que dis-tu de ça:

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

J'avais l'habitude de faire une approche en 2 tâches en utilisant des statistiques comme le suggère Bruce P. Maintenant, je fais cela comme une tâche avec create. Je pense que c'est beaucoup plus clair.

Tom Ekberg
la source
60
Ou encore mieux: command: mv /path/to/foo /path/to/bar creates=/path/to/bar removes=/path/to/foo
Fonant
8

Une autre option qui a bien fonctionné pour moi est d'utiliser le module de synchronisation . Supprimez ensuite le répertoire d'origine à l'aide du module de fichiers.

Voici un exemple tiré de la documentation:

- synchronize:
    src: /first/absolute/path
    dest: /second/absolute/path
    archive: yes
  delegate_to: "{{ inventory_hostname }}"
Andrew Becker
la source
Cela ne fonctionne pas localement dans tous les cas car il destest accessible via SSH même si le répertoire est sur la même machine.
Karl Richter
5

Une autre façon d'y parvenir est d'utiliser fileavec state: hard.

Voici un exemple que j'ai eu à travailler:

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

Testé uniquement sur localhost (OSX), mais devrait également fonctionner sur Linux. Je ne peux pas dire pour Windows.

Notez que des chemins absolus sont nécessaires. Sinon, cela ne me laisserait pas créer le lien. De plus, vous ne pouvez pas traverser les systèmes de fichiers, donc travailler avec n'importe quel support monté peut échouer.

Le lien dur est très similaire au déplacement, si vous supprimez le fichier source par la suite:

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

Un autre avantage est que les changements sont conservés lorsque vous êtes au milieu d'une pièce. Donc, si quelqu'un change la source, tout changement est reflété dans le fichier cible.

Vous pouvez vérifier le nombre de liens vers un fichier via ls -l. Le nombre de liens physiques est affiché à côté du mode (par exemple rwxr-xr-x 2, lorsqu'un fichier a 2 liens).

martinczerwi
la source
2
Malheureusement, cela ne fonctionnera pas pour un répertoire, car les liens physiques ne sont pas autorisés pour les répertoires (((
Drew
1
Cette réponse fait une hypothèse sur le système cible, en particulier que src et dest sont sur la même partition. Cela peut ne pas être vrai et cette réponse ne doit donc pas être utilisée.
mikky
4

Bruce n'essayait pas de déclarer la destination pour vérifier s'il fallait déplacer le fichier s'il était déjà là; il s'assurait que le fichier à déplacer existait réellement avant d'essayer le mv.

Si votre intérêt, comme celui de Tom, est de ne bouger que si le fichier n'existe pas déjà, je pense que nous devrions quand même intégrer le chèque de Bruce dans le mix:

- 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
la source
3

Voici comment je l'ai fait fonctionner pour moi:

  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

le playbook ci-dessus, vérifiera si le fichier abc.xts existe avant de déplacer le fichier vers le dossier tmp.

eduprado
la source
3
Pas besoin d'utiliser when: stat_result.stat.exists == True. Il suffit d’utiliser when: stat_result.stat.exists.
kuttumiah
J'utilise généralement le == Truecar je fais toujours quelque chose lorsque le fichier n'est pas trouvé ou == False.
eduprado
Selon la page de documentation officielle, lastat exists propriété du module renvoie une booleanvaleur. Donc, si vous ne mettez when: stat_result.stat.existsque cela remplira la condition si le fichier est présent, qui est également identique pour when: stat_result.stat.exists == Truemais avec plus de textes et une vérification conditionnelle inutile.
kuttumiah
0

Cela peut sembler exagéré, mais si vous voulez éviter d'utiliser le module de commande (ce que je fais, parce que l'utilisation de la commande n'est pas idempotente), vous pouvez utiliser une combinaison de copie et de désarchivage.

  1. Utilisez tar pour archiver le ou les fichiers dont vous aurez besoin. Si vous pensez à l'avance, cela a du sens. Vous voudrez peut-être une série de fichiers dans un répertoire donné. Créez ce répertoire avec tous les fichiers et archivez-les dans un tar.
  2. Utilisez le module de désarchivage. Lorsque vous faites cela, avec le mot-clé destination: et remote_src:, vous pouvez placer la copie de tous vos fichiers dans un dossier temporaire pour commencer, puis les décompresser exactement où vous le souhaitez.
Mark Chassy
la source
Il n'y a aucune idempotence dans l'archivage avec tar
visit1985
0

Vous pouvez le faire en -

Utilisation de la commande ad hoc

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

Ou vous si vous voulez le faire en utilisant playbook

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

Je sais que c'est un AN vieux sujet, mais je suis frustré et construit un rôle pour moi - même de faire exactement cela pour une liste arbitraire de fichiers. Prolongez comme bon vous semble:

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

Notez que la liaison matérielle est préférable à la copie ici, car elle préserve intrinsèquement la propriété et les autorisations (en plus de ne pas consommer plus d'espace disque pour une deuxième copie du fichier).

Orlach
la source
0

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

Pour renommer, utilisez plutôt la commande rename ou ren

Vitaly
la source