From 7cb6997da965bc6353b924a9bf0afec6af6e4b2a Mon Sep 17 00:00:00 2001 From: Shaun S Date: Mon, 21 Mar 2022 17:17:54 +0000 Subject: [PATCH] Initial Commit --- .gitattributes | 2 + 9781484281727.JPG | Bin 0 -> 32938 bytes Contributing.md | 14 ++ LICENSE.txt | 27 ++++ README.md | 16 ++ Vagrantfile | 82 ++++++++++ chapter02/ansible.cfg | 3 + chapter02/hosts | 2 + chapter03/ansible.cfg | 3 + chapter03/hosts | 17 ++ chapter03/inventory/load_balancers | 4 + chapter03/inventory/webservers | 9 ++ chapter03/ranges | 2 + chapter03/regional | 24 +++ chapter04/ansible.cfg | 3 + chapter04/files/index.html | 1 + chapter04/inventory/load_balancers | 4 + chapter04/inventory/webservers | 9 ++ chapter04/webservers.yml | 15 ++ chapter05/ansible.cfg | 4 + chapter05/exploring-apt.yml | 15 ++ chapter05/files/index.html | 1 + chapter05/inventory/load_balancers | 4 + chapter05/inventory/webservers | 9 ++ chapter05/upgrade.yml | 12 ++ chapter05/webservers.yml | 41 +++++ chapter06/ansible.cfg | 4 + chapter06/files/index.html | 1 + chapter06/inventory/group_vars/all | 2 + chapter06/inventory/group_vars/webservers | 2 + chapter06/inventory/load_balancers | 4 + chapter06/inventory/webservers | 6 + chapter06/upgrade.yml | 15 ++ chapter06/webservers.yml | 48 ++++++ chapter07/ansible.cfg | 4 + chapter07/hostname.yml | 17 ++ chapter07/inventory/group_vars/all | 2 + chapter07/inventory/group_vars/webservers | 2 + chapter07/inventory/load_balancers | 4 + chapter07/inventory/webservers | 6 + chapter07/templates/index.html.j2 | 16 ++ chapter07/templates/nginx-default.j2 | 14 ++ chapter07/upgrade.yml | 15 ++ chapter07/webservers.yml | 48 ++++++ chapter08/ansible.cfg | 4 + chapter08/hostname.yml | 17 ++ chapter08/inventory/group_vars/all | 2 + chapter08/inventory/group_vars/webservers | 2 + chapter08/inventory/load_balancers | 4 + chapter08/inventory/webservers | 6 + chapter08/templates/index.html.j2 | 16 ++ chapter08/templates/nginx-default.j2 | 14 ++ chapter08/upgrade.yml | 15 ++ chapter08/webservers.yml | 52 +++++++ chapter09/ansible.cfg | 4 + chapter09/inventory/group_vars/all | 2 + chapter09/inventory/group_vars/webservers | 2 + chapter09/inventory/load_balancers | 4 + chapter09/inventory/webservers | 6 + chapter09/roles/firewall/tasks/main.yml | 11 ++ chapter09/roles/webserver/defaults/main.yml | 2 + chapter09/roles/webserver/handlers/main.yml | 15 ++ chapter09/roles/webserver/meta/main.yml | 3 + chapter09/roles/webserver/tasks/main.yml | 23 +++ .../roles/webserver/templates/index.html.j2 | 16 ++ .../webserver/templates/nginx-default.j2 | 14 ++ chapter09/webservers.yml | 8 + chapter10/ansible.cfg | 4 + chapter10/inventory/group_vars/all | 3 + chapter10/inventory/group_vars/webservers | 2 + chapter10/inventory/load_balancers | 4 + chapter10/inventory/webservers | 6 + chapter10/provision.yml | 20 +++ chapter10/roles/firewall/tasks/main.yml | 15 ++ .../roles/load_balancer/handlers/main.yml | 6 + chapter10/roles/load_balancer/meta/main.yml | 3 + chapter10/roles/load_balancer/tasks/main.yml | 42 +++++ .../load_balancer/templates/backends.cfg.j2 | 6 + .../load_balancer/templates/frontend.cfg.j2 | 4 + chapter10/roles/webserver/defaults/main.yml | 2 + chapter10/roles/webserver/handlers/main.yml | 15 ++ chapter10/roles/webserver/meta/main.yml | 3 + chapter10/roles/webserver/tasks/main.yml | 25 +++ .../roles/webserver/templates/index.html.j2 | 16 ++ .../webserver/templates/nginx-default.j2 | 14 ++ chapter11/ansible.cfg | 4 + chapter11/inventory/databases | 4 + chapter11/inventory/group_vars/all | 11 ++ chapter11/inventory/group_vars/webservers | 2 + chapter11/inventory/load_balancers | 4 + chapter11/inventory/webservers | 6 + chapter11/provision.yml | 35 +++++ chapter11/roles/database/handlers/main.yml | 5 + chapter11/roles/database/tasks/main.yml | 50 ++++++ chapter11/roles/firewall/tasks/main.yml | 15 ++ .../roles/load_balancer/handlers/main.yml | 6 + chapter11/roles/load_balancer/meta/main.yml | 3 + chapter11/roles/load_balancer/tasks/main.yml | 42 +++++ .../load_balancer/templates/backends.cfg.j2 | 7 + .../load_balancer/templates/frontend.cfg.j2 | 4 + chapter11/roles/webserver/defaults/main.yml | 2 + chapter11/roles/webserver/handlers/main.yml | 15 ++ chapter11/roles/webserver/meta/main.yml | 3 + chapter11/roles/webserver/tasks/main.yml | 28 ++++ .../roles/webserver/templates/index.html.j2 | 16 ++ .../webserver/templates/nginx-default.j2 | 23 +++ chapter11/roles/wordpress/tasks/main.yml | 18 +++ .../wordpress/templates/wp-config.php.j2 | 31 ++++ chapter12/ansible.cfg | 5 + chapter12/inventory/databases | 4 + chapter12/inventory/group_vars/all | 23 +++ chapter12/inventory/group_vars/webservers | 2 + chapter12/inventory/load_balancers | 4 + chapter12/inventory/webservers | 6 + chapter12/provision.yml | 35 +++++ chapter12/roles/database/handlers/main.yml | 5 + chapter12/roles/database/tasks/main.yml | 50 ++++++ chapter12/roles/firewall/tasks/main.yml | 15 ++ .../roles/load_balancer/files/website.pem | 146 ++++++++++++++++++ .../roles/load_balancer/handlers/main.yml | 6 + chapter12/roles/load_balancer/meta/main.yml | 3 + chapter12/roles/load_balancer/tasks/main.yml | 47 ++++++ .../load_balancer/templates/backends.cfg.j2 | 7 + .../load_balancer/templates/frontend.cfg.j2 | 5 + chapter12/roles/webserver/defaults/main.yml | 2 + chapter12/roles/webserver/handlers/main.yml | 15 ++ chapter12/roles/webserver/meta/main.yml | 3 + chapter12/roles/webserver/tasks/main.yml | 28 ++++ .../roles/webserver/templates/index.html.j2 | 16 ++ .../webserver/templates/nginx-default.j2 | 23 +++ chapter12/roles/wordpress/tasks/main.yml | 18 +++ .../wordpress/templates/wp-config.php.j2 | 31 ++++ wp-config.php.j2 | 31 ++++ 133 files changed, 1829 insertions(+) create mode 100644 .gitattributes create mode 100644 9781484281727.JPG create mode 100644 Contributing.md create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 Vagrantfile create mode 100644 chapter02/ansible.cfg create mode 100644 chapter02/hosts create mode 100644 chapter03/ansible.cfg create mode 100644 chapter03/hosts create mode 100644 chapter03/inventory/load_balancers create mode 100644 chapter03/inventory/webservers create mode 100644 chapter03/ranges create mode 100644 chapter03/regional create mode 100644 chapter04/ansible.cfg create mode 100644 chapter04/files/index.html create mode 100644 chapter04/inventory/load_balancers create mode 100644 chapter04/inventory/webservers create mode 100644 chapter04/webservers.yml create mode 100644 chapter05/ansible.cfg create mode 100644 chapter05/exploring-apt.yml create mode 100644 chapter05/files/index.html create mode 100644 chapter05/inventory/load_balancers create mode 100644 chapter05/inventory/webservers create mode 100644 chapter05/upgrade.yml create mode 100644 chapter05/webservers.yml create mode 100644 chapter06/ansible.cfg create mode 100644 chapter06/files/index.html create mode 100644 chapter06/inventory/group_vars/all create mode 100644 chapter06/inventory/group_vars/webservers create mode 100644 chapter06/inventory/load_balancers create mode 100644 chapter06/inventory/webservers create mode 100644 chapter06/upgrade.yml create mode 100644 chapter06/webservers.yml create mode 100644 chapter07/ansible.cfg create mode 100644 chapter07/hostname.yml create mode 100644 chapter07/inventory/group_vars/all create mode 100644 chapter07/inventory/group_vars/webservers create mode 100644 chapter07/inventory/load_balancers create mode 100644 chapter07/inventory/webservers create mode 100644 chapter07/templates/index.html.j2 create mode 100644 chapter07/templates/nginx-default.j2 create mode 100644 chapter07/upgrade.yml create mode 100644 chapter07/webservers.yml create mode 100644 chapter08/ansible.cfg create mode 100644 chapter08/hostname.yml create mode 100644 chapter08/inventory/group_vars/all create mode 100644 chapter08/inventory/group_vars/webservers create mode 100644 chapter08/inventory/load_balancers create mode 100644 chapter08/inventory/webservers create mode 100644 chapter08/templates/index.html.j2 create mode 100644 chapter08/templates/nginx-default.j2 create mode 100644 chapter08/upgrade.yml create mode 100644 chapter08/webservers.yml create mode 100644 chapter09/ansible.cfg create mode 100644 chapter09/inventory/group_vars/all create mode 100644 chapter09/inventory/group_vars/webservers create mode 100644 chapter09/inventory/load_balancers create mode 100644 chapter09/inventory/webservers create mode 100644 chapter09/roles/firewall/tasks/main.yml create mode 100644 chapter09/roles/webserver/defaults/main.yml create mode 100644 chapter09/roles/webserver/handlers/main.yml create mode 100644 chapter09/roles/webserver/meta/main.yml create mode 100644 chapter09/roles/webserver/tasks/main.yml create mode 100644 chapter09/roles/webserver/templates/index.html.j2 create mode 100644 chapter09/roles/webserver/templates/nginx-default.j2 create mode 100644 chapter09/webservers.yml create mode 100644 chapter10/ansible.cfg create mode 100644 chapter10/inventory/group_vars/all create mode 100644 chapter10/inventory/group_vars/webservers create mode 100644 chapter10/inventory/load_balancers create mode 100644 chapter10/inventory/webservers create mode 100644 chapter10/provision.yml create mode 100644 chapter10/roles/firewall/tasks/main.yml create mode 100644 chapter10/roles/load_balancer/handlers/main.yml create mode 100644 chapter10/roles/load_balancer/meta/main.yml create mode 100644 chapter10/roles/load_balancer/tasks/main.yml create mode 100644 chapter10/roles/load_balancer/templates/backends.cfg.j2 create mode 100644 chapter10/roles/load_balancer/templates/frontend.cfg.j2 create mode 100644 chapter10/roles/webserver/defaults/main.yml create mode 100644 chapter10/roles/webserver/handlers/main.yml create mode 100644 chapter10/roles/webserver/meta/main.yml create mode 100644 chapter10/roles/webserver/tasks/main.yml create mode 100644 chapter10/roles/webserver/templates/index.html.j2 create mode 100644 chapter10/roles/webserver/templates/nginx-default.j2 create mode 100644 chapter11/ansible.cfg create mode 100644 chapter11/inventory/databases create mode 100644 chapter11/inventory/group_vars/all create mode 100644 chapter11/inventory/group_vars/webservers create mode 100644 chapter11/inventory/load_balancers create mode 100644 chapter11/inventory/webservers create mode 100644 chapter11/provision.yml create mode 100644 chapter11/roles/database/handlers/main.yml create mode 100644 chapter11/roles/database/tasks/main.yml create mode 100644 chapter11/roles/firewall/tasks/main.yml create mode 100644 chapter11/roles/load_balancer/handlers/main.yml create mode 100644 chapter11/roles/load_balancer/meta/main.yml create mode 100644 chapter11/roles/load_balancer/tasks/main.yml create mode 100644 chapter11/roles/load_balancer/templates/backends.cfg.j2 create mode 100644 chapter11/roles/load_balancer/templates/frontend.cfg.j2 create mode 100644 chapter11/roles/webserver/defaults/main.yml create mode 100644 chapter11/roles/webserver/handlers/main.yml create mode 100644 chapter11/roles/webserver/meta/main.yml create mode 100644 chapter11/roles/webserver/tasks/main.yml create mode 100644 chapter11/roles/webserver/templates/index.html.j2 create mode 100644 chapter11/roles/webserver/templates/nginx-default.j2 create mode 100644 chapter11/roles/wordpress/tasks/main.yml create mode 100644 chapter11/roles/wordpress/templates/wp-config.php.j2 create mode 100644 chapter12/ansible.cfg create mode 100644 chapter12/inventory/databases create mode 100644 chapter12/inventory/group_vars/all create mode 100644 chapter12/inventory/group_vars/webservers create mode 100644 chapter12/inventory/load_balancers create mode 100644 chapter12/inventory/webservers create mode 100644 chapter12/provision.yml create mode 100644 chapter12/roles/database/handlers/main.yml create mode 100644 chapter12/roles/database/tasks/main.yml create mode 100644 chapter12/roles/firewall/tasks/main.yml create mode 100644 chapter12/roles/load_balancer/files/website.pem create mode 100644 chapter12/roles/load_balancer/handlers/main.yml create mode 100644 chapter12/roles/load_balancer/meta/main.yml create mode 100644 chapter12/roles/load_balancer/tasks/main.yml create mode 100644 chapter12/roles/load_balancer/templates/backends.cfg.j2 create mode 100644 chapter12/roles/load_balancer/templates/frontend.cfg.j2 create mode 100644 chapter12/roles/webserver/defaults/main.yml create mode 100644 chapter12/roles/webserver/handlers/main.yml create mode 100644 chapter12/roles/webserver/meta/main.yml create mode 100644 chapter12/roles/webserver/tasks/main.yml create mode 100644 chapter12/roles/webserver/templates/index.html.j2 create mode 100644 chapter12/roles/webserver/templates/nginx-default.j2 create mode 100644 chapter12/roles/wordpress/tasks/main.yml create mode 100644 chapter12/roles/wordpress/templates/wp-config.php.j2 create mode 100644 wp-config.php.j2 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/9781484281727.JPG b/9781484281727.JPG new file mode 100644 index 0000000000000000000000000000000000000000..4a709f5af6a8424f3b132b2e030a2927fa1ea58a GIT binary patch literal 32938 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 literal 0 HcmV?d00001 diff --git a/Contributing.md b/Contributing.md new file mode 100644 index 0000000..f6005ad --- /dev/null +++ b/Contributing.md @@ -0,0 +1,14 @@ +# Contributing to Apress Source Code + +Copyright for Apress source code belongs to the author(s). However, under fair use you are encouraged to fork and contribute minor corrections and updates for the benefit of the author(s) and other readers. + +## How to Contribute + +1. Make sure you have a GitHub account. +2. Fork the repository for the relevant book. +3. Create a new branch on which to make your change, e.g. +`git checkout -b my_code_contribution` +4. Commit your change. Include a commit message describing the correction. Please note that if your commit message is not clear, the correction will not be accepted. +5. Submit a pull request. + +Thank you for your contribution! \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..e96f4e6 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,27 @@ +Freeware License, some rights reserved + +Copyright (c) 2022 Shaun R Smith and Peter Membrey + +Permission is hereby granted, free of charge, to anyone obtaining a copy +of this software and associated documentation files (the "Software"), +to work with the Software within the limits of freeware distribution and fair use. +This includes the rights to use, copy, and modify the Software for personal use. +Users are also allowed and encouraged to submit corrections and modifications +to the Software for the benefit of other users. + +It is not allowed to reuse, modify, or redistribute the Software for +commercial use in any way, or for a user’s educational materials such as books +or blog articles without prior permission from the copyright holder. + +The above copyright notice and this permission notice need to be included +in all copies or substantial portions of the software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS OR APRESS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..4ebe423 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# Apress Source Code + +This repository accompanies [*Beginning Ansible Concepts and Application: Provisioning, Configuring, and Managing Servers, Applications and their Dependencies*](https://www.link.springer.com/book/10.1007/9781484281727) by Shaun R Smith and Peter Membrey (Apress, 2022). + +[comment]: #cover +![Cover image](9781484281727.JPG) + +Download the files as a zip using the green button, or clone the repository to your machine using Git. + +## Releases + +Release v1.0 corresponds to the code in the published book, without corrections or updates. + +## Contributions + +See the file Contributing.md for more information on how you can contribute to this repository. \ No newline at end of file diff --git a/Vagrantfile b/Vagrantfile new file mode 100644 index 0000000..4c8350f --- /dev/null +++ b/Vagrantfile @@ -0,0 +1,82 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +Vagrant.configure("2") do |config| + config.vm.box = "ubuntu/focal64" + + # globally disable the default synced folder + config.vm.synced_folder ".", "/vagrant", disabled: true + + # do not create a secure private key per host, we want to use a single key + # this allows the controller to connect to the target hosts + config.ssh.insert_key = false + + # Set provider virtualbox to use GUI, for two reasons: + # 1. More obvious to the user what is running, so they don't consume too much background resource + # 2. To work around an x64 boot issue in Virtualbox when hardware virtualization is disabled in BIOS + config.vm.provider "virtualbox" do |v| +# v.gui = true + v.cpus = 1 + end + + # The Ansible controller machine + config.vm.define :controller, primary: true do |controller| + controller.vm.hostname = "ansible-controller" + controller.vm.network "private_network", ip: "192.168.98.100" + + # Sync the local directory with ansible-friendly permissions + controller.vm.synced_folder ".", "/vagrant", + owner: "vagrant", + mount_options: ["dmode=755,fmode=644"] + + controller.vm.provision "file", source: "~/.vagrant.d/insecure_private_key", destination: "$HOME/.ssh/id_rsa" + + controller.vm.provision "shell", inline: <<-SHELL + chmod 600 /home/vagrant/.ssh/id_rsa + apt-get install -y ansible sshpass + SHELL + end + + + # Example web servers + (1..2).each do |i| + config.vm.define "web-00#{i}" do |node| + node.vm.hostname = "web-00#{i}" + node.vm.network "private_network", ip: "192.168.98.11#{i}" + end + end + + # Example load balancer + (1..1).each do |i| + config.vm.define "lb-00#{i}" do |node| + node.vm.hostname = "lb-00#{i}" + node.vm.network "private_network", ip: "192.168.98.12#{i}" + end + end + + # Example database server + (1..1).each do |i| + config.vm.define "db-00#{i}" do |node| + node.vm.hostname = "db-00#{i}" + node.vm.network "private_network", ip: "192.168.98.13#{i}" + end + end + + # Generic provisioner to ensure we have python available + # This is an ansible requirement for all managed nodes + config.vm.provision "shell", inline: <<-SHELL + # Disable hardware based sha256sum in apt, not ideal - but Windows 10 WSL breaks VirtualBox + # and we can't really ask everyone to disable that + # See: https://askubuntu.com/questions/1235914/hash-sum-mismatch-error-due-to-identical-sha1-and-md5-but-different-sha256/1241893 + mkdir /etc/gcrypt + echo all >> /etc/gcrypt/hwf.deny + + apt-get update + apt-get install -y python3-minimal python3-apt avahi-daemon tree + + rm -f /etc/update-motd.d/* + sed -i "s/^ENABLED=.*/ENABLED=0/" /etc/default/motd-news + SHELL + + config.vm.boot_timeout = 360 +end diff --git a/chapter02/ansible.cfg b/chapter02/ansible.cfg new file mode 100644 index 0000000..fd15120 --- /dev/null +++ b/chapter02/ansible.cfg @@ -0,0 +1,3 @@ +[defaults] +host_key_checking = false +inventory = hosts diff --git a/chapter02/hosts b/chapter02/hosts new file mode 100644 index 0000000..2497f58 --- /dev/null +++ b/chapter02/hosts @@ -0,0 +1,2 @@ +web-001.local +web-002.local diff --git a/chapter03/ansible.cfg b/chapter03/ansible.cfg new file mode 100644 index 0000000..643231f --- /dev/null +++ b/chapter03/ansible.cfg @@ -0,0 +1,3 @@ +[defaults] +host_key_checking = false +inventory = inventory diff --git a/chapter03/hosts b/chapter03/hosts new file mode 100644 index 0000000..0e064ee --- /dev/null +++ b/chapter03/hosts @@ -0,0 +1,17 @@ +[webservers] +web-001.local +web-002 ansible_host=192.168.98.112 ansible_port=22 + +[webservers:vars] +http_port=8080 + +[load_balancers] +lb-001.local + +[staging] +web-002 + +[production] +web-001.local +lb-001.local + diff --git a/chapter03/inventory/load_balancers b/chapter03/inventory/load_balancers new file mode 100644 index 0000000..3f9f331 --- /dev/null +++ b/chapter03/inventory/load_balancers @@ -0,0 +1,4 @@ +load_balancers: + hosts: + lb-001.local: + diff --git a/chapter03/inventory/webservers b/chapter03/inventory/webservers new file mode 100644 index 0000000..286b29c --- /dev/null +++ b/chapter03/inventory/webservers @@ -0,0 +1,9 @@ +--- +webservers: + hosts: + web-001.local: + web-002: + ansible_host: 192.168.98.112 + vars: + http_port: 8080 + diff --git a/chapter03/ranges b/chapter03/ranges new file mode 100644 index 0000000..25acecc --- /dev/null +++ b/chapter03/ranges @@ -0,0 +1,2 @@ +[webservers] +web-0[01:10] diff --git a/chapter03/regional b/chapter03/regional new file mode 100644 index 0000000..10c4176 --- /dev/null +++ b/chapter03/regional @@ -0,0 +1,24 @@ +[germany] +web-de-00[1:2] + +[france] +web-fr-001 + +[netherlands] +web-nl-001 + +[spain] +web-es-00[1:3] + +[usa] +web-us-00[1:4] + +[europe:children] +germany +france +netherlands +spain + +[americas:children] +usa + diff --git a/chapter04/ansible.cfg b/chapter04/ansible.cfg new file mode 100644 index 0000000..643231f --- /dev/null +++ b/chapter04/ansible.cfg @@ -0,0 +1,3 @@ +[defaults] +host_key_checking = false +inventory = inventory diff --git a/chapter04/files/index.html b/chapter04/files/index.html new file mode 100644 index 0000000..8914320 --- /dev/null +++ b/chapter04/files/index.html @@ -0,0 +1 @@ +This is my website which was setup using Ansible diff --git a/chapter04/inventory/load_balancers b/chapter04/inventory/load_balancers new file mode 100644 index 0000000..3f9f331 --- /dev/null +++ b/chapter04/inventory/load_balancers @@ -0,0 +1,4 @@ +load_balancers: + hosts: + lb-001.local: + diff --git a/chapter04/inventory/webservers b/chapter04/inventory/webservers new file mode 100644 index 0000000..286b29c --- /dev/null +++ b/chapter04/inventory/webservers @@ -0,0 +1,9 @@ +--- +webservers: + hosts: + web-001.local: + web-002: + ansible_host: 192.168.98.112 + vars: + http_port: 8080 + diff --git a/chapter04/webservers.yml b/chapter04/webservers.yml new file mode 100644 index 0000000..30e5c8e --- /dev/null +++ b/chapter04/webservers.yml @@ -0,0 +1,15 @@ +--- +- hosts: webservers + become: true + tasks: + - name: Ensure nginx is installed + apt: + name: nginx + state: present + + - name: Push website content to the web root + copy : + src: index.html + dest: /var/www/html/ + mode: u=rw,g=r,o=r + diff --git a/chapter05/ansible.cfg b/chapter05/ansible.cfg new file mode 100644 index 0000000..c0cf984 --- /dev/null +++ b/chapter05/ansible.cfg @@ -0,0 +1,4 @@ +[defaults] +host_key_checking = false +inventory = inventory +stdout_callback = yaml diff --git a/chapter05/exploring-apt.yml b/chapter05/exploring-apt.yml new file mode 100644 index 0000000..f29ccf3 --- /dev/null +++ b/chapter05/exploring-apt.yml @@ -0,0 +1,15 @@ +--- +- hosts: web-001.local + become: true + tasks: + - name: Ensure nginx is installed + apt: + name: nginx + state: latest + cache_valid_time: 60 + + - name: Uninstall tree command + apt: + name: tree + state: absent + diff --git a/chapter05/files/index.html b/chapter05/files/index.html new file mode 100644 index 0000000..8914320 --- /dev/null +++ b/chapter05/files/index.html @@ -0,0 +1 @@ +This is my website which was setup using Ansible diff --git a/chapter05/inventory/load_balancers b/chapter05/inventory/load_balancers new file mode 100644 index 0000000..3f9f331 --- /dev/null +++ b/chapter05/inventory/load_balancers @@ -0,0 +1,4 @@ +load_balancers: + hosts: + lb-001.local: + diff --git a/chapter05/inventory/webservers b/chapter05/inventory/webservers new file mode 100644 index 0000000..286b29c --- /dev/null +++ b/chapter05/inventory/webservers @@ -0,0 +1,9 @@ +--- +webservers: + hosts: + web-001.local: + web-002: + ansible_host: 192.168.98.112 + vars: + http_port: 8080 + diff --git a/chapter05/upgrade.yml b/chapter05/upgrade.yml new file mode 100644 index 0000000..45be30a --- /dev/null +++ b/chapter05/upgrade.yml @@ -0,0 +1,12 @@ +--- +- hosts: web-001.local + become: true + tasks: + - name: Upgrade all packages + apt: + upgrade: dist + update_cache: yes + +- name: Reboot the host + reboot: + diff --git a/chapter05/webservers.yml b/chapter05/webservers.yml new file mode 100644 index 0000000..1cbccde --- /dev/null +++ b/chapter05/webservers.yml @@ -0,0 +1,41 @@ +--- +- hosts: webservers + become: true + tasks: + - name: Ensure nginx is installed + apt: + name: nginx + state: present + + - name: Push website content to the web root + copy: + src: index.html + dest: /var/www/html/ + mode: u=rw,g=r,o=r + + - name: index.html also known as main.html + file: + state: link + src: /var/www/html/index.html + dest: /var/www/html/main.html + + - name: Update the website content + lineinfile: + path: /var/www/html/index.html + line: "Just re-decorating a little!" + + - name: Firewall - Allow SSH connections + ufw: + rule: allow + name: OpenSSH + + - name: Firewall - Allow website connections + ufw: + rule: allow + name: "Nginx Full" + + - name: Firewall - Deny everything else + ufw: + state: enabled + policy: deny + diff --git a/chapter06/ansible.cfg b/chapter06/ansible.cfg new file mode 100644 index 0000000..c0cf984 --- /dev/null +++ b/chapter06/ansible.cfg @@ -0,0 +1,4 @@ +[defaults] +host_key_checking = false +inventory = inventory +stdout_callback = yaml diff --git a/chapter06/files/index.html b/chapter06/files/index.html new file mode 100644 index 0000000..8914320 --- /dev/null +++ b/chapter06/files/index.html @@ -0,0 +1 @@ +This is my website which was setup using Ansible diff --git a/chapter06/inventory/group_vars/all b/chapter06/inventory/group_vars/all new file mode 100644 index 0000000..2336abe --- /dev/null +++ b/chapter06/inventory/group_vars/all @@ -0,0 +1,2 @@ +--- +http_port: 80 diff --git a/chapter06/inventory/group_vars/webservers b/chapter06/inventory/group_vars/webservers new file mode 100644 index 0000000..e371e5a --- /dev/null +++ b/chapter06/inventory/group_vars/webservers @@ -0,0 +1,2 @@ +--- +http_port: 8080 diff --git a/chapter06/inventory/load_balancers b/chapter06/inventory/load_balancers new file mode 100644 index 0000000..3f9f331 --- /dev/null +++ b/chapter06/inventory/load_balancers @@ -0,0 +1,4 @@ +load_balancers: + hosts: + lb-001.local: + diff --git a/chapter06/inventory/webservers b/chapter06/inventory/webservers new file mode 100644 index 0000000..29e9668 --- /dev/null +++ b/chapter06/inventory/webservers @@ -0,0 +1,6 @@ +--- +webservers: + hosts: + web-001.local: + web-002.local: + diff --git a/chapter06/upgrade.yml b/chapter06/upgrade.yml new file mode 100644 index 0000000..548a35b --- /dev/null +++ b/chapter06/upgrade.yml @@ -0,0 +1,15 @@ +--- +- hosts: web-001.local + gather_facts: no + become: true + tasks: + - name: Upgrade all packages + apt: + upgrade: dist + update_cache: yes + register: upgrade_result + + - name: Reboot the host + reboot: + when: upgrade_result.changed + diff --git a/chapter06/webservers.yml b/chapter06/webservers.yml new file mode 100644 index 0000000..f50cb2f --- /dev/null +++ b/chapter06/webservers.yml @@ -0,0 +1,48 @@ +--- +- hosts: webservers + become: true + tasks: + - name: Ensure nginx is installed + apt: + name: nginx + state: present + + - name: Change the nginx port + replace: + path: /etc/nginx/sites-enabled/default + regexp: "listen [0-9]+" + replace: "listen {{ http_port }}" + + - name: Reload nginx for new config + service: + name: nginx + state: reloaded + + - name: Push website content to the web root + copy: + src: index.html + dest: /var/www/html/ + mode: u=rw,g=r,o=r + + - name: Firewall - Allow SSH connections + ufw: + rule: allow + name: OpenSSH + + - name: Firewall - Allow website connections + ufw: + rule: allow + port: "{{ http_port }}" + + - name: Firewall - Deny everything else + ufw: + state: enabled + policy: deny + + - name: Validate that the http_port is working + wait_for: + host: "{{ ansible_host }}" + port: "{{ http_port }}" + timeout: 5 + connection: local + diff --git a/chapter07/ansible.cfg b/chapter07/ansible.cfg new file mode 100644 index 0000000..c0cf984 --- /dev/null +++ b/chapter07/ansible.cfg @@ -0,0 +1,4 @@ +[defaults] +host_key_checking = false +inventory = inventory +stdout_callback = yaml diff --git a/chapter07/hostname.yml b/chapter07/hostname.yml new file mode 100644 index 0000000..c4e2b87 --- /dev/null +++ b/chapter07/hostname.yml @@ -0,0 +1,17 @@ +--- +- hosts: webservers + become: true + gather_facts: no + tasks: + - name: Raw value for inventory_hostname + debug: + msg: "{{ inventory_hostname }}" + + - name: Uppercase inventory_hostname + debug: + msg: "{{ inventory_hostname | upper }}" + + - name: Raw value for inventory_hostname + debug: + msg: "{{ inventory_hostname }}" + diff --git a/chapter07/inventory/group_vars/all b/chapter07/inventory/group_vars/all new file mode 100644 index 0000000..2336abe --- /dev/null +++ b/chapter07/inventory/group_vars/all @@ -0,0 +1,2 @@ +--- +http_port: 80 diff --git a/chapter07/inventory/group_vars/webservers b/chapter07/inventory/group_vars/webservers new file mode 100644 index 0000000..e371e5a --- /dev/null +++ b/chapter07/inventory/group_vars/webservers @@ -0,0 +1,2 @@ +--- +http_port: 8080 diff --git a/chapter07/inventory/load_balancers b/chapter07/inventory/load_balancers new file mode 100644 index 0000000..3f9f331 --- /dev/null +++ b/chapter07/inventory/load_balancers @@ -0,0 +1,4 @@ +load_balancers: + hosts: + lb-001.local: + diff --git a/chapter07/inventory/webservers b/chapter07/inventory/webservers new file mode 100644 index 0000000..5e335e4 --- /dev/null +++ b/chapter07/inventory/webservers @@ -0,0 +1,6 @@ +--- +webservers: + hosts: + web-001.local: + web-002.local: + status_url: "status" diff --git a/chapter07/templates/index.html.j2 b/chapter07/templates/index.html.j2 new file mode 100644 index 0000000..b755e66 --- /dev/null +++ b/chapter07/templates/index.html.j2 @@ -0,0 +1,16 @@ +My website, served from {{ inventory_hostname }} + +

