Ansible - Common Tasks
On this page we are going to be covering common Ansible tasks. These are going to include normal every day Ansible use cases that have already been implemented over and over by many different people. The purpose of this page will be to help prevent you from re-inventing the wheel. It should also give you a boost or head start automating configurations, deployments, and common tasks.
Better descripion:
- Common useful modules with examples
“Modules should be idempotent, that is, running a module multiple times in a sequence should have the same effect as running it just once.”
Ping
- This module just verifies connectivity.
- This is not an ICMP ping but it actually conects over SSH and runs a module.
- hosts: webservers
remote_user: root
tasks:
- name: test connection
ping:
remote_user: yourname
Command
- This module allows you to run a command on a remote host.
- Specify a command and list of args.
- It doesn’t use env vars and doesn’t work with operations like redirects and pipes. ( see shell for those things )
tasks:
- name: enable selinux
command: /sbin/setenforce 1
Shell
- This module runs a command using an actual shell
- Redirects, pipes, etc. should work here.
- Exit codes matter.
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand || /bin/true
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand
ignore_errors: True
Script
- Copies script to remote host and executes it.
- Passed through shell environment on remote host.
- Doesn’t need Python on the remote host
- name: Run a script with arguments (free form)
script: script1.sh -a 1234
- name: Run a script with arguments (using 'cmd' parameter)
script:
cmd: /opt/app1/script1.sh -a 1234
Raw
- Runs a command over SSH
- Doesn’t use the module subsystem
- Great for installing Python if it is missing ( which Ansible needs for most other tasks )
- name: Install Python on RHEL / Fedora
ansible.builtin.raw: dnf install -y python3
- name: Install Python on Ubuntu / Debian
ansible.builtin.raw: apt install -y python3
- name: Run a command that uses non-posix shell-isms (in this example /bin/sh doesn't handle redirection and wildcards together but bash does)
ansible.builtin.raw: cat < /tmp/*txt
args:
executable: /bin/bash
File
- Create, remove, change attributes
- Files, dirs, links
Make sure file exists and has these permissions / ownership:
- name: Change file ownership, group and permissions
ansible.builtin.file:
path: /etc/foo.conf
owner: foo
group: foo
mode: '0644'
More permissions, recursive:
- name: Touch the same file, but add/remove some permissions
ansible.builtin.file:
path: /data/set1
state: directory
recurse: yes
mode: u+rw,g-wx,o-rwx
Create dir:
- name: Create a directory if it does not exist
ansible.builtin.file:
path: /etc/some_directory
state: directory
mode: '0755'
Create a symlink:
- name: Create a symbolic link
ansible.builtin.file:
src: /file/to/link/to
dest: /path/to/symlink
state: link
Remove a file:
- name: Remove file (delete file)
ansible.builtin.file:
path: /etc/foo.txt
state: absent
Copy
- Copy files to a remote machine.
- name: Copy ansible inventory file to client
copy:
src=/etc/ansible/hosts
dest=/etc/ansible/hosts
owner=root
group=root
mode=0644
Synchronize
- This is basically a wrapper around rsync.
Setting this option may fix some stange issues but don’t set this if not needed:
betsy eo smith
compress: false
Sync from control host to remote host:
- name: Synchronization of src on the control machine to dest on the remote hosts
ansible.posix.synchronize:
src: some/relative/path
dest: /some/absolute/path
Pull down instead of pushing:
- name: Sync - Pull
ansible.posix.synchronize:
src: some/relative/path
dest: /some/absolute/path
mode: pull
Delegate to another host:
- name: Sync - Pull
ansible.posix.synchronize:
src: some/relative/path
dest: /some/absolute/path
mode: pull
delegate_to: delegate.host
Replace
- Replace all instances of a pattern in a file.
backup: true | make a dated backup of file |
before: “regex” | only replace lines before this |
after: “regex” | only replace lines after this |
regexp: “regex” | replace matching lines |
replace: “string” | string to replace with |
- name: Replace old hostname with new hostname (requires Ansible >= 2.4)
ansible.builtin.replace:
path: /etc/hosts
regexp: '(\s+)old\.host\.name(\s+.*)?$'
replace: '\1new.host.name\2'
- name: Replace between the expressions (requires Ansible >= 2.4)
ansible.builtin.replace:
path: /etc/hosts
after: '(?m)^<VirtualHost [*]>'
before: '</VirtualHost>'
regexp: '^(.+)$'
replace: '# \1'
Lineinfile
- Ensure that a line is in a file or replace a line in a file.
- Line is placed at the end of file by default unless matching insertafter/insertbefore/regex.
- regexp/search_string fall back to insertafter/insertbefore if no match
- NOTE - When replacing, make sure the modified line still matches for consistent behavior on subsequent runs.
backup: true | make a dated backup of file |
insertafter: “regex” | insert after last line that matches this |
insertbefore “regex” | insert before last line that matches this |
firstmatch: true | modify insertafter/insertbefore to match first line |
regexp: “regex” | replace last line matched, or remove if “state: absent” ( use regex ) |
search_string: “string” | replace last line matched, or remove if “state: absent” ( use literal ) |
line: “string” | the actual string we want |
state: absent | remove line instead, default is present, |
- name: Ensure SELinux is set to enforcing mode
ansible.builtin.lineinfile:
path: /etc/selinux/config
regexp: '^SELINUX='
line: SELINUX=enforcing
- name: Make sure group wheel is not in the sudoers configuration
ansible.builtin.lineinfile:
path: /etc/sudoers
state: absent
regexp: '^%wheel'
- name: Ensure the default Apache port is 8080
ansible.builtin.lineinfile:
path: /etc/httpd/conf/httpd.conf
regexp: '^Listen '
insertafter: '^#Listen '
line: Listen 8080
Blockinfile
- Insert/update/remove multiline text block with customizable marker lines
backup: true | make a dated backup of file |
insertafter: “regex” | insert after last line that matches this ( if no markers are found ) |
insertbefore “regex” | insert before last line that matches this ( if no markers are found ) |
block: “some text “ | the acctual block of text |
marker_begin: “BEGIN my section” | mark begin of block |
marker_end: “section END” | mark end of block |
mark: “# {mark} MY MANAGED BLOCK” | marker line template |
- name: Insert/Update "Match User" configuration block in /etc/ssh/sshd_config prepending and appending a new line
ansible.builtin.blockinfile:
path: /etc/ssh/sshd_config
append_newline: true
prepend_newline: true
block: |
Match User ansible-agent
PasswordAuthentication no
- name: Insert/Update eth0 configuration stanza in /etc/network/interfaces
(it might be better to copy files into /etc/network/interfaces.d/)
ansible.builtin.blockinfile:
path: /etc/network/interfaces
block: |
iface eth0 inet static
address 192.0.2.23
netmask 255.255.255.0
- name: Add mappings to /etc/hosts
ansible.builtin.blockinfile:
path: /etc/hosts
block: |
{{ item.ip }} {{ item.name }}
marker: "# {mark} ANSIBLE MANAGED BLOCK {{ item.name }}"
loop:
- { name: host1, ip: 10.10.1.10 }
- { name: host2, ip: 10.10.1.11 }
- { name: host3, ip: 10.10.1.12 }
Manage Packages with Apt ( Ubuntu / Debian )
- “state: latest” is optional but will cause it to be updated.
Install and remove package:
- name: Update repo cache and install nginx package
ansible.builtin.apt:
name: nginx
update_cache: yes
- name: Remove nginx package
ansible.builtin.apt:
name: nginx
state: absent
Manage Packages with DNF ( RHEL / CentOS / Fedora )
- “state: latest” is optional but will cause it to be updated.
Install and remove package:
- name: Install nginx package
ansible.builtin.dnf:
name: nginx
- name: Remove the nginx package
ansible.builtin.dnf:
name: nginx
state: absent
Manage Packages with Pacman ( Arch )
- Should be included with ansible but not ansible.core by default.
Install and remove package:
- name: Install package nginx
community.general.pacman:
name: nginx
- name: Install package nginx
community.general.pacman:
name: nginx
state: absent
Manage Packages with Zypper ( Suse )
- Should be included with ansible but not ansible.core by default.
Install and remove package:
- name: Install nginx
community.general.zypper:
name: nginx
- name: Install nginx
community.general.zypper:
name: nginx
state: absent
systemd Services
- Control systemd services and other units
Everything on:
- name: Make sure a service is started, enabled, and not masked
ansible.builtin.systemd_service:
state: started
name: nginx
enabled: true
masked: no
Everything off:
- name: Make sure a service is stopped, disabled, and masked
ansible.builtin.systemd_service:
state: stopped
name: nginx
enabled: false
masked: yes
Bounce:
- name: Bounce
ansible.builtin.systemd_service:
state: restarted
name: nginx
Reload:
- name: Reload
ansible.builtin.systemd_service:
state: reloaded
name: nginx
Manage User Accounts
groups | specify groups to be a member of |
append: yes | append groups instead of just creating |
state:absent | remove a user |
remove: yes | remove directories when removing a user |
update_password: on_create | only update password on initial creation ( default is always ) |
passwrod: “!” | specify a password hash, “!” to disable |
Create a user with defaults:
- name: Create a user
ansible.builtin.user:
name: jsmith
Specify hash:
- name: Create a user
ansible.builtin.user:
name: jsmith
password: {{ 'mypassword' | password_hash('sha512', 'mysecretsalt') }}
Create a user with multiple different options:
- name: Create a user
ansible.builtin.user:
name: jsmith
uid: 1040
groups: admins,developers
append: yes
shell: /bin/zsh
generate_ssh_key: yes
ssh_key_bits: 2048
ssh_key_file: .ssh/id_rsa
Remove user:
- name: Remove a user
ansible.builtin.user:
name: jsmith
state: absent
remove: yes
Examples specifying a password:
password: "!"
password: "$6$AQE675JFQhjtR8TD$Kb02EVmU56M3gcydDFkU6crdjtjksoswp8MOLWpyWX5ovlK4qkge69vjRzFpAhKp4rTLV4YsyqOfCmCy7jcom0"
password: {{ 'mypassword' | password_hash('sha512', 'mysecretsalt') }}
Generate a password hash on Linux:
mkpasswd --method=sha-512
Groups
Manage groups like this:
- name: Ensure group "somegroup" exists
ansible.builtin.group:
name: somegroup
state: present
- name: Ensure group "docker" exists with correct gid
ansible.builtin.group:
name: docker
state: present
gid: 1750
SSH Keys
Managing up SSH keys is easy:
- name: Set authorized key taken from file
ansible.posix.authorized_key:
user: charlie
state: present
key: "{{ lookup('file', '/home/charlie/.ssh/id_rsa.pub') }}"
Cron Jobs
Cron jobs can be managed like this:
- name: Ensure a job that runs at 2 and 5 exists. Creates an entry like "0 5,2 * * ls -alh > /dev/null"
ansible.builtin.cron:
name: "check dirs"
minute: "0"
hour: "5,2"
job: "ls -alh > /dev/null"
- name: 'Ensure an old job is no longer present. Removes any job that is prefixed by "#Ansible: an old job" from the crontab'
ansible.builtin.cron:
name: "an old job"
state: absent