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
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
74 changes: 74 additions & 0 deletions app_python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# DevOps Info Service

## Overview

Web service that reports system information and health status. Provides API endpoints for service info, hostname, platform, uptime, and request details.

## Prerequisites

- Python 3.11+
- pip

## Installation

```bash
python -m venv venv
venv\Scripts\activate
pip install -r requirements.txt
```

## Running

```bash
python app.py
```

Default: `http://0.0.0.0:5000`

**Custom config:**

```bash
PORT=8080 python app.py
HOST=127.0.0.1 PORT=3000 python app.py
```

## API Endpoints

### `GET /`

Returns service and system information.

```bash
curl http://localhost:5000/
```

### `GET /health`

Health check endpoint.

```bash
curl http://localhost:5000/health
```

## Configuration

| Variable | Default | Description |
| -------- | --------- | ------------ |
| `HOST` | `0.0.0.0` | Host address |
| `PORT` | `5000` | Port number |
| `DEBUG` | `False` | Debug mode |

## Project Structure

```
app_python/
├── app.py # Main app
├── config.py # Config
├── routes/ # API routes
├── services/ # Business logic
├── tests/
├── docs/ # Lab docs, screenshots
├── requirements.txt
├── .gitignore
└── README.md
```
42 changes: 42 additions & 0 deletions app_python/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import os
import logging
from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import JSONResponse
from routes.system_info import router as system_info_router
from config import HOST, PORT, DEBUG
import uvicorn

logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

app = FastAPI()

app.include_router(system_info_router)

@app.exception_handler(404)
async def not_found(request: Request, exc: HTTPException):
return JSONResponse(
status_code=404,
content={
"error": "Not Found",
"message": "Endpoint does not exist"
}
)

@app.exception_handler(Exception)
async def internal_error(request: Request, exc: Exception):
return JSONResponse(
status_code=500,
content={
"error": "Internal Server Error",
"message": "An unexpected error occurred"
}
)

if __name__ == "__main__":
logger.info(f"Application started on {HOST}:{PORT}")
uvicorn.run(app, host=HOST, port=PORT)

5 changes: 5 additions & 0 deletions app_python/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import os

HOST = os.getenv('HOST', '0.0.0.0')
PORT = int(os.getenv('PORT', 5000))
DEBUG = os.getenv('DEBUG', 'False').lower() == 'true'
67 changes: 67 additions & 0 deletions app_python/docs/LAB01.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Lab 1 Submission

## Framework Selection

**FastAPI** - Modern, fast, has auto-docs and async support.

| Criteria | FastAPI | Flask | Django |
| --------- | --------- | ---------- | ------ |
| Speed | Very Fast | Fast | Medium |
| Auto Docs | Yes | No | No |
| Async | Yes | Limited | Yes |
| Size | Small | Very Small | Large |

**Why not Flask?** Flask is simpler but FastAPI has better async and auto-docs.

**Why not Django?** Too big for this simple service.

## Best Practices Applied

1. **Code Organization** - Separated into routes/, services/, config.py
2. **Error Handling** - 404 and 500 handlers
3. **Logging** - Basic logging setup
4. **Environment Variables** - Config via env vars
5. **Clear Function Names** - get_system_info(), get_uptime(), etc.

## API Documentation

### `GET /`

Returns service info, system info, runtime, request details, and endpoints list.

```bash
curl http://localhost:5000/
```

### `GET /health`

Returns health status and uptime.

```bash
curl http://localhost:5000/health
```

### Error Responses

```bash
curl http://localhost:5000/something
# {"error": "Not Found", "message": "Endpoint does not exist"}
```

## Testing Evidence

Screenshots in `docs/screenshots/`:

- `01-main-endpoint.png`
- `02-health-check.png`
- `03-formatted-output.png`

## Challenges & Solutions

1. **Function name conflict** — Named the route handler `get_system_info()` which conflicted with the imported function from `services.system_info`. When calling `get_system_info()` inside the route handler, Python was calling the route handler itself instead of the imported function, causing recursion errors. Fixed by importing the entire module as `import services.system_info as system_info_service` and accessing functions via `system_info_service.get_system_info()`.

2. **Timezone method call error** — Used `timezone.utc.tzname()` without arguments, but `tzname()` method requires a datetime object as parameter. This caused `TypeError: timezone.tzname() takes exactly one argument (0 given)`. Fixed by calling `tzname()` on a datetime object: `datetime.now(timezone.utc).tzname()`.

## GitHub Community

\*Starring repositories helps with discovery and bookmarking — it signals project quality to the community and encourages maintainers. Following developers builds professional connections and keeps you informed about relevant projects and industry trends.
Binary file added app_python/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_python/docs/screenshots/02-health-check.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions app_python/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
fastapi==0.115.0
uvicorn[standard]==0.32.0
24 changes: 24 additions & 0 deletions app_python/routes/system_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from fastapi import APIRouter, Request
import logging
from datetime import datetime, timezone
import services.system_info as system_info_service

router = APIRouter()

@router.get("/")
async def get_system_info(request: Request):
return {
"service": system_info_service.get_service_info(),
"system": system_info_service.get_system_info(),
"runtime": system_info_service.get_runtime_info(),
"request": system_info_service.get_request_info(request),
"endpoints": system_info_service.get_endpoints_info()
}

@router.get("/health")
async def health():
return {
"status": "healthy",
"timestamp": datetime.now(timezone.utc).isoformat(),
"uptime_seconds": system_info_service.get_uptime()['seconds']
}
68 changes: 68 additions & 0 deletions app_python/services/system_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from fastapi import Request
import os
import platform
import socket
from datetime import datetime, timezone

start_time = datetime.now(timezone.utc)

def get_system_info():
hostname = socket.gethostname()
platform_name = platform.system()
platform_version = platform.platform()
architecture = platform.machine()
cpu_count = os.cpu_count()
python_version = platform.python_version()

return {
"hostname": hostname,
"platform": platform_name,
"platform_version": platform_version,
"architecture": architecture,
"cpu_count": cpu_count,
"python_version": python_version
}

def get_uptime():
delta = datetime.now(timezone.utc) - start_time
seconds = int(delta.total_seconds())
hours = seconds // 3600
minutes = (seconds % 3600) // 60

return {
'seconds': seconds,
'human': f"{hours} hours, {minutes} minutes"
}

def get_runtime_info():
uptime_info = get_uptime()

return {
"uptime_seconds": uptime_info['seconds'],
"uptime_human": uptime_info['human'],
'current_time': datetime.now(timezone.utc).isoformat(),
'timezone': datetime.now(timezone.utc).tzname()
}

def get_service_info():
return {
"name": "devops-info-service",
"version": "1.0.0",
"description": "DevOps course info service",
"framework": "FastAPI"
}

def get_request_info(request: Request):
return {
"client_ip": request.client.host,
"user_agent": request.headers.get('user-agent'),
"method": request.method,
"path": request.url.path
}

def get_endpoints_info():
return [
{"path": "/", "method": "GET", "description": "Service information"},
{"path": "/health", "method": "GET", "description": "Health check"}
]

1 change: 1 addition & 0 deletions app_python/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Tests package