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
14 changes: 13 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,13 @@
test
__pycache__/
*.py[cod]
venv/
__MACOSX/
*.log

.vscode/
.idea/

.obsidian

.DS_Store
.env
53 changes: 53 additions & 0 deletions app_go/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# DevOps Info Service (Go) — Bonus Task

## Overview
A Go implementation of the DevOps Info Service. It provides two endpoints:
- `GET /` returns service/system/runtime/request information in JSON
- `GET /health` returns a simple health status JSON

## Prerequisites
- Go installed (check with `go version`)

## Run (from source)
```bash
go run .
```
By default the service listens on `0.0.0.0:8080`.

### Custom configuration

```bash
HOST=127.0.0.1 PORT=9090 go run .
```

## Build (binary)

```bash
go build -o devops-info-service
```

## Run (binary)

```bash
./devops-info-service
```

### Custom configuration (binary)

```bash
HOST=127.0.0.1 PORT=9090 ./devops-info-service
```

## API Endpoints

### GET /

```bash
curl -s http://127.0.0.1:8080/ | python -m json.tool
```

### GET /health

```bash
curl -s http://127.0.0.1:8080/health | python -m json.tool
```
Binary file added app_go/devops-info-service
Binary file not shown.
7 changes: 7 additions & 0 deletions app_go/docs/GO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Why Go (Compiled Language)

I chose Go for the compiled-language bonus task because:
- Go compiles into a single binary, which is convenient for deployment.
- It has a minimal standard library for building HTTP services (`net/http`).
- It’s fast to build and run and is commonly used in infrastructure/DevOps tooling.
- Small, self-contained binaries work well with Docker multi-stage builds in later labs.
49 changes: 49 additions & 0 deletions app_go/docs/LAB01.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# LAB01 — Bonus Task (Go)

## Implemented Endpoints
- `GET /` — returns service, system, runtime, request info + endpoints list (JSON)
- `GET /health` — returns health status + timestamp + uptime_seconds (JSON)

The JSON structure matches the Python version (same top-level fields and same key layout inside each section).

## How to Run (from source)
```bash
go run .
```
#### Test:

```bash
curl -s http://127.0.0.1:8080/ | python -m json.tool curl -s http://127.0.0.1:8080/health | python -m json.tool
```

## How to Build and Run (binary)

#### Build:

```bash
go build -o devops-info-service ls -lh devops-info-service
```

#### Run:

```bash
./devops-info-service
```

#### Test binary:

```bash
curl -s http://127.0.0.1:8080/health | python -m json.tool
```

## Screenshots

Screenshots are stored in `docs/screenshots/`:

Recommended set:
- `01-go-run.png` — running from source (`go run .`)
- `02-main-endpoint.png` — `GET /` output
- `03-health-endpoint.png` — `GET /health` output
- `04-go-build.png` — `go build` + `ls -lh` showing binary size
- `05-binary-run.png` — running compiled binary (`./devops-info-service`)
- `06-binary-health.png` — health check from binary run
Binary file added app_go/docs/screenshots/01-go-run.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-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/03-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.
Binary file added app_go/docs/screenshots/04-go-build.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/05-binary-run.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/06-binary-health.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

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

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

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

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

type ResponseRoot struct {
Service map[string]any `json:"service"`
System map[string]any `json:"system"`
Runtime map[string]any `json:"runtime"`
Request map[string]any `json:"request"`
Endpoints []Endpoint `json:"endpoints"`
}

func uptimeSeconds() int {
return int(time.Since(startTime).Seconds())
}

func uptimeHuman(sec int) string {
h := sec / 3600
m := (sec % 3600) / 60
return fmt.Sprintf("%d hour(s), %d minute(s)", h, m)
}

func hostname() string {
h, err := os.Hostname()
if err != nil {
return ""
}
return h
}

func getClientIP(r *http.Request) string {
xff := r.Header.Get("X-Forwarded-For")
if xff != "" {
for i := 0; i < len(xff); i++ {
if xff[i] == ',' {
return xff[:i]
}
}
return xff
}

host, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
return r.RemoteAddr
}
return host
}

func writeJSON(w http.ResponseWriter, status int, v any) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
enc := json.NewEncoder(w)
enc.SetIndent("", " ")
_ = enc.Encode(v)
}

func mainHandler(w http.ResponseWriter, r *http.Request) {
up := uptimeSeconds()

resp := ResponseRoot{
Service: map[string]any{
"name": "devops-info-service",
"version": "1.0.0",
"description": "DevOps course info service",
"framework": "Go net/http",
},
System: map[string]any{
"hostname": hostname(),
"platform": runtime.GOOS,
"platform_version": "",
"architecture": runtime.GOARCH,
"cpu_count": runtime.NumCPU(),
"python_version": runtime.Version(),
},
Runtime: map[string]any{
"uptime_seconds": up,
"uptime_human": uptimeHuman(up),
"current_time": time.Now().UTC().Format(time.RFC3339Nano),
"timezone": "UTC",
},
Request: map[string]any{
"client_ip": getClientIP(r),
"user_agent": r.UserAgent(),
"method": r.Method,
"path": r.URL.Path,
},
Endpoints: []Endpoint{
{Path: "/", Method: "GET", Description: "Service information"},
{Path: "/health", Method: "GET", Description: "Health check"},
},
}

log.Printf("Request: %s %s", r.Method, r.URL.Path)
writeJSON(w, http.StatusOK, resp)
}

func healthHandler(w http.ResponseWriter, r *http.Request) {
log.Printf("Request: %s %s", r.Method, r.URL.Path)
writeJSON(w, http.StatusOK, map[string]any{
"status": "healthy",
"timestamp": time.Now().UTC().Format(time.RFC3339Nano),
"uptime_seconds": uptimeSeconds(),
})
}

func main() {
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
host := os.Getenv("HOST")
if host == "" {
host = "0.0.0.0"
}

http.HandleFunc("/", mainHandler)
http.HandleFunc("/health", healthHandler)

addr := host + ":" + port
log.Printf("Starting Go app on %s", addr)
log.Fatal(http.ListenAndServe(addr, nil))
}
13 changes: 13 additions & 0 deletions app_python/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
__pycache__/
*.py[cod]
venv/
__MACOSX/
*.log

.vscode/
.idea/

.obsidian

.DS_Store
.env
34 changes: 34 additions & 0 deletions app_python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# DevOps Info Service (Lab 01)

## Overview
Simple web service that returns service, system, runtime and request information.

## 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
PORT=8080 python app.py
HOST=127.0.0.1 PORT=3000 python app.py
```

## API Endpoints

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

|Variable|Default|Description|
|---|---|---|
|HOST|0.0.0.0|Bind host|
|PORT|5000|Bind port|
|DEBUG|False|Flask debug mode
Loading