如何使用 Ansible 以长格式列出文件和目录

AnsibleBeginner
立即练习

介绍

Ansible 是一个被广泛使用的 IT 自动化工具,它简化了基础设施管理和部署。在这个实验(Lab)中,我们将探讨如何使用 Ansible 以长格式列出文件和目录。你将学习如何设置 Ansible,创建 playbook,并使用内置模块从远程系统列出文件信息。通过完成这个实验,你将获得 Ansible 命令和技术的实践经验,这些经验可以增强你的自动化工作流程。

安装和设置 Ansible

在这一步,我们将在系统上安装 Ansible,并创建一个基本的 inventory 文件来管理我们的本地环境。

安装 Ansible

首先,让我们使用包管理器安装 Ansible:

sudo apt update
sudo apt install -y ansible

安装完成后,通过检查 Ansible 的版本来验证它是否正确安装:

ansible --version

你应该看到类似这样的输出:

ansible [core 2.12.0]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/labex/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  ansible collection location = /home/labex/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.10.x (default, Ubuntu 22.04)
  jinja version = 3.0.3
  libyaml = True

创建一个 Ansible Inventory

一个 inventory 文件是 Ansible 可以使用的被管理节点的列表。对于这个实验,我们将创建一个简单的 inventory 文件,其中包含我们的本地机器。

为我们的 Ansible 项目创建一个目录:

mkdir -p ~/project/ansible-lab
cd ~/project/ansible-lab

现在,使用 VS Code 编辑器创建一个 inventory 文件:

  1. 点击左侧边栏中的“Explorer”图标
  2. 导航到 ~/project/ansible-lab 目录
  3. 右键单击并选择“New File”
  4. 将文件命名为 inventory.ini
  5. 将以下内容添加到文件中:
[local]
localhost ansible_connection=local

这个 inventory 文件定义了一个名为 local 的组,该组仅包含我们的 localhost,并指定 Ansible 应该在本地连接而不是使用 SSH。

创建 Ansible 配置文件

让我们创建一个基本的 Ansible 配置文件来指定默认设置:

  1. 在 Explorer 面板中,右键单击 ansible-lab 目录并选择“New File”
  2. 将文件命名为 ansible.cfg
  3. 添加以下内容:
[defaults]
inventory = inventory.ini
host_key_checking = False

这个配置文件告诉 Ansible 默认使用我们的 inventory.ini 文件,并禁用 SSH 主机密钥检查,这对于实验环境很有用。

测试设置

让我们通过运行一个简单的命令来测试我们的 Ansible 设置:

cd ~/project/ansible-lab
ansible local -m ping

你应该看到类似这样的输出:

localhost | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

这确认了 Ansible 已正确配置,并且可以与我们的本地机器通信。

创建一个用于列出文件的基本 Ansible Playbook

在这一步,我们将创建一个基本的 Ansible playbook 来列出文件和目录。Playbook 是 YAML 文件,它定义了一组要在被管理节点上执行的任务。

理解 Ansible Playbook

在我们开始创建 playbook 之前,让我们了解一下什么是 playbook:

  • 一个 playbook 是一个 YAML 文件,其中包含 plays 的列表
  • 每个 play 定义了一组要在特定主机组上运行的任务
  • 任务是调用 Ansible 模块的单个操作
  • 模块是执行特定操作的可重用代码单元

创建我们的第一个 Playbook

让我们创建一个简单的 playbook 来列出 /etc 目录的内容:

  1. 在 Explorer 面板中,导航到 ~/project/ansible-lab 目录
  2. 右键单击并选择“New File”
  3. 将文件命名为 list_files.yml
  4. 添加以下内容:
---
- name: List files and directories
  hosts: local
  tasks:
    - name: Get directory listing
      command: ls -l /etc
      register: directory_contents

    - name: Display directory contents
      debug:
        var: directory_contents.stdout_lines

让我们了解一下这个 playbook 的作用:

  • 第一行 (---) 表示 YAML 文档的开始
  • name: List files and directories 是 play 的描述性名称
  • hosts: local 指定此 play 将在 local 组中的主机上运行(在我们的 inventory 中定义)
  • tasks: 开始要执行的任务列表
  • 第一个任务运行命令 ls -l /etc 并将结果存储在名为 directory_contents 的变量中
  • 第二个任务显示 directory_contents.stdout_lines 变量的内容

运行 Playbook

现在让我们运行我们的 playbook:

cd ~/project/ansible-lab
ansible-playbook list_files.yml

