Manipulate Files with Oracle Linux Automation Engine

3
0
Send lab feedback

Manipulate Files with Oracle Linux Automation Engine

Introduction

Oracle Linux Automation Engine automates the execution of playbooks on remote hosts deployed within your organization, often including the ability to create files and directories as part of the overall setup process as part of configuring a system.

This tutorial shows how to create and delete files and directories on your remote hosts.

Objectives

In this lab, you'll learn about writing and running a playbook that:

  • Creates an empty file
  • Creates a file with content
  • Creates multiple files in a single task
  • Sets file permissions
  • Creates a directory
  • Removes files and directories

What Do You Need?

  • A minimum of two Oracle Linux systems with the following configuration:

    • a non-root user with sudo permissions
    • ssh keypair for the non-root user
    • the ability to SSH from one host (control-node) to the other (host) using passwordless SSH login

Additional Information

Note: When using the free lab environment, see Oracle Linux Lab Basics for connection and other usage instructions.

Information: The free lab environment deploys an Oracle Linux on the provided nodes. This deployment takes approximately 5 minutes to finish after launch. Therefore, you might want to step away while this runs and then return to complete the lab.

Before proceeding: If you are unfamiliar with running playbooks, check out our introduction tutorial, Write a Playbook with Oracle Linux Automation Engine . This tutorial follows on from this tutorial, Enable the EPEL Repository with Oracle Linux Automation Engine .

Verify the Inventory

From a terminal on the Oracle Linux Automation Engine Control Node:

  1. Open a terminal and connect via SSH to the ol-control-node.

    ssh oracle@<ip_address_of_ol-control-node>
  2. Change to the working directory.

    cd ~/ol-setup-playbook

    The working directory stores the existing playbook and other files from the previous tutorial associated with this project.

    Note: This directory already exists when using the free lab environment or if continuing from the steps provided in the base tutorial. If the directory does not exist, complete the base tutorial steps at a minimum before proceeding.

  3. Test the connection with the ad-hoc ping command.

    ansible ol-node01 -i inventory -m ping -u opc

    The command connects successfully, reporting back SUCCESS with the ping key having a value of pong.

Update the Playbook

  1. Add the following to the existing playbook file.

    cat << EOF | tee -a setup-playbook.yml > /dev/null     
    
      - name: Create an example directory (if it does not already exist)
        ansible.builtin.file:
          path: "/home/{{ username }}/example"
          state: directory
          mode: '0755'
        become_user: "{{ username }}"
    
      - name: Create an empty file
        ansible.builtin.file:
          path: "/home/{{ username }}/example/test.txt"
          state: touch
          # mode: u=rw,g=r,o=r
        become_user: "{{ username }}"
    EOF

    This playbook adds two tasks within the defined play. The first creates a new directory called example in the remote user's $HOME directory, and the second creates an empty file called test.txt in the newly created example directory.

    While a playbook aims to be self-documenting, the information below will explain a few items further.

    • state:: The ansible.builtin.file module supports the following parameters: "absent", "directory", "file", "hard", "link" and "touch". These tasks use "directory", which creates the directory path if not already present, and "touch", which creates an empty file if not already present.
    • mode: Sets the filesystem permissions for the object created. When using the command line, you can use either octal ('0755') or symbolic (u=rw,g=r,o=r) modes (equivalent to 0644 in octal mode). The system default mode is applied if you omit the mode: parameter.
    • become_user: "{{ username }}": Uses the Oracle Linux Automation Engine privilege escalation functionality to execute a task. In previous tutorials, we introduced the become privilege escalation functionality to run a task as root. This example illustrates how to use similar functionality to execute a task as another user. We set the user as the variable "{{ username }}", which we predefine as the oracle user in the vars/defaults.yml file. Hence, this task runs as the oracle user and inherits that user's defaults.

