Preparation Set 3


Instructions

    1. You will be provided with the root password.
    1. You need to use the hostname , if told in the instructions.
    1. You need to use the IP address, if told in the instructions.
    1. You need to ensure that you can SSH into every machine in your inventory without being prompted for a password.

Q1: Install and configure ansible in the control node

  • a. Install the required packages
  • b. Create a static inventory file /home/devops/ansible/hosts so that:
    • i. Node1 is the member of developer host group
    • ii. Node2 is the member of testing host group
    • iii. Node3 is the member of production host group
  • c. The production group is a member of the webservers host group
  • d. Create a configuration file called /home/devops/ansible/ansible.cfg so that:
    • i. The host inventory file is /home/devops/ansible/hosts
    • ii. The default content collection directory is /home/devops/ansible/collections
    • iii. The default role directory is /home/devops/ansible/roles
# Check all the required packages [devops@ansible-server tasks]$ rpm -q epel-release epel-release-9-9.el9.noarch [devops@ansible-server tasks]$ rpm -q ansible-core ansible-core-2.14.18-1.el9.aarch64 [devops@ansible-server tasks]$ rpm -q ansible ansible-7.7.0-1.el9.noarch # Configure indentation for ansible playbooks (yaml) [devops@ansible-server ~]$ cat .vimrc autocmd FileType yaml setlocal ai ts=2 sw=2 et # Make sure ssh and ssh-copy-id is working in all the machines from the control node [devops@ansible-server tasks]$ ssh devops@192.168.208.181 devops@192.168.208.181's password: Last login: Mon Feb 24 14:29:40 2025 from 192.168.208.1 [devops@node1 ~]$ exit logout Connection to 192.168.208.181 closed. [devops@ansible-server tasks]$ ssh-copy-id devops@192.168.208.181 /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/devops/.ssh/id_rsa.pub" /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys devops@192.168.208.181's password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh 'devops@192.168.208.181'" and check to make sure that only the key(s) you wanted were added. # Configure ansible.cfg file and hosts file [devops@ansible-server tasks]$ ls ansible.cfg collections hosts roles [devops@ansible-server tasks]$ cat ansible.cfg [defaults] inventory=/home/devops/tasks/hosts roles_path=/home/devops/tasks/roles collection_path=/home/devops/tasks/collections remote_user=devops [privilege_escalation] become=true [devops@ansible-server tasks]$ cat hosts [developer] node1 [testing] node2 [production] node3 [webservers:children] production # Ping all the machines [devops@ansible-server tasks]$ ansible -m ping all node1 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python3" }, "changed": false, "ping": "pong" } node2 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python3" }, "changed": false, "ping": "pong" } node3 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python3" }, "changed": false, "ping": "pong" } # Add ANSIBLE_CONFIG Path [devops@ansible-server ~]$ tail -1 .bashrc export ANSIBLE_CONFIG=/home/devops/tasks/ansible.cfg # Check the ansible config working [devops@ansible-server ~]$ ansible --version ansible [core 2.14.18] config file = /home/devops/tasks/ansible.cfg configured module search path = ['/home/devops/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python3.9/site-packages/ansible ansible collection location = /home/devops/.ansible/collections:/usr/share/ansible/collections executable location = /usr/bin/ansible python version = 3.9.18 (main, Sep 7 2023, 00:00:00) [GCC 11.4.1 20230605 (Red Hat 11.4.1-2)] (/usr/bin/python3) jinja version = 3.1.2 libyaml = True # Check the hosts [devops@ansible-server ~]$ ansible all --list-hosts hosts (3): node1 node2 node3

Q2: Create and run a ansible playbook. As a system adminstrator you need to install software on managed hosts

  • a. Create a playbook called playbook2.yml to create yum repositories on each of the managed nodes as per the following details:
  • b. Note: You need to create 2 repos (BaseOS and AppStream) in the managed nodes.
  • c. The file should be external_repos.repo file

BaseOS:

AppStream:

[devops@ansible-server tasks]$ vim playbook2.yml [devops@ansible-server tasks]$ cat playbook2.yml - name: Playbook2 hosts: all tasks: - name: Import a key from a url ansible.builtin.rpm_key: state: present key: http://192.168.208.100/softwares/RPM-GPG-KEY-centosofficial - name: Add baseos repository ansible.builtin.yum_repository: name: BaseOS description: BaseOS Repo baseurl: http://192.168.208.100/softwares/BaseOS gpgcheck: yes enabled: yes file: external_repos gpgkey: http://192.168.208.100/softwares/RPM-GPG-KEY-centosofficial - name: Add appstream repository ansible.builtin.yum_repository: name: AppStream description: AppStream Repo baseurl: http://192.168.208.100/softwares/AppStream gpgcheck: yes enabled: yes file: external_repos gpgkey: http://192.168.208.100/softwares/RPM-GPG-KEY-centosofficial [devops@ansible-server tasks]$ [devops@ansible-server tasks]$ [devops@ansible-server tasks]$ ansible-playbook --syntax-check playbook2.yml playbook: playbook2.yml [devops@ansible-server tasks]$ ansible-playbook playbook2.yml [devops@ansible-server tasks]$ ansible all -m command -a 'cat /etc/yum.repos.d/external_repos.repo'

Q3: Create a playbook called /home/devops/tasks/playbook3.yml that:

  • Install the php and samba packages in the host in the developer, testing and production host groups only.
  • Install the RPM development tools package group on hosts in the developer host group only
  • Update all package to the latest version on hosts in the dev developer group only.
[devops@ansible-server tasks]$ vim playbook3.yml [devops@ansible-server tasks]$ cat playbook3.yml - name: Playbook3 hosts: all tasks: - name: Install the latest version of php and samba ansible.builtin.yum: name: "{{ item }}" state: latest loop: - php - samba when: inventory_hostname in groups['developer'] - name: Install the 'RPM Development Tools' package group ansible.builtin.yum: name: "@RPM Development Tools" state: present when: inventory_hostname in groups['developer'] - name: Upgrade all packages ansible.builtin.yum: name: '*' state: latest [devops@ansible-server tasks]$ ansible-playbook --syntax-check playbook3.yml [devops@ansible-server tasks]$ ansible-playbook playbook3.yml

Q4: Install the RHEL system roles package and create a playbook called /home/devops/tasks/playbook4.yml that:

  • Runs on all managed host
  • Use the timesync role
  • Configure the role to use the timeserver
  • Configure the role to set the iburst parameter as enabled
[devops@ansible-server tasks]$ sudo yum install rhel-system-roles [devops@ansible-server tasks]$ cat playbook4.yml - name: Manage timesync hosts: all vars: timesync_ntp_servers: - hostname: time.google.com iburst: true roles: - /usr/share/ansible/roles/rhel-system-roles.timesync

Q5: Create a role in apache in /home/devops/ansible/roles with the following requirement

  • The httpd package should be installed, httpd service should be enabled on boot, and started.
  • The firewall is enabled and running with a rule to allow access to the webserver.
  • A template file index.html.j2 exists(you have to create this file) and is used to create the file /var/www/html/index.html with the following output: Welcome to hostname on ipaddress, where hostname is the fully qualified domain name of the managed node and the ipaddress is the ipaddress of the managed node.
# Create index.html.j2 file [devops@ansible-server templates]$ vim index.html.j2 [devops@ansible-server templates]$ cat index.html.j2 welcome to {{ ansible_facts['fqdn'] }} on {{ ansible_facts['default_ipv4']['address'] }} # Create vars [devops@ansible-server vars]$ cat main.yml pkgs: - httpd - firewalld firewall_svcs: - http - https # Create tasks [devops@ansible-server tasks]$ cat main.yml - name: Install the latest version of Packages ansible.builtin.yum: name: "{{ item }}" state: latest loop: "{{ pkgs }}" - name: Start service if not started ansible.builtin.service: name: "{{ item }}" state: started enabled: yes loop: "{{ pkgs }}" - name: permit traffic in default zone for https service ansible.posix.firewalld: service: "{{ item }}" state: enabled permanent: true immediate: true loop: "{{ firewall_svcs }}" - name: Template a file to /var/www/html ansible.builtin.template: src: index.html.j2 dest: /var/www/html/index.html # Create playbook file and execute [devops@ansible-server tasks]$ cat playbook5.yml - name: Playbook5 hosts: developer roles: - /home/devops/tasks/roles/apache [devops@ansible-server tasks]$ ansible-playbook --syntax-check playbook5.yml playbook: playbook5.yml [devops@ansible-server tasks]$ ansible-playbook playbook5.yml # Check [devops@ansible-server tasks]$ ansible developer -m command -a 'cat /var/www/html/index.html' node1 | CHANGED | rc=0 >> welcome to node1 on 192.168.208.136 [devops@ansible-server tasks]$ curl http://192.168.208.181 welcome to node1 on 192.168.208.136