+IP Addresses:
+{% for ip in ansible_all_ipv4_addresses %} + {{ ip }}
+{% endfor %} +

+ +

+Operating System:
+{% for key, value in ansible_lsb.items() %} + {{ key }}: {{ value }}
+{% endfor %} +

+ diff --git a/chapter07/templates/nginx-default.j2 b/chapter07/templates/nginx-default.j2 new file mode 100644 index 0000000..26764dd --- /dev/null +++ b/chapter07/templates/nginx-default.j2 @@ -0,0 +1,14 @@ +server { + listen {{ http_port }} default_server; + + root /var/www/html; + + server_name _; + + {% if status_url is defined -%} + location /{{ status_url | default('status') }} { + stub_status on; + } + {%- endif %} +} + diff --git a/chapter07/upgrade.yml b/chapter07/upgrade.yml new file mode 100644 index 0000000..548a35b --- /dev/null +++ b/chapter07/upgrade.yml @@ -0,0 +1,15 @@ +--- +- hosts: web-001.local + gather_facts: no + become: true + tasks: + - name: Upgrade all packages + apt: + upgrade: dist + update_cache: yes + register: upgrade_result + + - name: Reboot the host + reboot: + when: upgrade_result.changed + diff --git a/chapter07/webservers.yml b/chapter07/webservers.yml new file mode 100644 index 0000000..19ac9f0 --- /dev/null +++ b/chapter07/webservers.yml @@ -0,0 +1,48 @@ +--- +- hosts: webservers + become: true + tasks: + - name: Ensure nginx is installed + apt: + name: nginx + state: present + + - name: Configure nginx + template: + src: nginx-default.j2 + dest: /etc/nginx/sites-available/default + mode: u=rw,g=r,o=r + + - name: Reload nginx for new config + service: + name: nginx + state: reloaded + + - name: Push website content to the web root + template: + src: index.html.j2 + dest: /var/www/html/index.html + mode: u=rw,g=r,o=r + + - name: Firewall - Allow SSH connections + ufw: + rule: allow + name: OpenSSH + + - name: Firewall - Allow website connections + ufw: + rule: allow + port: "{{ http_port }}" + + - name: Firewall - Deny everything else + ufw: + state: enabled + policy: deny + + - name: Validate that the http_port is working + wait_for: + host: "{{ ansible_host }}" + port: "{{ http_port }}" + timeout: 5 + connection: local + diff --git a/chapter08/ansible.cfg b/chapter08/ansible.cfg new file mode 100644 index 0000000..c0cf984 --- /dev/null +++ b/chapter08/ansible.cfg @@ -0,0 +1,4 @@ +[defaults] +host_key_checking = false +inventory = inventory +stdout_callback = yaml diff --git a/chapter08/hostname.yml b/chapter08/hostname.yml new file mode 100644 index 0000000..c4e2b87 --- /dev/null +++ b/chapter08/hostname.yml @@ -0,0 +1,17 @@ +--- +- hosts: webservers + become: true + gather_facts: no + tasks: + - name: Raw value for inventory_hostname + debug: + msg: "{{ inventory_hostname }}" + + - name: Uppercase inventory_hostname + debug: + msg: "{{ inventory_hostname | upper }}" + + - name: Raw value for inventory_hostname + debug: + msg: "{{ inventory_hostname }}" + diff --git a/chapter08/inventory/group_vars/all b/chapter08/inventory/group_vars/all new file mode 100644 index 0000000..2336abe --- /dev/null +++ b/chapter08/inventory/group_vars/all @@ -0,0 +1,2 @@ +--- +http_port: 80 diff --git a/chapter08/inventory/group_vars/webservers b/chapter08/inventory/group_vars/webservers new file mode 100644 index 0000000..e371e5a --- /dev/null +++ b/chapter08/inventory/group_vars/webservers @@ -0,0 +1,2 @@ +--- +http_port: 8080 diff --git a/chapter08/inventory/load_balancers b/chapter08/inventory/load_balancers new file mode 100644 index 0000000..3f9f331 --- /dev/null +++ b/chapter08/inventory/load_balancers @@ -0,0 +1,4 @@ +load_balancers: + hosts: + lb-001.local: + diff --git a/chapter08/inventory/webservers b/chapter08/inventory/webservers new file mode 100644 index 0000000..5e335e4 --- /dev/null +++ b/chapter08/inventory/webservers @@ -0,0 +1,6 @@ +--- +webservers: + hosts: + web-001.local: + web-002.local: + status_url: "status" diff --git a/chapter08/templates/index.html.j2 b/chapter08/templates/index.html.j2 new file mode 100644 index 0000000..b755e66 --- /dev/null +++ b/chapter08/templates/index.html.j2 @@ -0,0 +1,16 @@ +My website, served from {{ inventory_hostname }} + +

