Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
8dac7eb
feat: add lab1 submission
AlliumPro Jan 25, 2026
1798d09
Merge pull request #1 from AlliumPro/lab1
AlliumPro Feb 2, 2026
e6a514b
feat: add lab2 submission
AlliumPro Feb 2, 2026
89f4957
Merge pull request #2 from AlliumPro/lab2
AlliumPro Feb 7, 2026
4be02f4
Add workflow, tests, dev deps and report
AlliumPro Feb 7, 2026
199aef2
fix workflow
AlliumPro Feb 7, 2026
379f19b
fix workflow
AlliumPro Feb 7, 2026
dee4119
fix workflow
AlliumPro Feb 7, 2026
e828285
fix workflow
AlliumPro Feb 7, 2026
3d8b1dc
fix workflow
AlliumPro Feb 7, 2026
7ae1dcc
fix workflow
AlliumPro Feb 7, 2026
d5cb02e
fix workflow
AlliumPro Feb 7, 2026
3032c7f
Add screenshots
AlliumPro Feb 7, 2026
457cc45
Merge branch 'inno-devops-labs:master' into master
AlliumPro Feb 19, 2026
274e214
Merge pull request #3 from AlliumPro/lab3
AlliumPro Feb 19, 2026
f65fb89
feat: lab4
AlliumPro Feb 19, 2026
5494e2d
Merge branch 'inno-devops-labs:master' into master
AlliumPro Feb 26, 2026
e0de688
Merge pull request #4 from AlliumPro/lab04
AlliumPro Feb 26, 2026
621c386
feat: add lab5
AlliumPro Feb 26, 2026
fb4bd72
Merge pull request #5 from AlliumPro/lab05
AlliumPro Mar 5, 2026
88576fd
Complete Lab 06 main tasks and report
AlliumPro Mar 5, 2026
12014a2
Enable lab06 workflow trigger and branch badge
AlliumPro Mar 5, 2026
681f127
Fix ansible-lint violations for Lab 6 workflow
AlliumPro Mar 5, 2026
c0a19c9
Fix SSH key parsing for GitHub Actions deploy
AlliumPro Mar 5, 2026
3d1190a
Improve SSH secret parsing and diagnostics in Actions
AlliumPro Mar 5, 2026
6b02f2c
Remove sudo requirement from web_app deploy path
AlliumPro Mar 5, 2026
7a8ae81
Merge pull request #6 from AlliumPro/lab06
AlliumPro Mar 11, 2026
e2ed071
feat: do lab 7
AlliumPro Mar 11, 2026
dfb2ce8
Complete Lab 7: Loki stack, dashboards, JSON logging, Ansible bonus
AlliumPro Mar 11, 2026
aff5531
fix
AlliumPro Mar 11, 2026
bf55bfd
Merge pull request #7 from AlliumPro/lab07
AlliumPro Mar 19, 2026
b59b391
lab08: add Prometheus metrics stack, dashboards, and ansible automation
AlliumPro Mar 19, 2026
ced0769
feat: do lab 8 task
AlliumPro Mar 19, 2026
aa1809a
Merge pull request #8 from AlliumPro/lab08
AlliumPro Mar 26, 2026
6cb4bc1
Merge branch 'inno-devops-labs:master' into master
AlliumPro Mar 26, 2026
f820fa5
feat: do lab 9 tasks
AlliumPro Mar 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[flake8]
max-line-length = 120
exclude = .git,__pycache__,.venv,venv,app_python/.venv,app_python/venv
124 changes: 124 additions & 0 deletions .github/workflows/ansible-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
name: Ansible Deploy (Python App)

on:
push:
branches: [main, master, lab06]
paths:
- 'ansible/vars/app_python.yml'
- 'ansible/playbooks/provision.yml'
- 'ansible/playbooks/deploy.yml'
- 'ansible/playbooks/deploy_python.yml'
- 'ansible/roles/common/**'
- 'ansible/roles/docker/**'
- 'ansible/roles/web_app/**'
- '.github/workflows/ansible-deploy.yml'
- '!ansible/docs/**'
pull_request:
branches: [main, master, lab06]
paths:
- 'ansible/**'
- '.github/workflows/ansible-deploy.yml'
workflow_dispatch:

jobs:
lint:
name: Ansible Lint
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install Ansible tooling
run: |
python -m pip install --upgrade pip
pip install ansible-core ansible-lint
ansible-galaxy collection install community.docker community.general

