mirror of
https://github.com/stefanprodan/podinfo.git
synced 2026-08-28 17:57:16 +00:00
Move ping to api/echo
This commit is contained in:
@@ -1,11 +1,16 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/stefanprodan/k8s-podinfo/pkg/version"
|
||||
)
|
||||
|
||||
@@ -52,3 +57,122 @@ func (s *Server) apiInfo(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(d)
|
||||
}
|
||||
|
||||
func (s *Server) apiEcho(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/api/echo" && r.Method != http.MethodPost {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
log.Error().Msgf("Reading the request body failed: %v", err)
|
||||
jsonError(w, "invalid request body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
backendURL := os.Getenv("backendURL")
|
||||
if len(backendURL) > 0 {
|
||||
backendReq, err := http.NewRequest("POST", backendURL, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("%v backend call failed", r.URL.Path)
|
||||
jsonError(w, "backend call failed", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// forward headers
|
||||
copyTracingHeaders(r, backendReq)
|
||||
setVersionHeaders(backendReq)
|
||||
|
||||
// TODO: make the timeout configurable
|
||||
ctx, cancel := context.WithTimeout(backendReq.Context(), 2*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
// call backend
|
||||
resp, err := http.DefaultClient.Do(backendReq.WithContext(ctx))
|
||||
if err != nil {
|
||||
log.Error().Msgf("%v backend call failed", r.URL.Path)
|
||||
jsonError(w, "backend call failed", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
// copy error status from backend and exit
|
||||
if resp.StatusCode >= 400 {
|
||||
w.WriteHeader(resp.StatusCode)
|
||||
return
|
||||
}
|
||||
|
||||
// forward the received body
|
||||
rbody, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("%v reading the backend request body failed", r.URL.Path)
|
||||
jsonError(w, "backend call failed", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// set logLevel=info when load testing
|
||||
log.Debug().Msgf("Payload received %v from backend: %s", r.URL.Path, string(rbody))
|
||||
|
||||
setResponseHeaders(w)
|
||||
w.Write(rbody)
|
||||
} else {
|
||||
setResponseHeaders(w)
|
||||
w.Write(body)
|
||||
}
|
||||
}
|
||||
|
||||
func copyTracingHeaders(from *http.Request, to *http.Request) {
|
||||
headers := []string{
|
||||
"x-request-id",
|
||||
"x-b3-traceid",
|
||||
"x-b3-spanid",
|
||||
"x-b3-parentspanid",
|
||||
"x-b3-sampled",
|
||||
"x-b3-flags",
|
||||
"x-ot-span-context",
|
||||
}
|
||||
|
||||
for i := range headers {
|
||||
headerValue := from.Header.Get(headers[i])
|
||||
if len(headerValue) > 0 {
|
||||
to.Header.Set(headers[i], headerValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setVersionHeaders(r *http.Request) {
|
||||
r.Header.Set("X-API-Version", version.VERSION)
|
||||
r.Header.Set("X-API-Revision", version.GITCOMMIT)
|
||||
}
|
||||
|
||||
func setResponseHeaders(w http.ResponseWriter) {
|
||||
color := os.Getenv("color")
|
||||
if len(color) < 1 {
|
||||
color = "blue"
|
||||
}
|
||||
w.Header().Set("X-Color", color)
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
}
|
||||
|
||||
func jsonError(w http.ResponseWriter, error string, code int) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.WriteHeader(code)
|
||||
|
||||
data := struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}{
|
||||
Code: code,
|
||||
Message: error,
|
||||
}
|
||||
|
||||
body, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
log.Debug().Err(err).Msg("jsonError marshal failed")
|
||||
} else {
|
||||
w.Write(body)
|
||||
}
|
||||
}
|
||||
|
||||
+4
-30
@@ -104,27 +104,6 @@ func (s *Server) echoHeaders(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write(d)
|
||||
}
|
||||
|
||||
func copyTracingHeaders(from *http.Request, to *http.Request) {
|
||||
headers := []string{
|
||||
"x-request-id",
|
||||
"x-b3-traceid",
|
||||
"x-b3-spanid",
|
||||
"x-b3-parentspanid",
|
||||
"x-b3-sampled",
|
||||
"x-b3-flags",
|
||||
"x-ot-span-context",
|
||||
}
|
||||
|
||||
for i := range headers {
|
||||
headerValue := from.Header.Get(headers[i])
|
||||
if len(headerValue) > 0 {
|
||||
to.Header.Set(headers[i], headerValue)
|
||||
}
|
||||
}
|
||||
|
||||
to.Header.Set("X-API-Version", version.VERSION)
|
||||
}
|
||||
|
||||
func (s *Server) backend(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
@@ -136,7 +115,7 @@ func (s *Server) backend(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
backendURL := os.Getenv("backend_url")
|
||||
backendURL := os.Getenv("backendURL")
|
||||
if len(backendURL) > 0 {
|
||||
backendReq, err := http.NewRequest("POST", backendURL, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
@@ -148,6 +127,7 @@ func (s *Server) backend(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// forward tracing headers
|
||||
copyTracingHeaders(r, backendReq)
|
||||
setVersionHeaders(backendReq)
|
||||
|
||||
resp, err := http.DefaultClient.Do(backendReq)
|
||||
if err != nil {
|
||||
@@ -170,17 +150,11 @@ func (s *Server) backend(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
log.Debug().Msgf("Payload received from backend: %s", string(rbody))
|
||||
|
||||
color := os.Getenv("color")
|
||||
if len(color) < 1 {
|
||||
color = "blue"
|
||||
}
|
||||
w.Header().Set("X-Color", color)
|
||||
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
setResponseHeaders(w)
|
||||
w.Write(rbody)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte("Backend not specified, set backend_url env var"))
|
||||
w.Write([]byte("Backend not specified, set backendURL env var"))
|
||||
}
|
||||
default:
|
||||
w.WriteHeader(http.StatusNotAcceptable)
|
||||
|
||||
@@ -59,6 +59,7 @@ func NewServer(options ...func(*Server)) *Server {
|
||||
|
||||
// API
|
||||
s.mux.HandleFunc("/api/info", s.apiInfo)
|
||||
s.mux.HandleFunc("/api/echo", s.apiEcho)
|
||||
|
||||
return s
|
||||
}
|
||||
@@ -118,6 +119,12 @@ func ListenAndServe(port string, timeout time.Duration, stopCh <-chan struct{})
|
||||
|
||||
log.Info().Msgf("Shutting down HTTP server with timeout: %v", timeout)
|
||||
|
||||
// wait for Kubernetes readiness probe
|
||||
// to remove this instance from the load balancer
|
||||
// the readiness check interval must lower than the timeout
|
||||
time.Sleep(timeout)
|
||||
|
||||
// attempt graceful shutdown
|
||||
if err := srv.Shutdown(ctx); err != nil {
|
||||
log.Error().Err(err).Msg("HTTP server graceful shutdown failed")
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -166,7 +166,7 @@
|
||||
},
|
||||
postBackend: function() {
|
||||
var self = this
|
||||
fetch("/backend", {
|
||||
fetch("/api/echo", {
|
||||
method: 'post',
|
||||
headers: {
|
||||
"Content-type": "application/json; charset=UTF-8",
|
||||
|
||||
Reference in New Issue
Block a user