Skip to content

Commit 655d222

Browse files
committed
Add golang webserver files
Signed-off-by: Andreia Ocanoaia <andreia.ocanoaia@gmail.com>
1 parent 145f054 commit 655d222

6 files changed

Lines changed: 177 additions & 2 deletions

File tree

Dockerfile

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Start from the official Go image for building
2+
FROM golang:1.22 AS builder
3+
4+
# Set working directory
5+
WORKDIR /app
6+
7+
# Copy Go module files and download dependencies
8+
COPY go.mod go.sum ./
9+
RUN go mod download
10+
11+
# Copy the source code
12+
COPY . .
13+
14+
# Build the Go app (statically linked)
15+
RUN CGO_ENABLED=0 GOOS=linux go build -o server .
16+
17+
# Create a minimal runtime image
18+
FROM alpine:latest
19+
20+
WORKDIR /root/
21+
22+
# Copy binary from builder
23+
COPY --from=builder /app/server .
24+
25+
# Expose port
26+
EXPOSE 8080
27+
28+
# Run the binary
29+
CMD ["./server"]

README.md

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,46 @@
1-
# ci_cd_lab
2-
This is a repository for a CI/CD uni lab
1+
# CI/CD workshop repository
2+
3+
## Prerequisites
4+
5+
### Install Argo CD in k8s
6+
7+
```bash
8+
kubectl create namespace argocd
9+
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
10+
```
11+
12+
### Install Argo CD Argo Rollouts
13+
14+
```bash
15+
kubectl create namespace argoproj
16+
kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-rollouts/stable/manifests/install.yaml
17+
```
18+
19+
## Add a repository to Argo CD
20+
21+
Get the admin password and use it to login with argo cd:
22+
```shell
23+
kubectl get secret argocd-initial-admin-secret -n argocd -o jsonpath="{.data.password}" | base64 -d && echo
24+
argocd login localhost:8080 --username admin --password <password>
25+
```
26+
27+
Then add the git repo to Argo CD:
28+
```bash
29+
export USERNAME=<your-github-repository>
30+
export REPO=go-simple-webserver
31+
argocd app create go-simple-webserver \
32+
--repo https://github.com/$USERNAME/$REPO.git \
33+
--path manifests \
34+
--dest-server https://kubernetes.default.svc \
35+
--dest-namespace default
36+
```
37+
38+
## Argo UI Guideline
39+
40+
```bash
41+
kubectl port-forward svc/argocd-server -n argocd 8080:443
42+
```
43+
44+
To login use the following credentials: `admin/<password>`
45+
46+
`<password>` can be retrieved from `kubectl get secret argocd-initial-admin-secret -n argocd -o jsonpath="{.data.password}" | base64 -d && echo`

go.mod

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module simplewebserver
2+
3+
go 1.22.2
4+
5+
require github.com/go-chi/chi/v5 v5.2.1 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8=
2+
github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=

main.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log"
7+
"net/http"
8+
"os"
9+
"os/signal"
10+
"time"
11+
)
12+
13+
func main() {
14+
log.Println("Starting setup... (simulating 10s delay)")
15+
time.Sleep(10 * time.Second) // Simulated setup time
16+
log.Println("Setup complete. Starting server...")
17+
18+
mux := http.NewServeMux()
19+
20+
// Route: /
21+
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
22+
fmt.Fprintln(w, "Hello from Go HTTP server!")
23+
})
24+
25+
// Route: /health
26+
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
27+
w.WriteHeader(http.StatusOK)
28+
fmt.Fprintln(w, "OK")
29+
})
30+
31+
server := &http.Server{
32+
Addr: ":8080",
33+
Handler: mux,
34+
}
35+
36+
// Graceful shutdown setup
37+
idleConnsClosed := make(chan struct{})
38+
go func() {
39+
sigint := make(chan os.Signal, 1)
40+
signal.Notify(sigint, os.Interrupt)
41+
<-sigint
42+
43+
log.Println("Shutting down gracefully...")
44+
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
45+
defer cancel()
46+
47+
if err := server.Shutdown(ctx); err != nil {
48+
log.Printf("HTTP server Shutdown: %v", err)
49+
}
50+
close(idleConnsClosed)
51+
}()
52+
53+
log.Println("Starting server on http://localhost:8080")
54+
if err := server.ListenAndServe(); err != http.ErrServerClosed {
55+
log.Fatalf("HTTP server ListenAndServe: %v", err)
56+
}
57+
58+
<-idleConnsClosed
59+
log.Println("Server stopped.")
60+
}

main_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package main
2+
3+
import (
4+
"io"
5+
"net/http"
6+
"net/http/httptest"
7+
"testing"
8+
)
9+
10+
func TestRootHandler(t *testing.T) {
11+
// Create a new request
12+
req := httptest.NewRequest(http.MethodGet, "/", nil)
13+
14+
// Create a ResponseRecorder to record the response
15+
rr := httptest.NewRecorder()
16+
17+
// Call the handler directly
18+
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
19+
// Replicating the handler from main.go
20+
io.WriteString(w, "Hello from Go HTTP server!\n")
21+
})
22+
23+
handler.ServeHTTP(rr, req)
24+
25+
// Check the status code
26+
if status := rr.Code; status != http.StatusOK {
27+
t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK)
28+
}
29+
30+
// Check the response body
31+
expected := "Hello from Go HTTP server!\n"
32+
if rr.Body.String() != expected {
33+
t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected)
34+
}
35+
}

0 commit comments

Comments
 (0)