You are on page 1of 23

(Sander Labs) Samir Shrestha

Lab 4-1
Create a script with the name install.sh that makes sure managed hosts meet the following
requirements. It doesn't matter if the hosts already meet the requirements, your script should
be created such that it sets up a managed host according to these requirements if it has not yet
been configured.
- Install the httpd web server
- Start and enable the httpd web server
- Crate a user with the name anna
- Copy the /etc/hosts file from the control machine to the /tmp directory on the managed hosts.
Solution:

vim install.sh
#!/bin/bash

ansible all -m yum -a "name=httpd state=latest"


ansible all -m service -a "name=httpd state=started enabled=yes"
ansible all -m user -a "name=anna state=present"
ansible all -m copy -a 'src="/etc/hosts" dest=/tmp'

Lab 6-1
Configure a playbook that works with custom facts and meets the following requirements:
 Use the project directory chapter6
 Create an inventory file where ansible1 is member of the host group named file and
ansible2 is member of the host group named lamp.
 Create a custom facts file that contains a section named packages and set the following
variables:
smb_package = samba
ftp_package = vsftpd
db_package = mariadb
web_package = httpd
firewall_package = httpd
 Create another custom facts file that contains a section named services and set the
following variables:
smb_service = smb
ftp_service = vsftpd
db_service = mariadb
web_service = httpd
firewall_service = firewalld
 Create a playbook with the name copy_facts.yaml that copies these facts to all
managed hosts. In this playbook define a variable remote_dir to specify the directory
the fact files should be copied to. Use the variable fact_file to copy the fact files to
appropriate directories.
 Run the playbook and verify whether it works.
mkdir ~/chapter6
vim inventory
[file]
ansible1

[lamp]
ansible2
vim custom.fact
[packages]
smb_package = samba
ftp_package = vsftpd
db_package = mariadb
web_package = httpd
firewall_package = firewalld

[services]
smb_service = smb
ftp_service = vsftpd
db_service = mariadb
web_service = httpd
firewall_service = firewalld

vim copy_facts.yml
---
- name: copy facts to the managed hosts
hosts: all
vars:
remote_dir: /etc/ansible/facts.d
fact_file: custom.fact
tasks:
- name: create fact directory
file:
state: directory
recurse: yes
path: "{{ remote_dir }}"
- name: Transferring custom fact files
copy:
src: "{{ fact_file }}"
dest: "{{ remote_dir }}"

Lab 6-2
After copying over the facts files, create a playbook that uses the fact to set up the rest of the
environment. Make sure it meets the following requirements:
 Use a variable inclusion file with the name allvars.yml and set the following variables:
web_root = /var/www/html
ftp_root = /var/ftp
 Create a playbook that sets up the file services and the web services. Also ensure the
playbook opens the firewalld firewall to provide access to these servers.
 Make sure the webservice provides access to a file index.html, which contains the text
"Welcome to the Ansible Web Server."
 Run the playbook and use ad hoc commands to verify that the services have been
started.
vim allvars.yml
web_root: /var/www/html
ftp_root: /var/ftp

vim index.html
<h1> Welcome to the Ansible Web Server. </h1>
vim setup_with_facts.yml
---
- name: install and start the services
hosts: all
vars_files: allvars.yml
tasks:
- name: install the file and web packages
yum:
name:
- "{{ ansible_facts['ansible_local']['custom']['packages']['ftp_package'] }}"
- "{{ ansible_facts['ansible_local']['custom']['packages']['web_package'] }}"
state: latest
- name: start the file service
service:
name: "{{ ansible_facts['ansible_local']['custom']['services']['ftp_service'] }}"
state: started
enabled: yes
- name: start the web service
service:
name: "{{ ansible_facts['ansible_local']['custom']['services']['web_service'] }}
state: started
enabled: yes
- name: open ftp service to the firewall
firewalld:
service: ftp
permanent: yes
state: enabled
immediate: yes
- name: open http service to the firewall
firewalld:
service: http
permanent: yes
state: enabled
immediate: yes
- name: copy index.html to managed hosts
copy:
src: index.html
dest: "{{ web_root }}"

ansible-playbook setup_with_facts.yml
ansible all -a "systemctl status smb"
ansible all -a "systemctl status httpd"

