
This article covers basics of ansible based automation
- File structure
- Inventory preparation
- Securing credentials
- Example playbooks to test
Structure
- Simple ansible based automation have a inventory file and example playbooks. In this document we will prepare both in YAML format.
- Extended variables can also be stored outside main inventory file and these variable files are placed inside “group_vars” and “host_vars” directory.
- “group_vars” contains variables common to all hosts.
- “host_vars” contains variables specific to a host. For eg, if some hosts are using different ssh creds, then these can be defined in host specific file inside “host_vars” dir.
- Confidential information such as user/password, keys etc are prepared and stored in encrypted form using ansible vault.
For the test/demo setup following structure is prepared
tree ansible-works/
ansible-works/
├── backup <- unused
├── group_vars
│ └── all
│ └── creds.vault.yaml <- contains encrypted ssh username/password
├── homecreds.yml <- unused
├── inventory.yaml <- Inventory file
├── listfiles.yaml <- playbook to list files in /tmp
└── checkhosts.yaml <- playbook to check connection
Inventory preparation
Let us see details of following inventory file:
cat inventory.yaml
home_hosts:
hosts:
berry_nw_101:
ansible_host: 192.168.101.200
berry_nw_1:
ansible_host: 192.168.1.200
berry_localhost:
ansible_host: 127.0.0.1
vars:
ansible_ssh_common_args: '-o StrictHostKeyChecking=no'
ansible_user: "{{ ssh_username }}"
ansible_password: "{{ ssh_password }}"
“home_hosts” is just a host group name to bundle set of hosts. You can have multiple groups. For eng say “datacentre1-hosts”, “datacentre2-hosts”
“hosts” is a keyword and is used to define host you want to connect and run commands on. Each host entity shall have a logical name, say its hostname, for eg “berry_nw_101.
“ansible_host” is again a keyword and holds IPaddress or DNS name of device/server/host machine.
“vars” is also a keyword and holds varibles you want to define directory or as template. For eg in above eg, “ansible_ssh_common_args” is defined to skip host finger print verification, “ansible_user”, is a keyword, and shall pick value from “ssh_username” macro defined in “creds.vault.yaml” inside “group_vars” directory. Same for “ansible_password”.
Securing credentials
To avoid exposing sensitive information like ssh user/pass, we are using ansible vault to encrypt user/password file using a passowrd.
Create valut file:
ansible-vault create group_vars/all/creds1.vault.yaml
New Vault password:
Confirm New Vault password:
Add username password macro variables defined in inventory file (ssh_username, ssh_password in this case):
ssh_username: testuser
ssh_password: somepass
Save it. You can edit it in future using “ansible-vault edit <filename>” command.
Content is vault file are stored encrypted:
cat group_vars/all/creds.vault.yaml
$ANSIBLE_VAULT;1.1;AES256
34666663353465313337386361613566613436313738343935646462303038353436396132323631
3462616436623531346465373531373833646363356234370a663164336630346234343364343538
32616637376436353830373739653966336632393637303830313963373162636661326139666662
3564336265376562310a356631346562633239323664613461333536613031333966396637663337
31326666656239316265303963316633306365313364633036393837323335363766323134396537
3036393232383035343735336130343439306162303937616539
At this point you can verify inventory file using following command:
ansible-inventory -i inventory.yaml --list --ask-vault-pass
Enter vault password to decrypt vault
Vault password:
{
"_meta": {
"hostvars": {
"berry_localhost": {
"ansible_host": "127.0.0.1",
"ansible_password": "{{ ssh_password }}",
"ansible_ssh_common_args": "-o StrictHostKeyChecking=no",
"ansible_user": "{{ ssh_username }}",
"ssh_password": "somepass",
"ssh_username": "testuser"
},
"berry_nw_1": {
"ansible_host": "192.168.1.200",
"ansible_password": "{{ ssh_password }}",
"ansible_ssh_common_args": "-o StrictHostKeyChecking=no",
"ansible_user": "{{ ssh_username }}",
"ssh_password": "somepass",
"ssh_username": "testuser"
},
"berry_nw_101": {
"ansible_host": "192.168.101.200",
"ansible_password": "{{ ssh_password }}",
"ansible_ssh_common_args": "-o StrictHostKeyChecking=no",
"ansible_user": "{{ ssh_username }}",
"ssh_password": "somepass",
"ssh_username": "testuser"
}
},
"profile": "inventory_legacy"
},
"all": {
"children": [
"ungrouped",
"home_hosts"
]
},
"home_hosts": {
"hosts": [
"berry_nw_101",
"berry_nw_1",
"berry_localhost"
]
}
}
Example playbooks to test
Check ssh connection to hosts
This playbook uses ansible.builtin.ping ansible module. Remember this is not ICMP ping.
cat checkhosts.yaml
- name: Check connections
hosts: home_hosts
tasks:
- name: Ping lab hosts
ansible.builtin.ping:
- name: Print message
ansible.builtin.debug:
msg: Test connection
This playbook shall check ssh connection to hosts using credentials defined in creds.vault.yaml file
ansible-playbook -i inventory.yaml checkhosts.yaml --ask-vault-pass
Enter vault password
Vault password:
PLAY [Check connections] ********************************************************************************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************************************************************************************
[WARNING]: Host 'berry_localhost' is using the discovered Python interpreter at '/usr/bin/python3.13', but future installation of another Python interpreter could cause a different interpreter to be discovered. See https://docs.ansible.com/ansible-core/devel/reference_appendices/interpreter_discovery.html for more information.
ok: [berry_localhost]
[WARNING]: Host 'berry_nw_101' is using the discovered Python interpreter at '/usr/bin/python3.13', but future installation of another Python interpreter could cause a different interpreter to be discovered. See https://docs.ansible.com/ansible-core/devel/reference_appendices/interpreter_discovery.html for more information.
ok: [berry_nw_101]
[ERROR]: Task failed: Failed to connect to the host via ssh: ssh: connect to host 192.168.1.200 port 22: Connection timed out
fatal: [berry_nw_1]: UNREACHABLE! => {"changed": false, "msg": "Task failed: Failed to connect to the host via ssh: ssh: connect to host 192.168.1.200 port 22: Connection timed out", "unreachable": true}
TASK [Ping lab hosts] ***********************************************************************************************************************************************************************
ok: [berry_nw_101]
ok: [berry_localhost]
TASK [Print message] ************************************************************************************************************************************************************************
ok: [berry_nw_101] => {
"msg": "Test connection"
}
ok: [berry_localhost] => {
"msg": "Test connection"
}
PLAY RECAP **********************************************************************************************************************************************************************************
berry_localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
berry_nw_1 : ok=0 changed=0 unreachable=1 failed=0 skipped=0 rescued=0 ignored=0
berry_nw_101 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Here of three, two hosts are working. One host is dead at the time of test.
List files in /tmp of host machines
cat listfiles.yaml
Here “directory” is a variable with “/tmp” value and playbook uses OS “ls” command to list files.
- name: Home Play
hosts: home_hosts
vars:
directory: /tmp
tasks:
- command: "ls {{directory}}"
register: dir_out
- debug: var={{item}}
with_items: dir_out.stdout_lines
Run it to test
ansible-playbook -i inventory.yaml listfiles.yaml --ask-vault-pass
Enter Vault password
Vault password:
PLAY [Home Play] ****************************************************************************************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************************************************************************************
[WARNING]: Host 'berry_nw_101' is using the discovered Python interpreter at '/usr/bin/python3.13', but future installation of another Python interpreter could cause a different interpreter to be discovered. See https://docs.ansible.com/ansible-core/devel/reference_appendices/interpreter_discovery.html for more information.
ok: [berry_nw_101]
[WARNING]: Host 'berry_localhost' is using the discovered Python interpreter at '/usr/bin/python3.13', but future installation of another Python interpreter could cause a different interpreter to be discovered. See https://docs.ansible.com/ansible-core/devel/reference_appendices/interpreter_discovery.html for more information.
ok: [berry_localhost]
[ERROR]: Task failed: Failed to connect to the host via ssh: ssh: connect to host 192.168.1.200 port 22: Connection timed out
fatal: [berry_nw_1]: UNREACHABLE! => {"changed": false, "msg": "Task failed: Failed to connect to the host via ssh: ssh: connect to host 192.168.1.200 port 22: Connection timed out", "unreachable": true}
TASK [command] ******************************************************************************************************************************************************************************
changed: [berry_nw_101]
changed: [berry_localhost]
TASK [debug] ********************************************************************************************************************************************************************************
ok: [berry_nw_101] => (item=dir_out.stdout_lines) => {
"dir_out.stdout_lines": [
"checklist.txt",
"piperun",
"fluent",
"td-lock-202ssssw2b",
"SERVERENGINE_SOCKETMANAGER_2025-08-27T03:04:54Z_2451",
"test.txt"
],
"item": "dir_out.stdout_lines"
}
ok: [berry_localhost] => (item=dir_out.stdout_lines) => {
"dir_out.stdout_lines": [
"global.txt",
"apache.logs",
"fluentd-lock-20250827-2451-rhfw2b",
"somedata"
],
"item": "dir_out.stdout_lines"
}
PLAY RECAP **********************************************************************************************************************************************************************************
berry_localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
berry_nw_1 : ok=0 changed=0 unreachable=1 failed=0 skipped=0 rescued=0 ignored=0
berry_nw_101 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Here of 3, on two hosts “ls /tmp” got executed and out is recorded.
You can write more complex automations using ansible framework with nested playbooks using roles/tasks/templates.