+IP Addresses:
+{% for ip in ansible_all_ipv4_addresses %} + {{ ip }}
+{% endfor %} +

+ +

+Operating System:
+{% for key, value in ansible_lsb.items() %} + {{ key }}: {{ value }}
+{% endfor %} +

+ diff --git a/chapter08/templates/nginx-default.j2 b/chapter08/templates/nginx-default.j2 new file mode 100644 index 0000000..26764dd --- /dev/null +++ b/chapter08/templates/nginx-default.j2 @@ -0,0 +1,14 @@ +server { + listen {{ http_port }} default_server; + + root /var/www/html; + + server_name _; + + {% if status_url is defined -%} + location /{{ status_url | default('status') }} { + stub_status on; + } + {%- endif %} +} + diff --git a/chapter08/upgrade.yml b/chapter08/upgrade.yml new file mode 100644 index 0000000..548a35b --- /dev/null +++ b/chapter08/upgrade.yml @@ -0,0 +1,15 @@ +--- +- hosts: web-001.local + gather_facts: no + become: true + tasks: + - name: Upgrade all packages + apt: + upgrade: dist + update_cache: yes + register: upgrade_result + + - name: Reboot the host + reboot: + when: upgrade_result.changed + diff --git a/chapter08/webservers.yml b/chapter08/webservers.yml new file mode 100644 index 0000000..e7b9c48 --- /dev/null +++ b/chapter08/webservers.yml @@ -0,0 +1,52 @@ +--- +- hosts: webservers + become: true + handlers: + - name: Reload nginx + service: + name: nginx + state: reloaded + listen: "Reload web services" + + - name: Validate that the http_port is working + wait_for: + host: "{{ ansible_host }}" + port: "{{ http_port }}" + timeout: 5 + connection: local + listen: "Reload web services" + + tasks: + - name: Ensure nginx is installed + apt: + name: nginx + state: present + + - name: Configure nginx + template: + src: nginx-default.j2 + dest: /etc/nginx/sites-available/default + mode: u=rw,g=r,o=r + notify: "Reload web services" + + - name: Push website content to the web root + template: + src: index.html.j2 + dest: /var/www/html/index.html + mode: u=rw,g=r,o=r + + - name: Firewall - Allow SSH connections + ufw: + rule: allow + name: OpenSSH + + - name: Firewall - Allow website connections + ufw: + rule: allow + port: "{{ http_port }}" + + - name: Firewall - Deny everything else + ufw: + state: enabled + policy: deny + diff --git a/chapter09/ansible.cfg b/chapter09/ansible.cfg new file mode 100644 index 0000000..c0cf984 --- /dev/null +++ b/chapter09/ansible.cfg @@ -0,0 +1,4 @@ +[defaults] +host_key_checking = false +inventory = inventory +stdout_callback = yaml diff --git a/chapter09/inventory/group_vars/all b/chapter09/inventory/group_vars/all new file mode 100644 index 0000000..2336abe --- /dev/null +++ b/chapter09/inventory/group_vars/all @@ -0,0 +1,2 @@ +--- +http_port: 80 diff --git a/chapter09/inventory/group_vars/webservers b/chapter09/inventory/group_vars/webservers new file mode 100644 index 0000000..e371e5a --- /dev/null +++ b/chapter09/inventory/group_vars/webservers @@ -0,0 +1,2 @@ +--- +http_port: 8080 diff --git a/chapter09/inventory/load_balancers b/chapter09/inventory/load_balancers new file mode 100644 index 0000000..3f9f331 --- /dev/null +++ b/chapter09/inventory/load_balancers @@ -0,0 +1,4 @@ +load_balancers: + hosts: + lb-001.local: + diff --git a/chapter09/inventory/webservers b/chapter09/inventory/webservers new file mode 100644 index 0000000..5e335e4 --- /dev/null +++ b/chapter09/inventory/webservers @@ -0,0 +1,6 @@ +--- +webservers: + hosts: + web-001.local: + web-002.local: + status_url: "status" diff --git a/chapter09/roles/firewall/tasks/main.yml b/chapter09/roles/firewall/tasks/main.yml new file mode 100644 index 0000000..831ac5d --- /dev/null +++ b/chapter09/roles/firewall/tasks/main.yml @@ -0,0 +1,11 @@ +--- +- name: Firewall - Allow SSH connections + ufw: + rule: allow + name: OpenSSH + +- name: Firewall - Deny everything else + ufw: + state: enabled + policy: deny + diff --git a/chapter09/roles/webserver/defaults/main.yml b/chapter09/roles/webserver/defaults/main.yml new file mode 100644 index 0000000..2336abe --- /dev/null +++ b/chapter09/roles/webserver/defaults/main.yml @@ -0,0 +1,2 @@ +--- +http_port: 80 diff --git a/chapter09/roles/webserver/handlers/main.yml b/chapter09/roles/webserver/handlers/main.yml new file mode 100644 index 0000000..e3ae38f --- /dev/null +++ b/chapter09/roles/webserver/handlers/main.yml @@ -0,0 +1,15 @@ +--- +- name: Reload nginx + service: + name: nginx + state: reloaded + listen: "Reload web services" + +- name: Validate that the http_port is working + wait_for: + host: "{{ ansible_host }}" + port: "{{ http_port }}" + timeout: 5 + connection: local + listen: "Reload web services" + diff --git a/chapter09/roles/webserver/meta/main.yml b/chapter09/roles/webserver/meta/main.yml new file mode 100644 index 0000000..2a7a00a --- /dev/null +++ b/chapter09/roles/webserver/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - role: firewall diff --git a/chapter09/roles/webserver/tasks/main.yml b/chapter09/roles/webserver/tasks/main.yml new file mode 100644 index 0000000..a11f0c3 --- /dev/null +++ b/chapter09/roles/webserver/tasks/main.yml @@ -0,0 +1,23 @@ +- name: Ensure nginx is installed + apt: + name: nginx + state: present + +- name: Configure nginx + template: + src: nginx-default.j2 + dest: /etc/nginx/sites-available/default + mode: u=rw,g=r,o=r + notify: "Reload web services" + +- name: Push website content to the web root + template: + src: index.html.j2 + dest: /var/www/html/index.html + mode: u=rw,g=r,o=r + +- name: Firewall - Allow website connections + ufw: + rule: allow + port: "{{ http_port }}" + diff --git a/chapter09/roles/webserver/templates/index.html.j2 b/chapter09/roles/webserver/templates/index.html.j2 new file mode 100644 index 0000000..b755e66 --- /dev/null +++ b/chapter09/roles/webserver/templates/index.html.j2 @@ -0,0 +1,16 @@ +My website, served from {{ inventory_hostname }} + +

