Skip to content
Open

Lab06 #2846

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
b4cea83
feat: implement lab01 devops info service (python + go)
Jan 23, 2026
4c6284b
feat(lab02): dockerize apps; reorganize screenshots paths
Feb 2, 2026
d85c438
lab03 testing
Feb 10, 2026
9e5c69b
lab03 testing 2
Feb 10, 2026
d6af226
lab03 testing 3
Feb 10, 2026
21ea568
lab03 testing 4
Feb 10, 2026
a038152
testing 5
Feb 11, 2026
2258cee
lab03: Unit tests + CI pipeline
Feb 11, 2026
74d90c3
go-si test
Feb 18, 2026
692fd89
ci testing
Feb 19, 2026
48f5b62
ci testing
Feb 19, 2026
6963899
ci testing
Feb 19, 2026
e934137
main.tf updates
Feb 19, 2026
3ee6210
ci update cash
Feb 19, 2026
5e3ea6e
ci update 2
Feb 19, 2026
c7f4fcd
ci update 3
Feb 19, 2026
5651c02
go-ci fix try
Feb 19, 2026
5aa7a4c
go-ci fix try 2
Feb 19, 2026
f9e00f8
go-ci fix try 3
Feb 19, 2026
cdb38d7
go-ci fix try 4
Feb 19, 2026
daafd43
Lab04: solved + bonus task + lab3 bonus without doc.
Feb 19, 2026
68a7b26
LAB05 Solved + Bonus task
Feb 26, 2026
2099b3f
ansible-deploy.yml tests
Mar 5, 2026
61b875c
ansible-deploy.yml tests 1
Mar 5, 2026
50d8633
ansible-deploy.yml tests 2
Mar 5, 2026
704771d
ansible-deploy.yml tests 3
Mar 5, 2026
21ccfc2
ansible-deploy.yml tests 4
Mar 5, 2026
59db589
ansible-deploy.yml tests 5
Mar 5, 2026
45d390a
ansible-deploy.yml tests 6
Mar 5, 2026
3ab0313
ansible-deploy.yml tests 7
Mar 5, 2026
0bbe053
ansible-deploy.yml tests 8
Mar 5, 2026
eef380a
ansible-deploy.yml tests 9
Mar 5, 2026
bc3bbcb
ansible-deploy.yml tests 9
Mar 5, 2026
8954734
ansible-deploy.yml tests 10
Mar 5, 2026
d1934a3
ansible-deploy.yml tests 11
Mar 5, 2026
d92ef07
ansible-deploy.yml tests 12
Mar 5, 2026
8c7e6a1
ansible-deploy.yml tests 13
Mar 5, 2026
c57dd58
ansible-deploy.yml tests 14
Mar 5, 2026
15874cd
Complete Lab 6: Advanced Ansible & CI/CD
Mar 5, 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
162 changes: 162 additions & 0 deletions .github/workflows/ansible-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
name: Ansible Deployment

on:
push:
branches: [ "main", "master", "lab*" ]
paths:
- "ansible/**"
- ".github/workflows/ansible-deploy.yml"
- "!ansible/docs/**"
pull_request:
branches: [ "main", "master" ]
paths:
- "ansible/**"
- ".github/workflows/ansible-deploy.yml"
- "!ansible/docs/**"

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

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install ansible + ansible-lint
run: |
pip install ansible ansible-lint

- name: Create temporary vault password file for lint
env:
ANSIBLE_VAULT_PASSWORD: ${{ secrets.ANSIBLE_VAULT_PASSWORD }}
run: |
echo "$ANSIBLE_VAULT_PASSWORD" > ansible/.vault_pass
chmod 600 ansible/.vault_pass

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

- name: Cleanup vault password file
if: always()
run: rm -f ansible/.vault_pass

deploy:
name: Deploy Application (SSH + YC dynamic inventory)
needs: lint
if: github.event_name == 'push'
runs-on: ubuntu-latest
env:
YC_CLOUD_ID: ${{ secrets.YC_CLOUD_ID }}
YC_FOLDER_ID: ${{ secrets.YC_FOLDER_ID }}
YC_ZONE: ${{ secrets.YC_ZONE }}

steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Create temporary vault password file for deploy
env:
ANSIBLE_VAULT_PASSWORD: ${{ secrets.ANSIBLE_VAULT_PASSWORD }}
run: |
echo "$ANSIBLE_VAULT_PASSWORD" > ansible/.vault_pass
chmod 600 ansible/.vault_pass

- name: Install Ansible + collections
run: |
pip install ansible
ansible-galaxy collection install community.docker

