如果存在本地文件,使用ansible复制该文件

33

我正在一个项目中工作,我们使用ansible创建和部署服务器集群。 我需要实现的任务之一是,仅在本地存在该文件时才将本地文件复制到远程主机。 现在我正在尝试使用以下方法解决这个问题

- hosts: 127.0.0.1 
  connection: local
  tasks:
    - name: copy local filetocopy.zip to remote if exists
    - shell: if [[ -f "../filetocopy.zip" ]]; then /bin/true; else /bin/false; fi;
      register: result    
    - copy: src=../filetocopy.zip dest=/tmp/filetocopy.zip
      when: result|success
但是,以下错误消息导致此操作失败: ERROR:任务“将本地文件tocopy.zip复制到远程(如果存在)”中缺少“action”或“local_action”属性
我尝试使用命令任务来创建它。 我已经尝试使用local_action创建此任务,但是我无法使其工作。 我找到的所有示例都没有考虑在local_action中使用shell,只有命令的示例,而且除了命令之外没有其他内容。 是否有一种使用ansible执行此任务的方法?

这个回答解决了你的问题吗?Ansible只有在文件存在时才包含任务 - Helder Pereira
嗨 @HelderPereira,这篇文章是一段时间前发布的,在那时采纳的答案解决了我的问题。当时,最受欢迎的答案也解决了这个问题,但现在我无法评估它,因为我无法访问它的代码。 - dirceusemighini
6个回答

36
更全面的答案:如果您想在执行某些任务之前检查一个本地文件是否存在,这里是完整的代码片段:
- name: get file stat to be able to perform a check in the following task
  local_action: stat path=/path/to/file
  register: file

- name: copy file if it exists
  copy: src=/path/to/file dest=/destination/path
  when: file.stat.exists

如果你想在执行某个任务之前检查远程文件是否存在,那么这就是方法:

- name: get file stat to be able to perform check in the following task
  stat: path=/path/to/file
  register: file

- name: copy file if it exists
  copy: src=/path/to/file dest=/destination/path
  when: file.stat.exists

24

将你的第一步变成以下步骤

- name: copy local filetocopy.zip to remote if exists
  local_action: stat path="../filetocopy.zip"
  register: result    

似乎不像是sudo的问题。你是怎么调用playbook的? - Sandra Parsick
标准模式是使用stat模块,避免了需要使用shell/command的情况。 - tedder42
@SandraParsick 我是这样调用的:ansible-playbook -i inventory/hosts my.yml - dirceusemighini
1
您还需要在“register”段落中添加“ignore_errors:true”和“changed_when:false”。 - Sean Reifschneider
3
在当前版本的Ansible中,我不得不添加become: false才能让它正常工作。否则,它会因为无法使用sudo而报错并失败。 - Craig
显示剩余5条评论

24

如果您不想设置两个任务,您可以使用“is file”来检查本地文件是否存在:

tasks:
- copy: src=/a/b/filetocopy.zip dest=/tmp/filetocopy.zip
  when: '/a/b/filetocopy.zip' is file

路径是相对于playbook目录的,因此如果您引用角色目录中的文件,建议使用魔术变量role_path。

参考:http://docs.ansible.com/ansible/latest/playbooks_tests.html#testing-paths


6
这显然是最直截了当的版本,可以在任何任务中使用而无需额外任务。在 Ansible 的较新版本(2.6+)中,它可以写成 when: '/a/b/filetocopy.zip' is file,正如您提供文档的链接所示。 - Christian Ulbrich
尝试在旧版本中编写此代码时出现错误。这个问题看起来很容易解决。似乎有一个以引号开头的值,而YAML解析器期望看到以相同类型的引号结束的行。例如:when: "ok" in result.stdout可以写成: when: '"ok" in result.stdout'或等价地: when: "'ok' in result.stdout" - 10raw

4

Fileglob允许查找可能存在的文件。

- name: copy file if it exists
  copy: src="{{ item }}" dest=/destination/path
  with_fileglob: "/path/to/file"

1
这个怎么样?
tasks:
- copy: src=../filetocopy.zip dest=/tmp/filetocopy.zip
  failed_when: false

如果本地存在该文件,它将复制到目标位置。如果不存在,则什么也不会发生,因为错误被忽略。

这是一条注释还是一个答案? - Martin Zabel
一个答案,我添加了一些解释。 - Michael Wyraz
有趣的是,我没有时间测试它,但似乎很棒。 - dirceusemighini
7
这将隐藏其他故障情况,例如磁盘空间耗尽。 - Alex Coventry

1
抱歉唤起了死者,这是我搜索的第一个结果。使用“file”查找来尝试加载本地文件的内容,不适用于远程文件。
- name: "Use lookup to test for local_file"
  vars:
    local_file: "{{ playbook_dir }}/generated.file"
    remote_file: "~/remote.file"
  when: lookup( 'file', local_file, errors='ignore' )
  copy:
    src: "{{ local_file}}"
    dest: "{{ remote_file }}"

或者将其用于默认值:

- name: "Use lookup to test for local_file or use a default_file"
  vars:
    local_file: "{{ playbook_dir }}/generated.file"
    default_file: "{{ playbook_dir }}/default.file"
    file_to_copy: "{{ local_file if lookup( 'file', local_file, errors='ignore' else default_file )
  copy:
    src: "{{ file_to_copy}}"
    dest: "{{ remote_file }}"

注意:对于Ansible 2.9,有一个小细节需要注意,即使它应该被“忽略”,也会出现警告消息-如果使用“warning”选项,我会预料到这种情况。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接