+IP Addresses:
+{% for ip in ansible_all_ipv4_addresses %} + {{ ip }}
+{% endfor %} +

+ +

+Operating System:
+{% for key, value in ansible_lsb.items() %} + {{ key }}: {{ value }}
+{% endfor %} +

+ diff --git a/chapter09/roles/webserver/templates/nginx-default.j2 b/chapter09/roles/webserver/templates/nginx-default.j2 new file mode 100644 index 0000000..26764dd --- /dev/null +++ b/chapter09/roles/webserver/templates/nginx-default.j2 @@ -0,0 +1,14 @@ +server { + listen {{ http_port }} default_server; + + root /var/www/html; + + server_name _; + + {% if status_url is defined -%} + location /{{ status_url | default('status') }} { + stub_status on; + } + {%- endif %} +} + diff --git a/chapter09/webservers.yml b/chapter09/webservers.yml new file mode 100644 index 0000000..6773e14 --- /dev/null +++ b/chapter09/webservers.yml @@ -0,0 +1,8 @@ +--- +- hosts: webservers + become: true + tasks: + - name: Build webservers + include_role: + name: webserver + diff --git a/chapter10/ansible.cfg b/chapter10/ansible.cfg new file mode 100644 index 0000000..c0cf984 --- /dev/null +++ b/chapter10/ansible.cfg @@ -0,0 +1,4 @@ +[defaults] +host_key_checking = false +inventory = inventory +stdout_callback = yaml diff --git a/chapter10/inventory/group_vars/all b/chapter10/inventory/group_vars/all new file mode 100644 index 0000000..8d784df --- /dev/null +++ b/chapter10/inventory/group_vars/all @@ -0,0 +1,3 @@ +--- +http_port: 80 +https_port: 443 diff --git a/chapter10/inventory/group_vars/webservers b/chapter10/inventory/group_vars/webservers new file mode 100644 index 0000000..e371e5a --- /dev/null +++ b/chapter10/inventory/group_vars/webservers @@ -0,0 +1,2 @@ +--- +http_port: 8080 diff --git a/chapter10/inventory/load_balancers b/chapter10/inventory/load_balancers new file mode 100644 index 0000000..3f9f331 --- /dev/null +++ b/chapter10/inventory/load_balancers @@ -0,0 +1,4 @@ +load_balancers: + hosts: + lb-001.local: + diff --git a/chapter10/inventory/webservers b/chapter10/inventory/webservers new file mode 100644 index 0000000..5e335e4 --- /dev/null +++ b/chapter10/inventory/webservers @@ -0,0 +1,6 @@ +--- +webservers: + hosts: + web-001.local: + web-002.local: + status_url: "status" diff --git a/chapter10/provision.yml b/chapter10/provision.yml new file mode 100644 index 0000000..07b342a --- /dev/null +++ b/chapter10/provision.yml @@ -0,0 +1,20 @@ +--- +- hosts: webservers + become: true + tasks: + - name: Build webservers + include_role: + name: webserver + tags: + - always + +- hosts: load_balancers + become: true + tasks: + - name: Build load balancers + include_role: + name: load_balancer + tags: + - always + + diff --git a/chapter10/roles/firewall/tasks/main.yml b/chapter10/roles/firewall/tasks/main.yml new file mode 100644 index 0000000..ded7c0e --- /dev/null +++ b/chapter10/roles/firewall/tasks/main.yml @@ -0,0 +1,15 @@ +--- +- name: Firewall - Allow SSH connections + ufw: + rule: allow + name: OpenSSH + tags: + - firewall + +- name: Firewall - Deny everything else + ufw: + state: enabled + policy: deny + tags: + - firewall + diff --git a/chapter10/roles/load_balancer/handlers/main.yml b/chapter10/roles/load_balancer/handlers/main.yml new file mode 100644 index 0000000..698e131 --- /dev/null +++ b/chapter10/roles/load_balancer/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: Reload HAProxy + service: + name: haproxy + state: reloaded + diff --git a/chapter10/roles/load_balancer/meta/main.yml b/chapter10/roles/load_balancer/meta/main.yml new file mode 100644 index 0000000..2a7a00a --- /dev/null +++ b/chapter10/roles/load_balancer/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - role: firewall diff --git a/chapter10/roles/load_balancer/tasks/main.yml b/chapter10/roles/load_balancer/tasks/main.yml new file mode 100644 index 0000000..2d04432 --- /dev/null +++ b/chapter10/roles/load_balancer/tasks/main.yml @@ -0,0 +1,42 @@ +--- +- name: Install HAProxy + apt: + name: haproxy + state: present + cache_valid_time: 60 + +- name: Create configuration directory + file: + path: /etc/haproxy/fragments + state: directory + +- name: Copy original configuration file + copy: + src: /etc/haproxy/haproxy.cfg + dest: /etc/haproxy/fragments/00_defaults.cfg + remote_src: yes + force: no + +- name: Setup frontends + template: + src: frontends.cfg.j2 + dest: /etc/haproxy/fragments/40_frontends.cfg + +- name: Build configuration from fragments + assemble: + src: /etc/haproxy/fragments/ + dest: /etc/haproxy/haproxy.cfg + validate: "haproxy -f %s -c" + notify: Reload HAProxy + +- name: Firewall - Allow website connections + ufw: + rule: allow + port: "{{ item }}" + loop: + - "{{ http_port }}" + - "{{ https_port }}" + tags: + - firewall + + diff --git a/chapter10/roles/load_balancer/templates/backends.cfg.j2 b/chapter10/roles/load_balancer/templates/backends.cfg.j2 new file mode 100644 index 0000000..fc8a106 --- /dev/null +++ b/chapter10/roles/load_balancer/templates/backends.cfg.j2 @@ -0,0 +1,6 @@ +backend web_servers + balance roundrobin + {% for host in groups.webservers %} + server {{ host }} {{ host }}:{{ hostvars[host].http_port }} +{% endfor %} + diff --git a/chapter10/roles/load_balancer/templates/frontend.cfg.j2 b/chapter10/roles/load_balancer/templates/frontend.cfg.j2 new file mode 100644 index 0000000..fcd88a2 --- /dev/null +++ b/chapter10/roles/load_balancer/templates/frontend.cfg.j2 @@ -0,0 +1,4 @@ +frontend awesome_ansible + bind *:{{ http_port }} + stats uri /haproxy?stats + default_backend web_servers diff --git a/chapter10/roles/webserver/defaults/main.yml b/chapter10/roles/webserver/defaults/main.yml new file mode 100644 index 0000000..2336abe --- /dev/null +++ b/chapter10/roles/webserver/defaults/main.yml @@ -0,0 +1,2 @@ +--- +http_port: 80 diff --git a/chapter10/roles/webserver/handlers/main.yml b/chapter10/roles/webserver/handlers/main.yml new file mode 100644 index 0000000..e3ae38f --- /dev/null +++ b/chapter10/roles/webserver/handlers/main.yml @@ -0,0 +1,15 @@ +--- +- name: Reload nginx + service: + name: nginx + state: reloaded + listen: "Reload web services" + +- name: Validate that the http_port is working + wait_for: + host: "{{ ansible_host }}" + port: "{{ http_port }}" + timeout: 5 + connection: local + listen: "Reload web services" + diff --git a/chapter10/roles/webserver/meta/main.yml b/chapter10/roles/webserver/meta/main.yml new file mode 100644 index 0000000..2a7a00a --- /dev/null +++ b/chapter10/roles/webserver/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - role: firewall diff --git a/chapter10/roles/webserver/tasks/main.yml b/chapter10/roles/webserver/tasks/main.yml new file mode 100644 index 0000000..99841fb --- /dev/null +++ b/chapter10/roles/webserver/tasks/main.yml @@ -0,0 +1,25 @@ +- name: Ensure nginx is installed + apt: + name: nginx + state: present + +- name: Configure nginx + template: + src: nginx-default.j2 + dest: /etc/nginx/sites-available/default + mode: u=rw,g=r,o=r + notify: "Reload web services" + +- name: Push website content to the web root + template: + src: index.html.j2 + dest: /var/www/html/index.html + mode: u=rw,g=r,o=r + +- name: Firewall - Allow website connections + ufw: + rule: allow + port: "{{ http_port }}" + tags: + - firewall + diff --git a/chapter10/roles/webserver/templates/index.html.j2 b/chapter10/roles/webserver/templates/index.html.j2 new file mode 100644 index 0000000..b755e66 --- /dev/null +++ b/chapter10/roles/webserver/templates/index.html.j2 @@ -0,0 +1,16 @@ +My website, served from {{ inventory_hostname }} + +

