How to do fast, repeatable Linux installations #3 — Ansible
In previous articles about my use of automation in performing post-install tasks for new Linux installations, I discussed my progression from no automation at all but at least using written notes for consistency, to simple scripts, to using RPM packages to install tools from the Fedora repositories and my own scripts and files. Those approaches worked well for the times I used them, but as the requirements of my network and the hosts connected to it grew and became more complex, the capabilities of those tools couldn’t keep up.
I needed a new method for doing post-install tasks. I also needed new ways to perform other tasks, too. So as a series of experiments, I started working with Ansible to first familiarize myself with it and then to perform more complex tasks such as Fedora updates and my post-install tasks.
The three articles in the list below describe my progression with using Ansible for tasks ranging from simple to a bit more complex. Please read those whether you’re familiar with Ansible or not so you can understand how I employ it in my home lab setting. They’re also a good learning tool if you’re not already familiar with Ansible.
- Ansible #1: My first day using Ansible
- Ansible #2 How to create an Ansible Playbook
- Ansible #3: Finishing our Ansible playbook to manage workstation and server updates
How Ansible works — the short version
The key to using Ansible is in the way it works. The function of Ansible is to ensure that a Linux1 host is maintained in a certain state. That means that if the Ansible playbook defines certain RPMs and local files as being present or not present, particular text lines to be changed from the default in a configuration file, specific systemd services to be on or off, and much more, running the playbook will always set the system to the desired state.
This statefull approach to system configuration makes it possible to run the playbook at a later time, after undesired or temporary changes have been made to the system, to achieve the defined state. I’ve had many situations in which I’ve made changes to a system as part of my process or problem determination, or as the result of some experiments I performed to determine whether I wanted to make some configuration changes on a permanent basis. While making those changes, I don’t need to worry about making notes so I can get the host back to the state I want for those things that matter to me.
Preparation
For my experiments, I use my personal workstation as the Ansible hub and the VM as the target host. I also take a snapshot of the VM immediately after the new installation and setting up the PPKP. That makes it easy to restore the VM to a pristine condition before performing additional experiments.
First login to the target VM and enable SSH. Ensure that root can perform a remote login via SSH. If the host being used as the Ansible hub doesn’t already have a PPKP created, do that now and then copy the public key to the target. The article, How I use Public/Private/KeyPairs with SSH, will show you how to do both of those tasks.
The Playbook
Warning!!! — Don’t use this Ansible playbook on a production system until you know exactly what it does and have modified it to meet your own needs. This article and the playbook that goes with it are intended as a tool to demonstrate what can be done with Ansible to perform post-installation tasks. I strongly recommend that you experiment with this tool on a non-production virtual machine.
Now let’s look at how I used Ansible to perform post-install tasks. This is best done with the playbook itself, PostInstall.yml, starting in Figure 1. This is a very long listing of my Postinstall.yml playbook. A simple explanation of what it does begins at the end of Figure 1.
################################################################################
# PostInstall.yml #
# #
# This Ansible playbook performs post-installation updates and configuration #
# for newly installed Fedora hosts. #
# #
# Note: This playbook is intended for use only on one or more newly installed #
# hosts. It is not intended for use with hosts that have been in use #
# for a considerable period of time after installation. But it might #
# work fine for that with most of my personal hosts. #
# #
# #
#------------------------------------------------------------------------------#
# #
# Change History #
# Date Name Version Description #
# 2020/10/01 David Both 00.00 Started new code #
<SNIP>
# 2023/08/13 David Both 01.50 Add code to convert to NetworkManager for #
# resolv.conf to use nss-DNS and disable #
# mDNS. #
# 2023/09/22 David Both 01.51 Add sipcalc to cli tools. #
# 2023/09/22 David Both 01.52 Remove install of deltarpm. #
# 2024/06/23 David Both 01.53 Install fastfetch. #
# #
################################################################################
---
- name: Post-installation updates, package installation, and configuration
hosts: testvm1
vars:
# Set this to false to prevent rebooting after installation of updates
# and after the entire procedure has completed.
# However setting this to false is not recommended.
Reboot: "true"
# When set to True the Gui variable allows install of some GUI tools,
# wallpapers, and themes.
Gui: "true"
# When set to True, the Apps variable tells Ansible to install applications like
# LibreOffice and more.
Apps: "true"
# When set to True, install a large number of background pics.
# Takes a long time and space so default is false.
Wallpapers: "true"
# Performs tasks for my own hosts when set to true. Skips those when set to false
# for when I work on computers that are not my own. Default is true for
# my own stuff.
David: "true"
# Install development tools for a primary workstation
development: "false"
# When false, this variable removes dnfdragora from the host because it used
# to suck and did not work. I don't like it on my stuff so delete it which
# allows me to remove it from my systems. The default is false.
dnfdragora: "false"
# When true install glances
glances: "false"
# When true, install the designated desktops
xfce: "true"
cinnamon: "false"
# Problems installing LXDE due to conficts
lxde: "false"
# Problems installing Mate due to conficts
mate: "false"
tasks:
################################################################################
################################################################################
# Start with some kernel and system level configuration. #
################################################################################
################################################################################
# Configure maximum number of kernels to keep, install some local scripts that #
# we will use to do updates, and then install updates. #
# The default number of kernels is three and we change it to 5. #
################################################################################
- name: Set installonly_limit to 5. Allows saving up to 5 old kernels.
replace:
path: /etc/dnf/dnf.conf
regexp: 'installonly_limit=.*'
replace: 'installonly_limit=5'
- name: Remove possible old deprecated scripts
file:
path: "{{ item }}"
state: absent
with_items:
- /home/dboth/development/doUpdates
- /usr/local/bin/doUpdates
- /home/dboth/development/updatePrep.sh
- /usr/local/bin/updatePrep.sh
- name: Install local scripts
copy:
src: "{{ item }}"
dest: /usr/local/bin
mode: 0774
owner: root
group: root
with_fileglob:
- /home/dboth/development/ansible/PostInstall/files/usrlocal/bin/*
################################################################################
# Disable mDNS and configure nss-DNS instead. #
################################################################################
################################################################################
# Stop and disable AVAHI services that are not needed. Masked means that it #
# cannot be restarted until it is unmasked. This is mDNS #
################################################################################
- name: Stop and disable the Avahi service
systemd:
name: avahi-daemon.service
state: stopped
masked: yes
enabled: no
- name: Stop and disable the Avahi socket
systemd:
name: avahi-daemon.socket
state: stopped
masked: yes
enabled: no
# Disable the systemd resolver.
- name: Stop and disable the systemd resolver
systemd:
name: systemd-resolved.service
state: stopped
masked: no
enabled: no
# Delete /etc/resolv.conf link
- name: Remove old resolv.conf link
ansible.builtin.file:
path: /etc/resolv.conf
state: absent
# Restart NetworkManager which creates a new resolv.conf link every time
# it is started.
- name: Restart NetworkManager to create the new resolv.conf link.
systemd:
name: NetworkManager
state: restarted
enabled: yes
################################################################################
# Disable pcscd smart card daemons #
################################################################################
# Disable the smart card socket
- name: Stop and disable the pcscd smart card socket
systemd:
name: pcscd.socket
state: stopped
masked: no
enabled: no
# Disable the smart card service
- name: Stop and disable the pcscd smart card service
systemd:
name: pcscd.service
state: stopped
masked: no
enabled: no
################################################################################
################################################################################
# Install some files to standardize all kernel options (kernelopts) into #
# one place -- the /etc/sysctl.d directory. And a single file in the #
# directory local-sysctl.conf. #
################################################################################
################################################################################
- name: Install local-sysctl.conf
copy:
src: /home/dboth/development/ansible/BasicTools/files/local-sysctl.conf
dest: /etc/sysctl.d/local-sysctl.conf
mode: 644
owner: root
group: root
- name: Install latest MyStartup.sh
copy:
src: /home/dboth/development/ansible/BasicTools/files/MyStartup.sh
dest: /usr/local/bin/MyStartup.sh
mode: 754
owner: root
group: root
- name: Create directory /usr/local/lib/systemd/system/ which does not exist by default
ansible.builtin.file:
path: /usr/local/lib/systemd/system/
state: directory
mode: '0755'
owner: root
group: root
- name: Install latest MyStartup.service
copy:
src: /home/dboth/development/ansible/BasicTools/files/MyStartup.service
dest: /usr/local/lib/systemd/system/MyStartup.service
mode: 754
owner: root
group: root
- name: Enable and start MyStartup.service
service:
name: MyStartup.service
state: started
enabled: yes
################################################################################
# This lets us know if we need to reboot after installing updates. We probaly #
# will need to in most cases. #
################################################################################
- name: Check for currently available updates
command: doUpdates.sh -c
register: check
- debug: var=check.stdout_lines
################################################################################
# Now install all available updates. #
################################################################################
- name: Install all current updates
dnf:
name: "*"
state: latest
################################################################################
# This will reboot and then wait for the remote host to complete its #
# restart before proceeding with the rest of the tasks #
################################################################################
- name: Reboot if necessary and reboot extra variable is true
reboot:
when: (check.stdout | regex_search('reboot will be required')) and Reboot == "true"
################################################################################
# Install some additional repositories #
################################################################################
- name: Install and enable the RPM Fusion Free and nonfree repositories
dnf:
name: "{{ item }}"
state: present
# This is necessary to prevent a GPG error (version 32-1 - where did -1 come from?)
disable_gpg_check: yes
with_items:
- http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-{{ ansible_distribution_version }}.noarch.rpm
- http://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-{{ ansible_distribution_version }}.noarch.rpm
################################################################################
# Install a bunch of tools and other packages. Install them all here with a #
# bit of grouping to make things a bit easier to find. #
################################################################################
# Install command line tools
- name: Install command line tools
dnf:
name:
- apcupsd
- atop
- bc
- clamav
- python3-cpuinfo
- ddrescue
- detox
- dictd
- dmidecode
- fail2ban
- hddtemp
- htop
- hwinfo
- iftop
- inxi
- iotop
- konsole
- iptables-services
- iptraf-ng
- lm_sensors
- logwatch
- lshw
- mc
- fastfetch
- newfetch
- nmon
- nvme-cli
- plocate
- powertop
- psutils
- rpmorphan
- screen
- screenfetch
- sendmail
- sendmail-cf
- ShellCheck
- sipcalc
- sysstat
- task
- trash-cli
- units
- util-linux-user
- vim-common
- vim-enhanced
- vim-filesystem
- vim-minimal
- wget
- whois
state: latest
- name: Install some fun command line programs
dnf:
name:
- asciiquarium
- banner
- boxes
- bsd-games
- cmatrix
- cowsay
- figlet
- fortune-mod
- sl
state: latest
################################################################################
# Install development tools required for Python pip and VirtualBox as well as #
# for development and creating RPM packages. #
################################################################################
- name: Install some development tools
dnf:
name:
- kernel-devel
- gcc
- dkms
- rpm-build
- python-devel
state: latest
when: development == "true"
################################################################################
# Add some configuration customization to /etc/screenrc for the #
# hard status line. #
################################################################################
- name: Customize the /etc/screenrc hard status line 1.
lineinfile:
path: /etc/screenrc
insertafter: EOF
line: '# Customize the hard status line by David Both'
- name: Customize the /etc/screenrc hard status line 2.
lineinfile:
path: /etc/screenrc
insertafter: EOF
line: 'hardstatus alwayslastline'
- name: Customize the /etc/screenrc hard status line 3.
lineinfile:
path: /etc/screenrc
insertafter: EOF
line: "hardstatus string '%{= kG}[ %{G}%H %{g}][%= %{= kw}%?%-Lw%?%{r}(%{W}%n*%f%t%?(%u)%?%{r})%{w}%?%+Lw%?%?%= %{g}][%{B} %m-%d %{W}%c %{g}]'"
- name: Customize the /etc/screenrc hard status line 4.
lineinfile:
path: /etc/screenrc
insertafter: EOF
line: ''
################################################################################
# Install Midnight Commander configuration files #
################################################################################
- name: create ~/.config directory in /etc/skel
file:
path: /etc/skel/.config
state: directory
mode: 0775
owner: root
group: root
- name: copy latest personal Midnight Commander skin to /usr/share
copy:
src: /home/dboth/development/ansible/PostInstall/files/MidnightCommander/DavidsGoTar.ini
dest: /usr/share/mc/skins/DavidsGoTar.ini
mode: 0644
owner: root
group: root
- name: create ~/.config/mc directory for root
file:
path: /home/dboth/development/.config/mc
state: directory
mode: 0755
owner: root
group: root
- name: Copy the most current Midnight Commander configuration files to /home/dboth/development/.config/mc
copy:
src: "{{ item }}"
dest: /home/dboth/development/.config/mc
mode: 0755
owner: root
group: root
with_fileglob:
- /home/dboth/development/ansible/PostInstall/files/MidnightCommander/*ini
# Placing the config files in /etc/skel makes them available for
# all users created from now on.
- name: create ~/.config/mc directory in /etc/skel
file:
path: /etc/skel/.config/mc
state: directory
mode: 0775
owner: root
group: root
- name: Copy the most current Midnight Commander configuration files to /etc/skel
copy:
src: "{{ item }}"
dest: /etc/skel/.config/mc
mode: 0644
owner: root
group: root
with_fileglob:
- /home/dboth/development/ansible/PostInstall/files/MidnightCommander/*ini
################################################################################
# Install other configuration files #
################################################################################
# Copy .bash_logout to /etc/skel becuase it is not created by default
- name: copy .bash_logout file to /etc/skel
copy:
src: /home/dboth/development/ansible/PostInstall/files/BashConfigFiles/.bash_logout
dest: /etc/skel/
mode: 0644
owner: root
group: root
# Copy .bash_logout to /root because it is not created by default
- name: copy .bash_logout file to /root
copy:
src: /home/dboth/development/ansible/PostInstall/files/BashConfigFiles/.bash_logout
dest: /home/dboth/development/
mode: 0644
owner: root
group: root
- name: copy myBashConfig.sh file to /etc/profile.d
copy:
src: /home/dboth/development/ansible/PostInstall/files/BashConfigFiles/myBashConfig.sh
dest: /etc/profile.d
mode: 0644
owner: root
group: root
- name: copy top configuration file to root
copy:
src: /home/dboth/development/ansible/PostInstall/files/top/toprc
dest: /root
mode: 0644
owner: root
group: root
- name: copy top configuration file to /etc/skel
copy:
src: /home/dboth/development/ansible/PostInstall/files/top/toprc
dest: /etc/skel
mode: 0644
owner: root
group: root
- name: copy root crontab to /var/spool/cron
copy:
src: /home/dboth/development/ansible/PostInstall/files/crontab/root
dest: /var/spool/cron
mode: 0644
owner: root
group: root
- name: Restart the crond daemon
systemd:
name: crond
state: restarted
enabled: yes
################################################################################
# Install some additional files and Bash scripts to /root #
################################################################################
- name: Copy some additional Bash scripts to /root
copy:
src: "{{ item }}"
dest: /root
mode: 0774
owner: root
group: root
with_fileglob:
- /home/dboth/development/ansible/PostInstall/files/root/scripts/*
- name: Copy some additional non-executable files to /root
copy:
src: "{{ item }}"
dest: /root
mode: 0664
owner: root
group: root
with_fileglob:
- /home/dboth/development/ansible/PostInstall/files/root/files/*
################################################################################
# Stop the ABRT services to prevent crashes from sucking up huge amounts of #
# resources when a dump occurs. ABRT is the Automated Bug Reporting Tool that #
# is used for reporting crash information. #
################################################################################
- name: Stop and disable the abrt-xorg daemon
systemd:
name: abrt-xorg
state: stopped
masked: yes
enabled: no
- name: Stop and disable the abrt-journal-core daemon
systemd:
name: abrt-journal-core
state: stopped
masked: yes
enabled: no
- name: Stop and disable the abrt-oops daemon
systemd:
name: abrt-oops
state: stopped
masked: yes
enabled: no
- name: Stop and disable the abrtd daemon
systemd:
name: abrtd
state: stopped
masked: yes
enabled: no
################################################################################
# Start and enable some services that are needed. #
################################################################################
- name: Start and enable the sysstat daemon
systemd:
name: sysstat
state: started
enabled: yes
################################################################################
# Set up daily creation of the MOTD #
################################################################################
- name: Install create_motd script in /etc/cron.daily
copy:
src: /home/dboth/development/ansible/PostInstall/files/usrlocal/bin/create_motd
dest: /etc/cron.daily
mode: 0774
owner: root
group: root
- name: Create the /etc/motd file for the first time
command: /usr/local/bin/create_motd
################################################################################
# Setting SSHD configuration #
################################################################################
- name: Add banner location to end of sshd_config
lineinfile:
path: /etc/ssh/sshd_config
insertafter: EOF
line: 'Banner /etc/LogBanner'
- name: Copy the LogBanner file
copy:
src: /home/dboth/development/ansible/PostInstall/files/etc/LogBanner
dest: /etc
mode: 0664
owner: root
group: root
###############################################################################
# Set grub.conf to remove "rhgb" from kernel config line, set menu timeout to #
# 10 seconds and comment out "hiddenmenu". This gives more time to interrupt #
# the boot process and make on-the-fly changes to it. #
# #
# Also set selinux=0 to disable selinux on the kernel command line. #
###############################################################################
# modify /etc/default/grub
- name: Change /etc/default/grub to allow recovery boot option.
replace:
path: /etc/default/grub
regexp: 'GRUB_DISABLE_RECOVERY="true"'
replace: 'GRUB_DISABLE_RECOVERY="false"'
- name: Change /etc/default/grub to 10 second timeout
replace:
path: /etc/default/grub
regexp: 'GRUB_TIMEOUT=[0-9]*'
replace: 'GRUB_TIMEOUT=10'
- name: Remove rhgb option from /etc/default/grub kernel command line
replace:
path: /etc/default/grub
regexp: ' rhgb'
replace: ''
- name: Remove quiet option from /etc/default/grub kernel command line
replace:
path: /etc/default/grub
regexp: ' quiet'
replace: ''
- name: Set selinux=0 on /etc/default/grub kernel command line
replace:
path: /etc/default/grub
regexp: 'usr"'
replace: 'usr selinux=0"'
# Rebuild grub.cfg files
- name: Rebuild /boot/grub2/grub.cfg
command:
cmd: grub2-mkconfig -o /boot/grub2/grub.cfg
################################################################################
# Also set the selinux configuration file to permissive. #
################################################################################
- name: Set selinux to disabled in /etc/selinux/config
replace:
path: /etc/selinux/config
regexp: 'SELINUX=enforcing'
replace: 'SELINUX=permissive'
################################################################################
# Set the level of detail for logwatch.conf and start timer. #
################################################################################
- name: Add the highest level of detail to logwatch.conf
lineinfile:
path: /etc/logwatch/conf/logwatch.conf
insertafter: EOF
line: 'Detail = 6'
################################################################################
# Add my email address to /etc/aliases if it exists, so that all emails to #
# root go to my email address. This must be done after installing SendMail. #
################################################################################
- name: Add my email address to /etc/aliases
lineinfile:
path: /etc/aliases
insertafter: EOF
line: 'root: david@both.org'
- name: Activate revised aliases
command:
cmd: newaliases
################################################################################
# Install BOINC #
################################################################################
- name: Install the Boinc client and tui
dnf:
name:
- boinc-client
- boinc-tui
when: David == "true"
################################################################################
# Copy default boinc configuration files. #
################################################################################
- name: Install default boinc configuration files.
copy:
src: "{{ item }}"
dest: /var/lib/boinc
mode: 0644
owner: boinc
group: boinc
with_fileglob:
- /home/dboth/development/ansible/PostInstall/files/boinc/*
when: David == "true"
################################################################################
# Add a line to end of /etc/vimrc to set listchars to allow viewing of #
# whitespace characters. #
################################################################################
- name: Add a line to end of /etc/vimrc to allow viewing of whitespace characters.
lineinfile:
path: /etc/vimrc
insertafter: EOF
line: 'set listchars=eol:$,nbsp:_,tab:<->,trail:~,extends:>,space:+'
################################################################################
# Create non-root users #
# Use mkpasswd --method=sha-512 <Password> to generate the password hash. #
################################################################################
# Add non-root user dboth (me) This needs to be done before some other
# tasks and after installing Midnight Commander configuration files in /etc/skel
- name: Add user dboth
user:
name: dboth
comment: David Both
password: $6$iVSAb5VYBem/ZC.W$KcHhEiylLXsPFy2tu.Z2Mr2TnE8Ed69ojOmf57HfceJvf8y6J9QSAXmKuq9WDxdWJH9y09CZTuBPj3eTjZpak.
groups: wheel
state: present
create_home: yes
when: David == "true"
- name: Add student user for testing
user:
name: student
comment: Student User
password: $6$.N.Kuu3j8pu.WDZH$HyQeho4itMqwsy61PxiFwrOsDtCO8Km7jLDD0zQcvhL/LzB0zErHnr2zyrX/qIpMwhloegA4DcugUsNZnWYma0
state: present
create_home: yes
when: David == "true"
- name: Install some GUI admninistration tools
dnf:
name: gnote,vim-X11,xfe
state: latest
when: Gui == "true"
################################################################################
# Lightdm is the default display manager but install others just in case. #
################################################################################
# Install the display managers
- name: Install Alternative display managers, lxdm,xorg-x11-xdm,sddm,and lightdm
dnf:
name: lxdm,xorg-x11-xdm,sddm,lightdm
state: latest
################################################################################
# Install additional desktops if this is to be a GUI workstation. #
# - Mate Desktop #
# - Cinnamon Desktop #
# - LXDE Desktop #
# - Xfce Desktop #
# #
################################################################################
- name: Install Mate desktop
dnf:
name: '@Mate Desktop'
state: latest
when: mate == "true"
- name: Install Cinnamon desktop
dnf:
name: '@Cinnamon Desktop'
state: latest
when: cinnamon == "true"
- name: Install LXDE desktop
dnf:
name: '@LXDE Desktop'
state: latest
when: lxde == "true"
- name: Install XFCE desktop
dnf:
name: '@Xfce Desktop'
state: latest
when: xfce == "true"
################################################################################
# Installing these new desktops changes the enabled display manager. So we #
# reenable lightdm and restart the display manager service. #
################################################################################
- name: Disable the current display manager
ansible.builtin.systemd:
name: display-manager.service
enabled: no
- name: Enable lightdm
ansible.builtin.systemd:
name: lightdm.service
enabled: yes
- name: Copy a large number of big background files to /usr/share/wallpapers. This will take a while.
copy:
src: "{{ item }}"
dest: /usr/share/wallpapers/
mode: 0664
owner: root
group: root
with_fileglob:
- /home/dboth/development/ansible/PostInstall/files/wallpapers/*
when: Wallpapers == "true"
################################################################################
# Install some GUI applications here if variables Gui and Apps are both true. #
################################################################################
# Start with some groups
- name: Install basic LibreOffice applications
dnf:
name: '@LibreOffice'
state: latest
when: Gui == "true" and Apps == "true"
- name: Install fonts group from the Fedora repository
dnf:
name: '@fonts'
state: latest
when: Gui == "true" and Apps == "true"
- name: Install additional individual fonts from the Fedora repository
dnf:
name: 'cmatrix-x11-fonts'
state: latest
when: Gui == "true" and Apps == "true"
- name: Install some additional GUI applications and tools
dnf:
name:
- libreoffice-base
- libreoffice-draw
- libreoffice-math
- libreoffice-icon-theme-papirus
- libreoffice-TexMaths
- krusader
- kmymoney
- skrooge
- tellico
- gramps
- gnucash
- stellarium
- celestia
- thunderbird
- firefox
- okular
- amarok
- asunder
- audacious
- audacity
state: latest
when: Gui == "true" and Apps == "true"
################################################################################
# Remove some things that are not needed, not wanted, or just don't work. #
################################################################################
- name: Remove dnfdragora because it does not work.
dnf:
name: dnfdragora
state: absent
when: dnfdragora == "false"
################################################################################
# Perform some final tasks that need to be done after everything else #
################################################################################
- name: Install Rootkit Hunter
dnf:
name:
- rkhunter
state: latest
- name: Create a current file properties database for rkhunter
command:
cmd: rkhunter --propupd
# Rebuild the man pages
- name: Rebuild man pages
command: mandb
################################################################################
# This will reboot the target host and then wait for it to complete its final #
# reboot when the reboot variable is true. Which it is by default. The #
# sequence of operations in this playbook does not result in showing the added #
# user accounts on the graphical login screen. The reboot does that. It also #
# ensures that all newly created users and groups are acive for new logins and #
# the latest libraries are in effect. #
################################################################################
- name: Reboot at the end of the procedure
reboot:
when: Reboot == "true"
################################################################################
################################################################################
Figure 1: Ansible playbook for performing all my post-install tasks.
Warning!!! — Don’t use this Ansible playbook on a production system until you know exactly what it does and have modified it to meet your own needs. This article and the playbook that goes with it are intended as a tool to demonstrate what can be done with Ansible to perform post-installation tasks. I strongly recommend that you experiment with this tool on a non-production virtual machine.
What it does — a bit
Don’t worry — despite including the entire playbook so you can see some of the many things that can be done with Ansible, I’m not going to describe every line of this playbook. The comments and the Ansible tasks themselves are fairly explanatory. However, you do need to know that some of the files that are installed via this playbook are local ones and work only on my hosts.
The first part of the playbook sets a number of variables that are used throughout. The only one I usually change is the hostname. Any variables can be set from the command line using the ansible-playbook option, -e, but I do like to change them in the playbook; that’s just my preference.
Then there’s a short section that sets some configuration. The section that disables AVAHI services and enables the NSS DNS service is important to me. I find that, for my network, that’s a better option for name services. I have a DNS server in my network and, when configured with NSS, is faster than the very chatty, peer-dependent, AVAHI mDNS.
I also disable the smart-card deamon because I don’t use smart cards in my environment. I’ve never encountered a situation where this service was used, so I’m not sure why it’s even included by default, let alone enabled.
Then Ansible installs some files that need to be there after the installation of updates and the reboot.
It also installs all current updates and reboots the target host. This is where some of the advantages of using Ansible become apparent. Unless it’s updating itself, Ansible doesn’t run on the target host; it runs on the Ansible hub and sends commands to the target host via SSH. When Ansible sends the reboot command to the target host, it waits until that system has rebooted and is responding to SSH commands. Ansible then continues sending instructions from the rest of the playbook.
That bit of coolness prevents the SysAdmin, me, from needing to intervene manually to either perform the reboot or to restart the playbook after the reboot.
A large part of the rest of the playbook installs a large number of problem solving tools I like to use and that aren’t installed by default. Any of those tools that are already installed because I used a different Fedora spin, or whatever, are recognized by Ansible and noted with the green OK message. It also performs a number of configuration tasks that saves me a lot of time, both in performing the configuration, as well as in performance of my SysAdmin tasks.
You’ll also notice that the playbook does install some fun command line games. SysAdmins like to have fun, too.
Desktops
Whether your system already has a GUI desktop installed or not, this playbook can install any desktops that you specify, like Xfce, LCDE, MATE, or Cinnamon. Those are the ones I usually install. If you want to add others, you can add tesks to do so. Just list the desktop groups to install for Fedora with the command in Figure 2…
$ dnf grouplist | grep -i desk
Phosh Desktop
LXQt Desktop
MATE Desktop
Sugar Desktop Environment
Deepin Desktop
Budgie Desktop
Basic Desktop
i3 desktop
Sway Desktop
Xfce Desktop
LXDE Desktop
Cinnamon Desktop
Desktop accessibility
Budgie Desktop Applications
GNOME Desktop Environment
KDE (K Desktop Environment)
Figure 2: This command displays all Fedora package groups.
… Then get more information about the LXDE desktop, for example, as in Figure 3. You can use this command to learn more about any of the desktop groups.
$ dnf groupinfo "LXDE Desktop"
Last metadata expiration check: 0:05:06 ago on Mon 08 Jul 2024 01:01:35 PM EDT.
Environment Group: LXDE Desktop
Description: LXDE is a lightweight X11 desktop environment designed for computers with low hardware specifications like netbooks, mobile devices or older computers.
Mandatory Groups:
Administration Tools
Common NetworkManager Submodules
Core
Desktop accessibility
Dial-up Networking Support
Fonts
Guest Desktop Agents
Hardware Support
Input Methods
LXDE
Multimedia
Printing Support
Standard
base-x
Optional Groups:
3D Printing
Applications for the LXDE Desktop
Cloud Management Tools
LXDE Office
Multimedia support for LXDE
Figure 3: More detailed information about the LXDE desktop.
Once you’ve decided which desktops to install, add tasks to do that. It’s not necessary to delete any of the ones that are already there.
Parting thoughts
Performing all of my post-installation tasks using Ansible saves me having to monitor the process and to intervene. I have configured Ansible to send commands to the remote host using the root account, but it also provides options for using non-root accounts.
Modifying the Ansible playbook is easy so don’t hesitate to experiment with it on your VM.
If you have multiple target hosts you can have Ansible work on them both at the same time. Just list the hostnames in the hosts variable in the playbook or the extended-variables at the command line. Ansible keeps track of each host separately so even if they’re significantly different in speed, the fastest host isn’t forced to wait untill the slower hosts catch up. All hosts finish at their own speed.
I currently use Ansible to perform all of my post-installation tasks. It’s the best tool I’ve used in that it does everything I need it to and I don’t need to intervene at any point.