你应该看到类似这样的输出:

PLAY [List files and directories] *****************************************************

TASK [Gathering Facts] ****************************************************************
ok: [localhost]

TASK [Get directory listing] **********************************************************
changed: [localhost]

TASK [Display directory contents] *****************************************************
ok: [localhost] => {
    "directory_contents.stdout_lines": [
        "total 1088",
        "drwxr-xr-x  2 root root    4096 Apr 15 12:34 acpi",
        "drwxr-xr-x  3 root root    4096 Apr 15 12:34 alternatives",
        "-rw-r--r--  1 root root    3028 Aug  1  2017 bash.bashrc",
        "drwxr-xr-x  2 root root    4096 Apr 15 12:34 bash_completion.d",
        "... [more files and directories] ..."
    ]
}

PLAY RECAP ***************************************************************************
localhost                  : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

输出显示了 /etc 目录的内容,采用长格式,其中包括权限、所有者、组、大小和修改日期。

使用不同的目录

现在让我们修改我们的 playbook 以列出 /home/labex 目录的内容:

  1. 在编辑器中打开 list_files.yml 文件
  2. 将命令中的路径从 /etc 更改为 /home/labex
  3. 使用以下内容保存文件:
---
- name: List files and directories
  hosts: local
  tasks:
    - name: Get directory listing
      command: ls -l /home/labex
      register: directory_contents

    - name: Display directory contents
      debug:
        var: directory_contents.stdout_lines

再次运行 playbook:

ansible-playbook list_files.yml

输出现在将显示 /home/labex 目录的内容,而不是 /etc

使用 Ansible 的 File 模块进行长格式列表

在上一步中,我们使用了 command 模块来运行 ls -l 命令。虽然这可行,但 Ansible 提供了更专用的模块来处理文件和目录:ansible.builtin.file 模块。在这一步中,我们将学习如何将此模块与 ansible.builtin.find 模块一起使用,以更 Ansible 原生的方式列出文件。

使用 find 模块

ansible.builtin.find 模块旨在查找与特定条件匹配的文件。与 command 模块相比,它提供了一种更强大、更灵活的方式来列出文件。

让我们创建一个使用 find 模块的新 playbook:

  1. 在 Explorer 面板中,导航到 ~/project/ansible-lab 目录
  2. 右键单击并选择“New File”
  3. 将文件命名为 find_files.yml
  4. 添加以下内容:
---
- name: Find files with Ansible
  hosts: local
  tasks:
    - name: Find all files in /etc
      ansible.builtin.find:
        paths: /etc
        file_type: any
      register: found_files

    - name: Display the first 10 files
      debug:
        var: found_files.files[:10]

此 playbook 使用 find 模块来定位 /etc 目录中的所有文件和目录,然后显示前 10 个项目。

让我们运行 playbook:

cd ~/project/ansible-lab
ansible-playbook find_files.yml

你应该看到包含有关每个文件的详细信息的输出,包括:

  • 路径
  • 模式(权限)
  • 所有者和组
  • 大小
  • 修改时间

创建一个具有长格式详细信息的 Playbook

现在,让我们创建一个更全面的 playbook,它以长格式显示文件,并包含所有详细信息:

  1. 在 Explorer 面板中,右键单击并选择“New File”
  2. 将文件命名为 long_format.yml
  3. 添加以下内容:
---
- name: List files in long format
  hosts: local
  tasks:
    - name: Find files in /etc
      ansible.builtin.find:
        paths: /etc
        file_type: any
        recurse: no
      register: found_files

    - name: Create a formatted list of files
      set_fact:
        formatted_files: "{{ formatted_files | default([]) + [item] }}"
      loop: "{{ found_files.files }}"
      loop_control:
        label: "{{ item.path }}"
      vars:
        item_info: >-
          {{ item.mode }} {{ item.uid | string | ljust(5) }}
          {{ item.gid | string | ljust(5) }} {{ item.size | string | ljust(10) }}
          {{ item.mtime | string | ljust(11) }} {{ item.path }}

    - name: Display files in long format
      debug:
        msg: "{{ formatted_files[:10] }}"

此 playbook:

  1. 使用 find 模块来定位 /etc 目录中的文件
  2. 创建一个格式化的列表,类似于 ls -l 命令的输出
  3. 显示列表中的前 10 个文件

让我们运行 playbook:

ansible-playbook long_format.yml

输出将以类似于 ls -l 命令的格式显示文件详细信息。

