Distribute and Inspect Managed Files

AnsibleBeginner
Practice Now

Introduction

Reliable file automation distinguishes the controller's source, the managed copies and the artifacts collected back for inspection. Correct filenames alone do not establish content integrity, permissions or host identity.

You will deploy a banner, inspect its actual SHA-256 metadata with stat and register, generate per-host operational reports, and fetch those reports into separate controller paths. The prepared two-host SSH environment and privilege model are the same ones practiced earlier.

Distribute a File with Explicit Managed Permissions

In this step, you will copy a private controller source into a protected managed directory and choose remote ownership and permissions explicitly.

Open the Terminal and enter the project:

cd /home/labex/project

Create the reusable controller source, including its final newline:

printf 'Managed service banner\n' > site-banner.txt

chmod changes a local file's permissions. Mode 0600 gives its owner read/write access and no access to its group or others. Keep this controller source private while deliberately choosing different managed permissions:

chmod 0600 site-banner.txt

Write a distribution playbook:

cat > deploy-banner.yml <<'EOF'
- name: Distribute the managed banner
  hosts: all
  gather_facts: false
  become: true
  tasks:
    - name: Prepare the managed site directory
      ansible.builtin.file:
        path: /srv/ansible-site
        state: directory
        owner: root
        group: automation
        mode: "0750"

    - name: Copy the controller banner with explicit managed permissions
      ansible.builtin.copy:
        src: /home/labex/project/site-banner.txt
        dest: /srv/ansible-site/banner.txt
        owner: root
        group: automation
        mode: "0640"
EOF

The play-level become requests elevation on the managed nodes, where writing under /srv and assigning root ownership require it. It does not turn the controller's source-reading process into a root login.

The directory is owned by root, grouped to automation and mode 0750. The banner is root-owned, grouped to automation and mode 0640. That lets the ordinary automation account traverse the directory and read the banner without granting it write access. Explicit managed mode is independent of the controller source's 0600 mode.

Check and apply the playbook:

ansible-playbook deploy-banner.yml --syntax-check
ansible-playbook deploy-banner.yml

Both hosts should complete without failures. Test ordinary read access without become:

ansible all -m ansible.builtin.command -a 'cat /srv/ansible-site/banner.txt'

Each host should print Managed service banner. This demonstrates the intended remote group-read access while keeping the source and managed copies as separate files.

Register and Consume Structured File Metadata

In this step, you will inspect the real managed banner and write a per-host operational report from its metadata.

The stat module returns file information rather than copying it. checksum_algorithm: sha256 selects SHA-256 for content verification. register stores that task's result for later tasks on the same host; its stat field contains the file metadata.

Create an inspection playbook:

cat > inspect-and-collect.yml <<'EOF'
- name: Inspect the banner and prepare host reports
  hosts: all
  gather_facts: true
  tasks:
    - name: Inspect managed content and permissions
      ansible.builtin.stat:
        path: /srv/ansible-site/banner.txt
        checksum_algorithm: sha256
      register: banner_info

    - name: Display the structured file metadata
      ansible.builtin.debug:
        var: banner_info.stat

    - name: Write the per-host report from real metadata
      become: true
      ansible.builtin.copy:
        dest: /srv/ansible-site/node-report.txt
        content: |
          host={{ inventory_hostname }}
          distribution={{ ansible_facts.distribution }}
          banner_sha256={{ banner_info.stat.checksum }}
        owner: root
        group: automation
        mode: "0640"
EOF

The debug module displays an existing variable with var, so banner_info.stat reveals fields such as exists, mode, owner/group names, size and checksum. Displaying metadata does not create a file or prove a later operation succeeded.

The copy task consumes banner_info.stat.checksum together with inventory_hostname and the distribution fact. Its task-level become is needed to write the root-owned report. The inspection tasks themselves use ordinary read access.

Run the inspection and report generation:

ansible-playbook inspect-and-collect.yml

The metadata should identify a regular file with mode 0640, owner root and group automation. Each report has its own host name and a SHA-256 value derived from the actual remote banner.

sha256sum computes a local file's SHA-256 digest and prints the digest followed by its name. Compare the controller source digest with the metadata and report values:

sha256sum site-banner.txt

Read both remote reports:

ansible all -m ansible.builtin.command -a 'cat /srv/ansible-site/node-report.txt'

Each result should contain host=web1 or host=web2, distribution=Ubuntu and banner_sha256 followed by the matching 64-character digest. Keep observations tied to each real host, rather than replacing them with a constant debug message.

Fetch Separate Reports Back to the Controller

In this step, you will collect both managed reports without overwriting one host's result with the other.

copy normally sends a controller source to a managed destination. fetch works in the other direction: its src is on the managed node and its dest is a controller directory. With flat false, fetch includes the inventory host name and remote path beneath dest.

Append this task to the existing inspection playbook. Keep its indentation aligned with the other task entries; >> appends without replacing the earlier stat, register and report tasks:

cat >> inspect-and-collect.yml <<'EOF'

    - name: Collect each managed report without flattening host paths
      ansible.builtin.fetch:
        src: /srv/ansible-site/node-report.txt
        dest: /home/labex/project/reports/
        flat: false
EOF

Run the complete inspection and collection workflow:

ansible-playbook inspect-and-collect.yml

The first fetch should create the two controller copies. It runs as the ordinary automation account on each target because the report's group permissions already allow reads.

Inspect each collected artifact locally:

cat reports/web1/srv/ansible-site/node-report.txt
cat reports/web2/srv/ansible-site/node-report.txt

The paths preserve independent host identity. Each report's host field should match its path, and both checksum fields should match the deployed source. Flattening both results to one shared filename would lose one host's artifact.

Repeat the complete workflow:

ansible-playbook inspect-and-collect.yml

With unchanged source, facts and file state, both hosts should report changed=0 and no failures/unreachable results. You now have independently collected reports backed by actual managed metadata.

Summary

You kept controller and managed file state distinct, declared remote ownership and permissions, and consumed registered stat metadata instead of merely printing a success message. Per-host reports recorded real SHA-256 integrity information, and fetch preserved both hosts' artifacts in separate controller paths with stable repeat execution.