LAB 7-1
In this lab, you install and set up an Apache Web Server.
Write a playbook that installs the httpd and mod_ssl packages on host ansible2.
- Write a first play that installs the httpd and mod_ssl packages on host ansible2.
- Use variable inclusion to define the package names in a separate file.
- Use a conditional to loop over the list of packages to be installed.
- Install the packages only if the current operating system is CentOS or RedHat (but not
Fedora) version 8.0 or later. If that is not the case, the playbook should fail with the error
message "Host hostname does not meet minimal requirements," where hostname is replaced
with the current host name.

On the Ansible control host, create a file /tmp/index.html. This file must have the contents
"welcome to my webserver"
- If the file /tmp/index.html is successfully copied to /var/www/html, the web server process
must be restarted. If copying the package fails, the playbook should show an error message.
- The firewall must be opened for the http as well as the https services.
Solution:
vim packages
packages:
- name: httpd
state: latest
- name: mod_ssl
state: latest
vim lab71.yml
---
- name: manage packages httpd and mod_ssl
hosts: ansible2
vars_files: vars/package
tasks:
- name: install package
yum:
name: "{{ item.name }}"
state: "{{ item.state }}"
loop: "{{ packages }}"
ignore_errors: yes
when: ( ansible_facts['distribution'] == "CentOS" or ansible_facts['distribution'] == "RedHat" )
and ansible_facts['distribution_version'] >= "8.0"
- name: report a failure
fail:
msg: Host {{ inventory_hostname }} does not meet minimal requirement
when: ansible_facts['distribution'] == "Fedora" and ansible_facts['distribution_version'] < "8.0"

- name: create file on localhost


hosts: localhost
tasks:
- name: create index.html on localhost
copy:
content: "welcome to my webserver"
dest: /tmp/index.html
- name: copy to /var/www/html
copy:
src: /tmp/index.html
dest: /var/www/html/index.html
register: copy_result
ignore_errors: yes
notify: restart_httpd
- name: show error message
debug:
msg: "Error copying file to /var/www/html"
when: copy_result.failed
- name: open http and https services in firewall
firewalld:
service: "{{ item }}"
state: enabled
permanent: true
immediate: yes
loop:
- http
- https
handlers:
- name: restart_httpd
service:
name: httpd
state: restarted

Lab 8-1: Generate an /etc/hosts file


Write a playbook that generates an /etc/hosts file on all managed hosts. Apply the following
requirements:
- All hosts that are defined in inventory should be added to the /etc/hosts file.
Solution:
mkdir templates
vim templates/hosts.j2
{% for host in groups['all'] %}
{{ hostvars[host]['ansible_facts']['default_ipv4']['address'] }} {{ hostvars[host]['ansible_facts']
['fqdn'] }} {{ hostvars[host]['ansible_facts']['hostname'] }}
{% endfor %}

vim hostsfile.yml
---
- name: update /etc/hosts file dynamically
hosts: all
tasks:
- name: update /etc/hosts
template:
src: hosts.j2
dest: /etc/hosts
Run the playbook
ansible all -a "cat /etc/hosts" (to verify)

Lab 8-2: Manage a vsftpd service


Write a playbook that uses at least two plays to install a vsftpd service, configure the vsftpd
service using templates, and configure permissions as well as SELinux. Apply the following
requirements:
- Install, start and enable the vsftpd service. Also, open a port in the firewall to make it
accessible.
- Use the /etc/vsftpd/vsftpd.conf file to generate a template. In this template, you should use
the following variables to configure settings. Replace these settings with the variables and
leave all else unmodified:
- Anonymous_enable: yes
- Local_enable: yes
- Write_enable: yes
- Anon_upload_enable: yes
- Set permissions on the /var/ftp/pub directory to mode 0777.
- Configure the ftpd_anon_write Boolean to allow anonymous user writes.
- Set the public_content_rw_t SELinux context type to the /var/ftp/pub directory.

Solution:

Playbook outline:
3 different plays
i. get basic vsftpd operational
- install
- start and enable
- open port in firewall

ii. configure vsftpd using a template


- define variables to use them in template
- use template module to copy FTP config

iii. Configure vsftpd permissions and selinux


- install require selinux tools
- set permission directory
- set selinux boolean
- manage selinux settings

