GET /
+
+Returns comprehensive information about the service, system, and runtime.
+
+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.9.6"
+ },
+ "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
+
+Returns a simple health status, useful for monitoring and Kubernetes probes.
+
+Example response:
+
+```json
+{
+ "status": "healthy",
+ "timestamp": "2024-01-15T14:30:00.000Z",
+ "uptime_seconds": 3600
+}
+```
+
+## Configuration
+
+The following environment variables can be configured to change the application behavior:
+
+|Variable| Description| Default Value|
+|------|---|----|
+|HOST |Host |IP address| 0.0.0.0|
+|PORT |Port number| 5000|
+|DEBUG |Enable/Disable |debug mode| False|
\ No newline at end of file
diff --git a/app_python/app.py b/app_python/app.py
new file mode 100644
index 0000000000..dd8b5fe29f
--- /dev/null
+++ b/app_python/app.py
@@ -0,0 +1,148 @@
+import os
+import time
+import platform
+import logging
+import socket
+import uvicorn
+from datetime import datetime, timezone
+
+from fastapi import FastAPI, Request, HTTPException
+from fastapi.responses import JSONResponse
+
+# Configure logging
+logging.basicConfig(
+ level=logging.INFO,
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
+)
+logger = logging.getLogger(__name__)
+
+logger.info('Application starting...')
+
+# Configuration from environment variables
+HOST = os.getenv("HOST", "0.0.0.0")
+PORT = int(os.getenv("PORT", "5000"))
+DEBUG = os.getenv("DEBUG", "FALSE").lower() == "true"
+
+SERVICE_NAME = os.getenv("SERVICE_NAME", "devops-info-service")
+SERVICE_VERSION = os.getenv("SERVICE_VERSION", "1.0.0")
+SERVICE_DESCRIPTION = os.getenv("SERVICE_DESCRIPTION", "DevOps course info service")
+FRAMEWORK = "FastAPI"
+
+START_TIME = time.time()
+
+app = FastAPI(
+ title=SERVICE_NAME,
+ version=SERVICE_VERSION,
+ description=SERVICE_DESCRIPTION,
+)
+
+def get_uptime_seconds():
+ """
+ Calculate the uptime of the application.
+ Returns a dictionary with total seconds and human-readable format.
+ """
+ delta = time.time() - START_TIME
+ seconds = int(delta)
+ hours = seconds // 3600
+ minutes = (seconds % 3600) // 60
+ return {
+ 'seconds': seconds,
+ 'human': f"{hours} hours, {minutes} minutes"
+ }
+
+def iso_utc_now() -> str:
+ """
+ Get current time in ISO 8601 UTC format.
+ """
+ dt = datetime.now(timezone.utc)
+ return dt.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z"
+
+def system_info() -> dict:
+ """
+ Get system information such as platform, version, CPU count.
+ """
+ return {
+ "hostname": socket.gethostname(),
+ "platform": platform.system(),
+ "platform_version": platform.version(),
+ "architecture": platform.machine(),
+ "cpu_count": os.cpu_count() or 0,
+ "python_version": platform.python_version(),
+ }
+
+def client_ip_from_request(request: Request) -> str:
+ """
+ Extract client IP address from request.
+ """
+ if request.client and request.client.host:
+ return request.client.host
+ return "unknown"
+
+@app.get("/", response_class=JSONResponse)
+async def root(request: Request):
+ """
+ Main endpoint that returns service, system, and runtime information.
+ """
+ up = get_uptime_seconds()
+
+ logger.info(f"Received request: {request.method} {request.url.path} from {request.client.host}")
+
+ return {
+ "service": {
+ "name": SERVICE_NAME,
+ "version": SERVICE_VERSION,
+ "description": SERVICE_DESCRIPTION,
+ "framework": FRAMEWORK,
+ },
+ "system": system_info(),
+ "runtime": {
+ "uptime_seconds": up['seconds'],
+ "uptime_human": up['human'],
+ "current_time": iso_utc_now(),
+ "timezone": "UTC",
+ },
+ "request": {
+ "client_ip": client_ip_from_request(request),
+ "user_agent": request.headers.get("user-agent", "unknown"),
+ "method": request.method,
+ "path": request.url.path,
+ },
+ "endpoints": [
+ {"path": "/", "method": "GET", "description": "Service information"},
+ {"path": "/health", "method": "GET", "description": "Health check"},
+ ],
+ }
+
+@app.get("/health", response_class=JSONResponse)
+async def health(request: Request):
+ """
+ Health check endpoint for monitoring.
+ """
+ up = get_uptime_seconds()
+
+ logger.info(f"Received health check request: {request.method} {request.url.path} from {request.client.host}")
+ return {
+ "status": "healthy",
+ "timestamp": iso_utc_now(),
+ "uptime_seconds": up['seconds'],
+ }
+
+@app.exception_handler(404)
+async def not_found_exception(request: Request, exc: HTTPException):
+ logger.error(f"404 Error: {exc.detail} for {request.url.path}")
+ return JSONResponse(
+ status_code=404,
+ content={"message": "Endpoint not found", "error": str(exc)},
+ )
+
+@app.exception_handler(500)
+async def internal_server_error(request: Request, exc: HTTPException):
+ logger.error(f"500 Error: {str(exc)} for {request.url.path}")
+ return JSONResponse(
+ status_code=500,
+ content={"message": "Internal server error", "error": str(exc)},
+ )
+
+if __name__ == "__main__":
+ logger.info(f"Starting server on {HOST}:{PORT} with DEBUG={DEBUG}")
+ uvicorn.run("app:app", host=HOST, port=PORT, reload=DEBUG)
diff --git a/app_python/docs/LAB01.md b/app_python/docs/LAB01.md
new file mode 100644
index 0000000000..5d93dc5749
--- /dev/null
+++ b/app_python/docs/LAB01.md
@@ -0,0 +1,272 @@
+# LAB01 -- DevOps Info Service Implementation
+
+## Framework Selection
+
+### Choice: **FastAPI**
+
+I chose FastAPI because it's a lightweight and efficient framework specifically designed for building APIs, which is exactly what the lab requires. Since this is a DevOps course, a full-featured framework like Django would be overkill, as it includes many features we don't need, like an ORM for databases. FastAPI is fast, easy to learn, and supports asynchronous programming, making it ideal for scalable, performance-oriented services in a DevOps context. Additionally, it provides automatic API documentation, which is very useful for rapid development and testing.
+
+### Comparison Table
+
+| Feature | **FastAPI** | Flask | Django |
+|------------------------------------|----------------------------------|---------------------------------|--------------------------------|
+| **Type** | micro-web framework| micro-web framework| full-stack web framework|
+| **Asynchronous support** | built-in async support | limited (with extensions) | possible with help of Asyncio but slower.|
+| **Automatic API documentation** | Yes (Swagger, ReDoc) | Requires extensions (Flask-RESTful, Flask-OpenAPI) | Yes (DRF with auto docs) |
+| **Performance** | very fast for building APIs and microservices|slower because of manual validation and synchronised programming| fast for building large web applications |
+| **Learning curve** | Easy | Moderate | Complex |
+| **Flexibility** | High | High | Low (more opinionated) |
+| **Documentation** | clear, but smaller | large |extensive |
+
+---
+
+## Best Practices Applied
+
+### 1. **Clean Code Organization**
+
+- **Clear function names**: Functions are named descriptively to improve readability and maintainability.
+
+ Example:
+ ```python
+ def get_uptime_seconds():
+ """Calculate the uptime of the application."""
+ ```
+- **Grouping imports**: All imports are grouped into standard library imports, followed by third-party and local imports.
+
+ Example:
+ ```python
+ import os
+ import socket
+ import platform
+ from datetime import datetime, timezone
+ ```
+
+- **Comments and docstrings**: Comments are minimal, used only where the code is not self-explanatory, and function docstrings are added to describe their purpose.
+
+ Example:
+ ```python
+ def iso_utc_now() -> str:
+ """Returns the current time in ISO 8601 UTC format."""
+ dt = datetime.now(timezone.utc)
+ return dt.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z"
+ ```
+
+### 2. **Error Handling**
+
+- FastAPI handles errors automatically, but custom error handling can be added for cases like 404 (Not Found) and 500 (Internal Server Error).
+
+ Example:
+ ```python
+ @app.exception_handler(404)
+ async def not_found_exception(request: Request, exc: HTTPException):
+ return JSONResponse(
+ status_code=404,
+ content={"message": "Endpoint not found", "error": str(exc)},
+ )
+ ```
+
+ This allows us to give more informative and controlled responses for errors.
+
+### 3. **Logging**
+
+- Implemented logging to capture important application events and errors.
+
+ Example:
+ ```python
+ import logging
+
+ logging.basicConfig(
+ level=logging.INFO,
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
+ )
+ logger = logging.getLogger(__name__)
+
+ logger.info('Application starting...')
+ ```
+
+Logging helps in tracing application behavior and troubleshooting issues.
+
+### 4. **PEP 8 Compliance**
+
+- Adhered to Python’s **PEP 8** guidelines, including consistent naming conventions, indentation, and spacing.
+
+ Example:
+ ```python
+ def system_info() -> dict:
+ """Returns system information like hostname, platform, and architecture."""
+ return {
+ "hostname": socket.gethostname(),
+ "platform": platform.system(),
+ "platform_version": platform.version(),
+ "architecture": platform.machine(),
+ "cpu_count": os.cpu_count() or 0,
+ "python_version": platform.python_version(),
+ }
+ ```
+
+---
+
+## API Documentation
+
+### Request/Response Examples
+
+#### `GET /`
+
+**Request Example:**
+```bash
+curl http://127.0.0.1:5000/
+```
+
+Response Example:
+
+```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.9.6"
+ },
+ "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`
+
+Returns a simple health status, useful for monitoring and Kubernetes probes.
+
+**Request Example:**
+```bash
+curl http://127.0.0.1:5000/health
+```
+
+Example response:
+
+```json
+{
+ "status": "healthy",
+ "timestamp": "2024-01-15T14:30:00.000Z",
+ "uptime_seconds": 3600
+}
+```
+
+### Testing commands
+
+1. Test the `/` endpoint:
+
+ ```bash
+ curl -s http://127.0.0.1:5000/ | python -m json.tool
+ ```
+
+2. Test the `/health` endpoint:
+
+ ```bash
+ curl -s http://127.0.0.1:5000/health | python -m json.tool
+ ```
+
+## Testing evidence
+
+### Screenshots showing endpoints work
+
+1. `01-main-endpoint`:
+
+
+2. `02-health-check`:
+
+
+3. `03-formatted-output`:
+
+
+### Terminal output showing successful response
+
+1. 01-main-endpoint
+
+```bash
+zagur@LAPTOP-JONCQBVT:/mnt/c/Users/zagur/DevOps/DevOps-Core-Course$ curl -s http://127.0.0.1:3000/ | python3 -m json.tool
+{
+ "service": {
+ "name": "devops-info-service",
+ "version": "1.0.0",
+ "description": "DevOps course info service",
+ "framework": "FastAPI"
+ },
+ "system": {
+ "hostname": "LAPTOP-JONCQBVT",
+ "platform": "Linux",
+ "platform_version": "#1 SMP PREEMPT_DYNAMIC Thu Jun 5 18:30:46 UTC 2025",
+ "architecture": "x86_64",
+ "cpu_count": 8,
+ "python_version": "3.12.3"
+ },
+ "runtime": {
+ "uptime_seconds": 3,
+ "uptime_human": "0 hours, 0 minutes",
+ "current_time": "2026-01-24T18:38:52.811Z",
+ "timezone": "UTC"
+ },
+ "request": {
+ "client_ip": "127.0.0.1",
+ "user_agent": "curl/8.5.0",
+ "method": "GET",
+ "path": "/"
+ },
+ "endpoints": [
+ {
+ "path": "/",
+ "method": "GET",
+ "description": "Service information"
+ },
+ {
+ "path": "/health",
+ "method": "GET",
+ "description": "Health check"
+ }
+ ]
+}
+```
+
+2. 02-health-check
+
+```bash
+zagur@LAPTOP-JONCQBVT:/mnt/c/Users/zagur/DevOps/DevOps-Core-Course$ curl -s http://127.0.0.1:3000/health | python3 -m json.tool
+{
+ "status": "healthy",
+ "timestamp": "2026-01-24T18:39:57.365Z",
+ "uptime_seconds": 67
+}
+```
+
+## Challenges & Solutions
+
+**Problem:** Since I'm not very familiar with the syntax of FastAPI and Python, I encountered several syntax errors while writing the code, such as incorrect function definitions or missing imports. These errors caused issues like the app failing to start or returning unexpected results.
+
+**Solution:** To resolve this, I carefully referred to the FastAPI documentation and Python's official documentation. I also ran the app frequently during development to catch any issues early. Debugging with error messages and checking online resources helped me understand and correct mistakes in the syntax.
+
+## GitHub Community
+
+1. **Why stars matter in open source:** Stars are the way to discover, bookmark, and show appreciation for interesting and promising projects. The more stars a repo has, the more popular and trusted it is. This helps projects get more visibility and attract more contributors.
+
+2. **How followers can help:** Following developers lets you stay updated on their work and learn from them. It also helps you find potential teammates for future projects and stay aware of new technologies.
\ No newline at end of file
diff --git a/app_python/docs/screenshots/01-main-endpoint-browser.png b/app_python/docs/screenshots/01-main-endpoint-browser.png
new file mode 100644
index 0000000000000000000000000000000000000000..97c8c630982ef02ec1ef3668e546019666fdcde0
GIT binary patch
literal 61197
zcma&NXEcx2)M;I!uY&W{*`To3wxR!Fe+_0iNUuAH
zTSqxZgxa&puN;mG?0W(cTETP5N{siEWxGw5OWS+*S2O0`T7ODp^VLpi;Zz-yRy+W&
zF}1L?OgBY-NPlO(Kq`8UFK<%|4+JPxTla|VO3F`&r3dn?J5YI^US?9^iv8gBgjH+t
zy_We>OT7qEq|xb$)^SWDFDatImwezoJNshTibay;hnfKHUB5N+K4wArH*;5v&gIUh
z)hl(x=(RRl^h1e>d8|gmuG97_lYa}XXR3NJM9~2#OjF4f^999ryG+lzTWFe4v(f_bGN8s@16W6scvGN+{OlzOJgqw%VG&FhUVI1Y f<@jNwe
CXD~d5H|0C8Crzr;+Ooa1X8HD0
zQ67RXUvAzDsv|WoV8ReRw#NHAylGpDRY2r<5a}SSZ*w8>5dUf7edmN
kDBZVOm0EV53!l>=1>FZ2L=p{#+j1xnSTjL1
zIxcrWz$Z#pj&7#=U{=qdSI>kO6)}S!!Iifhp|ZD~n
X1N1(*<9lJDCfncdN55x6AUfZiOlXA$Z5ux`{32-HkJkbsJMDDl&30k_14_z+
z1$HoUPD%I#4+M}e$ULNIgzTRiH$R2B3=0$T%{#(@*AxIkW%>J4${vvZD@}V)r}tc;
zOY6{nQ&;~=%dm)LX~>v!83gong$W#ZpSx^JA0i`>VBUZPv$)o<@zLfN$a74md~sjC
z$V}VvLPx>n$i=qwB3J%l@nt7}H(@OeW?VqCPRmh0OF?=0S=|S6Ap#^U3iTEX#_coa
z>9+&qg08Syw~L`macv=y#ci5@&nXPqkKy6yk)9?-(Hkv$B}!#xAiwqv40L~dY|{d<
z@$m%rV8Th{xb}gsC