- name: Run ansible-lint
run: |
cd ansible
ansible-lint playbooks/*.yml roles/*

deploy:
name: Deploy Python App
needs: lint
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install Ansible and collections
run: |
python -m pip install --upgrade pip
pip install ansible-core
ansible-galaxy collection install community.docker community.general

- name: Configure SSH access
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
run: |
set -euo pipefail
mkdir -p ~/.ssh
KEY="${SSH_PRIVATE_KEY:-}"
if [ -z "$KEY" ]; then
echo "SSH_PRIVATE_KEY secret is empty" >&2
exit 1
fi

# Detect public key accidentally pasted into secret.
if printf '%s' "$KEY" | grep -qE '^(ssh-ed25519|ssh-rsa|ecdsa-sha2-) '; then
echo "SSH_PRIVATE_KEY looks like a public key. Paste private key block (BEGIN ... PRIVATE KEY)." >&2
exit 1
fi

# Support both escaped newlines (\\n) and regular multiline secrets.
if printf '%s' "$KEY" | grep -q '\\n'; then
printf '%b' "$KEY" > ~/.ssh/id_ed25519
else
printf '%s\n' "$KEY" > ~/.ssh/id_ed25519
fi
tr -d '\r' < ~/.ssh/id_ed25519 > ~/.ssh/id_ed25519.clean
mv ~/.ssh/id_ed25519.clean ~/.ssh/id_ed25519

# Fallback: support base64-encoded private key secret.
if ! grep -Eq 'BEGIN (OPENSSH|RSA|EC|DSA) PRIVATE KEY' ~/.ssh/id_ed25519; then
if printf '%s' "$KEY" | base64 -d > ~/.ssh/id_ed25519 2>/dev/null && grep -Eq 'BEGIN (OPENSSH|RSA|EC|DSA) PRIVATE KEY' ~/.ssh/id_ed25519; then
:
else
echo "SSH_PRIVATE_KEY has invalid format. Provide raw private key block or base64-encoded private key." >&2
exit 1
fi
fi

chmod 600 ~/.ssh/id_ed25519
ssh-keyscan -H ${{ secrets.VM_HOST }} >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts

- name: Run deployment playbook
env:
ANSIBLE_VAULT_PASSWORD: ${{ secrets.ANSIBLE_VAULT_PASSWORD }}
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
run: |
cd ansible
printf "%s" "$ANSIBLE_VAULT_PASSWORD" > /tmp/vault_pass
ansible-playbook playbooks/deploy_python.yml \
-i inventory/hosts.ini \
--vault-password-file /tmp/vault_pass
rm -f /tmp/vault_pass

- name: Verify deployment
run: |
sleep 10
curl -fsS http://${{ secrets.VM_HOST }}:5000
curl -fsS http://${{ secrets.VM_HOST }}:5000/health
132 changes: 132 additions & 0 deletions .github/workflows/python-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
name: Python CI — tests, lint, build & push

on:
push:
branches: [ main, master, lab3 ]
tags: [ '*' ]
paths:
- 'app_python/**'
- '.github/workflows/python-ci.yml'
pull_request:
branches: [ main, master ]
paths:
- 'app_python/**'
workflow_dispatch:

concurrency:
group: python-ci-${{ github.ref }}
cancel-in-progress: true

env:
IMAGE: ${{ secrets.DOCKERHUB_REPO }}

permissions:
contents: read

jobs:
test-and-lint:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.11", "3.12"]
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
cache-dependency-path: |
app_python/requirements.txt
app_python/requirements-dev.txt

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r app_python/requirements.txt
pip install -r app_python/requirements-dev.txt

- name: Lint (flake8)
run: flake8 app_python

- name: Run tests
run: pytest --maxfail=1 -q

- name: Snyk dependency scan
if: ${{ env.SNYK_TOKEN != '' }}
uses: snyk/actions/python@master
with:
command: test
args: >-
--file=app_python/requirements.txt
--package-manager=pip
--skip-unresolved
--severity-threshold=high
timeout-minutes: 5
env:
SNYK_TOKEN: ${{ env.SNYK_TOKEN }}

build-and-push:
runs-on: ubuntu-latest
needs: test-and-lint
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' || github.ref == 'refs/heads/lab3' || startsWith(github.ref, 'refs/tags/')
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Ensure target image is configured
run: |
if [ -z "${IMAGE}" ]; then
echo "DOCKERHUB_REPO secret is not configured" >&2
exit 1
fi

- name: Set up QEMU
uses: docker/setup-qemu-action@v2

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Determine version (CalVer)
id: calver
run: |
DATE=$(date -u +%Y.%m.%d)
VERSION="$DATE-${GITHUB_RUN_NUMBER}"
echo "VERSION=$VERSION" >> $GITHUB_ENV
echo "version=$VERSION" >> $GITHUB_OUTPUT

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: ./app_python
push: true
tags: |
${{ env.IMAGE }}:${{ env.VERSION }}
${{ env.IMAGE }}:latest

- name: Snyk scan (optional)
if: ${{ env.SNYK_TOKEN != '' }}
uses: snyk/actions/python@master
with:
command: test
args: >-
--file=app_python/requirements.txt
--package-manager=pip
--skip-unresolved
--severity-threshold=high
timeout-minutes: 5
env:
SNYK_TOKEN: ${{ env.SNYK_TOKEN }}
14 changes: 13 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,13 @@
test
test

# Environment secrets
.env
**/.env
*.env

# Local vault password helper
.vault_pass_tmp

# Python cache
__pycache__/
*.pyc
1 change: 1 addition & 0 deletions .vault_pass_tmp
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lab05-temp-vault
11 changes: 11 additions & 0 deletions ansible/ansible.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[defaults]
inventory = inventory/hosts.ini
roles_path = roles
host_key_checking = False
remote_user = devops
retry_files_enabled = False

[privilege_escalation]
become = True
become_method = sudo
become_user = root
Loading