vim templates/vsftpd.j2
anonymous_enable={{ anonymous_enable }}
local_enable={{ local_enable }}
write_enable={{ write_enable }}
anon_upload_enable={{ anon_upload_enable }}
dirmessage_enable=YES
xferlog_enable=YES
connect_from_port_20=YES
pam_service_name=vsfpd
userlist_enable=YES
# my_IP_Address={{ ansible_facts['default_ipv4']['address'] }}

---
- name: get basic vsftpd operational
hosts: all
tasks:
- name: install vsftpd
yum:
name: vsftpd
state: latest
- name: start and enable vsftpd
service:
name: vsftpd
state: started
enabled: yes
- name: open port in firewall
firewalld:
service: ftp
state: enabled
permanent: yes
immediate: yes

- name: configure vsftpd using a template


hosts: all
vars:
anonymous_enable: yes
local_enable: yes
write_enable: yes
anon_upload_enable: yes
tasks:
- name: use template to copy FTP config
template:
src: vsftpd.j2
dest: /etc/vsftpd/vsftpd.conf

- name: configure vsftpd permissions and selinux


hosts: all
tasks:
- name: install required selinux tools
yum:
name: policycoreutils-python-utils
state: latest
- name: set permissions
file:
path: /var/ftp/pub
mode: '0777'
- name: set selinux boolean
seboolean:
name: ftpd_anon_write
state: yes
persistent: yes
- name: manage selinux settings
sefcontext:
target: /var/ftp/pub
setype: public_content_rw_t
state: present
notify: run restorecon

handlers:
- name: run restorecon
command: restorecon -vR /var/ftp/pub

Lab 9-1
Create a playbook that starts the Nginx web server on ansible1, according to the following
requirements:
- A requirements file must be used to install the Nginx web server. Do NOT use the latest
version of the Galaxy role, but instead use the version before that.
- The same requirements file must also be used to install the latest version of postgresql.
- The playbook needs to ensure that neither httpd nor mysql is currently installed.
Solution:
mkdir roles
vim requirements.yml
# install the Nginx web server (not the LATEST)
- src: geerlingguy.nginx
version: "3.1.3"

# install the latest version of postgresql


- src: geerlingguy.postgresql

ansible-galaxy install -r roles/requirements -p roles (to install in roles directory)

vim lab91.yml
---
- name: lab91
hosts: ansible1
become: true
roles:
- geerlingguy.nginx
- geerlingguy.postgresql
tasks:
- name: Ensure neither httpd or mysql is currently installed
dnf:
name:
- httpd
- mysql
state: absent
Run the playbook
to verify,
ansible ansible1 -m shell -a 'systemctl is-active nginx ; systemctl is-active postgresql'
ansible ansible1 -m shell -a 'systemctl is-enabled nginx ; systemctl is-enabled postgresql'

Lab 9-2
Use the RHEL SELinux System Role to manage SELinux properties according to the
following requirements:
- A Boolean is set to allow SELinux relabeling to be automated using cron.
- The directory /var/ftp/uploads is created, permissions are set to 777, and the context label is
set to public_content_rw_t.
- SELinux should allow web servers to use port 82 instead of port 80.
- SELinux is in enforcing state.
Solution:
As usual while working with RHEL System roles, the most important thing to look out is variables.
In this particular case, 5 variables are needed
1. selinux_booleans
2. selinux_fcontexts
3. selinux_restore_dirs
4. selinux_ports
5. selinux_state
which can be explored in /usr/share/doc/rhel-system-roles/selinux/README.md
Before begin one thing to note, that if there is any task to be performed extra, then either the
solution is 'pre_tasks' or 'include_task'. But no need to worry about that since we are gonna go with
the sample playbook. in this case, creating a directory

---
- name: Manage SELinux policy example
hosts: ansible1.example.com
vars:
selinux_state: enforcing
selinux_booleans:
- name: 'cron_can_relabel' (to get this boolean first do `getsebool -a | grep cron`)
state: 'on'
persistent: 'yes'
selinux_fcontexts:
- target: '/var/ftp/uploads/'
setype: 'public_content_rw_t'
ftype: 'd'
state: 'present'
selinux_restoredirs:
- /var/ftp/uploads
selinux_ports:
- ports: '82'
proto: 'tcp'
setype: 'http_port_t'
state: 'present'
tasks:
- name: Creates directory
file:
path: /var/ftp/uploads
state: directory
mode: "0777"
- name: Execute the role and catch errors
block:
- name: Include selinux role
include_role:
name: rhel-system-roles.selinux
rescue:
- name: Handle errors
fail:
msg: "role failed"
when: not selinux_reboot_required
- name: Restart managed host
reboot:

- name: Wait for managed host to come back


wait_for_connection:
delay: 10
timeout: 300

- name: Reapply the role


include_role:
name: rhel-system-roles.selinux

Lab 10-1
The lab82.yaml file, which can find in the GitHub repository that goes with this course, is an
optimal candidate for optimization. Optimize this playbook according to the following
requirements:
- Use includes and import to make this a modular playbook where different files are used to
distinguish between the different tasks.
- Optimize this playbook such that it will run on no more than two hosts at the same time and
completes the entire playbook on these two hosts before continuing with the next host.

Scanerio
handlers is getting error in the task file while importing/including tasks from the main
playbook. Does handlers have to be written in main playbook.? (no roles)

Lab 11-1
The lesson11-lab.yaml playbook contains some errors. Fix them accroding to the following
instructions:
a. Use command-line tools and arguments to find the errors. Don't fix them by just reading
the YAML file, even if some errors are obvious.
b. After fixing an error in one task, start running the playbook with the next task. Try to avoid
running the same task over and over again.
c. Before applying the template, use a dry-run and a diff to see what the template will change
d. Use the debug module where neccessary
Solution:
a. ansible-playbook lesson11-lab.yaml --syntax-check
b. ansible-playbook --start-at-task="task name" lesson11-lab.yaml
c. ansible-playbook lesson11-lab.yaml --check --diff (this will give you the idea of what will be
changed)
In order to shorten the playbook, use the template instead of two tasks (which basically does the
same thing of changing some line)
vim lab111-httpd.j2
DocumentRoot "{{ newdoc_root }}"

