PL - 012 — Automating Linux system Administration Tasks with Ansible
Automating Linux system Adminstration Tasks
i. Software and Subscription Management ii. Scheduling Tasks
Lab Session:
aadarkdk@pop-os:~$ ssh cnode@192.168.254.15
cnode@192.168.254.15's password:
Last login: Wed Sep 16 06:10:27 2026
[cnode@control-node ~]$ ls
ansible-lab done validate_nodes.sh
[cnode@control-node ~]$ ./validate_nodes.sh
----- dev1 -----
dev1
root
----- dev2 -----
dev2
root
----- testserver -----
testserver
root
----- prodserver -----
prodserver
root
[cnode@control-node ~]$
Configure yum repository, manually and using Ansible:
Working mechanism of installing the package manually:
# when a package is installed:
[cnode@control-node ~]$ # yum/dnf -y install package_name
[cnode@control-node ~]$
[cnode@control-node ~]$ cd /etc/yum.repos.d/
[cnode@control-node yum.repos.d]$ pwd
/etc/yum.repos.d
[cnode@control-node yum.repos.d]$ ls
centos-addons.repo centos.repo
# This files contain the meta link from where the packages are copied
[cnode@control-node yum.repos.d]$ cat centos-addons.repo
[highavailability]
name=CentOS Stream $releasever - HighAvailability
metalink=https://mirrors.centos.org/metalink?repo=centos-highavailability-$stream&arch=$basearch&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[highavailability-debuginfo]
name=CentOS Stream $releasever - HighAvailability - Debug
metalink=https://mirrors.centos.org/metalink?repo=centos-highavailability-debug-$stream&arch=$basearch&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
...
[cnode@control-node yum.repos.d]$ cat centos.repo
[baseos]
name=CentOS Stream $releasever - BaseOS
metalink=https://mirrors.centos.org/metalink?repo=centos-baseos-$stream&arch=$basearch&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1
[baseos-debuginfo]
name=CentOS Stream $releasever - BaseOS - Debug
metalink=https://mirrors.centos.org/metalink?repo=centos-baseos-debug-$stream&arch=$basearch&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
...
[crb-debuginfo]
name=CentOS Stream $releasever - CRB - Debug
metalink=https://mirrors.centos.org/metalink?repo=centos-crb-debug-$stream&arch=$basearch&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[crb-source]
name=CentOS Stream $releasever - CRB - Source
metalink=https://mirrors.centos.org/metalink?repo=centos-crb-source-$stream&arch=source&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[cnode@control-node yum.repos.d]$
[cnode@control-node yum.repos.d]$ ls
centos-addons.repo centos.repo
[cnode@control-node yum.repos.d]$ sudo mkdir backup
[sudo] password for cnode:
[cnode@control-node yum.repos.d]$ ls
backup centos-addons.repo centos.repo
[cnode@control-node yum.repos.d]$ sudo mv *.repo backup/
[cnode@control-node yum.repos.d]$ ls
backup
[cnode@control-node yum.repos.d]$ ls backup/
centos-addons.repo centos.repo
[cnode@control-node yum.repos.d]$
# In two develop machines: manually removing defaults repo files
aadarkdk@pop-os:~$ ssh cnode@192.168.254.16
cnode@192.168.254.16's password:
Last login: Wed Sep 16 05:11:19 2026 from 192.168.254.152
[cnode@dev1 ~]$ cd /etc/yum.repos.d/
[cnode@dev1 yum.repos.d]$ ls
centos-addons.repo centos.repo
[cnode@dev1 yum.repos.d]$ mkdir backup
mkdir: cannot create directory ‘backup’: Permission denied
[cnode@dev1 yum.repos.d]$ sudo mkdir backup
[cnode@dev1 yum.repos.d]$ ls
backup centos-addons.repo centos.repo
[cnode@dev1 yum.repos.d]$ sudo mv *.repo backup/
[cnode@dev1 yum.repos.d]$ ls
backup
[cnode@dev1 yum.repos.d]$ ls backup/
centos-addons.repo centos.repo
[cnode@dev1 yum.repos.d]$
aadarkdk@pop-os:~$ ssh cnode@192.168.254.17
cnode@192.168.254.17's password:
Last login: Wed Sep 16 06:09:45 2026
[cnode@dev2 ~]$ cd /etc/yum.repos.d/
[cnode@dev2 yum.repos.d]$ ls
centos-addons.repo centos.repo
[cnode@dev2 yum.repos.d]$ mkdir backup
mkdir: cannot create directory ‘backup’: Permission denied
[cnode@dev2 yum.repos.d]$ sudo mkdir backup
[cnode@dev2 yum.repos.d]$ sudo mv *.repo backup/
[cnode@dev2 yum.repos.d]$ ls
backup
[cnode@dev2 yum.repos.d]$ ls backup/
centos-addons.repo centos.repo
[cnode@dev2 yum.repos.d]$
Manually creating repo configuration file
[cnode@control-node yum.repos.d]$ ls
backup
[cnode@control-node yum.repos.d]$ sudo vim local-custom.repo
[sudo] password for cnode:
[cnode@control-node yum.repos.d]$ ls
backup local-custom.repo
[cnode@control-node yum.repos.d]$ cat local-custom.repo
[baseos]
name=baseos repo
baseurl=http://mylocalserver.local.domain/BaseOS
enabled=1
gpgcheck=0
[appstream]
name=appstream repo
baseurl=http://mylocalserver.local.domain/AppStream
enabled=1
gpgcheck=0
[cnode@control-node yum.repos.d]$ ansible-doc yum-repository
[WARNING]: yum-repository was not found
[cnode@control-node yum.repos.d]$ ansible-doc yum_repository
[cnode@control-node yum.repos.d]$ ansible-doc rpm_key
[cnode@control-node yum.repos.d]$ pwd
/etc/yum.repos.d
[cnode@control-node yum.repos.d]$ ls /etc/pki/rpm-gpg/
RPM-GPG-KEY-centosofficial-PQC RPM-GPG-KEY-centosofficial-SHA256 RPM-GPG-KEY-CentOS-SIG-Extras-SHA512
[cnode@control-node yum.repos.d]$ ls /etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-PQC
/etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-PQC
[cnode@control-node yum.repos.d]$
[cnode@control-node ansible-lab]$ ls
ansible.cfg inventory
[cnode@control-node ansible-lab]$ hostname
control-node
[cnode@control-node ansible-lab]$ pwd
/home/cnode/ansible-lab
[cnode@control-node ansible-lab]$ vim yum_repo-pkgserver.yml
[cnode@control-node ansible-lab]$ cat yum_repo-pkgserver.yml
---
- name: Play to configure yum repo on the remote hosts
hosts: develop
tasks:
- name: Create a baseos yum repo
ansible.builtin.yum_repository:
name: mybaseos
description: My BaseOS YUM repo
file: mylocal
baseurl: http://mylocalserver.local.domain/BaseOS
enabled: yes
gpgcheck: yes
- name: Create a appstream yum repo
ansible.builtin.yum_repository:
name: myappstream
description: My AppStream YUM repo
file: mylocal
baseurl: http://mylocalserver.local.domain/AppStream
enabled: yes
gpgcheck: yes
- name: Import a key from a file
ansible.builtin.rpm_key:
state: present
key: /etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-PQC
[cnode@control-node ansible-lab]$
[cnode@control-node ansible-lab]$ ansible-playbook --syntax-check yum_repo-pkgserver.yml
playbook: yum_repo-pkgserver.yml
[cnode@control-node ansible-lab]$ ansible-playbook yum_repo-pkgserver.yml
PLAY [Play to configure yum repo on the remote hosts] *******************************
TASK [Gathering Facts] **************************************************************
ok: [dev2]
ok: [dev1]
TASK [Create a baseos yum repo] *****************************************************
changed: [dev2]
changed: [dev1]
TASK [Create a appstream yum repo] **************************************************
changed: [dev1]
changed: [dev2]
TASK [Import a key from a file] *****************************************************
changed: [dev2]
changed: [dev1]
PLAY RECAP **************************************************************************
dev1 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
dev2 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[cnode@control-node ansible-lab]$
In develop machines:
[cnode@dev2 yum.repos.d]$ ls
backup mylocal.repo
[cnode@dev2 yum.repos.d]$ cat mylocal.repo
[mybaseos]
baseurl = http://mylocalserver.local.domain/BaseOS
enabled = 1
gpgcheck = 1
name = My BaseOS YUM repo
[myappstream]
baseurl = http://mylocalserver.local.domain/AppStream
enabled = 1
gpgcheck = 1
name = My AppStream YUM repo
[cnode@dev2 yum.repos.d]$
[cnode@dev2 yum.repos.d]$ sudo dnf repolist
repo id repo name
myappstream My AppStream YUM repo
mybaseos My BaseOS YUM repo
[cnode@dev2 yum.repos.d]$
[cnode@dev1 yum.repos.d]$ ls
backup mylocal.repo
[cnode@dev1 yum.repos.d]$ cat mylocal.repo
[mybaseos]
baseurl = http://mylocalserver.local.domain/BaseOS
enabled = 1
gpgcheck = 1
name = My BaseOS YUM repo
[myappstream]
baseurl = http://mylocalserver.local.domain/AppStream
enabled = 1
gpgcheck = 1
name = My AppStream YUM repo
[cnode@dev1 yum.repos.d]$
[cnode@dev1 yum.repos.d]$ sudo yum repolist
repo id repo name
myappstream My AppStream YUM repo
mybaseos My BaseOS YUM repo
[cnode@dev1 yum.repos.d]$
[cnode@dev1 yum.repos.d]$ pwd
/etc/yum.repos.d
[cnode@dev1 yum.repos.d]$
[cnode@control-node ansible-lab]$ ansible develop -m ansible.builtin.file -a 'path=/etc/yum.repos.d/mylocal.repo state=absent'
dev2 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": true,
"path": "/etc/yum.repos.d/mylocal.repo",
"state": "absent"
}
dev1 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": true,
"path": "/etc/yum.repos.d/mylocal.repo",
"state": "absent"
}
[cnode@control-node ansible-lab]$
Cronjob
[cnode@dev1 yum.repos.d]$ crontab -l
no crontab for cnode
[cnode@dev1 yum.repos.d]$ sudo cat /var/spool/cron/cnode
cat: /var/spool/cron/cnode: No such file or directory
[cnode@dev1 yum.repos.d]$
[cnode@dev2 ~]$ ls /etc/cron.d
0hourly
[cnode@dev2 ~]$
[cnode@dev2 yum.repos.d]$ crontab -l
no crontab for cnode
[cnode@dev2 yum.repos.d]$ sudo cat /var/spool/cron/cnode
cat: /var/spool/cron/cnode: No such file or directory
[cnode@dev2 yum.repos.d]$
[cnode@dev1 yum.repos.d]$ ls /etc/cron.d
0hourly
[cnode@dev1 yum.repos.d]$
[cnode@control-node ansible-lab]$ ls
ansible.cfg inventory yum_repo-pkgserver.yml
[cnode@control-node ansible-lab]$ mv yum_repo-pkgserver.yml ../done/
[cnode@control-node ansible-lab]$ ls
ansible.cfg inventory
[cnode@control-node ansible-lab]$ vim cronjobs.yml
[cnode@control-node ansible-lab]$ cat cronjobs.yml
---
- name: Play to install cron job on develop machines
hosts: develop
tasks:
- name: Schedule cron job to run at 5 AM everyday
ansible.builtin.cron:
name: "Check logged in users"
minute: "00"
hour: "9"
job: "who >> /tmp/who-output"
[cnode@control-node ansible-lab]$ ansible-playbook --syntax-check cronjobs.yml
playbook: cronjobs.yml
[cnode@control-node ansible-lab]$ ansible-playbook cronjobs.yml
PLAY [Play to install cron job on develop machines] *********************************
TASK [Gathering Facts] **************************************************************
ok: [dev2]
ok: [dev1]
TASK [Schedule cron job to run at 5 AM everyday] ************************************
changed: [dev1]
changed: [dev2]
PLAY RECAP **************************************************************************
dev1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
dev2 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[cnode@control-node ansible-lab]$
[cnode@control-node ansible-lab]$ ansible develop -m command -a 'whoami'
dev2 | CHANGED | rc=0 >>
root
dev1 | CHANGED | rc=0 >>
root
[cnode@control-node ansible-lab]$
[cnode@dev2 ~]$ sudo crontab -l
#Ansible: Check logged in users
00 9 * * * who >> /tmp/who-output
[cnode@dev2 ~]$ whoami
cnode
[cnode@dev2 ~]$ sudo ls /var/spool/cron/
root
[cnode@dev2 ~]$ sudo cat /var/spool/cron/root
#Ansible: Check logged in users
00 9 * * * who >> /tmp/who-output
[cnode@dev2 ~]$
[cnode@dev1 ~]$ sudo crontab -l
#Ansible: Check logged in users
00 9 * * * who >> /tmp/who-output
[cnode@dev1 ~]$
[cnode@control-node ansible-lab]$ ls
ansible.cfg cronjobs.yml inventory
[cnode@control-node ansible-lab]$ cp cronjobs.yml cronjobs2.yml
[cnode@control-node ansible-lab]$ vim cronjobs2.yml
[cnode@control-node ansible-lab]$ cat cronjobs2.yml
---
- name: Play to install cron job on develop machines
hosts: develop
tasks:
- name: Schedule cron job to run at 5:30 PM on the first day every month
ansible.builtin.cron:
name: "Check disk info"
minute: "30"
hour: "17"
day: "1"
month: "*"
weekday: "*"
job: "df -h >> /tmp/who-output"
user: cnode
[cnode@control-node ansible-lab]$ ls
ansible.cfg cronjobs2.yml cronjobs.yml inventory
[cnode@control-node ansible-lab]$ ansible-playbook cronjobs2.yml
PLAY [Play to install cron job on develop machines] *********************************
TASK [Gathering Facts] **************************************************************
ok: [dev1]
ok: [dev2]
TASK [Schedule cron job to run at 5:30 PM on the first day every month] *************
changed: [dev1]
changed: [dev2]
PLAY RECAP **************************************************************************
dev1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
dev2 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[cnode@control-node ansible-lab]$
---
[cnode@dev2 ~]$ sudo ls /var/spool/cron/
cnode root
[cnode@dev2 ~]$ sudo cat /var/spool/cron/cnode
#Ansible: Check disk info
30 17 1 * * df -h >> /tmp/who-output
[cnode@dev2 ~]$ crontab -l
#Ansible: Check disk info
30 17 1 * * df -h >> /tmp/who-output
[cnode@dev2 ~]$ sudo crontab -l
#Ansible: Check logged in users
00 9 * * * who >> /tmp/who-output
[cnode@dev2 ~]$
Note:
- All modules have idempotent property. But, ansible.builtin.command or ansible.builtin.shell module does not have idempotent property