Skip to content

torshin5ergey/ansible-puzzle-labs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

72 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ansible.puzzle.ch labs

My solutions to Ansible Puzzle labs with VirtualBox and Terraform

1. Setting up Ansible

https://ansible.puzzle.ch/docs/01/

Task 1

  • Install Ansible on controller (localhost)
sudo apt update && sudo apt install ansible -y

Task 3

  • Ping hosts
ansible all:!controller -i inventory/hosts -m ping

Task 5

hosts

2. Documentation

https://ansible.puzzle.ch/docs/02/

Task 1

  • List all ansible modules
ansible-doc --list

3. Setup and Ad Hoc Commands

https://ansible.puzzle.ch/docs/03/

Task 1

  • Ping all nodes with ansible.builtin.ping
ansible nodes -i inventory/hosts -m ping

Task 2

  • Gather all facts from nodes
ansible nodes -i inventory/hosts -m gather_facts
# or
ansible nodes -i inventory/hosts -m setup
  • Gather only ansible_default_ipv4 fact from all nodes
ansible nodes -i inventory/hosts -m setup -a "filter=ansible_default_ipv4"

Tasks 3-4

  • Find module with hostname
ansible-doc -l | grep hostname
ansible-doc -s hostname

Task 5

  • Setup hostname on all hosts using the inventory
ansible nodes -i inventory/hosts -b -m hostname -a "name={{ inventory_hostname }}"
ansible nodes -i inventory/hosts -a "cat /etc/hostname"

Task 6

  • Install apache2 on web
ansible web inventory/hosts -b -m apt -a "name=apache2 state=installed"
  • Start and enable apache2
ansible web inventory/hosts -b -m systemd -a "name=apache2 state=started enabled=true"
  • Revert changes
ansible web -i inventory/hosts -b -m systemd -a "name=apache2 state=stopped enabled=false"
ansible web -i inventory/hosts -b -m apt -a "name=apache2 state=absent"

Task 7

  • Create file /etc/ansible/testfile.txt on ap-worker-node2
ansible ap-worker-node2 -i inventory/hosts -m file -a "path=/home/ansible/testfile.txt state=touch"
  • Paste custom test into the file using copy module
ansible ap-worker-node2 -i inventory/hosts -m copy -a "dest=/home/ansible/testfile.txt content='custom text'"
  • Remove the file
ansible ap-worker-node2 -i inventory/hosts -m file -a "path=/home/ansible/testfile.txt state=absent"

4. Ansible Playbooks - Basics

https://ansible.puzzle.ch/docs/04/

Tasks 1

04-webserver.yaml

Task 2

  • Create user config file
echo "[defaults]\ninventory = /home/ansible/techlab/inventory/hosts" > ansible.cfg

Task 4

04-tempfolder.yaml

4.1. Ansible Playbooks - Variables and Loops

https://ansible.puzzle.ch/docs/04/01/

Tasks 1-2

04-webserver.yaml

Task 3-5

04-motd.yaml

  • Set variable via command line
ansible-playbook playbooks/04-motd.yaml --extra-vars motd_content="new text\n"
  • Play playbook and limit nodes to ap-worker-node1 and ap-worker-node2
ansible-playbook playbooks/04-motd.yaml -l ap-worker-node1,ap-worker-node2

Task 7

04-takemehome.yaml

4.2. Ansible Playbooks - Templates

https://ansible.puzzle.ch/docs/04/02/

Task 1-2

Task 3

Task 4

4.3. Ansible Playbooks - Output

https://ansible.puzzle.ch/docs/04/03/

Tasks 1-3

04-output.yaml

Task 4

  • Ensure httpd is stopped on the group web by using an Ansible ad hoc command.
ansible web -b -a "systemctl stop apache2"

04-servicehandler.yaml

Task 5

  • By using an ansible ad hoc command, place an invalid configuration file /etc/httpd/conf/httpd.conf and backup the file before. Use the ansible.builtin.copy module to do this in ad hoc command. ansible.builtin.copy
ansible web -b -m copy -a "content='invalid config' dest=/etc/apache2/apache2.conf backup=true"
  • Restart httpd by using an Ansible ad hoc command. This should fail since the config file is not valid.