Run the Playbook

  1. Run the playbook to perform the additional tasks.

    ansible-playbook -i inventory setup-playbook.yml -u opc

    The playbook finishes successfully, showing a few WARNINGS that we can ignore and reporting the tasks with an ok or changed status.

    Example Output:

     [oracle@ol-control-node ol-setup-playbook]$ ansible-playbook -i inventory setup-playbook.yml -u opc
    
    PLAY [Playbook to setup Oracle Linux] **********************************************************
    
    TASK [Gathering Facts] *************************************************************************
    [WARNING]: Platform linux on host ol-node01 is using the discovered Python interpreter at
    /usr/bin/python3.6, but future installation of another Python interpreter could change the
    meaning of that path. See https://docs.ansible.com/ansible-
    core/2.15/reference_appendices/interpreter_discovery.html for more information.
    ok: [ol-node01]
    
    TASK [Add user account with access to sudo] ****************************************************
    [DEPRECATION WARNING]: Encryption using the Python crypt module is deprecated. The Python crypt
     module is deprecated and will be removed from Python 3.13. Install the passlib library for 
    continued encryption functionality. This feature will be removed in version 2.17. Deprecation 
    warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
    ok: [ol-node01]
    
    TASK [Set authorized key for user using local public key file] *********************************
    changed: [ol-node01]
    
    TASK [Install additional packages] *************************************************************
    ok: [ol-node01]
    
    TASK [Add the EPEL repository] *****************************************************************
    ok: [ol-node01]
    
    TASK [Install the htop utility package] ********************************************************
    ok: [ol-node01]
    
    TASK [Create an example directory (if it does not already exist)] ******************************
    [WARNING]: Module remote_tmp /home/oracle/.ansible/tmp did not exist and was created with a
    mode of 0700, this may cause issues when running as another user. To avoid this, create the
    remote_tmp dir with the correct permissions manually
    changed: [ol-node01]
    
    TASK [Create an empty file] ********************************************************************
    changed: [ol-node01]
    
    PLAY RECAP *************************************************************************************
    ol-node01                  : ok=8    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
       

Confirm The New Directory and File Exist

  1. Use SSH to get a directory listing on the remote host.

    ssh oracle@<ip_address_of_ol-node> ls -al example

    Example Output:

    [oracle@ol-control-node ol-setup-playbook]$ ssh oracle@130.162.213.42 ls -al example
    total 0
    drwxr-xr-x. 2 oracle oracle  22 Feb  2 14:47 .
    drwx------. 5 oracle oracle 105 Feb  2 14:47 ..
    -rw-r--r--. 1 oracle oracle   0 Feb  2 14:47 test.txt

    The output confirms the creation of a new directory and the empty file. Notice that the test.txt file has zero bytes, and the oracle user owns it.

Create Multiple Files

During the setup of a system, you may need to create several files within a directory. Rather than using individual tasks, you can create several files in a directory as an atomic operation. Here is one approach to achieving this.

  1. Add the following tasks to the playbook file.

    cat << EOF | tee -a setup-playbook.yml > /dev/null     
    
      - name: Add multiple files
        ansible.builtin.file:
          path: "/home/{{ username }}/example/{{ item }}"
          state: touch
        with_items:
        - file01.txt
        - file02.txt
        - file03.txt
        - file04.txt
        become_user: "{{ username }}"
    EOF

    This task uses a loop to create several empty files from a list.

    • path:: Defines the location on the remote system to write the files. Oracle Linux Automation Engine replaces the {{ item }} variable with each item from the with_items parameter during runtime.
    • with_items:: This parameter indicates the list of items to loop over during the running of this task. While this example uses only four file names, the list can be as long as you need.
  2. Run the playbook to perform the additional tasks.

    ansible-playbook -i inventory setup-playbook.yml -u opc

    Example Output:

    [oracle@ol-control-node ol-setup-playbook]$ ansible-playbook -i inventory setup-playbook.yml -u opc
    
    PLAY [Playbook to setup Oracle Linux] ********************************************************************
    
    TASK [Gathering Facts] ***********************************************************************************
    [WARNING]: Platform linux on host ol-node01 is using the discovered Python interpreter at
    /usr/bin/python3.6, but future installation of another Python interpreter could change the meaning of
    that path. See https://docs.ansible.com/ansible-core/2.15/reference_appendices/interpreter_discovery.html
    for more information.
    ok: [ol-node01]
    
    ...
    
    TASK [Create an empty file] ******************************************************************************
    changed: [ol-node01]
    
    TASK [Create an example directory (if it does not already exist)] ****************************************
    changed: [ol-node01] => (item=file01.txt)
    changed: [ol-node01] => (item=file02.txt)
    changed: [ol-node01] => (item=file03.txt)
    changed: [ol-node01] => (item=file04.txt)
    
    PLAY RECAP ***********************************************************************************************
    ol-node01                  : ok=9    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 
       

