找到一个文件并将其重命名为ansible playbook

Find a file and rename it ansible playbook

所以我一直在尝试使用剧本来修复我在所有服务器中犯的一个错误。基本上我启动了一个带有 logrotate 的 playbook 来解​​决不断增长的日志问题,并且其中有一个名为 btmp 的日志,我不应该旋转它但无论如何都是偶然的,现在 logrotate 更改了它的名称以添加一个日期并因此制动日志。现在我想使用一个剧本,它将在 /var/log 目录中找到一个名为 btmp 的日志并将其重命名,问题是文件 atm 在每个服务器中都不同,例如 1 个服务器有 btmp-20210316,另一个有 btmp -20210309,因此在 bash 命令行中可以使用通配符“btmp*”来绕过这些问题,但这似乎在 playbook 中不起作用。到目前为止,我想到了这个:

  tasks:
    - name: stat btmp*
      stat: path=/var/log
      register: btmp_stat

    - name: Move btmp
      command: mv /var/log/btmp* /var/log/btmp
      when: btmp_stat.stat.exists

然而,这会导致找不到文件的错误。所以我的问题是如何让通配符在剧本中工作,或者是否有一种等效的方法来查找名称中包含“btmp”的所有文件并重命名它们?顺便说一句,所有服务器都是 Centos 7 服务器。

所以我也会添加我自己的解决方案,即使答案解决方案更好。 在你的 ansible VM 中的任何地方用一行制作一个 bash 脚本。 行是:mv /var/log/filename* /var/log/filename

现在创建一个 playbook 来在目标 VM 中运行它:

---
- hosts: '{{ server }}'
  remote_user: username
  become: yes
  become_method: sudo

  vars_prompt:
    - name: "server"
      prompt: "Enter server name or group"
      private: no

  tasks:
    - name: Move the script to target host VM
      copy: src=/anywhereyouwant/bashscript.sh dest=/tmp mode=0777

    - name: Execute the script
      command: sh /tmp/bashscript.sh

    - name: delete the script
      command: rm /tmp/bashscript.sh

在 Ansible 中有不止一种方法可以做到这一点,使用 shell 模块当然是一种可行的方法(但你需要 shell 模块代替 command 因为后者不支持通配符)。我会按如下方式解决问题:

  1. 首先创建一个任务来查找所有匹配的文件(即 /var/log/btmp*)并将它们存储在一个变量中供以后处理 - 这看起来像这样:
    - name: Find all files named /var/log/btmp*
      ansible.builtin.find:
        paths: /var/log
        patterns: 'btmp*'
      register: find_btmp

此任务使用 find 模块定位 /var/log 中所有名为 btmp* 的文件 - 结果存储在名为 find_btmp.[=36= 的变量中]

  1. 接下来创建一个任务,将 btmp* 文件复制到 btmp。现在你很可能有超过 1 个文件路径上述模式,并且逻辑上你不想将它们全部重命名为 btmp 因为这只是每次都覆盖文件。相反,假设您只需要匹配的最新文件——我们可以使用一个聪明的 Jinja2 过滤器从第一个任务的结果中获取此条目:
    - name: Copy the btmp* to the required filename
      ansible.builtin.copy:
        src: "{{ find_btmp.files | sort(attribute='mtime',reverse=true) | map(attribute='path') | first }}"
        dest: /var/log/btmp
        remote_src: yes
      when: find_btmp.failed == false

此任务使用 Ansible 的 copy 模块将我们选择的源文件复制到 /var/log/btmpremote_src: yes 参数告诉复制模块源文件存在于远程机器上而不是 Ansible 主机本身。

我们使用 when 子句来确保如果找不到任何文件,我们不会 运行 此复制操作。

现在让我们分解一下 Jinja2 过滤器:

  • find_btmp.files - 这是我们的 find_btmp 变量
  • 中列出的所有文件
  • sort(attribute='mtime',reverse=true) - 这里我们使用 mtime(修改时间)属性对文件列表进行排序 - 我们进行反向排序,以便最新的条目位于列表的顶部。
  • map(attribute='path') - 我们正在使用 map 来“提取”文件字典的 path 属性,因为这是我们实际想要传递给复制模块的唯一数据 - 路径文件本身
  • first - 这只选择列表中的第一个元素(即最新的文件,因为它们被反向排序)
  1. 最后,您要求进行移动操作 - Ansible 中没有本地“移动”模块,因此您需要在复制后删除源文件 - 这可以按如下方式完成(Jinja2 过滤器与之前:
  - name: Delete the original file
    ansible.builtin.file:
      path: "{{ find_btmp.files | sort(attribute='mtime',reverse=true) | map(attribute='path') | first }}"
      state: absent
    when: find_btmp.failed == false

我们再次使用 when 子句来确保我们不会删除一开始没有找到的任何内容。

我已经在 Ansible 3.1.0/ansible-base 2.10.7 上测试过这个 - 如果你 运行ning Ansible 2.9 或更早版本,请从模块名称中删除 ansible.builtin.(即ansible.builtin.copy 变成 copy.)

希望对您有所帮助!