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

on:
push:
branches: [master, lab03]
paths:
- 'app_go/**'
- '.github/workflows/go-ci.yml'
pull_request:
branches: [master]
paths:
- 'app_go/**'
- '.github/workflows/go-ci.yml'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
name: Lint & Test
runs-on: ubuntu-latest
defaults:
run:
working-directory: app_go

steps:
- uses: actions/checkout@v4

- uses: actions/setup-go@v5
with:
go-version: '1.21'
cache-dependency-path: app_go/go.mod

- name: Lint with golangci-lint
uses: golangci/golangci-lint-action@v6
with:
working-directory: app_go

- name: Run tests
run: go test -v ./...

docker:
name: Build & Push Docker
needs: test
runs-on: ubuntu-latest
if: github.event_name == 'push'

steps:
- uses: actions/checkout@v4

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

- name: Generate CalVer tag
id: version
run: echo "TAG=$(date +%Y.%m).${{ github.run_number }}" >> "$GITHUB_OUTPUT"

- name: Build and push
uses: docker/build-push-action@v6
with:
context: app_go
push: true
tags: |
${{ secrets.DOCKERHUB_USERNAME }}/devops-info-service-go:${{ steps.version.outputs.TAG }}
${{ secrets.DOCKERHUB_USERNAME }}/devops-info-service-go:latest
85 changes: 85 additions & 0 deletions .github/workflows/python-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: Python CI

on:
push:
branches: [master, lab03]
paths:
- 'app_python/**'
- '.github/workflows/python-ci.yml'
pull_request:
branches: [master]
paths:
- 'app_python/**'
- '.github/workflows/python-ci.yml'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
name: Lint & Test
runs-on: ubuntu-latest
defaults:
run:
working-directory: app_python

steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: '3.13'
cache: 'pip'
cache-dependency-path: app_python/requirements-dev.txt

- name: Install dependencies
run: pip install -r requirements-dev.txt

- name: Lint with ruff
run: ruff check .

- name: Run tests with coverage
run: pytest -v --cov=. --cov-report=xml --cov-report=term

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
file: app_python/coverage.xml
token: ${{ secrets.CODECOV_TOKEN }}

- name: Snyk security scan
uses: snyk/actions/python@master
continue-on-error: true
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --file=requirements.txt --severity-threshold=high

docker:
name: Build & Push Docker
needs: test
runs-on: ubuntu-latest
if: github.event_name == 'push'

steps:
- uses: actions/checkout@v4

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

- name: Generate CalVer tag
id: version
run: echo "TAG=$(date +%Y.%m).${{ github.run_number }}" >> "$GITHUB_OUTPUT"

- name: Build and push
uses: docker/build-push-action@v6
with:
context: app_python
push: true
tags: |
${{ secrets.DOCKERHUB_USERNAME }}/devops-info-service:${{ steps.version.outputs.TAG }}
${{ secrets.DOCKERHUB_USERNAME }}/devops-info-service:latest
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
test
test
pyrightconfig.json
10 changes: 10 additions & 0 deletions app_go/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
devops-info-service
.git/
.gitignore
.vscode/
.idea/
*.md
docs/
.DS_Store
Dockerfile
.dockerignore
10 changes: 10 additions & 0 deletions app_go/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Binary
devops-info-service
*.exe

# IDE
.idea/
.vscode/

# OS
.DS_Store
16 changes: 16 additions & 0 deletions app_go/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
FROM golang:1.21-alpine AS builder

WORKDIR /build

COPY go.mod .
COPY main.go .

RUN CGO_ENABLED=0 GOOS=linux go build -o devops-info-service

FROM scratch

COPY --from=builder /build/devops-info-service /devops-info-service

EXPOSE 8080

ENTRYPOINT ["/devops-info-service"]
69 changes: 69 additions & 0 deletions app_go/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# DevOps Info Service (Go)

A web service that reports system information and health status, built with Go's standard library `net/http`.

## Prerequisites

- Go 1.21+

## Build

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

## Running the Application

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

With custom configuration:

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

Or run directly without building:

```bash
go run main.go
```

The service starts on `http://localhost:8080` by default.

## API Endpoints

| Method | Path | Description |
|--------|-----------|--------------------------------------|
| GET | `/` | Service and system information |
| GET | `/health` | Health check (status, uptime) |

### `GET /`

```bash
curl http://localhost:8080/
```

### `GET /health`

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

## Configuration

| Variable | Default | Description |
|----------|-----------|----------------------|
| `HOST` | `0.0.0.0` | Server bind address |
| `PORT` | `8080` | Server port |

## Binary Size Comparison

| Artifact | Size |
|----------------------|----------|
| Python (source) | ~5 KB |
| Go (compiled binary) | ~7 MB |

The Go binary is self-contained — no runtime, no dependencies, no virtual environment needed. Just copy and run.
28 changes: 28 additions & 0 deletions app_go/docs/GO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Language Justification: Go

## Why Go

| Criteria | Python (FastAPI) | Go (net/http) | Java (Spring Boot) |
|---------------------|------------------|---------------------|---------------------|
| Binary size | N/A (interpreted)| ~7 MB | ~20 MB (fat JAR) |
| Startup time | ~1s | Instant | ~2-3s |
| Dependencies | pip + venv | Zero (stdlib only) | Maven + JDK |
| Compilation speed | N/A | Very fast | Moderate |
| Memory usage | Moderate | Very low | High |
| Concurrency | GIL-limited | Goroutines (native) | Threads |

## Reasons for Choosing Go

1. **Zero external dependencies** — the entire service is built using Go's standard library (`net/http`, `encoding/json`, `runtime`). No frameworks, no package managers, no dependency hell.

2. **Single static binary** — `go build` produces one executable with everything baked in. No runtime needed, no JVM, no interpreter. Just copy the binary and run it anywhere.

3. **Ideal for Docker** — small binary size and no runtime dependencies make for minimal Docker images. A multi-stage build with `FROM scratch` can produce images under 10 MB.

4. **Fast compilation** — the entire project compiles in under a second, making the development loop fast.

## Trade-offs

- **Verbosity** — Go requires explicit struct definitions with JSON tags. More typing than Python dicts, but safer.
- **No auto-docs** — unlike FastAPI's built-in Swagger, Go's stdlib has no API documentation generation.
- **Error handling** — Go uses explicit `if err != nil` patterns instead of exceptions. More boilerplate but more predictable.
42 changes: 42 additions & 0 deletions app_go/docs/LAB01.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Lab 01 — DevOps Info Service (Go)

## Implementation Details

The Go implementation keeps everything in a single `main.go` file using only the standard library. This is idiomatic for small Go services — no need for a framework.

**Key components:**
- Struct types with JSON tags for response serialization
- `rootHandler` and `healthHandler` for the two endpoints
- `getUptime()` and `getHostname()` helper functions
- `startTime` package-level variable for uptime tracking

## Key Differences from Python Version

| Aspect | Python (FastAPI) | Go (net/http) |
|-----------------|----------------------------|----------------------------|
| Models | Pydantic `BaseModel` | Structs with JSON tags |
| Routing | `@router.get("/")` | `http.HandleFunc("/", fn)` |
| JSON | Automatic from dict/model | `json.NewEncoder().Encode` |
| Server | uvicorn (external) | Built-in `http.ListenAndServe` |
| Dependencies | fastapi, uvicorn | None (stdlib only) |
| Field naming | `python_version` | `go_version` |

## Build & Run

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

## Testing

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

## Screenshots

Screenshots in `screenshots/`:
- Compilation and binary output
- Running application with endpoint responses
Loading