Confirm The New Files Exist

  1. Use SSH again to confirm the files exist.

    ssh oracle@<ip_address_of_ol-node> ls -al example

    Example Output:

    [oracle@ol-control-node ol-setup-playbook]$ ssh oracle@130.162.213.42 ls -al example
    total 0
    drwxr-xr-x. 2 oracle oracle  94 Feb  2 15:20 .
    drwx------. 5 oracle oracle 105 Feb  2 14:47 ..
    -rw-r--r--. 1 oracle oracle   0 Feb  2 15:20 file01.txt
    -rw-r--r--. 1 oracle oracle   0 Feb  2 15:20 file02.txt
    -rw-r--r--. 1 oracle oracle   0 Feb  2 15:20 file03.txt
    -rw-r--r--. 1 oracle oracle   0 Feb  2 15:20 file04.txt
    -rw-r--r--. 1 oracle oracle   0 Feb  2 15:20 test.txt

Add Content To a File

While creating a file is helpful, an empty file serves little purpose. These next few tasks use the ansible.builtin.lineinfile module to insert individual lines and the ansible.builtin.blockinfile module to handle a block of text.

Add a Single Line to a File

  1. Update the playbook file with the new tasks.

    cat << 'EOF' | tee -a setup-playbook.yml > /dev/null     
    
      - name: Insert some text into the test.txt file
        ansible.builtin.lineinfile:
          path: "/home/{{ username }}/example/test.txt"
          line: This is a test
          create: True
          owner: "{{ username }}"
          group: "{{ username }}"
          mode: '0644'
    
      - name: Add an extra line, after the line just inserted
        ansible.builtin.lineinfile:
          path: "/home/{{ username }}/example/test.txt"
          regexp: '^a test'
          insertafter: 'This is a test'
          line: This is some updated text that was added later.
          create: True
          owner: "{{ username }}"
          group: "{{ username }}"
          mode: '0644'
    
      - name: Get the contents of the test.txt file
        ansible.builtin.command: cat ~/example/test.txt
        register: command_output
        become_user: "{{ username }}"
        
      - name: Print the results of the cat command
        ansible.builtin.debug:
          msg: "{{ command_output }}"
    
      - name: Print only the lines added to the text file
        ansible.builtin.debug:
          msg: "{{ command_output.stdout_lines }}"
    EOF
    • The first two tasks use the ansible.builtin.lineinfile to add and update single lines in the file.

    • The remaining tasks show a method to confirm the changes. The playbook first uses the ansible.builtin.command to output the content of the updated file to stdout and saves it to memory in a register variable. Then it uses the ansible.builtin.debug module to print that content to the screen as part of the playbook output. The second debug task shows a way to limit the output to only a particular part of the JSON output from the previous task.

  2. Run the playbook to perform the additional tasks.

    ansible-playbook -i inventory setup-playbook.yml -u opc

    Example Output:

     [oracle@ol-control-node ol-setup-playbook]$ ansible-playbook -i inventory setup-playbook.yml -u opc
    
    PLAY [Playbook to setup Oracle Linux] ********************************************************************
    
    TASK [Gathering Facts] ***********************************************************************************
    [WARNING]: Platform linux on host ol-node01 is using the discovered Python interpreter at
    /usr/bin/python3.6, but future installation of another Python interpreter could change the meaning of
    that path. See https://docs.ansible.com/ansible-core/2.15/reference_appendices/interpreter_discovery.html
    for more information.
    ok: [ol-node01]
    
    ...
    
    TASK [Insert some text into the 'test.txt' file] *****************************************************************************
    ok: [ol-node01]
    
    TASK [Add an extra line, after the line just inserted] ***********************************************************************
    ok: [ol-node01]
    
    TASK [Get the contents of the 'test.txt' file] ********************************************
    changed: [ol-node01]
    
    TASK [Print the command output] *************************************************************************************
    ok: [ol-node01] => {
        "msg": {
             "changed": true,
              "cmd": [
                  "cat",
                   "~/example/test.txt"
              ],
              "delta": "0:00:00.001678",
              "end": "2024-01-30 13:43:50.209312",
              "failed": false,
              "msg": "",
              "rc": 0,
              "start": "2024-01-30 13:43:50.207634",
              "stderr": "",
              "stderr_lines": [],
              "stdout": "This is a test\nThis is some updated text that was added later.",
              "stdout_lines": [
                  "This is a test",
                  "This is some updated text that was added later."
              ]
        }
    }
    
    TASK [Print only the lines added to the text file] ***************************************************************************
    ok: [ol-node01] => {
        "msg": [
            "This is a test",
            "This is some updated text that was added later."
        ]
    }
    
    PLAY RECAP *******************************************************************************************************************
    ol-node01                  : ok=14   changed=5    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
       

