├── .ansible-lint ├── .devcontainer ├── Dockerfile ├── devcontainer.json └── requirements.txt ├── .editorconfig ├── LICENSE ├── README.md ├── Vagrantfile ├── ansible.cfg ├── cleanup.yml ├── inventory ├── group_vars │ └── all └── hosts ├── site.yml └── templates ├── app.service.j2 └── nginx.conf.j2 /.ansible-lint: -------------------------------------------------------------------------------- 1 | --- 2 | exclude_paths: 3 | - .cache/ 4 | - .devcontainer 5 | - .github/ 6 | - ./collections/ 7 | 8 | warn_list: 9 | - role-name 10 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # [Choice] Python version: 3, 3.10, 3.9, 3.8, 3.7, 3.6 2 | ARG VARIANT=3 3 | FROM mcr.microsoft.com/vscode/devcontainers/python:${VARIANT} 4 | 5 | # [Option] Install Node.js 6 | ARG INSTALL_NODE="true" 7 | ARG NODE_VERSION="lts/*" 8 | RUN if [ "${INSTALL_NODE}" = "true" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi 9 | 10 | # [Optional] If your pip requirements rarely change, uncomment this section to add them to the image. 11 | COPY requirements.txt /tmp/pip-tmp/ 12 | RUN pip3 --disable-pip-version-check --no-cache-dir install -r /tmp/pip-tmp/requirements.txt \ 13 | && rm -rf /tmp/pip-tmp 14 | 15 | # [Optional] Uncomment this section to install additional OS packages. 16 | RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 17 | && apt-get -y install --no-install-recommends sshpass 18 | 19 | # [Optional] Uncomment this line to install global node packages. 20 | # RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g " 2>&1 21 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Python 3", 3 | "build": { 4 | "dockerfile": "Dockerfile", 5 | "args": { 6 | "VARIANT": "3.10", 7 | "INSTALL_NODE": "true", 8 | "NODE_VERSION": "lts/*" 9 | } 10 | }, 11 | "settings": { 12 | "terminal.integrated.profiles.linux": { 13 | "bash (login)": { 14 | "path": "bash", 15 | "args": [ 16 | "-l" 17 | ] 18 | } 19 | }, 20 | "python.pythonPath": "/usr/local/bin/python", 21 | "python.languageServer": "Pylance", 22 | "python.linting.enabled": true, 23 | "python.linting.pylintEnabled": true, 24 | "python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8", 25 | "python.formatting.blackPath": "/usr/local/py-utils/bin/black", 26 | "python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf", 27 | "python.linting.banditPath": "/usr/local/py-utils/bin/bandit", 28 | "python.linting.flake8Path": "/usr/local/py-utils/bin/flake8", 29 | "python.linting.mypyPath": "/usr/local/py-utils/bin/mypy", 30 | "python.linting.pycodestylePath": "/usr/local/py-utils/bin/pycodestyle", 31 | "python.linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle", 32 | "python.linting.pylintPath": "/usr/local/py-utils/bin/pylint" 33 | }, 34 | "extensions": [ 35 | "github.vscode-pull-request-github", 36 | "ms-python.python", 37 | "ms-python.vscode-pylance", 38 | "redhat.vscode-yaml" 39 | ], 40 | "forwardPorts": [], 41 | "postCreateCommand": "ansible-galaxy collection install -r requirements.yml -p ./collections && ansible-galaxy role install -r requirements.yml -p ./roles", 42 | "remoteUser": "vscode" 43 | } -------------------------------------------------------------------------------- /.devcontainer/requirements.txt: -------------------------------------------------------------------------------- 1 | ansible==5.6.0 2 | ansible-lint==6.7.0 3 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_spaces = false 13 | max_line_length = 80 14 | 15 | [*.yml] 16 | indent_style = space 17 | indent_size = 2 18 | 19 | [*.json] 20 | insert_final_newline = false 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 DmyMi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ansible Lab 2 | 3 | ## Requirements 4 | 5 | * Python 3.x 6 | * Python 3 Pip (sudo apt install python3-pip) 7 | * Ansible 5.x (`sudo pip3 install ansible`) 8 | * It's better to have Ubuntu or other Debian-based linux (for other linux distros you will need to modify package installation commands) 9 | * Template works on localhost, but you can do it remotely on a server that is available through SSH by modifying [inventory](./inventory/hosts) (remote group) and [site.yml](./site.yml) (host variable) 10 | 11 | ## Before tasks 12 | 13 | ### If you have GitLab account 14 | Fork this project by clicking [https://gitlab.com/DmyMi/ansible-lab/-/forks/new](https://gitlab.com/DmyMi/ansible-lab/-/forks/new) 15 | ### If you have GitHub account 16 | Follow this article [https://nira.com/how-to-migrate-from-gitlab-to-github/](https://nira.com/how-to-migrate-from-gitlab-to-github/) to copy the project to your Github. 17 | 18 | Doing the lab requires you to know how to use Git :) 19 | 20 | ## Tasks 21 | 22 | Write an Ansible playbook using the template in [site.yml](./site.yml). 23 | 24 | The playbook itself is an Ansible version of Lab 1 with extra steps :) 25 | 26 | 1. The playbook should use the `packages`, `aptcachetime`, `app_dir`, `app_file` variables defined in [all](./inventory/group_vars/all) vars file. 27 | 2. Playbook should use the [app.service.j2](./templates/app.service.j2) that you need to write. Use the `app_dir`, `app_file` variables to specify the path to Java app. Use the `app_port` variable to specifyt the `PORT` environment variable for Java app. 28 | * If you have created additional users for Lab1 - add the user creation to `site.yml` with the help of [user module](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/user_module.html). 29 | 3. Playbook should use the [nginx.conf.j2](./templates/nginx.conf.j2) template with a simple Nginx config. There you should write the `server` block to let Nginx listen on port `80`. Nginx should *proxy* all requests to Java app at `localhost:`. Target port should be specified dynamically using the `app_port` variable. 30 | 31 | To run the playbook if it's written correctly: 32 | ```bash 33 | # If you have paswordless SUDO 34 | ansible-playbook site.yml 35 | # or if you have password SUDO 36 | ansible-playbook site.yml -K 37 | ``` 38 | 39 | ## Cleanup 40 | 41 | The [cleanup.yml](./cleanup.yml) playbook can be used to remove everything from you server/vm (if you followed the template and did not add additional packages). 42 | 43 | ```bash 44 | # If you have paswordless SUDO 45 | ansible-playbook cleanup.yml 46 | # or if you have password SUDO 47 | ansible-playbook cleanup.yml -K 48 | ``` 49 | 50 | ## Submission 51 | 52 | All i need is a link to your Github/Gitlab project in Classroom. -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | Vagrant.configure("2") do |config| 5 | config.vm.box = "ubuntu/focal64" 6 | config.vm.hostname = "vagrant-ubuntu2004" 7 | config.vm.define "ubuntu2004" 8 | config.vm.network "private_network", ip: "192.168.56.222" 9 | 10 | config.vm.provider "virtualbox" do |vb| 11 | vb.name = "ubuntu2004" 12 | vb.memory = "2048" 13 | end 14 | 15 | config.vm.provision "ansible" do |ansible| 16 | ansible.playbook = "site.yml" 17 | ansible.inventory_path = "inventory/" 18 | ansible.host_key_checking = false 19 | ansible.limit = "vagrant" 20 | end 21 | 22 | end 23 | -------------------------------------------------------------------------------- /ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | inventory = inventory/ 3 | roles_path = ./roles/ 4 | collections_paths = ./collections 5 | host_key_checking = False 6 | retry_files_enabled = False 7 | 8 | gathering = smart 9 | 10 | [ssh_connection] 11 | pipelining = True 12 | -------------------------------------------------------------------------------- /cleanup.yml: -------------------------------------------------------------------------------- 1 | - name: Cleanup 2 | # TODO: change to remote if you have one 3 | hosts: local 4 | become: true 5 | tasks: 6 | - name: Remove packages 7 | apt: 8 | name: "{{ item }}" 9 | state: absent 10 | loop: "{{ packages }}" 11 | - name: Stop sample.service 12 | ansible.builtin.systemd: 13 | name: sample.service 14 | state: stopped 15 | enabled: no 16 | - name: Remove sample.service 17 | ansible.builtin.file: 18 | path: /etc/systemd/system/sample.service 19 | state: absent 20 | - name: Reload Systemd 21 | ansible.builtin.systemd: 22 | daemon_reload: yes 23 | - name: Force delete Unit 24 | ansible.builtin.shell: systemctl reset-failed 25 | - name: Remove {{ app_dir }}/{{ app_file }} 26 | ansible.builtin.file: 27 | path: "{{ app_dir }}/{{ app_file }}" 28 | state: absent -------------------------------------------------------------------------------- /inventory/group_vars/all: -------------------------------------------------------------------------------- 1 | --- 2 | # these are the variables which apply to every host in this playbook 3 | packages: 4 | - nginx 5 | - openjdk-11-jre 6 | aptcachetime: 3600 7 | app_dir: /opt/sample 8 | app_file: service.jar 9 | app_port: 8080 -------------------------------------------------------------------------------- /inventory/hosts: -------------------------------------------------------------------------------- 1 | [vagrant] 2 | vagrant-vm ansible_host=192.168.56.222 ansible_user=vagrant ansible_ssh_private_key_file='.vagrant/machines/ubuntu2004/virtualbox/private_key' 3 | 4 | [remote] 5 | # TODO: if you are doing a remote config - change the values here 6 | remote-server ansible_host= ansible_user= 7 | 8 | [local] 9 | localhost ansible_connection=local -------------------------------------------------------------------------------- /site.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ansible lab 3 | # TODO: change to remote if you have one 4 | hosts: local 5 | gather_facts: true 6 | 7 | tasks: 8 | # Use {{ aptcachetime }} variable to specify cache time 9 | # Find implementation in https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt_module.html#examples 10 | - name: Install some basic packages defined in variable "packages" 11 | become: true 12 | apt: 13 | name: "{{ item }}" 14 | update_cache: yes 15 | cache_valid_time: "{{ aptcachetime }}" 16 | loop: "{{ packages }}" 17 | 18 | # Find implementation in https://docs.ansible.com/ansible/latest/collections/ansible/builtin/systemd_module.html#examples 19 | - name: Enable Nginx service, ensure it is not masked and start it 20 | become: true 21 | ansible.builtin.systemd: 22 | name: nginx.service 23 | enabled: yes 24 | state: started 25 | masked: no 26 | 27 | # Find implementation in https://docs.ansible.com/ansible/latest/collections/ansible/builtin/file_module.html#examples 28 | # path should be {{ app_dir }} 29 | # owner should be {{ ansible_user_id }} 30 | # mode should be 755 31 | - name: Create {{ app_dir }} directory if it does not exist 32 | become: true 33 | ansible.builtin.file: 34 | path: "{{ app_dir }}" 35 | state: directory 36 | mode: "775" 37 | owner: "{{ ansible_user_id }}" 38 | 39 | # Find implementation in https://docs.ansible.com/ansible/latest/collections/ansible/builtin/get_url_module.html#examples 40 | # Download url: https://storage.googleapis.com/devops-practice-files/systemd/ServicesLab-0.0.1.jar 41 | # dest should be {{ app_dir }}/{{ app_file }} 42 | # owner should be {{ ansible_user_id }} 43 | # mode should be 644 44 | - name: Download Java app to {{ app_dir }}/{{ app_file }} 45 | ansible.builtin.get_url: 46 | url: "https://storage.googleapis.com/devops-practice-files/systemd/ServicesLab-0.0.1.jar" 47 | dest: "{{ app_dir }}/{{ app_file }}" 48 | owner: "{{ ansible_user_id }}" 49 | mode: "644" 50 | 51 | # Find implementation in https://docs.ansible.com/ansible/latest/collections/ansible/builtin/template_module.html#examples 52 | # dest should be /etc/systemd/system/sample.service 53 | # source is app.service.j2 54 | # mode should be 644 55 | # owner should be root 56 | # group should be root 57 | - name: Create a Java App Unit 58 | become: true 59 | # To show how handlers work. This happens when you change the template that already exists 60 | notify: 61 | - Reload Systemd 62 | ansible.builtin.template: 63 | dest: /etc/systemd/system/sample.service 64 | src: "templates/app.service.j2" 65 | mode: "644" 66 | owner: root 67 | group: root 68 | 69 | # Find implementation in https://docs.ansible.com/ansible/latest/collections/ansible/builtin/systemd_module.html#examples 70 | - name: Enable sample.service, ensure it is not masked and start it 71 | become: true 72 | ansible.builtin.systemd: 73 | name: sample.service 74 | enabled: yes 75 | state: started 76 | masked: no 77 | 78 | # Find implementation in https://docs.ansible.com/ansible/latest/collections/ansible/builtin/template_module.html#examples 79 | # dest should be /etc/nginx/nginx.conf 80 | # source is nginx.conf.j2 81 | # mode should be 644 82 | # owner should be root 83 | # group should be root 84 | - name: Create a Nginx config 85 | become: true 86 | ansible.builtin.template: 87 | dest: /etc/nginx/nginx.conf 88 | src: "templates/nginx.conf.j2" 89 | mode: "644" 90 | owner: root 91 | group: root 92 | 93 | # Find implementation in https://docs.ansible.com/ansible/latest/collections/ansible/builtin/systemd_module.html#examples 94 | - name: Restart Nginx 95 | become: true 96 | ansible.builtin.systemd: 97 | name: nginx.service 98 | state: restarted 99 | 100 | handlers: 101 | # Do a daemon reload 102 | # Find implementation in https://docs.ansible.com/ansible/latest/collections/ansible/builtin/systemd_module.html#examples 103 | - name: Reload Systemd 104 | become: true 105 | ansible.builtin.systemd: 106 | daemon_reload: yes 107 | -------------------------------------------------------------------------------- /templates/app.service.j2: -------------------------------------------------------------------------------- 1 | {# 2 | TODO: reuse your unit from Lab 1 3 | TODO: Path to jar should use variables {{ app_dir }}/{{ app_file }} 4 | TODO: Environment variable for PORT should use value from variable {{ app_port }} 5 | #} 6 | [Unit] 7 | Description=Uryn Dmytro Lab 3 8 | Requires=network-online.target local-fs.target 9 | After=network-online.target local-fs.target 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | 14 | [Service] 15 | ExecStart=java -jar {{ app_dir }}/{{ app_file }} 16 | User=dmytro 17 | Environment=PORT={{ app_port }} 18 | Restart=always 19 | RestartSec=20 20 | -------------------------------------------------------------------------------- /templates/nginx.conf.j2: -------------------------------------------------------------------------------- 1 | {# 2 | Not the best way, but we will re-write entire default config :) 3 | Setup Nginx to listen on port 80 as a reverse proxy. 4 | Proxy pass destination should use {{ app_port }} variable 5 | to specify port on localhost where Java app lives 6 | #} 7 | user www-data; 8 | worker_processes auto; 9 | pid /run/nginx.pid; 10 | include /etc/nginx/modules-enabled/*.conf; 11 | 12 | events { 13 | worker_connections 768; 14 | } 15 | 16 | http { 17 | sendfile on; 18 | tcp_nopush on; 19 | types_hash_max_size 2048; 20 | 21 | include /etc/nginx/mime.types; 22 | default_type application/octet-stream; 23 | 24 | 25 | access_log /var/log/nginx/access.log; 26 | error_log /var/log/nginx/error.log; 27 | 28 | gzip on; 29 | 30 | server { 31 | listen 80; 32 | server_name localhost; 33 | 34 | location / { 35 | proxy_pass http://localhost:{{ app_port }}; 36 | } 37 | } 38 | } 39 | --------------------------------------------------------------------------------