ansible web -b -m systemd -a "name=apache2 state=restarted"

04-servicehandler.yaml

4.4. Ansible-Pull

https://ansible.puzzle.ch/docs/04/04/

Task 2

04-install-ansible-pull.yaml

  • Use an ansible-pull command that uses the resources in the folder resources/ansible-pull/ of our GitHub repository located at https://github.com/puzzle/ansible-techlab. Apply the playbook local.yml located at the resource/ansible-pull folder and run it on all hosts in the inventory file hosts
ansible-pull --url https://github.com/puzzle/ansible-techlab -i resources/ansible-pull/hosts resources/ansible-pull/local.yml
  • Show the content of /etc/motd and verify, that the file was copied using ansible-pull
cat /etc/motd
  • Also verify, that no content of the git repository was copied to the local folder.
ls -l

Task 3

  • Cron job
# /etc/cron.d/ansible-pull
* * * * * vagrant ansible-pull -U https://github.com/puzzle/ansible-techlab -i resources/ansible-pull/hosts resources/ansible-pull/local.yml
  • Command watch to show the content of /etc/motd every second
watch -n 1 cat /etc/motd

Task 4

04-revert_motd.yaml

4.5. Task control

https://ansible.puzzle.ch/docs/04/05/

Task 1

  • Write an ad-hoc command that sleeps for 1000 seconds and runs on node1. Ensure that the command times out after 10 seconds if not completed by then.
ansible ap-worker-node1 -B 10 -a "sleep 1000"
  • Use the time command to see how long your ad-hoc command had to run. Use man time to see how time works.
# -B, --background run asynchronously, failing after N seconds
time ansible ap-worker-node1 -B 10 -a "sleep 1000"
  • Now add a polling interval of 30 seconds. Run the task, and ensure with the time command, that it had a longer runtime.
# -P, --poll poll interval for background tasks
time ansible ap-worker-node1 -B 10 -P 30 -a "sleep 1000"

Tasks 2-3

04-async.yaml

5. Ansible Roles - Basics

https://ansible.puzzle.ch/docs/05/

Task 1

ansible.cfg

Task 2

roles/apache2/

roles/apache2
├── defaults
│   └── main.yml
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── README.md
├── tasks
│   └── main.yml #
├── templates
├── tests
│   ├── inventory
│   └── test.yml
└── vars
    └── main.yml

Task 3

05-webserver.yaml

Task 4

roles/base
├── defaults
│   └── main.yml #
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── README.md
├── tasks
│   ├── main.yml #
│   ├── motd.yaml #
│   └── packages.yaml #
├── templates
│   └── motd.j2 #
├── tests
│   ├── inventory
│   └── test.yml
└── vars
    └── main.yml

Task 5

roles/base
├── defaults
│   └── main.yml #
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml #
├── README.md
├── tasks
│   ├── main.yml #
│   ├── motd.yaml #
│   └── packages.yaml #
├── templates
│   └── motd.j2 #
├── tests
│   ├── inventory
│   └── test.yml
└── vars
    └── main.yml

5.1. Ansible Roles - Handlers and Blocks

https://ansible.puzzle.ch/docs/05/01/

Tasks 1

roles/handlerrole
├── defaults
│   └── main.yml
├── files
├── handlers
│   └── main.yml #
├── meta
│   └── main.yml
├── README.md
├── tasks
│   ├── main.yml #
│   └── timestamp.yaml #
├── templates
│   └── readme.j2 #
├── tests
│   ├── inventory
│   └── test.yml
└── vars
    └── main.yml

Task 2

  • 05-download.yaml
  • roles/downloader/ roles/downloader ├── defaults │ └── main.yml ├── files ├── handlers │ └── main.yml ├── meta │ └── main.yml ├── README.md ├── tasks │ ├── downloadfile.yaml # │ └── main.yml # ├── templates ├── tests │ ├── inventory │ └── test.yml └── vars └── main.yml

6. Managing Secrets with Ansible Vault

https://ansible.puzzle.ch/docs/06/

Task 1

