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

on:
push:
paths:
- "app_python/**"
- ".github/workflows/python-ci.yml"
pull_request:
paths:
- "app_python/**"

jobs:
test-and-build:
runs-on: ubuntu-latest

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

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

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

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

- name: Run tests
run: |
cd app_python
pytest

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

- name: Set Docker image version
run: echo "VERSION=$(date +%Y.%m.%d)" >> $GITHUB_ENV

- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: app_python
push: true
tags: |
${{ secrets.DOCKERHUB_USERNAME }}/devops-info-python:${{ env.VERSION }}
${{ secrets.DOCKERHUB_USERNAME }}/devops-info-python:latest

- name: Install Snyk
run: npm install -g snyk

- name: Run Snyk test
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
run: snyk test --all-projects --severity-threshold=high
1 change: 1 addition & 0 deletions app_go/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
devops-info
22 changes: 22 additions & 0 deletions app_go/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# DevOps Info Service (Go)

## Overview
Compiled implementation of the DevOps Info Service using Go.
Designed for efficient containerization and minimal runtime footprint.

## Requirements
- Go 1.22+

## Build
```bash
go build -o devops-info
```

## Run
```bash
./devops-info
```

## Endpoints
- `GET /`
- `GET /health`
5 changes: 5 additions & 0 deletions app_go/docs/GO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## Why Go

Go was chosen for the compiled implementation due to its simplicity, fast compilation, and suitability for containerized environments.
It produces a single static binary, which makes it ideal for multi-stage Docker builds and minimal runtime images.
Go is widely used in DevOps tooling, including Docker, Kubernetes, and Prometheus.
17 changes: 17 additions & 0 deletions app_go/docs/LAB01.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
## Implementation Details

The Go version implements the same API structure as the Python service using the standard `net/http` package.

## Build Process
```bash
go build -o devops-info
```

## Binary Size Comparison

| Implementation | Size |
| -------------- | ---------------------------- |
| Python (Flask) | ~30–50 MB (with venv & deps) |
| Go binary | ~7–10 MB |

The Go binary does not require an interpreter or external dependencies, making it more efficient for deployment.
Binary file added app_go/docs/screenshots/01-main-endpoint.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app_go/docs/screenshots/02-health-endpoint.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions app_go/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module devops-info-service

go 1.22
123 changes: 123 additions & 0 deletions app_go/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package main

import (
"encoding/json"
"fmt"
"net/http"
"os"
"runtime"
"time"
)

var startTime = time.Now().UTC()

type Service struct {
Name string `json:"name"`
Version string `json:"version"`
Description string `json:"description"`
Framework string `json:"framework"`
}

type System struct {
Hostname string `json:"hostname"`
Platform string `json:"platform"`
Architecture string `json:"architecture"`
CPUCount int `json:"cpu_count"`
GoVersion string `json:"go_version"`
}

type RuntimeInfo struct {
UptimeSeconds int `json:"uptime_seconds"`
UptimeHuman string `json:"uptime_human"`
CurrentTime string `json:"current_time"`
Timezone string `json:"timezone"`
}

type RequestInfo struct {
Method string `json:"method"`
Path string `json:"path"`
}

type Endpoint struct {
Path string `json:"path"`
Method string `json:"method"`
Description string `json:"description"`
}

type ServiceInfo struct {
Service Service `json:"service"`
System System `json:"system"`
Runtime RuntimeInfo `json:"runtime"`
Request RequestInfo `json:"request"`
Endpoints []Endpoint `json:"endpoints"`
}

func getUptime() (int, string) {
seconds := int(time.Since(startTime).Seconds())
hours := seconds / 3600
minutes := (seconds % 3600) / 60
return seconds, fmt.Sprintf("%d hours %d minutes", hours, minutes)
}

func mainHandler(w http.ResponseWriter, r *http.Request) {
hostname, _ := os.Hostname()
uptimeSeconds, uptimeHuman := getUptime()

info := ServiceInfo{
Service: Service{
Name: "devops-info-service",
Version: "1.0.0",
Description: "DevOps Course Info Service",
Framework: "Go net/http",
},
System: System{
Hostname: hostname,
Platform: runtime.GOOS,
Architecture: runtime.GOARCH,
CPUCount: runtime.NumCPU(),
GoVersion: runtime.Version(),
},
Runtime: RuntimeInfo{
UptimeSeconds: uptimeSeconds,
UptimeHuman: uptimeHuman,
CurrentTime: time.Now().UTC().Format(time.RFC3339),
Timezone: "UTC",
},
Request: RequestInfo{
Method: r.Method,
Path: r.URL.Path,
},
Endpoints: []Endpoint{
{Path: "/", Method: "GET", Description: "Main service information endpoint"},
{Path: "/health", Method: "GET", Description: "Health check endpoint"},
},
}

w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(info)
}

func healthHandler(w http.ResponseWriter, r *http.Request) {
uptimeSeconds, _ := getUptime()

response := map[string]interface{}{
"status": "healthy",
"timestamp": time.Now().UTC().Format(time.RFC3339),
"uptime_seconds": uptimeSeconds,
}

w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}

func main() {
http.HandleFunc("/", mainHandler)
http.HandleFunc("/health", healthHandler)

port := os.Getenv("PORT")
if port == "" {
port = "8080"
}

http.ListenAndServe(":"+port, nil)
}
15 changes: 15 additions & 0 deletions app_python/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
__pycache__/
*.pyc
*.pyo
*.pyd

.git/
.gitignore

venv/
.venv/

docs/
tests/

README.md
12 changes: 12 additions & 0 deletions app_python/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Python
__pycache__/
*.py[cod]
venv/
*.log

# IDE
.vscode/
.idea/

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

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

# Non-root user setup
RUN useradd --create-home appuser

WORKDIR /app

COPY requirements.txt .

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

# Copy application code
COPY app.py .

#Swithh to non-root user
USER appuser

EXPOSE 8000

CMD ["python", "app.py"]
54 changes: 54 additions & 0 deletions app_python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# DevOps Info Service

[![Python CI](https://github.com/Gpshfrd/DevOps-Core-Course/actions/workflows/python-ci.yml/badge.svg)](https://github.com/Gpshfrd/DevOps-Core-Course/actions/workflows/python-ci.yml)

## Overview
A lightweight web service, that exposes the system, runtime, and request information.
Used as a foundation for DevOps labs (Docker, CI/CD, monitoring).

## Prerequisites
- Python 3.11+
- pip

## Installation
```bash
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
```

## Running the Application
```bash
python app.py
# Or with custom config
PORT=8080 python app.py
```

## API Endpoints
- `GET /` - Service and system information
- `GET /health` - Health check

## Configuration

| Variable | Default | Description |
| ---------- | --------- | ------------------ |
| `HOST` | `0.0.0.0` | Bind address |
| `PORT` | `5000` | Server port number |
| `DEBUG` | `false` | Debug mode |

## Docker

Build image locally:
```bash
docker build -t devops-info-python .
```

Run container:
```bash
docker run -p 8000:8000 devops-info-python
```

Pull from Docker Hub:
```bash
docker pull gpshfrd/devops-info-python:1.0.0
```
Loading