Skip to content
Open
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
131 changes: 131 additions & 0 deletions .github/workflows/python-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
name: Python CI/CD

on:
push:
branches:
- master
- main
- lab03
paths:
- 'Lab-1/app_python/**'
- '.github/workflows/python-ci.yml'
pull_request:
branches:
- master
- main
paths:
- 'Lab-1/app_python/**'
- '.github/workflows/python-ci.yml'

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

permissions:
contents: read

jobs:
quality:
name: Lint and tests (Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
python-version: ['3.11', '3.12']

defaults:
run:
working-directory: Lab-1/app_python

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

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

- name: Install dependencies
run: pip install -r requirements.txt -r requirements-dev.txt

- name: Lint with Ruff
run: ruff check .

- name: Run tests with coverage
run: pytest --cov=. --cov-report=term-missing --cov-fail-under=70

security:
name: Snyk dependency scan
runs-on: ubuntu-latest
needs: quality

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

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

- name: Install dependencies
working-directory: Lab-1/app_python
run: pip install -r requirements.txt

- name: Run Snyk scan
if: ${{ secrets.SNYK_TOKEN != '' }}
uses: snyk/actions/python@master
continue-on-error: true
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
command: test
args: --file=Lab-1/app_python/requirements.txt --severity-threshold=high

- name: Snyk token is missing
if: ${{ secrets.SNYK_TOKEN == '' }}
run: echo "SNYK_TOKEN is not configured. Security scan skipped."

docker:
name: Build and push Docker image
runs-on: ubuntu-latest
needs:
- quality
- security
if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main')

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

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

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

- name: Generate CalVer tags
run: |
echo "CALVER=$(date -u +'%Y.%m.%d').${GITHUB_RUN_NUMBER}" >> "$GITHUB_ENV"
echo "CALVER_MONTH=$(date -u +'%Y.%m')" >> "$GITHUB_ENV"

- name: Build and push image
uses: docker/build-push-action@v6
with:
context: ./Lab-1/app_python
file: ./Lab-1/app_python/Dockerfile
push: true
tags: |
${{ secrets.DOCKERHUB_USERNAME }}/devops-lab2:${{ env.CALVER }}
${{ secrets.DOCKERHUB_USERNAME }}/devops-lab2:${{ env.CALVER_MONTH }}
${{ secrets.DOCKERHUB_USERNAME }}/devops-lab2:latest
cache-from: type=gha
cache-to: type=gha,mode=max
66 changes: 66 additions & 0 deletions .github/workflows/terraform-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Terraform Validate

on:
push:
branches:
- master
- main
- lab04
paths:
- 'terraform/**'
- '.github/workflows/terraform-ci.yml'
pull_request:
branches:
- master
- main
paths:
- 'terraform/**'
- '.github/workflows/terraform-ci.yml'

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

permissions:
contents: read

jobs:
validate:
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
workdir:
- terraform
- terraform/github-import

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

- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.9.8

- name: Setup TFLint
uses: terraform-linters/setup-tflint@v4

- name: Check Terraform formatting
run: terraform fmt -check -recursive

- name: Terraform init
working-directory: ${{ matrix.workdir }}
run: terraform init -backend=false

- name: Terraform validate
working-directory: ${{ matrix.workdir }}
run: terraform validate

- name: Initialize TFLint plugins
working-directory: ${{ matrix.workdir }}
run: tflint --init

- name: Run TFLint
working-directory: ${{ matrix.workdir }}
run: tflint --format compact
35 changes: 34 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,34 @@
test
test

# Terraform
*.tfstate
*.tfstate.*
.terraform/
.terraform.lock.hcl
terraform.tfvars
*.tfvars
crash.log
override.tf
override.tf.json
*_override.tf
*_override.tf.json

# Pulumi
.pulumi/
Pulumi.*.yaml
pulumi/venv/

# Python caches
.pytest_cache/
.ruff_cache/
.coverage
**/__pycache__/
**/*.pyc

# Credentials and keys
*.pem
*.key
*.p12
*.jks
*.json
credentials
Binary file added Lab-1/app_python/.coverage
Binary file not shown.
13 changes: 13 additions & 0 deletions Lab-1/app_python/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
__pycache__/
*.py[cod]
*.log
.env
venv/
.venv/
.git/
.gitignore
.vscode/
.idea/
docs/
tests/
README.md
13 changes: 13 additions & 0 deletions Lab-1/app_python/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Python
__pycache__/
*.py[cod]
venv/
*.log
.env

# IDE
.vscode/
.idea/

# OS
.DS_Store
19 changes: 19 additions & 0 deletions Lab-1/app_python/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
FROM python:3.13-slim

ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1

WORKDIR /app

RUN addgroup --system app && adduser --system --ingroup app app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY app.py .

EXPOSE 5000

USER app

CMD ["python", "app.py"]
95 changes: 95 additions & 0 deletions Lab-1/app_python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# DevOps Info Service (Flask)
[![Python CI/CD](https://github.com/Linktur/DevOps-Core-Course/actions/workflows/python-ci.yml/badge.svg?branch=master)](https://github.com/Linktur/DevOps-Core-Course/actions/workflows/python-ci.yml)

## Overview
A small Flask web service that reports service metadata, system information, runtime details, and request context. It also exposes a health check endpoint and Swagger UI.

## Prerequisites
- Python 3.11+
- pip

## Installation
```bash
python -m venv venv
# Linux/macOS
source venv/bin/activate
# Windows PowerShell
.\venv\Scripts\Activate.ps1

pip install -r requirements.txt
```

## Configuration via .env (optional)
Create a `.env` file in `app_python/`:
```env
HOST=0.0.0.0
PORT=5000
DEBUG=false
```

## Running the Application
```bash
python app.py
```

With custom configuration:
```bash
PORT=8080 python app.py
HOST=127.0.0.1 PORT=3000 DEBUG=true python app.py
```

Windows PowerShell:
```powershell
$env:PORT=8080; python app.py
$env:HOST='127.0.0.1'; $env:PORT=3000; $env:DEBUG='true'; python app.py
```

## Docker
Build image (pattern):
```bash
docker build -t linktur/devops-lab2:v1 .
```

Run container (pattern):
```bash
docker run --rm -p 5000:5000 --name devops-lab2 linktur/devops-lab2:v1
```

Pull from Docker Hub (pattern):
```bash
docker pull linktur/devops-lab2:v1
```

## API Endpoints
- `GET /` - Service and system information
- `GET /health` - Health check
- `GET /swagger.json` - OpenAPI spec
- `GET /docs` - Swagger UI

## Local Quality Checks
Install development dependencies:
```bash
pip install -r requirements.txt -r requirements-dev.txt
```

Run linter:
```bash
ruff check .
```

Run unit tests:
```bash
pytest
```

Run tests with coverage threshold (same as CI):
```bash
pytest --cov=. --cov-report=term-missing --cov-fail-under=70
```

## Configuration
| Variable | Default | Description |
|---|---|---|
| `HOST` | `0.0.0.0` | Bind address |
| `PORT` | `5000` | HTTP port |
| `DEBUG` | `False` | Flask debug mode (`true`/`false`) |
Loading
Loading