Q6: Use Ansible galaxy with the requirement file /home/devops/tasks/roles/requirements.yml to download and install roles to /home/admin/ansible/roles from the following URLs:

[devops@ansible-server tasks]$ cd roles/ [devops@ansible-server roles]$ cat requirements.yml - src: http://192.168.208.100/downloads/role1.tar.gz name: role1 - src: http://192.168.208.100/downloads/role2.tar.gz name: role2 [devops@ansible-server roles]$ ansible-galaxy role install -r requirements.yml

Q7: Create a playbook called role1.yml as per the following details.

  • The playbook contains a play that runs on hosts in the developer group and uses the role1 role present in your machine.
[devops@ansible-server tasks]$ cat playbook6.yml - name: Playbook6 hosts: developer roles: - /home/devops/tasks/roles/role1 [devops@ansible-server tasks]$ curl http://192.168.208.181 Role1 Tasks !!! welcome to node1 on 192.168.208.136

Q8: Create a playbook called test.yml as per the following details:

  • The playbook runs on the managed nodes in the developer host group.
  • Create directory /webtest with the group ownership webgroup and having the regular permission rwx for the owner and group, and rx for the others.
  • Apply the special group permission: set group ID
  • Symbollically link /var/www/html/webtest to /webtest directory.
  • Create the file /webtest/index.html with a single line of text that reads :Testing.
[devops@ansible-server tasks]$ cat playbook8.yml - name: Playbook8 hosts: developer tasks: - name: Ensure group "webgroup" exists ansible.builtin.group: name: webgroup state: present - name: Create directory ansible.builtin.file: path: /webtest state: directory group: webgroup owner: root mode: '2775' - name: Create a symbolic link ansible.builtin.file: src: /webtest dest: /var/www/html/webtest state: link - name: Copy using inline content ansible.builtin.copy: content: "Testing\n" dest: /webtest/index.html group: webgroup owner: root mode: '0664' - name: Appending the group 'webgroup' and 'apache' ansible.builtin.user: name: apache groups: webgroup append: yes

If curl is returning forbidden request, then set selinux to permissive

- name: Set SELinux to permissive ansible.posix.selinux: policy: targeted state: permissive

Q9: Create an ansible vault to store user password with the following conditions:

  • The name of the vault is vault.yml
  • The vault contains two variables dev_pass with value as redhat and mgr_pass with value as linux respectively.
  • The password to encrypt and decrypt the vault is devops
  • The password is stored in the file /home/devops/ansible/password.txt file.
[devops@ansible-server tasks]$ cat password.txt devops [devops@ansible-server tasks]$ ansible-vault create --vault-password-file password.txt vault.yml [devops@ansible-server tasks]$ ansible-vault view vault.yml Vault password: dev_pass: redhat mgr_pass: linux

Q10: Generate host files:

  • Download an initial template file called hosts.j2 from the below URL: http://192.168.208.100/content/hosts.j2 to /home/devops/tasks/directory. Complete the template so that it can be used to generate a file with a line for each inventory host in the same format as /etc/hosts.
  • Create a playbook called playbook10.yml that uses this template to generate the file /etc/myhosts on hosts in the all host group
  • When completed, the file /etc/myhosts on hosts in the all host group should have a line for each managed host:
[devops@ansible-server tasks]$ vim playbook10.yml [devops@ansible-server tasks]$ cat playbook10.yml - name: Playbook10 hosts: all tasks: - name: Template a file ansible.builtin.template: src: /home/devops/tasks/hosts.j2 dest: /etc/myhosts [devops@ansible-server tasks]$ cat hosts.j2 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 {% for x in groups['all'] %} {{ hostvars[x]['ansible_facts']['default_ipv4']['address'] }} {{ hostvars[x]['ansible_facts']['hostname'] }} {{ hostvars[x]['ansible_facts']['fqdn'] }} {% endfor %} [devops@ansible-server tasks]$ ansible all -m command -a 'cat /etc/myhosts' node3 | CHANGED | rc=0 >> 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.208.136 node1 node1 192.168.208.151 node2 node2 192.168.208.152 node3 node3 node1 | CHANGED | rc=0 >> 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.208.136 node1 node1 192.168.208.151 node2 node2 192.168.208.152 node3 node3 node2 | CHANGED | rc=0 >> 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.208.136 node1 node1 192.168.208.151 node2 node2 192.168.208.152 node3 node3

Q11: Create a playbook called playbook11.yml that produces an output file called /root/hwreport.txt on all the managed nodes with following information

  • Inventory Hostname :
  • Total Memory in MB :
  • BIOS Version :
  • nvme0n1 Size :
  • nvme0n2 Size : Each line of the output file contains a single key-value pair. If no device then write NONE
[devops@ansible-server tasks]$ cat playbook11.yml - name: Playbook11 hosts: all tasks: - name: Template a file ansible.builtin.template: src: /home/devops/tasks/hwreport.j2 dest: /root/hwreport.txt [devops@ansible-server tasks]$ cat hwreport.j2 * Inventory Hostname : {{ ansible_facts['hostname'] }} * Total Memory in MB : {{ ansible_facts['memtotal_mb'] }} * BIOS Version : {{ ansible_facts['bios_version'] }} * nvme0n1 Size : {% if ansible_facts['devices']['nvme0n1'] is defined %} {{ ansible_facts['devices']['nvme0n1']['size'] }} {% else %} NONE {% endif %} * nvme0n2 Size : {% if ansible_facts['devices']['nvme0n2'] is defined %} {{ ansible_facts['devices']['nvme0n2']['size'] }} {% else %} NO NE {% endif %}

Q12: Create a playbook called /home/devops/tasks/playbook12.yml as per the following requirements

  • The playbook runs on all inventory hosts
  • The playbook replaces the contents of /etc/issue with a single line of text as:
    • On host in the developer host group, the line reads: Development
    • On host in the testing host group, the line reads: Testing
    • On host in the production host group, the line reads: Production
[devops@ansible-server tasks]$ vim playbook12.yml [devops@ansible-server tasks]$ cat playbook12.yml - name: Playbook12 hosts: all tasks: - name: Copy using inline content for developer ansible.builtin.copy: content: "Development\n" dest: /etc/issue when: inventory_hostname in groups['developer'] - name: Copy using inline content for testing ansible.builtin.copy: content: "Testing\n" dest: /etc/issue when: inventory_hostname in groups['testing'] - name: Copy using inline content for production ansible.builtin.copy: content: "Production\n" dest: /etc/issue when: inventory_hostname in groups['production'] [devops@ansible-server tasks]$ ansible-playbook playbook12.yml [devops@ansible-server tasks]$ ansible all -m command -a 'cat /etc/issue' node3 | CHANGED | rc=0 >> Production node2 | CHANGED | rc=0 >> Testing node1 | CHANGED | rc=0 >> Development

Q13: Rekey an existing ansible vault as per the following condition:

  • Use the vault.yml file that you have created earlier
  • Set the new vault password as ansible
  • The vault remains in an encrypted state with the new password
[devops@ansible-server tasks]$ vim password.txt [devops@ansible-server tasks]$ cat password.txt ansible [devops@ansible-server tasks]$ ansible-vault rekey --new-vault-password-file=password.txt vault.yml Vault password: Rekey successful # Using new vault password - ansible [devops@ansible-server tasks]$ ansible-vault view vault.yml Vault password: dev_pass: redhat mgr_pass: linux

Q14: 14. Create user accounts. A list of users to be created can be found in the file called user_list.yml which you should download from "http://192.168.208.100/content/user_list.yml" and save to /home/devops/tasks/ directory. Using the password vault created elsewhere in this exam, create a playbook called playbook14.yml that creates user accounts as follows:

  • Users with a job description of developer should be created on managed nodes in the developer and testing host groups assigned the password from the dev_pass variable and is a member of supplementary group hit_developer.
  • Users with a job description of manager should be created on managed nodes in the production host group assigned the password from the mgr_pass variable and is a member of supplementary group hit_manager.
  • Passwords should use the SHA512 hash format. Your playbook should work using the vault password file created elsewhere in this exam.