根据条件过滤文件

使用 Ansible 模块的一个优点是能够根据各种条件过滤文件。让我们创建一个 playbook,它仅列出配置文件(以 .conf 结尾的文件):

  1. 在 Explorer 面板中,右键单击并选择“New File”
  2. 将文件命名为 filter_files.yml
  3. 添加以下内容:
---
- name: List filtered files in long format
  hosts: local
  tasks:
    - name: Find configuration files in /etc
      ansible.builtin.find:
        paths: /etc
        patterns: "*.conf"
        file_type: file
      register: conf_files

    - name: Display configuration files
      debug:
        msg: "{{ item.mode }} {{ item.uid }} {{ item.gid }} {{ item.size }} {{ item.mtime }} {{ item.path }}"
      loop: "{{ conf_files.files }}"
      loop_control:
        label: "{{ item.path }}"

此 playbook:

  1. 使用 find 模块来定位 /etc 目录中以 .conf 结尾的文件
  2. 显示每个文件的详细信息

让我们运行 playbook:

ansible-playbook filter_files.yml

输出将仅显示 /etc 目录中 .conf 文件的详细信息。

与 Command 模块的比较

让我们再创建一个 playbook 来比较 find 模块的输出与传统的 ls -l 命令:

  1. 在 Explorer 面板中,右键单击并选择“New File”
  2. 将文件命名为 compare_methods.yml
  3. 添加以下内容:
---
- name: Compare listing methods
  hosts: local
  tasks:
    - name: Get directory listing with ls command
      command: ls -l /etc/passwd
      register: ls_output

    - name: Get file info with find module
      ansible.builtin.find:
        paths: /etc
        patterns: "passwd"
        file_type: file
      register: find_output

    - name: Display ls command output
      debug:
        var: ls_output.stdout_lines

    - name: Display find module output
      debug:
        var: find_output.files[0]

此 playbook:

  1. 使用 command 模块在 /etc/passwd 文件上运行 ls -l
  2. 使用 find 模块来定位相同的文件
  3. 显示两个输出以进行比较

让我们运行 playbook:

ansible-playbook compare_methods.yml

你现在可以看到这两种方法之间的区别:

  • ls -l 命令以传统的 Unix 格式给你一行文本
  • find 模块给你一个结构化的数据对象,你可以在 Ansible 中操作它

创建一个可重用的文件列表角色

在这一步中,我们将学习如何创建一个 Ansible 角色用于文件列表。角色是一种组织 playbook 并使其更可重用的方法。当你需要在多个 playbook 或项目中执行相同的任务时,这尤其有用。

理解 Ansible 角色

一个 Ansible 角色是一组任务、变量、文件、模板和其他资源,它们被分组到一个标准的目录结构中。角色使重用代码并与他人共享代码更容易。

角色的标准目录结构如下所示:

roles/
  rolename/
    tasks/      ## 角色主要任务
    handlers/   ## 由任务触发的处理器
    defaults/   ## 默认变量
    vars/       ## 角色变量
    files/      ## 静态文件
    templates/  ## 模板
    meta/       ## 角色元数据

创建一个文件列表角色

让我们创建一个角色,用于以长格式列出文件:

  1. 首先,为我们的角色创建目录结构:
cd ~/project/ansible-lab
mkdir -p roles/file_lister/tasks
  1. 为我们的角色创建主要任务文件:
cd ~/project/ansible-lab
  1. 在 Explorer 面板中,导航到 ~/project/ansible-lab/roles/file_lister/tasks
  2. 右键单击并选择“New File”
  3. 将文件命名为 main.yml
  4. 添加以下内容:
---
## Tasks for file_lister role

- name: Find files in the specified directory
  ansible.builtin.find:
    paths: "{{ path | default('/etc') }}"
    patterns: "{{ patterns | default('*') }}"
    file_type: "{{ file_type | default('any') }}"
    recurse: "{{ recurse | default(false) }}"
  register: found_files

- name: Display files in long format
  debug:
    msg: "{{ item.mode }} {{ item.uid }} {{ item.gid }} {{ item.size }} {{ item.mtime }} {{ item.path }}"
  loop: "{{ found_files.files | sort(attribute='path') }}"
  loop_control:
    label: "{{ item.path }}"
  when: show_details | default(true)

- name: Display only file paths
  debug:
    msg: "{{ item.path }}"
  loop: "{{ found_files.files | sort(attribute='path') }}"
  loop_control:
    label: "{{ item.path }}"
  when: not (show_details | default(true))

