diff --git a/app_python/.gitignore b/app_python/.gitignore new file mode 100644 index 0000000000..4de420a8f7 --- /dev/null +++ b/app_python/.gitignore @@ -0,0 +1,12 @@ +# Python +__pycache__/ +*.py[cod] +venv/ +*.log + +# IDE +.vscode/ +.idea/ + +# OS +.DS_Store \ No newline at end of file diff --git a/app_python/README.md b/app_python/README.md new file mode 100644 index 0000000000..f13371036c --- /dev/null +++ b/app_python/README.md @@ -0,0 +1,137 @@ +# DevOps Info Service + +A FastAPI-based web service providing detailed information about the service, system, and runtime environment. + +## Overview + +This service is part of the DevOps course and provides: +- Comprehensive system information +- Health check endpoint for monitoring +- Runtime statistics +- Automatic OpenAPI documentation + +## Prerequisites + +- Python 3.11 or higher +- pip (Python package manager) + +## Installation + +1. Clone the repository: + ```bash + git clone + cd app_python + ``` + +2. Create and activate virtual environment: + ```bash + python -m venv venv + source venv/bin/activate + ``` + +3. Install dependencies: + ```bash + pip install -r requirements.txt + ``` + +## Running the Application + +### Basic usage: +```bash +python app.py +``` + +### With custom configuration: +```bash +# Custom port +PORT=8080 python app.py + +# Custom host and port +HOST=127.0.0.1 PORT=3000 python app.py + +# Enable debug mode +DEBUG=true python app.py +``` + +### Using uvicorn directly: +```bash +uvicorn app:app --host 0.0.0.0 --port 5000 --reload +``` + +### Testing + +Test the endpoints using curl: + +```bash +# Get service info +curl http://localhost:5000/ + +# Health check +curl http://localhost:5000/health + +# Pretty-print JSON output +curl http://localhost:5000/ | python -m json.tool +``` + +## API Endpoints + +### GET `/` +Returns comprehensive service and system information. + +**Example Response:** +```json +{ + "service": { + "name": "devops-info-service", + "version": "1.0.0", + "description": "DevOps course info service", + "framework": "FastAPI" + }, + "system": { + "hostname": "my-laptop", + "platform": "Linux", + "platform_version": "Ubuntu 24.04", + "architecture": "x86_64", + "cpu_count": 8, + "python_version": "3.13.1" + }, + "runtime": { + "uptime_seconds": 3600, + "uptime_human": "1 hour, 0 minutes", + "current_time": "2026-01-07T14:30:00.000Z", + "timezone": "UTC" + }, + "request": { + "client_ip": "127.0.0.1", + "user_agent": "curl/7.81.0", + "method": "GET", + "path": "/" + }, + "endpoints": [ + {"path": "/", "method": "GET", "description": "Service information"}, + {"path": "/health", "method": "GET", "description": "Health check"} + ] +} +``` + +### GET `/health` +Health check endpoint for monitoring and Kubernetes probes. + +**Example Response:** +```json +{ + "status": "healthy", + "timestamp": "2024-01-15T14:30:00.000Z", + "uptime_seconds": 3600 +} +``` + +## Configuration + +The application can be configured using environment variables: + +| Variable | Default | Description | +|----------|---------|-------------| +| `HOST` | `0.0.0.0` | Host to bind the server to | +| `PORT` | `5000` | Port to listen on | +| `DEBUG` | `False` | Enable debug mode and hot reload | diff --git a/app_python/app.py b/app_python/app.py new file mode 100644 index 0000000000..b29786647b --- /dev/null +++ b/app_python/app.py @@ -0,0 +1,155 @@ +import os +import socket +import platform +import logging +from datetime import datetime, timezone +from typing import Dict, Any + +from fastapi import FastAPI, Request +from fastapi.responses import JSONResponse +from fastapi.middleware.cors import CORSMiddleware + +# Application configuration +HOST = os.getenv("HOST", "0.0.0.0") +PORT = int(os.getenv("PORT", "5000")) +DEBUG = os.getenv("DEBUG", "False").lower() == "true" + +# Configure logging +logging.basicConfig( + level=logging.DEBUG if DEBUG else logging.INFO, + format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" +) +logger = logging.getLogger(__name__) + +# Application start time +START_TIME = datetime.now(timezone.utc) + +# Create FastAPI application +app = FastAPI( + title="DevOps Info Service", + version="1.0.0", + description="DevOps course information service", +) + +# Add CORS middleware +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + +def get_system_info() -> Dict[str, Any]: + """Collect and return system information.""" + return { + "hostname": socket.gethostname(), + "platform": platform.system(), + "platform_version": platform.version(), + "architecture": platform.machine(), + "cpu_count": os.cpu_count(), + "python_version": platform.python_version(), + } + +def get_uptime() -> Dict[str, Any]: + """Calculate application 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_request_info(request: Request) -> Dict[str, Any]: + """Extract request information.""" + client_ip = request.client.host if request.client else "127.0.0.1" + user_agent = request.headers.get("user-agent", "Unknown") + + return { + "client_ip": client_ip, + "user_agent": user_agent, + "method": request.method, + "path": request.url.path, + } + +@app.get("/", response_model=Dict[str, Any]) +async def root(request: Request) -> Dict[str, Any]: + """ + Main endpoint returning comprehensive service and system information. + """ + logger.info(f"GET / requested by {request.client.host if request.client else 'unknown'}") + + return { + "service": { + "name": "devops-info-service", + "version": "1.0.0", + "description": "DevOps course info service", + "framework": "FastAPI", + }, + "system": get_system_info(), + "runtime": { + "uptime_seconds": get_uptime()["seconds"], + "uptime_human": get_uptime()["human"], + "current_time": datetime.now(timezone.utc).isoformat(), + "timezone": "UTC", + }, + "request": get_request_info(request), + "endpoints": [ + {"path": "/", "method": "GET", "description": "Service information"}, + {"path": "/health", "method": "GET", "description": "Health check"}, + ], + } + +@app.get("/health", response_model=Dict[str, Any]) +async def health() -> Dict[str, Any]: + """ + Health check endpoint for monitoring and Kubernetes probes. + """ + return { + "status": "healthy", + "timestamp": datetime.now(timezone.utc).isoformat(), + "uptime_seconds": get_uptime()["seconds"], + } + +@app.exception_handler(404) +async def not_found(request: Request, exc): + """Handle 404 errors.""" + return JSONResponse( + status_code=404, + content={ + "error": "Not Found", + "message": f"The requested endpoint {request.url.path} does not exist" + } + ) + +@app.exception_handler(500) +async def internal_error(request: Request, exc): + """Handle 500 errors.""" + logger.error(f"Internal server error: {exc}") + return JSONResponse( + status_code=500, + content={ + "error": "Internal Server Error", + "message": "An unexpected error occurred" + } + ) + +def main(): + """Application entry point.""" + logger.info(f"Starting DevOps Info Service on {HOST}:{PORT}") + logger.info(f"Debug mode: {DEBUG}") + + import uvicorn + uvicorn.run( + "app:app", + host=HOST, + port=PORT, + reload=DEBUG, + log_level="debug" if DEBUG else "info" + ) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/app_python/docs/LAB01.md b/app_python/docs/LAB01.md new file mode 100644 index 0000000000..7f7e14b4ae --- /dev/null +++ b/app_python/docs/LAB01.md @@ -0,0 +1,308 @@ +# Lab 1 Submission + +## Framework Selection + +### Choice: FastAPI +I selected FastAPI as the web framework for this project. + +### Justification: +FastAPI offers several advantages over alternatives: + +1. **Performance**: Built on Starlette and Pydantic, FastAPI is one of the fastest Python frameworks available +2. **Automatic Documentation**: Generates OpenAPI/Swagger documentation automatically +3. **Modern Features**: Native async/await support, type hints, and dependency injection +4. **Developer Experience**: Excellent editor support with autocompletion and validation +5. **Standards Compliance**: Based on OpenAPI and JSON Schema standards + +### Comparison Table: + +| Feature | FastAPI | Flask | Django | +|---------|---------|-------|--------| +| Performance | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | +| Learning Curve | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐ | +| Auto Documentation | ✅ | ❌ | ❌ | +| Async Support | ✅ | Limited | ✅ | +| Built-in Admin | ❌ | ❌ | ✅ | +| Project Size | Micro | Micro | Full-stack | +| Best For | APIs, Microservices | Small apps, Prototyping | Large applications | + +For a DevOps-focused service that needs to be lightweight, fast, and well-documented, FastAPI is the optimal choice. + +## Best Practices Applied + +### 1. Clean Code Organization +- **File structure**: Clear separation of concerns with dedicated functions +- **Function names**: Descriptive names like `get_system_info()`, `get_uptime()` +- **Import grouping**: Standard library imports first, then third-party, then local +- **Comments**: Only where necessary to explain complex logic +- **Type hints**: All functions have return type annotations + +```python +def get_system_info() -> Dict[str, Any]: + """Collect and return system information.""" + return { + "hostname": socket.gethostname(), + "platform": platform.system(), + "platform_version": platform.version(), + "architecture": platform.machine(), + "cpu_count": os.cpu_count(), + "python_version": platform.python_version(), + } +``` + +### 2. Error Handling +- Custom exception handlers for 404 and 500 errors +- JSON responses for API consistency +- Logging of internal errors + +```python +@app.exception_handler(404) +async def not_found(request: Request, exc): + return JSONResponse( + status_code=404, + content={ + "error": "Not Found", + "message": f"The requested endpoint {request.url.path} does not exist" + } + ) +``` + +### 3. Logging +- Structured logging with timestamps and levels +- Configurable log levels via DEBUG environment variable +- Request logging for monitoring + +```python +logging.basicConfig( + level=logging.DEBUG if DEBUG else logging.INFO, + format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" +) +logger = logging.getLogger(__name__) + +# Usage in endpoints +logger.info(f"GET / requested by {request.client.host if request.client else 'unknown'}") +``` + +### 4. Configuration Management +- Environment variables for configuration +- Sensible defaults +- Type conversion for numeric values + +```python +HOST = os.getenv("HOST", "0.0.0.0") +PORT = int(os.getenv("PORT", "5000")) +DEBUG = os.getenv("DEBUG", "False").lower() == "true" +``` + +### 5. Dependencies Management +- Pinned versions in `requirements.txt` +- Production-ready dependencies with performance extras + +```txt +fastapi==0.115.0 +uvicorn[standard]==0.32.0 +``` + +### 6. Git Ignore +- Comprehensive `.gitignore` file +- Covers Python, IDE files, logs, and OS-specific files + +```gitignore +# Python +__pycache__/ +*.py[cod] +venv/ + +# Logs +*.log + +# IDE +.vscode/ +.idea/ + +# OS +.DS_Store +``` + +### 7. CORS Middleware +- Added CORS middleware for cross-origin requests +- Configurable for different environments + +```python +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) +``` + +## API Documentation + +### Endpoints: + +#### GET `/` +**Description**: Returns comprehensive service and system information + +**Request:** +```bash +curl http://localhost:5000/ +``` + +**Response:** +```json +{ + "service": { + "name": "devops-info-service", + "version": "1.0.0", + "description": "DevOps course info service", + "framework": "FastAPI" + }, + "system": { + "hostname": "your-hostname", + "platform": "Linux", + "platform_version": "#1 SMP ...", + "architecture": "x86_64", + "cpu_count": 8, + "python_version": "3.11.0" + }, + "runtime": { + "uptime_seconds": 120, + "uptime_human": "0 hours, 2 minutes", + "current_time": "2026-01-28T10:30:00.000Z", + "timezone": "UTC" + }, + "request": { + "client_ip": "127.0.0.1", + "user_agent": "curl/7.81.0", + "method": "GET", + "path": "/" + }, + "endpoints": [ + {"path": "/", "method": "GET", "description": "Service information"}, + {"path": "/health", "method": "GET", "description": "Health check"} + ] +} +``` + +#### GET `/health` +**Description**: Health check endpoint for monitoring + +**Request:** +```bash +curl http://localhost:5000/health +``` + +**Response:** +```json +{ + "status": "healthy", + "timestamp": "2026-01-28T10:30:00.000Z", + "uptime_seconds": 120 +} +``` + +### Testing Commands: + +```bash +# Test with different ports +PORT=8080 python app.py +curl http://localhost:8080/ + +# Test health endpoint +curl http://localhost:5000/health + +# Test with pretty-print +curl http://localhost:5000/ | python -m json.tool + +# Test auto-documentation +curl http://localhost:5000/docs + +# Test error handling +curl http://localhost:5000/nonexistent + +# Test with environment variables +HOST=127.0.0.1 PORT=3000 python app.py +curl http://127.0.0.1:3000/ +``` + +## Testing Evidence + +### Screenshots: +All screenshots are available in `docs/screenshots/`: +1. `01-main-endpoint.png` - Complete JSON response from `/` +2. `02-health-check.png` - Health endpoint response +3. `03-formatted-output.png` - Pretty-printed JSON output + +### Terminal Output Examples: + +**Starting the server:** +``` +$ cd app_python +$ venv/bin/python app.py +2026-01-28 10:30:00 - app - INFO - Starting DevOps Info Service on 0.0.0.0:5000 +2026-01-28 10:30:00 - app - INFO - Debug mode: False +INFO: Started server process [12345] +INFO: Waiting for application startup. +INFO: Application startup complete. +INFO: Uvicorn running on http://0.0.0.0:5000 (Press CTRL+C to quit) +``` + +**Testing endpoints:** +``` +$ curl http://localhost:5000/health +{"status":"healthy","timestamp":"2026-01-28T10:30:15.123456Z","uptime_seconds":15} + +$ curl http://localhost:5000/ | jq '.service' +{ + "name": "devops-info-service", + "version": "1.0.0", + "description": "DevOps course info service", + "framework": "FastAPI" +} + +$ curl http://localhost:5000/nonexistent +{"error":"Not Found","message":"The requested endpoint /nonexistent does not exist"} +``` + +**Testing environment variables:** +``` +$ PORT=8080 venv/bin/python app.py & +$ curl http://localhost:8080/health +{"status":"healthy","timestamp":"2026-01-28T10:31:00.000000Z","uptime_seconds":5} +``` + +## Challenges & Solutions + +### Shell Compatibility (Fish vs Bash) +**Problem**: Virtual environment activation scripts are shell-specific +**Solution**: + +```bash +# Instead of: source venv/bin/activate +# Use: source venv/bin/activate.fish +``` + +## GitHub Community + +### GitHub Social Features Engagement + +**1. Why Starring Repositories Matters:** +Starring repositories serves multiple purposes in open source: +- **Discovery & Bookmarking**: Stars help bookmark interesting projects for future reference and indicate community trust. They serve as a personal library of quality projects you want to remember. +- **Open Source Signal**: Star counts show appreciation to maintainers, help projects gain visibility in GitHub searches and recommendations, and serve as social proof of a project's quality. +- **Professional Context**: Starring quality projects demonstrates awareness of industry tools and best practices to potential employers and collaborators. It shows you're engaged with the developer ecosystem. + +**2. How Following Developers Helps:** +Following developers on GitHub provides several benefits for professional growth: +- **Networking**: Build professional connections and see what others in your field are working on. Following professors and TAs keeps you updated on their research and projects. +- **Learning**: Discover new projects, learn from others' code and commit patterns, and stay current with best practices. Following classmates allows you to learn from peers. +- **Collaboration**: Stay updated on classmates' work for potential future collaborations. Seeing others' approaches to the same problems can inspire new solutions. +- **Career Growth**: Follow thought leaders in your technology stack to stay current with industry trends and emerging technologies. + +**GitHub Best Practices Applied:** +- ✅ Starred the course repository to show engagement and bookmark for reference +- ✅ Starred the simple-container-com/api project to support open-source container tools +- ✅ Followed professor and TAs for mentorship opportunities and to learn from experienced developers +- ✅ Followed at least 3 classmates diff --git a/app_python/docs/screenshots/01-main-endpoint.png b/app_python/docs/screenshots/01-main-endpoint.png new file mode 100644 index 0000000000..f2c1250d1e Binary files /dev/null and b/app_python/docs/screenshots/01-main-endpoint.png differ diff --git a/app_python/docs/screenshots/02-health-check.png b/app_python/docs/screenshots/02-health-check.png new file mode 100644 index 0000000000..2d857c77a3 Binary files /dev/null and b/app_python/docs/screenshots/02-health-check.png differ diff --git a/app_python/docs/screenshots/03-formatted-output.png b/app_python/docs/screenshots/03-formatted-output.png new file mode 100644 index 0000000000..a8b580abf5 Binary files /dev/null and b/app_python/docs/screenshots/03-formatted-output.png differ diff --git a/app_python/requirements.txt b/app_python/requirements.txt new file mode 100644 index 0000000000..2bc4f697c2 --- /dev/null +++ b/app_python/requirements.txt @@ -0,0 +1,3 @@ +# Web Framework +fastapi==0.115.0 +uvicorn[standard]==0.32.0 \ No newline at end of file diff --git a/app_python/tests/__init__.py b/app_python/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2