- name: Install YC CLI
run: |
curl -sSL https://storage.yandexcloud.net/yandexcloud-yc/install.sh | bash -s -- -i /opt/yc -n
echo "/opt/yc/bin" >> $GITHUB_PATH
/opt/yc/bin/yc --version

- name: Write YC service account key file
env:
YC_SERVICE_ACCOUNT_KEY_JSON: ${{ secrets.YC_SERVICE_ACCOUNT_KEY_JSON }}
run: |
echo "$YC_SERVICE_ACCOUNT_KEY_JSON" > "$RUNNER_TEMP/yc-sa-key.json"
chmod 600 "$RUNNER_TEMP/yc-sa-key.json"
echo "YC_SERVICE_ACCOUNT_KEY_FILE=$RUNNER_TEMP/yc-sa-key.json" >> $GITHUB_ENV

- name: Configure YC CLI auth (service account key)
run: |
/opt/yc/bin/yc config set service-account-key "$YC_SERVICE_ACCOUNT_KEY_FILE"
/opt/yc/bin/yc config set cloud-id "$YC_CLOUD_ID"
/opt/yc/bin/yc config set folder-id "$YC_FOLDER_ID"
/opt/yc/bin/yc config set compute-default-zone "$YC_ZONE"
/opt/yc/bin/yc config list

- name: Smoke check dynamic inventory (must include webservers)
run: |
cd ansible
python3 inventory/yandex_cloud.py > /tmp/inv.json
python3 - <<'PY'
import json
d=json.load(open("/tmp/inv.json"))
hosts=d.get("webservers",{}).get("hosts",[])
print("webservers:", hosts)
if not hosts:
raise SystemExit("No hosts found in dynamic inventory")
PY
ansible-inventory -i inventory/yandex_cloud.py --graph

- name: Setup SSH key (for Ansible -> VM)
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
run: |
mkdir -p ~/.ssh
echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa

- name: Populate known_hosts from dynamic inventory
run: |
cd ansible
python3 - <<'PY' > /tmp/ips.txt
import json, subprocess
inv = subprocess.check_output(["python3","inventory/yandex_cloud.py"], text=True)
d = json.loads(inv)
hosts = d.get("webservers",{}).get("hosts",[])
for h in hosts:
print(d["_meta"]["hostvars"][h]["ansible_host"])
PY

mkdir -p ~/.ssh
while read -r ip; do
echo "Scanning host key for $ip"
timeout 10s ssh-keyscan -H "$ip" >> ~/.ssh/known_hosts || true
done < /tmp/ips.txt

- name: Deploy with Ansible
run: |
cd ansible
ansible-playbook -i inventory/yandex_cloud.py playbooks/deploy.yml

- name: Verify Deployment (curl to discovered public IP)
run: |
cd ansible
VM_IP=$(python3 - <<'PY'
import json, subprocess
inv = subprocess.check_output(["python3","inventory/yandex_cloud.py"], text=True)
d = json.loads(inv)
host = d["webservers"]["hosts"][0]
print(d["_meta"]["hostvars"][host]["ansible_host"])
PY
)
echo "Using VM IP: $VM_IP"
sleep 10
curl -f "http://$VM_IP:5000/health"
curl -f "http://$VM_IP:5000/"

- name: Cleanup vault password file
if: always()
run: rm -f ansible/.vault_pass
88 changes: 88 additions & 0 deletions .github/workflows/go-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
name: go-ci

on:
push:
branches: [ "main", "master", "lab*" ]
paths:
- "app_go/**"
- ".github/workflows/go-ci.yml"
pull_request:
paths:
- "app_go/**"
- ".github/workflows/go-ci.yml"

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

jobs:
test:
runs-on: ubuntu-latest
defaults:
run:
working-directory: app_go
steps:
- uses: actions/checkout@v4

- uses: actions/setup-go@v5
with:
go-version-file: app_go/go.mod
cache: true
cache-dependency-path: app_go/go.sum

- name: fmt check (print files)
run: |
echo "Go version:"
go version

files="$(gofmt -l .)"
if [ -n "$files" ]; then
echo "::error::gofmt wants to reformat these files:"
echo "$files"
exit 1
fi

- name: vet
run: go vet ./...

- name: test + coverage
run: go test ./... -coverprofile=coverage.out

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
files: app_go/coverage.out
flags: app_go

# Docker push if tests passed
docker:
needs: [test]
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/lab'))
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: docker/setup-buildx-action@v3
id: buildx

- name: Set tags
run: |
echo "CALVER=$(date -u +'%Y.%m.%d')" >> $GITHUB_ENV
echo "SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV

- uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}