此角色:

  1. 根据参数在指定目录中查找文件
  2. 以长格式或仅路径显示文件
  3. 如果未指定参数,则使用默认值

在 Playbook 中使用我们的角色

现在,让我们创建一个使用我们新角色的 playbook:

  1. 在 Explorer 面板中,导航到 ~/project/ansible-lab 目录
  2. 右键单击并选择“New File”
  3. 将文件命名为 use_role.yml
  4. 添加以下内容:
---
- name: Use file listing role
  hosts: local
  roles:
    - role: file_lister
      vars:
        path: "/etc"
        patterns: "*.conf"
        file_type: "file"
        show_details: true

此 playbook:

  1. 在本地主机上运行
  2. 使用我们的 file_lister 角色
  3. 为角色设置变量以自定义其行为

让我们运行 playbook:

cd ~/project/ansible-lab
ansible-playbook use_role.yml

你应该看到输出,显示 /etc 目录中所有 .conf 文件的详细信息。

自定义角色变量

角色的优点之一是我们可以通过更改变量轻松地自定义其行为。让我们创建另一个 playbook,该 playbook 使用具有不同参数的角色:

  1. 在 Explorer 面板中,右键单击并选择“New File”
  2. 将文件命名为 custom_listing.yml
  3. 添加以下内容:
---
- name: Custom file listing
  hosts: local
  roles:
    - role: file_lister
      vars:
        path: "/home/labex"
        patterns: "*.yml"
        file_type: "file"
        show_details: false

此 playbook:

  1. 使用我们的 file_lister 角色
  2. 将其设置为在 /home/labex 目录中查找
  3. 过滤 YAML 文件 (*.yml)
  4. 仅显示文件路径(不是完整的详细信息)

让我们运行 playbook:

ansible-playbook custom_listing.yml

你应该看到 /home/labex 目录中所有 YAML 文件的列表,没有详细信息。

高级用法:创建报告

最后,让我们创建一个更高级的 playbook,它使用我们的角色来生成文件报告:

  1. 在 Explorer 面板中,右键单击并选择“New File”
  2. 将文件命名为 generate_report.yml
  3. 添加以下内容:
---
- name: Generate file listing report
  hosts: local
  vars:
    report_path: "~/project/ansible-lab/file_report.txt"
  tasks:
    - name: Find files in the specified directory
      ansible.builtin.find:
        paths: "/etc"
        patterns: "*.conf"
        file_type: "file"
      register: found_files

    - name: Create report header
      copy:
        dest: "{{ report_path }}"
        content: |
          File Listing Report
          Generated on: {{ ansible_date_time.date }} at {{ ansible_date_time.time }}
          -----------------------------------------------------------
          Mode       Owner  Group  Size       Modified    Path
          -----------------------------------------------------------
        force: yes

    - name: Append file information to report
      lineinfile:
        path: "{{ report_path }}"
        line: "{{ item.mode }} {{ item.uid }} {{ item.gid }} {{ item.size | string | ljust(10) }} {{ item.mtime }} {{ item.path }}"
      loop: "{{ found_files.files | sort(attribute='path') }}"
      loop_control:
        label: "{{ item.path }}"

    - name: Display report location
      debug:
        msg: "Report generated at {{ report_path }}"

此 playbook:

  1. /etc 目录中查找 .conf 文件
  2. 创建一个带有标题的文本文件
  3. 将有关每个文件的信息附加到报告中
  4. 显示报告的位置

让我们运行 playbook:

ansible-playbook generate_report.yml

运行 playbook 后,你可以查看报告:

cat ~/project/ansible-lab/file_report.txt

你应该看到一个格式化的报告,列出 /etc 目录中的所有 .conf 文件。

总结

在这个实验中,你已经学习了如何使用 Ansible 以长格式列出文件和目录。你获得了以下方面的实践经验:

  1. 通过安装软件和创建清单文件来设置 Ansible
  2. 创建使用 command 模块运行 ls -l 命令的基本 playbook
  3. 使用 Ansible 内置的 file 和 find 模块获取有关文件的详细信息
  4. 创建一个可重用的 Ansible 角色,用于使用各种选项列出文件
  5. 根据文件信息生成格式化的报告

这些技能将帮助你自动化跨基础设施的文件管理任务,并将文件列表集成到更大的自动化工作流程中。随着你继续使用 Ansible,你可以基于这些概念构建更复杂的自动化,以管理整个环境中的文件、目录及其权限。