+IP Addresses:
+{% for ip in ansible_all_ipv4_addresses %} + {{ ip }}
+{% endfor %} +

+ +

+Operating System:
+{% for key, value in ansible_lsb.items() %} + {{ key }}: {{ value }}
+{% endfor %} +

+ diff --git a/chapter10/roles/webserver/templates/nginx-default.j2 b/chapter10/roles/webserver/templates/nginx-default.j2 new file mode 100644 index 0000000..26764dd --- /dev/null +++ b/chapter10/roles/webserver/templates/nginx-default.j2 @@ -0,0 +1,14 @@ +server { + listen {{ http_port }} default_server; + + root /var/www/html; + + server_name _; + + {% if status_url is defined -%} + location /{{ status_url | default('status') }} { + stub_status on; + } + {%- endif %} +} + diff --git a/chapter11/ansible.cfg b/chapter11/ansible.cfg new file mode 100644 index 0000000..c0cf984 --- /dev/null +++ b/chapter11/ansible.cfg @@ -0,0 +1,4 @@ +[defaults] +host_key_checking = false +inventory = inventory +stdout_callback = yaml diff --git a/chapter11/inventory/databases b/chapter11/inventory/databases new file mode 100644 index 0000000..94f21d9 --- /dev/null +++ b/chapter11/inventory/databases @@ -0,0 +1,4 @@ +--- +databases: + hosts: + db-001.local: diff --git a/chapter11/inventory/group_vars/all b/chapter11/inventory/group_vars/all new file mode 100644 index 0000000..42d548a --- /dev/null +++ b/chapter11/inventory/group_vars/all @@ -0,0 +1,11 @@ +--- +http_port: 80 +https_port: 443 + +database: + host: db-001.local + name: wordpress + username: wordpress_rw + password: SomeSuperStrongPassword + root_password: EvenStrongerPassword + diff --git a/chapter11/inventory/group_vars/webservers b/chapter11/inventory/group_vars/webservers new file mode 100644 index 0000000..e371e5a --- /dev/null +++ b/chapter11/inventory/group_vars/webservers @@ -0,0 +1,2 @@ +--- +http_port: 8080 diff --git a/chapter11/inventory/load_balancers b/chapter11/inventory/load_balancers new file mode 100644 index 0000000..3f9f331 --- /dev/null +++ b/chapter11/inventory/load_balancers @@ -0,0 +1,4 @@ +load_balancers: + hosts: + lb-001.local: + diff --git a/chapter11/inventory/webservers b/chapter11/inventory/webservers new file mode 100644 index 0000000..5e335e4 --- /dev/null +++ b/chapter11/inventory/webservers @@ -0,0 +1,6 @@ +--- +webservers: + hosts: + web-001.local: + web-002.local: + status_url: "status" diff --git a/chapter11/provision.yml b/chapter11/provision.yml new file mode 100644 index 0000000..b0cc02b --- /dev/null +++ b/chapter11/provision.yml @@ -0,0 +1,35 @@ +--- +- hosts: webservers + become: true + tasks: + - name: Build webservers + include_role: + name: webserver + tags: + - always + + - name: Install Wordpress + include_role: + name: wordpress + tags: + - always + +- hosts: databases + become: true + tasks: + - name: Build Databases + include_role: + name: database + tags: + - always + +- hosts: load_balancers + become: true + tasks: + - name: Build load balancers + include_role: + name: load_balancer + tags: + - always + + diff --git a/chapter11/roles/database/handlers/main.yml b/chapter11/roles/database/handlers/main.yml new file mode 100644 index 0000000..bce7c24 --- /dev/null +++ b/chapter11/roles/database/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: Restart MySQL + service: + name: mysql + state: restarted diff --git a/chapter11/roles/database/tasks/main.yml b/chapter11/roles/database/tasks/main.yml new file mode 100644 index 0000000..0bc7d14 --- /dev/null +++ b/chapter11/roles/database/tasks/main.yml @@ -0,0 +1,50 @@ +--- +- name: Install MySQL + apt: + name: + - mysql-server + - python3-pymysql + state: present + +- name: Set the root password + mysql_user: + name: root + password: "{{ database.root_password }}" + state: present + login_user: root + login_password: "{{database.root_password }}" + login_unix_socket: /var/run/mysqld/mysqld.sock + no_log: True + +- name: Create the wordpress database + mysql_db: + name: "{{ database.name }}" + state: present + login_user: root + login_password: "{{database.root_password }}" + +- name: Create the wordpress user + mysql_user: + name: "{{ database.username }}" + password: "{{database.password }}" + priv: "{{ database.name }}.*:ALL" + host: "%" + state: present + login_user: root + login_password: "{{database.root_password }}" + no_log: True + +- name: Ensure MySQL listens on the network + lineinfile: + path: /etc/mysql/mysql.conf.d/mysqld.cnf + regexp: '^bind-address' + line: 'bind-address = 0.0.0.0' + notify: + - Restart MySQL + +- name: Firewall - Allow database connections + ufw: + rule: allow + port: "3306" + tags: + - firewall diff --git a/chapter11/roles/firewall/tasks/main.yml b/chapter11/roles/firewall/tasks/main.yml new file mode 100644 index 0000000..ded7c0e --- /dev/null +++ b/chapter11/roles/firewall/tasks/main.yml @@ -0,0 +1,15 @@ +--- +- name: Firewall - Allow SSH connections + ufw: + rule: allow + name: OpenSSH + tags: + - firewall + +- name: Firewall - Deny everything else + ufw: + state: enabled + policy: deny + tags: + - firewall + diff --git a/chapter11/roles/load_balancer/handlers/main.yml b/chapter11/roles/load_balancer/handlers/main.yml new file mode 100644 index 0000000..698e131 --- /dev/null +++ b/chapter11/roles/load_balancer/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: Reload HAProxy + service: + name: haproxy + state: reloaded + diff --git a/chapter11/roles/load_balancer/meta/main.yml b/chapter11/roles/load_balancer/meta/main.yml new file mode 100644 index 0000000..2a7a00a --- /dev/null +++ b/chapter11/roles/load_balancer/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - role: firewall diff --git a/chapter11/roles/load_balancer/tasks/main.yml b/chapter11/roles/load_balancer/tasks/main.yml new file mode 100644 index 0000000..2d04432 --- /dev/null +++ b/chapter11/roles/load_balancer/tasks/main.yml @@ -0,0 +1,42 @@ +--- +- name: Install HAProxy + apt: + name: haproxy + state: present + cache_valid_time: 60 + +- name: Create configuration directory + file: + path: /etc/haproxy/fragments + state: directory + +- name: Copy original configuration file + copy: + src: /etc/haproxy/haproxy.cfg + dest: /etc/haproxy/fragments/00_defaults.cfg + remote_src: yes + force: no + +- name: Setup frontends + template: + src: frontends.cfg.j2 + dest: /etc/haproxy/fragments/40_frontends.cfg + +- name: Build configuration from fragments + assemble: + src: /etc/haproxy/fragments/ + dest: /etc/haproxy/haproxy.cfg + validate: "haproxy -f %s -c" + notify: Reload HAProxy + +- name: Firewall - Allow website connections + ufw: + rule: allow + port: "{{ item }}" + loop: + - "{{ http_port }}" + - "{{ https_port }}" + tags: + - firewall + + diff --git a/chapter11/roles/load_balancer/templates/backends.cfg.j2 b/chapter11/roles/load_balancer/templates/backends.cfg.j2 new file mode 100644 index 0000000..8c59468 --- /dev/null +++ b/chapter11/roles/load_balancer/templates/backends.cfg.j2 @@ -0,0 +1,7 @@ +backend web_servers + balance roundrobin + cookie SERVERID insert indirect nocache + {% for host in groups.webservers %} + server {{ host }} {{ host }}:{{ hostvars[host].http_port }} check cookie {{ host }} +{% endfor %} + diff --git a/chapter11/roles/load_balancer/templates/frontend.cfg.j2 b/chapter11/roles/load_balancer/templates/frontend.cfg.j2 new file mode 100644 index 0000000..fcd88a2 --- /dev/null +++ b/chapter11/roles/load_balancer/templates/frontend.cfg.j2 @@ -0,0 +1,4 @@ +frontend awesome_ansible + bind *:{{ http_port }} + stats uri /haproxy?stats + default_backend web_servers diff --git a/chapter11/roles/webserver/defaults/main.yml b/chapter11/roles/webserver/defaults/main.yml new file mode 100644 index 0000000..2336abe --- /dev/null +++ b/chapter11/roles/webserver/defaults/main.yml @@ -0,0 +1,2 @@ +--- +http_port: 80 diff --git a/chapter11/roles/webserver/handlers/main.yml b/chapter11/roles/webserver/handlers/main.yml new file mode 100644 index 0000000..e3ae38f --- /dev/null +++ b/chapter11/roles/webserver/handlers/main.yml @@ -0,0 +1,15 @@ +--- +- name: Reload nginx + service: + name: nginx + state: reloaded + listen: "Reload web services" + +- name: Validate that the http_port is working + wait_for: + host: "{{ ansible_host }}" + port: "{{ http_port }}" + timeout: 5 + connection: local + listen: "Reload web services" + diff --git a/chapter11/roles/webserver/meta/main.yml b/chapter11/roles/webserver/meta/main.yml new file mode 100644 index 0000000..2a7a00a --- /dev/null +++ b/chapter11/roles/webserver/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - role: firewall diff --git a/chapter11/roles/webserver/tasks/main.yml b/chapter11/roles/webserver/tasks/main.yml new file mode 100644 index 0000000..c6831aa --- /dev/null +++ b/chapter11/roles/webserver/tasks/main.yml @@ -0,0 +1,28 @@ +- name: Ensure nginx is installed + apt: + name: + - nginx + - php-fpm + - php-mysql + state: present + +- name: Configure nginx + template: + src: nginx-default.j2 + dest: /etc/nginx/sites-available/default + mode: u=rw,g=r,o=r + notify: "Reload web services" + +- name: Push website content to the web root + template: + src: index.html.j2 + dest: /var/www/html/index.html + mode: u=rw,g=r,o=r + +- name: Firewall - Allow website connections + ufw: + rule: allow + port: "{{ http_port }}" + tags: + - firewall + diff --git a/chapter11/roles/webserver/templates/index.html.j2 b/chapter11/roles/webserver/templates/index.html.j2 new file mode 100644 index 0000000..b755e66 --- /dev/null +++ b/chapter11/roles/webserver/templates/index.html.j2 @@ -0,0 +1,16 @@ +My website, served from {{ inventory_hostname }} + +

