Skip to content
Open

Lab06 #2850

Show file tree
Hide file tree
Changes from all commits
Commits
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
Binary file added .coverage
Binary file not shown.
23 changes: 23 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[run]
source = .
omit =
*/venv/*
*/tests/*
*/__pycache__/*
*/htmlcov/*
setup.py

[report]
exclude_lines =
pragma: no cover
def __repr__
raise AssertionError
raise NotImplementedError
if __name__ == .__main__.:
if TYPE_CHECKING:
@abstractmethod

precision = 2
show_missing = True
skip_covered = False

51 changes: 51 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Git
.git
.gitignore
.github

# Python
__pycache__
*.pyc
*.pyo
*.pyd
.Python
*.so
*.egg
*.egg-info
dist
build
venv/
.venv/
env/
ENV/

# Testing
.pytest_cache
.coverage
coverage.xml
htmlcov/
.tox/
.hypothesis/

# IDE
.vscode/
.idea/
*.swp
*.swo
*~

# Documentation
*.md
docs/
labs/
lectures/

# CI/CD
.github/

# Other
.DS_Store
*.log
.env
.env.local

19 changes: 19 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[flake8]
max-line-length = 127
extend-ignore = E203, E266, E501, W503
exclude =
.git,
__pycache__,
venv,
.venv,
env,
ENV,
build,
dist,
*.egg-info,
.pytest_cache,
htmlcov,
.coverage,
coverage.xml
max-complexity = 10

82 changes: 82 additions & 0 deletions .github/workflows/ansible-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: Ansible Deployment

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

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

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

- name: Install dependencies
run: |
pip install ansible ansible-lint
ansible-galaxy collection install community.docker community.general

- name: Run ansible-lint
run: ansible-lint playbooks/provision.yml roles/

deploy:
name: Deploy Application
needs: lint
runs-on: ubuntu-latest
if: github.event_name == 'push'
defaults:
run:
working-directory: ansible
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: |
pip install ansible
ansible-galaxy collection install community.docker community.general

- name: Setup SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H ${{ secrets.VM_HOST }} >> ~/.ssh/known_hosts 2>/dev/null || true

- name: Deploy with Ansible
env:
ANSIBLE_VAULT_PASSWORD: ${{ secrets.ANSIBLE_VAULT_PASSWORD }}
run: |
echo "$ANSIBLE_VAULT_PASSWORD" > /tmp/vault_pass
ansible-playbook playbooks/deploy.yml \
-i inventory/hosts.ini \
--vault-password-file /tmp/vault_pass
rm -f /tmp/vault_pass

- name: Verify Deployment
run: |
sleep 10
curl -f --connect-timeout 10 "http://${{ secrets.VM_HOST }}:5000" || exit 1
curl -f --connect-timeout 10 "http://${{ secrets.VM_HOST }}:5000/health" || exit 1
178 changes: 178 additions & 0 deletions .github/workflows/python-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
name: Python CI/CD Pipeline

on:
push:
branches:
- main
- master
- lab03
paths:
- 'app_python/**'
- 'app.py'
- 'requirements.txt'
- 'requirements-dev.txt'
- '.github/workflows/python-ci.yml'
- 'Dockerfile'
pull_request:
branches:
- main
- master
paths:
- 'app_python/**'
- 'app.py'
- 'requirements.txt'
- 'requirements-dev.txt'
- '.github/workflows/python-ci.yml'
- 'Dockerfile'
workflow_dispatch:

env:
PYTHON_VERSION: '3.11'
DOCKER_IMAGE_NAME: ${{ secrets.DOCKER_USERNAME || 'devops-info-service' }}/devops-info-service

jobs:
test:
name: Test & Lint
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'

- name: Cache pip dependencies
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('requirements*.txt') }}
restore-keys: |
${{ runner.os }}-pip-

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

- name: Run linter (flake8)
run: |
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics

- name: Check code formatting (black)
run: |
black --check --diff .

- name: Run tests with coverage
run: |
pytest app_python/tests/ -v --cov=app_python --cov-report=xml --cov-report=term-missing --cov-report=html

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
file: ./coverage.xml
flags: python
name: python-coverage
fail_ci_if_error: false

security:
name: Security Scan
runs-on: ubuntu-latest
needs: test

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

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'

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

- name: Run Snyk to check for vulnerabilities
uses: snyk/actions/python@master
continue-on-error: true
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high

- name: Upload Snyk results to GitHub Security
uses: github/codeql-action/upload-sarif@v3
if: always()
continue-on-error: true

docker:
name: Build & Push Docker Image
runs-on: ubuntu-latest
needs: test
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

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

- name: Log in to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Generate CalVer version
id: calver
run: |
VERSION_MONTH=$(date +%Y.%m)
VERSION_DAY=$(date +%Y.%m.%d)
GIT_SHA=$(git rev-parse --short HEAD)
echo "version_month=$VERSION_MONTH" >> $GITHUB_OUTPUT
echo "version_day=$VERSION_DAY" >> $GITHUB_OUTPUT
echo "git_sha=$GIT_SHA" >> $GITHUB_OUTPUT
echo "Generated CalVer: $VERSION_MONTH, $VERSION_DAY, sha-$GIT_SHA"

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.DOCKER_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' }}
type=raw,value=${{ steps.calver.outputs.version_month }},enable=${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' }}
type=raw,value=${{ steps.calver.outputs.version_day }},enable=${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' }}
type=raw,value=sha-${{ steps.calver.outputs.git_sha }}

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64

- name: Image digest
run: echo ${{ steps.meta.outputs.digest }}

8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
test
test

# Ansible
*.retry
.vault_pass
ansible/inventory/*.pyc
__pycache__/
Loading