diff --git a/.gitignore b/.gitignore index daf913b..f6f1d83 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,5 @@ _testmain.go *.exe *.test *.prof + +gowhoami diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..fe0094a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,5 @@ +FROM alpine:3.17 +RUN adduser -u 1001 -D gowhoami +COPY gowhoami / +USER 1001 +ENTRYPOINT ["/gowhoami"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9143650 --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +.PHONY: build push + + +IMAGE = jonazz/gowhoami +VERSION = 0.0.4 + +build: + CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-w' + +container: build + docker build -t $(IMAGE):$(VERSION) . + +push: container + docker push $(IMAGE):$(VERSION); + +all: push + +run: + docker run -i --rm -p 8080:8080 -t $(IMAGE):$(VERSION) diff --git a/flags.go b/flags.go new file mode 100644 index 0000000..a1c881b --- /dev/null +++ b/flags.go @@ -0,0 +1,12 @@ +package main + +type msgFlags []string + +func (i *msgFlags) String() string { + return "my string representation" +} + +func (i *msgFlags) Set(value string) error { + *i = append(*i, value) + return nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..d40623b --- /dev/null +++ b/go.mod @@ -0,0 +1,7 @@ +module github.com/jonaz/gowhoami + +go 1.19 + +require github.com/sirupsen/logrus v1.9.0 + +require golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..ed65537 --- /dev/null +++ b/go.sum @@ -0,0 +1,15 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/kube.yml b/kube.yml new file mode 100644 index 0000000..c6abea4 --- /dev/null +++ b/kube.yml @@ -0,0 +1,70 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: gowhoami-v1 + labels: + app: gowhoami + version: "1" +spec: + replicas: 2 + selector: + matchLabels: + app: gowhoami + template: + metadata: + labels: + app: gowhoami + version: "1" + spec: + containers: + - image: jonazz/gowhoami:0.0.4 + imagePullPolicy: Always + args: + - -d=false + resources: + limits: + cpu: 200m + memory: 100Mi + requests: + cpu: 50m + memory: 50Mi + name: gowhoami + ports: + - containerPort: 8080 + readinessProbe: + httpGet: + # Path to probe; should be cheap, but representative of typical behavior + path: / + port: 8080 + scheme: HTTP + initialDelaySeconds: 5 +--- +apiVersion: v1 +kind: Service +metadata: + name: gowhoami +spec: + type: NodePort + ports: + - port: 8080 + protocol: TCP + name: http + selector: + app: gowhoami +--- +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: gowhoami + namespace: default + annotations: + nginx.ingress.kubernetes.io/ssl-redirect: "false" +spec: + rules: + - http: + paths: + - backend: + serviceName: gowhoami + servicePort: 8080 + path: /api/gowhoami diff --git a/main.go b/main.go index 25bdafe..9497dae 100644 --- a/main.go +++ b/main.go @@ -1,30 +1,72 @@ package main import ( + "context" "flag" "fmt" "log" "net/http" + "os" + "os/signal" "sort" + "syscall" + "time" + + "github.com/sirupsen/logrus" ) -var port string +var ( + port string + debug bool + messages msgFlags + allowSleep bool +) func init() { + flag.Var(&messages, "msg", "custom message to print out. can be used multiple times") flag.StringVar(&port, "p", "8080", "Port to listen on") + flag.BoolVar(&debug, "d", true, "debug. Print all requests") + flag.BoolVar(&allowSleep, "allow-sleep", true, "Allows ?sleep= query parameter") } func main() { flag.Parse() + + logrus.SetFormatter(&logrus.JSONFormatter{TimestampFormat: time.RFC3339Nano}) + + http.HandleFunc("/api/gowhoami/log", func(_ http.ResponseWriter, _ *http.Request) { + logrus.WithFields(logrus.Fields{ + "field1": "test", + }).Info("Test logging") + }) http.HandleFunc("/", handler) log.Println("Starting server on port: " + port) - log.Fatal(http.ListenAndServe(":"+port, nil)) + + server, shutdown := NewServerWithTimeout(10 * time.Second) + server.Handler = http.DefaultServeMux + server.Addr = ":" + port + + log.Println(server.ListenAndServe()) + + <-shutdown + log.Println("Stopped") } func handler(w http.ResponseWriter, r *http.Request) { + hostname, err := os.Hostname() + if err != nil { + fmt.Fprintf(w, "Error: %s\n", err.Error()) + return + } + + for _, msg := range messages { + fmt.Fprintf(w, "%s\n", msg) + } + fmt.Fprintf(w, "Hostname: %s\n", hostname) fmt.Fprintf(w, "RemoteAddr: %s\n", r.RemoteAddr) fmt.Fprintf(w, "Host: %s\n", r.Host) fmt.Fprintf(w, "Protocol: %s\n", r.Proto) + fmt.Fprintf(w, "Path: %s\n", r.URL.Path) keys := make([]string, 0, len(r.Header)) for key := range r.Header { @@ -37,5 +79,49 @@ func handler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "%s:%s\n", v, r.Header.Get(v)) } - log.Printf("| %s | %s | %s", r.RemoteAddr, r.Method, r.RequestURI) + if debug { + log.Printf("| %s | %s | %s", r.RemoteAddr, r.Method, r.RequestURI) + log.Printf("Host: %s\n", r.Host) + for _, v := range keys { + log.Printf("%s:%s\n", v, r.Header.Get(v)) + } + } + + if allowSleep { + strTime := r.URL.Query().Get("sleep") + if strTime == "" { + return + } + dur, err := time.ParseDuration(strTime) + if err != nil { + logrus.Error(err) + fmt.Fprintf(w, "error: %s\n", err.Error()) + return + } + time.Sleep(dur) + } +} + +func NewServerWithTimeout(t time.Duration) (*http.Server, chan struct{}) { + shutdown := make(chan struct{}) + srv := &http.Server{} + + quit := make(chan os.Signal, 1) + signal.Notify(quit, os.Interrupt, syscall.SIGQUIT, syscall.SIGTERM) + go func() { + <-quit + log.Println("gograce: Shutdown Server ...") + + time.Sleep(5 * time.Second) + + ctx, cancel := context.WithTimeout(context.Background(), t) + defer cancel() + if err := srv.Shutdown(ctx); err != nil { + log.Println("gograce: error server shutdown:", err) + } + close(shutdown) + log.Println("gograce: server exited") + }() + + return srv, shutdown }