Add Multiple Lines to a File

Adding a large text block one line at a time is slow and inefficient. Oracle Linux Automation Engine provides multiple ways to achieve these tasks based on your requirements. The ansible.builtin.blockinfile module allows the insert, update, and removal of multiple lines of text with custom markers. These markers enable easy identification of the text and ensure idempotency. The idempotency of Oracle Linux Automation Engine allows running the playbook repeatedly, yielding the same results.

The second option uses the ansible.builtin.copy module. This module's primary purpose is to copy files from one location to another, but it can also create a new file and insert text into it in a single operation.

  1. Update the playbook with the new tasks.

    cat << EOF | tee -a setup-playbook.yml > /dev/null     
    
      - name: Add two lines into test.txt
        ansible.builtin.blockinfile:
          path: "/home/{{ username }}/example/test.txt"
          insertafter: 'This is some updated text that was added later.'
          block: |
            "Welcome to {{ ansible_hostname }}"
            "Last updated on {{ ansible_date_time.iso8601 }}"
    
      - name: Create a new file and insert content into it
        ansible.builtin.copy:
          content: |
            === The text below was added by Oracle Linux Automation Engine ==========
    
            Hello from the ansible.builtin.copy module
            This is an example of how to insert more than one line into a text file
            You can insert more lines if you want
    
            === The text above was added by Oracle Linux Automation Engine ===========
          dest: "/home/{{ username }}/example/testing.txt"
          mode: '0644'
        become_user: "{{ username }}"
    EOF
  2. Run the playbook to perform the additional tasks.

    ansible-playbook -i inventory setup-playbook.yml -u opc

    Example Output:

     [oracle@ol-control-node ol-setup-playbook]$ ansible-playbook -i inventory setup-playbook.yml -u opc
    
    PLAY [Playbook to setup Oracle Linux] ********************************************************************
    
    TASK [Gathering Facts] ***********************************************************************************
    [WARNING]: Platform linux on host ol-node01 is using the discovered Python interpreter at
    /usr/bin/python3.6, but future installation of another Python interpreter could change the meaning of
    that path. See https://docs.ansible.com/ansible-core/2.15/reference_appendices/interpreter_discovery.html
    for more information.
    ok: [ol-node01]
    
    ...
    
    TASK [Add two lines into test.txt] *******************************************************************************************
    changed: [ol-node01]
    
    TASK [Create a new file and insert content into it] **************************************************************************
    changed: [ol-node01]
    
    PLAY RECAP *******************************************************************************************************************
    ol-node01                  : ok=16   changed=5    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 
       

Confirm The New Lines Exist

  1. Confirm two new lines are present in test.txt.

    ssh oracle@<ip_address_of_ol-node> cat example/test.txt

    Example Output:

    [oracle@ol-control-node ol-setup-playbook]$ ssh oracle@130.162.213.42 cat example/test.txt
    This is a test
    This is some updated text that was added later.
    # BEGIN ANSIBLE MANAGED BLOCK
    "Welcome to ol-node01"
    "Last updated on 2024-01-30T14:05:58Z"
    # END ANSIBLE MANAGED BLOCK

    The output shows the added content and interprets the task's variable values based on the automatic fact gathering done by the playbook against the remote host during runtime.

  2. Confirm creating the testing.txt file and the added content.

    ssh oracle@<ip_address_of_ol-node> cat example/testing.txt

    Example Output:

    [oracle@ol-control-node ol-setup-playbook]$ ssh oracle@130.162.213.42 cat example/testing.txt 
    === The text below was added by Oracle Linux Automation Engine ==========
    
    Hello from the ansible.builtin.copy module
    This is an example of how to insert more than one line into a text file
    You can insert more lines if you want
    
    === The text above was added by Oracle Linux Automation Engine ===========