- uses: docker/build-push-action@v6
with:
context: ./app_go
push: true
builder: ${{ steps.buildx.outputs.name }}
cache-from: type=gha
cache-to: type=gha,mode=max
tags: |
${{ secrets.DOCKER_USERNAME }}/app-go:${{ env.CALVER }}
${{ secrets.DOCKER_USERNAME }}/app-go:sha-${{ env.SHA_SHORT }}
${{ secrets.DOCKER_USERNAME }}/app-go:latest
140 changes: 140 additions & 0 deletions .github/workflows/python-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
name: Python CI

on:
push:
# Run CI only if something has changed in the application folder or in the workflow itself
paths:
- "app_python/**/*.py"
- "app_python/requirements*.txt"
- "app_python/Dockerfile"
- ".github/workflows/python-ci.yml"

pull_request:
paths:
- "app_python/**/*.py"
- "app_python/requirements*.txt"
- "app_python/Dockerfile"
- ".github/workflows/python-ci.yml"

# Prevents old launches from replaying when new pushes are made
concurrency:
group: python-ci-${{ github.ref }}
cancel-in-progress: true

# Minimum required privileges are provided
permissions:
contents: read

env:
# To avoid duplicating paths/versions throughout the file
APP_DIR: app_python
PYTHON_VERSION: "3.12"
# Image repository on Docker Hub (tags added separately)
IMAGE_NAME: ${{ secrets.DOCKER_USERNAME }}/app_python
# SNYK token
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 10

steps:
# We're grabbing the repository code for the runner
- name: Checkout
uses: actions/checkout@v4

# Prepare the required version of Python and enable the pip cache (to speed up the work during subsequent launches)
- name: Setup Python (pip cache)
uses: actions/setup-python@v6
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: "pip"
cache-dependency-path: |
app_python/requirements.txt
app_python/requirements-dev.txt

# Installing dependencies
- name: Install deps
working-directory: ${{ env.APP_DIR }}
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt

# Code Quality Check: Style + Typical Errors (Before Testing)
- name: Lint (flake8)
working-directory: ${{ env.APP_DIR }}
run: flake8 app.py tests

# Running unit tests
- name: Tests (pytest)
working-directory: ${{ env.APP_DIR }}
run: pytest -q

# Security scan
- name: Setup Snyk
# Run Snyk only on the push branches we need and only if SNYK_TOKEN is specified (otherwise skip this step)
if: ${{ github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'master' || startsWith(github.ref_name, 'lab')) && env.SNYK_TOKEN != '' }}
uses: snyk/actions/setup@master

# Checking dependencies for vulnerabilities (build stops at high+)
- name: Snyk dependency scan (fail on high+)
if: ${{ github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'master' || startsWith(github.ref_name, 'lab')) && env.SNYK_TOKEN != '' }}
working-directory: ${{ env.APP_DIR }}
env:
SNYK_TOKEN: ${{ env.SNYK_TOKEN }}
run: snyk test --severity-threshold=high

# Checking code for vulnerabilities (build stops at high+)
- name: Snyk code scan (SAST)
if: ${{ github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'master' || startsWith(github.ref_name, 'lab')) && env.SNYK_TOKEN != '' }}
working-directory: ${{ env.APP_DIR }}
env:
SNYK_TOKEN: ${{ env.SNYK_TOKEN }}
run: snyk code test --severity-threshold=high

docker:
# Docker job is started only if tests/linter passed
needs: [test]
runs-on: ubuntu-latest
timeout-minutes: 15

# push image only on push
if: ${{ github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'master' || startsWith(github.ref_name, 'lab')) }}

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Docker Buildx (for GHA cache)
uses: docker/setup-buildx-action@v3
with:
driver: docker-container
install: true

# CalVer - version by date
# SHA — a unique tag for each commit
- name: Generate CalVer + SHA tag
run: |
echo "CALVER=$(date -u +'%Y.%m.%d')" >> $GITHUB_ENV
echo "SHORT_SHA=${GITHUB_SHA::7}" >> $GITHUB_ENV

# Authorization in Docker Hub using a token from GitHub Secrets
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}

# Build and push the image (Layers are cached to make rebuilds faster)
- name: Build and push (with cache)
uses: docker/build-push-action@v6
with:
context: ./${{ env.APP_DIR }}
push: true
tags: |
${{ env.IMAGE_NAME }}:${{ env.CALVER }}
${{ env.IMAGE_NAME }}:sha-${{ env.SHORT_SHA }}
${{ env.IMAGE_NAME }}:latest
cache-from: type=gha
cache-to: type=gha,mode=max
Loading