When managing remote systems with Ansible, tasks are generally executed on target hosts over SSH. However, there are scenarios where you might want to execute certain tasks on the local machine (the control node) instead of the remote hosts. Ansible provides built-in mechanisms for delegating tasks to the local host or other specific hosts while running playbooks remotely.
This approach can be useful in many situations, including:
- Managing files or processes that are only available on the control node.
- Executing local scripts or tools that need to interact with remote hosts.
- Handling configuration or orchestration steps that require local control before dispatching remote tasks.
Key Concepts: delegate_to and local_action
There are two main ways to delegate tasks in Ansible to the local host:
delegate_to: This directive allows you to specify the host on which a task should run. To run a task on the control node, you setdelegate_to: localhost.local_action: This is a shorthand that allows you to directly execute a task locally. It is often more convenient for one-liner commands.
Example: Using delegate_to for Local Execution
Here’s a basic playbook example demonstrating the use of delegate_to to run a task on the control node while managing remote hosts over SSH.
---
- name: Manage remote and local tasks
hosts: all
tasks:
- name: Perform a task on remote hosts
ansible.builtin.shell: echo "This runs on {{ inventory_hostname }}"
- name: Perform a local task
ansible.builtin.shell: echo "This runs on the control node"
delegate_to: localhost
In this playbook:
- The first task runs on all remote hosts as usual.
- The second task, however, is delegated to
localhost, which is the machine running the Ansible playbook (the control node).
Example: Using local_action for Local Execution
The local_action is often used as a shorthand for running a task locally. The following example shows how you can use local_action to achieve the same effect.
---
- name: Manage remote and local tasks with local_action
hosts: all
tasks:
- name: Perform a task on remote hosts
ansible.builtin.shell: echo "This runs on {{ inventory_hostname }}"
- name: Perform a local task with local_action
local_action: ansible.builtin.shell echo "This runs on the control node"
Both delegate_to: localhost and local_action serve the same purpose, but local_action can be more concise for simple tasks.
Real-World Use Case: Copying Files Locally and Remotely
One common use case is when you need to fetch files from remote hosts to the local machine, process them, and then distribute the processed files back to the remote machines.
Here’s a more complex example where a file is fetched from a remote server, processed locally, and then copied back to the remote server:
---
- name: Fetch, process, and return file
hosts: all
tasks:
- name: Fetch a file from the remote host
ansible.builtin.fetch:
src: /etc/config.conf
dest: /tmp/config-{{ inventory_hostname }}.conf
flat: yes
- name: Process the file locally
ansible.builtin.shell: |
sed -i 's/OPTION=oldvalue/OPTION=newvalue/' /tmp/config-{{ inventory_hostname }}.conf
delegate_to: localhost
- name: Copy the modified file back to the remote host
ansible.builtin.copy:
src: /tmp/config-{{ inventory_hostname }}.conf
dest: /etc/config.conf
In this playbook:
- Files from each remote host are fetched to the control node.
- The file is modified locally using
sedto replace configuration values. - The updated file is then copied back to each respective remote host.
Conclusion
Delegating tasks to the local machine during remote execution in Ansible allows for flexible playbook design, especially when dealing with files or processes that must interact with the control node. By using the delegate_to directive or local_action, you can achieve granular control over where tasks are executed, ensuring that your infrastructure management tasks are both efficient and powerful.