<Directory "{{ newdoc_root }}"> (this in the place of '/var/www' not in '/var/www/html'

The complete playbook will look something like this


---
- name: Managing web server SELinux properties
hosts: ansible1
vars:
package: httpd
service: httpd
message: warning! authorized use only
newdoc_root: /web
tasks:
- name: ensure SELinux is enabled and enforcing
selinux:
policy: targeted
state: enforcing
- name: install the webserver
yum:
name: "{{ package }}"
state: latest
- name: start and enable the webserver
service:
name: "{{ service }}"
state: started
enabled: yes
- name: open the firewall service
firewalld:
service: http
immediate: yes
permanent: yes
state: enabled
- name: create the /web directory
file:
name: /web
state: directory
- name: create the index.html file in /web
copy:
content: "{{ message }}"
dest: /web/index.html
- name: copy template file
template:
src: lab111-httpd.j2
dest: /etc/httpd/conf/httpd.conf
- name: use sefcontext to set context on new documentroot
sefcontext:
target: '/web(/.*)?'
setype: httpd_sys_content_t
state: present
- name: run the restorecon command
command: restorecon -Rv /web
- name: allow the web server to run user content
seboolean:
name: httpd_read_user_content
state: yes
persistent: yes

Lab 12-1
Configure the control.example.com host as a repository server, according to the following
requirements:
- Create a directory with the name /repo, and in that directory copy all packages that have a
name starting with nginx.
- Generate the metadata that makes this directory a repository.
- Configure the Apache web server to provide access to the repository server. You just have to
make sure that the DocumentRoot in Apache is going to set to the /repo directory (not exactly)

LAB 12-2
Write a playbook to configure all managed servers according to the following requirements:
- All hosts can access the repository that was created in Lab 12-1.
- Have the same playbook install the nginx package
- DO NOT start the service. Use the appropriate module to gather information about the
installed nginx package, and let the playbok print a message starting the name of the nginx
package as well as the version.

Solution:
vim lab121-server.yml
---
- name: install, configure, start and enable http
hosts: localhost
ignore_errors: yes
tasks:
- name: install http server
yum:
name: httpd
state: latest
- name: apply modifications to configuration file
blockinfile:
path: /etc/httpd/conf/httpd.conf
block: |
DocumentRoot "/repo"
<Directory "/repo">
Options ALL Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
# for this reason 'ignore_errors' is included because the directory doesn't exist yet and starting the
service will fail. This task is changing the default DocumentRoot and shortening the URL to just
http://control.example.com not http://control.example.com/repo
- name: start and enable the service
service:
name: httpd
enabled: yes
state: latest

- name: setup the repo directory


hosts: localhost
tasks:
- name: make directory
file:
path: /repo
state: directory
- name: give access to apache user
acl:
path: /repo/
entity: apache
etype: user
permissions: rwx
default: true (recursive apply of the permissions)
state: present
- name: change SELinux context
file:
path: /repo/
recurse: yes
setype: httpd_sys_content_t (file module on the file directly not on the policy level)
- name: download packages without installing them
yum:
name: nginx
download_only: yes
download_dir: /repo/ (notice no state)
- name: install createrepo package
yum:
name: createrepo_c
state: latest
- name: createrepo
command: createrepo /repo
notify:
- restart_httpd
handlers:
- name: restart_httpd
service:
name: httpd
state: restarted

vim lab122-client.yml
---
- name: configure repository
hosts: all
vars:
my_package: nginx
tasks:
- name: connect to example repository
yum_repository:
name: lab123
description: RHCE9 exercise123 repository
file: lab123
baseurl: http://control.example.com (notice no need of /repo)
gpgcheck: no
- name: ensure control is resolvable
lineinfile:
path: /etc/hosts
line: 192.168.122.170 control.example.com control
- name: install package
yum:
name: "{{ my_package }}"
state: present
- name: update package facts
package_facts:
manager: auto
- name: show package facts for {{ my_package }}
debug:
var: ansible_facts.packages[my_package]
when: my_package in ansible_facts.packages

Lab 13-1 Write a playbook that creates users according to the following specifications:
- Create users kim, christina, kelly, and bill.
- Users kim and kelly must be members of the profs group; users christina and bill are
members of the students group.
- While creating the users, set the encrypted password to "password"
- Ensure that the members of the group profs have sudo privileges.
Solution:
vim lab131-vars.yml
users:
- name: kim
groups: profs
- name: kelly
groups: profs
- name: christina
groups: students
- name: bill
groups: students

vim lab131.yml
---
- name: setting up users and properties
hosts: ansible2
vars_files:
- lab131-vars.yml
tasks:
- name: set up groups
group:
name: "{{ item.groups }}"
loop: "{{ users }}"
- name: set up users with encrypted password
user:
name: "{{ item.name }}"
groups: "{{ item.groups }}"
password: $6$mysecretsalt$MI
loop: "{{ users }}"
- name: give group profs sudo privileges
copy:
content: '%profs ALL=(ALL) NOPASSWD:ALL'
dest: /etc/sudoers.d/profs

Lab 14-1
Write a playbook according to the following specifications:
- The cron module must be used to restart your managed servers at 2 a.m. each weekday
- After rebooting, a message must be written to syslog, with the text "CRON initiated reboot
just completed."
- The default systemd target must be set to multi-user.target
- The last task should use service_facts to show the current version of the cron process.
Solution:
---
- name: lab141
hosts: all
tasks:
- name: restart your managed servers
cron:
name: "reboot you nodes"
weekday: "1-5"
minute: "0"
hour: "2"
job: "/sbin/reboot"
- name: run a cron job on reboot
cron:
name: "run on reboot"
state: present
special_time: reboot
job: '/usr/bin/logger "CRON initiated reboot just completed."'
- name: set target to multi-user.target
file:
src: /usr/lib/systemd/system/multi-user.target
dest: /etc/systemd/system/default.target
state: link
- name: show the current version of the cron process
service_facts:
- debug:
var: ansible_facts.services['crond.service']

Lab 15-1 Write a playbook to clean up the second disk that was configured on the managed
hosts.
Solution:
---
- name: clean up hosts that have an vdb device
hosts: all
tasks:
- name: ensure that second disk exists
fail:
msg: there is no second disk
when: ansible_facts['devices']['vdb'] is not defined
- name: unmount the filesystem
mount:
path: /file
state: absent (if you don't do this step, then the managed nodes will go to the emergency
mode)
- name: clean the disks
command: dd if=/dev/zero of=/dev/vdb bs=1M count=10
- name: reboot the machine
reboot:
msg: reboot initiated by ansible
test_command: whoami
- name: show the message
debug:
msg: successfully rebooted

You might also like