[devops@ansible-server tasks]$ cat user_list.yml users: - name: dilane job: developer uid: 3300 - name: fahim job: manager uid: 3301 - name: safayet job: developer uid: 3302 [devops@ansible-server tasks]$ cat playbook14.yml - name: Playbook14 developer hosts: developer,testing vars_files: - /home/devops/tasks/vault.yml - /home/devops/tasks/user_list.yml tasks: - name: Ensure group "hit_developer" exists ansible.builtin.group: name: hit_developer state: present - name: Add the user ansible.builtin.user: name: "{{ item.name }}" uid: "{{ item.uid }}" group: hit_developer password: "{{ dev_pass | password_hash('sha512') }}" loop: "{{ users }}" when: item.job == "developer" - name: Playbook14 manager hosts: production vars_files: - /home/devops/tasks/vault.yml - /home/devops/tasks/user_list.yml tasks: - name: Ensure group "hit_manager" exists ansible.builtin.group: name: hit_manager state: present - name: Add the user ansible.builtin.user: name: "{{ item.name }}" uid: "{{ item.uid }}" group: hit_manager password: "{{ dev_pass | password_hash('sha512') }}" loop: "{{ users }}" when: item.job == "manager"

Q15: Configure Cron Jobs: Create /home/devops/tasks/playbook15.yml playbook as per the following requirement

  • This playbook runs on all managed nodes in the hostgroup
  • Configure cronjob, which runs every 2 minutes and executes the following command: logger "EX294 exam in progress" and runs as user natasha
[devops@ansible-server tasks]$ cat playbook15.yml - name: Playbook15 hosts: all tasks: - name: Add the user ansible.builtin.user: name: mohit - name: Ensure a job ansible.builtin.cron: name: "cron log" minute: "*/2" user: mohit job: 'logger "EX294 exam in progress"' [devops@ansible-server tasks]$ ansible all -m command -a 'crontab -l -u mohit' node3 | CHANGED | rc=0 >> #Ansible: cron log */2 * * * * logger "EX294 exam in progress" node1 | CHANGED | rc=0 >> #Ansible: cron log */2 * * * * logger "EX294 exam in progress" node2 | CHANGED | rc=0 >> #Ansible: cron log */2 * * * * logger "EX294 exam in progress"

Q16: Create & use a logical volume: Create a playbook called /home/devops/tasks/playbook16.yml that runs on all the managed nodes and does the following:

  • Creates a logical volume with the following requirements:
    • The logical volume is created in the developer volume group.
    • The logical volume name is data.
    • The logical volume size is 1200 Mib.
    • Format the logical volume with the ext file-system.
    • If the requested logical volume size cannot be created, the error message "could not create logical volume of that size" should be displayed and size 800 MiB should be used instead.
    • If the volume research does not exist, the error message "volume group does not exist" should be displayed.
    • Don't mount the logical volume in any way.
[devops@ansible-server tasks]$ vim playbook16.yml [devops@ansible-server tasks]$ cat playbook16.yml - name: Playbook16 hosts: all tasks: - name: block,rescue,always block: - name: If VG not present ansible.builtin.debug: msg: "volume group does not exist" when: ansible_facts['lvm']['vgs']['research'] is not defined - name: Create a logical volume of 1200m community.general.lvol: vg: research lv: data size: 1200 when: ansible_facts['lvm']['vgs']['research'] is defined rescue: - name: If VG size is not sufficient ansible.builtin.debug: msg: "could not create logical volume of that size" when: ansible_facts['lvm']['vgs']['research'] is defined - name: Create a logical volume of 800m community.general.lvol: vg: research lv: data size: 800 when: ansible_facts['lvm']['vgs']['research'] is defined always: - name: Create a ext4 community.general.filesystem: fstype: ext4 dev: /dev/research/data when: ansible_facts['lvm']['vgs']['research'] is defined [devops@ansible-server tasks]$ ansible-playbook playbook16.yml
All systems normal

© 2025 2023 Sanjeeb KC. All rights reserved.