ansible nodes -a "cat /etc/MI6"

Task 2

Task 3

  • Encrypt the secret_vars.yaml file by using ansible-vault with the password goldfinger.
ansible-vault encrypt playbooks/secret_vars.yaml
# New Vault password:
# Confirm New Vault password:
  • Rerun the playbook providing the password for decrypting secret_vars.yaml at the command prompt.
ansible-playbook playbooks/06-secretservice.yaml --ask-vault-pass
  • Rerun the playbook providing the password for decrypting secret_vars.yaml from the file vaultpassword. vaultpassword
# decrypt
ansible-vault decrypt playbooks/secret_vars.yaml

# encrypt with vault id
ansible-vault encrypt playbooks/secret_vars.yaml --vault-id vaultpassword
# run with vault id
ansible-playbook playbooks/06-secretservice.yaml --vault-id vaultpassword

Task 4

ansible.cfg

Task 5

  • Decrypt the file secret_vars.yaml.
ansible-vault decrypt playbooks/secret_vars.yaml
# Decryption successful
  • Encrypt the values of the variables username and password and put them into the secret_vars.yaml file.
ansible-vault encrypt_string jamesbond -n var_username
# Encryption successful
ansible-vault encrypt_string miss_moneypenny -n var_password
# Encryption successful

ansible-playbook playbooks/06-secretservice.yaml

secret_vars.yaml

Task 6

  • Remove the /etc/MI6 file on the nodes using an ad hoc command.
ansible nodes -b -a "rm /etc/MI6"
# or
ansible nodes -b -m file -a "path=/etc/MI6 state=absent"

Task 7

  • Encrypt another file secret_vars2.yaml. Ensure it is encrypted with your vault password file vaultpassword
ansible-vault encrypt playbooks/secret_vars2.yaml

secret_vars2.yaml

  • Change the encryption of the file: encrypt it with another password provided at the command line.
ansible-vault rekey playbooks/secret_vars2.yaml --new-vault-id @prompt
# New vault password (default): test
# Confirm new vault password (default): test
# Rekey successful

# Test
ansible-vault decrypt playbooks/secret_vars2.yaml --output - --vault-id @prompt
# or
ansible-vault view playbooks/secret_vars2.yaml --vault-id @prompt

# Vault password (default): test
# ---
# var_username: jamesbond
# var_password: miss_moneypenny

Task 8

7. Ansible Galaxy and more

https://ansible.puzzle.ch/docs/07/

Task 1

ansible-galaxy search nginx | grep nginxinc
  • Install such a nginx role using ansible-galaxy.
ansible-galaxy install nginxinc.nginx
  • Create a tar.gz file nginx.tar.gz with the content of the role using an Ansible ad hoc command.
ansible controller -m archive -a "path=$HOME/ansible-puzzle-labs/ansible/roles/nginxinc.nginx dest=$HOME/ansible-puzzle-labs/ansible/nginx.tar.gz"

Task 2

  • Remove the nginx role using ansible-galaxy.
ansible-galaxy remove nginxinc.nginx
  • 07-requirements.yaml
  • Install the role by using an appropriate ansible-galaxy command and the requirements.yml file.
ansible-galaxy install -r roles/07-requirements.yaml
  • Remove the role mynginx using ansible-galaxy.
ansible-galaxy remove mynginx
  • Remove the file nginx.tar.gz and roles/requirements.yml by using an ad hoc command for each.
ansible controller -m file -a "path=$HOME/ansible-puzzle-labs/ansible/nginx.tar.gz state=absent"

ansible controller -m file -a "path=$HOME/ansible-puzzle-labs/ansible/roles/07-requirements.yaml state=absent"

8. Ansible Collections

https://ansible.puzzle.ch/docs/08/

Task 1

  • Create a collection with the ansible-galaxy collection command. Choose a namespace and a collection name of your liking.
ansible-galaxy collection init --init-path collections puzzle.mycollection

/collections/puzzle/mycollection/

Task 2

  • Build a collection from your newly initialized collection-skeleton. Have a close look at the name that was set.
