One place for hosting & domains

      Ansible

      How To Access System Information (Facts) in Ansible Playbooks



      Part of the Series:
      How To Write Ansible Playbooks

      Ansible is a modern configuration management tool that doesn’t require the use of an agent software on remote nodes, using only SSH and Python to communicate and execute commands on managed servers. This series will walk you through the main Ansible features that you can use to write playbooks for server automation. At the end, we’ll see a practical example of how to create a playbook to automate setting up a remote Nginx web server and deploy a static HTML website to it.

      By default, before executing the set of tasks defined in a playbook, Ansible will take a few moments to gather information about the systems that are being provisioned. This information, referred to as facts, contain details such as network interfaces and addresses, the operating system running on remote nodes, and available memory, among other things.

      Ansible stores facts in JSON format, with items grouped in nodes. To check what kind of information is available for the systems you’re provisioning, you can run the setup module with an ad hoc command:

      • ansible all -i inventory -m setup -u sammy

      This command will output an extensive JSON containing information about your server. To obtain a subset of that data, you can use the filter parameter and provide a pattern. For instance, if you’d like to obtain information about all IPv4 addresses in the remote nodes, you can use the following command:

      • ansible all -i inventory -m setup -a "filter=*ipv4*" -u sammy

      You’ll see output like this:

      Output

      203.0.113.10 | SUCCESS => { "ansible_facts": { "ansible_all_ipv4_addresses": [ "203.0.113.10", "198.51.100.23" ], "ansible_default_ipv4": { "address": "203.0.113.10", "alias": "eth0", "broadcast": "203.0.113.255", "gateway": "203.0.113.1", "interface": "eth0", "macaddress": "06:c7:91:16:2e:b7", "mtu": 1500, "netmask": "203.0.113.0", "network": "203.0.113.0", "type": "ether" } }, "changed": false }

      Once you have found the facts that will be useful for your play, you can update your playbook accordingly. As an example, the following playbook will print out the IPv4 address of the default network interface. From the previous command output, we can see that this value is available through ansible_default_ipv4.address in the JSON provided by Ansible.

      Create a new file called playbook-03.yml in your ansible-practice directory:

      • nano ~/ansible-practice/playbook-03.yml

      Then add the following lines to the new playbook file:

      ~/ansible-practice/playbook-03.yml

      ---
      - hosts: all
        tasks:
          - name: print facts
            debug:
              msg: "IPv4 address: {{ ansible_default_ipv4.address }}"
      

      Save and close the file when you’re done.

      To try this playbook on servers from your inventory file, run ansible-playbook with the same connection arguments you’ve used before when running our first example. Again, we’ll be using an inventory file named inventory and the sammy user to connect to the remote servers:

      • ansible-playbook -i inventory playbook-03.yml -u sammy

      When you run the playbook, you’ll see your remote server’s IPv4 address in the output as expected:

      Output

      ... TASK [print facts] *************************************************************************************************************************************************************************** ok: [server1] => { "msg": "IPv4 address: 203.0.113.10" } ...

      Facts encapsulate important data that you can leverage to better customize your playbooks. To learn more about all the information you can obtain through facts, please refer to the official Ansible documentation.



      Source link

      Understanding Privilege Escalation in Ansible Playbooks



      Part of the Series:
      How To Write Ansible Playbooks

      Ansible is a modern configuration management tool that doesn’t require the use of an agent software on remote nodes, using only SSH and Python to communicate and execute commands on managed servers. This series will walk you through the main Ansible features that you can use to write playbooks for server automation. At the end, we’ll see a practical example of how to create a playbook to automate setting up a remote Nginx web server and deploy a static HTML website to it.

      Just as with regular commands that you execute on a terminal, some tasks will require special privileges in order for Ansible to execute them successfully on your remote nodes.

      It is important to understand how privilege escalation works in Ansible so that you’re able to execute your tasks with appropriate permissions. By default, tasks will run as the connecting user – this might be either root or any regular user with SSH access to the remote nodes in an inventory file.

      To run a command with extended permissions, such as a command that requires sudo, you’ll need to include a become directive set to yes in your play. This can be done either as a global setting valid to all tasks in that play, or as an individual instruction applied per task. Depending on how your sudo user is set up within the remote nodes, you may also need to provide the user’s sudo password. The following example updates the apt cache, a task that requires root permissions.

      Create a new file called playbook-07.yml in your ansible-practice directory:

      • nano ~/ansible-practice/playbook-07.yml

      Then add the following lines to the new playbook file:

      ~/ansible-practice/playbook-07.yml

      ---
      - hosts: all
        become: yes
        tasks:
          - name: Update apt cache
            apt:
              update_cache: yes
      

      Save and close the file when you’re done.

      To run this playbook, you’ll need to include the -K option within the ansible-playbook command. This will make Ansible prompt you for the sudo password for the specified user.

      • ansible-playbook -i inventory playbook-07.yml -u sammy -K

      You can also change which user you want to switch to while executing a task or play. To do that, set the become_user directive to the name of the remote user you want to switch to. This is useful when you have several tasks in a playbook that rely on sudo, but also a few tasks that should run as your regular user.

      The following example defines that all tasks in this play will be executed with sudo by default. This is set at the play level, right after the hosts definition. The first task creates a file on /tmp using root privileges, since that is the default became_user value. The last task, however, defines its own become_user.

      Create a new file called playbook-08.yml in your ansible-practice directory:

      • nano ~/ansible-practice/playbook-08.yml

      Add the following content to the new playbook file:

      ~/ansible-practice/playbook-08.yml

      ---
      - hosts: all
        become: yes
        vars:
          user: "{{ ansible_env.USER }}"
        tasks:
          - name: Create root file
            file:
              path: /tmp/my_file_root
              state: touch
      
          - name: Create user file
            become_user: "{{ user }}"
            file:
              path: /tmp/my_file_{{ user }}
              state: touch
      
      

      Save and close the file when you’re finished.

      The ansible_env.USER fact contains the username of the connecting user, which can be defined at execution time when running the ansible-playbook command with the -u option. Throughout this guide, we’re connecting as sammy:

      • ansible-playbook -i inventory playbook-08.yml -u sammy -K

      Output

      BECOME password: PLAY [all] ********************************************************************************************** TASK [Gathering Facts] ********************************************************************************** ok: [203.0.113.10] TASK [Create root file] ********************************************************************************* changed: [203.0.113.10] TASK [Create user file] ********************************************************************************* changed: [203.0.113.10] PLAY RECAP ********************************************************************************************** 203.0.113.10 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

      When the playbook is finished running, you can log onto the remote node(s) to verify that two new files were created on /tmp, each with different ownership information:

      Output

      -rw-r--r-- 1 root root 0 Apr 14 13:19 /tmp/my_file_root -rw-r--r-- 1 sammy sudo 0 Apr 14 12:07 /tmp/my_file_sammy

      For more detailed information about privilege escalation in Ansible, please refer to the official documentation.



      Source link

      How To Use Conditionals in Ansible Playbooks



      Part of the Series:
      How To Write Ansible Playbooks

      Ansible is a modern configuration management tool that doesn’t require the use of an agent software on remote nodes, using only SSH and Python to communicate and execute commands on managed servers. This series will walk you through the main Ansible features that you can use to write playbooks for server automation. At the end, we’ll see a practical example of how to create a playbook to automate setting up a remote Nginx web server and deploy a static HTML website to it.

      In Ansible, you can define conditions that will be evaluated before a task is executed. When a condition is not met, the task is then skipped. This is done with the when keyword, which accepts expressions that are typically based on a variable or a fact.

      The following example defines two variables: create_user_file and user. When the create_user_file is evaluated to true, a new file will be created in the home directory of the user defined by the user variable:

      Create a new file called playbook-04.yml in your ansible-practice directory:

      • nano ~/ansible-practice/playbook-04.yml

      Then add the following lines to the new playbook file:

      ~/ansible-practice/playbook-04.yml

      ---
      - hosts: all
        vars:
          - create_user_file: yes
          - user: sammy  
        tasks:
          - name: create file for user
            file:
              path: /home/{{ user }}/myfile
              state: touch
            when: create_user_file
      

      Save and close the file when you’re done editing its contents.

      To execute this playbook on servers from your inventory file, run ansible-playbook with the same connection arguments you’ve used before when running other playbooks in this series. Again, we’ll be using an inventory file named inventory and the sammy user to connect to the remote servers:

      • ansible-playbook -i inventory playbook-04.yml -u sammy

      When the condition is met, you’ll see a changed status in the play output:

      Output

      ... TASK [create file for user] ***************************************************************************** changed: [203.0.113.10] ...

      If you change the value of create_user_file to no, the condition will be evaluated to false. In this case, you’ll see a skipping status in the play output, indicating that the task was not executed:

      Output

      ... TASK [create file for user] ***************************************************************************** skipping: [203.0.113.10] ...

      A common use for conditionals in the context of Ansible playbooks is to combine them with register, a keyword that creates a new variable and assigns it with the output obtained from a command. This way, you can use any external command to evaluate the execution of a task.

      One important thing to notice is that, by default, Ansible will interrupt a play if the command you’re using to evaluate a condition fails. For that reason, you’ll need to include an ignore_errors directive set to yes in said task, and this will make Ansible move on to the next task and continue the play.

      The following example will only create a new file in the user home directory in case that file doesn’t exist yet, which we’ll test with an ls command. If the file exists, however, we’ll show a message using the debug module.

      Create a new file called playbook-05.yml in your ansible-practice directory:

      • nano ~/ansible-practice/playbook-05.yml

      Then add the following content to the new playbook file:

      ~/ansible-practice/playbook-05.yml

      ---
      - hosts: all
        vars:
          - user: sammy
        tasks:
          - name: Check if file already exists
            command: ls /home/{{ user }}/myfile
            register: file_exists
            ignore_errors: yes
      
          - name: create file for user
            file:
              path: /home/{{ user }}/myfile
              state: touch
            when: file_exists is failed
      
          - name: show message if file exists
            debug:
              msg: The user file already exists.
            when: file_exists is succeeded
      

      Save and close the file when you’re done.

      Then, run ansible-playbook with the same connection arguments from the previous examples. Here, we’re using an inventory file named inventory and a user named sammy, but you should change these values accordingly:

      • ansible-playbook -i inventory playbook-05.yml -u sammy

      The first time you run this playbook, the command will fail because the file doesn’t exist in that path. The task that creates the file will then be executed, while the last task will be skipped:

      Output

      ... TASK [Check if file already exists] ********************************************************************* fatal: [203.0.113.10]: FAILED! => {"changed": true, "cmd": ["ls", "/home/sammy/myfile"], "delta": "0:00:00.004258", "end": "2020-10-22 13:10:12.680074", "msg": "non-zero return code", "rc": 2, "start": "2020-10-22 13:10:12.675816", "stderr": "ls: cannot access '/home/sammy/myfile': No such file or directory", "stderr_lines": ["ls: cannot access '/home/sammy/myfile': No such file or directory"], "stdout": "", "stdout_lines": []} ...ignoring TASK [create file for user] ***************************************************************************** changed: [203.0.113.10] TASK [show message if file exists] ********************************************************************** skipping: [203.0.113.10] ...

      From the output, you can see that the create file for user task caused a change in the server, which means the file was created. Now, run the playbook again and you’ll get a different result:

      • ansible-playbook -i inventory playbook-05.yml -u sammy

      Output

      ... TASK [Check if file already exists] ********************************************************************* changed: [203.0.113.10] TASK [create file for user] ***************************************************************************** skipping: [203.0.113.10] TASK [show message if file exists] ********************************************************************** ok: [203.0.113.10] => { "msg": "The user file already exists." } ...

      If you’d like to learn more about using conditionals in Ansible playbooks, please refer to the official documentation.



      Source link