+IP Addresses:
+{% for ip in ansible_all_ipv4_addresses %} + {{ ip }}
+{% endfor %} +

+ +

+Operating System:
+{% for key, value in ansible_lsb.items() %} + {{ key }}: {{ value }}
+{% endfor %} +

+ diff --git a/chapter11/roles/webserver/templates/nginx-default.j2 b/chapter11/roles/webserver/templates/nginx-default.j2 new file mode 100644 index 0000000..be1ca44 --- /dev/null +++ b/chapter11/roles/webserver/templates/nginx-default.j2 @@ -0,0 +1,23 @@ +server { + listen {{ http_port }} default_server; + + root /var/www/html; + + server_name _; + + {% if status_url is defined -%} + location /{{ status_url | default('status') }} { + stub_status on; + } + {%- endif %} + + + index index.php index.html index.htm; + + location ~ \.php$ { + include snippets/fastcgi-php.conf; + fastcgi_pass unix:/var/run/php/php-fpm.sock; + } + +} + diff --git a/chapter11/roles/wordpress/tasks/main.yml b/chapter11/roles/wordpress/tasks/main.yml new file mode 100644 index 0000000..3eb6d36 --- /dev/null +++ b/chapter11/roles/wordpress/tasks/main.yml @@ -0,0 +1,18 @@ +--- +- name: Download and unarchive Wordpress + unarchive: + src: https://wordpress.org/latest.tar.gz + remote_src: True + owner: root + group: www-data + dest: "/var/www/html/" + creates: "/var/www/html/wordpress" + +- name: Configure Wordpress + template: + src: "wp-config.php.j2" + dest: "/var/www/html/wordpress/wp-config.php" + owner: root + group: www-data + mode: 'u=rw,g=r,o=' + diff --git a/chapter11/roles/wordpress/templates/wp-config.php.j2 b/chapter11/roles/wordpress/templates/wp-config.php.j2 new file mode 100644 index 0000000..37347dd --- /dev/null +++ b/chapter11/roles/wordpress/templates/wp-config.php.j2 @@ -0,0 +1,31 @@ + +IP Addresses:
+{% for ip in ansible_all_ipv4_addresses %} + {{ ip }}
+{% endfor %} +