ansible-galaxy collection build collections/puzzle/mycollection --output-path collections
  • Change the namespace and collection name in the file galaxy.yml in the skeleton. galaxy.yml
  • Rebuild the collection and see the new name.
ansible-galaxy collection build collections/puzzle/mycollection --output-path collections

Task 3

  • Install one of your newly built collections from the tar.gz file. See where it was installed.
ansible-galaxy collection install collections/puzzle-mycollection-1.0.0.tar.gz
# ...
# Installing 'puzzle.mycollection:1.0.0' to '/home/sergey/.ansible/collections/ansible_collections/puzzle/mycollection'
# ...
  • Change the ansible configuration so that the collection gets installed at /home/ansible/techlab/collections. ansible.cfg collections_paths

Task 4

  • Use ansible-config dump to see what default galaxy server is configured
ansible-config dump
# ...
# GALAXY_SERVER_LIST(default) = None
# ...
  • Add another galaxy server to your GALAXY_SERVER_LIST. This entry can point to a nonexistent galaxy server. ansible.cfg server_list
  • Set it explicitly to galaxy.ansible.com in the ansible.cfg file, even though this is the default value. ansible.cfg [galaxy_server.mygalaxyserver]

Task 5

  • Install the collection nginxinc.nginx_controller using the ansible-galaxy command.
ansible-galaxy collection install nginxinc.nginx_controller
  • Write a requirements file requirements.yml that ensures the collection cloud from cloudscale_ch is installed. Install the collection by using this requirements file. 08-requirements.yaml
ansible-galaxy collection install --requirements-file collections/08-requirements.yaml

Task 6

  • Install the collection podman from namespace containers using any of the methods you know.
ansible-galaxy collection install containers.podman --force
ansible-playbook playbooks/08-collection.yaml --ask-become-pass

sudo podman ps

Task 7

  • Remove podman with an ad-hoc command to not interfere with the next labs.
ansible controller -b -m apt -a "name=podman state=absent purge=true autoremove=true" --ask-become-pass

9.1. AWX / Ascender / AAP / Installation

https://ansible.puzzle.ch/docs/09/01/

Task 1

Tasks 2-3

https://ansible-community.github.io/awx-operator-helm/

helm repo add awx-operator https://ansible-community.github.io/awx-operator-helm/

kubectl apply -f awx/00-namespace.yaml

helm install awx-operator awx-operator/awx-operator -n awx

mkdir /mnt/awx-storage
chown -R 26:26 /mnt/awx-storage
chmod -R 750 /mnt/awx-storage

kubectl apply -f awx/
kubectl get pods -n awx

Task 4

kubectl get svc ansible-awx-service -n awx

# <minikube ip>:<nodeport>

# username admin
# password
kubectl get secret ansible-awx-admin-password -o jsonpath="{.data.password}" -n awx | base64 --decode ; echo

10. Ansible-Navigator

https://ansible.puzzle.ch/docs/10/

Task 1

https://ansible.readthedocs.io/projects/navigator/installation/

# Ready to run
ansible-navigator

Task 2

Task 3

10-site.yaml

Task 4

  • Run the playbook site.yml by using ansible-navigator and the configuration from Task 2.
ansible-navigator
:run playbooks/10-site.yaml
# Or
ansible-navigator run playbooks/10-site.yaml
  • While running the playbook, check in another terminal window if the container gets startet and stopped. You can do this by issuing watch podman container list.
watch docker ps

Task 5

  • After a successful run of your playbook, we play around with the TUI. Be sure to not let ansible-navigator run in interactive mode and not stdout mode (-m stdout). Since interactive is the default, you shouldn’t have any problems with that.
ansible-navigator run playbooks/10-site.yaml
# Or
ansible-navigator run playbooks/10-site.yaml -m interactive

Task 6

  • Use ansible-navigator to see the documentation of the file module.
ansible-navigator
:doc file
# Or
ansible-navigator doc file
  • Use ansible-navigator to see the documentation of the dig lookup plugin.
ansible-navigator
:doc dig -t lookup
# Or
ansible-navigator doc dig -t lookup

Task 7

  • Use ansible-navigator to see the current inventory.
ansible-navigator
:inventory
# Or
ansible-navigator inventory