Delete Files and Directories

Besides creating files and directories and adding text, Oracle Linux Automation Engine can also delete these items. Let's remove the directory and all the files this playbook creates and leave the system in the same state as when we started. These tasks first use the state: parameter set to absent to remove the list of files and then the directory. The second task handles removing the files in a single step along with the directory. Still, we include the first task for additional demonstration of the Oracle Linux Automation Engine features.

  1. Add the following to the playbook file.

    cat << EOF | tee -a setup-playbook.yml > /dev/null     
    
      - name: Delete multiple files
        ansible.builtin.file:
          path: '{{ item }}'
          state: absent
        with_items:
          - "/home/{{ username }}/example/test.txt"
          - "/home/{{ username }}/example/file01.txt"
          - "/home/{{ username }}/example/file02.txt"
          - "/home/{{ username }}/example/file03.txt"
          - "/home/{{ username }}/example/file04.txt"
          - "/home/{{ username }}/example/testing.txt"
    
      - name: Recursively remove directory
        ansible.builtin.file:
          path: "/home/{{ username }}/example"
          state: absent
    EOF

    Note: It is possible to recursively delete a directory (including any contents) using the second task shown. The first task, deleting the files individually, is present in case you only want to delete files. If you want to delete both files and files and directories, the second task is more efficient.

  2. Run the playbook to perform the additional tasks.

    ansible-playbook -i inventory setup-playbook.yml -u opc

    Example Output:

     [oracle@ol-control-node ol-setup-playbook]$ ansible-playbook -i inventory setup-playbook.yml -u opc
    
    PLAY [Playbook to setup Oracle Linux] ********************************************************************
    
    TASK [Gathering Facts] ***********************************************************************************
    [WARNING]: Platform linux on host ol-node01 is using the discovered Python interpreter at
    /usr/bin/python3.6, but future installation of another Python interpreter could change the meaning of
    that path. See https://docs.ansible.com/ansible-core/2.15/reference_appendices/interpreter_discovery.html
    for more information.
    ok: [ol-node01]
    
    ...
    
    TASK [Delete multiple files] *********************************************************************************************
    changed: [ol-node01] => (item=/home/oracle/example/test.txt)
    changed: [ol-node01] => (item=/home/oracle/example/file01.txt)
    changed: [ol-node01] => (item=/home/oracle/example/file02.txt)
    changed: [ol-node01] => (item=/home/oracle/example/file03.txt)
    changed: [ol-node01] => (item=/home/oracle/example/file04.txt)
    changed: [ol-node01] => (item=/home/oracle/example/testing.txt)
    
    TASK [Recursively remove directory] **************************************************************************************
    changed: [ol-node01]
    
    PLAY RECAP ***************************************************************************************************************
    ol-node01                  : ok=18   changed=6    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

Confirm Directory and Files Deletion

  1. Verify the removal of the example directory.

    ssh oracle@<ip_address_of_ol-node> ls

    Example Output:

    [oracle@ol-control-node ol-setup-playbook]$ ssh oracle@130.162.213.42 ls
    [oracle@ol-control-node ol-setup-playbook]$ 

    The lack of output confirms the example directory and the files created during this tutorial are gone.

Summary

Congratulations on making it this far. This tutorial introduced a flavor of the approaches Oracle Linux Automation Engine makes available to create, update, and delete files and directories. The tutorial also showed how to use Oracle Linux Automation Engine's ansible.builtin.debug module to return information to the terminal while executing a Playbook.

For More Information

Oracle Linux Automation Manager Documentation
Oracle Linux Automation Manager Training
Oracle Linux Training Station

SSR