From a3c30cc5cb949f1fdd91908387248fa74505e389 Mon Sep 17 00:00:00 2001 From: Aravinth Manivannan Date: Sun, 16 Jul 2023 17:28:34 +0530 Subject: [PATCH] feat: deploy loadbalanced libreddit instance --- .gitignore | 11 ++ Makefile | 105 ++++++++++++++++ ansible/.gitignore | 158 ++++++++++++++++++++++++ ansible/init.sh | 19 +++ ansible/libreddit.yml | 63 ++++++++++ ansible/loadbalance.yml | 83 +++++++++++++ ansible/ping.yml | 12 ++ ansible/playbook.yml | 50 ++++++++ ansible/shutdown.yml | 8 ++ cloud_init.cfg | 23 ++++ conf.tf | 210 ++++++++++++++++++++++++++++++++ network_config.cfg | 4 + requirements.txt | 31 +++++ scripts/on.sh | 7 ++ templates/hosts.yml.tftpl | 9 ++ templates/nginx-libreddit.tftpl | 22 ++++ tests/requirements.txt | 9 ++ tests/test_basic.py | 45 +++++++ tests/test_libreddit.py | 40 ++++++ tests/test_loadbalance.py | 47 +++++++ 20 files changed, 956 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 ansible/.gitignore create mode 100755 ansible/init.sh create mode 100644 ansible/libreddit.yml create mode 100644 ansible/loadbalance.yml create mode 100644 ansible/ping.yml create mode 100644 ansible/playbook.yml create mode 100644 ansible/shutdown.yml create mode 100644 cloud_init.cfg create mode 100644 conf.tf create mode 100644 network_config.cfg create mode 100644 requirements.txt create mode 100755 scripts/on.sh create mode 100644 templates/hosts.yml.tftpl create mode 100644 templates/nginx-libreddit.tftpl create mode 100644 tests/requirements.txt create mode 100644 tests/test_basic.py create mode 100644 tests/test_libreddit.py create mode 100644 tests/test_loadbalance.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3a5e0c4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +plan +.terraform/ +.pytest_cache/ +venv/ +__pycache__/ +ansible/inventory/hosts.ini +terraform.tfstate +terraform.tfstate.backup +.terraform/ +.terraform.lock.hcl +bullseye diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b3c2f24 --- /dev/null +++ b/Makefile @@ -0,0 +1,105 @@ +# SPDX-FileCopyrightText: 2023 Aravinth Manivannan +# +# SPDX-License-Identifier: AGPL-3.0-or-later + + +define configure_ping + ansible-playbook -i ./ansible/inventory/hosts.ini -f 10 ./ansible/ping.yml +endef + +define configure_base + ansible-playbook -i ./ansible/inventory/hosts.ini -f 10 ./ansible/playbook.yml +endef + +define configure_loadbalance + ansible-playbook -i ./ansible/inventory/hosts.ini -f 10 ./ansible/loadbalance.yml +endef + +define configure_libreddit + ansible-playbook -i ./ansible/inventory/hosts.ini -f 10 ./ansible/libreddit.yml +endef + +define test_base + . ./venv/bin/activate && \ + cd tests/ && \ + py.test --hosts='ansible://all' \ + -n 10 \ + --verbose \ + --ansible-inventory='../ansible/inventory/hosts.ini' \ + test_basic.py + +endef + +define test_libreddit + . ./venv/bin/activate && \ + cd tests/ && \ + py.test --hosts='ansible://bullseye_libreddit' \ + -n 10 \ + --verbose \ + --ansible-inventory='../ansible/inventory/hosts.ini' \ + test_libreddit.py +endef + + + +define test_loadbalance + . ./venv/bin/activate && \ + cd tests/ && \ + py.test --hosts='ansible://bullseye_loadbalance' \ + -n 10 \ + --verbose \ + --ansible-inventory='../ansible/inventory/hosts.ini' \ + test_loadbalance.py +endef + + +configure: + $(call configure_ping) + $(call configure_base) + $(call configure_libreddit) + $(call configure_loadbalance) + +configure.ping: + $(call configure_ping) + +configure.base: + $(call configure_ping) + $(call configure_base) + +configure.libreddit: + $(call configure_ping) + $(call configure_libreddit) + +configure.loadbalance: + $(call configure_ping) + $(call configure_loadbalance) + + +lint: + terraform fmt + ansible-lint --write ./ansible/playbook.yml + ansible-lint --write ./ansible/shutdown.yml + ansible-lint --write ./ansible/loadbalance.yml + ansible-lint --write ./ansible/libreddit.yml + . ./venv/bin/activate && black tests/ + +on: + ./scripts/on.sh + virsh list + +shutdown: + ansible-playbook -i ./ansible/inventory/hosts.ini -f 10 ./ansible/shutdown.yml + +test: + $(call test_base) + $(call test_loadbalance) + $(call test_libreddit) + +test.base: + $(call test_base) + +test.loadbalance: + $(call test_loadbalance) + +test.libreddit: + $(call test_libreddit) diff --git a/ansible/.gitignore b/ansible/.gitignore new file mode 100644 index 0000000..b899908 --- /dev/null +++ b/ansible/.gitignore @@ -0,0 +1,158 @@ +inventory/ +.env +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ +keys +htmlcov/ +tmp/ +static/ diff --git a/ansible/init.sh b/ansible/init.sh new file mode 100755 index 0000000..c17443e --- /dev/null +++ b/ansible/init.sh @@ -0,0 +1,19 @@ +#!/bin/bash + + +ansible live \ + -m ansible.builtin.ping \ + -i ./ansible/inventory + +ansible live \ + -m ansible.builtin.apt \ + -f 10 \ + -a "update_cache=yes upgrade=safe" \ + -i ./ansible/inventory/ + + +ansible live \ + -m ansible.builtin.apt \ + -f 10 \ + -a "name=nginx,git,curl,wget,vim,zip,nginx" \ + -i ./ansible/inventory/ diff --git a/ansible/libreddit.yml b/ansible/libreddit.yml new file mode 100644 index 0000000..3d5ebce --- /dev/null +++ b/ansible/libreddit.yml @@ -0,0 +1,63 @@ +# SPDX-FileCopyrightText: 2023 Aravinth Manivannan +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +--- +- name: Deploy libreddit + hosts: bullseye_libreddit + remote_user: atm + + tasks: + - name: Ensure all VMs are reachable + ansible.builtin.ping: + + - name: Create /etc/apt/keyrings dir + ansible.builtin.file: + path: /etc/apt/keyrings + state: directory + recurse: true + + - name: Add Docker GPG apt Key + ansible.builtin.apt_key: + url: https://download.docker.com/linux/debian/gpg + state: present + + - name: Add Docker Repository + ansible.builtin.apt_repository: + repo: deb https://download.docker.com/linux/debian buster stable + state: present + + - name: Update apt and install docker-ce + ansible.builtin.apt: + name: docker-ce + update_cache: true + + - name: Install Docker Module for Python + ansible.builtin.pip: + name: docker + + - name: Ensure docker group is present + ansible.builtin.group: + name: docker + state: present + + - name: Add user atm to docker group + ansible.builtin.user: + name: atm + groups: docker,users,admin + + - name: Deploy libreddit + ansible.builtin.docker_container: + name: libreddit + state: started + image: "spikecodes/libreddit" + pull: true + ports: + - "8080:8080" + + - name: Allow port 8080 + community.general.ufw: + state: enabled + proto: tcp + rule: allow + port: "8080" diff --git a/ansible/loadbalance.yml b/ansible/loadbalance.yml new file mode 100644 index 0000000..780ab9f --- /dev/null +++ b/ansible/loadbalance.yml @@ -0,0 +1,83 @@ +# SPDX-FileCopyrightText: 2023 Aravinth Manivannan +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +--- +- name: Configure loadbalancers + hosts: bullseye_loadbalance + remote_user: root + + tasks: + - name: Ensure all VMs are reachable + ansible.builtin.ping: + - name: Update package cache + ansible.builtin.apt: + update_cache: true + upgrade: safe + + - name: Install git, zip, nginx, wget, curl & other utils + ansible.builtin.apt: + update_cache: true + pkg: + - nginx + - ca-certificates + - ufw + + - name: Add user atm to docker group + ansible.builtin.user: + name: atm + groups: users,admin + + - name: Set logging + community.general.ufw: + logging: "on" + + - name: Allow port 22 and enable UFW + community.general.ufw: + state: enabled + rule: allow + proto: tcp + port: "22" + + - name: Allow port 80 + community.general.ufw: + state: enabled + proto: tcp + rule: allow + port: "80" + + - name: Allow port 443 + community.general.ufw: + state: enabled + proto: tcp + rule: allow + port: "443" + + - name: Enable and start ufw service + ansible.builtin.service: + name: ufw + enabled: true + state: started + + - name: Copy the Nginx config file and restart nginx + ansible.builtin.copy: + src: ./assets/nginx.cfg + dest: /etc/nginx/sites-available/nginx.cfg + + - name: Create symlink + ansible.builtin.file: + src: /etc/nginx/sites-available/nginx.cfg + dest: /etc/nginx/sites-enabled/default + state: link + + - name: Enable and start nginx service + ansible.builtin.service: + name: nginx + enabled: true + state: started + + - name: Enable and start nginx service + ansible.builtin.service: + name: nginx + enabled: true + state: restarted diff --git a/ansible/ping.yml b/ansible/ping.yml new file mode 100644 index 0000000..6a09194 --- /dev/null +++ b/ansible/ping.yml @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: 2023 Aravinth Manivannan +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +--- +- name: Configure webservers + hosts: [bullseye_libreddit,bullseye_loadbalance] + remote_user: root + + tasks: + - name: Ensure all VMs are reachable + ansible.builtin.ping: diff --git a/ansible/playbook.yml b/ansible/playbook.yml new file mode 100644 index 0000000..ee2a154 --- /dev/null +++ b/ansible/playbook.yml @@ -0,0 +1,50 @@ +# SPDX-FileCopyrightText: 2023 Aravinth Manivannan +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +--- +- name: Configure webservers + hosts: [bullseye_libreddit,bullseye_loadbalance] + remote_user: root + + tasks: + - name: Ensure all VMs are reachable + ansible.builtin.ping: + - name: Update package cache + ansible.builtin.apt: + update_cache: true + upgrade: safe + + - name: Install git, zip, nginx, wget, curl & other utils + ansible.builtin.apt: + update_cache: true + pkg: + - git + - wget + - curl + - gpg + - ca-certificates + - zip + - python3-pip + - virtualenv + - ufw + - python3-setuptools + + + - name: Set logging + community.general.ufw: + logging: "on" + + - name: Allow port 22 and enable UFW + community.general.ufw: + state: enabled + rule: allow + proto: tcp + port: "22" + + + - name: Enable and start ufw service + ansible.builtin.service: + name: ufw + enabled: true + state: started diff --git a/ansible/shutdown.yml b/ansible/shutdown.yml new file mode 100644 index 0000000..2df37a1 --- /dev/null +++ b/ansible/shutdown.yml @@ -0,0 +1,8 @@ +--- +- name: Shutdown machines + hosts: [bullseye_loadbalance,bullseye_app] + remote_user: root + + tasks: + - name: Ensure all VMs are reachable + community.general.shutdown: diff --git a/cloud_init.cfg b/cloud_init.cfg new file mode 100644 index 0000000..1a4f40b --- /dev/null +++ b/cloud_init.cfg @@ -0,0 +1,23 @@ +#cloud-config +# vim: syntax=yaml + +users: +- name: root + ssh_authorized_keys: + - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC/wXdHpwpY/4ubhYTmuNdGepQpj1kchvTUTApxMZyfyVW4uzrPRTYsle1y9QbTBV35qLkNajRC/wmC5/xPchdXpsJpuD9st1HMhLeR8qwaPyptiYJYT+z/WisWw2k6oWhG3QKvPoRtBdW9nhZnkG+O6zkuGXiRHpS7j2VVboDPpWEe1UdELQFVCwfraRal2g3ENFZ/9V1UrW/4ahRnQnSxERplZUm/fgSxQtmXubTkW68ut7yasBsrKFffMm8JztW0tWgTlTKONd3LCjv4juM0t5+cJDotNDnUR86Tq2PG8io7no/h8BWtazmjdpfGgn02ibX26BkdU0LDEYbJt5q9/Fh9TGk2ZwcMQeyepO1AWQgkmHXZWZELqu6MLQpqdtsOjHp9k0MeSpuIbdwzgf10Ydy7vK1z8irS24tVNNnJaMBwOlVOPwfyztHRADPkFcv2lKSjS1uyKR0FIkV8Kvs4txaIjmwv2LfMg6lF5W6j3ZPLyeE4cplJP0DDjzorSanu31xVnqVb3A8V9awsJ/4H7d59bI99c7QHL4K3fBVP3O0gqd31xAVRsdGs5Tj2P+RpiI6o5JJiOa1+DuBdWzrVIXYchQ30ZjaJp1wTNsYLmAsjeYuQZE2tf1xvywdzD4MB4avugDEWikzRWN9V5PHDZr1bamTCCjOrb2PRCd7eSQ== aravinth7820@gmail.com +- name: atm + gecos: Aravinth Manivannan + groups: users, admin + sudo: ALL=(ALL) NOPASSWD:ALL + shell: /bin/bash + lock_passwd: true + plain_text_passwd: fooabr12 + ssh_authorized_keys: + - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC/wXdHpwpY/4ubhYTmuNdGepQpj1kchvTUTApxMZyfyVW4uzrPRTYsle1y9QbTBV35qLkNajRC/wmC5/xPchdXpsJpuD9st1HMhLeR8qwaPyptiYJYT+z/WisWw2k6oWhG3QKvPoRtBdW9nhZnkG+O6zkuGXiRHpS7j2VVboDPpWEe1UdELQFVCwfraRal2g3ENFZ/9V1UrW/4ahRnQnSxERplZUm/fgSxQtmXubTkW68ut7yasBsrKFffMm8JztW0tWgTlTKONd3LCjv4juM0t5+cJDotNDnUR86Tq2PG8io7no/h8BWtazmjdpfGgn02ibX26BkdU0LDEYbJt5q9/Fh9TGk2ZwcMQeyepO1AWQgkmHXZWZELqu6MLQpqdtsOjHp9k0MeSpuIbdwzgf10Ydy7vK1z8irS24tVNNnJaMBwOlVOPwfyztHRADPkFcv2lKSjS1uyKR0FIkV8Kvs4txaIjmwv2LfMg6lF5W6j3ZPLyeE4cplJP0DDjzorSanu31xVnqVb3A8V9awsJ/4H7d59bI99c7QHL4K3fBVP3O0gqd31xAVRsdGs5Tj2P+RpiI6o5JJiOa1+DuBdWzrVIXYchQ30ZjaJp1wTNsYLmAsjeYuQZE2tf1xvywdzD4MB4avugDEWikzRWN9V5PHDZr1bamTCCjOrb2PRCd7eSQ== aravinth7820@gmail.com + +ssh_pwauth: true +chpasswd: + list: | + root:foobar12 + atm:foobar12 + expire: False diff --git a/conf.tf b/conf.tf new file mode 100644 index 0000000..e04ebe9 --- /dev/null +++ b/conf.tf @@ -0,0 +1,210 @@ +terraform { + required_version = ">= 0.13" + required_providers { + libvirt = { + source = "dmacvicar/libvirt" + version = "~> 0.7.0" + } + } +} + +# instance the provider +provider "libvirt" { + uri = "qemu:///system" +} + +resource "libvirt_pool" "bullseye_basic" { + name = "bullseye_basic" + type = "dir" + path = "/home/atm/code/libvirt/pool/bullseye_basic" + +} + +# We fetch the latest bullseye_basic release image from their mirrors +resource "libvirt_volume" "debian-bullseye-qcow2" { + name = "debian-bullseye-qcow2" + pool = libvirt_pool.bullseye_basic.name + source = "/home/atm/disk-images/debian/11/cloud/debian-11-genericcloud-amd64.qcow2" + format = "qcow2" +} + +variable "loadbalance_count" { + default = 1 +} + + +variable "libreddit_count" { + default = 4 +} + + +resource "libvirt_volume" "domain_bullseye_loadbalance_volume" { + name = "domain_bullseye_loadbalance_volume-${count.index}" + base_volume_id = libvirt_volume.debian-bullseye-qcow2.id + count = var.loadbalance_count + pool = libvirt_pool.bullseye_basic.name + size = 85368709120 +} + + +resource "libvirt_volume" "domain_bullseye_libreddit_volume" { + name = "domain_bullseye_libreddit_volume-${count.index}" + base_volume_id = libvirt_volume.debian-bullseye-qcow2.id + pool = libvirt_pool.bullseye_basic.name + count = var.libreddit_count + size = 85368709120 +} + +data "template_file" "user_data" { + template = file("${path.module}/cloud_init.cfg") +} + +data "template_file" "network_config" { + template = file("${path.module}/network_config.cfg") +} + +# for more info about paramater check this out +# https://github.com/dmacvicar/terraform-provider-libvirt/blob/loadbalance/website/docs/r/cloudinit.html.markdown +# Use CloudInit to add our ssh-key to the instance +# you can add also meta_data field +resource "libvirt_cloudinit_disk" "commoninit" { + name = "commoninit.iso" + user_data = data.template_file.user_data.rendered + network_config = data.template_file.network_config.rendered + pool = libvirt_pool.bullseye_basic.name +} + +# Create the libreddit machine +resource "libvirt_domain" "domain_bullseye_libreddit" { + count = var.libreddit_count + + name = "bullseye_libreddit_${count.index}" + memory = "3000" + vcpu = 4 + + cloudinit = libvirt_cloudinit_disk.commoninit.id + + network_interface { + network_name = "default" + wait_for_lease = true + } + + # IMPORTANT: this is a known bug on cloud images, since they expect a console + # we need to pass it + # https://bugs.launchpad.net/cloud-images/+bug/1573095 + console { + type = "pty" + target_port = "0" + target_type = "serial" + } + + console { + type = "pty" + target_type = "virtio" + target_port = "1" + } + + disk { + volume_id = element(libvirt_volume.domain_bullseye_libreddit_volume.*.id, count.index) + } + + graphics { + type = "spice" + listen_type = "address" + autoport = true + } +} + +# Create the machine +resource "libvirt_domain" "domain_bullseye_loadbalance" { + count = var.loadbalance_count + + name = "bullseye_loadbalance_${count.index}" + memory = "3000" + vcpu = 4 + + cloudinit = libvirt_cloudinit_disk.commoninit.id + + network_interface { + network_name = "default" + wait_for_lease = true + } + + # IMPORTANT: this is a known bug on cloud images, since they expect a console + # we need to pass it + # https://bugs.launchpad.net/cloud-images/+bug/1573095 + console { + type = "pty" + target_port = "0" + target_type = "serial" + } + + console { + type = "pty" + target_type = "virtio" + target_port = "1" + } + + disk { + volume_id = element(libvirt_volume.domain_bullseye_loadbalance_volume.*.id, count.index) + } + + graphics { + type = "spice" + listen_type = "address" + autoport = true + } +} + +locals { + libreddit_vm_ips = [for i in libvirt_domain.domain_bullseye_libreddit : i.network_interface.0.addresses[0]] + libreddit_vm_names = [for i in libvirt_domain.domain_bullseye_libreddit : i.name] + libreddit_vm_map = [for i in libvirt_domain.domain_bullseye_libreddit : { + ip = i.network_interface.0.addresses[0], + name = i.name + }] + + loadbalance_vm_ips = [for i in libvirt_domain.domain_bullseye_loadbalance : i.network_interface.0.addresses[0]] + loadbalance_vm_names = [for i in libvirt_domain.domain_bullseye_loadbalance : i.name] + loadbalance_vm_map = [for i in libvirt_domain.domain_bullseye_loadbalance : { + ip = i.network_interface.0.addresses[0], + name = i.name + }] + + +} +output "bullseye_libreddit_ip" { + value = local.libreddit_vm_map +} + +output "bullseye_loadbalance_ip" { + value = local.loadbalance_vm_map +} + +resource "local_file" "hosts_yml" { + content = templatefile("./templates/hosts.yml.tftpl", + { + libreddit_vm_ips = local.libreddit_vm_ips, + libreddit_vm_names = local.libreddit_vm_names, + libreddit_vms = local.libreddit_vm_map, + + loadbalance_vm_ips = local.loadbalance_vm_ips, + loadbalance_vm_names = local.loadbalance_vm_names, + loadbalance_vms = local.loadbalance_vm_map + + }) + + filename = "./ansible/inventory/hosts.ini" +} + +resource "local_file" "nginx_loadbalance_conf" { + content = templatefile("./templates/nginx-libreddit.tftpl", + { + libreddit_vm_ips = local.libreddit_vm_ips, + libreddit_vm_names = local.libreddit_vm_names, + libreddit_vms = local.libreddit_vm_map, + + }) + + filename = "./ansible/assets/nginx.cfg" +} diff --git a/network_config.cfg b/network_config.cfg new file mode 100644 index 0000000..5b2cbca --- /dev/null +++ b/network_config.cfg @@ -0,0 +1,4 @@ +version: 2 +ethernets: + ens3: + dhcp4: true diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..6e46125 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,31 @@ +ansible==8.1.0 +ansible-core==2.15.1 +certifi==2023.5.7 +cffi==1.15.1 +charset-normalizer==3.2.0 +contextvars==2.4 +cryptography==41.0.2 +distro==1.8.0 +execnet==2.0.2 +idna==3.4 +immutables==0.19 +iniconfig==2.0.0 +Jinja2==3.1.2 +jmespath==1.0.1 +looseversion==1.3.0 +MarkupSafe==2.1.3 +msgpack==1.0.5 +packaging==23.1 +pluggy==1.2.0 +psutil==5.9.5 +pycparser==2.21 +pycryptodomex==3.18.0 +pytest==7.4.0 +pytest-testinfra==8.1.0 +pytest-xdist==3.3.1 +PyYAML==6.0 +pyzmq==25.0.2 +requests==2.31.0 +resolvelib==1.0.1 +salt==3006.1 +urllib3==2.0.3 diff --git a/scripts/on.sh b/scripts/on.sh new file mode 100755 index 0000000..cc953cb --- /dev/null +++ b/scripts/on.sh @@ -0,0 +1,7 @@ +#!/bin/bash + + +for vm in $(virsh list --all --name --state-shutoff); do \ + echo "[*] Starting vm: $vm"; \ + virsh start $vm; \ +done diff --git a/templates/hosts.yml.tftpl b/templates/hosts.yml.tftpl new file mode 100644 index 0000000..42bea26 --- /dev/null +++ b/templates/hosts.yml.tftpl @@ -0,0 +1,9 @@ +[bullseye_loadbalance] +%{ for vm in loadbalance_vms ~} +${vm.name} ansible_host=${vm.ip} ansible_user=root +%{ endfor ~} + +[bullseye_libreddit] +%{ for vm in libreddit_vms ~} +${vm.name} ansible_host=${vm.ip} ansible_user=root +%{ endfor ~} diff --git a/templates/nginx-libreddit.tftpl b/templates/nginx-libreddit.tftpl new file mode 100644 index 0000000..cac70be --- /dev/null +++ b/templates/nginx-libreddit.tftpl @@ -0,0 +1,22 @@ +upstream libreddit { + %{ for vm in libreddit_vms ~} + server ${vm.ip}:8080; #${vm.name} + %{ endfor ~} +} + +server { + + listen 80 default_server; + listen [::]:80 default_server; + + server_name _; + + location / { + + proxy_read_timeout 300s; + + proxy_pass http://libreddit; #pass all requests processed to the libreddit upstream servers + proxy_http_version 1.1; + + } +} diff --git a/tests/requirements.txt b/tests/requirements.txt new file mode 100644 index 0000000..168bebf --- /dev/null +++ b/tests/requirements.txt @@ -0,0 +1,9 @@ +attrs==22.1.0 +iniconfig==1.1.1 +packaging==21.3 +pluggy==1.0.0 +py==1.11.0 +pyparsing==3.0.9 +pytest==7.1.3 +pytest-testinfra==6.8.0 +tomli==2.0.1 diff --git a/tests/test_basic.py b/tests/test_basic.py new file mode 100644 index 0000000..1b1bb96 --- /dev/null +++ b/tests/test_basic.py @@ -0,0 +1,45 @@ +# SPDX-FileCopyrightText: 2023 Aravinth Manivannan +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +import os + + +def test_packages_are_installed(host): + packages = [ + "git", + "wget", + "curl", + "gpg", + "ca-certificates", + "zip", + "python3-pip", + "virtualenv", + "python3-setuptools", + ] + for p in packages: + print(f"[*] Checking if {p} is installed") + pkg = host.package(p) + assert pkg.is_installed + + +def test_ssh_is_listening(host): + socket = host.socket(f"tcp://0.0.0.0:22") + assert socket.is_listening + + +def test_ufw_service_running_and_enabled(host): + service = host.service("ufw") + assert service.is_running + assert service.is_enabled + + +def test_ssh_service_running_and_enabled(host): + service = host.service("ssh") + assert service.is_running + assert service.is_enabled + + +def test_ssh_is_installed(host): + pkg = host.package("openssh-server") + assert pkg.is_installed diff --git a/tests/test_libreddit.py b/tests/test_libreddit.py new file mode 100644 index 0000000..a7e81ae --- /dev/null +++ b/tests/test_libreddit.py @@ -0,0 +1,40 @@ +# SPDX-FileCopyrightText: 2023 Aravinth Manivannan +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +import os + + +def test_packages_are_installed(host): + packages = [ + "ufw", + "docker-ce", + ] + for p in packages: + print(f"[*] Checking if {p} is installed") + pkg = host.package(p) + assert pkg.is_installed + +def test_docker_is_installed(host): + keyring_dir = host.file("/etc/apt/keyrings") + assert keyring_dir.exists + assert keyring_dir.is_directory + +def test_docker_is_installed(host): + keyring_dir = host.file("/etc/apt/keyrings") + assert keyring_dir.exists + assert keyring_dir.is_directory + + +def test_ufw_service_running_and_enabled(host): + service = host.service("ufw") + assert service.is_running + assert service.is_enabled + +def test_libreddit_docker_img(host): + libreddit = host.docker("libreddit") + assert libreddit.is_running + +def test_libreddit_is_listening(host): + socket = host.socket(f"tcp://0.0.0.0:8080") + assert socket.is_listening diff --git a/tests/test_loadbalance.py b/tests/test_loadbalance.py new file mode 100644 index 0000000..ba64f5f --- /dev/null +++ b/tests/test_loadbalance.py @@ -0,0 +1,47 @@ +# SPDX-FileCopyrightText: 2023 Aravinth Manivannan +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +import os + + +def test_packages_are_installed(host): + packages = [ + "nginx", + "ufw", + "git", + "nginx", + "wget", + "curl", + "gpg", + "ca-certificates", + "zip", + "python3-pip", + "virtualenv", + "python3-setuptools", + ] + for p in packages: + print(f"[*] Checking if {p} is installed") + pkg = host.package(p) + assert pkg.is_installed + + + +def test_nginx_service_running_and_enabled(host): + service = host.service("nginx") + assert service.is_running + assert service.is_enabled + +def test_config_is_present(host): + file = host.file("/etc/nginx/sites-available/nginx.cfg") + assert file.exists + assert file.is_file + + sym_file = host.file("/etc/nginx/sites-enabled/default") + assert sym_file.exists + assert sym_file.is_symlink + assert sym_file.linked_to == file + +def test_nginx_is_listening(host): + socket = host.socket(f"tcp://0.0.0.0:80") + assert socket.is_listening