We used Ansible to manage users on before, today we'll use Ansible for something more daily, which is update packages on the system, if you are using OpenBSD current this can be very useful for you.
1. a OpenBSD server.
2. Ansible installed on your machine ($ doas pkg_add ansible).
3. Python installed on the OpenBSD server (at this time the Python version is 3.13, $ doas pkg_add python).
If you didn't kept yours from the other article, the inventory file is typically named `hosts` and it lists the servers that Ansible will manage plus the ansible_python_interpreter plus many other fun things:
$ cat hosts
[current:vars]
ansible_python_interpreter=/usr/local/bin/python3.13
[release:vars]
ansible_python_interpreter=/usr/local/bin/python3.12
[current]
ports
nextcloud
apu01
rock64
[release]
serv00
dns01
In this file:
- [current:vars] : This section sets variables for the `current` group.
- ansible_python_interpreter=/usr/local/bin/python3.13 : This specifies where Python is located on the OpenBSD server.
- [current]/[release] : This section lists the IP addresses of the servers in the `current` and `release` group. If you have a proper entry on your ssh_config(5) you can just use that hostname since Ansible will connect to it over ssh.
The playbook Ansible playbook that will create the user:
$ cat update_pkgs.yml
---
- name: OpenBSD package update + cleanup
hosts: current
become: true
become_method: doas # Uses doas to become root
tasks:
- name: Update all packages
community.general.openbsd_pkg:
name: '*'
state: latest
register: update_result # Saves the module's result so we can read its .msg later
- name: Clean up orphaned packages
command: pkg_delete -a
register: cleanup_result
changed_when: "'No packages to delete' not in cleanup_result.stdout"
# ↑ Prevents Ansible from marking the task as "changed" every time when
# pkg_delete -a finds nothing to remove (makes output much cleaner)
- name: Show update summary
debug:
msg: "{{ update_result.msg | default('No changes or no output') }}"
# ↑ Uses .msg from the openbsd_pkg module if it exists,
# otherwise shows a friendly fallback message instead of empty output
- name: Show cleanup summary
debug:
msg: "{{ cleanup_result.stdout | default('No packages removed') }}"
# ↑ Shows whatever pkg_delete printed, or a message if nothing happened
If you don’t want to give the user running Ansible passwordless access via doas(8) (for example, by adding a permit nopass rule in /etc/doas.conf), and you’d rather use your regular user password, Ansible Vault (or see the here) will do the trick. It lets you encrypt the become password so it’s never stored in plain text in your playbooks.
To run the playbook, we use the following:
$ ansible-playbook -i hosts update_pkgs.yml
PLAY [OpenBSD package update + cleanup] *****************************************************
TASK [Gathering Facts] **********************************************************************
ok: [ports]
ok: [nextcloud]
ok: [apu01]
ok: [rock64]
TASK [Update all packages] ******************************************************************
changed: [ports]
changed: [nextcloud]
changed: [apu01]
changed: [rock64]
TASK [Clean up orphaned packages] ***********************************************************
changed: [ports]
changed: [nextcloud]
changed: [apu01]
changed: [rock64]
TASK [Show update summary] ******************************************************************
ok: [ports] => {
"msg": "No changes or no output"
}
ok: [nextcloud] => {
"msg": "No changes or no output"
}
ok: [apu01] => {
"msg": "No changes or no output"
}
ok: [rock64] => {
"msg": "No changes or no output"
}
TASK [Show cleanup summary] ****************************************************************
ok: [ports] => {
"msg": ""
}
ok: [nextcloud] => {
"msg": ""
}
ok: [apu01] => {
"msg": ""
}
ok: [rock64] => {
"msg": ""
}
PLAY RECAP *********************************************************************************
ports : ok=5 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
nextcloud : ok=5 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
apu01 : ok=5 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
rock64 : ok=5 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Life is too short to upgrade all the packages by hand so using Ansible to manage it can be very useful and easy once you do all the effort writing down the playbook. You can add syspatch(8) also to the playbook if you are using -release.