+ +

+Operating System:
+{% for key, value in ansible_lsb.items() %} + {{ key }}: {{ value }}
+{% endfor %} +

+ diff --git a/chapter12/roles/webserver/templates/nginx-default.j2 b/chapter12/roles/webserver/templates/nginx-default.j2 new file mode 100644 index 0000000..be1ca44 --- /dev/null +++ b/chapter12/roles/webserver/templates/nginx-default.j2 @@ -0,0 +1,23 @@ +server { + listen {{ http_port }} default_server; + + root /var/www/html; + + server_name _; + + {% if status_url is defined -%} + location /{{ status_url | default('status') }} { + stub_status on; + } + {%- endif %} + + + index index.php index.html index.htm; + + location ~ \.php$ { + include snippets/fastcgi-php.conf; + fastcgi_pass unix:/var/run/php/php-fpm.sock; + } + +} + diff --git a/chapter12/roles/wordpress/tasks/main.yml b/chapter12/roles/wordpress/tasks/main.yml new file mode 100644 index 0000000..3eb6d36 --- /dev/null +++ b/chapter12/roles/wordpress/tasks/main.yml @@ -0,0 +1,18 @@ +--- +- name: Download and unarchive Wordpress + unarchive: + src: https://wordpress.org/latest.tar.gz + remote_src: True + owner: root + group: www-data + dest: "/var/www/html/" + creates: "/var/www/html/wordpress" + +- name: Configure Wordpress + template: + src: "wp-config.php.j2" + dest: "/var/www/html/wordpress/wp-config.php" + owner: root + group: www-data + mode: 'u=rw,g=r,o=' + diff --git a/chapter12/roles/wordpress/templates/wp-config.php.j2 b/chapter12/roles/wordpress/templates/wp-config.php.j2 new file mode 100644 index 0000000..37347dd --- /dev/null +++ b/chapter12/roles/wordpress/templates/wp-config.php.j2 @@ -0,0 +1,31 @@ +