Task 8

  • Use ansible-navigator to see the current ansible configuration.
ansible-navigator
:config
# Or
ansible-navigator config

Task 9

  • Replay the run by using ansible-navigator with the corresponding option.
ansible-navigator replay artifacts/10-site-artifact...

Task 10

  • Use ansible-navigator to show all available collections.
ansible-navigator
:collections
# Or
ansible-navigator collections

10.1. Ansible-Builder

https://ansible.puzzle.ch/docs/10/01/

Task 1

ansible-builder -h

Task 2

  • Create a playbook container.yml that installs podman and pulls the image docker.io/bitnami/mariadb on all db servers. 10-continer.yaml
  • Run this playbook and observe how it fails because the collection containers.podman is not available in the demo EE ansible-navigator-demo-ee.
ansible-navigator run playbooks/10-container.yaml

Tasks 3-5

ansible-builder build -f 10-default-ee.yaml -t default-ee -vvv

ansible-navigator images

Task 6

10.2. Ansible Runner

https://ansible.puzzle.ch/docs/10/02/

Task 1

ansible-runner --version
ansible-runner --help

Task 2

.
...
├── inventory
│   └── hosts # without extension
└── project
    └── 10-site.yaml
...
  • Use ansible-runner to run the play site.yml.
ansible-runner run . -p 10-site.yaml

Task 3

artifacts/

Task 4

.
├── env
│   ├── settings
│   └── ssh_key
├── inventory
│   └── hosts
└── project
    └── 10-site.yaml

11.1. Event Driven Ansible - Basics

https://ansible.puzzle.ch/docs/11/01/

Task 1

https://ansible.readthedocs.io/projects/rulebook/en/latest/rulebooks.html

python3 -m pip install ansible-rulebook

ansible-rulebook -h

Task 2

Task 3

ansible-galaxy collection install ansible.eda

Task 4

  • Start webserver_rulebook.yml in verbose mode.
ansible-rulebook --rulebook 11-webserver_rulebook.yaml -i inventory/hosts --verbose

Task 5

  • Write the rulebook webhook_rulebook.yml that opens a webhook on port 5000 of the control node control0. 11-webhook_rulebook.yaml

Task 6

  • Run the rulebook webhook_rulebook.yml in verbose mode.
ansible-rulebook --rulebook 11-webhook_rulebook.yaml -i inventory/hosts --verbose
  • Send the string “webservers running” to the webhook.
curl -H 'Content-Type: application/json' -d "{\"message\": \"webservers running\"}" 127.0.0.1:5000/endpoint
  • Now send the message “webservers down” to the webhook. See how the playbook webserver.yml is run.
curl -H 'Content-Type: application/json' -d "{\"message\": \"webservers down\"}" 127.0.0.1:5000/endpoint

Task 7

11-complex_rulebook.yaml Run with

ansible-rulebook --rulebook 11-complex_rulebook.yaml -i inventory/hosts --verbose

Check with

curl -H 'Content-Type: application/json' -d "{\"message\": \"webservers down\"}" 127.0.0.1:5000/endpoint

11.2. Event Driven Ansible - Events and Facts

https://ansible.puzzle.ch/docs/11/02/

Task 1

11-debug_event_rulebook.yaml Run with

ansible-rulebook --rulebook 11-debug_event_rulebook.yaml -i inventory/hosts --verbose
# output
...
** 2025-03-26 22:01:37.247327 [debug] ********************************************
event: {'url_check': {'url': 'http://192.168.0.26', 'status': 'down', 'error_msg': "Cannot connect to host 192.168.0.26:80 ssl:default [Connect call failed ('192.168.0.26', 80)]"}, 'meta': {'source': {'name': 'Check webserver', 'type': 'ansible.eda.url_check'}, 'received_at': '2025-03-26T19:01:37.243178Z', 'uuid': 'b7fa6fe6-8e69-4fb8-8cd8-1fc9b7e7083c'}}
...

Task 2

ansible-rulebook --rulebook 11-debug_event_rulebook.yaml -i inventory/hosts --verbose
  • sosreports will be at /tmp/ on node